Подписка на новости

Опрос

Нужны ли комментарии к статьям? Комментировали бы вы?

Реклама

 

2009 №11

Проектирование учебного процессора с фиксированной запятой в САПР Quartus II компании Altera

Буслов Артем  
Давыдов Сергей  
Строгонов Андрей  

В статье предлагается на основе системы команд из работы и модели процессора с управляющим автоматом на шесть состояний, позволяющим проводить вычисления с фиксированной запятой, реализованной в системе MATLAB/Simulink [2], разработать процессор в базисе ПЛИС Stratix III компании Altera с использованием САПР Quartus II. Особенностью модели процессора, представленного в работе [2], является распределенная система управления функциональными блоками, то есть каждый блок имеет свой локальный управляющий сигнал (шину), которым управляет цифровой автомат. Основные функциональные блоки проектируемого процессора описаны на языке VHDL, код которого был сгенерирован в автоматическом режиме с помощью Simulink HDL Coder системы MATLAB/Simulink.

На рис. 1 представлена электрическая схема процессора в САПР ПЛИС Quartus II версии 8.1. Проектируемый процессор состоит из следующих функциональных блоков: управляющий автомат (блок CPU_Controller, пример 1); регистр специального назначения (РСН, блок PC_Incrementer, пример 2), он необходим для обеспечения «прыжковых» команд, таких как JMP, JMPZ, CALL и RET; счетчик команд (блок Program_ Counter, пример 3); память программ — ПЗУ процессора (блок Instruction_ROM, пример 4); регистр инструкций (блок Instruction_Register, пример 5); два регистра общего назначения (РОН, блок RegisterA, пример 6); АЛУ процессора (блок ALU, пример 7). Регистры на D-триггерах (четыре 8- (блок dff8) и один 16-разрядный (блок dff16)), тактируемые фронтом синхросигнала, разработаны в дополнение к [2] с использованием мегафункции LPM_FF.

Рис. 1. Схема процессора с управляющим автоматом в САПР Quartus II

На рис. 2, 3 показаны временные диаграммы работы процессора с управляющим автоматом в САПР Quartus II. Осуществляется тестирование команд MOV A,12; MOV B,23; ADD A,B (рис. 2) и команд JMPZ11, JMP7 (рис. 3).

Рис. 2. Временные диаграммы работы процессора с управляющим автоматом в САПР Quartus II. Тестирование команд MOV A,12; MOV B,23; ADD A,B

Рис. 3. Временные диаграммы работы процессора с управляющим автоматом в САПР Quartus II. Тестирование команд JMPZ11, JMP7

VHDL является языком со строгим контролем типов. Поэтому бывает необходимо преобразовать сигнал одного типа в сигнал другого типа. Даже при выполнении простых действий, если типы объектов не совпадают, может потребоваться обращение к функции преобразования типов. Различают два вида преобразования типа: переход типа и вызов функции преобразования типа. Переход типа применяется для преобразования тесно связанных типов или подтипов. Если типы не тесно связанные, то необходимо выполнить вызов функции преобразования типа.

Пакет numeric_std содержит стандартный набор арифметических, логических функций и функций сравнения для работы с типами signed, unsigned, integer, std_ulogic, std_logic, std_logic_vector. В пакете numeric_std есть функция преобразования векторного типа to_unsigned с операндами arg (тип integer), size (тип natural, битовая ширина) и типом результата unsigned. Тип unsigned интерпретируется как двоичное представление числа без знака, а тип signed обозначает двоичные числа со знаком в дополнительном коде. Например: CPU_state_temp : = to_unsigned(3, 8);. Целое десятичное число 3 преобразуется в 8-разрядное двоичное число без знака, которое присваивается переменной CPU_state_temp. А переменная CPU_state_temp объявлена как массив двоичных чисел без знака: VARIABLE CPU_state_temp : unsigned(7 DOWNTO 0);. Это явное преобразование тесно связанных между собой типов.

Или IR_func <= std_logic_vector(to_ unsigned(3, 2));. Десятичное число 3 преобразуется в двоичное число "11" типа unsigned, затем тип unsigned неявно преобразуется в тип std_logic_vector. Сигналу IR_func будет назначено двоичное число "11".

При генерации кода языка VHDL блока АЛУ используется дополнительная функция tmw_to_signed, которая преобразует двоичное число типа unsigned в двоичное число типа signed (пример 7) с шириной битовой шины типа integer, что необходимо для обеспечения операции вычитания (вызов функции преобразования типа):

FUNCTION tmw_to_signed(arg: unsigned; width: integer) RETURN signed IS
--SUB A,B
ina_1 := tmw_to_signed(unsigned(inA), 9) - tmw_to_signed(unsigned (inB), 9);

Оператор srl, введенный в стандарте VHDL93, осуществляет операцию логического сдвига одномерного массива (левый оператор) с элементами типа bit вправо, на число, указанное правым оператором типа integer. Например, одномерный массив main_opcode_temp типа unsigned(15 DOWNTO 0), представляющий собой 16-битовое двоичное число, сдвигается вправо на 8 бит. Например: main_opcode_ temp := unsigned(IR_in); cr := main_opcode_ temp srl 8;.

