Итак, начинаем все дело с нуля. В смысле, не совсем с нуля, а с того уровня
знаний, который накоплен к этому моменту времени и с имеющегося опыта.
Для начала, определимся с тем, на какой ПЛИС делать:
Разумеется, выбор падает на ПЛИС фирмы ALTERA, ибо опыт работы у меня
имеется только с ними.
Конкретно выбор падает на микросхему EP1K50QC208-2, которая стоит в
устройстве, что имеется у меня под боком. Чисто принципиально, подойдет и
любая другая ПЛИС семейства ACEX, лишь бы хватило ее объема для реазлизации
процессора и удовлетворила скорость его работы. Speed-Grade = 2 -- это не
самая низкая, но и не самая высокая скорость.
Чтобы уточнить, что же у меня есть под боком, добавлю, что в этом устройстве
кроме ПЛИС есть:
ПЗУ, объемом 512 килобайт, 256Кx16, и временем доступа 70нс;
OЗУ - 256Кб - 128Кx16, 15нс;
полный IDE-интерфейс.
ОЗУ и ПЗУ, имеют общую шину адреса, общую шину данных, к которой подключена
и шина данных IDE (через буферы!). Отдельно от всех устройств подключена
SD-RAM-100MHz, объемом 8Мегабайт - 1Mx8.
Тактовый генератор - 100MHz - Микросхема (однократно)программируемого
генератора фирмы Epson - SG8002.
Из устройств, которые пока не нужны, есть два интерфейса PS/2, через которые
можно подключить клавиатуру и мышь, а так же имеется вторая ПЛИС с VGA
контроллером, который, можно использовать в режиме CGA 80x25 символов.
По мере движения вперед, возможно, всплывет и какая-то новая информация,
необходимая для ведения разработки.
Разумеется, в устройстве есть схема связи с PC (через LPT).
=============================
Начнем с планирования блоков, которые должны быть в процессоре и около него.
1. Тактовый генератор. Вероятность того, что процессор сразу заработает на
100MHz можно исключить, поэтому первым делом в ПЛИС-е устанавливается
тактовый генератор с переменным коэфициентом деления. Для этого тактовая
частота простой схемой умножается на 2, а затем делится на 2N, где N -
заданный коэфициент.
Четное число только для того, чтобы был меандр на выходе, кто захочет, тот
может сделать и деление на нечетное число.
=== GEN.TDF ===
- Код: Выделить всё
TITLE "Generator";
-- include "clklock";
PARAMETERS
(
FRQ = 0
);
SUBDESIGN gen
(
CLK : INPUT;
CLKF : BIDIR;
COEF[3..0] : INPUT = GND;
)
VARIABLE
CNT[4..0] : DFF;
CLK100 : NODE;
CLK100X : NODE;
CLK200 : NODE;
BEGIN
CLK100 = CLK;
CLK100X = TFF(VCC,CLK200,,);
CLK200 = LCELL(CLK100 xor CLK100X);
-- CLK200 = clklock (CLK100) WITH (CLOCKBOOST=2, INPUT_FREQUENCY=90);
CNT[].clk = CLK200;
IF (FRQ == 0) GENERATE
IF (CNT[3..0] == 0) THEN
CNT[] = (!CNT4,COEF[]);
ELSE
CNT[] = CNT[] - 1;
END IF;
ELSE GENERATE
IF (CNT[3..0] == 0) THEN
CNT[] = (!CNT4,(H"F" & FRQ));
ELSE
CNT[] = CNT[] - 1;
END IF;
END GENERATE;
CLKF = TRI(CNT4,VCC);
END;
===
Параметр FRQ указывает, какой коэфициент деления использовать. При FRQ=0
коэфициент берется со входов, иначе, задается значением FRQ+1
Т.е. При FRQ=3 и входной частоте 100MHz, выходная частота 25MHz.
Выход генератора подключен через трехстабильный буфер для упрощения работы с
симулятором.
В симуляторе можно задать высокую тактовую частоту проекта, в результате
чего, после компиляции MAX+ сразу же выдаст приблизительную передельную
частоту для каждого вывода синхронизации. Если же вывод синхронизации не
выведен наружу и не является трехстабильным, то никакой информации о
предельной частоте по этому сигналу выдано не будет.
=======================
2. Стеки.
Стеки можно реализовывать несколькими способами. Здесь приведу только два из
них:
a) Стек на логических ячейках. Имеет высокую скорость, но малую глубину,
занимает много места в ПЛИС:
=== STACK_LC.TDF ===
- Код: Выделить всё
TITLE "Stack_on_lcell";
PARAMETERS
(
WIDTH=16,
DEPTH=8,
FULL = "NO" -- "YES" for 6 bit CMD
);
SUBDESIGN STACK_LC
(
CLK : INPUT;
DI[WIDTH-1..0] : INPUT;
DO[WIDTH-1..0] : OUTPUT;
AO[WIDTH-1..0] : OUTPUT;
EMPTY : OUTPUT;
EMPTY1 : OUTPUT;
CMD[1..0] : INPUT = GND;
COMAND[5..0] : INPUT = GND;
ENA : INPUT = VCC;
)
VARIABLE
DATA[DEPTH-1..0][WIDTH-1..0] : DFFE;
EMP[DEPTH-1..0] : DFFE;
PUSH/POP : NODE;
P/P0 : NODE;
P/P1 : NODE;
GO : NODE;
GO0 : NODE;
GO1 : NODE;
BEGIN
-- 000000 - NOP
-- 000111 - PUSH
-- 111111 - POP/DROP
-- 000110 - DUP
-- 111110 - NIP
-- 001111 - OVER
-- 001011 - SWAP
-- 110111 - DROP/DROP/PUSH - external 2 operand operation
-- 000001 - DROP/PUSH - external 1 operand operation
IF (FULL == "YES") GENERATE
(PUSH/POP,P/P0,P/P1,GO,GO0,GO1) = COMAND[];
ELSE GENERATE
(PUSH/POP,P/P0,P/P1,GO,GO0,GO1) = (CMD1,CMD1,CMD1,CMD0,CMD0,CMD0);
END GENERATE;
DATA[][].clk = CLK;
EMP[].clk = CLK;
DATA[DEPTH-1..2][].ena = GO & ENA;
EMP[DEPTH-1..2].ena = GO & ENA;
DATA[1][].ena = GO1 & ENA;
EMP[1].ena = GO1 & ENA;
DATA[0][].ena = GO0 & ENA;
EMP[0].ena = GO0 & ENA;
FOR i IN DEPTH-1 TO 3 GENERATE
CASE PUSH/POP IS
WHEN 0 => DATA[i-1][] = DATA[i-2][]; EMP[i-1] = EMP[i-2];
WHEN 1 => DATA[i-1][] = DATA[i][]; EMP[i-1] = EMP[i];
END CASE;
END GENERATE;
CASE PUSH/POP IS
WHEN 0 => DATA[DEPTH-1][] = DATA[DEPTH-2][]; EMP[DEPTH-1] = EMP[DEPTH-2];
WHEN 1 => DATA[DEPTH-1][] = GND; EMP[DEPTH-1] = GND;
END CASE;
CASE P/P1 IS
WHEN 0 => DATA[1][] = DATA[0][]; EMP[1] = EMP[0];
WHEN 1 => DATA[1][] = DATA[2][]; EMP[1] = EMP[2];
END CASE;
CASE P/P0 IS
WHEN 0 => DATA[0][] = DI[];
EMP[0] = VCC;
WHEN 1 => DATA[0][] = DATA[1][];
EMP[0] = EMP[1];
END CASE;
AO[] = DATA[1][];
DO[] = DATA[0][];
EMPTY = EMP[0];
EMPTY1 = EMP[1];
END;
===
==========================
б). Стек на внутренних блоках памяти:
=== STACK_M.TDF ===
- Код: Выделить всё
TITLE "STACK";
PARAMETERS
(
WIDTH=16
);
INCLUDE "lpm_ram_dq";
SUBDESIGN STACK_M
(
CLK : INPUT;
DI[WIDTH-1..0] : INPUT;
DO[WIDTH-1..0] : OUTPUT;
COMAND[1..0] : INPUT;
WRITE : INPUT;
)
VARIABLE
ADRESS[7..0] : DFF;
ADRESS_NEW[7..0]: NODE;
XX[7..0] : NODE;
BEGIN
ADRESS[].CLK = CLK;
ADRESS[] = ADRESS_NEW[];
ADRESS_NEW[] = ADRESS[] + XX[];
XX[7..1] = COMAND1;
XX0 = COMAND0;
DO[] = lpm_ram_dq(DI[],ADRESS_NEW[],CLK,!CLK,WRITE)
WITH (lpm_width=WIDTH,lpm_widthad=8,lpm_outdata="REGISTERED");
END;
===
Эти два варианта стека не имеют общего интерфейса, что, вообще говоря,
следует исправить. Но этим можно заняться и позже. Для начала, можно
использовать первый вариант в режиме малой разрядности команды, т.е. команды
для стека в 2 бита + вход управления ENA, который необходим при организации
циклов ожидания.
====================
Дракон всегда прав. Даже, когда он Лев - он прав!