-- See the file "LICENSE" for the full license governing this code. -- library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use work.lt16x32_internal.all; use work.lt16x32_global.all; -- the decoder_fsm is the finite state machine handling multi-cycle operation and interrupt acknowledgement entity decoder_fsm is port( -- clock signal clk : in std_logic; -- reset signal, active high, synchronous rst : in std_logic; -- stall signal, active high stall : in std_logic; -- signals from pre-decoder in_pre : in pre_fsm; -- signals from control path in_cp : in cp_dec; -- signals from datapath in_dp : in dp_dec; -- signals to 16bit decoder out_16 : out fsm_dec16; -- signals to 32bit decoder out_32 : out fsm_dec32; -- signals to shadow decoder out_shd : out fsm_decshd; -- signals to decoder mux out_mux : out fsm_decmux; -- signals to pc counter out_pc : out dec_pc; -- signals to instruction memory out_imem : out dec_imem; -- signals from interrupt controller in_irq : in irq_dec; -- signals to interrupt controller out_irq : out dec_irq ); end entity decoder_fsm; architecture RTL of decoder_fsm is -- possible states of fsm type state_type is (normal, reset, reset2, copyPCtoLR, branchdelay, irq_decSP1, irq_pushSR, irq_pushLR, irq_setSR, irq_setPC, reti_popLR, reti_incSP1, reti_popSR, reti_incSP2); --add irq_decSP2 for 4 instruction irq stack solution -- current state signal state : state_type := normal; -- temporary storage for multicycle operations signal multicycleinstruction : std_logic_vector(31 downto 0); begin -- the finite state machine is modelled as mealy-machine -- generate output (combinatoric part) output : process(in_pre, state, multicycleinstruction, in_cp.condition_holds) is variable state_variable : state_type; begin -- standard output out_16.instruction <= nop16; out_32.instruction <= in_pre.instruction; out_shd.instruction(31 downto 28) <= op_shd_push; out_shd.instruction(27 downto 0) <= (others => '0'); out_mux.mode <= sel_ir16; out_pc.stall <= '0'; out_imem.en <= '1'; out_irq.ack <= '0'; out_irq.trap_req <= '0'; out_irq.trap_num <= (others => '0'); -- copy state to variable for further processing state_variable := state; -- don't insert nop in branch delay if no branch taken -- happens only, if execute_branch_delay_slot is false if ((state = branchdelay) and (in_cp.condition_holds = '0')) then state_variable := normal; end if; -- don't write LR if no call happens if ((state = copyPCtoLR) and (in_cp.condition_holds = '0')) then state_variable := normal; end if; -- generate state dependend output case state_variable is when reset => -- first cycle in reset out_pc.stall <= '1'; out_shd.instruction(31 downto 28) <= op_shd_reset; out_mux.mode <= sel_irshadow; when reset2 => -- second cycle in reset out_pc.stall <= '0'; out_16.instruction <= nop16; out_mux.mode <= sel_ir16; when normal => -- standard mode out_pc.stall <= '0'; case in_pre.mode is -- check decoder_pre mode output when sel_normal16 => -- normal 16 bit instruction out_mux.mode <= sel_ir16; out_16.instruction <= in_pre.instruction(15 downto 0); when sel_normal32 => -- normal 32 bit instruction out_mux.mode <= sel_ir32; out_32.instruction <= in_pre.instruction; when sel_branch => -- branch instruction out_mux.mode <= sel_ir16; out_16.instruction <= in_pre.instruction(15 downto 0); when sel_call => -- call instruction out_mux.mode <= sel_ir16; out_16.instruction <= op_bct & "01" & in_pre.instruction(9 downto 0); --out_imem.en <= '0'; -- imem must be read in case that condition does not hold and next instruction should be executed when sel_trap => -- trap instruction out_mux.mode <= sel_ir16; out_16.instruction <= nop16; out_irq.trap_num <= unsigned(in_pre.instruction(irq_num_width - 1 downto 0)); out_irq.trap_req <= '1'; when sel_reti => -- reti instruction out_mux.mode <= sel_ir16; out_16.instruction <= op_bct & "0110" & std_logic_vector(lr_num) & "0000"; out_imem.en <= '0'; when sel_stall => -- stall (i.e. imem not ready) out_mux.mode <= sel_ir16; out_16.instruction <= in_pre.instruction(15 downto 0); out_pc.stall <= '1'; end case; when copyPCtoLR => -- LR = PC, used in call and irq -- only if condition true, else normal instruction (this check is done in state transition) out_mux.mode <= sel_ir16; out_16.instruction <= op_or & std_logic_vector(lr_num) & std_logic_vector(pc_num) & std_logic_vector(pc_num); out_imem.en <= '1'; when branchdelay => -- insert NOP to branch delay slot if enabled in configuration out_pc.stall <= '0'; out_mux.mode <= sel_ir16; out_imem.en <= '1'; --when irq_pushLR => -- irq: push LR -- out_pc.stall <= '1'; -- out_mux.mode <= sel_irshadow; -- out_shd.instruction(31 downto 28) <= op_shd_push; -- out_shd.instruction(3 downto 0) <= std_logic_vector(lr_num); -- out_imem.en <= '0'; when irq_pushLR => out_pc.stall <= '1'; out_mux.mode <= sel_ir16; out_16.instruction <= op_mem & op_mem_st32 & std_logic_vector(sp_num) & std_logic_vector(lr_num); out_imem.en <= '1'; when irq_setSR => -- irq: push SR and set new SR value out_pc.stall <= '1'; out_mux.mode <= sel_irshadow; out_shd.instruction(31 downto 28) <= op_shd_setsr; -- new runtime priority, other SR flags all zero out_shd.instruction(7 downto (8 - irq_prio_width)) <= multicycleinstruction(16 + irq_prio_width - 1 downto 16); out_imem.en <= '0'; when irq_setPC => -- irq: branch to irq address out_pc.stall <= '1'; out_mux.mode <= sel_ir16; out_16.instruction <= op_bct & "11" & multicycleinstruction(9 downto 0); out_imem.en <= '0'; when reti_popLR => -- reti: load LR from stack out_pc.stall <= '0'; --former 1 out_mux.mode <= sel_ir16; out_16.instruction <= op_mem & op_mem_ld32 & std_logic_vector(lr_num) & std_logic_vector(sp_num); out_imem.en <= '0'; when reti_popSR => -- reti: load SR from stack out_pc.stall <= '1'; out_mux.mode <= sel_ir16; out_16.instruction <= op_mem & op_mem_ld32 & std_logic_vector(sr_num) & std_logic_vector(sp_num); out_imem.en <= '1'; when reti_incSP1 => -- reti: increment SP out_pc.stall <= '1'; out_mux.mode <= sel_ir16; out_16.instruction <= op_addi & std_logic_vector(sp_num) & std_logic_vector(to_signed(4, 8)); out_imem.en <= '0'; when reti_incSP2 => -- reti increment SP out_pc.stall <= '1'; out_mux.mode <= sel_ir16; out_16.instruction <= op_addi & std_logic_vector(sp_num) & std_logic_vector(to_signed(4, 8)); out_imem.en <= '0'; when irq_pushSR => -- irq: push SR (store and decrement SP afterwards) out_mux.mode <= sel_irshadow; out_shd.instruction(31 downto 28) <= op_shd_push; out_shd.instruction(3 downto 0) <= std_logic_vector(sr_num); out_irq.ack <= '1'; out_pc.stall <= '1'; --when irq_pushSR => -- out_pc.stall <= '1'; -- out_mux.mode <= sel_ir16; -- out_16.instruction <= op_mem & op_mem_st32 & std_logic_vector(sp_num) & std_logic_vector(sr_num); -- out_imem.en <= '1'; -- out_irq.ack <= '1'; when irq_decSP1 => out_pc.stall <= '1'; out_mux.mode <= sel_ir16; out_16.instruction <= op_addi & std_logic_vector(sp_num) & std_logic_vector(to_signed(-4, 8)); out_imem.en <= '0'; --when irq_decSP2 => -- out_pc.stall <= '1'; -- out_mux.mode <= sel_ir16; --out_16.instruction <= op_addi & std_logic_vector(sp_num) & std_logic_vector(to_signed(-4, 8)); --out_imem.en <= '0'; end case; end process output; -- state transition (clocked part) state_transition : process(clk) is begin if (rising_edge(clk)) then if (rst = '1') then state <= reset; elsif (stall = '0') then state <= state; -- in default: keep state -- check for interrupt request if ( -- not near branch and not in multicycle operation (in_pre.mode /= sel_branch) and (state = normal) -- interrupt request and (in_irq.req = '1') -- priority higher than runtime priority or non maskable interrupt and ((unsigned(in_irq.priority) > in_dp.runtime_priority) or (in_irq.nmi = '1')) ) then -- in normal mode and irq request --state <= irq_pushSR; state <= irq_decSP1; multicycleinstruction <= (others => '0'); multicycleinstruction(16 + irq_prio_width - 1 downto 16) <= std_logic_vector(in_irq.priority); multicycleinstruction(irq_num_width downto 0) <= std_logic_vector(in_irq.num) & "0"; -- synthesis translate_off assert false report "current runtime priority is " & integer'image(to_integer(in_dp.runtime_priority)) & ". IRQ priority is " & integer'image(to_integer(unsigned(in_irq.priority))) & "." severity note; assert false report "handle irq request #" & integer'image(to_integer(unsigned(in_irq.num))) severity note; -- synthesis translate_on else -- no irq request valid -- for state transition diagram see documentation case state is when normal => case in_pre.mode is when sel_normal16 => state <= normal; when sel_normal32 => state <= normal; when sel_call => state <= copyPCtoLR; when sel_branch => if (execute_branch_delay_slot) then state <= normal; else state <= branchdelay; end if; when sel_trap => state <= normal; when sel_reti => --state <= reti_incSP1; state <= reti_popLR; when sel_stall => state <= normal; end case; when copyPCtoLR => state <= normal; when branchdelay => state <= normal; --! group by multicycle opertation/pseudo-instruction -TF -- i.e. IRQ entry (multicycle) when irq_decSP1 => state <= irq_pushSR; when irq_pushSR => --state <= irq_decSP2; state <= irq_pushLR; --when irq_decSP2 => -- state <= irq_pushLR; when irq_pushLR => state <= irq_setSR; when irq_setSR => state <= irq_setPC; when irq_setPC => state <= copyPCtoLR; when reti_popLR => state <= reti_incSP1; when reti_incSP1 => state <= reti_popSR; when reti_popSR => state <= reti_incSP2; when reti_incSP2 => state <= normal; when reset => state <= reset2; when reset2 => state <= normal; end case; end if; end if; end if; end process state_transition; end architecture RTL;