Логический оператор AND (тип левого операнда, правого и тип результата unsigned) используется для выделения 8-разрядного сигнала (операнда) address_data_next из 16-разрядной команды процессора путем логического умножения сигнала major_ opcode_temp с маской to_unsigned(255, 16). Например:

-- IR_in <8..1>
c_uint := main_opcode_temp AND to_unsigned(255, 16);
IF c_uint(15 DOWNTO 8) /= "00000000" THEN address_data_next <= "11111111";
ELSE
address_data_next <= c_uint(7 DOWNTO 0);
END IF;

В примере 3 используется оператор конкатенации &, который предопределен для всех одноразмерных массивов. Этот оператор выстраивает массивы путем комбинирования с их операндами. Оператор & используется для добавления одиночного элемента в конец массива PC_value типа unsigned(7 DOWNTO 0):

-- increment PC
ain := resize(PC_value & '0' & '0' & '0' & '0' & '0' & '0' & '0', 16);
ain_0 := ain + 128;
IF (ain_0(15) /= '0') OR (ain_0(14 DOWNTO 7) = "11111111") THEN
PC_value_next <= "11111111";
ELSE
PC_value_next <= ain_0(14 DOWNTO 7) + ("0" & (ain_0(6)));
END IF;

Функция изменения размера resize (тип левого оператора unsigned, количество позиций типа natural, тип результата unsigned) позволяет из 8-разрядного сигнала PC_value сконструировать локальную переменную ain типа unsigned(15 DOWNTO 0). Функция '+' позволяет осуществить арифметическую операцию сложения, если тип левого оператора unsigned, а правого — integer с результатом unsigned.

LIBRARY ieee;

USE ieee.std_logk_1164.all;

USE ieee.numeric_std.all;

ENTITY CPU_Controller IS
PORT (
clk : IN std_logic;
clk_enable : IN std_logic;
reset : IN std_logic;
master_rst : IN std_logic;
IR_in : IN std_logic_vector(15 DOWNTO 0);
Reg_A : IN std_logic_vector(7 DOWNTO 0);
ALU_func : OUT std_logic_vector(3 DOWNTO 0);
IR_func : OUT std_logic_vector(1 DOWNTO 0);
PC_inc_func : OUT std_logic_vector(1 DOWNTO 0);
PC_func : OUT std_logic_vector(1 DOWNTO 0);
addr_inc : OUT std_logic_vector(7 DOWNTO 0);
IM_read : OUT std_logic;

RegA_func : OUT std_logic_vector(2 DOWNTO 0);
RegB_func : OUT std_logic_vector(2 DOWNTO 0);
Reg_OutA : OUT std_logic_vector(7 DOWNTO 0);
Reg_OutB : OUT std_logic_vector(7 DOWNTO 0));
END CPU_Controller;

ARCHITECTURE fsm_SFHDL OF CPU_Controller IS

SIGNAL CPU_state : unsigned(7 DOWNTO 0);
SIGNAL major_opcode : unsigned(3 DOWNTO 0);
SIGNAL main_opcode : unsigned(15 DOWNTO 0);
SIGNAL minor_opcode : unsigned(3 DOWNTO 0);
SIGNAL address_data : unsigned(7 DOWNTO 0);
SIGNAL CPU_state_next : unsigned(7 DOWNTO 0);

SIGNAL major_opcode_next : unsigned(3 DOWNTO 0);

SIGNAL main_opcode_next : unsigned(15 DOWNTO 0);

SIGNAL minor_opcode_next : unsigned(3 DOWNTO 0);

SIGNAL address_data_next : unsigned(7 DOWNTO 0);

BEGIN

initialize_CPU_Controller : PROCESS (reset, clk)
-- local variables

BEGIN
IF reset = '1' THEN
CPU_state <= to_unsigned(0, 8);
main_opcode <= to_unsigned(0, 16);
major_opcode <= to_unsigned(0, 4);
minor_opcode <= to_unsigned(0, 4);
address_data <= to_unsigned(0, 8);
ELSIF clk'EVENT AND clk= '1' THEN
IF clk_enable= '1' THEN
CPU_state <= CPU_state_next;
major_opcode <= major_opcode_next;
main_opcode <= main_opcode_next;
minor_opcode <= minor_opcode_next;
address_data <= address_data_next;
END IF;
END IF;

END PROCESS initialize_CPU_Controller;

CPU_Controller : PROCESS (CPU_state, major_opcode, main_opcode,

minor_opcode,

address_data, master_rst, IR_in, Reg_A)
-- local variables

VARIABLE c_uint : unsigned(15 DOWNTO 0);
VARIABLE b_c_uint : unsigned(3 DOWNTO 0);

