Line 46... |
Line 46... |
use neorv32.neorv32_package.all;
|
use neorv32.neorv32_package.all;
|
|
|
entity neorv32_cpu_control is
|
entity neorv32_cpu_control is
|
generic (
|
generic (
|
-- General --
|
-- General --
|
HW_THREAD_ID : std_ulogic_vector(31 downto 0):= x"00000000"; -- hardware thread id
|
HW_THREAD_ID : natural := 0; -- hardware thread id (32-bit)
|
CPU_BOOT_ADDR : std_ulogic_vector(31 downto 0):= x"00000000"; -- cpu boot address
|
CPU_BOOT_ADDR : std_ulogic_vector(31 downto 0):= x"00000000"; -- cpu boot address
|
-- RISC-V CPU Extensions --
|
-- RISC-V CPU Extensions --
|
CPU_EXTENSION_RISCV_A : boolean := false; -- implement atomic extension?
|
CPU_EXTENSION_RISCV_A : boolean := false; -- implement atomic extension?
|
CPU_EXTENSION_RISCV_B : boolean := false; -- implement bit manipulation extensions?
|
CPU_EXTENSION_RISCV_B : boolean := false; -- implement bit manipulation extensions?
|
CPU_EXTENSION_RISCV_C : boolean := false; -- implement compressed extension?
|
CPU_EXTENSION_RISCV_C : boolean := false; -- implement compressed extension?
|
CPU_EXTENSION_RISCV_E : boolean := false; -- implement embedded RF extension?
|
CPU_EXTENSION_RISCV_E : boolean := false; -- implement embedded RF extension?
|
CPU_EXTENSION_RISCV_M : boolean := false; -- implement muld/div extension?
|
CPU_EXTENSION_RISCV_M : boolean := false; -- implement muld/div extension?
|
CPU_EXTENSION_RISCV_U : boolean := false; -- implement user mode extension?
|
CPU_EXTENSION_RISCV_U : boolean := false; -- implement user mode extension?
|
CPU_EXTENSION_RISCV_Zicsr : boolean := true; -- implement CSR system?
|
CPU_EXTENSION_RISCV_Zicsr : boolean := true; -- implement CSR system?
|
CPU_EXTENSION_RISCV_Zifencei : boolean := true; -- implement instruction stream sync.?
|
CPU_EXTENSION_RISCV_Zifencei : boolean := false; -- implement instruction stream sync.?
|
-- Physical memory protection (PMP) --
|
-- Physical memory protection (PMP) --
|
PMP_NUM_REGIONS : natural := 0; -- number of regions (0..64)
|
PMP_NUM_REGIONS : natural := 0; -- number of regions (0..64)
|
PMP_MIN_GRANULARITY : natural := 64*1024; -- minimal region granularity in bytes, has to be a power of 2, min 8 bytes
|
PMP_MIN_GRANULARITY : natural := 64*1024; -- minimal region granularity in bytes, has to be a power of 2, min 8 bytes
|
-- Hardware Performance Monitors (HPM) --
|
-- Hardware Performance Monitors (HPM) --
|
HPM_NUM_CNTS : natural := 0 -- number of implemented HPM counters (0..29)
|
HPM_NUM_CNTS : natural := 0 -- number of implemented HPM counters (0..29)
|
Line 174... |
Line 174... |
rs1_is_r0 : std_ulogic;
|
rs1_is_r0 : std_ulogic;
|
is_atomic_lr : std_ulogic;
|
is_atomic_lr : std_ulogic;
|
is_atomic_sc : std_ulogic;
|
is_atomic_sc : std_ulogic;
|
is_bitmanip_imm : std_ulogic;
|
is_bitmanip_imm : std_ulogic;
|
is_bitmanip_reg : std_ulogic;
|
is_bitmanip_reg : std_ulogic;
|
|
sys_env_cmd : std_ulogic_vector(11 downto 0);
|
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, EXECUTE, ALU_WAIT, BRANCH, FENCE_OP, LOADSTORE_0, LOADSTORE_1, LOADSTORE_2, SYS_ENV, CSR_ACCESS);
|
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, 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 195... |
Line 197... |
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 fullfilled
|
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_vector(1 downto 0); -- 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
|
last_pc : std_ulogic_vector(data_width_c-1 downto 0); -- PC of last executed instruction
|
last_pc : std_ulogic_vector(data_width_c-1 downto 0); -- PC of last executed instruction
|
--
|
--
|
sleep : std_ulogic; -- CPU in sleep mode
|
sleep : std_ulogic; -- CPU in sleep mode
|
sleep_nxt : std_ulogic;
|
sleep_nxt : std_ulogic;
|
if_rst : std_ulogic; -- instruction fetch was reset
|
branched : std_ulogic; -- instruction fetch was reset
|
if_rst_nxt : std_ulogic;
|
branched_nxt : std_ulogic;
|
end record;
|
end record;
|
signal execute_engine : execute_engine_t;
|
signal execute_engine : execute_engine_t;
|
|
|
-- trap controller --
|
-- trap controller --
|
type trap_ctrl_t is record
|
type trap_ctrl_t is record
|
Line 294... |
Line 297... |
privilege : std_ulogic_vector(1 downto 0); -- hart's current privilege mode
|
privilege : std_ulogic_vector(1 downto 0); -- hart's current privilege mode
|
priv_m_mode : std_ulogic; -- CPU in M-mode
|
priv_m_mode : std_ulogic; -- CPU in M-mode
|
priv_u_mode : std_ulogic; -- CPU in u-mode
|
priv_u_mode : std_ulogic; -- CPU in u-mode
|
--
|
--
|
mepc : std_ulogic_vector(data_width_c-1 downto 0); -- mepc: machine exception pc (R/W)
|
mepc : std_ulogic_vector(data_width_c-1 downto 0); -- mepc: machine exception pc (R/W)
|
mcause : std_ulogic_vector(data_width_c-1 downto 0); -- mcause: machine trap cause (R/W)
|
mcause : std_ulogic_vector(5 downto 0); -- mcause: machine trap cause (R/W)
|
mtvec : std_ulogic_vector(data_width_c-1 downto 0); -- mtvec: machine trap-handler base address (R/W), bit 1:0 == 00
|
mtvec : std_ulogic_vector(data_width_c-1 downto 0); -- mtvec: machine trap-handler base address (R/W), bit 1:0 == 00
|
mtval : std_ulogic_vector(data_width_c-1 downto 0); -- mtval: machine bad address or isntruction (R/W)
|
mtval : std_ulogic_vector(data_width_c-1 downto 0); -- mtval: machine bad address or instruction (R/W)
|
--
|
--
|
mhpmevent : mhpmevent_t; -- mhpmevent*: machine performance-monitoring event selector (R/W)
|
mhpmevent : mhpmevent_t; -- mhpmevent*: machine performance-monitoring event selector (R/W)
|
mhpmevent_rd : mhpmevent_rd_t; -- mhpmevent*: actual read data
|
mhpmevent_rd : mhpmevent_rd_t; -- mhpmevent*: actual read data
|
--
|
--
|
mscratch : std_ulogic_vector(data_width_c-1 downto 0); -- mscratch: scratch register (R/W)
|
mscratch : std_ulogic_vector(data_width_c-1 downto 0); -- mscratch: scratch register (R/W)
|
Line 385... |
Line 388... |
ipb.clear <= '0';
|
ipb.clear <= '0';
|
|
|
-- state machine --
|
-- state machine --
|
case fetch_engine.state is
|
case fetch_engine.state is
|
|
|
when IFETCH_RESET => -- reset engine and prefetch buffer, get appilcation PC
|
when IFETCH_RESET => -- reset engine and prefetch buffer, get application PC
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
fetch_engine.bus_err_ack <= '1'; -- acknowledge any instruction bus errors, the execute engine has to take care of them / terminate current transfer
|
fetch_engine.bus_err_ack <= '1'; -- acknowledge any instruction bus errors, the execute engine has to take care of them / terminate current transfer
|
fetch_engine.pc_nxt <= execute_engine.pc(data_width_c-1 downto 1) & '0'; -- initialize with "real" application PC
|
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
|
ipb.clear <= '1'; -- clear prefetch buffer
|
fetch_engine.state_nxt <= IFETCH_REQUEST;
|
fetch_engine.state_nxt <= IFETCH_REQUEST;
|
Line 597... |
Line 600... |
imm_gen: process(execute_engine.i_reg, clk_i)
|
imm_gen: process(execute_engine.i_reg, clk_i)
|
variable opcode_v : std_ulogic_vector(6 downto 0);
|
variable opcode_v : std_ulogic_vector(6 downto 0);
|
begin
|
begin
|
opcode_v := execute_engine.i_reg(instr_opcode_msb_c downto instr_opcode_lsb_c+2) & "11";
|
opcode_v := execute_engine.i_reg(instr_opcode_msb_c downto instr_opcode_lsb_c+2) & "11";
|
if rising_edge(clk_i) then
|
if rising_edge(clk_i) then
|
if (execute_engine.state = BRANCH) then -- next_PC as immediate for jump-and-link operations (=return address)
|
if (execute_engine.state = BRANCH) then -- next_PC as immediate for jump-and-link operations (=return address) via ALU.MOV_B
|
imm_o <= execute_engine.next_pc;
|
imm_o <= execute_engine.next_pc;
|
else -- "normal" immediate from instruction
|
else -- "normal" immediate from instruction word
|
case opcode_v is -- save some bits here, LSBs are always 11 for rv32
|
case opcode_v is -- save some bits here, the two LSBs are always "11" for rv32
|
when opcode_store_c => -- S-immediate
|
when opcode_store_c => -- S-immediate
|
imm_o(31 downto 11) <= (others => execute_engine.i_reg(31)); -- sign extension
|
imm_o(31 downto 11) <= (others => execute_engine.i_reg(31)); -- sign extension
|
imm_o(10 downto 05) <= execute_engine.i_reg(30 downto 25);
|
imm_o(10 downto 05) <= execute_engine.i_reg(30 downto 25);
|
imm_o(04 downto 01) <= execute_engine.i_reg(11 downto 08);
|
imm_o(04 downto 01) <= execute_engine.i_reg(11 downto 08);
|
imm_o(00) <= execute_engine.i_reg(07);
|
imm_o(00) <= execute_engine.i_reg(07);
|
Line 664... |
Line 667... |
begin
|
begin
|
if (rstn_i = '0') then
|
if (rstn_i = '0') then
|
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.if_rst <= '1'; -- instruction fetch is reset after system reset
|
execute_engine.branched <= '1'; -- reset is a branch from "somewhere"
|
elsif rising_edge(clk_i) then
|
elsif rising_edge(clk_i) then
|
-- PC update --
|
-- PC update --
|
if (execute_engine.pc_we = '1') then
|
if (execute_engine.pc_we = '1') then
|
case execute_engine.pc_mux_sel is
|
if (execute_engine.pc_mux_sel = '0') then
|
when "00" => execute_engine.pc <= alu_add_i(data_width_c-1 downto 1) & '0'; -- jump/taken_branch
|
execute_engine.pc <= execute_engine.next_pc(data_width_c-1 downto 1) & '0'; -- normal (linear) increment
|
when "01" => execute_engine.pc <= execute_engine.next_pc(data_width_c-1 downto 1) & '0'; -- normal (linear) increment
|
else
|
when "10" => execute_engine.pc <= csr.mtvec(data_width_c-1 downto 1) & '0'; -- trap enter
|
execute_engine.pc <= alu_add_i(data_width_c-1 downto 1) & '0'; -- jump/taken_branch
|
when others => execute_engine.pc <= csr.mepc(data_width_c-1 downto 1) & '0'; -- trap exit
|
end if;
|
end case;
|
|
end if;
|
end if;
|
--
|
--
|
execute_engine.state <= execute_engine.state_nxt;
|
execute_engine.state <= execute_engine.state_nxt;
|
execute_engine.sleep <= execute_engine.sleep_nxt;
|
execute_engine.sleep <= execute_engine.sleep_nxt;
|
execute_engine.if_rst <= execute_engine.if_rst_nxt;
|
execute_engine.branched <= execute_engine.branched_nxt;
|
end if;
|
end if;
|
end process execute_engine_fsm_sync_rst;
|
end process execute_engine_fsm_sync_rst;
|
|
|
|
|
-- for registers that do NOT require a specific reset state --
|
-- for registers that do NOT require a specific reset state --
|
Line 691... |
Line 693... |
if rising_edge(clk_i) then
|
if rising_edge(clk_i) then
|
execute_engine.state_prev <= execute_engine.state;
|
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_cp_op <= execute_engine.is_cp_op_nxt;
|
execute_engine.is_cp_op <= execute_engine.is_cp_op_nxt;
|
-- next PC (next linear instruction) --
|
-- PC & IR of "last executed" instruction --
|
if (execute_engine.state = EXECUTE) then
|
|
if (execute_engine.is_ci = '1') then -- compressed instruction?
|
|
execute_engine.next_pc <= std_ulogic_vector(unsigned(execute_engine.pc) + 2);
|
|
else
|
|
execute_engine.next_pc <= std_ulogic_vector(unsigned(execute_engine.pc) + 4);
|
|
end if;
|
|
end if;
|
|
-- PC & IR of last "executed" instruction --
|
|
if (execute_engine.state = EXECUTE) then
|
if (execute_engine.state = EXECUTE) then
|
execute_engine.last_pc <= execute_engine.pc;
|
execute_engine.last_pc <= execute_engine.pc;
|
execute_engine.i_reg_last <= execute_engine.i_reg;
|
execute_engine.i_reg_last <= execute_engine.i_reg;
|
end if;
|
end if;
|
|
-- next PC --
|
|
case execute_engine.state is
|
|
when TRAP_ENTER => execute_engine.next_pc <= csr.mtvec(data_width_c-1 downto 1) & '0'; -- trap enter
|
|
when TRAP_EXIT => execute_engine.next_pc <= csr.mepc(data_width_c-1 downto 1) & '0'; -- trap exit
|
|
when EXECUTE => execute_engine.next_pc <= std_ulogic_vector(unsigned(execute_engine.pc) + unsigned(execute_engine.next_pc_inc)); -- next linear PC
|
|
when others => NULL;
|
|
end case;
|
-- main control bus --
|
-- main control bus --
|
ctrl <= ctrl_nxt;
|
ctrl <= ctrl_nxt;
|
end if;
|
end if;
|
end process execute_engine_fsm_sync;
|
end process execute_engine_fsm_sync;
|
|
|
-- CSR access address --
|
-- PC increment for next linear instruction (+2 for compressed instr., +4 otherwise) --
|
csr.addr <= execute_engine.i_reg(instr_csr_id_msb_c downto instr_csr_id_lsb_c);
|
execute_engine.next_pc_inc <= x"00000004" when ((execute_engine.is_ci = '0') or (CPU_EXTENSION_RISCV_C = false)) else x"00000002";
|
|
|
-- PC output --
|
-- PC output --
|
curr_pc_o <= execute_engine.pc(data_width_c-1 downto 1) & '0'; -- PC for ALU ops
|
curr_pc_o <= execute_engine.pc(data_width_c-1 downto 1) & '0'; -- PC for ALU ops
|
|
|
|
-- CSR access address --
|
|
csr.addr <= execute_engine.i_reg(instr_csr_id_msb_c downto instr_csr_id_lsb_c);
|
|
|
|
|
-- CPU Control Bus Output -----------------------------------------------------------------
|
-- CPU Control Bus Output -----------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
ctrl_output: process(ctrl, fetch_engine, trap_ctrl, atomic_ctrl, bus_fast_ir, execute_engine, csr)
|
ctrl_output: process(ctrl, fetch_engine, trap_ctrl, atomic_ctrl, bus_fast_ir, execute_engine, csr)
|
begin
|
begin
|
Line 753... |
Line 757... |
|
|
|
|
-- Decoding Helper Logic ------------------------------------------------------------------
|
-- Decoding Helper Logic ------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
decode_helper: process(execute_engine)
|
decode_helper: process(execute_engine)
|
|
variable sys_env_cmd_mask_v : std_ulogic_vector(11 downto 0);
|
begin
|
begin
|
-- defaults --
|
-- defaults --
|
decode_aux.alu_immediate <= '0';
|
decode_aux.alu_immediate <= '0';
|
decode_aux.rs1_is_r0 <= '0';
|
decode_aux.rs1_is_r0 <= '0';
|
decode_aux.is_atomic_lr <= '0';
|
decode_aux.is_atomic_lr <= '0';
|
Line 789... |
Line 794... |
)
|
)
|
) or
|
) or
|
((execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c+2) = "01100") and (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = "101")) or -- RORI
|
((execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c+2) = "01100") and (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = "101")) or -- RORI
|
((execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c+2) = "00101") and (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = "101") and (execute_engine.i_reg(instr_imm12_lsb_c+6 downto instr_imm12_lsb_c) = "0000111")) or -- GORCI.b 7 (orc.b)
|
((execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c+2) = "00101") and (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = "101") and (execute_engine.i_reg(instr_imm12_lsb_c+6 downto instr_imm12_lsb_c) = "0000111")) or -- GORCI.b 7 (orc.b)
|
((execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c+2) = "01101") and (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = "101") and (execute_engine.i_reg(instr_imm12_lsb_c+6 downto instr_imm12_lsb_c) = "0011000")) then -- GREVI.-8 (rev8)
|
((execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c+2) = "01101") and (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = "101") and (execute_engine.i_reg(instr_imm12_lsb_c+6 downto instr_imm12_lsb_c) = "0011000")) then -- GREVI.-8 (rev8)
|
decode_aux.is_bitmanip_imm <= '1';
|
decode_aux.is_bitmanip_imm <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_B);
|
end if;
|
end if;
|
-- register operation --
|
-- register operation --
|
if ((execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c) = "0110000") and (execute_engine.i_reg(instr_funct3_msb_c-1 downto instr_funct3_lsb_c) = "01")) or -- ROR / ROL
|
if ((execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c) = "0110000") and (execute_engine.i_reg(instr_funct3_msb_c-1 downto instr_funct3_lsb_c) = "01")) or -- ROR / ROL
|
((execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c) = "0000101") and (execute_engine.i_reg(instr_funct3_msb_c) = '1')) or -- MIN[U] / MAX[U]
|
((execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c) = "0000101") and (execute_engine.i_reg(instr_funct3_msb_c) = '1')) or -- MIN[U] / MAX[U]
|
((execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c) = "0000100") and (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = "100")) or -- PACK
|
((execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c) = "0000100") and (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = "100")) or -- PACK
|
Line 802... |
Line 807... |
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = "111") or -- ANDN
|
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = "111") or -- ANDN
|
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = "110") or -- ORN
|
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = "110") or -- ORN
|
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = "100") -- XORN
|
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = "100") -- XORN
|
)
|
)
|
) then
|
) then
|
decode_aux.is_bitmanip_reg <= '1';
|
decode_aux.is_bitmanip_reg <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_B);
|
end if;
|
end if;
|
|
-- system/environment instructions --
|
|
sys_env_cmd_mask_v := funct12_ecall_c or funct12_ebreak_c or funct12_mret_c or funct12_wfi_c; -- sum-up set bits
|
|
decode_aux.sys_env_cmd(11 downto 0) <= execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) and sys_env_cmd_mask_v; -- set unsued bits to always-zero
|
end process decode_helper;
|
end process decode_helper;
|
|
|
|
|
-- Execute Engine FSM Comb ----------------------------------------------------------------
|
-- Execute Engine FSM Comb ----------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
Line 819... |
Line 827... |
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;
|
execute_engine.is_cp_op_nxt <= execute_engine.is_cp_op;
|
execute_engine.is_cp_op_nxt <= execute_engine.is_cp_op;
|
execute_engine.is_ci_nxt <= execute_engine.is_ci;
|
execute_engine.is_ci_nxt <= execute_engine.is_ci;
|
execute_engine.sleep_nxt <= execute_engine.sleep;
|
execute_engine.sleep_nxt <= execute_engine.sleep;
|
execute_engine.if_rst_nxt <= execute_engine.if_rst;
|
execute_engine.branched_nxt <= execute_engine.branched;
|
--
|
--
|
execute_engine.pc_mux_sel <= (others => '0'); -- select "slowest path" as default
|
execute_engine.pc_mux_sel <= '0';
|
execute_engine.pc_we <= '0';
|
execute_engine.pc_we <= '0';
|
|
|
-- instruction dispatch --
|
-- instruction dispatch --
|
fetch_engine.reset <= '0';
|
fetch_engine.reset <= '0';
|
|
|
Line 868... |
Line 876... |
|
|
when SYS_WAIT => -- System delay cycle (used to wait for side effects to kick in) [and to init r0 with zero if it is a physical register]
|
when SYS_WAIT => -- System delay cycle (used to wait for side effects to kick in) [and to init r0 with zero if it is a physical register]
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
-- set reg_file's r0 to zero --
|
-- set reg_file's r0 to zero --
|
if (rf_r0_is_reg_c = true) then -- is r0 implemented as physical register, which has to be set to zero?
|
if (rf_r0_is_reg_c = true) then -- is r0 implemented as physical register, which has to be set to zero?
|
ctrl_nxt(ctrl_rf_in_mux_msb_c downto ctrl_rf_in_mux_lsb_c) <= "11"; -- RF input = CSR output (hacky! results zero since there is no valid CSR-read)
|
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_copro_c; -- hacky! CSR read-access CP selected without a valid CSR-read -> results zero
|
|
ctrl_nxt(ctrl_cp_id_msb_c downto ctrl_cp_id_lsb_c) <= cp_sel_csr_rd_c; -- use CSR-READ CP
|
ctrl_nxt(ctrl_rf_r0_we_c) <= '1'; -- force RF write access and force rd=r0
|
ctrl_nxt(ctrl_rf_r0_we_c) <= '1'; -- force RF write access and force rd=r0
|
end if;
|
end if;
|
--
|
--
|
execute_engine.state_nxt <= DISPATCH;
|
execute_engine.state_nxt <= DISPATCH;
|
|
|
|
|
when DISPATCH => -- Get new command from instruction issue engine
|
when DISPATCH => -- Get new command from instruction issue engine
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
|
-- PC update --
|
|
execute_engine.pc_mux_sel <= '0'; -- linear next PC
|
-- IR update --
|
-- IR update --
|
execute_engine.pc_mux_sel <= "01"; -- linear next PC
|
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 beeing executed
|
|
execute_engine.i_reg_nxt <= cmd_issue.data(31 downto 0);
|
execute_engine.i_reg_nxt <= cmd_issue.data(31 downto 0);
|
--
|
--
|
if (cmd_issue.valid = '1') then -- instruction available?
|
if (cmd_issue.valid = '1') then -- instruction available?
|
|
-- PC update --
|
|
execute_engine.branched_nxt <= '0';
|
|
execute_engine.pc_we <= not execute_engine.branched; -- update PC with linear next_pc if there was no actual branch
|
-- IR update - exceptions --
|
-- IR update - exceptions --
|
trap_ctrl.instr_ma <= cmd_issue.data(33); -- misaligned instruction fetch address
|
trap_ctrl.instr_ma <= cmd_issue.data(33); -- misaligned instruction fetch address
|
trap_ctrl.instr_be <= cmd_issue.data(34); -- bus access fault during instruction fetch
|
trap_ctrl.instr_be <= cmd_issue.data(34); -- bus access fault during instruction fetch
|
illegal_compressed <= cmd_issue.data(35); -- invalid decompressed instruction
|
illegal_compressed <= cmd_issue.data(35); -- invalid decompressed instruction
|
-- PC update --
|
|
execute_engine.if_rst_nxt <= '0';
|
|
execute_engine.pc_we <= not execute_engine.if_rst; -- update PC with linear next_pc if there was NO non-linear PC modification
|
|
-- any reason to go to trap state? --
|
-- any reason to go to trap state? --
|
if (execute_engine.sleep = '1') or (trap_ctrl.env_start = '1') or (trap_ctrl.exc_fire = '1') or ((cmd_issue.data(33) or cmd_issue.data(34)) = '1') then
|
if (execute_engine.sleep = '1') or (trap_ctrl.env_start = '1') or (trap_ctrl.exc_fire = '1') or ((cmd_issue.data(33) or cmd_issue.data(34)) = '1') then
|
execute_engine.state_nxt <= TRAP;
|
execute_engine.state_nxt <= TRAP_ENTER;
|
else
|
else
|
execute_engine.state_nxt <= EXECUTE;
|
execute_engine.state_nxt <= EXECUTE;
|
end if;
|
end if;
|
end if;
|
end if;
|
|
|
|
|
when TRAP => -- Start trap environment (also used as cpu sleep state)
|
when TRAP_ENTER => -- Start trap environment - get MTVEC, stay here for sleep mode
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
execute_engine.pc_mux_sel <= "10"; -- csr.mtvec (trap)
|
|
execute_engine.if_rst_nxt <= '1'; -- this will be a non-linear PC modification
|
|
if (trap_ctrl.env_start = '1') then -- trap triggered?
|
if (trap_ctrl.env_start = '1') then -- trap triggered?
|
trap_ctrl.env_start_ack <= '1';
|
trap_ctrl.env_start_ack <= '1';
|
|
execute_engine.state_nxt <= TRAP_EXECUTE;
|
|
end if;
|
|
|
|
when TRAP_EXIT => -- Return from trap environment - get MEPC
|
|
-- ------------------------------------------------------------
|
|
trap_ctrl.env_end <= '1';
|
|
execute_engine.state_nxt <= TRAP_EXECUTE;
|
|
|
|
when TRAP_EXECUTE => -- Start trap environment - jump to MTVEC / return from trap environment - jump to MEPC
|
|
-- ------------------------------------------------------------
|
|
execute_engine.pc_mux_sel <= '0'; -- next PC (csr.mtvec)
|
fetch_engine.reset <= '1';
|
fetch_engine.reset <= '1';
|
execute_engine.pc_we <= '1';
|
execute_engine.pc_we <= '1';
|
execute_engine.sleep_nxt <= '0'; -- waky waky
|
execute_engine.sleep_nxt <= '0'; -- disable sleep mode
|
execute_engine.state_nxt <= SYS_WAIT;
|
execute_engine.state_nxt <= SYS_WAIT;
|
end if;
|
|
|
|
|
|
when EXECUTE => -- Decode and execute instruction (control has to be here for excatly 1 cyle in any case!)
|
when EXECUTE => -- Decode and execute instruction (control has to be here for excatly 1 cyle in any case!)
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
opcode_v := execute_engine.i_reg(instr_opcode_msb_c downto instr_opcode_lsb_c+2) & "11"; -- save some bits here, LSBs are always 11 for rv32
|
opcode_v := execute_engine.i_reg(instr_opcode_msb_c downto instr_opcode_lsb_c+2) & "11"; -- save some bits here, LSBs are always 11 for rv32
|
Line 921... |
Line 939... |
|
|
when opcode_alu_c | opcode_alui_c => -- (immediate) ALU operation
|
when opcode_alu_c | opcode_alui_c => -- (immediate) ALU operation
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
ctrl_nxt(ctrl_alu_opa_mux_c) <= '0'; -- use RS1 as ALU.OPA
|
ctrl_nxt(ctrl_alu_opa_mux_c) <= '0'; -- use RS1 as ALU.OPA
|
ctrl_nxt(ctrl_alu_opb_mux_c) <= decode_aux.alu_immediate; -- use IMM as ALU.OPB for immediate operations
|
ctrl_nxt(ctrl_alu_opb_mux_c) <= decode_aux.alu_immediate; -- use IMM as ALU.OPB for immediate operations
|
ctrl_nxt(ctrl_rf_in_mux_msb_c) <= '0'; -- RF input = ALU result
|
ctrl_nxt(ctrl_rf_in_mux_c) <= '0'; -- RF input = ALU result
|
|
|
-- ALU arithmetic operation type and ADD/SUB --
|
-- ALU arithmetic operation type and ADD/SUB --
|
if (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_slt_c) or
|
if (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_slt_c) or
|
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_sltu_c) then
|
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_sltu_c) then
|
ctrl_nxt(ctrl_alu_arith_c) <= alu_arith_cmd_slt_c;
|
ctrl_nxt(ctrl_alu_arith_c) <= alu_arith_cmd_slt_c;
|
Line 993... |
Line 1011... |
if (execute_engine.i_reg(instr_opcode_lsb_c+5) = opcode_lui_c(5)) then -- LUI
|
if (execute_engine.i_reg(instr_opcode_lsb_c+5) = opcode_lui_c(5)) then -- LUI
|
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_logic_c; -- actual ALU operation = MOVB
|
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_logic_c; -- actual ALU operation = MOVB
|
else -- AUIPC
|
else -- AUIPC
|
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_arith_c; -- actual ALU operation = ADD
|
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_arith_c; -- actual ALU operation = ADD
|
end if;
|
end if;
|
ctrl_nxt(ctrl_rf_in_mux_msb_c) <= '0'; -- RF input = ALU result
|
ctrl_nxt(ctrl_rf_in_mux_c) <= '0'; -- RF input = ALU result
|
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;
|
execute_engine.state_nxt <= DISPATCH;
|
|
|
when opcode_load_c | opcode_store_c | opcode_atomic_c => -- load/store / atomic memory access
|
when opcode_load_c | opcode_store_c | opcode_atomic_c => -- load/store / atomic memory access
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
Line 1017... |
Line 1035... |
end if;
|
end if;
|
end if;
|
end if;
|
|
|
when opcode_branch_c | opcode_jal_c | opcode_jalr_c => -- branch / jump and link (with register)
|
when opcode_branch_c | opcode_jal_c | opcode_jalr_c => -- branch / jump and link (with register)
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
-- compute target address --
|
-- target address (ALU.ADD) operands --
|
ctrl_nxt(ctrl_alu_arith_c) <= alu_arith_cmd_addsub_c; -- actual ALU operation = ADD
|
|
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_arith_c; -- actual ALU operation = ADD
|
|
if (execute_engine.i_reg(instr_opcode_lsb_c+3 downto instr_opcode_lsb_c+2) = opcode_jalr_c(3 downto 2)) then -- JALR
|
if (execute_engine.i_reg(instr_opcode_lsb_c+3 downto instr_opcode_lsb_c+2) = opcode_jalr_c(3 downto 2)) then -- JALR
|
ctrl_nxt(ctrl_alu_opa_mux_c) <= '0'; -- use RS1 as ALU.OPA (branch target address base)
|
ctrl_nxt(ctrl_alu_opa_mux_c) <= '0'; -- use RS1 as ALU.OPA (branch target address base)
|
else -- JAL / branch
|
else -- JAL
|
ctrl_nxt(ctrl_alu_opa_mux_c) <= '1'; -- use PC as ALU.OPA (branch target address base)
|
ctrl_nxt(ctrl_alu_opa_mux_c) <= '1'; -- use PC as ALU.OPA (branch target address base)
|
end if;
|
end if;
|
ctrl_nxt(ctrl_alu_opb_mux_c) <= '1'; -- use IMM as ALU.OPB (branch target address offset)
|
ctrl_nxt(ctrl_alu_opb_mux_c) <= '1'; -- use IMM as ALU.OPB (branch target address offset)
|
--
|
|
execute_engine.state_nxt <= BRANCH;
|
execute_engine.state_nxt <= BRANCH;
|
|
|
when opcode_fence_c => -- fence operations
|
when opcode_fence_c => -- fence operations
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
execute_engine.state_nxt <= FENCE_OP;
|
execute_engine.state_nxt <= FENCE_OP;
|
|
|
when opcode_syscsr_c => -- system/csr access
|
when opcode_syscsr_c => -- system/csr access
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
if (CPU_EXTENSION_RISCV_Zicsr = true) then
|
if (CPU_EXTENSION_RISCV_Zicsr = true) then
|
csr.re_nxt <= csr_acc_valid; -- always read CSR if valid access, only relevant for CSR-instructions
|
csr.re_nxt <= csr_acc_valid; -- always read CSR if valid access, only relevant for CSR-instructions
|
|
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_copro_c; -- only relevant for CSR-instructions
|
|
ctrl_nxt(ctrl_cp_id_msb_c downto ctrl_cp_id_lsb_c) <= cp_sel_csr_rd_c; -- use CSR-READ CP, only relevant for CSR-instructions
|
if (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_env_c) then -- system/environment
|
if (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_env_c) then -- system/environment
|
execute_engine.state_nxt <= SYS_ENV;
|
execute_engine.state_nxt <= SYS_ENV;
|
else -- CSR access
|
else -- CSR access
|
execute_engine.state_nxt <= CSR_ACCESS;
|
execute_engine.state_nxt <= CSR_ACCESS;
|
end if;
|
end if;
|
Line 1055... |
Line 1072... |
end case;
|
end case;
|
|
|
|
|
when SYS_ENV => -- system environment operation - execution
|
when SYS_ENV => -- system environment operation - execution
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
execute_engine.pc_mux_sel <= "11"; -- csr.mepc (only relevant for MRET)
|
|
case execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) is
|
|
when funct12_ecall_c => -- ECALL
|
|
trap_ctrl.env_call <= '1';
|
|
when funct12_ebreak_c => -- EBREAK
|
|
trap_ctrl.break_point <= '1';
|
|
when funct12_mret_c => -- MRET
|
|
trap_ctrl.env_end <= '1';
|
|
execute_engine.pc_we <= '1'; -- update PC from MEPC
|
|
fetch_engine.reset <= '1';
|
|
execute_engine.if_rst_nxt <= '1'; -- this is a non-linear PC modification
|
|
when funct12_wfi_c => -- WFI
|
|
execute_engine.sleep_nxt <= '1'; -- good night
|
|
when others => -- undefined
|
|
NULL;
|
|
end case;
|
|
execute_engine.state_nxt <= SYS_WAIT;
|
execute_engine.state_nxt <= SYS_WAIT;
|
|
case decode_aux.sys_env_cmd is -- use a simplified input here (with permanent zeros)
|
|
when funct12_ecall_c => trap_ctrl.env_call <= '1'; -- ECALL
|
|
when funct12_ebreak_c => trap_ctrl.break_point <= '1'; -- EBREAK
|
|
when funct12_mret_c => execute_engine.state_nxt <= TRAP_EXIT; -- MRET
|
|
when funct12_wfi_c => execute_engine.sleep_nxt <= '1'; -- WFI
|
|
when others => NULL;-- undefined
|
|
end case;
|
|
|
|
|
when CSR_ACCESS => -- read & write status and control register (CSR)
|
when CSR_ACCESS => -- read & write status and control register (CSR)
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
-- CSR write access --
|
-- CSR write access --
|
Line 1086... |
Line 1094... |
csr.we_nxt <= (not decode_aux.rs1_is_r0) and csr_acc_valid; -- write CSR if rs1/imm is not zero and if valid access
|
csr.we_nxt <= (not decode_aux.rs1_is_r0) and csr_acc_valid; -- write CSR if rs1/imm is not zero and if valid access
|
when others => -- invalid
|
when others => -- invalid
|
csr.we_nxt <= '0';
|
csr.we_nxt <= '0';
|
end case;
|
end case;
|
-- register file write back --
|
-- register file 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_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_copro_c;
|
|
ctrl_nxt(ctrl_rf_in_mux_c) <= '0'; -- RF input = ALU result
|
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;
|
execute_engine.state_nxt <= DISPATCH;
|
|
|
|
|
when ALU_WAIT => -- wait for multi-cycle ALU operation (shifter or CP) to finish
|
when ALU_WAIT => -- wait for multi-cycle ALU operation (shifter or CP) to finish
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
ctrl_nxt(ctrl_rf_in_mux_msb_c) <= '0'; -- RF input = ALU result
|
ctrl_nxt(ctrl_rf_in_mux_c) <= '0'; -- 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 or alu.shift? --
|
-- cp access or alu.shift? --
|
if (execute_engine.is_cp_op = '1') then
|
if (execute_engine.is_cp_op = '1') then
|
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_copro_c;
|
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_copro_c;
|
else
|
else
|
Line 1113... |
Line 1122... |
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
-- get and store return address (only relevant for jump-and-link operations) --
|
-- get and store return address (only relevant for jump-and-link operations) --
|
ctrl_nxt(ctrl_alu_opb_mux_c) <= '1'; -- use IMM as ALU.OPB (next_pc from immediate generator = return address)
|
ctrl_nxt(ctrl_alu_opb_mux_c) <= '1'; -- use IMM as ALU.OPB (next_pc from immediate generator = return address)
|
ctrl_nxt(ctrl_alu_logic1_c downto ctrl_alu_logic0_c) <= alu_logic_cmd_movb_c; -- MOVB
|
ctrl_nxt(ctrl_alu_logic1_c downto ctrl_alu_logic0_c) <= alu_logic_cmd_movb_c; -- MOVB
|
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_logic_c; -- actual ALU operation = MOVB
|
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_logic_c; -- actual ALU operation = MOVB
|
ctrl_nxt(ctrl_rf_in_mux_msb_c) <= '0'; -- RF input = ALU result
|
ctrl_nxt(ctrl_rf_in_mux_c) <= '0'; -- RF input = ALU result
|
ctrl_nxt(ctrl_rf_wb_en_c) <= execute_engine.i_reg(instr_opcode_lsb_c+2); -- valid RF write-back? (is jump-and-link?)
|
ctrl_nxt(ctrl_rf_wb_en_c) <= execute_engine.i_reg(instr_opcode_lsb_c+2); -- valid RF write-back? (is jump-and-link?)
|
-- destination address --
|
-- destination address --
|
execute_engine.pc_mux_sel <= "00"; -- alu.add = branch/jump destination
|
execute_engine.pc_mux_sel <= '1'; -- alu.add = branch/jump destination
|
if (execute_engine.i_reg(instr_opcode_lsb_c+2) = '1') or (execute_engine.branch_taken = '1') then -- JAL/JALR or taken branch
|
if (execute_engine.i_reg(instr_opcode_lsb_c+2) = '1') or (execute_engine.branch_taken = '1') then -- JAL/JALR or taken branch
|
execute_engine.pc_we <= '1'; -- update PC
|
execute_engine.pc_we <= '1'; -- update PC
|
|
execute_engine.branched_nxt <= '1'; -- this is an actual branch
|
fetch_engine.reset <= '1'; -- trigger new instruction fetch from modified PC
|
fetch_engine.reset <= '1'; -- trigger new instruction fetch from modified PC
|
execute_engine.if_rst_nxt <= '1'; -- this is a non-linear PC modification
|
|
execute_engine.state_nxt <= SYS_WAIT;
|
execute_engine.state_nxt <= SYS_WAIT;
|
else
|
else
|
execute_engine.state_nxt <= DISPATCH;
|
execute_engine.state_nxt <= DISPATCH;
|
end if;
|
end if;
|
|
|
Line 1132... |
Line 1141... |
when FENCE_OP => -- fence operations - execution
|
when FENCE_OP => -- fence operations - execution
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
execute_engine.state_nxt <= SYS_WAIT;
|
execute_engine.state_nxt <= SYS_WAIT;
|
-- FENCE.I --
|
-- FENCE.I --
|
if (CPU_EXTENSION_RISCV_Zifencei = true) then
|
if (CPU_EXTENSION_RISCV_Zifencei = true) then
|
execute_engine.pc_mux_sel <= "01"; -- linear next PC = start *new* instruction fetch with next instruction (only relevant for fence.i)
|
execute_engine.pc_mux_sel <= '0'; -- linear next PC = start *new* instruction fetch with next instruction (only relevant for fence.i)
|
if (execute_engine.i_reg(instr_funct3_lsb_c) = funct3_fencei_c(0)) then
|
if (execute_engine.i_reg(instr_funct3_lsb_c) = funct3_fencei_c(0)) then
|
execute_engine.pc_we <= '1';
|
execute_engine.pc_we <= '1'; -- update PC
|
execute_engine.if_rst_nxt <= '1'; -- this is a non-linear PC modification
|
execute_engine.branched_nxt <= '1'; -- this is an actual branch
|
fetch_engine.reset <= '1';
|
fetch_engine.reset <= '1'; -- trigger new instruction fetch from modified PC
|
ctrl_nxt(ctrl_bus_fencei_c) <= '1';
|
ctrl_nxt(ctrl_bus_fencei_c) <= '1';
|
end if;
|
end if;
|
end if;
|
end if;
|
-- FENCE --
|
-- FENCE --
|
if (execute_engine.i_reg(instr_funct3_lsb_c) = funct3_fence_c(0)) then
|
if (execute_engine.i_reg(instr_funct3_lsb_c) = funct3_fence_c(0)) then
|
Line 1170... |
Line 1179... |
if (CPU_EXTENSION_RISCV_A = true) then
|
if (CPU_EXTENSION_RISCV_A = true) then
|
ctrl_nxt(ctrl_cp_id_msb_c downto ctrl_cp_id_lsb_c) <= cp_sel_atomic_c; -- 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; -- atomic.SC: result comes from "atomic co-processor"
|
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_copro_c;
|
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_copro_c;
|
end if;
|
end if;
|
-- register file write-back --
|
-- register file write-back --
|
ctrl_nxt(ctrl_rf_in_mux_lsb_c) <= '0'; -- RF input = ALU.res or MEM
|
|
if (decode_aux.is_atomic_sc = '1') then
|
if (decode_aux.is_atomic_sc = '1') then
|
ctrl_nxt(ctrl_rf_in_mux_msb_c) <= '0'; -- RF input = ALU.res (only relevant for atomic.SC)
|
ctrl_nxt(ctrl_rf_in_mux_c) <= '0'; -- RF input = ALU.res (only relevant for atomic.SC)
|
else
|
else
|
ctrl_nxt(ctrl_rf_in_mux_msb_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)
|
end if;
|
end if;
|
--
|
--
|
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 operations)
|
-- 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
|
Line 1205... |
Line 1213... |
-- ****************************************************************************************************************************
|
-- ****************************************************************************************************************************
|
-- Invalid Instruction / CSR access check
|
-- Invalid Instruction / CSR access check
|
-- ****************************************************************************************************************************
|
-- ****************************************************************************************************************************
|
|
|
|
|
-- Illegal CSR Access Check ---------------------------------------------------------------
|
-- CSR Access Check -----------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
invalid_csr_access_check: process(execute_engine.i_reg, csr)
|
csr_access_check: process(execute_engine.i_reg, csr)
|
variable csr_wacc_v : std_ulogic; -- to check access to read-only CSRs
|
variable csr_wacc_v : std_ulogic; -- to check access to read-only CSRs
|
-- variable csr_racc_v : std_ulogic; -- to check access to write-only CSRs
|
-- variable csr_racc_v : std_ulogic; -- to check access to write-only CSRs
|
variable csr_mcounteren_hpm_v : std_ulogic_vector(28 downto 0); -- max 29 HPM counters
|
variable csr_mcounteren_hpm_v : std_ulogic_vector(28 downto 0); -- max 29 HPM counters
|
begin
|
begin
|
-- is this CSR instruction really going to write/read to/from a CSR? --
|
-- is this CSR instruction really going to write/read to/from a CSR? --
|
Line 1362... |
Line 1370... |
-- custom read-only CSRs --
|
-- custom read-only CSRs --
|
when csr_mzext_c => csr_acc_valid <= (not csr_wacc_v) and csr.priv_m_mode; -- M-mode only, read-only
|
when csr_mzext_c => csr_acc_valid <= (not csr_wacc_v) and csr.priv_m_mode; -- M-mode only, read-only
|
--
|
--
|
when others => csr_acc_valid <= '0'; -- invalid access
|
when others => csr_acc_valid <= '0'; -- invalid access
|
end case;
|
end case;
|
end process invalid_csr_access_check;
|
end process csr_access_check;
|
|
|
|
|
-- Illegal Instruction Check --------------------------------------------------------------
|
-- Illegal Instruction Check --------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
illegal_instruction_check: process(execute_engine, decode_aux, csr_acc_valid)
|
illegal_instruction_check: process(execute_engine, decode_aux, csr_acc_valid)
|
Line 1608... |
Line 1616... |
for i in 0 to 15 loop
|
for i in 0 to 15 loop
|
trap_ctrl.irq_buf(interrupt_firq_0_c+i) <= csr.mie_firqe(i) and (trap_ctrl.irq_buf(interrupt_firq_0_c+i) or trap_ctrl.firq_sync(i)) and (not (trap_ctrl.irq_ack(interrupt_firq_0_c+i) or csr.mip_clear(interrupt_firq_0_c+i)));
|
trap_ctrl.irq_buf(interrupt_firq_0_c+i) <= csr.mie_firqe(i) and (trap_ctrl.irq_buf(interrupt_firq_0_c+i) or trap_ctrl.firq_sync(i)) and (not (trap_ctrl.irq_ack(interrupt_firq_0_c+i) or csr.mip_clear(interrupt_firq_0_c+i)));
|
end loop;
|
end loop;
|
-- trap control --
|
-- trap control --
|
if (trap_ctrl.env_start = '0') then -- no started trap handler
|
if (trap_ctrl.env_start = '0') then -- no started trap handler
|
if (trap_ctrl.exc_fire = '1') or ((trap_ctrl.irq_fire = '1') and -- exception/IRQ detected!
|
if (trap_ctrl.exc_fire = '1') or ((trap_ctrl.irq_fire = '1') and -- trap triggered!
|
((execute_engine.state = EXECUTE) or (execute_engine.state = TRAP))) then -- sample IRQs in EXECUTE or TRAP state only to continue execution even if permanent IRQ
|
((execute_engine.state = EXECUTE) or (execute_engine.state = TRAP_ENTER))) then -- fire IRQs in EXECUTE or TRAP state only to continue execution even on permanent IRQ
|
trap_ctrl.cause <= trap_ctrl.cause_nxt; -- capture source ID for program (for mcause csr)
|
trap_ctrl.cause <= trap_ctrl.cause_nxt; -- capture source ID for program (for mcause csr)
|
trap_ctrl.exc_ack <= '1'; -- clear execption
|
trap_ctrl.exc_ack <= '1'; -- clear execption
|
trap_ctrl.irq_ack <= trap_ctrl.irq_ack_nxt; -- clear interrupt with interrupt ACK mask
|
trap_ctrl.irq_ack <= trap_ctrl.irq_ack_nxt; -- clear interrupt with interrupt ACK mask
|
trap_ctrl.env_start <= '1'; -- now execute engine can start trap handler
|
trap_ctrl.env_start <= '1'; -- now execute engine can start trap handler
|
end if;
|
end if;
|
Line 1799... |
Line 1807... |
trap_ctrl.irq_ack_nxt <= (others => '0');
|
trap_ctrl.irq_ack_nxt <= (others => '0');
|
end if;
|
end if;
|
end process trap_priority;
|
end process trap_priority;
|
|
|
|
|
-- Atomic Operation Controller ------------------------------------------------------------
|
-- Atomic Memory Access - Status Controller -----------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
atomics_controller: process(rstn_i, clk_i)
|
atomic_memacc_controller: process(rstn_i, clk_i)
|
begin
|
begin
|
if (rstn_i = '0') then
|
if (rstn_i = '0') then
|
atomic_ctrl.lock <= '0';
|
atomic_ctrl.lock <= '0';
|
atomic_ctrl.env_end_ff <= '0';
|
atomic_ctrl.env_end_ff <= '0';
|
elsif rising_edge(clk_i) then
|
elsif rising_edge(clk_i) then
|
Line 1821... |
Line 1829... |
else
|
else
|
atomic_ctrl.lock <= '0';
|
atomic_ctrl.lock <= '0';
|
atomic_ctrl.env_end_ff <= '0';
|
atomic_ctrl.env_end_ff <= '0';
|
end if;
|
end if;
|
end if;
|
end if;
|
end process atomics_controller;
|
end process atomic_memacc_controller;
|
|
|
|
|
-- ****************************************************************************************************************************
|
-- ****************************************************************************************************************************
|
-- Control and Status Registers (CSRs)
|
-- Control and Status Registers (CSRs)
|
-- ****************************************************************************************************************************
|
-- ****************************************************************************************************************************
|
Line 1868... |
Line 1876... |
csr.mie_mtie <= '0';
|
csr.mie_mtie <= '0';
|
csr.mie_firqe <= (others => '0');
|
csr.mie_firqe <= (others => '0');
|
csr.mtvec <= (others => '0');
|
csr.mtvec <= (others => '0');
|
csr.mscratch <= x"19880704"; -- :)
|
csr.mscratch <= x"19880704"; -- :)
|
csr.mepc <= (others => '0');
|
csr.mepc <= (others => '0');
|
-- mcause = TRAP_CODE_RESET (hardware reset, "non-maskable interrupt")
|
csr.mcause <= trap_reset_c; -- mcause = TRAP_CODE_RESET (hardware reset, "non-maskable interrupt")
|
csr.mcause <= (others => '0');
|
|
csr.mcause(csr.mcause'left) <= trap_reset_c(trap_reset_c'left);
|
|
csr.mcause(trap_reset_c'left-1 downto 0) <= trap_reset_c(trap_reset_c'left-1 downto 0);
|
|
--
|
--
|
csr.mtval <= (others => '0');
|
csr.mtval <= (others => '0');
|
csr.mip_clear <= (others => '0');
|
csr.mip_clear <= (others => '0');
|
--
|
--
|
csr.pmpcfg <= (others => (others => '0'));
|
csr.pmpcfg <= (others => (others => '0'));
|
Line 1889... |
Line 1894... |
csr.mcounteren_hpm <= (others => '0');
|
csr.mcounteren_hpm <= (others => '0');
|
--
|
--
|
csr.mcountinhibit_cy <= '0';
|
csr.mcountinhibit_cy <= '0';
|
csr.mcountinhibit_ir <= '0';
|
csr.mcountinhibit_ir <= '0';
|
csr.mcountinhibit_hpm <= (others => '0');
|
csr.mcountinhibit_hpm <= (others => '0');
|
|
|
elsif rising_edge(clk_i) then
|
elsif rising_edge(clk_i) then
|
-- write access? --
|
-- write access? --
|
csr.we <= csr.we_nxt;
|
csr.we <= csr.we_nxt;
|
if (CPU_EXTENSION_RISCV_Zicsr = true) then
|
if (CPU_EXTENSION_RISCV_Zicsr = true) then
|
|
|
Line 1927... |
Line 1933... |
csr.mtvec <= csr.wdata(data_width_c-1 downto 2) & "00"; -- mtvec.MODE=0
|
csr.mtvec <= csr.wdata(data_width_c-1 downto 2) & "00"; -- mtvec.MODE=0
|
when csr_mcounteren_c => -- R/W: machine counter enable register
|
when csr_mcounteren_c => -- R/W: machine counter enable register
|
csr.mcounteren_cy <= csr.wdata(0); -- enable user-level access to cycle[h]
|
csr.mcounteren_cy <= csr.wdata(0); -- enable user-level access to cycle[h]
|
csr.mcounteren_tm <= csr.wdata(1); -- enable user-level access to time[h]
|
csr.mcounteren_tm <= csr.wdata(1); -- enable user-level access to time[h]
|
csr.mcounteren_ir <= csr.wdata(2); -- enable user-level access to instret[h]
|
csr.mcounteren_ir <= csr.wdata(2); -- enable user-level access to instret[h]
|
csr.mcounteren_hpm <= csr.wdata(csr.mcounteren_hpm'left+3 downto 3); -- enable user-level access to mhpmcounterx[h]
|
csr.mcounteren_hpm <= csr.wdata(csr.mcounteren_hpm'left+3 downto 3); -- enable user-level access to hpmcounterx[h]
|
|
|
-- machine trap handling --
|
-- machine trap handling --
|
-- --------------------------------------------------------------------
|
-- --------------------------------------------------------------------
|
when csr_mscratch_c => -- R/W: mscratch - machine scratch register
|
when csr_mscratch_c => -- R/W: mscratch - machine scratch register
|
csr.mscratch <= csr.wdata;
|
csr.mscratch <= csr.wdata;
|
when csr_mepc_c => -- R/W: mepc - machine exception program counter
|
when csr_mepc_c => -- R/W: mepc - machine exception program counter
|
csr.mepc <= csr.wdata(data_width_c-1 downto 1) & '0';
|
csr.mepc <= csr.wdata(data_width_c-1 downto 1) & '0';
|
when csr_mcause_c => -- R/W: mcause - machine trap cause
|
when csr_mcause_c => -- R/W: mcause - machine trap cause
|
csr.mcause <= (others => '0');
|
|
csr.mcause(csr.mcause'left) <= csr.wdata(31); -- 1: interrupt, 0: exception
|
csr.mcause(csr.mcause'left) <= csr.wdata(31); -- 1: interrupt, 0: exception
|
csr.mcause(4 downto 0) <= csr.wdata(4 downto 0); -- identifier
|
csr.mcause(4 downto 0) <= csr.wdata(4 downto 0); -- identifier
|
when csr_mtval_c => -- R/W: mtval - machine bad address/instruction
|
when csr_mtval_c => -- R/W: mtval - machine bad address/instruction
|
csr.mtval <= csr.wdata;
|
csr.mtval <= csr.wdata;
|
when csr_mip_c => -- R/W: mip - machine interrupt pending
|
when csr_mip_c => -- R/W: mip - machine interrupt pending
|
Line 1953... |
Line 1958... |
|
|
-- physical memory protection: R/W: pmpcfg* - PMP configuration registers --
|
-- physical memory protection: R/W: pmpcfg* - PMP configuration registers --
|
-- --------------------------------------------------------------------
|
-- --------------------------------------------------------------------
|
when csr_pmpcfg0_c | csr_pmpcfg1_c | csr_pmpcfg2_c | csr_pmpcfg3_c | csr_pmpcfg4_c | csr_pmpcfg5_c | csr_pmpcfg6_c | csr_pmpcfg7_c |
|
when csr_pmpcfg0_c | csr_pmpcfg1_c | csr_pmpcfg2_c | csr_pmpcfg3_c | csr_pmpcfg4_c | csr_pmpcfg5_c | csr_pmpcfg6_c | csr_pmpcfg7_c |
|
csr_pmpcfg8_c | csr_pmpcfg9_c | csr_pmpcfg10_c | csr_pmpcfg11_c | csr_pmpcfg12_c | csr_pmpcfg13_c | csr_pmpcfg14_c | csr_pmpcfg15_c =>
|
csr_pmpcfg8_c | csr_pmpcfg9_c | csr_pmpcfg10_c | csr_pmpcfg11_c | csr_pmpcfg12_c | csr_pmpcfg13_c | csr_pmpcfg14_c | csr_pmpcfg15_c =>
|
|
if (PMP_NUM_REGIONS > 0) then
|
for i in 0 to PMP_NUM_REGIONS-1 loop
|
for i in 0 to PMP_NUM_REGIONS-1 loop
|
if (csr.addr(3 downto 0) = std_ulogic_vector(to_unsigned(i, 4))) then
|
if (csr.addr(3 downto 0) = std_ulogic_vector(to_unsigned(i, 4))) then
|
if (csr.pmpcfg(i)(7) = '0') then -- unlocked pmpcfg access
|
if (csr.pmpcfg(i)(7) = '0') then -- unlocked pmpcfg access
|
csr.pmpcfg(i)(0) <= csr.wdata((i mod 4)*8+0); -- R (rights.read)
|
csr.pmpcfg(i)(0) <= csr.wdata((i mod 4)*8+0); -- R (rights.read)
|
csr.pmpcfg(i)(1) <= csr.wdata((i mod 4)*8+1); -- W (rights.write)
|
csr.pmpcfg(i)(1) <= csr.wdata((i mod 4)*8+1); -- W (rights.write)
|
Line 1967... |
Line 1973... |
csr.pmpcfg(i)(6) <= '0'; -- reserved
|
csr.pmpcfg(i)(6) <= '0'; -- reserved
|
csr.pmpcfg(i)(7) <= csr.wdata((i mod 4)*8+7); -- L (locked / rights also enforced in m-mode)
|
csr.pmpcfg(i)(7) <= csr.wdata((i mod 4)*8+7); -- L (locked / rights also enforced in m-mode)
|
end if;
|
end if;
|
end if;
|
end if;
|
end loop; -- i (PMP regions)
|
end loop; -- i (PMP regions)
|
|
else
|
|
NULL;
|
|
end if;
|
|
|
-- physical memory protection: R/W: pmpaddr* - PMP address registers --
|
-- physical memory protection: R/W: pmpaddr* - PMP address registers --
|
-- --------------------------------------------------------------------
|
-- --------------------------------------------------------------------
|
when csr_pmpaddr0_c | csr_pmpaddr1_c | csr_pmpaddr2_c | csr_pmpaddr3_c | csr_pmpaddr4_c | csr_pmpaddr5_c | csr_pmpaddr6_c | csr_pmpaddr7_c |
|
when csr_pmpaddr0_c | csr_pmpaddr1_c | csr_pmpaddr2_c | csr_pmpaddr3_c | csr_pmpaddr4_c | csr_pmpaddr5_c | csr_pmpaddr6_c | csr_pmpaddr7_c |
|
csr_pmpaddr8_c | csr_pmpaddr9_c | csr_pmpaddr10_c | csr_pmpaddr11_c | csr_pmpaddr12_c | csr_pmpaddr13_c | csr_pmpaddr14_c | csr_pmpaddr15_c |
|
csr_pmpaddr8_c | csr_pmpaddr9_c | csr_pmpaddr10_c | csr_pmpaddr11_c | csr_pmpaddr12_c | csr_pmpaddr13_c | csr_pmpaddr14_c | csr_pmpaddr15_c |
|
Line 1978... |
Line 1987... |
csr_pmpaddr24_c | csr_pmpaddr25_c | csr_pmpaddr26_c | csr_pmpaddr27_c | csr_pmpaddr28_c | csr_pmpaddr29_c | csr_pmpaddr30_c | csr_pmpaddr31_c |
|
csr_pmpaddr24_c | csr_pmpaddr25_c | csr_pmpaddr26_c | csr_pmpaddr27_c | csr_pmpaddr28_c | csr_pmpaddr29_c | csr_pmpaddr30_c | csr_pmpaddr31_c |
|
csr_pmpaddr32_c | csr_pmpaddr33_c | csr_pmpaddr34_c | csr_pmpaddr35_c | csr_pmpaddr36_c | csr_pmpaddr37_c | csr_pmpaddr38_c | csr_pmpaddr39_c |
|
csr_pmpaddr32_c | csr_pmpaddr33_c | csr_pmpaddr34_c | csr_pmpaddr35_c | csr_pmpaddr36_c | csr_pmpaddr37_c | csr_pmpaddr38_c | csr_pmpaddr39_c |
|
csr_pmpaddr40_c | csr_pmpaddr41_c | csr_pmpaddr42_c | csr_pmpaddr43_c | csr_pmpaddr44_c | csr_pmpaddr45_c | csr_pmpaddr46_c | csr_pmpaddr47_c |
|
csr_pmpaddr40_c | csr_pmpaddr41_c | csr_pmpaddr42_c | csr_pmpaddr43_c | csr_pmpaddr44_c | csr_pmpaddr45_c | csr_pmpaddr46_c | csr_pmpaddr47_c |
|
csr_pmpaddr48_c | csr_pmpaddr49_c | csr_pmpaddr50_c | csr_pmpaddr51_c | csr_pmpaddr52_c | csr_pmpaddr53_c | csr_pmpaddr54_c | csr_pmpaddr55_c |
|
csr_pmpaddr48_c | csr_pmpaddr49_c | csr_pmpaddr50_c | csr_pmpaddr51_c | csr_pmpaddr52_c | csr_pmpaddr53_c | csr_pmpaddr54_c | csr_pmpaddr55_c |
|
csr_pmpaddr56_c | csr_pmpaddr57_c | csr_pmpaddr58_c | csr_pmpaddr59_c | csr_pmpaddr60_c | csr_pmpaddr61_c | csr_pmpaddr62_c | csr_pmpaddr63_c =>
|
csr_pmpaddr56_c | csr_pmpaddr57_c | csr_pmpaddr58_c | csr_pmpaddr59_c | csr_pmpaddr60_c | csr_pmpaddr61_c | csr_pmpaddr62_c | csr_pmpaddr63_c =>
|
|
if (PMP_NUM_REGIONS > 0) then
|
for i in 0 to PMP_NUM_REGIONS-1 loop
|
for i in 0 to PMP_NUM_REGIONS-1 loop
|
pmpaddr_v := std_ulogic_vector(unsigned(csr_pmpaddr0_c(6 downto 0)) + i); -- adapt to *non-aligned* base address (csr_pmpaddr0_c)
|
pmpaddr_v := std_ulogic_vector(unsigned(csr_pmpaddr0_c(6 downto 0)) + i); -- adapt to *non-aligned* base address (csr_pmpaddr0_c)
|
if (csr.addr(6 downto 0) = pmpaddr_v) and (csr.pmpcfg(i)(7) = '0') then -- unlocked pmpaddr access
|
if (csr.addr(6 downto 0) = pmpaddr_v) and (csr.pmpcfg(i)(7) = '0') then -- unlocked pmpaddr access
|
csr.pmpaddr(i) <= csr.wdata;
|
csr.pmpaddr(i) <= csr.wdata;
|
csr.pmpaddr(i)(index_size_f(PMP_MIN_GRANULARITY)-4 downto 0) <= (others => '1');
|
csr.pmpaddr(i)(index_size_f(PMP_MIN_GRANULARITY)-4 downto 0) <= (others => '1');
|
end if;
|
end if;
|
end loop; -- i (PMP regions)
|
end loop; -- i (PMP regions)
|
|
else
|
|
NULL;
|
|
end if;
|
|
|
-- machine counter setup --
|
-- machine counter setup --
|
-- --------------------------------------------------------------------
|
-- --------------------------------------------------------------------
|
when csr_mcountinhibit_c => -- R/W: mcountinhibit - machine counter-inhibit register
|
when csr_mcountinhibit_c => -- R/W: mcountinhibit - machine counter-inhibit register
|
csr.mcountinhibit_cy <= csr.wdata(0); -- enable auto-increment of [m]cycle[h] counter
|
csr.mcountinhibit_cy <= csr.wdata(0); -- enable auto-increment of [m]cycle[h] counter
|
Line 2000... |
Line 2013... |
when csr_mhpmevent3_c | csr_mhpmevent4_c | csr_mhpmevent5_c | csr_mhpmevent6_c | csr_mhpmevent7_c | csr_mhpmevent8_c |
|
when csr_mhpmevent3_c | csr_mhpmevent4_c | csr_mhpmevent5_c | csr_mhpmevent6_c | csr_mhpmevent7_c | csr_mhpmevent8_c |
|
csr_mhpmevent9_c | csr_mhpmevent10_c | csr_mhpmevent11_c | csr_mhpmevent12_c | csr_mhpmevent13_c | csr_mhpmevent14_c |
|
csr_mhpmevent9_c | csr_mhpmevent10_c | csr_mhpmevent11_c | csr_mhpmevent12_c | csr_mhpmevent13_c | csr_mhpmevent14_c |
|
csr_mhpmevent15_c | csr_mhpmevent16_c | csr_mhpmevent17_c | csr_mhpmevent18_c | csr_mhpmevent19_c | csr_mhpmevent20_c |
|
csr_mhpmevent15_c | csr_mhpmevent16_c | csr_mhpmevent17_c | csr_mhpmevent18_c | csr_mhpmevent19_c | csr_mhpmevent20_c |
|
csr_mhpmevent21_c | csr_mhpmevent22_c | csr_mhpmevent23_c | csr_mhpmevent24_c | csr_mhpmevent25_c | csr_mhpmevent26_c |
|
csr_mhpmevent21_c | csr_mhpmevent22_c | csr_mhpmevent23_c | csr_mhpmevent24_c | csr_mhpmevent25_c | csr_mhpmevent26_c |
|
csr_mhpmevent27_c | csr_mhpmevent28_c | csr_mhpmevent29_c | csr_mhpmevent30_c | csr_mhpmevent31_c => -- R/W: mhpmevent* - machine performance-monitoring event selector
|
csr_mhpmevent27_c | csr_mhpmevent28_c | csr_mhpmevent29_c | csr_mhpmevent30_c | csr_mhpmevent31_c => -- R/W: mhpmevent* - machine performance-monitoring event selector
|
|
if (HPM_NUM_CNTS > 0) then
|
for i in 0 to HPM_NUM_CNTS-1 loop
|
for i in 0 to HPM_NUM_CNTS-1 loop
|
if (csr.addr(4 downto 0) = std_ulogic_vector(to_unsigned(i+3, 5))) then
|
if (csr.addr(4 downto 0) = std_ulogic_vector(to_unsigned(i+3, 5))) then
|
csr.mhpmevent(i) <= csr.wdata(csr.mhpmevent(i)'left downto 0);
|
csr.mhpmevent(i) <= csr.wdata(csr.mhpmevent(i)'left downto 0);
|
csr.mhpmevent(i)(1) <= '0'; -- would be used for "TIME"
|
csr.mhpmevent(i)(1) <= '0'; -- would be used for "TIME"
|
end if;
|
end if;
|
end loop; -- i (CSRs)
|
end loop; -- i (CSRs)
|
|
else
|
|
NULL;
|
|
end if;
|
|
|
-- undefined --
|
-- undefined --
|
-- --------------------------------------------------------------------
|
-- --------------------------------------------------------------------
|
when others =>
|
when others =>
|
NULL;
|
NULL;
|
Line 2023... |
Line 2040... |
|
|
-- mcause, mepc, mtval: machine trap cause, PC and value register --
|
-- mcause, mepc, mtval: machine trap cause, PC and value register --
|
-- --------------------------------------------------------------------
|
-- --------------------------------------------------------------------
|
if (trap_ctrl.env_start_ack = '1') then -- trap handler starting?
|
if (trap_ctrl.env_start_ack = '1') then -- trap handler starting?
|
-- trap cause ID code --
|
-- trap cause ID code --
|
csr.mcause <= (others => '0');
|
|
csr.mcause(csr.mcause'left) <= trap_ctrl.cause(trap_ctrl.cause'left); -- 1: interrupt, 0: exception
|
csr.mcause(csr.mcause'left) <= trap_ctrl.cause(trap_ctrl.cause'left); -- 1: interrupt, 0: exception
|
csr.mcause(4 downto 0) <= trap_ctrl.cause(4 downto 0); -- identifier
|
csr.mcause(4 downto 0) <= trap_ctrl.cause(4 downto 0); -- identifier
|
-- trap PC --
|
-- trap PC --
|
if (trap_ctrl.cause(trap_ctrl.cause'left) = '1') then -- for INTERRUPTS
|
if (trap_ctrl.cause(trap_ctrl.cause'left) = '1') then -- for INTERRUPTS
|
csr.mepc <= execute_engine.pc(data_width_c-1 downto 1) & '0'; -- this is the CURRENT pc = interrupted instruction
|
csr.mepc <= execute_engine.pc(data_width_c-1 downto 1) & '0'; -- this is the CURRENT pc = interrupted instruction
|
Line 2272... |
Line 2288... |
when csr_mscratch_c => -- R/W: mscratch - machine scratch register
|
when csr_mscratch_c => -- R/W: mscratch - machine scratch register
|
csr.rdata <= csr.mscratch;
|
csr.rdata <= csr.mscratch;
|
when csr_mepc_c => -- R/W: mepc - machine exception program counter
|
when csr_mepc_c => -- R/W: mepc - machine exception program counter
|
csr.rdata <= csr.mepc(data_width_c-1 downto 1) & '0';
|
csr.rdata <= csr.mepc(data_width_c-1 downto 1) & '0';
|
when csr_mcause_c => -- R/W: mcause - machine trap cause
|
when csr_mcause_c => -- R/W: mcause - machine trap cause
|
csr.rdata <= csr.mcause;
|
csr.rdata(31) <= csr.mcause(csr.mcause'left);
|
|
csr.rdata(csr.mcause'left-1 downto 0) <= csr.mcause(csr.mcause'left-1 downto 0);
|
when csr_mtval_c => -- R/W: mtval - machine bad address or instruction
|
when csr_mtval_c => -- R/W: mtval - machine bad address or instruction
|
csr.rdata <= csr.mtval;
|
csr.rdata <= csr.mtval;
|
when csr_mip_c => -- R/W: mip - machine interrupt pending
|
when csr_mip_c => -- R/W: mip - machine interrupt pending
|
csr.rdata(03) <= csr.mip_status(interrupt_msw_irq_c);
|
csr.rdata(03) <= csr.mip_status(interrupt_msw_irq_c);
|
csr.rdata(07) <= csr.mip_status(interrupt_mtime_irq_c);
|
csr.rdata(07) <= csr.mip_status(interrupt_mtime_irq_c);
|
Line 2488... |
Line 2505... |
when csr_marchid_c => -- R/-: marchid - arch ID
|
when csr_marchid_c => -- R/-: marchid - arch ID
|
csr.rdata(4 downto 0) <= "10011"; -- official RISC-V open-source arch ID
|
csr.rdata(4 downto 0) <= "10011"; -- official RISC-V open-source arch ID
|
when csr_mimpid_c => -- R/-: mimpid - implementation ID
|
when csr_mimpid_c => -- R/-: mimpid - implementation ID
|
csr.rdata <= hw_version_c; -- NEORV32 hardware version
|
csr.rdata <= hw_version_c; -- NEORV32 hardware version
|
when csr_mhartid_c => -- R/-: mhartid - hardware thread ID
|
when csr_mhartid_c => -- R/-: mhartid - hardware thread ID
|
csr.rdata <= HW_THREAD_ID;
|
csr.rdata <= std_ulogic_vector(to_unsigned(HW_THREAD_ID, 32));
|
|
|
-- custom machine read-only CSRs --
|
-- custom machine read-only CSRs --
|
when csr_mzext_c => -- R/-: mzext - available RISC-V Z* extensions
|
when csr_mzext_c => -- R/-: mzext - available RISC-V Z* extensions
|
csr.rdata(0) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zicsr); -- Zicsr
|
csr.rdata(0) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zicsr); -- Zicsr
|
csr.rdata(1) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zifencei); -- Zifencei
|
csr.rdata(1) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zifencei); -- Zifencei
|