Начинаю с файла определений типов используемых шин и сигналов - файл mydef.vhd:
Код:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
USE IEEE.std_logic_unsigned.all;
package mydef2 is
subtype node is std_logic;
constant vcc : std_logic := '1';
constant gnd : std_logic := '0';
subtype WORD is std_logic_vector ( 15 downto 0);
constant zero16 : word := "0000000000000000";
subtype BYTE is std_logic_vector ( 7 downto 0);
constant zero8 : byte := "00000000";
SUBTYPE NIBBLE IS STD_LOGIC_VECTOR (3 DOWNTO 0);
SUBTYPE DWORD is std_logic_vector ( 31 downto 0);
end mydef2;
--package body mydef2 is
--
--end;
Второй файл - собственно процессор (с 4-хбитной командой, ес-сна) CPU2012.vhd:
Код:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
USE IEEE.std_logic_unsigned.all;
use WORK.mydef2.all;
entity CPU2012 IS
PORT(
CLK : IN NODE;
CLKO : OUT NODE;
DI : IN WORD;
DO : OUT WORD;
ADR : OUT WORD;
MRD, MWR : OUT NODE
-- TEST_CMDR :OUT WORD
);
END CPU2012;
ARCHITECTURE RTL OF CPU2012 IS
CONSTANT NOP_C : NIBBLE := "0000"; -- loading CMD register
CONSTANT LIT_C : NIBBLE := "0001"; -- loading literal
CONSTANT CALL_C : NIBBLE := "0010"; -- call subprogram
CONSTANT RET_C : NIBBLE := "0011"; -- return from subprogram
CONSTANT PRISW_C : NIBBLE := "0100";-- !
CONSTANT RAZIM_C : NIBBLE := "0101";-- @
CONSTANT DROP_C : NIBBLE := "0110"; -- drop like operations
CONSTANT DUP_C : NIBBLE := "0111"; -- dup like operations
CONSTANT SWAP_C : NIBBLE := "1000"; -- swap like operations
CONSTANT TOR_C : NIBBLE := "1001"; -- >R
CONSTANT FROMR_C : NIBBLE := "1010";-- R>
CONSTANT StackDepth : integer :=9;
TYPE STACK_T IS ARRAY (0 TO StackDepth-1)OF WORD;
TYPE CPU_T IS RECORD
PC, TOP, CMD : WORD;
RST,DST : STACK_T;
ADR,DO : WORD;
MRD,MWR : NODE;
DUP_PRECALC,DROP_PRECALC,SWAP1_PRECALC, SWAP2_PRECALC : WORD;
MUL_PRECALC : DWORD;
END RECORD;
SIGNAL CPU : CPU_T;
FUNCTION PUSH(ST:STACK_T; DATA:WORD) RETURN STACK_T IS
VARIABLE NEW_ST : STACK_T;
BEGIN
NEW_ST := ST;
NEW_ST(0) := DATA;
NEW_ST(1 TO StackDepth-1) := ST(0 TO StackDepth-2);
RETURN NEW_ST;
END;
FUNCTION POP(ST:STACK_T) RETURN STACK_T IS
VARIABLE NEW_ST : STACK_T;
BEGIN
NEW_ST(StackDepth-1) := ZERO16;
NEW_ST(0 TO StackDepth-2) := ST(1 TO StackDepth-1);
RETURN NEW_ST;
END;
function MAIN_CPU(CPU: CPU_T;DI:WORD) RETURN CPU_T IS
VARIABLE NEW_CPU : CPU_T;
BEGIN
NEW_CPU := CPU;
NEW_CPU.DROP_PRECALC := CPU.DST(0);
NEW_CPU.DUP_PRECALC :=CPU.TOP;
NEW_CPU.CMD := CPU.CMD(11 DOWNTO 0)&NOP_C;
NEW_CPU.ADR := CPU.PC;
NEW_CPU.DO := CPU.TOP;
NEW_CPU.MRD := GND;
NEW_CPU.MWR := GND;
CASE (CPU.CMD(15 DOWNTO 12)) IS
WHEN NOP_C =>
NEW_CPU.CMD := DI;
NEW_CPU.PC := CPU.PC+1;
NEW_CPU.MRD:= VCC;
WHEN LIT_C =>
NEW_CPU.TOP := DI;
NEW_CPU.DST := PUSH(CPU.DST,CPU.TOP);
NEW_CPU.PC := CPU.PC+1;
NEW_CPU.MRD:= VCC;
WHEN CALL_C =>
NEW_CPU.PC := DI;
NEW_CPU.MRD:= VCC;
NEW_CPU.RST :=PUSH(CPU.RST,CPU.PC);
NEW_CPU.CMD := ZERO16;
WHEN RET_C =>
NEW_CPU.PC :=CPU.RST(0);
NEW_CPU.RST :=POP(CPU.RST);
NEW_CPU.CMD := ZERO16;
WHEN PRISW_C =>
NEW_CPU.ADR :=CPU.TOP;
NEW_CPU.DO := CPU.DST(0);
NEW_CPU.MWR := VCC;
NEW_CPU.RST :=POP(POP(CPU.RST));
NEW_CPU.TOP := CPU.DST(2);
WHEN RAZIM_C =>
NEW_CPU.ADR :=CPU.TOP;
NEW_CPU.TOP := DI;
NEW_CPU.MRD:= VCC;
WHEN DROP_C =>
-- NEW_CPU.TOP := CPU.DROP_PRECALC;
NEW_CPU.TOP := CPU.DST(0);
NEW_CPU.DST := POP(CPU.DST);
WHEN DUP_C =>
--NEW_CPU.DST := PUSH(CPU.DST,CPU.DUP_PRECALC);
NEW_CPU.DST := PUSH(CPU.DST,CPU.TOP);
WHEN SWAP_C =>
NEW_CPU.DST(0) := CPU.TOP;
NEW_CPU.TOP := CPU.DST(0);
WHEN TOR_C =>
NEW_CPU.DST := POP(CPU.DST);
NEW_CPU.TOP := CPU.DST(0);
NEW_CPU.RST := PUSH(CPU.RST,CPU.TOP);
WHEN FROMR_C =>
NEW_CPU.RST := POP(CPU.RST);
NEW_CPU.TOP := CPU.RST(0);
NEW_CPU.DST := PUSH(CPU.DST,CPU.TOP);
WHEN OTHERS => NULL;
END CASE;
RETURN NEW_CPU;
END;
BEGIN
CLKO <= CLK;
PROCESS (CLK)BEGIN
IF CLK'EVENT AND CLK = VCC THEN
CPU <= MAIN_CPU(CPU,DI);
END IF;
ADR <= MAIN_CPU(CPU,DI).ADR;
DO <= MAIN_CPU(CPU,DI).DO;
MRD <= MAIN_CPU(CPU,DI).MRD;
MWR <= MAIN_CPU(CPU,DI).MWR;
-- TEST_CMDR <= CPU.CMD;
END PROCESS;
END;
система команд -немного измененная система команд процессора
EQUINOXрегистры процессора с суфиксом PRECALC введены с рассчетом на дальнейшую конвееризацию префиксных операций
Дополнительно предполагаю ввести дифференциацию вызовов подпрограмм по старшему биту адреса. команда
RET будет по-разному работать в зависимости от адреса исполнения. Если в младшей половине памяти - то это обычный
RET, если в старшей, будет исполняться
NEXT (RET-CALL), что позволит вызывать форт-слова как подпрограммы.