VARIABLE cr : unsigned(15 DOWNTO 0);
VARIABLE CPU_state_temp : unsigned(7 DOWNTO 0);
VARIABLE major_opcode_temp : unsigned(3 DOWNTO 0);
VARIABLE main_opcode_temp : unsigned(15 DOWNTO 0);
VARIABLE reg_a_0 : unsigned(7 DOWNTO 0);
BEGIN

minor_opcode_next <= minor_opcode;
address_data_next <= address_data;
CPU_state_temp := CPU_state;
major_opcode_temp := major_opcode;
main_opcode_temp := main_opcode;
-- CPU Controller
-- 16-bit Instruction Encoding:

---------------minor_opcode---------

-- NOP: 00000 000 <00000000>
-- JMP: 00000 001 <8-bit>
-- JMPZ: 00000 010 <8-bit>
-- CALL: 00000 011 <8-bit>
-- MOV A,xx: 00000 100 <8-bit>
-- MOV B,xx: 00000 101 <8-bit>
-- RET: 00000 110 <00000000>

-- MOV A,B: 00000 110 <00000001>
-- MOV B,A: 00000 110 <00000010>
-- XCHG A,B: 00000 110 <00000011>
-- ADD A,B: 00000 110 <00000100>
-- SUB A,B: 00000 110 <00000101>
-- AND A,B: 00000 110 <00000110>
-- OR A,B: 00000 110 <00000111>
-- XOR A,B: 00000 110 <00001000>
-- DEC A: 00000 110 <00001001>
IF master_rst /= '0' THEN

CPU_state_temp := to_unsigned(0, 8);
END IF;

PC_inc_func <= std_logic_vector(to_unsigned(0, 2));
IR_func <= std_logic_vector(to_unsigned(3, 2));
PC_func <= std_logic_vector(to_unsigned(3, 2));
IM_read <= '0';

addr_inc <= std_logic_vector(to_unsigned(0, 8));
Reg_OutA <= std_logic_vector(to_unsigned(0, 8));
Reg_OutB <= std_logic_vector(to_unsigned(0, 8));
RegA_func <= std_logic_vector(to_unsigned(4, 3));
RegB_func <= std_logic_vector(to_unsigned(4, 3));
ALU_func <= std_logic_vector(to_unsigned(9, 4));
-- NOP

-- main_code: <16..1>
-- major_opcode: <16..9>
-- minor_opcode: <12..9>
-- address_data: <8..1>
CASE CPU_state_temp IS

WHEN "00000000" =>

--%%%%%%%%%%%%%%%%%%%%%%%%%%%

-- RESETTING OUTPUTS
--%%%%%%%%%%%%%%%%%%%%%%%%%%%

PC_inc_func <= std_logic_vector(to_unsigned(0, 2));
PC_func <= std_logic_vector(to_unsigned(0, 2));
IR_func <= std_logic_vector(to_unsigned(0, 2));
RegA_func <= std_logic_vector(to_unsigned(0, 3));
RegB_func <= std_logic_vector(to_unsigned(0, 3));

CPU_state_temp := to_unsigned(1, 8);
--%%%%%%%%%%%%%%%%%%%%%%%%%%%

-- FETCH

--%%%%%%%%%%%%%%%%%%%%%%%%%%%

WHEN "00000001" =>
-- Read from IM (ROM)
IM_read <= '1';
-- PC increment PC+1

PC_func <= std_logic_vector(to_unsigned(2, 2));
-- store into IR

IR_func <= std_logic_vector(to_unsigned(1, 2));
CPU_state_temp := to_unsigned(2, 8);
WHEN "00000010" =>
-- Read from IR

IR_func <= std_logic_vector(to_unsigned(2, 2));
-- Accommodating for the 'unit delay' from IR_out to IR_in
CPU_state_temp := to_unsigned(3, 8);
WHEN "00000011" =>
-- IR_in <16..1>

main_opcode_temp := unsigned(IR_in);

-- IR_in <16..9>

cr := main_opcode_temp srl 8;

IF cr(15 DOWNTO 4) /= "000000000000" THEN

major_opcode_temp := "1111";
ELSE

major_opcode_temp := cr(3 DOWNTO 0);
END IF;

-- for instructions NOP,JMP,JMPZ,CALL,MOV A,xx MOV
B,xx,RET

-- IR_in <12..9>

b_c_uint := major_opcode_temp AND to_unsigned(15, 4);
minor_opcode_next <= b_c_uint;
-- IR_in <8..1>

c_uint := main_opcode_temp AND to_unsigned(255, 16);
IF c_uint(15 DOWNTO 8) /= "00000000" THEN

address_data_next <= "11111111";
ELSE

address_data_next <= c_uint(7 DOWNTO 0);
END IF;
-- Go to the decode stage
CPU_state_temp := to_unsigned(4, 8);

--%%%%%%%%%%%%%%%%%%%%%%%%%

-- DECODE AND EXECUTE
--%%%%%%%%%%%%%%%%%%%%%%%%%

