--- /dev/null
+--------------------------------------------------------------------------------
+--
+-- +---+ +---+ +---+ +---+ +---+
+-- | T | | R | |MDR| | I | |PC |
+-- +---+ +---+ +---+ +---+ +---+
+-- | N | : :
+-- +---+
+-- : :
+--
+--------------------------------------------------------------------------------
+-- WISHBONE DATASHEET
+--
+-- Wishbone specification used: Rev B.3
+-- Interface type: master
+-- Port size: 8-bit
+-- Operand sizes: 8-bit, 32-bit
+-- Endianness: little
+-- Data transfer sequence: undefined
+-- Clock constraints: none
+-- Signals:
+-- * rst_i
+-- * clk_i
+-- * cyc_o
+-- * stb_o
+-- * we_o
+-- * ack_i
+-- * adr_o (32-bit)
+-- * dat_i (8-bit)
+-- * dat_o (8-bit)
+--------------------------------------------------------------------------------
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.std_logic_misc.all;
+use ieee.numeric_std.all;
+
+library unisim;
+use unisim.vcomponents.all;
+
+
+entity cpu_opt is
+ port (
+ rst_i: in std_logic;
+ clk_i: in std_logic;
+
+ cyc_o: out std_logic;
+ stb_o: out std_logic;
+ we_o: out std_logic;
+ ack_i: in std_logic;
+ adr_o: out std_logic_vector(31 downto 0);
+ dat_o: out std_logic_vector(7 downto 0);
+ dat_i: in std_logic_vector(7 downto 0);
+
+ int_i: in std_logic;
+ vec_i: in std_logic_vector(7 downto 0);
+
+ -- Debugging
+ halt_i: in std_logic;
+ step_i: in std_logic;
+ pc_o: out std_logic_vector(31 downto 0);
+ ins_o: out std_logic_vector(7 downto 0);
+ t_o: out std_logic_vector(31 downto 0);
+ n_o: out std_logic_vector(31 downto 0);
+ r_o: out std_logic_vector(31 downto 0)
+ );
+end cpu_opt;
+
+
+architecture behavioral of cpu_opt is
+
+ type state_t is (
+ S_WAIT, S_FETCH2,
+ S_RESET, S_FETCH, S_MEMORY,
+ S_IMM32_0, S_IMM32_1, S_IMM32_2, S_IMM32_3,
+ S_LD8, S_LD32_0, S_LD32_1, S_LD32_2, S_LD32_3,
+ S_ST8, S_ST32_0, S_ST32_1, S_ST32_2, S_ST32_3,
+ S_EXEC, S_INT
+ );
+
+ type mem_op_t is (MEM_IMM, MEM_LD, MEM_ST, MEM_NONE);
+ type adr_sel_t is (ADR_PC, ADR_T, ADR_T0, ADR_T1, ADR_T2, ADR_T3);
+ type dat_sel_t is (DAT_N0, DAT_N1, DAT_N2, DAT_N3);
+ -- type alu_op_t is (ALU_T, ALU_N, ALU_ADD, ALU_SUB, ALU_AND, ALU_OR, ALU_XOR, ALU_NOT, ALU_R, ALU_MDR, ALU_INTVEC);
+ type r_sel_t is (R_T, R_PC, R_NC);
+ type pc_sel_t is (PC_MDR, PC_R, PC_INC, PC_NC, PC_INTVEC);
+ type stackop_t is (ST_INC, ST_DEC, ST_NC);
+ type cond_t is (C_NEG, C_ZERO, C_POS, C_NONE);
+
+ constant D_NC: std_logic_vector(1 downto 0) := "00";
+ constant D_DEC: std_logic_vector(1 downto 0) := "01";
+ constant D_INC: std_logic_vector(1 downto 0) := "10";
+ constant D_PSH: std_logic_vector(1 downto 0) := "11";
+
+ constant ALU_M8: std_logic_vector(3 downto 0) := "0000";
+ constant ALU_M32: std_logic_vector(3 downto 0) := "0001";
+ constant ALU_N8: std_logic_vector(3 downto 0) := "0010";
+ constant ALU_N32: std_logic_vector(3 downto 0) := "0011";
+ constant ALU_Tx: std_logic_vector(3 downto 0) := "0100"; -- \_ for setting/clearing iflag with bit 0
+ constant ALU_T: std_logic_vector(3 downto 0) := "0101"; -- /
+ constant ALU_ADD: std_logic_vector(3 downto 0) := "0110";
+ constant ALU_SUB: std_logic_vector(3 downto 0) := "0111";
+ constant ALU_AND: std_logic_vector(3 downto 0) := "1000";
+ constant ALU_OR: std_logic_vector(3 downto 0) := "1001";
+ constant ALU_XOR: std_logic_vector(3 downto 0) := "1010";
+ constant ALU_NOT: std_logic_vector(3 downto 0) := "1011";
+ constant ALU_VEC: std_logic_vector(3 downto 0) := "1100";
+ constant ALU_R: std_logic_vector(3 downto 0) := "1101";
+
+ type instr_decode_t is record
+ -- Memory operation
+ mem_op: mem_op_t;
+
+ -- Stack updates
+ --s_op: stackop_t;
+ s_op: std_logic_vector(1 downto 0);
+ r_op: stackop_t;
+
+ -- Datapath multiplexion
+ --alu_op: alu_op_t; -- selects new T
+ --alu_op: std_logic_vector(3 downto 0);
+ --t_to_n: std_logic; -- T->N (push)
+ r_sel: r_sel_t; -- selects new R
+ pc_sel: pc_sel_t; -- selects new PC
+
+ imask_set: std_logic;
+ --imask_clr: std_logic;
+ --cond: cond_t;
+ end record;
+
+ -- Control FSM
+ signal state_reg: state_t;
+ signal state_next: state_t;
+ signal adr_sel: adr_sel_t;
+
+ -- Instruction register
+ signal ins_reg: std_logic_vector(7 downto 0);
+ signal ins_ld: std_logic;
+ signal ins_decode: instr_decode_t;
+ signal dat_sel: dat_sel_t;
+
+ -- Program counter
+ signal pc_reg: std_logic_vector(31 downto 0);
+ signal pc_next: std_logic_vector(31 downto 0);
+ signal pc_sel: pc_sel_t;
+
+ -- Memory data register
+ signal mdr_reg: std_logic_vector(31 downto 0);
+ signal mdr_ld_0: std_logic;
+ signal mdr_ld_1: std_logic;
+ signal mdr_ld_2: std_logic;
+ signal mdr_ld_3: std_logic;
+
+ -- Parameter stack
+ signal s_ptr_reg: unsigned(7 downto 0);
+ signal s_ptr_next: unsigned(7 downto 0);
+ signal s_ptr_op: std_logic_vector(1 downto 0);
+ signal s_ptr_ld: std_logic;
+ signal s_write: std_logic;
+ signal s_n_reg: std_logic_vector(31 downto 0);
+ signal s_t_reg: std_logic_vector(31 downto 0);
+ signal s_t_new: std_logic_vector(31 downto 0);
+ signal s_t_ld: std_logic;
+
+ -- Return stack
+ signal r_ptr_reg: unsigned(7 downto 0);
+ signal r_ptr_next: unsigned(7 downto 0);
+ signal r_ptr_op: stackop_t;
+ signal r_ptr_ld: std_logic;
+ signal r_write: std_logic;
+ signal r_tos_reg: std_logic_vector(31 downto 0);
+ signal r_tos_new: std_logic_vector(31 downto 0);
+
+ signal addra: std_logic_vector(8 downto 0);
+ signal addrb: std_logic_vector(8 downto 0);
+
+ -- Kludged-in to allow S_INT logic to override the values from ins_decode
+ signal r_sel: r_sel_t;
+ signal alu_op: std_logic_vector(3 downto 0); -- alu_op_t;
+ signal imask_reg: std_logic;
+ signal imask_set: std_logic;
+ signal imask_clr: std_logic;
+
+ signal n: std_logic;
+ signal z: std_logic;
+ signal p: std_logic;
+ signal cond_n: std_logic;
+ signal cond_z: std_logic;
+ signal cond_p: std_logic;
+ signal cond: std_logic;
+ signal ins_pc_sel: pc_sel_t;
+
+ signal t_to_n: std_logic;
+ signal wordsize: std_logic;
+ signal ins_decode_alu_op: std_logic_vector(3 downto 0);
+
+begin
+
+ -- Debugging signals
+ pc_o <= pc_reg;
+ ins_o <= ins_reg;
+ t_o <= s_t_reg;
+ n_o <= s_n_reg;
+ r_o <= r_tos_reg;
+
+ -- Control state machine
+ process (rst_i, clk_i, state_next)
+ begin
+ if rising_edge(clk_i) then
+ if rst_i = '1' then
+ state_reg <= S_RESET;
+ else
+ state_reg <= state_next;
+ end if;
+ end if;
+ end process;
+
+ process (state_reg, ack_i, ins_decode, int_i, ins_pc_sel, imask_reg, step_i, halt_i, wordsize, t_to_n, ins_decode_alu_op)
+ begin
+ state_next <= state_reg;
+ cyc_o <= '0';
+ stb_o <= '0';
+ we_o <= '0';
+ adr_sel <= ADR_PC;
+ ins_ld <= '0';
+ pc_sel <= PC_NC;
+ mdr_ld_0 <= '0';
+ mdr_ld_1 <= '0';
+ mdr_ld_2 <= '0';
+ mdr_ld_3 <= '0';
+ dat_sel <= DAT_N0;
+ s_t_ld <= '0';
+ s_write <= '0';
+ r_write <= '0';
+ s_ptr_op <= D_NC;
+ r_ptr_op <= ST_NC;
+ s_ptr_ld <= '0';
+ r_ptr_ld <= '0';
+ r_sel <= ins_decode.r_sel;
+ alu_op <= ins_decode_alu_op;
+ imask_set <= ins_decode.imask_set; --'0';
+
+ case state_reg is
+ when S_FETCH =>
+ if halt_i = '0' then
+ state_next <= S_FETCH2;
+ elsif step_i = '0' then
+ state_next <= S_WAIT;
+ end if;
+ when S_WAIT =>
+ if step_i = '1' then
+ state_next <= S_FETCH2;
+ end if;
+ when S_FETCH2 =>
+ adr_sel <= ADR_PC;
+ cyc_o <= '1';
+ stb_o <= '1';
+ ins_ld <= '1';
+
+ if ack_i = '1' then
+ pc_sel <= PC_INC;
+ state_next <= S_MEMORY;
+ end if;
+
+ when S_MEMORY =>
+ -- Mask interrupts now if the instruction requests it
+ -- The mask flag register will be set in the following clock cycle,
+ -- so this prevents us from having to check ins_decode.imask_set
+ -- in the S_EXEC state, which would otherwise be necessary to make
+ -- sure we don't enter an interrupt after a "mask-int" instruction
+ -- and then return with interrupts unmasked into a critical section
+ --imask_clr <= ins_decode.imask_clr;
+
+ if wordsize = '1' then
+ case ins_decode.mem_op is
+ when MEM_IMM => state_next <= S_IMM32_0;
+ when MEM_LD => state_next <= S_LD32_0;
+ when MEM_ST => state_next <= S_ST32_0;
+ when others => state_next <= S_EXEC;
+ end case;
+ else
+ case ins_decode.mem_op is
+ when MEM_IMM => state_next <= S_IMM32_0;
+ when MEM_LD => state_next <= S_LD8;
+ when MEM_ST => state_next <= S_ST8;
+ when others => state_next <= S_EXEC;
+ end case;
+ end if;
+
+ when S_IMM32_0 =>
+ adr_sel <= ADR_PC;
+ cyc_o <= '1';
+ stb_o <= '1';
+ mdr_ld_0 <= '1';
+
+ if ack_i = '1' then
+ pc_sel <= PC_INC;
+ if wordsize = '1' then
+ state_next <= S_IMM32_1;
+ else
+ state_next <= S_EXEC;
+ end if;
+ end if;
+
+ when S_IMM32_1 =>
+ adr_sel <= ADR_PC;
+ cyc_o <= '1';
+ stb_o <= '1';
+ mdr_ld_1 <= '1';
+
+ if ack_i = '1' then
+ pc_sel <= PC_INC;
+ state_next <= S_IMM32_2;
+ end if;
+
+ when S_IMM32_2 =>
+ adr_sel <= ADR_PC;
+ cyc_o <= '1';
+ stb_o <= '1';
+ mdr_ld_2 <= '1';
+
+ if ack_i = '1' then
+ pc_sel <= PC_INC;
+ state_next <= S_IMM32_3;
+ end if;
+
+ when S_IMM32_3 =>
+ adr_sel <= ADR_PC;
+ cyc_o <= '1';
+ stb_o <= '1';
+ mdr_ld_3 <= '1';
+
+ if ack_i = '1' then
+ pc_sel <= PC_INC;
+ state_next <= S_EXEC;
+ end if;
+
+ when S_LD8 =>
+ adr_sel <= ADR_T;
+ cyc_o <= '1';
+ stb_o <= '1';
+ mdr_ld_0 <= '1';
+
+ if ack_i = '1' then
+ state_next <= S_EXEC;
+ end if;
+
+ when S_LD32_0 =>
+ adr_sel <= ADR_T0;
+ cyc_o <= '1';
+ stb_o <= '1';
+ mdr_ld_0 <= '1';
+
+ if ack_i = '1' then
+ state_next <= S_LD32_1;
+ end if;
+
+ when S_LD32_1 =>
+ adr_sel <= ADR_T1;
+ cyc_o <= '1';
+ stb_o <= '1';
+ mdr_ld_1 <= '1';
+
+ if ack_i = '1' then
+ state_next <= S_LD32_2;
+ end if;
+
+ when S_LD32_2 =>
+ adr_sel <= ADR_T2;
+ cyc_o <= '1';
+ stb_o <= '1';
+ mdr_ld_2 <= '1';
+
+ if ack_i = '1' then
+ state_next <= S_LD32_3;
+ end if;
+
+ when S_LD32_3 =>
+ adr_sel <= ADR_T3;
+ cyc_o <= '1';
+ stb_o <= '1';
+ mdr_ld_3 <= '1';
+
+ if ack_i = '1' then
+ state_next <= S_EXEC;
+ end if;
+
+ when S_ST8 =>
+ adr_sel <= ADR_T;
+ cyc_o <= '1';
+ stb_o <= '1';
+ we_o <= '1';
+ dat_sel <= DAT_N0;
+
+ if ack_i = '1' then
+ state_next <= S_EXEC;
+ end if;
+
+ when S_ST32_0 =>
+ adr_sel <= ADR_T0;
+ cyc_o <= '1';
+ stb_o <= '1';
+ we_o <= '1';
+ dat_sel <= DAT_N0;
+
+ if ack_i = '1' then
+ state_next <= S_ST32_1;
+ end if;
+
+ when S_ST32_1 =>
+ adr_sel <= ADR_T1;
+ cyc_o <= '1';
+ stb_o <= '1';
+ we_o <= '1';
+ dat_sel <= DAT_N1;
+
+ if ack_i = '1' then
+ state_next <= S_ST32_2;
+ end if;
+
+ when S_ST32_2 =>
+ adr_sel <= ADR_T2;
+ cyc_o <= '1';
+ stb_o <= '1';
+ we_o <= '1';
+ dat_sel <= DAT_N2;
+
+ if ack_i = '1' then
+ state_next <= S_ST32_3;
+ end if;
+
+ when S_ST32_3 =>
+ adr_sel <= ADR_T3;
+ cyc_o <= '1';
+ stb_o <= '1';
+ we_o <= '1';
+ dat_sel <= DAT_N3;
+
+ if ack_i = '1' then
+ state_next <= S_EXEC;
+ end if;
+
+ when S_EXEC =>
+ -- At this point, MDR will contain any immediate or loaded value and any stores have been performed
+
+ -- Load T with new value
+ s_t_ld <= '1';
+
+ -- Load N with new value
+ --if ins_decode.t_to_n = '1' then
+ if t_to_n = '1' then
+ s_write <= '1';
+ end if;
+
+ -- Load R with new value
+ if ins_decode.r_sel /= R_NC then
+ r_write <= '1';
+ end if;
+
+ -- Load PC with new value
+ -- ins_pc_sel includes conditions
+ pc_sel <= ins_pc_sel;
+
+ -- Use updated stack pointers
+ s_ptr_op <= ins_decode.s_op;
+ r_ptr_op <= ins_decode.r_op;
+ s_ptr_ld <= '1';
+ r_ptr_ld <= '1';
+
+ -- Clear the interrupt mask flag if necessary
+ -- The flag will be cleared in the next clock cycle, so the next
+ -- instruction is guaranteed to be executed if an interrupt is
+ -- pending, useful for clearing the interrupt flag and then returning
+ --imask_set <= ins_decode.imask_set;
+
+ -- Check for interrupts during the execute step so we don't have any in-progress memory operations to cancel
+ if int_i = '1' and imask_reg = '1' then
+ state_next <= S_INT;
+ else
+ state_next <= S_FETCH;
+ end if;
+
+ when S_INT =>
+ -- Load T with the vector value, load N with old T, push down the stack
+ alu_op <= ALU_VEC;
+ s_t_ld <= '1';
+ s_write <= '1';
+ s_ptr_op <= D_INC;
+ s_ptr_ld <= '1';
+
+ -- Push PC onto the return stack
+ r_sel <= R_PC;
+ r_write <= '1';
+ r_ptr_op <= ST_INC;
+ r_ptr_ld <= '1';
+
+ -- Load PC with the vector address
+ pc_sel <= PC_INTVEC;
+
+ -- Mask further interruptions
+ imask_clr <= '1';
+
+ state_next <= S_FETCH;
+
+ when S_RESET =>
+ state_next <= S_FETCH;
+
+ when others =>
+ state_next <= S_FETCH;
+ end case;
+ end process;
+
+
+ -- Interrupt mask flag
+ process (rst_i, clk_i, imask_set, imask_clr)
+ begin
+ if rising_edge(clk_i) then
+ if rst_i = '1' then
+ imask_reg <= '0';
+ elsif imask_set = '1' then
+ imask_reg <= wordsize;
+ end if;
+ end if;
+ end process;
+
+
+ -- Program counter
+ cond <= (cond_n and n) or (cond_z and z) or (cond_p and p);
+ process (cond, ins_decode)
+ begin
+ if ins_decode.pc_sel = PC_MDR and cond = '0' then
+ ins_pc_sel <= PC_NC;
+ else
+ ins_pc_sel <= ins_decode.pc_sel;
+ end if;
+
+ --if ins_decode.cond = C_NONE then
+ -- ins_pc_sel <= ins_decode.pc_sel;
+ --elsif ins_decode.cond = C_NEG then
+ -- if n = '1' then
+ -- ins_pc_sel <= ins_decode.pc_sel;
+ -- else
+ -- ins_pc_sel <= PC_NC;
+ -- end if;
+ --elsif ins_decode.cond = C_ZERO then
+ -- if z = '1' then
+ -- ins_pc_sel <= ins_decode.pc_sel;
+ -- else
+ -- ins_pc_sel <= PC_NC;
+ -- end if;
+ --elsif ins_decode.cond = C_POS then
+ -- if p = '1' then
+ -- ins_pc_sel <= ins_decode.pc_sel;
+ -- else
+ -- ins_pc_sel <= PC_NC;
+ -- end if;
+ --end if;
+ end process;
+
+ with pc_sel select pc_next <=
+ mdr_reg when PC_MDR,
+ r_tos_reg when PC_R,
+ std_logic_vector(unsigned(pc_reg) + 1) when PC_INC,
+ (others => '0') when PC_INTVEC,
+ pc_reg when others;
+
+ process (rst_i, clk_i, pc_reg, pc_next)
+ begin
+ if rising_edge(clk_i) then
+ if rst_i = '1' then
+ pc_reg <= (others => '0');
+ else
+ pc_reg <= pc_next;
+ end if;
+ end if;
+ end process;
+
+
+ -- Instruction register and decode
+ process (clk_i, ins_ld, dat_i)
+ begin
+ if rising_edge(clk_i) then
+ if ins_ld = '1' then
+ ins_reg <= dat_i;
+ end if;
+ end if;
+ end process;
+
+ with ins_reg(3 downto 0) select ins_decode <=
+ ( -- #8, #32
+ mem_op => MEM_IMM,
+ s_op => D_INC,
+ r_op => ST_NC,
+ r_sel => R_NC,
+ pc_sel => PC_NC,
+ imask_set => '0'
+ ) when "0001",
+ ( -- @8, @32
+ mem_op => MEM_LD,
+ s_op => D_NC,
+ r_op => ST_NC,
+ r_sel => R_NC,
+ pc_sel => PC_NC,
+ imask_set => '0'
+ ) when "0010",
+ ( -- !8, !32
+ mem_op => MEM_ST,
+ s_op => D_DEC,
+ r_op => ST_NC,
+ r_sel => R_NC,
+ pc_sel => PC_NC,
+ imask_set => '0'
+ ) when "0011",
+ ( -- r@, DUP
+ mem_op => MEM_NONE,
+ s_op => D_INC,
+ r_op => ST_NC,
+ r_sel => R_NC,
+ pc_sel => PC_NC,
+ imask_set => '0'
+ ) when "0100",
+ ( -- +, -, &, |, ^, DROP
+ mem_op => MEM_NONE,
+ s_op => D_DEC,
+ r_op => ST_NC,
+ r_sel => R_NC,
+ pc_sel => PC_NC,
+ imask_set => '0'
+ ) when "0101",
+ ( -- >r
+ mem_op => MEM_NONE,
+ s_op => D_DEC,
+ r_op => ST_INC,
+ r_sel => R_T,
+ pc_sel => PC_NC,
+ imask_set => '0'
+ ) when "0110",
+ ( -- r>
+ mem_op => MEM_NONE,
+ s_op => D_INC,
+ r_op => ST_DEC,
+ r_sel => R_NC,
+ pc_sel => PC_NC,
+ imask_set => '0'
+ ) when "1000",
+ ( -- call
+ mem_op => MEM_IMM,
+ s_op => D_NC,
+ r_op => ST_INC,
+ r_sel => R_PC,
+ pc_sel => PC_MDR,
+ imask_set => '0'
+ ) when "0111",
+ ( -- ;
+ mem_op => MEM_NONE,
+ s_op => D_NC,
+ r_op => ST_DEC,
+ r_sel => R_NC,
+ pc_sel => PC_R,
+ imask_set => '0'
+ ) when "1101",
+ ( -- jmp
+ mem_op => MEM_IMM,
+ s_op => D_NC,
+ r_op => ST_NC,
+ r_sel => R_NC,
+ pc_sel => PC_MDR,
+ imask_set => '0'
+ ) when "1111",
+ ( -- jz
+ mem_op => MEM_IMM,
+ s_op => D_DEC,
+ r_op => ST_NC,
+ r_sel => R_NC,
+ pc_sel => PC_MDR,
+ imask_set => '0'
+ ) when "1010",
+ ( -- jn
+ mem_op => MEM_IMM,
+ s_op => D_DEC,
+ r_op => ST_NC,
+ r_sel => R_NC,
+ pc_sel => PC_MDR,
+ imask_set => '0'
+ ) when "1001",
+ ( -- jp
+ mem_op => MEM_IMM,
+ s_op => D_DEC,
+ r_op => ST_NC,
+ r_sel => R_NC,
+ pc_sel => PC_MDR,
+ imask_set => '0'
+ ) when "1100",
+ ( -- SWAP
+ mem_op => MEM_NONE,
+ s_op => D_PSH,
+ r_op => ST_NC,
+ r_sel => R_NC,
+ pc_sel => PC_NC,
+ imask_set => '0'
+ ) when "1110",
+ ( -- imask_set, imask_clr
+ mem_op => MEM_NONE,
+ s_op => D_NC,
+ r_op => ST_NC,
+ r_sel => R_NC,
+ pc_sel => PC_NC,
+ imask_set => '1'
+ ) when "1011",
+ ( -- NOP, ~
+ mem_op => MEM_NONE,
+ s_op => D_NC,
+ r_op => ST_NC,
+ r_sel => R_NC,
+ pc_sel => PC_NC,
+ imask_set => '0'
+ ) when others;
+
+ t_to_n <= ins_decode.s_op(1);
+ ins_decode_alu_op <= ins_reg(7 downto 4);
+ wordsize <= ins_decode_alu_op(0);
+ cond_n <= ins_reg(0);
+ cond_z <= ins_reg(1);
+ cond_p <= ins_reg(2);
+
+
+ -- Address multiplexer
+ with adr_sel select adr_o <=
+ pc_reg when ADR_PC,
+ s_t_reg when ADR_T,
+ s_t_reg(31 downto 2) & "00" when ADR_T0,
+ s_t_reg(31 downto 2) & "01" when ADR_T1,
+ s_t_reg(31 downto 2) & "10" when ADR_T2,
+ s_t_reg(31 downto 2) & "11" when ADR_T3,
+ (others => '0') when others;
+
+
+ -- Memory data register
+ process (clk_i, mdr_ld_0, mdr_ld_1, mdr_ld_2, mdr_ld_3)
+ begin
+ if rising_edge(clk_i) then
+ if mdr_ld_0 = '1' then
+ -- Zero-extend for 8-bit loads
+ -- Zeroes will be overwritten for 32-bit loads
+ mdr_reg( 7 downto 0) <= dat_i;
+ mdr_reg(31 downto 8) <= (others => '0');
+ elsif mdr_ld_1 = '1' then
+ mdr_reg(15 downto 8) <= dat_i;
+ elsif mdr_ld_2 = '1' then
+ mdr_reg(23 downto 16) <= dat_i;
+ elsif mdr_ld_3 = '1' then
+ mdr_reg(31 downto 24) <= dat_i;
+ end if;
+ end if;
+ end process;
+
+ with dat_sel select dat_o <=
+ s_n_reg(31 downto 24) when DAT_N3,
+ s_n_reg(23 downto 16) when DAT_N2,
+ s_n_reg(15 downto 8) when DAT_N1,
+ s_n_reg( 7 downto 0) when others;
+
+
+ -- ALU
+ with alu_op select s_t_new <=
+ s_t_reg when ALU_T,
+ s_t_reg when ALU_Tx,
+ s_n_reg when ALU_N8,
+ s_n_reg when ALU_N32,
+ std_logic_vector(signed(s_t_reg) + signed(s_n_reg)) when ALU_ADD,
+ std_logic_vector(signed(s_t_reg) - signed(s_n_reg)) when ALU_SUB,
+ s_t_reg and s_n_reg when ALU_AND,
+ s_t_reg or s_n_reg when ALU_OR,
+ s_t_reg xor s_n_reg when ALU_XOR,
+ not s_t_reg when ALU_NOT,
+ r_tos_reg when ALU_R,
+ mdr_reg when ALU_M8,
+ mdr_reg when ALU_M32,
+ x"000000" & vec_i when ALU_VEC,
+ (others => '0') when others;
+
+
+ -- Next R
+ with r_sel select r_tos_new <=
+ s_t_reg when R_T,
+ pc_reg when R_PC,
+ r_tos_reg when others;
+
+
+ -- Stack memory
+ p_s_tos: process (clk_i, s_t_ld, s_t_new)
+ begin
+ if rising_edge(clk_i) then
+ if rst_i = '1' then
+ -- Reset to zero as the "reset vector"
+ s_t_reg <= (others => '0');
+ elsif s_t_ld = '1' then
+ s_t_reg <= s_t_new;
+ end if;
+ end if;
+ end process;
+
+ n <= s_t_reg(s_t_reg'high);
+ z <= not or_reduce(s_t_reg);
+ p <= (not n) and (not z);
+
+ p_s_ptr: process (rst_i, clk_i, s_ptr_ld, s_ptr_next)
+ begin
+ if rising_edge(clk_i) then
+ if rst_i = '1' then
+ s_ptr_reg <= (others => '0');
+ else
+ if s_ptr_ld = '1' then
+ s_ptr_reg <= s_ptr_next;
+ end if;
+ end if;
+ end if;
+ end process;
+
+ with s_ptr_op select s_ptr_next <=
+ s_ptr_reg + 1 when D_INC,
+ s_ptr_reg - 1 when D_DEC,
+ s_ptr_reg when others;
+
+ p_r_ptr: process (rst_i, clk_i, r_ptr_ld, r_ptr_next)
+ begin
+ if rising_edge(clk_i) then
+ if rst_i = '1' then
+ r_ptr_reg <= (others => '0');
+ else
+ if r_ptr_ld = '1' then
+ r_ptr_reg <= r_ptr_next;
+ end if;
+ end if;
+ end if;
+ end process;
+
+ with r_ptr_op select r_ptr_next <=
+ r_ptr_reg + 1 when ST_INC,
+ r_ptr_reg - 1 when ST_DEC,
+ r_ptr_reg when others;
+
+ addra <= '0' & std_logic_vector(s_ptr_next);
+ addrb <= '1' & std_logic_vector(r_ptr_next);
+
+ e_stack_mem: ramb16_s36_s36
+ port map (
+ -- Port A, parameter stack
+ ssra => rst_i,
+ clka => clk_i,
+ ena => '1',
+ wea => s_write,
+ addra => addra,
+
+ doa => s_n_reg,
+ dopa => open,
+ dia => s_t_reg,
+ dipa => "0000",
+
+ -- Port B, return stack
+ ssrb => rst_i,
+ clkb => clk_i,
+ enb => '1',
+ web => r_write,
+ addrb => addrb,
+
+ dob => r_tos_reg,
+ dopb => open,
+ dib => r_tos_new,
+ dipb => "0000"
+ );
+
+
+end behavioral;