Line 149... |
Line 149... |
|
|
-- instruction execution engine --
|
-- instruction execution engine --
|
type execute_engine_state_t is (SYS_WAIT, DISPATCH, TRAP, EXECUTE, ALU_WAIT, BRANCH, LOADSTORE_0, LOADSTORE_1, LOADSTORE_2, CSR_ACCESS);
|
type execute_engine_state_t is (SYS_WAIT, DISPATCH, TRAP, EXECUTE, ALU_WAIT, BRANCH, LOADSTORE_0, LOADSTORE_1, LOADSTORE_2, 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_prev : execute_engine_state_t;
|
state_nxt : execute_engine_state_t;
|
state_nxt : execute_engine_state_t;
|
i_reg : std_ulogic_vector(31 downto 0);
|
i_reg : std_ulogic_vector(31 downto 0);
|
i_reg_nxt : std_ulogic_vector(31 downto 0);
|
i_reg_nxt : std_ulogic_vector(31 downto 0);
|
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;
|
Line 324... |
Line 325... |
fetch_engine.bus_err_ack <= '0';
|
fetch_engine.bus_err_ack <= '0';
|
|
|
-- instruction prefetch buffer interface --
|
-- instruction prefetch buffer interface --
|
ipb.we <= '0';
|
ipb.we <= '0';
|
ipb.clear <= '0';
|
ipb.clear <= '0';
|
ipb.wdata <= '0' & fetch_engine.i_buf2(33 downto 32) & '0' & fetch_engine.i_buf2(31 downto 0);
|
ipb.wdata <= (others => '0');
|
ipb.waddr <= fetch_engine.pc_real(data_width_c-1 downto 1) & '0';
|
ipb.waddr <= fetch_engine.pc_real(data_width_c-1 downto 1) & '0';
|
|
|
-- state machine --
|
-- state machine --
|
case fetch_engine.state is
|
case fetch_engine.state is
|
|
|
Line 386... |
Line 387... |
if (fetch_engine.i_buf2(17 downto 16) = "11") then -- uncompressed
|
if (fetch_engine.i_buf2(17 downto 16) = "11") then -- uncompressed
|
ipb.wdata <= '0' & fetch_engine.i_buf(33 downto 32) & '0' & fetch_engine.i_buf(15 downto 00) & fetch_engine.i_buf2(31 downto 16);
|
ipb.wdata <= '0' & fetch_engine.i_buf(33 downto 32) & '0' & fetch_engine.i_buf(15 downto 00) & fetch_engine.i_buf2(31 downto 16);
|
fetch_engine.pc_real_add <= std_ulogic_vector(to_unsigned(4, data_width_c));
|
fetch_engine.pc_real_add <= std_ulogic_vector(to_unsigned(4, data_width_c));
|
fetch_engine.pc_fetch_add <= std_ulogic_vector(to_unsigned(4, data_width_c));
|
fetch_engine.pc_fetch_add <= std_ulogic_vector(to_unsigned(4, data_width_c));
|
fetch_engine.state_nxt <= IFETCH_0;
|
fetch_engine.state_nxt <= IFETCH_0;
|
else -- uncompressed
|
else -- compressed
|
ipb.wdata <= ci_illegal & fetch_engine.i_buf(33 downto 32) & '1' & ci_instr32;
|
ipb.wdata <= ci_illegal & fetch_engine.i_buf(33 downto 32) & '1' & ci_instr32;
|
fetch_engine.pc_fetch_add <= std_ulogic_vector(to_unsigned(2, data_width_c));
|
fetch_engine.pc_fetch_add <= std_ulogic_vector(to_unsigned(2, data_width_c));
|
fetch_engine.pc_real_add <= std_ulogic_vector(to_unsigned(2, data_width_c));
|
fetch_engine.pc_real_add <= std_ulogic_vector(to_unsigned(2, data_width_c));
|
fetch_engine.state_nxt <= IFETCH_0;
|
fetch_engine.state_nxt <= IFETCH_0;
|
end if;
|
end if;
|
Line 526... |
Line 527... |
|
|
-- for registers that do NOT require a specific reset state --
|
-- for registers that do NOT require a specific reset state --
|
execute_engine_fsm_sync: process(clk_i)
|
execute_engine_fsm_sync: process(clk_i)
|
begin
|
begin
|
if rising_edge(clk_i) then
|
if rising_edge(clk_i) then
|
|
execute_engine.state_prev <= execute_engine.state;
|
execute_engine.i_reg <= execute_engine.i_reg_nxt;
|
execute_engine.i_reg <= execute_engine.i_reg_nxt;
|
execute_engine.is_ci <= execute_engine.is_ci_nxt;
|
execute_engine.is_ci <= execute_engine.is_ci_nxt;
|
execute_engine.is_jump <= execute_engine.is_jump_nxt;
|
execute_engine.is_jump <= execute_engine.is_jump_nxt;
|
-- control signals --
|
--
|
ctrl <= ctrl_nxt;
|
ctrl <= ctrl_nxt;
|
end if;
|
end if;
|
end process execute_engine_fsm_sync;
|
end process execute_engine_fsm_sync;
|
|
|
-- PC output --
|
-- PC output --
|
Line 685... |
Line 687... |
ctrl_nxt(ctrl_alu_opb_mux_lsb_c) <= alu_immediate_v; -- use IMM as ALU.OPB for immediate operations
|
ctrl_nxt(ctrl_alu_opb_mux_lsb_c) <= alu_immediate_v; -- use IMM as ALU.OPB for immediate operations
|
ctrl_nxt(ctrl_alu_opc_mux_c) <= not alu_immediate_v;
|
ctrl_nxt(ctrl_alu_opc_mux_c) <= not alu_immediate_v;
|
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_operation_v; -- actual ALU operation
|
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_operation_v; -- actual ALU operation
|
ctrl_nxt(ctrl_rf_in_mux_msb_c downto ctrl_rf_in_mux_lsb_c) <= "00"; -- RF input = ALU result
|
ctrl_nxt(ctrl_rf_in_mux_msb_c downto ctrl_rf_in_mux_lsb_c) <= "00"; -- RF input = ALU result
|
-- multi cycle alu operation? --
|
-- multi cycle alu operation? --
|
if (alu_operation_v = alu_cmd_shift_c) or -- shift operation
|
if (alu_operation_v = alu_cmd_shift_c) or -- shift operation?
|
((CPU_EXTENSION_RISCV_M = true) and (execute_engine.i_reg(instr_opcode_msb_c downto instr_opcode_lsb_c) = opcode_alu_c) and
|
((CPU_EXTENSION_RISCV_M = true) and (execute_engine.i_reg(instr_opcode_msb_c downto instr_opcode_lsb_c) = opcode_alu_c) and
|
(execute_engine.i_reg(instr_funct7_lsb_c) = '1')) then -- MULDIV?
|
(execute_engine.i_reg(instr_funct7_lsb_c) = '1')) then -- MULDIV?
|
execute_engine.state_nxt <= ALU_WAIT;
|
execute_engine.state_nxt <= ALU_WAIT;
|
else
|
else
|
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back
|
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back
|
Line 699... |
Line 701... |
if (CPU_EXTENSION_RISCV_M = true) and (execute_engine.i_reg(instr_opcode_msb_c downto instr_opcode_lsb_c) = opcode_alu_c) and
|
if (CPU_EXTENSION_RISCV_M = true) and (execute_engine.i_reg(instr_opcode_msb_c downto instr_opcode_lsb_c) = opcode_alu_c) and
|
(execute_engine.i_reg(instr_funct7_lsb_c) = '1') then -- MULDIV?
|
(execute_engine.i_reg(instr_funct7_lsb_c) = '1') then -- MULDIV?
|
ctrl_nxt(ctrl_cp_use_c) <= '1'; -- use CP
|
ctrl_nxt(ctrl_cp_use_c) <= '1'; -- use CP
|
end if;
|
end if;
|
|
|
|
|
when opcode_lui_c | opcode_auipc_c => -- load upper immediate (add to PC)
|
when opcode_lui_c | opcode_auipc_c => -- load upper immediate (add to PC)
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
ctrl_nxt(ctrl_rf_clear_rs1_c) <= '1'; -- force RS1 = r0 (only relevant for LUI)
|
ctrl_nxt(ctrl_rf_clear_rs1_c) <= '1'; -- force RS1 = r0 (only relevant for LUI)
|
if (execute_engine.i_reg(instr_opcode_msb_c downto instr_opcode_lsb_c) = opcode_auipc_c) then -- AUIPC
|
if (execute_engine.i_reg(instr_opcode_msb_c downto instr_opcode_lsb_c) = opcode_auipc_c) then -- AUIPC
|
ctrl_nxt(ctrl_alu_opa_mux_lsb_c) <= '1'; -- use PC as ALU.OPA
|
ctrl_nxt(ctrl_alu_opa_mux_lsb_c) <= '1'; -- use PC as ALU.OPA
|
Line 837... |
Line 838... |
-- RF write back --
|
-- RF write back --
|
ctrl_nxt(ctrl_rf_in_mux_msb_c downto ctrl_rf_in_mux_lsb_c) <= "11"; -- RF input = CSR output
|
ctrl_nxt(ctrl_rf_in_mux_msb_c downto ctrl_rf_in_mux_lsb_c) <= "11"; -- RF input = CSR output
|
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back
|
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back
|
execute_engine.state_nxt <= DISPATCH; -- FIXME should be SYS_WAIT? have another cycle to let side-effects kick in
|
execute_engine.state_nxt <= DISPATCH; -- FIXME should be SYS_WAIT? have another cycle to let side-effects kick in
|
|
|
when ALU_WAIT => -- wait for multi-cycle ALU operation to finish
|
when ALU_WAIT => -- wait for multi-cycle ALU operation (shifter or CP) to finish
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_operation_v; -- actual ALU operation
|
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_shift_c;
|
ctrl_nxt(ctrl_rf_in_mux_msb_c downto ctrl_rf_in_mux_lsb_c) <= "00"; -- RF input = ALU result
|
ctrl_nxt(ctrl_rf_in_mux_msb_c downto ctrl_rf_in_mux_lsb_c) <= "00"; -- RF input = ALU result
|
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back (permanent write-back)
|
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back (permanent write-back)
|
|
-- cp access? --
|
|
if (CPU_EXTENSION_RISCV_M = true) and (execute_engine.i_reg(instr_funct7_lsb_c) = '1') then -- MULDIV?
|
|
ctrl_nxt(ctrl_cp_use_c) <= '1'; -- use CP
|
|
end if;
|
|
-- wait for result --
|
if (alu_wait_i = '0') then
|
if (alu_wait_i = '0') then
|
execute_engine.state_nxt <= DISPATCH;
|
execute_engine.state_nxt <= DISPATCH;
|
end if;
|
end if;
|
|
|
when BRANCH => -- update PC for taken branches and jumps
|
when BRANCH => -- update PC for taken branches and jumps
|
Line 1618... |
Line 1624... |
when x"c82" | x"b82" => -- R/(W): instreth/minstreth: Instructions-retired counter HIGH
|
when x"c82" | x"b82" => -- R/(W): instreth/minstreth: Instructions-retired counter HIGH
|
csr_rdata_o <= x"000" & csr.minstreth(19 downto 0); -- only the lowest 20 bit!
|
csr_rdata_o <= x"000" & csr.minstreth(19 downto 0); -- only the lowest 20 bit!
|
|
|
-- machine information registers --
|
-- machine information registers --
|
when x"f11" => -- R/-: mvendorid
|
when x"f11" => -- R/-: mvendorid
|
csr_rdata_o <= (others => '0'); -- not yet assigned for NEORV32
|
csr_rdata_o <= (others => '0'); -- not available for NEORV32
|
when x"f12" => -- R/-: marchid
|
when x"f12" => -- R/-: marchid
|
csr_rdata_o <= (others => '0'); -- not yet assigned for NEORV32
|
csr_rdata_o <= (others => '0'); -- not available for NEORV32
|
when x"f13" => -- R/-: mimpid - implementation ID / NEORV32: version
|
when x"f13" => -- R/-: mimpid - implementation ID / NEORV32: version
|
csr_rdata_o <= hw_version_c;
|
csr_rdata_o <= hw_version_c;
|
when x"f14" => -- R/-: mhartid - hardware thread ID
|
when x"f14" => -- R/-: mhartid - hardware thread ID
|
csr_rdata_o <= HW_THREAD_ID;
|
csr_rdata_o <= HW_THREAD_ID;
|
|
|
Line 1692... |
Line 1698... |
-- minstret (instret) --
|
-- minstret (instret) --
|
minstret_msb <= csr.minstret(csr.minstret'left);
|
minstret_msb <= csr.minstret(csr.minstret'left);
|
if (csr.we = '1') and (execute_engine.i_reg(31 downto 20) = x"b02") then -- write access
|
if (csr.we = '1') and (execute_engine.i_reg(31 downto 20) = x"b02") then -- write access
|
csr.minstret(31 downto 0) <= csr_wdata_i;
|
csr.minstret(31 downto 0) <= csr_wdata_i;
|
csr.minstret(32) <= '0';
|
csr.minstret(32) <= '0';
|
elsif (execute_engine.state_nxt /= EXECUTE) and (execute_engine.state = EXECUTE) then -- automatic update
|
elsif (execute_engine.state_prev /= EXECUTE) and (execute_engine.state = EXECUTE) then -- automatic update
|
csr.minstret <= std_ulogic_vector(unsigned(csr.minstret) + 1);
|
csr.minstret <= std_ulogic_vector(unsigned(csr.minstret) + 1);
|
end if;
|
end if;
|
|
|
-- minstreth (instreth) --
|
-- minstreth (instreth) --
|
if (csr.we = '1') and (execute_engine.i_reg(31 downto 20) = x"b82") then -- write access
|
if (csr.we = '1') and (execute_engine.i_reg(31 downto 20) = x"b82") then -- write access
|