WHEN "00000100" =>
CASE minor_opcode IS
WHEN "0000" =>
-- NOP

CPU_state_temp := to_unsigned(1, 8);
WHEN "0001" =>
-- JMP

addr_inc <= std_logic_vector(address_data);
PC_inc_func <= std_logic_vector(to_unsigned(1, 2));
PC_func <= std_logic_vector(to_unsigned(1, 2));
CPU_state_temp := to_unsigned(1, 8);
WHEN "0010" =>
--JMPZ
reg_a_0 := unsigned(Reg_A);
IF reg_a_0 = 0 THEN

addr_inc <= std_logic_vector(address_data);
PC_inc_func <= std_logic_vector(to_unsigned( 1, 2));
PC_func <= std_logic_vector(to_unsigned(1, 2));
END IF;

CPU_state_temp := to_unsigned(1, 8);
WHEN "0011" =>
-- CALL

addr_inc <= std_logic_vector(address_data);
PC_inc_func <= std_logic_vector(to_unsigned(1, 2));
PC_func <= std_logic_vector(to_unsigned(1, 2));
CPU_state_temp := to_unsigned(1, 8);
WHEN "0100" =>
--MOV A,xx

Reg_OutA <= std_logic_vector(address_data);
RegA_func <= std_logic_vector(to_unsigned(1, 3));
CPU_state_temp := to_unsigned(1, 8);
WHEN "0101" =>
--MOV B,xx

Reg_OutB <= std_logic_vector(address_data);
RegB_func <= std_logic_vector(to_unsigned(1, 3));
CPU_state_temp := to_unsigned(1, 8);
WHEN "0110" =>
CASE address_data IS
WHEN "00000000" =>
--RET

PC_inc_func <= std_logic_vector(to_unsigned(2, 2));
PC_func <= std_logic_vector(to_unsigned(2, 2));
CPU_state_temp := to_unsigned(5, 8);
WHEN "00000001" =>
--MOV A,B

ALU_func <= std_logic_vector(to_unsigned(0, 4));
RegA_func <= std_logic_vector(to_unsigned(2, 3));
RegB_func <= std_logic_vector(to_unsigned(2, 3));
CPU_state_temp := to_unsigned(5, 8);
WHEN "00000010" =>
--MOV B,A

ALU_func <= std_logic_vector(to_unsigned(1, 4));
RegA_func <= std_logic_vector(to_unsigned(2, 3));
RegB_func <= std_logic_vector(to_unsigned(2, 3));
CPU_state_temp := to_unsigned(5, 8);
WHEN "00000011" =>
--XCHG A,B

ALU_func <= std_logic_vector(to_unsigned(2, 4));
RegA_func <= std_logic_vector(to_unsigned(2, 3));
RegB_func <= std_logic_vector(to_unsigned(2, 3));
CPU_state_temp := to_unsigned(5, 8);
WHEN "00000100" =>
--ADD A,B

ALU_func <= std_logic_vector(to_unsigned(3, 4));
RegA_func <= std_logic_vector(to_unsigned(2, 3));
RegB_func <= std_logic_vector(to_unsigned(2, 3));
CPU_state_temp := to_unsigned(5, 8);
WHEN "00000101" =>
--SUB A,B

ALU_func <= std_logic_vector(to_unsigned(4, 4));
RegA_func <= std_logic_vector(to_unsigned(2, 3));
RegB_func <= std_logic_vector(to_unsigned(2, 3));
CPU_state_temp := to_unsigned(5, 8);
WHEN "00000110" =>
--AND A,B

ALU_func <= std_logic_vector(to_unsigned(5, 4));
RegA_func <= std_logic_vector(to_unsigned(2, 3));
RegB_func <= std_logic_vector(to_unsigned(2, 3));
CPU_state_temp := to_unsigned(5, 8);
WHEN "00000111" =>
--OR A,B

ALU_func <= std_logic_vector(to_unsigned(6, 4));
RegA_func <= std_logic_vector(to_unsigned(2, 3));
RegB_func <= std_logic_vector(to_unsigned(2, 3));
CPU_state_temp := to_unsigned(5, 8);
WHEN "00001000" =>
--XOR A,B

ALU_func <= std_logic_vector(to_unsigned(7, 4));
RegA_func <= std_logic_vector(to_unsigned(2, 3));
RegB_func <= std_logic_vector(to_unsigned(2, 3));
CPU_state_temp := to_unsigned(5, 8);
WHEN "00001001" =>

--DEC A

ALU_func <= std_logic_vector(to_unsigned(8, 4));
RegA_func <= std_logic_vector(to_unsigned(2, 3));
CPU_state_temp := to_unsigned(5, 8);
WHEN OTHERS =>
NULL;
END CASE;
WHEN OTHERS =>

NULL;
END CASE;
WHEN "00000101" =>

