Проектирование учебного процессора для реализации в базисе ПЛИС
Программные заготовки можно легко подстраивать к условиям нового проекта, они обладают высоким быстродействием и независимы от технологии. Их реализация в ПЛИС (например, 8-разрядное микропроцессорное ядро PicoBlaze для реализации в базисе ПЛИС семейств Spartan и Virtex [2]) позволяет ускорить процесс разработки микропроцессорных систем. Наиболее важными потребительскими свойствами вычислительных заготовок процессоров являются повторяемость, быстрoдействие, аппаратурные затраты.
Путем несложной перенастройки «мягкой» заготовки можно получить ряд модификаций микроконтроллера с различным сочетанием объема памяти, периферийных устройств, источников прерывания и т. п. Такой процессор можно реализовать в ПЛИС различных фирм. Описание процессора на языке VHDL позволяет не только сделать ее перенастраиваемой и независимой от технологии, но и выполнять ее моделирование и синтез на симуляторах и средствах синтеза различных фирм.
В работах [36] рассматривается проектирование процессоров для реализации в базе ПЛИС с использованием языков аппаратурных средств VHDL [3, 4] и AHDL [6]. Интересный вариант построения RISC-процессора на языке VHDL описан в работе [1]. Проект процессора ориентирован на реализацию в ПЛИС Virtex-E фирмы Xilinx. Процессор имеет структуру с распределенным управлением, развитую систему команд и может быть использован в качестве основы ультрабыстрого процессора 80С51.
Воспользуемся системой команд гипотетического синхронного процессора, реализованного с помощью конечного автомата, с циклом работы в два такта [3]. При разработке системы команд процессора автор работы [3] использовал слабое кодирование. В таблице 1 представлена система команд процессора с синхронной архитектурой [3]. Процессор основан на использовании раздельных шин данных и команд.
Код операции | Мнемоника | Описание |
---|---|---|
0 | NOP | Нет операции |
01xxH | JMP | Безусловный переход по адресу, заданному младшим байтом команды |
02xxH | JMPZ | Переход по адресу, заданному младшим байтом команды, если содержимое регистра A равно нулю |
03xxH | CALL | Вызов подпрограммы по адресу, заданному младшим байтом команды |
04xxH | MOV A,xx | Непосредственная загрузка в регистр A значения, заданного младшим байтом команды |
05xxH | MOV B,xx | Непосредственная загрузка в регистр B значения, заданного младшим байтом команды |
0600H | Возврат из подпрограммы | |
0601H | MOV A,B | Загрузка в регистр A значения, содержащегося в регистре B |
0602H | MOV B,A | Загрузка в регистр B значения, содержащегося в регистре A |
0603H | XCHG A,B | Обмен местами значений в регистрах A и B |
0604H | ADD A,B | Сложение значений в регистрах A и B, результат помещается в A |
0605H | SUB A,B | Вычитание значений в регистрах A и B, результат помещается в A |
0606H | AND A,B | Побитное логическое И значений в регистрах A и B, результат помещается в A |
0607H | OR A,B | Побитное логическое ИЛИ значений в регистрах A и B, результат помещается в A |
0608H | XOR A,B | Побитное логическое ИСКЛЮЧАЮЩЕЕ ИЛИ значений в регистрах A и B, результат помещается в A |
0609H | DEC A | Декремент регистра А (вычитание 1) |
Предлагаемый в работе [3] процессор способен работать с синхронным ОЗУ. Это обеспечивается употреблением оператора case, который используется в ветви оператора if при детектировании атрибута переднего фронта синхроимпульса clk и позволяет организовать цикл работы в два такта.
В качестве примера воспользуемся процессором, представленным в работе [3], и реализуем его в ПЛИС фирмы Altera APEX20KE с асинхронным ПЗУ. Реализация синхронного процессора с циклом работы в два такта возможна при использовании более современных семейств ПЛИС фирмы Altera Stratix и Сyclone.
с использованием управляющего автомата и асинхронного ПЗУ
На рис. 1 показана тестовая схема управляющего автомата процессора в графическом редакторе САПР ПЛИС Quartus II, а на рис. 2 содержимое конфигурационного файла ПЗУ. В описание процессора на языке VHDL добавлен асинхронный сброс регистров А, В и счетчика команд на регистре ip. Как и в работе [3], декодирование переменной-селектора cmd осуществляется с помощью оператора case.
для тестирования команды обращения
к подпрограммам CALL и возврата RET
Оператор case, подобно оператору if, задает ветвление алгоритма. В этом операторе вычисляется заданное выражение expression, по его значению выбирается одна из альтернатив choices (constant_value) и исполняются соответствующие последовательные операторы statement. В каждом из наборов альтернатив constant_value можно записать один или большее число последовательных операторов.
Значения в списках разделяются символом «|». Когда значение выражения встречается в одном из списков значений, выполняется соответствующая последовательность операторов. Если значение выражения не присутствует ни в одном из списков, то выполняется список операторов, соответствующий ветви when others.
Синтаксис оператора case :
CASE __expression IS WHEN __constant_value => __statement; __statement; WHEN __constant_value => __statement; __statement; WHEN OTHERS => __statement; __statement; END CASE;
Функция conv_integer(cmd) переводит вектор в десятичное число отдельных кодов. При каждом допустимом значении кода команды происходят различные действия, которые состоят в присвоении регистрам новых значений в соответствии с описанием команд. Счетчик команд (регистр) не обновляется автоматически, поэтому в каждом варианте кода команды присваивание счетчику нового значения указывается явно [3]. Процессор ограничивается двумя регистрами общего назначения (A и В), а также имеет указатель инструкций ip и регистр r для хранения адреса, с которого происходит вызов подпрограммы, поддерживает минимальный набор команд: команда пересылки «регистр регистр»; команды непосредственной загрузки; команда безусловного перехода к новому адресу; команды перехода по условию; набор арифметико-логических операций [3]. Приведем пример реализации на языке VHDL управляющего автомата:
library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; entity proc is port (ip: inout std_logic_vector(7 downto 0); cmd: inout std_logic_vector(15 downto 0); clk,res: in std_logic; a: inout std_logic_vector(7 downto 0); b,r: inout std_logic_vector(7 downto 0)); end proc; architecture a of proc is signal stage: std_logic; begin process(clk) begin if (res = '1') then a <=«00000000»; b <=«00000000»; ip <=«00000000»; elsif clk'event and clk='1' then case stage is when '0'=> stage<='1'; when others=> stage<='0'; case conv_integer(cmd) is when 0=> ip <= ip+1; when 256 to 511 =>ip<=cmd(7 downto 0); when 512 to 767 =>if conv_integer(a)=0 then ip<=cmd(7 downto 0); else ip<=ip+1; end if; when 768 to 1023 =>r<=ip; ip<=cmd(7 downto 0); when 1024 to 1279 => a<=cmd(7 downto 0); ip<=ip+1; when 1280 to 1535 => b<=cmd(7 downto 0); ip<=ip+1; when 1536 =>ip<=r+1; when 1537=>a<=b; ip<=ip+1; when 1538=>b<=a; ip<=ip+1; when 1539=>a<=b;b<=a; ip<=ip+1; when 1540=>a<=a+b; ip<=ip+1; when 1541=>a<=a-b; ip<=ip+1; when 1542=>a<=a and b; ip<=ip+1; when 1543=>a<=a or b; ip<=ip+1; when 1544=>a<=a xor b; ip<=ip+1; when 1545=>a<=a-1; ip<=ip+1; when others=>ip<=ip+1; end case; end case; end if; end process; end a;
Наиболее сложными являются команды передачи управления JMP и JMPZ, а также команда обращения к подпрограммам CALL и команда возврата из подпрограмм RET. Временные диаграммы на рис. 3 демонстрируют принцип работы управляющего автомата с асинхронным ПЗУ при отработке команд CALL (0305H) и RET (0600H). При нормальной последовательности работы процессора отрабатываются регистровые команды. Последовательно загружаются регистры А и В. В регистр А загружается число 1D (1H), а в регистр В число 17D (11H). По команде 0305H происходит запись содержимого счетчика команд ip в регистр r (2D) и загрузка в счетчик команд числа 5D. Таким образом, процессор начнет выполнять подпрограмму, хранящуюся в ПЗУ, с адреса 5H. По указанному адресу извлекается регистровая команда 0403H. Происходит загрузка в регистр A числа 3H, командой 0404H загрузка числа 4H. Посредством следующей команды с кодом 0604Н произойдет сложение содержимых регистров с сохранением результата в регистре А (число 21D). Далее будут отработаны команды 0406Н и 0407Н. По команде возврата из подпрограммы 600Н произойдет изменение содержимого счетчика с 10D на 2D+1D, то есть на 3D.
(отрабатываются регистровые команды и команда вызова подпрограммы с кодом 0305H (CALL)
и команда возврата из подпрограммы 0600H (RET))
Для использования устаревших серий ПЛИС в учебных проектах предлагается отказаться от цикла работы в два такта. С этой целью регистровые команды 04xxH, 05xxH, 0601H0609H предлагается реализовать на тактируемом дешифраторе, выполняющем функцию арифметически-логического устройства (АЛУ):
LIBRARY ieee; use ieee.std_logic_1164.all; use IEEE.std_logic_arith.all; use IEEE.std_logic_unsigned.all; ENTITY alu IS PORT (cmd : IN STD_LOGIC_VECTOR (10 DOWNTO 0); clk,res : IN STD_LOGIC; a,b : INOUT STD_LOGIC_VECTOR(7 DOWNTO 0)); END alu; ARCHITECTURE a OF alu IS signal regA,regB: std_logic_vector(7 downto 0); BEGIN PROCESS (clk,res) BEGIN if (RES = '1') then egA <=«00000000»; regB <=«00000000»; elsif (clk'event and clk='1') then case conv_integer(cmd) is when 1024 to 1279 => regA<=cmd(7 downto 0); when 1280 to 1535 => regB<=cmd(7 downto 0); when 1537=>regA<=regB; when 1538=>regB<=regA; when 1539=>regA<=regB; regB<=regA; when 1540=>regA<=regA+regB; when 1541=>regA<=regA-regB; when 1542=>regA<=regA and regB; when 1543=>regA<=regA or regB; when 1544=>regA<=regA xor regB; when 1545=>regA<=regA-1; when others=> a<=regA; b<=regB; end case; end if; a<=regA; b<=regB; END PROCESS; END a;
в
А команды передачи управления JMP, JMPZ и обращения к подпрограммам с кодами 01xxH-03xxH, 0600H на 8-разрядном суммирующем счетчике адресов памяти команд, тактируемом фронтом синхросигнала (рис. 4), выглядят так:
LIBRARY ieee; USE ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; use ieee.std_logic_arith.all; ENTITY counter IS PORT( Clk : IN STD_LOGIC; reset : IN STD_LOGIC; cmd : IN STD_LOGIC_VECTOR(10 downto 0); a : INOUT STD_LOGIC_VECTOR(7 downto 0); r : INOUT STD_LOGIC_VECTOR(7 downto 0); Qa,Qb : OUT STD_LOGIC_VECTOR(7 downto 0)); END counter; ARCHITECTURE a OF counter IS SIGNAL pci,data,regA: STD_LOGIC_VECTOR(7 downto 0); SIGNAL cop: STD_LOGIC_VECTOR(2 downto 0); BEGIN regA<=a; cop<=cmd(10 downto 8); data<=cmd(7 downto 0); -- cmd 11 bit wide -- 11 bit encoding -- JMP: 001 <data> -- JMPZ: 010 <data> -- CALL: 011 <data> -- RET: 110 00000000 process(clk,reset) begin if (reset = '1') then pci <=(others=>'0'); r <=(others=>'0'); elsif (clk'event and clk='1') then if cop=«001» then pci<=data; elsif (cop=«010» and conv_integer(regA)=0) then pci<=data; elsif cop=«011» then r<=pci; pci<=data; elsif cmd=«11000000000» then pci<=r+1; else pci<=pci+1; end if; end if; end process; Qa <= pci; Qb <=data; a<=regA; END a;
Счетчик содержит асинхронный сброс Reset. Активным является сигнал высокого уровня. Во вложенных ветвях оператора if происходит проверка условий и синхронная загрузка счетчика команд.
Оператор if используется для ветвления алгоритма по различным условиям. Наиболее простой синтаксис имеет вид:
IF __expression THEN __statement; END IF;
Вначале проверяется булево выражение boolean-expression, и если оно имеет значение true, то исполняется последовательный оператор sequential-statement. Возможно использовать предложение else c другим последовательным оператором sequential-statement, который исполняется, если булево выражение имеет значение false. В САПР Quartus II рекомендуется использовать следующий синтаксис оператора if (шаблон):
IF __expression THEN __statement; __statement; ELSIF __expression THEN __statement; __statement; ELSE __statement; __statement; END IF;
Счетчик команд ip и регистр r при инициализации системы по сигналу Reset устанавливаются в состояние 0, после чего производится счет адресов памяти программ, хранимых в ПЗУ. Регистр r выполняет функцию стека, в который заносится прежнее состояние счетчика команд. Из шины cmd[10..0] для счетчика команд выделяется поле cop[10..8] и поле data[7..0]. Поле cop означает код операции, который используется для идентификации команд JMP, JMPZ и CALL. Для команды RET поле cop не формируется, а задается полный адрес на шине cmd «11000000000», это связано с тем, что 8 младших бит для команд JMP, JMPZ и CALL могут принимать любые значения, а для команды RET только указанное. Поле data содержит 8-разрядный операнд, который загружается в регистр команд.
ПЗУ реализовано с использованием мегафункции LPM_ROM. В таблице 2 представлены сведения по общему числу задействованных ресурсов ПЛИС. В обоих случаях проект отображается в ПЛИС APEX20KE. На рис. 5 показано тестирование процессора.
Номер проекта | ПЛИС | Общее число логических элементов |
Общее число используемых ESB-бит |
D-триггеров |
---|---|---|---|---|
С использованием управляющего автомата | EP20K30ETC144-1 | 198/1200 (16%) | 2816/24576 (11%) | 32 |
Вариант с асинхронным ПЗУ | EP20K30ETC144-1 | 164/1200 (13%) | 2816/24576 (11%) | 32 |
Рассмотрим вариант реализации проектируемого процессора с использованием асинхронного ОЗУ (рис. 6). Для этого воспользуемся мегафункцией LPM_RAM_IO. Для того чтобы ОЗУ выполняло функцию ПЗУ, необходимо сигнал разрешения записи we «посадить» на «землю», так как активным является сигнал высокого уровня, а сигнал разрешения вывода outenab подключить к питанию. На рис. 7 показан файл конфигурации ОЗУ для тестирования команды JMPZ c кодом 0205H. По команде 0205H осуществляется переход по адресу, заданному младшим байтом команды (на адрес в ОЗУ под номером 5, где хранится команда 0403H), если содержимое регистра A равно нулю. Чтобы содержимое регистра А оказалось равным нулю, необходимо воспользоваться регистровыми командами 0405H и 0505H для загрузки в регистры А и В числа 5, а затем с помощью команды 0605H (SUB A,B) осуществить операцию AB (рис. 8).
в графическом редакторе САПР ПЛИС Quartus II
команды JMPZ
Данный вариант процессора, реализованный в базисе ПЛИС, можно отнести к классу RISC-процессоров, у которых все команды выполняются за один такт синхрочастоты. Процессор может быть модифицирован путем наращивания блока регистров, добавления блока управления прерываний, добавления блока управления ввода/вывода и других функциональных блоков. Вариант с асинхронным ПЗУ, реализованный в ПЛИС APEX20KE EP20K30ETC144-1, занимает всего лишь 13% от общего числа логических элементов и способен работать на частоте 60 МГц. Модифицированный вариант оказался на 3% компактнее по числу задействованных ресурсов ПЛИС и способен работать с морально устаревшими сериями ПЛИС. Однако процессор без использования управляющего автомата может быть пригоден для учебных целей. Недостатком является невозможность поддержки современной концепции синхронного кодирования при разработке микропроцессорных ядер.
Литература
- Сергиенко А. М. VHDL для проектирования вычислительных устройств. Киев: ООО «ТИД «ДС»», 2003.
- Зотов В. Ю. Проектирование встраиваемых микропроцессорных систем на основе ПЛИС фирмы XILINX. М.: Горячая линия Телеком, 2006.
- Тарасов И. Проектирование конфигурируемых процессоров на базе ПЛИС. Часть I // Компоненты и технологии. 2006. № 2.
- Тарасов И. Проектирование конфигурируемых процессоров на базе ПЛИС. Часть II // Компоненты и технологии. 2006. № 3.
- Каршенбойм И. Микропроцессор своими руками // Компоненты и технологии. 2002. № 67.
- Каршенбойм И. Микропроцессор своими руками-2. Битовый процессор // Компоненты и технологии. 2003. № 78.