From: rs <> Date: Sun, 21 Sep 2025 03:49:04 +0000 (-0500) Subject: Add attempt at resource-optimized CPU X-Git-Url: https://git.the-white-hart.net/?a=commitdiff_plain;h=330750af70c7bd0b7e8fc65681e4747cbbdece2f;p=vhdl Add attempt at resource-optimized CPU --- diff --git a/projects/cpu_0/cpu_opt.vhd b/projects/cpu_0/cpu_opt.vhd new file mode 100644 index 0000000..c437863 --- /dev/null +++ b/projects/cpu_0/cpu_opt.vhd @@ -0,0 +1,873 @@ +-------------------------------------------------------------------------------- +-- +-- +---+ +---+ +---+ +---+ +---+ +-- | 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;