RegA_func <= std_logic_vector(to_unsigned(2, 3));
RegB_func <= std_logic_vector(to_unsigned(2, 3));
CPU_state_temp := to_unsigned(1, 8);
WHEN OTHERS =>
NULL;
END CASE;

CPU_state_next <= CPU_state_temp;
major_opcode_next <= major_opcode_temp;
main_opcode_next <= main_opcode_temp;
END PROCESS CPU_Controller;

END fsm_SFHDL;

Пример 1. Код языка VHDL управляющего автомата
проектируемого процессора, сгенерированный в
автоматическом режиме с помощью Simulink HDL Coder
системы MATLAB/Simulink

LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.numeric_std.all;
ENTITY PC_Incrementer IS
PORT (

clk : IN std_logic;
clk_enable : IN std_logic;
reset : IN std_logic;

func : IN std_logic_vector(1 DOWNTO 0);
addr : IN std_logic_vector(7 DOWNTO 0);
PC_curr : IN std_logic_vector(7 DOWNTO 0);
PC_next : OUT std_logic_vector(7 DOWNTO 0);
Temp : OUT std_logic_vector(7 DOWNTO 0));
END PC_Incrementer;

ARCHITECTURE fsm_SFHDL OF PC_Incrementer IS

SIGNAL PC_Temp : unsigned(7 DOWNTO 0);
SIGNAL PC_Temp_next : unsigned(7 DOWNTO 0);

BEGIN

initialize_PC_Incrementer : PROCESS (reset, clk)

-- local variables

BEGIN

IF reset = '1' THEN

PC_Temp <= to_unsigned(0, 8);
ELSIF clk'EVENT AND clk= '1' THEN
IF clk_enable= '1' THEN

PC_Temp <= PC_Temp_next;
END IF;
END IF;

END PROCESS initialize_PC_Incrementer;

PC_Incrementer : PROCESS (PC_Temp, func, addr, PC_curr)
-- local variables

VARIABLE PC_Temp_temp : unsigned(7 DOWNTO 0);
BEGIN

PC_Temp_temp := PC_Temp;
-- func = 0 => reset PC_Inc

-- func = 1 => store into PC_Inc when JMP, JMPZ, CALL
-- func = 2 => load from PC_Inc when RET
PC_next <= PC_curr;

Temp <= std_logic_vector(to_unsigned(0, 8));
CASE func IS
WHEN "00" =>
-- reset PC_Inc

PC_next <= std_logic_vector(to_unsigned(0, 8));
WHEN "01" =>

-- store into PC_Inc when JMP, JMPZ, CALL
PC_next <= addr;

PC_Temp_temp := unsigned(PC_curr);
Temp <= std_logic_vector(PC_Temp_temp);
WHEN "10" =>

-- load from PC_Inc when RET
PC_next <= std_logic_vector(PC_Temp);
WHEN OTHERS =>
NULL;
END CASE;

PC_Temp_next <= PC_Temp_temp;
END PROCESS PC_Incrementer;
END fsm_SFHDL;

Пример 2. Регистр специального назначения
процессора на языке VHDL

КОМПОНЕНТЫ И ТЕХНОЛОГИИ • № 11 '2009

www.kit-e.ru

LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.numeric_std.all;
ENTITY Program_Counter IS
PORT (
clk : IN std_logic;
clk_enable : IN std_logic;
reset : IN std_logic;

func : IN std_logic_vector(1 DOWNTO 0);
addr_in : IN std_logic_vector(7 DOWNTO 0);
addr_out : OUT std_logic_vector(7 DOWNTO 0));
END Program_Counter;

ARCHITECTURE fsm_SFHDL OF Program_Counter IS

SIGNAL PC_value : unsigned(7 DOWNTO 0);
SIGNAL PC_value_next : unsigned(7 DOWNTO 0);

BEGIN

initialize_Program_Counter : PROCESS (reset, clk)

-- local variables
BEGIN
IF reset = '1' THEN

PC_value <= to_unsigned(0, 8);
ELSIF clk'EVENT AND clk= '1' THEN
IF clk_enable= '1' THEN

PC_value <= PC_value_next;
END IF;
END IF;

END PROCESS initialize_Program_Counter;

Program_Counter : PROCESS (PC_value, func, addr_in)
-- local variables

VARIABLE ain : unsigned(15 DOWNTO 0);
VARIABLE ain_0 : unsigned(15 DOWNTO 0);
BEGIN

PC_value_next <= PC_value;
-- Program Counter
-- func = 0 => reset PC
-- func = 1 => load PC
-- func = 2 => increment PC
addr_out <= std_logic_vector(PC_value);
CASE func IS
WHEN "00" =>
-- reset

PC_value_next <= to_unsigned(0, 8);
WHEN "01" =>
-- store into PC

PC_value_next <= unsigned(addr_in);
WHEN "10" =>
-- increment PC

ain := resize(PC_value & '0' & '0' & '0' & '0' & '0' & '0' & '0', 16);
ain_0 := ain + 128;

IF (ain_0(15) /= '0') OR (ain_0( 14 DOWNTO 7) = "11111111")

