Files
lt16lab/soc/core/decoder_fsm.vhd
Thomas Fehmel 657a54ba18 Initial Commit
2016-10-18 14:21:45 +02:00

320 lines
12 KiB
VHDL

-- 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;