OpenCores
URL https://opencores.org/ocsvn/neorv32/neorv32/trunk

Subversion Repositories neorv32

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /neorv32/trunk/rtl/core
    from Rev 28 to Rev 29
    Reverse comparison

Rev 28 → Rev 29

/neorv32_application_image.vhd
88,7 → 88,7
00000077 => x"00112623",
00000078 => x"00812423",
00000079 => x"514000ef",
00000080 => x"7f8000ef",
00000080 => x"7b8000ef",
00000081 => x"02050c63",
00000082 => x"3a4000ef",
00000083 => x"00001537",
95,12 → 95,12
00000084 => x"a4c50513",
00000085 => x"598000ef",
00000086 => x"00000513",
00000087 => x"7ec000ef",
00000087 => x"7ac000ef",
00000088 => x"00000413",
00000089 => x"0ff47513",
00000090 => x"7e0000ef",
00000090 => x"7a0000ef",
00000091 => x"0c800513",
00000092 => x"788000ef",
00000092 => x"7a0000ef",
00000093 => x"00140413",
00000094 => x"fedff06f",
00000095 => x"00001537",
582,28 → 582,28
00000571 => x"00140993",
00000572 => x"000c0513",
00000573 => x"f99ff06f",
00000574 => x"00050593",
00000575 => x"fe002503",
00000576 => x"ff010113",
00000577 => x"00112623",
00000578 => x"00f55513",
00000579 => x"044000ef",
00000580 => x"00051863",
00000581 => x"00c12083",
00000582 => x"01010113",
00000583 => x"00008067",
00000584 => x"00000013",
00000585 => x"00000013",
00000586 => x"00000013",
00000587 => x"00000013",
00000588 => x"fff50513",
00000589 => x"fddff06f",
00000590 => x"fe802503",
00000591 => x"01055513",
00000592 => x"00157513",
00000593 => x"00008067",
00000594 => x"f8a02223",
00000595 => x"00008067",
00000574 => x"fe802503",
00000575 => x"01055513",
00000576 => x"00157513",
00000577 => x"00008067",
00000578 => x"f8a02223",
00000579 => x"00008067",
00000580 => x"00050593",
00000581 => x"fe002503",
00000582 => x"ff010113",
00000583 => x"00112623",
00000584 => x"00f55513",
00000585 => x"02c000ef",
00000586 => x"00051863",
00000587 => x"00c12083",
00000588 => x"01010113",
00000589 => x"00008067",
00000590 => x"00000013",
00000591 => x"00000013",
00000592 => x"00000013",
00000593 => x"00000013",
00000594 => x"fff50513",
00000595 => x"fddff06f",
00000596 => x"00050613",
00000597 => x"00000513",
00000598 => x"0015f693",
/neorv32_cpu.vhd
10,7 → 10,7
-- # * neorv32_cpu_decompressor.vhd : Compressed instructions decoder #
-- # * neorv32_cpu_regfile.vhd : Data register file #
-- # #
-- # Check the processor's documentary for more information: docs/NEORV32.pdf #
-- # Check out the processor's data sheet for more information: docs/NEORV32.pdf #
-- # ********************************************************************************************* #
-- # BSD 3-Clause License #
-- # #
117,7 → 117,6
signal instr : std_ulogic_vector(data_width_c-1 downto 0); -- new instruction
signal rs1, rs2 : std_ulogic_vector(data_width_c-1 downto 0); -- source registers
signal alu_res : std_ulogic_vector(data_width_c-1 downto 0); -- alu result
signal alu_add : std_ulogic_vector(data_width_c-1 downto 0); -- alu adder result
signal rdata : std_ulogic_vector(data_width_c-1 downto 0); -- memory read data
signal alu_wait : std_ulogic; -- alu is busy due to iterative unit
signal bus_i_wait : std_ulogic; -- wait for current bus instruction fetch
193,7 → 192,6
-- data input --
instr_i => instr, -- instruction
cmp_i => alu_cmp, -- comparator status
alu_add_i => alu_add, -- ALU.add result
alu_res_i => alu_res, -- ALU processing result
-- data output --
imm_o => imm, -- immediate
263,7 → 261,6
imm_i => imm, -- immediate
-- data output --
cmp_o => alu_cmp, -- comparator status
add_o => alu_add, -- OPA + OPB
res_o => alu_res, -- ALU result
-- co-processor interface --
cp0_start_o => cp0_start, -- trigger co-processor 0
337,7 → 334,7
ma_instr_o => ma_instr, -- misaligned instruction address
be_instr_o => be_instr, -- bus error on instruction access
-- cpu data access interface --
addr_i => alu_add, -- ALU.add result -> access address
addr_i => alu_res, -- ALU result -> access address
wdata_i => rs2, -- write data
rdata_o => rdata, -- read data
mar_o => mar, -- current memory address register
/neorv32_cpu_alu.vhd
58,7 → 58,6
imm_i : in std_ulogic_vector(data_width_c-1 downto 0); -- immediate
-- data output --
cmp_o : out std_ulogic_vector(1 downto 0); -- comparator status
add_o : out std_ulogic_vector(data_width_c-1 downto 0); -- OPA + OPB
res_o : out std_ulogic_vector(data_width_c-1 downto 0); -- ALU result
-- co-processor interface --
cp0_start_o : out std_ulogic; -- trigger co-processor 0
75,19 → 74,16
architecture neorv32_cpu_cpu_rtl of neorv32_cpu_alu is
 
-- operands --
signal opa, opb, opc : std_ulogic_vector(data_width_c-1 downto 0);
signal opa, opb : std_ulogic_vector(data_width_c-1 downto 0);
 
-- results --
signal add_res : std_ulogic_vector(data_width_c-1 downto 0);
signal alu_res : std_ulogic_vector(data_width_c-1 downto 0);
signal cp_res : std_ulogic_vector(data_width_c-1 downto 0);
signal addsub_res : std_ulogic_vector(data_width_c-1 downto 0);
signal cp_res : std_ulogic_vector(data_width_c-1 downto 0);
 
-- comparator --
signal cmp_opx : std_ulogic_vector(data_width_c downto 0);
signal cmp_opy : std_ulogic_vector(data_width_c downto 0);
signal cmp_sub : std_ulogic_vector(data_width_c downto 0);
signal sub_res : std_ulogic_vector(data_width_c-1 downto 0);
signal cmp_equal : std_ulogic;
signal cmp_less : std_ulogic;
 
-- shifter --
104,6 → 100,7
 
-- co-processor arbiter and interface --
type cp_ctrl_t is record
cmd : std_ulogic;
cmd_ff : std_ulogic;
busy : std_ulogic;
start : std_ulogic;
115,34 → 112,52
 