THEN

PC_value_next <= "11111111";
ELSE

PC_value_next <= am_0(14 DOWNTO 7) + ("0" & (ain_0(6)));
END IF;
WHEN OTHERS =>
NULL;
END CASE;
END PROCESS Program_Counter;
END fsm_SFHDL;

Пример 3. Счетчик команд процессора
на языке VHDL

LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.numeric_std.all;
ENTITY Instruction_ROM IS
PORT (
clk : IN std_logic;
clk_enable : IN std_logic;
reset : IN std_logic;

addr : IN std_logic_vector(7 DOWNTO 0);
read : IN std_logic;

instr_out : OUT std_logic_vector(15 DOWNTO 0));
END Instruction_ROM;

ARCHITECTURE fsm_SFHDL OF Instruction_ROM IS
-- TMW_TO_SIGNED

FUNCTION tmw_to_signed(arg: unsigned; width: integer) RETURN

signed IS

BEGIN

IF arg(arg'right) = 'U' OR arg(arg'right) = 'X' THEN

RETURN to_signed(1, width);
END IF;

RETURN to_signed(to_integer(arg), width);
END FUNCTION;

TYPE T_UFIX_16_256 IS ARRAY (255 DOWNTO 0) of unsigned

(15 DOWNTO 0);

SIGNAL data : T_UFIX_16_256;

SIGNAL data_next : T_UFIX_16_256;

BEGIN

initialize_Instruction_ROM : PROCESS (reset, clk)
-- local variables
VARIABLE b_0 : INTEGER;
BEGIN
IF reset = '1' THEN
FOR b IN 0 TO 255 LOOP

data(b) <= to_unsigned(0, 16);
END LOOP;
ELSIF clk'EVENT AND clk= '1' THEN
IF clk_enable= '1' THEN
FOR b_0 IN 0 TO 255 LOOP

data(b_0) <= data_next(b_0);
END LOOP;
END IF;
END IF;

END PROCESS initialize_Instruction_ROM;

Instruction_ROM : PROCESS (data, addr, read)
-- local variables

VARIABLE data_temp : T_UFIX_16_256;
BEGIN
FOR b IN 0 TO 255 LOOP
data_temp(b) := data(b);
END LOOP;

data_temp(0) := to_unsigned(1036, 16);
data_temp(1) := to_unsigned(1303, 16);
data_temp(2) := to_unsigned(1540, 16);
data_temp(3) := to_unsigned(1545, 16);
data_temp(4) := to_unsigned(1358, 16);
data_temp(5) := to_unsigned(1539, 16);
data_temp(6) := to_unsigned(1541, 16);
data_temp(7) := to_unsigned(1545, 16);
data_temp(8) := to_unsigned(1542, 16);
data_temp(9) := to_unsigned(523, 16);
data_temp(10) := to_unsigned(263, 16);
data_temp(11) := to_unsigned(1037, 16);
data_temp(12) := to_unsigned(1397, 16);
data_temp(13) := to_unsigned(1543, 16);
data_temp(14) := to_unsigned(1539, 16);
data_temp(15) := to_unsigned(1544, 16);
data_temp(16) := to_unsigned(277, 16);
data_temp(17) := to_unsigned(1135, 16);
data_temp(18) := to_unsigned(1480, 16);
data_temp(19) := to_unsigned(1542, 16);
data_temp(20) := to_unsigned(1536, 16);
data_temp(21) := to_unsigned(785, 16);
data_temp(22) := to_unsigned(0, 16);
IF read = '1' THEN
instr_out <= std_logic_vector(data_temp(to_integer(tmw_to
signed(unsigned(addr) + 1, 32) - 1)));
ELSE

instr_out <= std_logic_vector(to_unsigned(0, 16));
END IF;

FOR c IN 0 TO 255 LOOP

data_next(c) <= data_temp(c);
END LOOP;
END PROCESS Instruction_ROM;
END fsm_SFHDL;

Пример 4. Память программ процессора
на языке VHDL

LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.numeric_std.all;
ENTITY Instruction_Register IS
PORT (
clk : IN std_logic;
clk_enable : IN std_logic;
reset : IN std_logic;

func : IN std_logic_vector(1 DOWNTO 0);
IR_in : IN std_logic_vector(15 DOWNTO 0);
IR_out : OUT std_logic_vector(15 DOWNTO 0));
END Instruction_Register;

ARCHITECTURE fsm_SFHDL OF Instruction_Register IS
SIGNAL IR_value : unsigned(15 DOWNTO 0);
SIGNAL IR_value_next : unsigned(15 DOWNTO 0);
BEGIN

initialize_Instruction_Register : PROCESS (reset, clk)

-- local variables
BEGIN
IF reset = '1' THEN

IR_value <= to_unsigned(0, 16);
ELSIF clk'EVENT AND clk= '1' THEN
IF clk_enable= '1' THEN

IR_value <= IR_value_next;
END IF;
END IF;

