Line 76... |
Line 76... |
ctrl_o : out std_ulogic_vector(ctrl_width_c-1 downto 0); -- main control bus
|
ctrl_o : out std_ulogic_vector(ctrl_width_c-1 downto 0); -- main control bus
|
-- status input --
|
-- status input --
|
alu_wait_i : in std_ulogic; -- wait for ALU
|
alu_wait_i : in std_ulogic; -- wait for ALU
|
bus_i_wait_i : in std_ulogic; -- wait for bus
|
bus_i_wait_i : in std_ulogic; -- wait for bus
|
bus_d_wait_i : in std_ulogic; -- wait for bus
|
bus_d_wait_i : in std_ulogic; -- wait for bus
|
|
excl_state_i : in std_ulogic; -- atomic/exclusive access lock status
|
-- data input --
|
-- data input --
|
instr_i : in std_ulogic_vector(data_width_c-1 downto 0); -- instruction
|
instr_i : in std_ulogic_vector(data_width_c-1 downto 0); -- instruction
|
cmp_i : in std_ulogic_vector(1 downto 0); -- comparator status
|
cmp_i : in std_ulogic_vector(1 downto 0); -- comparator status
|
alu_add_i : in std_ulogic_vector(data_width_c-1 downto 0); -- ALU address result
|
alu_add_i : in std_ulogic_vector(data_width_c-1 downto 0); -- ALU address result
|
rs1_i : in std_ulogic_vector(data_width_c-1 downto 0); -- rf source 1
|
rs1_i : in std_ulogic_vector(data_width_c-1 downto 0); -- rf source 1
|
Line 122... |
Line 123... |
|
|
-- HPM counter width - high/low parts --
|
-- HPM counter width - high/low parts --
|
constant hpm_cnt_lo_width_c : natural := natural(cond_sel_int_f(boolean(HPM_CNT_WIDTH < 32), HPM_CNT_WIDTH, 32));
|
constant hpm_cnt_lo_width_c : natural := natural(cond_sel_int_f(boolean(HPM_CNT_WIDTH < 32), HPM_CNT_WIDTH, 32));
|
constant hpm_cnt_hi_width_c : natural := natural(cond_sel_int_f(boolean(HPM_CNT_WIDTH > 32), HPM_CNT_WIDTH-32, 0));
|
constant hpm_cnt_hi_width_c : natural := natural(cond_sel_int_f(boolean(HPM_CNT_WIDTH > 32), HPM_CNT_WIDTH-32, 0));
|
|
|
-- instruction fetch enginge --
|
-- instruction fetch engine --
|
type fetch_engine_state_t is (IFETCH_RESET, IFETCH_REQUEST, IFETCH_ISSUE);
|
type fetch_engine_state_t is (IFETCH_REQUEST, IFETCH_ISSUE);
|
type fetch_engine_t is record
|
type fetch_engine_t is record
|
state : fetch_engine_state_t;
|
state : fetch_engine_state_t;
|
state_nxt : fetch_engine_state_t;
|
state_nxt : fetch_engine_state_t;
|
state_prev : fetch_engine_state_t;
|
state_prev : fetch_engine_state_t;
|
|
restart : std_ulogic;
|
|
restart_nxt : std_ulogic;
|
pc : std_ulogic_vector(data_width_c-1 downto 0);
|
pc : std_ulogic_vector(data_width_c-1 downto 0);
|
pc_nxt : std_ulogic_vector(data_width_c-1 downto 0);
|
pc_nxt : std_ulogic_vector(data_width_c-1 downto 0);
|
reset : std_ulogic;
|
reset : std_ulogic;
|
bus_err_ack : std_ulogic;
|
bus_err_ack : std_ulogic;
|
end record;
|
end record;
|
signal fetch_engine : fetch_engine_t;
|
signal fetch_engine : fetch_engine_t;
|
|
|
-- instrucion prefetch buffer (IPB, real FIFO) --
|
-- instruction prefetch buffer (IPB, real FIFO) --
|
type ipb_data_fifo_t is array (0 to ipb_entries_c-1) of std_ulogic_vector(2+31 downto 0);
|
type ipb_data_fifo_t is array (0 to ipb_entries_c-1) of std_ulogic_vector(2+31 downto 0);
|
type ipb_t is record
|
type ipb_t is record
|
wdata : std_ulogic_vector(2+31 downto 0); -- write status (bus_error, align_error) + 32-bit instruction data
|
wdata : std_ulogic_vector(2+31 downto 0); -- write status (bus_error, align_error) + 32-bit instruction data
|
we : std_ulogic; -- trigger write
|
we : std_ulogic; -- trigger write
|
free : std_ulogic; -- free entry available?
|
free : std_ulogic; -- free entry available?
|
Line 162... |
Line 165... |
-- pre-decoder --
|
-- pre-decoder --
|
signal ci_instr16 : std_ulogic_vector(15 downto 0);
|
signal ci_instr16 : std_ulogic_vector(15 downto 0);
|
signal ci_instr32 : std_ulogic_vector(31 downto 0);
|
signal ci_instr32 : std_ulogic_vector(31 downto 0);
|
signal ci_illegal : std_ulogic;
|
signal ci_illegal : std_ulogic;
|
|
|
-- instruction issue enginge --
|
-- instruction issue engine --
|
type issue_engine_state_t is (ISSUE_ACTIVE, ISSUE_REALIGN);
|
type issue_engine_state_t is (ISSUE_ACTIVE, ISSUE_REALIGN);
|
type issue_engine_t is record
|
type issue_engine_t is record
|
state : issue_engine_state_t;
|
state : issue_engine_state_t;
|
state_nxt : issue_engine_state_t;
|
state_nxt : issue_engine_state_t;
|
align : std_ulogic;
|
align : std_ulogic;
|
Line 196... |
Line 199... |
end record;
|
end record;
|
signal decode_aux : decode_aux_t;
|
signal decode_aux : decode_aux_t;
|
|
|
-- instruction execution engine --
|
-- instruction execution engine --
|
type execute_engine_state_t is (SYS_WAIT, DISPATCH, TRAP_ENTER, TRAP_EXIT, TRAP_EXECUTE, EXECUTE, ALU_WAIT, BRANCH,
|
type execute_engine_state_t is (SYS_WAIT, DISPATCH, TRAP_ENTER, TRAP_EXIT, TRAP_EXECUTE, EXECUTE, ALU_WAIT, BRANCH,
|
FENCE_OP,LOADSTORE_0, LOADSTORE_1, LOADSTORE_2, ATOMIC_SC_EVAL, SYS_ENV, CSR_ACCESS);
|
FENCE_OP,LOADSTORE_0, LOADSTORE_1, LOADSTORE_2, SYS_ENV, CSR_ACCESS);
|
type execute_engine_t is record
|
type execute_engine_t is record
|
state : execute_engine_state_t;
|
state : execute_engine_state_t;
|
state_nxt : execute_engine_state_t;
|
state_nxt : execute_engine_state_t;
|
state_prev : execute_engine_state_t;
|
state_prev : execute_engine_state_t;
|
--
|
--
|
Line 211... |
Line 214... |
is_ci : std_ulogic; -- current instruction is de-compressed instruction
|
is_ci : std_ulogic; -- current instruction is de-compressed instruction
|
is_ci_nxt : std_ulogic;
|
is_ci_nxt : std_ulogic;
|
is_cp_op : std_ulogic; -- current instruction is a co-processor operation
|
is_cp_op : std_ulogic; -- current instruction is a co-processor operation
|
is_cp_op_nxt : std_ulogic;
|
is_cp_op_nxt : std_ulogic;
|
--
|
--
|
branch_taken : std_ulogic; -- branch condition fullfilled
|
branch_taken : std_ulogic; -- branch condition fulfilled
|
pc : std_ulogic_vector(data_width_c-1 downto 0); -- actual PC, corresponding to current executed instruction
|
pc : std_ulogic_vector(data_width_c-1 downto 0); -- actual PC, corresponding to current executed instruction
|
pc_mux_sel : std_ulogic; -- source select for PC update
|
pc_mux_sel : std_ulogic; -- source select for PC update
|
pc_we : std_ulogic; -- PC update enabled
|
pc_we : std_ulogic; -- PC update enabled
|
next_pc : std_ulogic_vector(data_width_c-1 downto 0); -- next PC, corresponding to next instruction to be executed
|
next_pc : std_ulogic_vector(data_width_c-1 downto 0); -- next PC, corresponding to next instruction to be executed
|
next_pc_inc : std_ulogic_vector(data_width_c-1 downto 0); -- increment to get next PC
|
next_pc_inc : std_ulogic_vector(data_width_c-1 downto 0); -- increment to get next PC
|
Line 361... |
Line 364... |
-- Fetch Engine FSM Sync ------------------------------------------------------------------
|
-- Fetch Engine FSM Sync ------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
fetch_engine_fsm_sync: process(rstn_i, clk_i)
|
fetch_engine_fsm_sync: process(rstn_i, clk_i)
|
begin
|
begin
|
if (rstn_i = '0') then
|
if (rstn_i = '0') then
|
fetch_engine.state <= IFETCH_RESET;
|
fetch_engine.state <= IFETCH_REQUEST;
|
fetch_engine.state_prev <= IFETCH_RESET;
|
fetch_engine.state_prev <= IFETCH_REQUEST;
|
|
fetch_engine.restart <= '1';
|
fetch_engine.pc <= (others => def_rst_val_c);
|
fetch_engine.pc <= (others => def_rst_val_c);
|
elsif rising_edge(clk_i) then
|
elsif rising_edge(clk_i) then
|
if (fetch_engine.reset = '1') then
|
|
fetch_engine.state <= IFETCH_RESET;
|
|
else
|
|
fetch_engine.state <= fetch_engine.state_nxt;
|
fetch_engine.state <= fetch_engine.state_nxt;
|
end if;
|
|
fetch_engine.state_prev <= fetch_engine.state;
|
fetch_engine.state_prev <= fetch_engine.state;
|
|
fetch_engine.restart <= fetch_engine.restart_nxt;
|
|
if (fetch_engine.restart = '1') then
|
|
fetch_engine.pc <= execute_engine.pc(data_width_c-1 downto 1) & '0'; -- initialize with "real" application PC
|
|
else
|
fetch_engine.pc <= fetch_engine.pc_nxt;
|
fetch_engine.pc <= fetch_engine.pc_nxt;
|
end if;
|
end if;
|
|
end if;
|
end process fetch_engine_fsm_sync;
|
end process fetch_engine_fsm_sync;
|
|
|
-- PC output --
|
-- PC output --
|
fetch_pc_o <= fetch_engine.pc(data_width_c-1 downto 1) & '0'; -- half-word aligned
|
fetch_pc_o <= fetch_engine.pc(data_width_c-1 downto 1) & '0'; -- half-word aligned
|
|
|
Line 388... |
Line 393... |
-- arbiter defaults --
|
-- arbiter defaults --
|
bus_fast_ir <= '0';
|
bus_fast_ir <= '0';
|
fetch_engine.state_nxt <= fetch_engine.state;
|
fetch_engine.state_nxt <= fetch_engine.state;
|
fetch_engine.pc_nxt <= fetch_engine.pc;
|
fetch_engine.pc_nxt <= fetch_engine.pc;
|
fetch_engine.bus_err_ack <= '0';
|
fetch_engine.bus_err_ack <= '0';
|
|
fetch_engine.restart_nxt <= fetch_engine.restart or fetch_engine.reset;
|
|
|
-- instruction prefetch buffer interface --
|
-- instruction prefetch buffer interface --
|
ipb.we <= '0';
|
ipb.we <= '0';
|
ipb.wdata <= be_instr_i & ma_instr_i & instr_i(31 downto 0); -- store exception info and instruction word
|
ipb.wdata <= be_instr_i & ma_instr_i & instr_i(31 downto 0); -- store exception info and instruction word
|
ipb.clear <= '0';
|
ipb.clear <= fetch_engine.restart;
|
|
|
-- state machine --
|
-- state machine --
|
case fetch_engine.state is
|
case fetch_engine.state is
|
|
|
when IFETCH_RESET => -- reset engine and prefetch buffer, get application PC
|
when IFETCH_REQUEST => -- request new 32-bit-aligned instruction word
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
fetch_engine.bus_err_ack <= '1'; -- acknowledge any instruction bus errors, the execute engine has to take care of them / terminate current transfer
|
if (ipb.free = '1') and (fetch_engine.restart = '0') then -- free entry in buffer AND no reset request?
|
fetch_engine.pc_nxt <= execute_engine.pc(data_width_c-1 downto 1) & '0'; -- initialize with "real" application PC
|
|
ipb.clear <= '1'; -- clear prefetch buffer
|
|
fetch_engine.state_nxt <= IFETCH_REQUEST;
|
|
|
|
when IFETCH_REQUEST => -- output current PC to bus system and request 32-bit (aligned!) instruction data
|
|
-- ------------------------------------------------------------
|
|
if (ipb.free = '1') then -- free entry in buffer?
|
|
bus_fast_ir <= '1'; -- fast instruction fetch request
|
bus_fast_ir <= '1'; -- fast instruction fetch request
|
fetch_engine.state_nxt <= IFETCH_ISSUE;
|
fetch_engine.state_nxt <= IFETCH_ISSUE;
|
end if;
|
end if;
|
|
if (fetch_engine.restart = '1') then -- reset request?
|
|
fetch_engine.restart_nxt <= '0';
|
|
end if;
|
|
|
when IFETCH_ISSUE => -- store instruction data to prefetch buffer
|
when IFETCH_ISSUE => -- store instruction data to prefetch buffer
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
fetch_engine.bus_err_ack <= be_instr_i or ma_instr_i; -- ACK bus/alignment errors
|
fetch_engine.bus_err_ack <= be_instr_i or ma_instr_i; -- ACK bus/alignment errors
|
if (bus_i_wait_i = '0') or (be_instr_i = '1') or (ma_instr_i = '1') then -- wait for bus response
|
if (bus_i_wait_i = '0') or (be_instr_i = '1') or (ma_instr_i = '1') then -- wait for bus response
|
fetch_engine.pc_nxt <= std_ulogic_vector(unsigned(fetch_engine.pc) + 4);
|
fetch_engine.pc_nxt <= std_ulogic_vector(unsigned(fetch_engine.pc) + 4);
|
ipb.we <= '1';
|
ipb.we <= not fetch_engine.restart; -- write to IPB if not being reset
|
|
if (fetch_engine.restart = '1') then -- reset request?
|
|
fetch_engine.restart_nxt <= '0';
|
|
end if;
|
fetch_engine.state_nxt <= IFETCH_REQUEST;
|
fetch_engine.state_nxt <= IFETCH_REQUEST;
|
end if;
|
end if;
|
|
|
when others => -- undefined
|
when others => -- undefined
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
fetch_engine.state_nxt <= IFETCH_RESET;
|
fetch_engine.state_nxt <= IFETCH_REQUEST;
|
|
|
end case;
|
end case;
|
end process fetch_engine_fsm_comb;
|
end process fetch_engine_fsm_comb;
|
|
|
|
|
Line 685... |
Line 690... |
-- registers that DO require a specific reset state --
|
-- registers that DO require a specific reset state --
|
execute_engine.pc <= CPU_BOOT_ADDR(data_width_c-1 downto 1) & '0';
|
execute_engine.pc <= CPU_BOOT_ADDR(data_width_c-1 downto 1) & '0';
|
execute_engine.state <= SYS_WAIT;
|
execute_engine.state <= SYS_WAIT;
|
execute_engine.sleep <= '0';
|
execute_engine.sleep <= '0';
|
execute_engine.branched <= '1'; -- reset is a branch from "somewhere"
|
execute_engine.branched <= '1'; -- reset is a branch from "somewhere"
|
-- no dedicated RESEt required --
|
-- no dedicated RESET required --
|
execute_engine.state_prev <= SYS_WAIT;
|
execute_engine.state_prev <= SYS_WAIT;
|
execute_engine.i_reg <= (others => def_rst_val_c);
|
execute_engine.i_reg <= (others => def_rst_val_c);
|
execute_engine.is_ci <= def_rst_val_c;
|
execute_engine.is_ci <= def_rst_val_c;
|
execute_engine.is_cp_op <= def_rst_val_c;
|
execute_engine.is_cp_op <= def_rst_val_c;
|
execute_engine.last_pc <= (others => def_rst_val_c);
|
execute_engine.last_pc <= (others => def_rst_val_c);
|
Line 772... |
Line 777... |
ctrl_o(ctrl_ir_opcode7_6_c downto ctrl_ir_opcode7_0_c) <= execute_engine.i_reg(instr_opcode_msb_c downto instr_opcode_lsb_c);
|
ctrl_o(ctrl_ir_opcode7_6_c downto ctrl_ir_opcode7_0_c) <= execute_engine.i_reg(instr_opcode_msb_c downto instr_opcode_lsb_c);
|
ctrl_o(ctrl_ir_funct12_11_c downto ctrl_ir_funct12_0_c) <= execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c);
|
ctrl_o(ctrl_ir_funct12_11_c downto ctrl_ir_funct12_0_c) <= execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c);
|
ctrl_o(ctrl_ir_funct3_2_c downto ctrl_ir_funct3_0_c) <= execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c);
|
ctrl_o(ctrl_ir_funct3_2_c downto ctrl_ir_funct3_0_c) <= execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c);
|
-- cpu status --
|
-- cpu status --
|
ctrl_o(ctrl_sleep_c) <= execute_engine.sleep; -- cpu is in sleep mode
|
ctrl_o(ctrl_sleep_c) <= execute_engine.sleep; -- cpu is in sleep mode
|
|
ctrl_o(ctrl_trap_c) <= trap_ctrl.env_start_ack; -- cpu is starting a trap handler
|
end process ctrl_output;
|
end process ctrl_output;
|
|
|
|
|
-- Decoding Helper Logic ------------------------------------------------------------------
|
-- Decoding Helper Logic ------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
Line 869... |
Line 875... |
|
|
|
|
-- Execute Engine FSM Comb ----------------------------------------------------------------
|
-- Execute Engine FSM Comb ----------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
execute_engine_fsm_comb: process(execute_engine, decode_aux, fetch_engine, cmd_issue, trap_ctrl, csr, ctrl, csr_acc_valid,
|
execute_engine_fsm_comb: process(execute_engine, decode_aux, fetch_engine, cmd_issue, trap_ctrl, csr, ctrl, csr_acc_valid,
|
alu_wait_i, bus_d_wait_i, ma_load_i, be_load_i, ma_store_i, be_store_i)
|
alu_wait_i, bus_d_wait_i, ma_load_i, be_load_i, ma_store_i, be_store_i, excl_state_i)
|
variable opcode_v : std_ulogic_vector(6 downto 0);
|
variable opcode_v : std_ulogic_vector(6 downto 0);
|
begin
|
begin
|
-- arbiter defaults --
|
-- arbiter defaults --
|
execute_engine.state_nxt <= execute_engine.state;
|
execute_engine.state_nxt <= execute_engine.state;
|
execute_engine.i_reg_nxt <= execute_engine.i_reg;
|
execute_engine.i_reg_nxt <= execute_engine.i_reg;
|
Line 913... |
Line 919... |
if (execute_engine.i_reg(instr_opcode_lsb_c+4) = '1') then -- ALU ops
|
if (execute_engine.i_reg(instr_opcode_lsb_c+4) = '1') then -- ALU ops
|
ctrl_nxt(ctrl_alu_unsigned_c) <= execute_engine.i_reg(instr_funct3_lsb_c+0); -- unsigned ALU operation? (SLTIU, SLTU)
|
ctrl_nxt(ctrl_alu_unsigned_c) <= execute_engine.i_reg(instr_funct3_lsb_c+0); -- unsigned ALU operation? (SLTIU, SLTU)
|
else -- branches
|
else -- branches
|
ctrl_nxt(ctrl_alu_unsigned_c) <= execute_engine.i_reg(instr_funct3_lsb_c+1); -- unsigned branches? (BLTU, BGEU)
|
ctrl_nxt(ctrl_alu_unsigned_c) <= execute_engine.i_reg(instr_funct3_lsb_c+1); -- unsigned branches? (BLTU, BGEU)
|
end if;
|
end if;
|
-- bus interface --
|
-- Atomic store-conditional instruction (evaluate lock status) --
|
ctrl_nxt(ctrl_bus_excl_c) <= ctrl(ctrl_bus_excl_c); -- keep exclusive bus access request alive if set
|
if (CPU_EXTENSION_RISCV_A = true) then
|
|
ctrl_nxt(ctrl_bus_ch_lock_c) <= decode_aux.is_atomic_sc;
|
|
else
|
|
ctrl_nxt(ctrl_bus_ch_lock_c) <= '0';
|
|
end if;
|
|
|
|
|
-- state machine --
|
-- state machine --
|
case execute_engine.state is
|
case execute_engine.state is
|
|
|
Line 935... |
Line 945... |
|
|
|
|
when DISPATCH => -- Get new command from instruction issue engine
|
when DISPATCH => -- Get new command from instruction issue engine
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
-- housekeeping --
|
-- housekeeping --
|
execute_engine.is_cp_op_nxt <= '0'; -- init
|
execute_engine.is_cp_op_nxt <= '0'; -- no compressed instruction yet
|
ctrl_nxt(ctrl_bus_excl_c) <= '0'; -- clear exclusive data bus access
|
|
-- PC update --
|
-- PC update --
|
execute_engine.pc_mux_sel <= '0'; -- linear next PC
|
execute_engine.pc_mux_sel <= '0'; -- linear next PC
|
-- IR update --
|
-- IR update --
|
execute_engine.is_ci_nxt <= cmd_issue.data(32); -- flag to indicate a de-compressed instruction
|
execute_engine.is_ci_nxt <= cmd_issue.data(32); -- flag to indicate a de-compressed instruction
|
execute_engine.i_reg_nxt <= cmd_issue.data(31 downto 0);
|
execute_engine.i_reg_nxt <= cmd_issue.data(31 downto 0);
|
Line 1219... |
Line 1228... |
end if;
|
end if;
|
|
|
|
|
when LOADSTORE_0 => -- trigger memory request
|
when LOADSTORE_0 => -- trigger memory request
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
ctrl_nxt(ctrl_bus_excl_c) <= decode_aux.is_atomic_lr; -- atomic.LR: exclusive memory access request
|
ctrl_nxt(ctrl_bus_lock_c) <= decode_aux.is_atomic_lr; -- atomic.LR: set lock
|
if (execute_engine.i_reg(instr_opcode_msb_c-1) = '0') or (decode_aux.is_atomic_lr = '1') then -- normal load or atomic load-reservate
|
if (execute_engine.i_reg(instr_opcode_msb_c-1) = '0') or (decode_aux.is_atomic_lr = '1') then -- normal load or atomic load-reservate
|
ctrl_nxt(ctrl_bus_rd_c) <= '1'; -- read request
|
ctrl_nxt(ctrl_bus_rd_c) <= '1'; -- read request
|
else -- store
|
else -- store
|
|
if (CPU_EXTENSION_RISCV_A = true) and (decode_aux.is_atomic_sc = '1') then -- evaluate lock state
|
|
if (excl_state_i = '1') then -- lock is still ok - perform write access
|
ctrl_nxt(ctrl_bus_wr_c) <= '1'; -- write request
|
ctrl_nxt(ctrl_bus_wr_c) <= '1'; -- write request
|
end if;
|
end if;
|
|
else
|
|
ctrl_nxt(ctrl_bus_wr_c) <= '1'; -- (normal) write request
|
|
end if;
|
|
end if;
|
execute_engine.state_nxt <= LOADSTORE_1;
|
execute_engine.state_nxt <= LOADSTORE_1;
|
|
|
|
|
when LOADSTORE_1 => -- memory latency
|
when LOADSTORE_1 => -- memory latency
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
ctrl_nxt(ctrl_bus_mi_we_c) <= '1'; -- write input data to MDI (only relevant for LOAD)
|
ctrl_nxt(ctrl_bus_mi_we_c) <= '1'; -- write input data to MDI (only relevant for LOAD)
|
if (CPU_EXTENSION_RISCV_A = true) and (decode_aux.is_atomic_sc = '1') then -- execute and evaluate atomic store-conditional
|
|
execute_engine.state_nxt <= ATOMIC_SC_EVAL;
|
|
else -- normal load/store
|
|
execute_engine.state_nxt <= LOADSTORE_2;
|
execute_engine.state_nxt <= LOADSTORE_2;
|
end if;
|
|
|
|
|
|
when LOADSTORE_2 => -- wait for bus transaction to finish
|
when LOADSTORE_2 => -- wait for bus transaction to finish
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
ctrl_nxt(ctrl_bus_mi_we_c) <= '1'; -- keep writing input data to MDI (only relevant for load operations)
|
ctrl_nxt(ctrl_bus_mi_we_c) <= '1'; -- keep writing input data to MDI (only relevant for load (and SC.W) operations)
|
ctrl_nxt(ctrl_rf_in_mux_c) <= '1'; -- RF input = memory input (only relevant for LOADs)
|
ctrl_nxt(ctrl_rf_in_mux_c) <= '1'; -- RF input = memory input (only relevant for LOADs)
|
-- wait for memory response --
|
-- wait for memory response --
|
if ((ma_load_i or be_load_i or ma_store_i or be_store_i) = '1') then -- abort if exception
|
if ((ma_load_i or be_load_i or ma_store_i or be_store_i) = '1') then -- abort if exception
|
execute_engine.state_nxt <= DISPATCH;
|
execute_engine.state_nxt <= DISPATCH;
|
elsif (bus_d_wait_i = '0') then -- wait for bus to finish transaction
|
elsif (bus_d_wait_i = '0') then -- wait for bus to finish transaction
|
-- data write-back
|
-- remove atomic lock if this is NOT the LR.W instruction used to SET the lock --
|
if (execute_engine.i_reg(instr_opcode_msb_c-1) = '0') or (decode_aux.is_atomic_lr = '1') then -- normal load OR atomic load
|
if (CPU_EXTENSION_RISCV_A = true) and (decode_aux.is_atomic_lr = '0') then -- execute and evaluate atomic store-conditional
|
|
ctrl_nxt(ctrl_bus_de_lock_c) <= '1';
|
|
end if;
|
|
-- data write-back --
|
|
if (execute_engine.i_reg(instr_opcode_msb_c-1) = '0') or -- normal load
|
|
(decode_aux.is_atomic_lr = '1') or -- atomic load-reservate
|
|
(decode_aux.is_atomic_sc = '1') then -- atomic store-conditional
|
ctrl_nxt(ctrl_rf_wb_en_c) <= '1';
|
ctrl_nxt(ctrl_rf_wb_en_c) <= '1';
|
end if;
|
end if;
|
execute_engine.state_nxt <= DISPATCH;
|
execute_engine.state_nxt <= DISPATCH;
|
end if;
|
end if;
|
|
|
|
|
when ATOMIC_SC_EVAL => -- wait for bus transaction to finish and evaluate if SC was successful
|
|
-- ------------------------------------------------------------
|
|
if (CPU_EXTENSION_RISCV_A = true) then
|
|
-- atomic.SC: result comes from "atomic co-processor" --
|
|
ctrl_nxt(ctrl_cp_id_msb_c downto ctrl_cp_id_lsb_c) <= cp_sel_atomic_c;
|
|
execute_engine.is_cp_op_nxt <= '1'; -- this is a CP operation
|
|
ctrl_nxt(ctrl_rf_in_mux_c) <= '0'; -- RF input = ALU.res
|
|
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- allow reg file write back
|
|
-- wait for memory response --
|
|
if ((ma_load_i or be_load_i or ma_store_i or be_store_i) = '1') then -- abort if exception
|
|
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_copro_c; -- trigger atomic-coprocessor operation for SC status evaluation
|
|
execute_engine.state_nxt <= ALU_WAIT;
|
|
elsif (bus_d_wait_i = '0') then -- wait for bus to finish transaction
|
|
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_copro_c; -- trigger atomic-coprocessor operation for SC status evaluation
|
|
execute_engine.state_nxt <= ALU_WAIT;
|
|
end if;
|
|
else
|
|
execute_engine.state_nxt <= SYS_WAIT;
|
|
end if;
|
|
|
|
|
|
when others => -- undefined
|
when others => -- undefined
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
execute_engine.state_nxt <= SYS_WAIT;
|
execute_engine.state_nxt <= SYS_WAIT;
|
|
|
end case;
|
end case;
|