-- Operand Mux ----------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
opa <= rs1_i when (ctrl_i(ctrl_alu_opa_mux_c) = '0') else pc2_i; -- operand a (first ALU input operand)
opb <= rs2_i when (ctrl_i(ctrl_alu_opb_mux_c) = '0') else imm_i; -- operand b (second ALU input operand)
opc <= rs2_i when (ctrl_i(ctrl_alu_opc_mux_c) = '0') else imm_i; -- operand c (third ALU input operand for comparison and SUB)
opa <= pc2_i when (ctrl_i(ctrl_alu_opa_mux_c) = '1') else rs1_i; -- operand a (first ALU input operand)
opb <= imm_i when (ctrl_i(ctrl_alu_opb_mux_c) = '1') else rs2_i; -- operand b (second ALU input operand)
 
 
-- Comparator Unit ------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
-- less than (x < y) --
cmp_opx <= (rs1_i(rs1_i'left) and (not ctrl_i(ctrl_alu_unsigned_c))) & rs1_i;
cmp_opy <= (opc(opc'left) and (not ctrl_i(ctrl_alu_unsigned_c))) & opc;
cmp_sub <= std_ulogic_vector(signed(cmp_opx) - signed(cmp_opy));
cmp_less <= cmp_sub(cmp_sub'left); -- carry (borrow) indicates a "less"
sub_res <= cmp_sub(data_width_c-1 downto 0); -- use the less-comparator also for SUB operations
cmp_opy <= (rs2_i(rs2_i'left) and (not ctrl_i(ctrl_alu_unsigned_c))) & rs2_i;
cmp_sub <= std_ulogic_vector(signed(cmp_opx) - signed(cmp_opy)); -- less than (x < y)
 
-- equal (for branch check only) --
cmp_equal <= '1' when (rs1_i = rs2_i) else '0';
cmp_o(alu_cmp_equal_c) <= '1' when (rs1_i = rs2_i) else '0';
cmp_o(alu_cmp_less_c) <= cmp_sub(cmp_sub'left); -- less = carry (borrow)
 
-- output for branch condition evaluation --
cmp_o(alu_cmp_equal_c) <= cmp_equal;
cmp_o(alu_cmp_less_c) <= cmp_less;
 
 
-- Binary Adder ---------------------------------------------------------------------------
-- Binary Adder/Subtractor ----------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
add_res <= std_ulogic_vector(unsigned(opa) + unsigned(opb));
add_o <= add_res; -- direct output (for PC modification)
binary_arithmetic_core: process(ctrl_i, opa, opb)
variable cin_v : std_ulogic_vector(0 downto 0);
variable op_a_v : std_ulogic_vector(data_width_c downto 0);
variable op_b_v : std_ulogic_vector(data_width_c downto 0);
variable op_y_v : std_ulogic_vector(data_width_c downto 0);
variable res_v : std_ulogic_vector(data_width_c downto 0);
begin
-- operand sign-extension --
op_a_v := (opa(opa'left) and (not ctrl_i(ctrl_alu_unsigned_c))) & opa;
op_b_v := (opb(opb'left) and (not ctrl_i(ctrl_alu_unsigned_c))) & opb;
 
-- add/sub(slt) select --
if (ctrl_i(ctrl_alu_addsub_c) = '1') then -- subtraction
op_y_v := not op_b_v;
cin_v(0) := '1';
else-- addition
op_y_v := op_b_v;
cin_v(0) := '0';
end if;
 
-- adder core --
res_v := std_ulogic_vector(unsigned(op_a_v) + unsigned(op_y_v) + unsigned(cin_v(0 downto 0)));
 
-- output --
cmp_less <= res_v(32);
addsub_res <= res_v(31 downto 0);
addsub_res <= res_v(31 downto 0);
end process binary_arithmetic_core;
 
 
-- Iterative Shifter Unit -----------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
shifter_unit: process(rstn_i, clk_i)
182,7 → 197,7
end process shifter_unit;
 
-- is shift operation? --
shifter.cmd <= '1' when (ctrl_i(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) = alu_cmd_shift_c) and (ctrl_i(ctrl_cp_use_c) = '0') else '0';
shifter.cmd <= '1' when (ctrl_i(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) = alu_cmd_shift_c) else '0';
shifter.start <= '1' when (shifter.cmd = '1') and (shifter.cmd_ff = '0') else '0';
 
-- shift operation running? --
199,7 → 214,7
cp_ctrl.busy <= '0';
elsif rising_edge(clk_i) then
if (CPU_EXTENSION_RISCV_M = true) then
cp_ctrl.cmd_ff <= ctrl_i(ctrl_cp_use_c);
cp_ctrl.cmd_ff <= cp_ctrl.cmd;
if (cp_ctrl.start = '1') then
cp_ctrl.busy <= '1';
elsif ((cp0_valid_i or cp1_valid_i) = '1') then -- cp computation done?
213,7 → 228,8
end process cp_arbiter;
 
-- is co-processor operation? --
cp_ctrl.start <= '1' when (ctrl_i(ctrl_cp_use_c) = '1') and (cp_ctrl.cmd_ff = '0') else '0';
cp_ctrl.cmd <= '1' when (ctrl_i(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) = alu_cmd_cp_c) else '0';
cp_ctrl.start <= '1' when (cp_ctrl.cmd = '1') and (cp_ctrl.cmd_ff = '0') else '0';
cp0_start_o <= '1' when (cp_ctrl.start = '1') and (ctrl_i(ctrl_cp_id_msb_c downto ctrl_cp_id_lsb_c) = cp_sel_muldiv_c) else '0'; -- MULDIV CP
cp1_start_o <= '0'; -- not yet implemented
 
221,31 → 237,30
cp_ctrl.halt <= cp_ctrl.busy or cp_ctrl.start;
 
-- co-processor result --
cp_res <= cp0_data_i or cp1_data_i; -- only the selected cp may output data != 0
cp_res <= cp0_data_i or cp1_data_i; -- only the **actaully selected** co-processor should output data != 0
 
 
-- ALU Function Select --------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
alu_function_mux: process(ctrl_i, opa, opb, add_res, sub_res, cmp_less, shifter.sreg)
alu_function_mux: process(ctrl_i, opa, opb, addsub_res, cp_res, cmp_less, shifter.sreg)
begin
case ctrl_i(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) is
when alu_cmd_xor_c => alu_res <= opa xor opb;
when alu_cmd_or_c => alu_res <= opa or opb;
when alu_cmd_and_c => alu_res <= opa and opb;
when alu_cmd_movb_c => alu_res <= opb;
when alu_cmd_sub_c => alu_res <= sub_res;
when alu_cmd_add_c => alu_res <= add_res;
when alu_cmd_shift_c => alu_res <= shifter.sreg;
when alu_cmd_slt_c => alu_res <= (others => '0'); alu_res(0) <= cmp_less;
when others => alu_res <= (others => '0'); -- undefined
when alu_cmd_xor_c => res_o <= opa xor opb;
when alu_cmd_or_c => res_o <= opa or opb;
when alu_cmd_and_c => res_o <= opa and opb;
when alu_cmd_movb_c => res_o <= opb;
when alu_cmd_addsub_c => res_o <= addsub_res;
when alu_cmd_cp_c => res_o <= cp_res;
when alu_cmd_shift_c => res_o <= shifter.sreg;
when alu_cmd_slt_c => res_o <= (others => '0'); res_o(0) <= cmp_less;
when others => res_o <= opb; -- undefined
end case;
end process alu_function_mux;
 
 
-- ALU Result -----------------------------------------------------------------------------
-- ALU Busy -------------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
wait_o <= shifter.halt or cp_ctrl.halt; -- wait until iterative units have completed
res_o <= cp_res when (ctrl_i(ctrl_cp_use_c) = '1') else alu_res; -- FIXME?
 
 
end neorv32_cpu_cpu_rtl;
/neorv32_cpu_bus.vhd
460,7 → 460,7
pmp_check_permission: process(pmp, pmp_ctrl_i, priv_mode_i)
begin
for r in 0 to PMP_NUM_REGIONS-1 loop -- iterate over all regions
if ((priv_mode_i = u_priv_mode_c) or (pmp_ctrl_i(r)(pmp_cfg_l_c) = '1')) and -- user privilege level or locked pmp entry -> enforce permissions also for machine mode
if ((priv_mode_i = priv_mode_u_c) or (pmp_ctrl_i(r)(pmp_cfg_l_c) = '1')) and -- user privilege level or locked pmp entry -> enforce permissions also for machine mode
(pmp_ctrl_i(r)(pmp_cfg_ah_c downto pmp_cfg_al_c) /= pmp_off_mode_c) then -- active entry
pmp.if_fault(r) <= pmp.i_match(r) and (not pmp_ctrl_i(r)(pmp_cfg_x_c)); -- fetch access match no execute permission
pmp.ld_fault(r) <= pmp.d_match(r) and (not pmp_ctrl_i(r)(pmp_cfg_r_c)); -- load access match no read permission
/neorv32_cpu_control.vhd
72,7 → 72,6
-- data input --
instr_i : in std_ulogic_vector(data_width_c-1 downto 0); -- instruction
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.add result
alu_res_i : in std_ulogic_vector(data_width_c-1 downto 0); -- ALU processing result
-- data output --
imm_o : out std_ulogic_vector(data_width_c-1 downto 0); -- immediate
161,6 → 160,8
is_ci_nxt : std_ulogic;
is_jump : std_ulogic; -- current instruction is jump instruction
is_jump_nxt : std_ulogic;
is_cp_op : std_ulogic; -- current instruction is a co-processor operation
is_cp_op_nxt : std_ulogic;
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_nxt : std_ulogic_vector(data_width_c-1 downto 0);
210,20 → 211,24
type pmp_ctrl_t is array (0 to PMP_NUM_REGIONS-1) of std_ulogic_vector(7 downto 0);
type pmp_addr_t is array (0 to PMP_NUM_REGIONS-1) of std_ulogic_vector(data_width_c-1 downto 0);
type csr_t is record
we : std_ulogic; -- write enable
we : std_ulogic; -- csr write enable
we_nxt : std_ulogic;
re : std_ulogic; -- read enable
re : std_ulogic; -- csr read enable
re_nxt : std_ulogic;
wdata : std_ulogic_vector(data_width_c-1 downto 0); -- write data
rdata : std_ulogic_vector(data_width_c-1 downto 0); -- read data
wdata : std_ulogic_vector(data_width_c-1 downto 0); -- csr write data
rdata : std_ulogic_vector(data_width_c-1 downto 0); -- csr read data
--
mstatus_mie : std_ulogic; -- mstatus.MIE: global IRQ enable (R/W)
mstatus_mpie : std_ulogic; -- mstatus.MPIE: previous global IRQ enable (R/-)
mstatus_mpp : std_ulogic_vector(1 downto 0); -- mstatus.MPP: machine previous privilege mode
--
mie_msie : std_ulogic; -- mie.MSIE: machine software interrupt enable (R/W)
mie_meie : std_ulogic; -- mie.MEIE: machine external interrupt enable (R/W)
mie_mtie : std_ulogic; -- mie.MEIE: machine timer interrupt enable (R/W
mie_firqe : std_ulogic_vector(3 downto 0); -- mie.firq*e: fast interrupt enabled (R/W)
mpp : std_ulogic_vector(1 downto 0); -- machine previous privilege mode
--
privilege : std_ulogic_vector(1 downto 0); -- hart's current previous privilege mode
--
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/-)
mtvec : std_ulogic_vector(data_width_c-1 downto 0); -- mtvec: machine trap-handler base address (R/W), bit 1:0 == 00
547,6 → 552,7
execute_engine.i_reg <= execute_engine.i_reg_nxt;
execute_engine.is_ci <= execute_engine.is_ci_nxt;
execute_engine.is_jump <= execute_engine.is_jump_nxt;
execute_engine.is_cp_op <= execute_engine.is_cp_op_nxt;
--
ctrl <= ctrl_nxt;
end if;
563,7 → 569,7
 
-- CPU Control Bus Output -----------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
ctrl_output: process(ctrl, fetch_engine, trap_ctrl, csr, bus_fast_ir)
ctrl_output: process(ctrl, fetch_engine, trap_ctrl, bus_fast_ir, execute_engine)
begin
ctrl_o <= ctrl;
-- fast bus access requests --
571,6 → 577,8
-- bus error control --
ctrl_o(ctrl_bus_ierr_ack_c) <= fetch_engine.bus_err_ack;
ctrl_o(ctrl_bus_derr_ack_c) <= trap_ctrl.env_start_ack;
-- co-processor operation --
ctrl_o(ctrl_cp_cmd2_c downto ctrl_cp_cmd0_c) <= execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c);
end process ctrl_output;
 
 
577,19 → 585,20
-- Execute Engine FSM Comb ----------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
execute_engine_fsm_comb: process(execute_engine, fetch_engine, ipb, trap_ctrl, csr, ctrl, csr_acc_valid,
alu_add_i, alu_wait_i, bus_d_wait_i, ma_load_i, be_load_i, ma_store_i, be_store_i)
alu_res_i, alu_wait_i, bus_d_wait_i, ma_load_i, be_load_i, ma_store_i, be_store_i)
variable alu_immediate_v : std_ulogic;
variable rs1_is_r0_v : std_ulogic;
begin
-- arbiter defaults --
execute_engine.state_nxt <= execute_engine.state;
execute_engine.i_reg_nxt <= execute_engine.i_reg;
execute_engine.is_jump_nxt <= '0';
execute_engine.is_ci_nxt <= execute_engine.is_ci;
execute_engine.pc_nxt <= execute_engine.pc;
execute_engine.last_pc_nxt <= execute_engine.last_pc;
execute_engine.sleep_nxt <= execute_engine.sleep;
execute_engine.if_rst_nxt <= execute_engine.if_rst;
execute_engine.state_nxt <= execute_engine.state;
execute_engine.i_reg_nxt <= execute_engine.i_reg;
execute_engine.is_jump_nxt <= '0';
execute_engine.is_cp_op_nxt <= execute_engine.is_cp_op;
execute_engine.is_ci_nxt <= execute_engine.is_ci;
execute_engine.pc_nxt <= execute_engine.pc;
execute_engine.last_pc_nxt <= execute_engine.last_pc;
execute_engine.sleep_nxt <= execute_engine.sleep;
execute_engine.if_rst_nxt <= execute_engine.if_rst;
 
-- instruction dispatch --
fetch_engine.reset <= '0';
620,8 → 629,7
ctrl_nxt(ctrl_bus_unsigned_c) <= execute_engine.i_reg(instr_funct3_msb_c); -- unsigned LOAD (LBU, LHU)
ctrl_nxt(ctrl_alu_shift_dir_c) <= execute_engine.i_reg(instr_funct3_msb_c); -- shift direction (left/right)
ctrl_nxt(ctrl_alu_shift_ar_c) <= execute_engine.i_reg(30); -- is arithmetic shift
ctrl_nxt(ctrl_cp_cmd2_c downto ctrl_cp_cmd0_c) <= execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c); -- CP operation
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_add_c; -- default ALU operation: ADD(I)
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_addsub_c; -- default ALU operation: ADD(I)
ctrl_nxt(ctrl_cp_id_msb_c downto ctrl_cp_id_lsb_c) <= cp_sel_muldiv_c; -- only CP0 (=MULDIV) implemented yet
ctrl_nxt(ctrl_rf_rd_adr4_c downto ctrl_rf_rd_adr0_c) <= ctrl(ctrl_rf_rd_adr4_c downto ctrl_rf_rd_adr0_c); -- keep rd addr
ctrl_nxt(ctrl_rf_rs1_adr4_c downto ctrl_rf_rs1_adr0_c) <= ctrl(ctrl_rf_rs1_adr4_c downto ctrl_rf_rs1_adr0_c); -- keep rs1 addr
699,32 → 707,37
-- ------------------------------------------------------------
ctrl_nxt(ctrl_alu_opa_mux_c) <= '0'; -- use RS1 as ALU.OPA
ctrl_nxt(ctrl_alu_opb_mux_c) <= alu_immediate_v; -- use IMM as ALU.OPB for immediate operations
ctrl_nxt(ctrl_alu_opc_mux_c) <= alu_immediate_v; -- use IMM as ALU.OPC for immediate operations (SLT(I)(U))
ctrl_nxt(ctrl_rf_in_mux_msb_c downto ctrl_rf_in_mux_lsb_c) <= "00"; -- RF input = ALU result
 
-- actual ALU operation (re-coding) --
case execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) is
when funct3_sll_c => ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_shift_c; -- SLL(I)
when funct3_slt_c => ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_slt_c; -- SLT(I)
when funct3_sltu_c => ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_slt_c; -- SLTU(I)
when funct3_xor_c => ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_xor_c; -- XOR(I)
when funct3_sr_c => ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_shift_c; -- SRL(I) / SRA(I)
when funct3_or_c => ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_or_c; -- OR(I)
when funct3_and_c => ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_and_c; -- AND(I)
when others => -- ADD(I) / SUB
if (alu_immediate_v = '0') and (execute_engine.i_reg(instr_funct7_msb_c-1) = '1') then -- not an immediate op and funct7.6 set => SUB
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_sub_c; -- SUB
else
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_add_c; -- ADD(I)
end if;
end case;
 
-- cp access? --
if (CPU_EXTENSION_RISCV_M = true) and (execute_engine.i_reg(instr_opcode_lsb_c+5) = opcode_alu_c(5)) and
(execute_engine.i_reg(instr_funct7_lsb_c) = '1') then -- MULDIV?
ctrl_nxt(ctrl_cp_use_c) <= '1'; -- use CP
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_cp_c;
execute_engine.is_cp_op_nxt <= '1'; -- use CP
-- ALU operation --
else
case execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) is -- actual ALU operation (re-coding)
when funct3_sll_c => ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_shift_c; -- SLL(I)
when funct3_slt_c => ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_slt_c; -- SLT(I)
when funct3_sltu_c => ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_slt_c; -- SLTU(I)
when funct3_xor_c => ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_xor_c; -- XOR(I)
when funct3_sr_c => ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_shift_c; -- SRL(I) / SRA(I)
when funct3_or_c => ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_or_c; -- OR(I)
when funct3_and_c => ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_and_c; -- AND(I)
when others => ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_addsub_c; -- ADD(I) / SUB
end case;
execute_engine.is_cp_op_nxt <= '0'; -- no CP operation
end if;
 
-- ADD/SUB --
if ((alu_immediate_v = '0') and (execute_engine.i_reg(instr_funct7_msb_c-1) = '1')) or -- not an immediate op and funct7.6 set => SUB
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_slt_c) or -- SLT operation
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_sltu_c) then -- SLTU operation
ctrl_nxt(ctrl_alu_addsub_c) <= '1'; -- SUB/SLT
else
ctrl_nxt(ctrl_alu_addsub_c) <= '0'; -- ADD(I)
end if;
 
-- multi cycle alu operation? --
if (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_sll_c) or -- SLL shift operation?
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_sr_c) or -- SR shift operation?
742,7 → 755,7
if (execute_engine.i_reg(instr_opcode_lsb_c+5) = opcode_lui_c(5)) then -- LUI
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_movb_c; -- actual ALU operation = MOVB
else -- AUIPC
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_add_c; -- actual ALU operation = ADD
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_addsub_c; -- actual ALU operation = ADD
end if;
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
752,31 → 765,25
-- ------------------------------------------------------------
ctrl_nxt(ctrl_alu_opa_mux_c) <= '0'; -- use RS1 as ALU.OPA
ctrl_nxt(ctrl_alu_opb_mux_c) <= '1'; -- use IMM as ALU.OPB
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_add_c; -- actual ALU operation = ADD
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_addsub_c; -- actual ALU operation = ADD
ctrl_nxt(ctrl_bus_mar_we_c) <= '1'; -- write to MAR
ctrl_nxt(ctrl_bus_mdo_we_c) <= '1'; -- write to MDO (only relevant for stores)
execute_engine.state_nxt <= LOADSTORE_0;
 
when opcode_branch_c => -- branch instruction
when opcode_branch_c | opcode_jal_c | opcode_jalr_c => -- branch / jump and link (with register)
-- ------------------------------------------------------------
ctrl_nxt(ctrl_alu_opa_mux_c) <= '1'; -- use PC as ALU.OPA (branch target address base)
ctrl_nxt(ctrl_alu_opb_mux_c) <= '1'; -- use IMM as ALU.OPB (branch target address offset)
ctrl_nxt(ctrl_alu_opc_mux_c) <= '0'; -- use RS2 as ALU.OPC (for branch condition check)
execute_engine.state_nxt <= BRANCH;
 
when opcode_jal_c | opcode_jalr_c => -- jump and link (with register)
-- ------------------------------------------------------------
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_addsub_c; -- actual ALU operation = ADD
-- compute target address --
if (execute_engine.i_reg(instr_opcode_lsb_c+3) = opcode_jal_c(3)) then -- JAL
ctrl_nxt(ctrl_alu_opa_mux_c) <= '1'; -- use PC as ALU.OPA
else -- JALR
ctrl_nxt(ctrl_alu_opa_mux_c) <= '0'; -- use RS1 as ALU.OPA
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)
else -- JAL / branch
ctrl_nxt(ctrl_alu_opa_mux_c) <= '1'; -- use PC as ALU.OPA (branch target address base)
end if;
ctrl_nxt(ctrl_alu_opb_mux_c) <= '1'; -- use IMM as ALU.OPB
ctrl_nxt(ctrl_alu_opb_mux_c) <= '1'; -- use IMM as ALU.OPB (branch target address offset)
-- save return address --
ctrl_nxt(ctrl_rf_in_mux_msb_c downto ctrl_rf_in_mux_lsb_c) <= "10"; -- RF input = next PC (save return address)
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back
execute_engine.is_jump_nxt <= '1'; -- this is a jump operation
ctrl_nxt(ctrl_rf_wb_en_c) <= execute_engine.i_reg(instr_opcode_lsb_c+2); -- valid RF write-back? (for JAL/JALR)
execute_engine.is_jump_nxt <= execute_engine.i_reg(instr_opcode_lsb_c+2); -- is this is a jump operation? (for JAL/JALR)
execute_engine.state_nxt <= BRANCH;
 
when opcode_fence_c => -- fence operations
840,7 → 847,7
csr.we_nxt <= csr_acc_valid; -- always write CSR if valid access
when funct3_csrrs_c | funct3_csrrsi_c | funct3_csrrc_c | funct3_csrrci_c => -- CSRRS(I) / CSRRC(I)
csr.we_nxt <= (not rs1_is_r0_v) and csr_acc_valid; -- write CSR if rs1/imm is not zero and if valid access
when others =>
when others => -- invalid
csr.we_nxt <= '0';
end case;
-- register file write back --
850,22 → 857,23
 
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_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_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
-- cp access or alu shift? --
if (execute_engine.is_cp_op = '1') then
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_cp_c;
else
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_shift_c;
end if;
-- wait for result --
if (alu_wait_i = '0') then
execute_engine.state_nxt <= DISPATCH;
execute_engine.state_nxt <= DISPATCH;
end if;
 
when BRANCH => -- update PC for taken branches and jumps
-- ------------------------------------------------------------
if (execute_engine.is_jump = '1') or (execute_engine.branch_taken = '1') then
execute_engine.pc_nxt <= alu_add_i; -- branch/jump destination
execute_engine.pc_nxt <= alu_res_i; -- branch/jump destination
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;
919,7 → 927,7
variable is_m_mode_v : std_ulogic;
begin
-- are we in machine mode? --
if (csr.privilege = m_priv_mode_c) then
if (csr.privilege = priv_mode_m_c) then
is_m_mode_v := '1';
else
is_m_mode_v := '0';
926,48 → 934,50
end if;
 
-- check CSR access --
case execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) is
when x"300" => csr_acc_valid <= is_m_mode_v; -- mstatus
when x"301" => csr_acc_valid <= is_m_mode_v; -- misa
when x"304" => csr_acc_valid <= is_m_mode_v; -- mie
when x"305" => csr_acc_valid <= is_m_mode_v; -- mtvec
when x"340" => csr_acc_valid <= is_m_mode_v; -- mscratch
when x"341" => csr_acc_valid <= is_m_mode_v; -- mepc
when x"342" => csr_acc_valid <= is_m_mode_v; -- mcause
when x"343" => csr_acc_valid <= is_m_mode_v; -- mtval
when x"344" => csr_acc_valid <= is_m_mode_v; -- mip
case execute_engine.i_reg(instr_csr_id_msb_c downto instr_csr_id_lsb_c) is
when csr_mstatus_c => csr_acc_valid <= is_m_mode_v;
when csr_misa_c => csr_acc_valid <= is_m_mode_v;
when csr_mie_c => csr_acc_valid <= is_m_mode_v;
when csr_mtvec_c => csr_acc_valid <= is_m_mode_v;
when csr_mscratch_c => csr_acc_valid <= is_m_mode_v;
when csr_mepc_c => csr_acc_valid <= is_m_mode_v;
when csr_mcause_c => csr_acc_valid <= is_m_mode_v;
when csr_mtval_c => csr_acc_valid <= is_m_mode_v;
when csr_mip_c => csr_acc_valid <= is_m_mode_v;
--
when x"3a0" => csr_acc_valid <= bool_to_ulogic_f(PMP_USE) and bool_to_ulogic_f(boolean(PMP_NUM_REGIONS >= 1)) and is_m_mode_v; -- pmpacfg0
when x"3a1" => csr_acc_valid <= bool_to_ulogic_f(PMP_USE) and bool_to_ulogic_f(boolean(PMP_NUM_REGIONS >= 5)) and is_m_mode_v; -- pmpacfg1
when csr_pmpcfg0_c => csr_acc_valid <= bool_to_ulogic_f(PMP_USE) and bool_to_ulogic_f(boolean(PMP_NUM_REGIONS >= 1)) and is_m_mode_v;
when csr_pmpcfg1_c => csr_acc_valid <= bool_to_ulogic_f(PMP_USE) and bool_to_ulogic_f(boolean(PMP_NUM_REGIONS >= 5)) and is_m_mode_v;
--
when x"3b0" => csr_acc_valid <= bool_to_ulogic_f(PMP_USE) and bool_to_ulogic_f(boolean(PMP_NUM_REGIONS >= 1)) and is_m_mode_v; -- pmpaddr0
when x"3b1" => csr_acc_valid <= bool_to_ulogic_f(PMP_USE) and bool_to_ulogic_f(boolean(PMP_NUM_REGIONS >= 2)) and is_m_mode_v; -- pmpaddr1
when x"3b2" => csr_acc_valid <= bool_to_ulogic_f(PMP_USE) and bool_to_ulogic_f(boolean(PMP_NUM_REGIONS >= 3)) and is_m_mode_v; -- pmpaddr2
when x"3b3" => csr_acc_valid <= bool_to_ulogic_f(PMP_USE) and bool_to_ulogic_f(boolean(PMP_NUM_REGIONS >= 4)) and is_m_mode_v; -- pmpaddr3
when x"3b4" => csr_acc_valid <= bool_to_ulogic_f(PMP_USE) and bool_to_ulogic_f(boolean(PMP_NUM_REGIONS >= 5)) and is_m_mode_v; -- pmpaddr4
when x"3b5" => csr_acc_valid <= bool_to_ulogic_f(PMP_USE) and bool_to_ulogic_f(boolean(PMP_NUM_REGIONS >= 6)) and is_m_mode_v; -- pmpaddr5
when x"3b6" => csr_acc_valid <= bool_to_ulogic_f(PMP_USE) and bool_to_ulogic_f(boolean(PMP_NUM_REGIONS >= 7)) and is_m_mode_v; -- pmpaddr6
when x"3b7" => csr_acc_valid <= bool_to_ulogic_f(PMP_USE) and bool_to_ulogic_f(boolean(PMP_NUM_REGIONS >= 8)) and is_m_mode_v; -- pmpaddr7
when csr_pmpaddr0_c => csr_acc_valid <= bool_to_ulogic_f(PMP_USE) and bool_to_ulogic_f(boolean(PMP_NUM_REGIONS >= 1)) and is_m_mode_v;
when csr_pmpaddr1_c => csr_acc_valid <= bool_to_ulogic_f(PMP_USE) and bool_to_ulogic_f(boolean(PMP_NUM_REGIONS >= 2)) and is_m_mode_v;
when csr_pmpaddr2_c => csr_acc_valid <= bool_to_ulogic_f(PMP_USE) and bool_to_ulogic_f(boolean(PMP_NUM_REGIONS >= 3)) and is_m_mode_v;
when csr_pmpaddr3_c => csr_acc_valid <= bool_to_ulogic_f(PMP_USE) and bool_to_ulogic_f(boolean(PMP_NUM_REGIONS >= 4)) and is_m_mode_v;
when csr_pmpaddr4_c => csr_acc_valid <= bool_to_ulogic_f(PMP_USE) and bool_to_ulogic_f(boolean(PMP_NUM_REGIONS >= 5)) and is_m_mode_v;
when csr_pmpaddr5_c => csr_acc_valid <= bool_to_ulogic_f(PMP_USE) and bool_to_ulogic_f(boolean(PMP_NUM_REGIONS >= 6)) and is_m_mode_v;
when csr_pmpaddr6_c => csr_acc_valid <= bool_to_ulogic_f(PMP_USE) and bool_to_ulogic_f(boolean(PMP_NUM_REGIONS >= 7)) and is_m_mode_v;
when csr_pmpaddr7_c => csr_acc_valid <= bool_to_ulogic_f(PMP_USE) and bool_to_ulogic_f(boolean(PMP_NUM_REGIONS >= 8)) and is_m_mode_v;
--
when x"c00" => csr_acc_valid <= '1'; -- cycle
when x"c01" => csr_acc_valid <= '1'; -- time
when x"c02" => csr_acc_valid <= '1'; -- instret
when x"c80" => csr_acc_valid <= '1'; -- cycleh
when x"c81" => csr_acc_valid <= '1'; -- timeh
when x"c82" => csr_acc_valid <= '1'; -- instreth
when csr_mcycle_c => csr_acc_valid <= is_m_mode_v;
when csr_minstret_c => csr_acc_valid <= is_m_mode_v;
--
when x"b00" => csr_acc_valid <= is_m_mode_v; -- mcycle
when x"b02" => csr_acc_valid <= is_m_mode_v; -- minstret
when x"b80" => csr_acc_valid <= is_m_mode_v; -- mcycleh
when x"b82" => csr_acc_valid <= is_m_mode_v; -- minstreth
when csr_mcycleh_c => csr_acc_valid <= is_m_mode_v;
when csr_minstreth_c => csr_acc_valid <= is_m_mode_v;
--
when x"f11" => csr_acc_valid <= is_m_mode_v; -- mvendorid
when x"f12" => csr_acc_valid <= is_m_mode_v; -- marchid
when x"f13" => csr_acc_valid <= is_m_mode_v; -- mimpid
when x"f14" => csr_acc_valid <= is_m_mode_v; -- mhartid
when csr_cycle_c => csr_acc_valid <= '1';
when csr_time_c => csr_acc_valid <= '1';
when csr_instret_c => csr_acc_valid <= '1';
--
when x"fc0" => csr_acc_valid <= is_m_mode_v; -- mzext (custom CSR)
when csr_cycleh_c => csr_acc_valid <= '1';
when csr_timeh_c => csr_acc_valid <= '1';
when csr_instreth_c => csr_acc_valid <= '1';
--
when csr_mvendorid_c => csr_acc_valid <= is_m_mode_v;
when csr_marchid_c => csr_acc_valid <= is_m_mode_v;
when csr_mimpid_c => csr_acc_valid <= is_m_mode_v;
when csr_mhartid_c => csr_acc_valid <= is_m_mode_v;
--
when csr_mzext_c => csr_acc_valid <= is_m_mode_v;
--
when others => csr_acc_valid <= '0'; -- undefined, invalid access
end case;
end process invalid_csr_access_check;
1195,7 → 1205,6
trap_ctrl.exc_ack <= '1'; -- clear execption
trap_ctrl.irq_ack <= trap_ctrl.irq_ack_nxt; -- capture and clear with interrupt ACK mask
trap_ctrl.env_start <= '1'; -- now execute engine can start trap handler
-- assert false report "NEORV32.CPU TRAP: mcause=" & integer'image(to_integer(unsigned(trap_ctrl.cause_nxt))) severity note; -- for debugging
end if;
else -- trap waiting to get started
if (trap_ctrl.env_start_ack = '1') then -- start of trap handler acknowledged by execution engine
1319,6 → 1328,7
-- -------------------------------------------------------------------------------------------
csr_write_data: process(execute_engine.i_reg, csr.rdata, alu_res_i)
begin
-- "mini ALU" for CSR update operations --
case execute_engine.i_reg(instr_funct3_lsb_c+1 downto instr_funct3_lsb_c) is
when "10" => csr.wdata <= csr.rdata or alu_res_i; -- CSRRS(I)
when "11" => csr.wdata <= csr.rdata and (not alu_res_i); -- CSRRC(I)
1333,10 → 1343,11
begin
if (rstn_i = '0') then
csr.we <= '0';
csr.re <= '0';
--
csr.mstatus_mie <= '0';
csr.mstatus_mpie <= '0';
csr.mstatus_mpp <= priv_mode_m_c; -- start in MACHINE mode
csr.privilege <= priv_mode_m_c; -- start in MACHINE mode
csr.mie_msie <= '0';
csr.mie_meie <= '0';
csr.mie_mtie <= '0';
1346,163 → 1357,188
csr.mepc <= (others => '0');
csr.mcause <= (others => '0');
csr.mtval <= (others => '0');
csr.mpp <= m_priv_mode_c; -- start in MACHINE mode
csr.privilege <= m_priv_mode_c; -- start in MACHINE mode
csr.pmpcfg <= (others => (others => '0'));
csr.pmpaddr <= (others => (others => '0'));
elsif rising_edge(clk_i) then
if (CPU_EXTENSION_RISCV_Zicsr = true) then
-- access --
csr.we <= csr.we_nxt;
csr.re <= csr.re_nxt;
 
-- registers that can be modified by user --
if (csr.we = '1') then -- manual update
-- write access? --
csr.we <= csr.we_nxt;
 
-- Machine CSRs --
if (execute_engine.i_reg(31 downto 28) = x"3") then
-- machine trap setup --
if (execute_engine.i_reg(27 downto 24) = x"0") then
case execute_engine.i_reg(23 downto 20) is
when x"0" => -- R/W: mstatus - machine status register
csr.mstatus_mie <= csr.wdata(03);
csr.mstatus_mpie <= csr.wdata(07);
--
if (CPU_EXTENSION_RISCV_U = true) then -- user mode implemented
csr.mpp(0) <= csr.wdata(11) and csr.wdata(12);
csr.mpp(1) <= csr.wdata(11) and csr.wdata(12);
end if;
when x"4" => -- R/W: mie - machine interrupt-enable register
csr.mie_msie <= csr.wdata(03); -- machine SW IRQ enable
csr.mie_mtie <= csr.wdata(07); -- machine TIMER IRQ enable
csr.mie_meie <= csr.wdata(11); -- machine EXT IRQ enable
--
csr.mie_firqe(0) <= csr.wdata(16); -- fast interrupt channel 0
csr.mie_firqe(1) <= csr.wdata(17); -- fast interrupt channel 1
csr.mie_firqe(2) <= csr.wdata(18); -- fast interrupt channel 2
csr.mie_firqe(3) <= csr.wdata(19); -- fast interrupt channel 3
when x"5" => -- R/W: mtvec - machine trap-handler base address (for ALL exceptions)
csr.mtvec <= csr.wdata(data_width_c-1 downto 2) & "00"; -- mtvec.MODE=0
when others =>
NULL;
end case;
-- --------------------------------------------------------------------------------
-- CSRs that can be written by application software only
-- --------------------------------------------------------------------------------
if (CPU_EXTENSION_RISCV_Zicsr = true) and (csr.we = '1') then -- manual update
 
-- machine CSRs --
if (execute_engine.i_reg(31 downto 28) = csr_mie_c(11 downto 8)) then
 
-- machine trap setup --
if (execute_engine.i_reg(27 downto 24) = csr_mie_c(7 downto 4)) then
if (execute_engine.i_reg(23 downto 20) = csr_mie_c(3 downto 0)) then -- R/W: mie - machine interrupt-enable register
csr.mie_msie <= csr.wdata(03); -- machine SW IRQ enable
csr.mie_mtie <= csr.wdata(07); -- machine TIMER IRQ enable
csr.mie_meie <= csr.wdata(11); -- machine EXT IRQ enable
--
csr.mie_firqe(0) <= csr.wdata(16); -- fast interrupt channel 0
csr.mie_firqe(1) <= csr.wdata(17); -- fast interrupt channel 1
csr.mie_firqe(2) <= csr.wdata(18); -- fast interrupt channel 2
csr.mie_firqe(3) <= csr.wdata(19); -- fast interrupt channel 3
end if;
-- machine trap handling --
if (execute_engine.i_reg(27 downto 24) = x"4") then
case execute_engine.i_reg(23 downto 20) is
when x"0" => -- R/W: mscratch - machine scratch register
csr.mscratch <= csr.wdata;
when x"1" => -- R/W: mepc - machine exception program counter
csr.mepc <= csr.wdata(data_width_c-1 downto 1) & '0';
when x"3" => -- R/W: mtval - machine bad address or instruction
csr.mtval <= csr.wdata;
when others =>
NULL;
end case;
if (execute_engine.i_reg(23 downto 20) = csr_mtvec_c(3 downto 0)) then -- R/W: mtvec - machine trap-handler base address (for ALL exceptions)
csr.mtvec <= csr.wdata(data_width_c-1 downto 2) & "00"; -- mtvec.MODE=0
end if;
-- machine physical memory protection (pmp) --
if (PMP_USE = true) then
-- pmpcfg --
if (execute_engine.i_reg(27 downto 24) = x"a") then
if (PMP_NUM_REGIONS >= 1) then
if (execute_engine.i_reg(23 downto 20) = x"0") then -- pmpcfg0
for j in 0 to 3 loop -- bytes in pmpcfg CSR
if ((j+1) <= PMP_NUM_REGIONS) then
if (csr.pmpcfg(0+j)(7) = '0') then -- unlocked pmpcfg access
csr.pmpcfg(0+j)(0) <= csr.wdata(j*8+0); -- R
csr.pmpcfg(0+j)(1) <= csr.wdata(j*8+1); -- W
csr.pmpcfg(0+j)(2) <= csr.wdata(j*8+2); -- X
csr.pmpcfg(0+j)(3) <= csr.wdata(j*8+3) and csr.wdata(j*8+4); -- A_L
csr.pmpcfg(0+j)(4) <= csr.wdata(j*8+3) and csr.wdata(j*8+4); -- A_H - NAPOT/OFF only
csr.pmpcfg(0+j)(5) <= '0'; -- reserved
csr.pmpcfg(0+j)(6) <= '0'; -- reserved
csr.pmpcfg(0+j)(7) <= csr.wdata(j*8+7); -- L
end if;
end if;
 
-- machine trap handling --
if (execute_engine.i_reg(27 downto 20) = csr_mscratch_c(7 downto 0)) then -- R/W: mscratch - machine scratch register
csr.mscratch <= csr.wdata;
end if;
 
-- machine physical memory protection (pmp) --
if (PMP_USE = true) then
-- pmpcfg --
if (execute_engine.i_reg(27 downto 24) = csr_pmpcfg0_c(7 downto 4)) then
if (PMP_NUM_REGIONS >= 1) then
if (execute_engine.i_reg(23 downto 20) = csr_pmpcfg0_c(3 downto 0)) then -- pmpcfg0
for j in 0 to 3 loop -- bytes in pmpcfg CSR
if ((j+1) <= PMP_NUM_REGIONS) then
if (csr.pmpcfg(0+j)(7) = '0') then -- unlocked pmpcfg access
csr.pmpcfg(0+j)(0) <= csr.wdata(j*8+0); -- R
csr.pmpcfg(0+j)(1) <= csr.wdata(j*8+1); -- W
csr.pmpcfg(0+j)(2) <= csr.wdata(j*8+2); -- X
csr.pmpcfg(0+j)(3) <= csr.wdata(j*8+3) and csr.wdata(j*8+4); -- A_L
csr.pmpcfg(0+j)(4) <= csr.wdata(j*8+3) and csr.wdata(j*8+4); -- A_H - NAPOT/OFF only
csr.pmpcfg(0+j)(5) <= '0'; -- reserved
csr.pmpcfg(0+j)(6) <= '0'; -- reserved
csr.pmpcfg(0+j)(7) <= csr.wdata(j*8+7); -- L
end if;
end loop; -- j (bytes in CSR)
end if;
end if;
end loop; -- j (bytes in CSR)
end if;
if (PMP_NUM_REGIONS >= 5) then
if (execute_engine.i_reg(23 downto 20) = x"1") then -- pmpcfg1
for j in 0 to 3 loop -- bytes in pmpcfg CSR
if ((j+1+4) <= PMP_NUM_REGIONS) then
if (csr.pmpcfg(4+j)(7) = '0') then -- unlocked pmpcfg access
csr.pmpcfg(4+j)(0) <= csr.wdata(j*8+0); -- R
csr.pmpcfg(4+j)(1) <= csr.wdata(j*8+1); -- W
csr.pmpcfg(4+j)(2) <= csr.wdata(j*8+2); -- X
csr.pmpcfg(4+j)(3) <= csr.wdata(j*8+3) and csr.wdata(j*8+4); -- A_L
csr.pmpcfg(4+j)(4) <= csr.wdata(j*8+3) and csr.wdata(j*8+4); -- A_H - NAPOT/OFF only
csr.pmpcfg(4+j)(5) <= '0'; -- reserved
csr.pmpcfg(4+j)(6) <= '0'; -- reserved
csr.pmpcfg(4+j)(7) <= csr.wdata(j*8+7); -- L
end if;
end if;
if (PMP_NUM_REGIONS >= 5) then
if (execute_engine.i_reg(23 downto 20) = csr_pmpcfg1_c(3 downto 0)) then -- pmpcfg1
for j in 0 to 3 loop -- bytes in pmpcfg CSR
if ((j+1+4) <= PMP_NUM_REGIONS) then
if (csr.pmpcfg(4+j)(7) = '0') then -- unlocked pmpcfg access
csr.pmpcfg(4+j)(0) <= csr.wdata(j*8+0); -- R
csr.pmpcfg(4+j)(1) <= csr.wdata(j*8+1); -- W
csr.pmpcfg(4+j)(2) <= csr.wdata(j*8+2); -- X
csr.pmpcfg(4+j)(3) <= csr.wdata(j*8+3) and csr.wdata(j*8+4); -- A_L
csr.pmpcfg(4+j)(4) <= csr.wdata(j*8+3) and csr.wdata(j*8+4); -- A_H - NAPOT/OFF only
csr.pmpcfg(4+j)(5) <= '0'; -- reserved
csr.pmpcfg(4+j)(6) <= '0'; -- reserved
csr.pmpcfg(4+j)(7) <= csr.wdata(j*8+7); -- L
end if;
end loop; -- j (bytes in CSR)
end if;
end if;
end loop; -- j (bytes in CSR)
end if;
end if;
-- pmpaddr --
if (execute_engine.i_reg(27 downto 24) = x"b") then
for i in 0 to PMP_NUM_REGIONS-1 loop
if (execute_engine.i_reg(23 downto 20) = std_ulogic_vector(to_unsigned(i, 4))) and (csr.pmpcfg(i)(7) = '0') then -- unlocked pmpaddr access
csr.pmpaddr(i) <= csr.wdata(31 downto 1) & '0'; -- min granularity is 8 bytes -> bit zero cannot be configured
end if;
end loop; -- i (CSRs)
end if;
end if; -- implement PMP at all?
end if;
end if;
-- pmpaddr --
if (execute_engine.i_reg(27 downto 24) = csr_pmpaddr0_c(7 downto 4)) then
for i in 0 to PMP_NUM_REGIONS-1 loop
if (execute_engine.i_reg(23 downto 20) = std_ulogic_vector(to_unsigned(i, 4))) and (csr.pmpcfg(i)(7) = '0') then -- unlocked pmpaddr access
csr.pmpaddr(i) <= csr.wdata(31 downto 1) & '0'; -- min granularity is 8 bytes -> bit zero cannot be configured
end if;
end loop; -- i (CSRs)
end if;
end if; -- implement PMP at all?
end if;
 
-- automatic update by hardware --
else
end if;
 
-- machine exception PC & machine trap value register --
if (trap_ctrl.env_start_ack = '1') then -- trap handler starting?
-- trap ID code --
csr.mcause <= (others => '0');
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
if (trap_ctrl.cause(trap_ctrl.cause'left) = '1') then -- for INTERRUPTS (is mcause(31))
csr.mepc <= execute_engine.pc(data_width_c-1 downto 1) & '0'; -- this is the CURRENT pc = interrupted instruction
csr.mtval <= (others => '0'); -- mtval is zero for interrupts
else -- for EXCEPTIONS (according to their priority)
csr.mepc <= execute_engine.last_pc(data_width_c-1 downto 1) & '0'; -- this is the LAST pc = last executed instruction
if (trap_ctrl.cause(4 downto 0) = trap_iba_c(4 downto 0)) or -- instruction access error OR
(trap_ctrl.cause(4 downto 0) = trap_ima_c(4 downto 0)) or -- misaligned instruction address OR
(trap_ctrl.cause(4 downto 0) = trap_brk_c(4 downto 0)) or -- breakpoint OR
(trap_ctrl.cause(4 downto 0) = trap_menv_c(4 downto 0)) then -- environment call
csr.mtval <= execute_engine.pc(data_width_c-1 downto 1) & '0'; -- address of faulting instruction
elsif (trap_ctrl.cause(4 downto 0) = trap_iil_c(4 downto 0)) then -- illegal instruction
csr.mtval <= execute_engine.i_reg; -- faulting instruction itself
else -- load/store misalignments/access errors
csr.mtval <= mar_i; -- faulting data access address
end if;
-- --------------------------------------------------------------------------------
-- CSRs that can be written by application and hardware (application access)
-- --------------------------------------------------------------------------------
if (CPU_EXTENSION_RISCV_Zicsr = true) and (csr.we = '1') then -- manual update
 
-- machine CSRs --
if (execute_engine.i_reg(31 downto 28) = csr_mstatus_c(11 downto 8)) then
 
-- machine trap setup --
if (execute_engine.i_reg(27 downto 20) = csr_mstatus_c(7 downto 0)) then -- R/W: mstatus - machine status register
csr.mstatus_mie <= csr.wdata(03);
csr.mstatus_mpie <= csr.wdata(07);
--
if (CPU_EXTENSION_RISCV_U = true) then -- user mode implemented
csr.mstatus_mpp(0) <= csr.wdata(11) or csr.wdata(12);
csr.mstatus_mpp(1) <= csr.wdata(11) or csr.wdata(12);
end if;
end if;
 
-- context switch in mstatus --
if (trap_ctrl.env_start_ack = '1') then -- ENTER: trap handler starting?
csr.mstatus_mie <= '0'; -- disable interrupts
csr.mstatus_mpie <= csr.mstatus_mie; -- buffer previous mie state
if (CPU_EXTENSION_RISCV_U = true) then -- implement user mode
csr.privilege <= m_priv_mode_c; -- execute trap in machine mode
csr.mpp <= csr.privilege; -- buffer previous privilege mode
-- machine trap handling --
if (execute_engine.i_reg(27 downto 24) = csr_mepc_c(7 downto 4)) then
if (execute_engine.i_reg(23 downto 20) = csr_mepc_c(3 downto 0)) then -- R/W: mepc - machine exception program counter
csr.mepc <= csr.wdata(data_width_c-1 downto 1) & '0';
end if;
elsif (trap_ctrl.env_end = '1') then -- EXIT: return from exception
csr.mstatus_mie <= csr.mstatus_mpie; -- restore global IRQ enable flag
csr.mstatus_mpie <= '1';
if (CPU_EXTENSION_RISCV_U = true) then -- implement user mode
csr.privilege <= csr.mpp; -- go back to previous privilege mode
csr.mpp <= u_priv_mode_c;
if (execute_engine.i_reg(23 downto 20) = csr_mtval_c(3 downto 0)) then -- R/W: mtval - machine bad address or instruction
csr.mtval <= csr.wdata;
end if;
end if;
 
-- user mode NOT implemented --
if (CPU_EXTENSION_RISCV_U = false) then -- implement user mode
csr.privilege <= m_priv_mode_c;
csr.mpp <= m_priv_mode_c;
end if;
 
-- --------------------------------------------------------------------------------
-- CSRs that can be written by application and hardware (hardware access)
-- --------------------------------------------------------------------------------
else -- hardware update
 
-- mepc & mtval: machine exception PC & machine trap value register --
if (trap_ctrl.env_start_ack = '1') then -- trap handler starting?
if (trap_ctrl.cause(trap_ctrl.cause'left) = '1') then -- for INTERRUPTS (is mcause(31))
csr.mepc <= execute_engine.pc(data_width_c-1 downto 1) & '0'; -- this is the CURRENT pc = interrupted instruction
csr.mtval <= (others => '0'); -- mtval is zero for interrupts
else -- for EXCEPTIONS (according to their priority)
csr.mepc <= execute_engine.last_pc(data_width_c-1 downto 1) & '0'; -- this is the LAST pc = last executed instruction
if (trap_ctrl.cause(4 downto 0) = trap_iba_c(4 downto 0)) or -- instruction access error OR
(trap_ctrl.cause(4 downto 0) = trap_ima_c(4 downto 0)) or -- misaligned instruction address OR
(trap_ctrl.cause(4 downto 0) = trap_brk_c(4 downto 0)) or -- breakpoint OR
(trap_ctrl.cause(4 downto 0) = trap_menv_c(4 downto 0)) then -- environment call
csr.mtval <= execute_engine.pc(data_width_c-1 downto 1) & '0'; -- address of faulting instruction
elsif (trap_ctrl.cause(4 downto 0) = trap_iil_c(4 downto 0)) then -- illegal instruction
csr.mtval <= execute_engine.i_reg; -- faulting instruction itself
else -- load/store misalignments/access errors
csr.mtval <= mar_i; -- faulting data access address
end if;
end if;
end if;
 
-- mstatus: context switch --
if (trap_ctrl.env_start_ack = '1') then -- ENTER: trap handler starting?
csr.mstatus_mie <= '0'; -- disable interrupts
csr.mstatus_mpie <= csr.mstatus_mie; -- buffer previous mie state
if (CPU_EXTENSION_RISCV_U = true) then -- implement user mode
csr.privilege <= priv_mode_m_c; -- execute trap in machine mode
csr.mstatus_mpp <= csr.privilege; -- buffer previous privilege mode
end if;
elsif (trap_ctrl.env_end = '1') then -- EXIT: return from exception
csr.mstatus_mie <= csr.mstatus_mpie; -- restore global IRQ enable flag
csr.mstatus_mpie <= '1';
if (CPU_EXTENSION_RISCV_U = true) then -- implement user mode
csr.privilege <= csr.mstatus_mpp; -- go back to previous privilege mode
csr.mstatus_mpp <= priv_mode_u_c;
end if;
end if;
-- user mode NOT implemented --
if (CPU_EXTENSION_RISCV_U = false) then
csr.privilege <= priv_mode_m_c;
csr.mstatus_mpp <= priv_mode_m_c;
end if;
end if;
 
-- --------------------------------------------------------------------------------
-- CSRs that can be written by hardware only
-- --------------------------------------------------------------------------------
 
-- mcause
if (trap_ctrl.env_start_ack = '1') then -- trap handler starting?
-- trap ID code --
csr.mcause <= (others => '0');
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
end if;
 
end if;
end process csr_write_access;
 
1513,16 → 1549,17
begin
if rising_edge(clk_i) then
csr.rdata <= (others => '0'); -- default
csr.re <= csr.re_nxt; -- read access?
if (CPU_EXTENSION_RISCV_Zicsr = true) and (csr.re = '1') then
case execute_engine.i_reg(31 downto 20) is
case execute_engine.i_reg(instr_csr_id_msb_c downto instr_csr_id_lsb_c) is
 
-- machine trap setup --
when x"300" => -- R/W: mstatus - machine status register
when csr_mstatus_c => -- R/W: mstatus - machine status register
csr.rdata(03) <= csr.mstatus_mie; -- MIE
csr.rdata(07) <= csr.mstatus_mpie; -- MPIE
csr.rdata(11) <= csr.mpp(0); -- MPP: machine previous privilege mode low
csr.rdata(12) <= csr.mpp(1); -- MPP: machine previous privilege mode high
when x"301" => -- R/-: misa - ISA and extensions
csr.rdata(11) <= csr.mstatus_mpp(0); -- MPP: machine previous privilege mode low
csr.rdata(12) <= csr.mstatus_mpp(1); -- MPP: machine previous privilege mode high
when csr_misa_c => -- R/-: misa - ISA and extensions
csr.rdata(02) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_C); -- C CPU extension
csr.rdata(04) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_E); -- E CPU extension
csr.rdata(08) <= not bool_to_ulogic_f(CPU_EXTENSION_RISCV_E); -- I CPU extension (if not E)
1531,7 → 1568,7
csr.rdata(23) <= '1'; -- X CPU extension (non-std extensions)
csr.rdata(30) <= '1'; -- 32-bit architecture (MXL lo)
csr.rdata(31) <= '0'; -- 32-bit architecture (MXL hi)
when x"304" => -- R/W: mie - machine interrupt-enable register
when csr_mie_c => -- R/W: mie - machine interrupt-enable register
csr.rdata(03) <= csr.mie_msie; -- machine software IRQ enable
csr.rdata(07) <= csr.mie_mtie; -- machine timer IRQ enable
csr.rdata(11) <= csr.mie_meie; -- machine external IRQ enable
1540,19 → 1577,19
csr.rdata(17) <= csr.mie_firqe(1); -- fast interrupt channel 1
csr.rdata(18) <= csr.mie_firqe(2); -- fast interrupt channel 2
csr.rdata(19) <= csr.mie_firqe(3); -- fast interrupt channel 3
when x"305" => -- R/W: mtvec - machine trap-handler base address (for ALL exceptions)
when csr_mtvec_c => -- R/W: mtvec - machine trap-handler base address (for ALL exceptions)
csr.rdata <= csr.mtvec(data_width_c-1 downto 2) & "00"; -- mtvec.MODE=0
 
-- machine trap handling --
when x"340" => -- R/W: mscratch - machine scratch register
when csr_mscratch_c => -- R/W: mscratch - machine scratch register
csr.rdata <= csr.mscratch;
when x"341" => -- 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';
when x"342" => -- R/-: mcause - machine trap cause
when csr_mcause_c => -- R/-: mcause - machine trap cause
csr.rdata <= csr.mcause;
when x"343" => -- R/W: mtval - machine bad address or instruction
when csr_mtval_c => -- R/W: mtval - machine bad address or instruction
csr.rdata <= csr.mtval;
when x"344" => -- R/W: mip - machine interrupt pending
when csr_mip_c => -- R/W: mip - machine interrupt pending
csr.rdata(03) <= trap_ctrl.irq_buf(interrupt_msw_irq_c);
csr.rdata(07) <= trap_ctrl.irq_buf(interrupt_mtime_irq_c);
csr.rdata(11) <= trap_ctrl.irq_buf(interrupt_mext_irq_c);
1563,7 → 1600,7
csr.rdata(19) <= trap_ctrl.irq_buf(interrupt_firq_3_c);
 
-- physical memory protection --
when x"3a0" => -- R/W: pmpcfg0 - physical memory protection configuration register 0
when csr_pmpcfg0_c => -- R/W: pmpcfg0 - physical memory protection configuration register 0
if (PMP_USE = true) then
if (PMP_NUM_REGIONS >= 1) then
csr.rdata(07 downto 00) <= csr.pmpcfg(0);
1578,7 → 1615,7
csr.rdata(31 downto 24) <= csr.pmpcfg(3);
end if;
end if;
when x"3a1" => -- R/W: pmpcfg1 - physical memory protection configuration register 1
when csr_pmpcfg1_c => -- R/W: pmpcfg1 - physical memory protection configuration register 1
if (PMP_USE = true) then
if (PMP_NUM_REGIONS >= 5) then
csr.rdata(07 downto 00) <= csr.pmpcfg(4);
1594,7 → 1631,7
end if;
end if;
 
when x"3b0" => -- R/W: pmpaddr0 - physical memory protection address register 0
when csr_pmpaddr0_c => -- R/W: pmpaddr0 - physical memory protection address register 0
if (PMP_USE = true) and (PMP_NUM_REGIONS >= 1) then
csr.rdata <= csr.pmpaddr(0);
if (csr.pmpcfg(0)(4 downto 3) = "00") then -- mode = off
1603,7 → 1640,7
csr.rdata(PMP_GRANULARITY-2 downto 0) <= (others => '1');
end if;
end if;
when x"3b1" => -- R/W: pmpaddr1 - physical memory protection address register 1
when csr_pmpaddr1_c => -- R/W: pmpaddr1 - physical memory protection address register 1
if (PMP_USE = true) and (PMP_NUM_REGIONS >= 2) then
csr.rdata <= csr.pmpaddr(1);
if (csr.pmpcfg(1)(4 downto 3) = "00") then -- mode = off
1612,7 → 1649,7
csr.rdata(PMP_GRANULARITY-2 downto 0) <= (others => '1');
end if;
end if;
when x"3b2" => -- R/W: pmpaddr2 - physical memory protection address register 2
when csr_pmpaddr2_c => -- R/W: pmpaddr2 - physical memory protection address register 2
if (PMP_USE = true) and (PMP_NUM_REGIONS >= 3) then
csr.rdata <= csr.pmpaddr(2);
if (csr.pmpcfg(2)(4 downto 3) = "00") then -- mode = off
1621,7 → 1658,7
csr.rdata(PMP_GRANULARITY-2 downto 0) <= (others => '1');
end if;
end if;
when x"3b3" => -- R/W: pmpaddr3 - physical memory protection address register 3
when csr_pmpaddr3_c => -- R/W: pmpaddr3 - physical memory protection address register 3
if (PMP_USE = true) and (PMP_NUM_REGIONS >= 4) then
csr.rdata <= csr.pmpaddr(3);
if (csr.pmpcfg(3)(4 downto 3) = "00") then -- mode = off
1630,7 → 1667,7
csr.rdata(PMP_GRANULARITY-2 downto 0) <= (others => '1');
end if;
end if;
when x"3b4" => -- R/W: pmpaddr4 - physical memory protection address register 4
when csr_pmpaddr4_c => -- R/W: pmpaddr4 - physical memory protection address register 4
if (PMP_USE = true) and (PMP_NUM_REGIONS >= 5) then
csr.rdata <= csr.pmpaddr(4);
if (csr.pmpcfg(4)(4 downto 3) = "00") then -- mode = off
1639,7 → 1676,7
csr.rdata(PMP_GRANULARITY-2 downto 0) <= (others => '1');
end if;
end if;
when x"3b5" => -- R/W: pmpaddr5 - physical memory protection address register 5
when csr_pmpaddr5_c => -- R/W: pmpaddr5 - physical memory protection address register 5
if (PMP_USE = true) and (PMP_NUM_REGIONS >= 6) then
csr.rdata <= csr.pmpaddr(5);
if (csr.pmpcfg(5)(4 downto 3) = "00") then -- mode = off
1648,7 → 1685,7
csr.rdata(PMP_GRANULARITY-2 downto 0) <= (others => '1');
end if;
end if;
when x"3b6" => -- R/W: pmpaddr6 - physical memory protection address register 6
when csr_pmpaddr6_c => -- R/W: pmpaddr6 - physical memory protection address register 6
if (PMP_USE = true) and (PMP_NUM_REGIONS >= 7) then
csr.rdata <= csr.pmpaddr(6);
if (csr.pmpcfg(6)(4 downto 3) = "00") then -- mode = off
1657,7 → 1694,7
csr.rdata(PMP_GRANULARITY-2 downto 0) <= (others => '1');
end if;
end if;
when x"3b7" => -- R/W: pmpaddr7 - physical memory protection address register 7
when csr_pmpaddr7_c => -- R/W: pmpaddr7 - physical memory protection address register 7
if (PMP_USE = true) and (PMP_NUM_REGIONS >= 8) then
csr.rdata <= csr.pmpaddr(7);
if (csr.pmpcfg(7)(4 downto 3) = "00") then -- mode = off
1667,32 → 1704,32
end if;
end if;
 
-- counter and timers --
when x"c00" | x"b00" => -- R/(W): cycle/mcycle: Cycle counter LOW
-- counters and timers --
when csr_cycle_c | csr_mcycle_c => -- R/(W): [m]cycle: Cycle counter LOW
csr.rdata <= csr.mcycle(31 downto 0);
when x"c01" => -- R/-: time: System time LOW (from MTIME unit)
when csr_time_c => -- R/-: time: System time LOW (from MTIME unit)
csr.rdata <= time_i(31 downto 0);
when x"c02" | x"b02" => -- R/(W): instret/minstret: Instructions-retired counter LOW
when csr_instret_c | csr_minstret_c => -- R/(W): [m]instret: Instructions-retired counter LOW
csr.rdata <= csr.minstret(31 downto 0);
when x"c80" | x"b80" => -- R/(W): cycleh/mcycleh: Cycle counter HIGH
when csr_cycleh_c | csr_mcycleh_c => -- R/(W): [m]cycleh: Cycle counter HIGH
csr.rdata <= csr.mcycleh(31 downto 0);
when x"c81" => -- R/-: timeh: System time HIGH (from MTIME unit)
when csr_timeh_c => -- R/-: timeh: System time HIGH (from MTIME unit)
csr.rdata <= time_i(63 downto 32);
when x"c82" | x"b82" => -- R/(W): instreth/minstreth: Instructions-retired counter HIGH
when csr_instreth_c | csr_minstreth_c => -- R/(W): [m]instreth: Instructions-retired counter HIGH
csr.rdata <= csr.minstreth(31 downto 0);
 
-- machine information registers --
when x"f11" => -- R/-: mvendorid - vendor ID
when csr_mvendorid_c => -- R/-: mvendorid - vendor ID
csr.rdata <= (others => '0');
when x"f12" => -- R/-: marchid - architecture ID
when csr_marchid_c => -- R/-: marchid - architecture ID
csr.rdata <= (others => '0');
when x"f13" => -- R/-: mimpid - implementation ID / NEORV32 hardware version
when csr_mimpid_c => -- R/-: mimpid - implementation ID / NEORV32 hardware version
csr.rdata <= hw_version_c;
when x"f14" => -- R/-: mhartid - hardware thread ID
when csr_mhartid_c => -- R/-: mhartid - hardware thread ID
csr.rdata <= HW_THREAD_ID;
 
-- custom machine read-only CSRs --
when x"fc0" => -- R/-: mzext
when csr_mzext_c => -- R/-: mzext
csr.rdata(0) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zicsr); -- Zicsr CPU extension
csr.rdata(1) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zifencei); -- Zifencei CPU extension
 
1701,8 → 1738,6
csr.rdata <= (others => '0'); -- not implemented
 
end case;
else
csr.rdata <= (others => '0');
end if;
end if;
end process csr_read_access;
1742,7 → 1777,7
 
-- mcycle (cycle) --
mcycle_msb <= csr.mcycle(csr.mcycle'left);
if (csr.we = '1') and (execute_engine.i_reg(31 downto 20) = x"b00") then -- write access
if (csr.we = '1') and (execute_engine.i_reg(instr_csr_id_msb_c downto instr_csr_id_lsb_c) = csr_mcycle_c) then -- write access
csr.mcycle(31 downto 0) <= csr.wdata;
csr.mcycle(32) <= '0';
elsif (execute_engine.sleep = '0') then -- automatic update (if CPU is not in sleep mode)
1750,7 → 1785,7
end if;
 
-- mcycleh (cycleh) --
if (csr.we = '1') and (execute_engine.i_reg(31 downto 20) = x"b80") then -- write access
if (csr.we = '1') and (execute_engine.i_reg(instr_csr_id_msb_c downto instr_csr_id_lsb_c) = csr_mcycleh_c) then -- write access
csr.mcycleh <= csr.wdata(csr.mcycleh'left downto 0);
elsif ((mcycle_msb xor csr.mcycle(csr.mcycle'left)) = '1') then -- automatic update
csr.mcycleh <= std_ulogic_vector(unsigned(csr.mcycleh) + 1);
1758,7 → 1793,7
 
-- minstret (instret) --
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(instr_csr_id_msb_c downto instr_csr_id_lsb_c) = csr_minstret_c) then -- write access
csr.minstret(31 downto 0) <= csr.wdata;
csr.minstret(32) <= '0';
elsif (execute_engine.state_prev /= EXECUTE) and (execute_engine.state = EXECUTE) then -- automatic update
1766,7 → 1801,7
end if;
 
-- 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(instr_csr_id_msb_c downto instr_csr_id_lsb_c) = csr_minstreth_c) then -- write access
csr.minstreth <= csr.wdata(csr.minstreth'left downto 0);
elsif ((minstret_msb xor csr.minstret(csr.minstret'left)) = '1') then -- automatic update
csr.minstreth <= std_ulogic_vector(unsigned(csr.minstreth) + 1);
/neorv32_dmem.vhd
58,6 → 58,10
 
architecture neorv32_dmem_rtl of neorv32_dmem is
 
-- IO space: module base address --
constant hi_abb_c : natural := 31; -- high address boundary bit
constant lo_abb_c : natural := index_size_f(DMEM_SIZE); -- low address boundary bit
 
-- local signals --
signal acc_en : std_ulogic;
signal rdata : std_ulogic_vector(31 downto 0);
96,7 → 100,7
 
-- Access Control -------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
acc_en <= '1' when (addr_i >= DMEM_BASE) and (addr_i < std_ulogic_vector(unsigned(DMEM_BASE) + DMEM_SIZE)) else '0';
acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = DMEM_BASE(hi_abb_c downto lo_abb_c)) else '0';
addr <= addr_i(index_size_f(DMEM_SIZE/4)+1 downto 2); -- word aligned
 
 
/neorv32_imem.vhd
67,6 → 67,10
 
architecture neorv32_imem_rtl of neorv32_imem is
 
-- IO space: module base address --
constant hi_abb_c : natural := 31; -- high address boundary bit
constant lo_abb_c : natural := index_size_f(IMEM_SIZE); -- low address boundary bit
 
-- ROM types --
type imem_file8_t is array (0 to IMEM_SIZE/4-1) of std_ulogic_vector(07 downto 0);
 
140,7 → 144,7
 
-- Access Control -------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
acc_en <= '1' when (addr_i >= IMEM_BASE) and (addr_i < std_ulogic_vector(unsigned(IMEM_BASE) + IMEM_SIZE)) else '0';
acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = IMEM_BASE(hi_abb_c downto lo_abb_c)) else '0';
addr <= addr_i(index_size_f(IMEM_SIZE/4)+1 downto 2); -- word aligned
 
 
/neorv32_package.vhd
41,7 → 41,7
-- Architecture Constants -----------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
constant data_width_c : natural := 32; -- data width - do not change!
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01040400"; -- no touchy!
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01040402"; -- no touchy!
constant pmp_max_r_c : natural := 8; -- max PMP regions - FIXED!
 
-- Architecture Configuration -------------------------------------------------------------
183,9 → 183,9
constant ctrl_alu_cmd0_c : natural := 19; -- ALU command bit 0
constant ctrl_alu_cmd1_c : natural := 20; -- ALU command bit 1
constant ctrl_alu_cmd2_c : natural := 21; -- ALU command bit 2
constant ctrl_alu_opa_mux_c : natural := 22; -- operand A select (0=rs1, 1=PC)
constant ctrl_alu_opb_mux_c : natural := 23; -- operand B select (0=rs2, 1=IMM)
constant ctrl_alu_opc_mux_c : natural := 24; -- operand C select (0=rs2, 1=IMM)
constant ctrl_alu_addsub_c : natural := 22; -- 0=ADD, 1=SUB
constant ctrl_alu_opa_mux_c : natural := 23; -- operand A select (0=rs1, 1=PC)
constant ctrl_alu_opb_mux_c : natural := 24; -- operand B select (0=rs2, 1=IMM)
constant ctrl_alu_unsigned_c : natural := 25; -- is unsigned ALU operation
constant ctrl_alu_shift_dir_c : natural := 26; -- shift direction (0=left, 1=right)
constant ctrl_alu_shift_ar_c : natural := 27; -- is arithmetic shift
204,17 → 204,14
constant ctrl_bus_fence_c : natural := 39; -- executed fence operation
constant ctrl_bus_fencei_c : natural := 40; -- executed fencei operation
-- co-processors --
constant ctrl_cp_use_c : natural := 41; -- is cp operation
constant ctrl_cp_id_lsb_c : natural := 42; -- cp select ID lsb
constant ctrl_cp_id_msb_c : natural := 43; -- cp select ID msb
constant ctrl_cp_cmd0_c : natural := 44; -- cp command bit 0
constant ctrl_cp_cmd1_c : natural := 45; -- cp command bit 1
constant ctrl_cp_cmd2_c : natural := 46; -- cp command bit 2
constant ctrl_cp_id_lsb_c : natural := 41; -- cp select ID lsb
constant ctrl_cp_id_msb_c : natural := 42; -- cp select ID msb
constant ctrl_cp_cmd0_c : natural := 43; -- cp command bit 0
constant ctrl_cp_cmd1_c : natural := 44; -- cp command bit 1
constant ctrl_cp_cmd2_c : natural := 45; -- cp command bit 2
-- control bus size --
constant ctrl_width_c : natural := 47; -- control bus size
constant ctrl_width_c : natural := 46; -- control bus size
 
constant ctrl_alu_aopb_inv_c : natural := 48;
 
-- ALU Comparator Bus ---------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
constant alu_cmp_equal_c : natural := 0;
252,7 → 249,7
constant opcode_alu_c : std_ulogic_vector(6 downto 0) := "0110011"; -- ALU operation (operation via funct3 and funct7)
-- control flow --
constant opcode_jal_c : std_ulogic_vector(6 downto 0) := "1101111"; -- jump and link
constant opcode_jalr_c : std_ulogic_vector(6 downto 0) := "1100111"; -- jump and register
constant opcode_jalr_c : std_ulogic_vector(6 downto 0) := "1100111"; -- jump and link with register
constant opcode_branch_c : std_ulogic_vector(6 downto 0) := "1100011"; -- branch (condition set via funct3)
-- memory access --
constant opcode_load_c : std_ulogic_vector(6 downto 0) := "0000011"; -- load (data type via funct3)
309,6 → 306,52
constant funct12_mret_c : std_ulogic_vector(11 downto 0) := x"302"; -- MRET
constant funct12_wfi_c : std_ulogic_vector(11 downto 0) := x"105"; -- WFI
 
-- RISC-V CSR Addresses -------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
constant csr_mstatus_c : std_ulogic_vector(11 downto 0) := x"300"; -- mstatus
constant csr_misa_c : std_ulogic_vector(11 downto 0) := x"301"; -- misa
constant csr_mie_c : std_ulogic_vector(11 downto 0) := x"304"; -- mie
constant csr_mtvec_c : std_ulogic_vector(11 downto 0) := x"305"; -- mtvec
--
constant csr_mscratch_c : std_ulogic_vector(11 downto 0) := x"340"; -- mscratch
constant csr_mepc_c : std_ulogic_vector(11 downto 0) := x"341"; -- mepc
constant csr_mcause_c : std_ulogic_vector(11 downto 0) := x"342"; -- mcause
constant csr_mtval_c : std_ulogic_vector(11 downto 0) := x"343"; -- mtval
constant csr_mip_c : std_ulogic_vector(11 downto 0) := x"344"; -- mip
--
constant csr_pmpcfg0_c : std_ulogic_vector(11 downto 0) := x"3a0"; -- pmpcfg0
constant csr_pmpcfg1_c : std_ulogic_vector(11 downto 0) := x"3a1"; -- pmpcfg1
--
constant csr_pmpaddr0_c : std_ulogic_vector(11 downto 0) := x"3b0"; -- pmpaddr0
constant csr_pmpaddr1_c : std_ulogic_vector(11 downto 0) := x"3b1"; -- pmpaddr1
constant csr_pmpaddr2_c : std_ulogic_vector(11 downto 0) := x"3b2"; -- pmpaddr2
constant csr_pmpaddr3_c : std_ulogic_vector(11 downto 0) := x"3b3"; -- pmpaddr3
constant csr_pmpaddr4_c : std_ulogic_vector(11 downto 0) := x"3b4"; -- pmpaddr4
constant csr_pmpaddr5_c : std_ulogic_vector(11 downto 0) := x"3b5"; -- pmpaddr5
constant csr_pmpaddr6_c : std_ulogic_vector(11 downto 0) := x"3b6"; -- pmpaddr6
constant csr_pmpaddr7_c : std_ulogic_vector(11 downto 0) := x"3b7"; -- pmpaddr7
--
constant csr_mcycle_c : std_ulogic_vector(11 downto 0) := x"b00"; -- mcycle
constant csr_minstret_c : std_ulogic_vector(11 downto 0) := x"b02"; -- minstret
--
constant csr_mcycleh_c : std_ulogic_vector(11 downto 0) := x"b80"; -- mcycleh
constant csr_minstreth_c : std_ulogic_vector(11 downto 0) := x"b82"; -- minstreth
--
constant csr_cycle_c : std_ulogic_vector(11 downto 0) := x"c00"; -- cycle
constant csr_time_c : std_ulogic_vector(11 downto 0) := x"c01"; -- time
constant csr_instret_c : std_ulogic_vector(11 downto 0) := x"c02"; -- instret
--
constant csr_cycleh_c : std_ulogic_vector(11 downto 0) := x"c80"; -- cycleh
constant csr_timeh_c : std_ulogic_vector(11 downto 0) := x"c81"; -- timeh
constant csr_instreth_c : std_ulogic_vector(11 downto 0) := x"c82"; -- instreth
--
constant csr_mvendorid_c : std_ulogic_vector(11 downto 0) := x"f11"; -- mvendorid
constant csr_marchid_c : std_ulogic_vector(11 downto 0) := x"f12"; -- marchid
constant csr_mimpid_c : std_ulogic_vector(11 downto 0) := x"f13"; -- mimpid
constant csr_mhartid_c : std_ulogic_vector(11 downto 0) := x"f14"; -- mhartid
--
constant csr_mzext_c : std_ulogic_vector(11 downto 0) := x"fc0"; -- mzext
 
-- Co-Processor Operations ----------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
-- cp ids --
325,14 → 368,14
 
-- ALU Function Codes ---------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
constant alu_cmd_add_c : std_ulogic_vector(2 downto 0) := "000"; -- r <= A + B
constant alu_cmd_sub_c : std_ulogic_vector(2 downto 0) := "001"; -- r <= A - B
constant alu_cmd_slt_c : std_ulogic_vector(2 downto 0) := "010"; -- r <= A < B
constant alu_cmd_shift_c : std_ulogic_vector(2 downto 0) := "011"; -- r <= A <</>> B
constant alu_cmd_xor_c : std_ulogic_vector(2 downto 0) := "100"; -- r <= A xor B
constant alu_cmd_or_c : std_ulogic_vector(2 downto 0) := "101"; -- r <= A or B
constant alu_cmd_and_c : std_ulogic_vector(2 downto 0) := "110"; -- r <= A and B
constant alu_cmd_movb_c : std_ulogic_vector(2 downto 0) := "111"; -- r <= B
constant alu_cmd_addsub_c : std_ulogic_vector(2 downto 0) := "000"; -- r <= A +/- B
constant alu_cmd_slt_c : std_ulogic_vector(2 downto 0) := "001"; -- r <= A < B
constant alu_cmd_cp_c : std_ulogic_vector(2 downto 0) := "010"; -- r <= CP result (iterative)
constant alu_cmd_shift_c : std_ulogic_vector(2 downto 0) := "011"; -- r <= A <</>> B (iterative)
constant alu_cmd_movb_c : std_ulogic_vector(2 downto 0) := "100"; -- r <= B
constant alu_cmd_xor_c : std_ulogic_vector(2 downto 0) := "101"; -- r <= A xor B
constant alu_cmd_or_c : std_ulogic_vector(2 downto 0) := "110"; -- r <= A or B
constant alu_cmd_and_c : std_ulogic_vector(2 downto 0) := "111"; -- r <= A and B
 
-- Trap ID Codes --------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
383,8 → 426,8
 
-- CPU Privilege Modes --------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
constant m_priv_mode_c : std_ulogic_vector(1 downto 0) := "11"; -- machine mode
constant u_priv_mode_c : std_ulogic_vector(1 downto 0) := "00"; -- user mode
constant priv_mode_m_c : std_ulogic_vector(1 downto 0) := "11"; -- machine mode
constant priv_mode_u_c : std_ulogic_vector(1 downto 0) := "00"; -- user mode
 
-- Clock Generator -------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
571,7 → 614,6
-- data input --
instr_i : in std_ulogic_vector(data_width_c-1 downto 0); -- instruction
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.add result
alu_res_i : in std_ulogic_vector(data_width_c-1 downto 0); -- ALU processing result
-- data output --
imm_o : out std_ulogic_vector(data_width_c-1 downto 0); -- immediate
641,7 → 683,6
imm_i : in std_ulogic_vector(data_width_c-1 downto 0); -- immediate
-- data output --
cmp_o : out std_ulogic_vector(1 downto 0); -- comparator status
add_o : out std_ulogic_vector(data_width_c-1 downto 0); -- OPA + OPB
res_o : out std_ulogic_vector(data_width_c-1 downto 0); -- ALU result
-- co-processor interface --
cp0_start_o : out std_ulogic; -- trigger co-processor 0
/neorv32_top.vhd
131,6 → 131,10
-- CPU boot address --
constant cpu_boot_addr_c : std_ulogic_vector(31 downto 0) := cond_sel_stdulogicvector_f(BOOTLOADER_USE, boot_rom_base_c, ispace_base_c);
 
-- alignment check for internal memories --
constant imem_align_check_c : std_ulogic_vector(index_size_f(MEM_INT_IMEM_SIZE)-1 downto 0) := (others => '0');
constant dmem_align_check_c : std_ulogic_vector(index_size_f(MEM_INT_DMEM_SIZE)-1 downto 0) := (others => '0');
 
-- reset generator --
signal rstn_i_sync0 : std_ulogic;
signal rstn_i_sync1 : std_ulogic;
227,15 → 231,18
-- memory system - data/instruction fetch --
assert not ((MEM_EXT_USE = false) and (MEM_INT_DMEM_USE = false)) report "NEORV32 PROCESSOR CONFIG ERROR! Core cannot fetch data without external memory interface and internal data memory." severity error;
assert not ((MEM_EXT_USE = false) and (MEM_INT_IMEM_USE = false) and (BOOTLOADER_USE = false)) report "NEORV32 PROCESSOR CONFIG ERROR! Core cannot fetch instructions without external memory interface, internal data memory and bootloader." severity error;
-- memory system --
assert not (imem_base_c(1 downto 0) /= "00") report "NEORV32 PROCESSOR CONFIG ERROR! Instruction memory space base address must be 4-byte-aligned." severity error;
assert not (dmem_base_c(1 downto 0) /= "00") report "NEORV32 PROCESSOR CONFIG ERROR! Data memory space base address must be 4-byte-aligned." severity error;
-- memory system - alignment --
assert not (ispace_base_c(1 downto 0) /= "00") report "NEORV32 PROCESSOR CONFIG ERROR! Instruction memory space base address must be 4-byte-aligned." severity error;
assert not (dspace_base_c(1 downto 0) /= "00") report "NEORV32 PROCESSOR CONFIG ERROR! Data memory space base address must be 4-byte-aligned." severity error;
assert not ((ispace_base_c(index_size_f(MEM_INT_IMEM_SIZE)-1 downto 0) /= imem_align_check_c) and (MEM_INT_IMEM_USE = true)) report "NEORV32 PROCESSOR CONFIG ERROR! Instruction memory space base address has to be aligned to IMEM size." severity error;
assert not ((dspace_base_c(index_size_f(MEM_INT_DMEM_SIZE)-1 downto 0) /= dmem_align_check_c) and (MEM_INT_DMEM_USE = true)) report "NEORV32 PROCESSOR CONFIG ERROR! Data memory space base address has to be aligned to DMEM size." severity error;
-- memory system - max latency --
assert not (MEM_EXT_TIMEOUT < 1) report "NEORV32 PROCESSOR CONFIG ERROR! Invalid bus timeout. Processor-internal components have 1 cycle latency." severity error;
-- clock --
assert not (CLOCK_FREQUENCY = 0) report "NEORV32 PROCESSOR CONFIG ERROR! Core clock frequency (CLOCK_FREQUENCY) not specified." severity error;
-- memory layout notifier --
assert not (imem_base_c /= x"00000000") report "NEORV32 PROCESSOR CONFIG WARNING! Non-default base address for instruction address space. Make sure this is sync with the software framework." severity warning;
assert not (dmem_base_c /= x"80000000") report "NEORV32 PROCESSOR CONFIG WARNING! Non-default base address for data address space. Make sure this is sync with the software framework." severity warning;
assert not (ispace_base_c /= x"00000000") report "NEORV32 PROCESSOR CONFIG WARNING! Non-default base address for instruction address space. Make sure this is sync with the software framework." severity warning;
assert not (dspace_base_c /= x"80000000") report "NEORV32 PROCESSOR CONFIG WARNING! Non-default base address for data address space. Make sure this is sync with the software framework." severity warning;
 
 
-- Reset Generator ------------------------------------------------------------------------

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.