END PROCESS initialize_Instruction_Register;

Instruction_Register : PROCESS (IR_value, func, IR_in)

-- local variables
BEGIN
IR_value_next <= IR_value;

-- A 16-bit Instruction Register with the following func:
-- func == 0 => reset
-- func == 1 => store into IR
-- func == 2 => read from IR;
-- otherwise, preserve old value and return 0
IR_out <= std_logic_vector(to_unsigned(0, 16));
CASE func IS
WHEN "00" =>
-- reset

IR_value_next <= to_unsigned(0, 16);
WHEN "01" =>
-- store into IR

IR_value_next <= unsigned(IR_in);
WHEN "10" =>
-- read IR

IR_out <= std_logic_vector(IR_value);
WHEN OTHERS =>
NULL;
END CASE;
END PROCESS Instruction_Register;
END fsm_SFHDL;

Пример 5. Блок регистра инструкций процессора
на языке VHDL

LIBRARY ieee;

USE ieee.std_logic_1164.all;

USE ieee.numeric_std.all;

ENTITY RegisterA IS
PORT (
clk : IN std_logic;
clk_enable : IN std_logic;
reset : IN std_logic;

func : IN std_logic_vector(2 DOWNTO 0);
Reg_in_A_1 : IN std_logic_vector(7 DOWNTO 0);
Reg_in_A_2 : IN std_logic_vector(7 DOWNTO 0);
Reg_out_A : OUT std_logic_vector(7 DOWNTO 0));
END RegisterA;

ARCHITECTURE fsm_SFHDL OF RegisterA IS

SIGNAL Reg_value : unsigned(7 DOWNTO 0);
SIGNAL Reg_value_next : unsigned(7 DOWNTO 0);

BEGIN

initialize_RegisterA : PROCESS (reset, clk)

-- local variables
BEGIN
IF reset = '1' THEN

Reg_value <= to_unsigned(0, 8);
ELSIF clk'EVENT AND clk= '1' THEN
IF clk_enable= '1' THEN

Reg_value <= Reg_value_next;
END IF;
END IF;

END PROCESS initialize_RegisterA;

RegisterA : PROCESS (Reg_value, func, Reg_in_A_1, Reg_in_A_2)

-- local variables
BEGIN

Reg_value_next <= Reg_value;
-- func == 0 => reset;

-- func == 1 => store into RegisterA from port 1;
-- func == 2 => store into RegisterA from port 2;
-- func == 3 => read from RegisterA;
-- HDL specific fimath
Reg_out_A <= std_logic_vector(Reg_value);
CASE func IS
WHEN "000" =>
-- reset

Reg_value_next <= to_unsigned(0, 8);
WHEN "001" =>

-- store into Reg_A from port 1
Reg_value_next <= unsigned(Reg_in_A_1);
WHEN "010" =>

-- store into Reg_A from port 2
Reg_value_next <= unsigned(Reg_in_A_2);
WHEN "011" =>
-- read Reg_A

Reg_out_A <= std_logic_vector(Reg_value);
WHEN OTHERS =>
NULL;
END CASE;
END PROCESS RegisterA;
END fsm_SFHDL;

Пример 6. Блок регистра общего назначения A
процессора на языке VHDL

LIBRARY ieee;

USE ieee.std_logic_1164.all;

USE ieee.numeric_std.all;

ENTITY ALU IS
PORT (
clk : IN std_logic;
clk_enable : IN std_logic;
reset : IN std_logic;

func : IN std_logic_vector(3 DOWNTO 0);
inA : IN std_logic_vector(7 DOWNTO 0);
inB : IN std_logic_vector(7 DOWNTO 0);
outA : OUT std_logic_vector(7 DOWNTO 0);
outB : OUT std_logic_vector(7 DOWNTO 0));
END ALU;

ARCHITECTURE fsm_SFHDL OF ALU IS
-- TMW_TO_SIGNED

FUNCTION tmw_to_signed( arg: unsigned; width: integer) RETURN
signed IS
BEGIN

IF arg(arg'right) = 'U' OR arg(arg'right) = 'X' THEN

RETURN to_signed(1, width);
END IF;

RETURN to_signed(to_integer(arg), width);
END FUNCTION;

-- TMW_TO_UNSIGNED

FUNCTION tmw_to_unsigned(arg: signed; width integer) RETURN
unsigned IS

CONSTANT ARG_LEFT: INTEGER := ARG'LENGTH-1;
ALIAS XARG: SIGNED(ARG_LEFT downto 0) is ARG;
VARIABLE result : unsigned(width-1 DOWNTO 0);
VARIABLE argSize : integer;
BEGIN

IF XARG(XARG'high-1) = 'U' OR arg(arg'right) = 'X' THEN

RETURN to_unsigned(1, width);
END IF;

IF (ARG_LEFT < width-1) THEN
result := (OTHERS => XARG(ARG_LEFT));
result(ARG_LEFT downto 0) := unsigned(XARG);
ELSE

result(width-1 downto 0) := unsigned(XARG(width-1 downto 0));
END IF;
RETURN result;
END FUNCTION;

BEGIN

ALU : PROCESS (func, inA, inB)
-- local variables

VARIABLE X_temp : unsigned(7 DOWNTO 0);
VARIABLE ina_0 : unsigned(7 DOWNTO 0);
VARIABLE ina_1 : signed(8 DOWNTO 0);
VARIABLE ina_2 : signed(8 DOWNTO 0);
BEGIN

-- This 8-bit ALU supports the following operations:

-- MOV, XCHG, ADD, SUB, AND, OR, XOR, DEC

-- func = 0 => MOV A,B

-- func = 1 => MOV B,A

-- func = 2 => XCHG A,B

-- func = 3 => ADD A,B

-- func = 4 => SUB A,B

-- func = 5 => AND A,B

-- func = 6 => OR A,B

-- func = 7 => XOR A,B

-- func = 8 => DEC A

-- Simply pass the inA, when there is no designated func
outA <= inA;

-- Simply pass the inB, when there is no designated func
outB <= inB;
CASE func IS
WHEN "0000" =>
--MOV A,B
outA <= inB;
WHEN "0001" =>
--MOV B,A
outB <= inA;
WHEN "0010" =>
--XCHG A,B

X_temp := unsigned(inB);
outB <= inA;

outA <= std_logic_vector(X_temp);
WHEN "0011" =>
--ADD A,B

ina_0 := unsigned(inA) + unsigned(inB);
outA <= std_logic_vector(ina_0);
WHEN "0100" =>
--SUB A,B

ina_1 := tmw_to_signed(unsigned(inA), 9) - tmw_to_signed
(unsigned(inB), 9);

IF ina_1(8) = '1' THEN
outA <= "00000000";
ELSE

outA <= std_logic_vector(resize(unsigned(ina_1(7
DOWNTO 0)), 8));

END IF;
WHEN "0101" =>
--AND A,B

outA <= std_logic_vector(tmw_to_unsigned(tmw_to_
signed(unsigned(inA), 32) AND tmw_to_signed(unsigned(inB), 32), 8));
WHEN "0110" =>
--OR A,B

outA <= std_logic_vector(tmw_to_unsigned(tmw_to_
signed(unsigned(inA), 32) OR tmw_to_signed(unsigned(inB), 32), 8));
WHEN "0111" =>
--XOR A,B

outA <= std_logic_vector(tmw_to_unsigned(tmw_to_
signed(unsigned(inA), 32) XOR tmw_to_signed(unsigned(inB), 32), 8));
WHEN "1000" =>
--DEC A

ina_2 := tmw_to_signed(unsigned(inA), 9) - 1;
IF ina_2(8) = '1' THEN
outA <= "00000000";
ELSE

outA <= std_logic_vector(resize(unsigned(ina_2(7
DOWNTO 0)), 8));

END IF;
WHEN OTHERS =>
NULL;
END CASE;
END PROCESS ALU;

END fsm_SFHDL;
Пример 7. Блок АЛУ процессора на языке VHDL

Процессор, позволяющий проводить вычисления в формате с фиксированной запятой, код языка которого был получен с использованием Simulink HDL Coder системы визуального имитационного моделирования MATLAB/ Simulink [2], показал свою работоспособность в САПР Quartus II компании Altera. Процессор может быть успешно размещен в ПЛИС Stratix III EP3SL50F484C2 и занимает менее 1% ресурсов адаптивных таблиц перекодировок (ALUT, 209) для реализации комбинационной логики и менее 1% ресурсов последовательностной логики (регистров, 105).

Автоматически сгенерированный код языка VHDL c использованием Simulink HDL Coder системы MATLAB/Simulink позволяет значительно ускорить процесс разработки пользовательских процессорных ядер, для реализации их в базисе ПЛИС.

К недостаткам этого кода следует отнести наличие достаточно большого числа явных преобразований тесно связанных между собой типов, что определяется форматом представления исходных данных системы MATLAB/Simulink.

Литература

  1. Тарасов И. Проектирование конфигурируемых процессоров на базе ПЛИС. Часть I // Компоненты и технологии. 2006. № 2.
  2. Строгонов А. Проектирование учебного процессора с фиксированной запятой в системе MATLAB/Simulink // Компоненты и технологии. 2009. № 7.
  3. Cуворова Е. А., Шейнин Ю. Е. Проектирование цифровых систем на VHDL. СПб.: БХВ-Петербург, 2003.
  4. Поляков А. К. Языки VHDL и VERILOG в проектировании цифровой аппаратуры. М.: СОЛОН-Пресс, 2003.
  5. Уэйкерли Дж. Ф. Проектирование цифровых устройств. Том 2. М.: Постмаркет, 2002.

Скачать статью в формате PDF  Скачать статью Компоненты и технологии PDF

 


Другие статьи по данной теме:

Сообщить об ошибке