Line 61... |
Line 61... |
CPU_EXTENSION_RISCV_Zifencei : boolean := true; -- implement instruction stream sync.?
|
CPU_EXTENSION_RISCV_Zifencei : boolean := true; -- 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 inmplemnted HPM counters (0..29)
|
HPM_NUM_CNTS : natural := 0 -- number of implemented HPM counters (0..29)
|
);
|
);
|
port (
|
port (
|
-- global control --
|
-- global control --
|
clk_i : in std_ulogic; -- global clock, rising edge
|
clk_i : in std_ulogic; -- global clock, rising edge
|
rstn_i : in std_ulogic; -- global reset, low-active, async
|
rstn_i : in std_ulogic; -- global reset, low-active, async
|
Line 87... |
Line 87... |
-- interrupts (risc-v compliant) --
|
-- interrupts (risc-v compliant) --
|
msw_irq_i : in std_ulogic; -- machine software interrupt
|
msw_irq_i : in std_ulogic; -- machine software interrupt
|
mext_irq_i : in std_ulogic; -- machine external interrupt
|
mext_irq_i : in std_ulogic; -- machine external interrupt
|
mtime_irq_i : in std_ulogic; -- machine timer interrupt
|
mtime_irq_i : in std_ulogic; -- machine timer interrupt
|
-- fast interrupts (custom) --
|
-- fast interrupts (custom) --
|
firq_i : in std_ulogic_vector(3 downto 0);
|
firq_i : in std_ulogic_vector(7 downto 0);
|
|
firq_ack_o : out std_ulogic_vector(7 downto 0);
|
-- system time input from MTIME --
|
-- system time input from MTIME --
|
time_i : in std_ulogic_vector(63 downto 0); -- current system time
|
time_i : in std_ulogic_vector(63 downto 0); -- current system time
|
-- physical memory protection --
|
-- physical memory protection --
|
pmp_addr_o : out pmp_addr_if_t; -- addresses
|
pmp_addr_o : out pmp_addr_if_t; -- addresses
|
pmp_ctrl_o : out pmp_ctrl_if_t; -- configs
|
pmp_ctrl_o : out pmp_ctrl_if_t; -- configs
|
Line 211... |
Line 212... |
-- trap controller --
|
-- trap controller --
|
type trap_ctrl_t is record
|
type trap_ctrl_t is record
|
exc_buf : std_ulogic_vector(exception_width_c-1 downto 0);
|
exc_buf : std_ulogic_vector(exception_width_c-1 downto 0);
|
exc_fire : std_ulogic; -- set if there is a valid source in the exception buffer
|
exc_fire : std_ulogic; -- set if there is a valid source in the exception buffer
|
irq_buf : std_ulogic_vector(interrupt_width_c-1 downto 0);
|
irq_buf : std_ulogic_vector(interrupt_width_c-1 downto 0);
|
|
firq_sync : std_ulogic_vector(7 downto 0);
|
irq_fire : std_ulogic; -- set if there is a valid source in the interrupt buffer
|
irq_fire : std_ulogic; -- set if there is a valid source in the interrupt buffer
|
exc_ack : std_ulogic; -- acknowledge all exceptions
|
exc_ack : std_ulogic; -- acknowledge all exceptions
|
irq_ack : std_ulogic_vector(interrupt_width_c-1 downto 0); -- acknowledge specific interrupt
|
irq_ack : std_ulogic_vector(interrupt_width_c-1 downto 0); -- acknowledge specific interrupt
|
irq_ack_nxt : std_ulogic_vector(interrupt_width_c-1 downto 0);
|
irq_ack_nxt : std_ulogic_vector(interrupt_width_c-1 downto 0);
|
cause : std_ulogic_vector(5 downto 0); -- trap ID for mcause CSR
|
cause : std_ulogic_vector(5 downto 0); -- trap ID for mcause CSR
|
Line 273... |
Line 275... |
mstatus_mpp : std_ulogic_vector(1 downto 0); -- mstatus.MPP: machine previous privilege mode
|
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_msie : std_ulogic; -- mie.MSIE: machine software interrupt enable (R/W)
|
mie_meie : std_ulogic; -- mie.MEIE: machine external 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_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)
|
mie_firqe : std_ulogic_vector(7 downto 0); -- mie.firq*e: fast interrupt enabled (R/W)
|
--
|
--
|
mcounteren_cy : std_ulogic; -- mcounteren.cy: allow cycle[h] access from user-mode
|
mcounteren_cy : std_ulogic; -- mcounteren.cy: allow cycle[h] access from user-mode
|
mcounteren_tm : std_ulogic; -- mcounteren.tm: allow time[h] access from user-mode
|
mcounteren_tm : std_ulogic; -- mcounteren.tm: allow time[h] access from user-mode
|
mcounteren_ir : std_ulogic; -- mcounteren.ir: allow instret[h] access from user-mode
|
mcounteren_ir : std_ulogic; -- mcounteren.ir: allow instret[h] access from user-mode
|
mcounteren_hpm : std_ulogic_vector(HPM_NUM_CNTS-1 downto 0); -- mcounteren.hpmx: allow mhpmcounterx[h] access from user-mode
|
mcounteren_hpm : std_ulogic_vector(HPM_NUM_CNTS-1 downto 0); -- mcounteren.hpmx: allow mhpmcounterx[h] access from user-mode
|
Line 640... |
Line 642... |
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
branch_check: process(execute_engine.i_reg, cmp_i)
|
branch_check: process(execute_engine.i_reg, cmp_i)
|
begin
|
begin
|
case execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) is
|
case execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) is
|
when funct3_beq_c => -- branch if equal
|
when funct3_beq_c => -- branch if equal
|
execute_engine.branch_taken <= cmp_i(alu_cmp_equal_c);
|
execute_engine.branch_taken <= cmp_i(cmp_equal_c);
|
when funct3_bne_c => -- branch if not equal
|
when funct3_bne_c => -- branch if not equal
|
execute_engine.branch_taken <= not cmp_i(alu_cmp_equal_c);
|
execute_engine.branch_taken <= not cmp_i(cmp_equal_c);
|
when funct3_blt_c | funct3_bltu_c => -- branch if less (signed/unsigned)
|
when funct3_blt_c | funct3_bltu_c => -- branch if less (signed/unsigned)
|
execute_engine.branch_taken <= cmp_i(alu_cmp_less_c);
|
execute_engine.branch_taken <= cmp_i(cmp_less_c);
|
when funct3_bge_c | funct3_bgeu_c => -- branch if greater or equal (signed/unsigned)
|
when funct3_bge_c | funct3_bgeu_c => -- branch if greater or equal (signed/unsigned)
|
execute_engine.branch_taken <= not cmp_i(alu_cmp_less_c);
|
execute_engine.branch_taken <= not cmp_i(cmp_less_c);
|
when others => -- undefined
|
when others => -- undefined
|
execute_engine.branch_taken <= '0';
|
execute_engine.branch_taken <= '0';
|
end case;
|
end case;
|
end process branch_check;
|
end process branch_check;
|
|
|
Line 729... |
Line 731... |
ctrl_o(ctrl_rf_rs2_adr4_c downto ctrl_rf_rs2_adr0_c) <= execute_engine.i_reg(instr_rs2_msb_c downto instr_rs2_lsb_c);
|
ctrl_o(ctrl_rf_rs2_adr4_c downto ctrl_rf_rs2_adr0_c) <= execute_engine.i_reg(instr_rs2_msb_c downto instr_rs2_lsb_c);
|
ctrl_o(ctrl_rf_rd_adr4_c downto ctrl_rf_rd_adr0_c) <= execute_engine.i_reg(instr_rd_msb_c downto instr_rd_lsb_c);
|
ctrl_o(ctrl_rf_rd_adr4_c downto ctrl_rf_rd_adr0_c) <= execute_engine.i_reg(instr_rd_msb_c downto instr_rd_lsb_c);
|
-- fast bus access requests --
|
-- fast bus access requests --
|
ctrl_o(ctrl_bus_if_c) <= bus_fast_ir;
|
ctrl_o(ctrl_bus_if_c) <= bus_fast_ir;
|
-- bus error control --
|
-- bus error control --
|
ctrl_o(ctrl_bus_ierr_ack_c) <= fetch_engine.bus_err_ack;
|
ctrl_o(ctrl_bus_ierr_ack_c) <= fetch_engine.bus_err_ack; -- instruction fetch bus access error ACK
|
ctrl_o(ctrl_bus_derr_ack_c) <= trap_ctrl.env_start_ack;
|
ctrl_o(ctrl_bus_derr_ack_c) <= trap_ctrl.env_start_ack; -- data access bus error access ACK
|
|
-- memory access size / sign --
|
|
ctrl_o(ctrl_bus_unsigned_c) <= execute_engine.i_reg(instr_funct3_msb_c); -- unsigned LOAD (LBU, LHU)
|
|
ctrl_o(ctrl_bus_size_msb_c downto ctrl_bus_size_lsb_c) <= execute_engine.i_reg(instr_funct3_lsb_c+1 downto instr_funct3_lsb_c); -- mem transfer size
|
|
-- alu.shifter --
|
|
ctrl_o(ctrl_alu_shift_dir_c) <= execute_engine.i_reg(instr_funct3_msb_c); -- shift direction (left/right)
|
|
ctrl_o(ctrl_alu_shift_ar_c) <= execute_engine.i_reg(30); -- is arithmetic shift
|
-- instruction's function blocks (for co-processors) --
|
-- instruction's function blocks (for co-processors) --
|
ctrl_o(ctrl_ir_opcode7_6_c downto ctrl_ir_opcode7_0_c) <= execute_engine.i_reg(instr_opcode_msb_c downto instr_opcode_lsb_c);
|
ctrl_o(ctrl_ir_opcode7_6_c downto ctrl_ir_opcode7_0_c) <= execute_engine.i_reg(instr_opcode_msb_c downto instr_opcode_lsb_c);
|
ctrl_o(ctrl_ir_funct12_11_c downto ctrl_ir_funct12_0_c) <= execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c);
|
ctrl_o(ctrl_ir_funct12_11_c downto ctrl_ir_funct12_0_c) <= execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c);
|
ctrl_o(ctrl_ir_funct3_2_c downto ctrl_ir_funct3_0_c) <= execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c);
|
ctrl_o(ctrl_ir_funct3_2_c downto ctrl_ir_funct3_0_c) <= execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c);
|
-- locked bus operation (for atomica memory operations) --
|
-- locked bus operation (for atomic memory operations) --
|
ctrl_o(ctrl_bus_lock_c) <= atomic_ctrl.lock; -- (bus) lock status
|
ctrl_o(ctrl_bus_lock_c) <= atomic_ctrl.lock; -- (bus) lock status
|
|
-- cpu status --
|
|
ctrl_o(ctrl_sleep_c) <= execute_engine.sleep; -- cpu is in sleep mode
|
end process ctrl_output;
|
end process ctrl_output;
|
|
|
|
|
-- Decoding Helper Logic ------------------------------------------------------------------
|
-- Decoding Helper Logic ------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
Line 839... |
Line 849... |
atomic_ctrl.env_end <= '0';
|
atomic_ctrl.env_end <= '0';
|
atomic_ctrl.env_abort <= '0';
|
atomic_ctrl.env_abort <= '0';
|
|
|
-- CONTROL DEFAULTS --
|
-- CONTROL DEFAULTS --
|
ctrl_nxt <= (others => '0'); -- default: all off
|
ctrl_nxt <= (others => '0'); -- default: all off
|
|
-- ALU main control --
|
|
ctrl_nxt(ctrl_alu_addsub_c) <= '0'; -- ADD(I)
|
|
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_arith_c; -- default ALU function select: arithmetic
|
|
ctrl_nxt(ctrl_alu_arith_c) <= alu_arith_cmd_addsub_c; -- default ALU arithmetic operation: ADDSUB
|
|
-- ALU sign control --
|
if (execute_engine.i_reg(instr_opcode_lsb_c+4) = '1') then -- ALU ops
|
if (execute_engine.i_reg(instr_opcode_lsb_c+4) = '1') then -- ALU ops
|
ctrl_nxt(ctrl_alu_unsigned_c) <= execute_engine.i_reg(instr_funct3_lsb_c+0); -- unsigned ALU operation? (SLTIU, SLTU)
|
ctrl_nxt(ctrl_alu_unsigned_c) <= execute_engine.i_reg(instr_funct3_lsb_c+0); -- unsigned ALU operation? (SLTIU, SLTU)
|
else -- branches
|
else -- branches
|
ctrl_nxt(ctrl_alu_unsigned_c) <= execute_engine.i_reg(instr_funct3_lsb_c+1); -- unsigned branches? (BLTU, BGEU)
|
ctrl_nxt(ctrl_alu_unsigned_c) <= execute_engine.i_reg(instr_funct3_lsb_c+1); -- unsigned branches? (BLTU, BGEU)
|
end if;
|
end if;
|
-- memory access --
|
|
ctrl_nxt(ctrl_bus_unsigned_c) <= execute_engine.i_reg(instr_funct3_msb_c); -- unsigned LOAD (LBU, LHU)
|
|
ctrl_nxt(ctrl_bus_size_msb_c downto ctrl_bus_size_lsb_c) <= execute_engine.i_reg(instr_funct3_lsb_c+1 downto instr_funct3_lsb_c); -- mem transfer size
|
|
-- alu.shifter --
|
|
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
|
|
-- ALU main control --
|
|
ctrl_nxt(ctrl_alu_addsub_c) <= '0'; -- ADD(I)
|
|
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_arith_c; -- default ALU function select: arithmetic
|
|
ctrl_nxt(ctrl_alu_arith_c) <= alu_arith_cmd_addsub_c; -- default ALU arithmetic operation: ADDSUB
|
|
|
|
|
|
-- state machine --
|
-- state machine --
|
case execute_engine.state is
|
case execute_engine.state is
|
|
|
Line 1125... |
Line 1130... |
|
|
|
|
when FENCE_OP => -- fence operations - execution
|
when FENCE_OP => -- fence operations - execution
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
execute_engine.state_nxt <= SYS_WAIT;
|
execute_engine.state_nxt <= SYS_WAIT;
|
execute_engine.pc_mux_sel <= "01"; -- linear next PC = "refetch" next instruction (only relevant for fence.i)
|
|
-- FENCE.I --
|
-- FENCE.I --
|
if (CPU_EXTENSION_RISCV_Zifencei = true) and (execute_engine.i_reg(instr_funct3_lsb_c) = funct3_fencei_c(0)) 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)
|
|
if (execute_engine.i_reg(instr_funct3_lsb_c) = funct3_fencei_c(0)) then
|
execute_engine.pc_we <= '1';
|
execute_engine.pc_we <= '1';
|
execute_engine.if_rst_nxt <= '1'; -- this is a non-linear PC modification
|
execute_engine.if_rst_nxt <= '1'; -- this is a non-linear PC modification
|
fetch_engine.reset <= '1';
|
fetch_engine.reset <= '1';
|
ctrl_nxt(ctrl_bus_fencei_c) <= '1';
|
ctrl_nxt(ctrl_bus_fencei_c) <= '1';
|
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
|
ctrl_nxt(ctrl_bus_fence_c) <= '1';
|
ctrl_nxt(ctrl_bus_fence_c) <= '1';
|
end if;
|
end if;
|
|
|
Line 1572... |
Line 1579... |
if (rstn_i = '0') then
|
if (rstn_i = '0') then
|
trap_ctrl.exc_buf <= (others => '0');
|
trap_ctrl.exc_buf <= (others => '0');
|
trap_ctrl.irq_buf <= (others => '0');
|
trap_ctrl.irq_buf <= (others => '0');
|
trap_ctrl.exc_ack <= '0';
|
trap_ctrl.exc_ack <= '0';
|
trap_ctrl.irq_ack <= (others => '0');
|
trap_ctrl.irq_ack <= (others => '0');
|
trap_ctrl.cause <= trap_reset_c;
|
|
trap_ctrl.env_start <= '0';
|
trap_ctrl.env_start <= '0';
|
|
trap_ctrl.cause <= trap_reset_c;
|
|
trap_ctrl.firq_sync <= (others => '0');
|
elsif rising_edge(clk_i) then
|
elsif rising_edge(clk_i) then
|
if (CPU_EXTENSION_RISCV_Zicsr = true) then
|
if (CPU_EXTENSION_RISCV_Zicsr = true) then
|
-- exception buffer: misaligned load/store/instruction address
|
-- exception buffer: misaligned load/store/instruction address
|
trap_ctrl.exc_buf(exception_lalign_c) <= (trap_ctrl.exc_buf(exception_lalign_c) or ma_load_i) and (not trap_ctrl.exc_ack);
|
trap_ctrl.exc_buf(exception_lalign_c) <= (trap_ctrl.exc_buf(exception_lalign_c) or ma_load_i) and (not trap_ctrl.exc_ack);
|
trap_ctrl.exc_buf(exception_salign_c) <= (trap_ctrl.exc_buf(exception_salign_c) or ma_store_i) and (not trap_ctrl.exc_ack);
|
trap_ctrl.exc_buf(exception_salign_c) <= (trap_ctrl.exc_buf(exception_salign_c) or ma_store_i) and (not trap_ctrl.exc_ack);
|
Line 1594... |
Line 1602... |
-- interrupt buffer: machine software/external/timer interrupt
|
-- interrupt buffer: machine software/external/timer interrupt
|
trap_ctrl.irq_buf(interrupt_msw_irq_c) <= csr.mie_msie and (trap_ctrl.irq_buf(interrupt_msw_irq_c) or msw_irq_i) and (not (trap_ctrl.irq_ack(interrupt_msw_irq_c) or csr.mip_clear(interrupt_msw_irq_c)));
|
trap_ctrl.irq_buf(interrupt_msw_irq_c) <= csr.mie_msie and (trap_ctrl.irq_buf(interrupt_msw_irq_c) or msw_irq_i) and (not (trap_ctrl.irq_ack(interrupt_msw_irq_c) or csr.mip_clear(interrupt_msw_irq_c)));
|
trap_ctrl.irq_buf(interrupt_mext_irq_c) <= csr.mie_meie and (trap_ctrl.irq_buf(interrupt_mext_irq_c) or mext_irq_i) and (not (trap_ctrl.irq_ack(interrupt_mext_irq_c) or csr.mip_clear(interrupt_mext_irq_c)));
|
trap_ctrl.irq_buf(interrupt_mext_irq_c) <= csr.mie_meie and (trap_ctrl.irq_buf(interrupt_mext_irq_c) or mext_irq_i) and (not (trap_ctrl.irq_ack(interrupt_mext_irq_c) or csr.mip_clear(interrupt_mext_irq_c)));
|
trap_ctrl.irq_buf(interrupt_mtime_irq_c) <= csr.mie_mtie and (trap_ctrl.irq_buf(interrupt_mtime_irq_c) or mtime_irq_i) and (not (trap_ctrl.irq_ack(interrupt_mtime_irq_c) or csr.mip_clear(interrupt_mtime_irq_c)));
|
trap_ctrl.irq_buf(interrupt_mtime_irq_c) <= csr.mie_mtie and (trap_ctrl.irq_buf(interrupt_mtime_irq_c) or mtime_irq_i) and (not (trap_ctrl.irq_ack(interrupt_mtime_irq_c) or csr.mip_clear(interrupt_mtime_irq_c)));
|
-- interrupt buffer: custom fast interrupts
|
-- interrupt buffer: custom fast interrupts
|
trap_ctrl.irq_buf(interrupt_firq_0_c) <= csr.mie_firqe(0) and (trap_ctrl.irq_buf(interrupt_firq_0_c) or firq_i(0)) and (not (trap_ctrl.irq_ack(interrupt_firq_0_c) or csr.mip_clear(interrupt_firq_0_c)));
|
trap_ctrl.firq_sync <= firq_i;
|
trap_ctrl.irq_buf(interrupt_firq_1_c) <= csr.mie_firqe(1) and (trap_ctrl.irq_buf(interrupt_firq_1_c) or firq_i(1)) and (not (trap_ctrl.irq_ack(interrupt_firq_1_c) or csr.mip_clear(interrupt_firq_1_c)));
|
--
|
trap_ctrl.irq_buf(interrupt_firq_2_c) <= csr.mie_firqe(2) and (trap_ctrl.irq_buf(interrupt_firq_2_c) or firq_i(2)) and (not (trap_ctrl.irq_ack(interrupt_firq_2_c) or csr.mip_clear(interrupt_firq_2_c)));
|
trap_ctrl.irq_buf(interrupt_firq_0_c) <= csr.mie_firqe(0) and (trap_ctrl.irq_buf(interrupt_firq_0_c) or trap_ctrl.firq_sync(0)) and (not (trap_ctrl.irq_ack(interrupt_firq_0_c) or csr.mip_clear(interrupt_firq_0_c)));
|
trap_ctrl.irq_buf(interrupt_firq_3_c) <= csr.mie_firqe(3) and (trap_ctrl.irq_buf(interrupt_firq_3_c) or firq_i(3)) and (not (trap_ctrl.irq_ack(interrupt_firq_3_c) or csr.mip_clear(interrupt_firq_3_c)));
|
trap_ctrl.irq_buf(interrupt_firq_1_c) <= csr.mie_firqe(1) and (trap_ctrl.irq_buf(interrupt_firq_1_c) or trap_ctrl.firq_sync(1)) and (not (trap_ctrl.irq_ack(interrupt_firq_1_c) or csr.mip_clear(interrupt_firq_1_c)));
|
|
trap_ctrl.irq_buf(interrupt_firq_2_c) <= csr.mie_firqe(2) and (trap_ctrl.irq_buf(interrupt_firq_2_c) or trap_ctrl.firq_sync(2)) and (not (trap_ctrl.irq_ack(interrupt_firq_2_c) or csr.mip_clear(interrupt_firq_2_c)));
|
|
trap_ctrl.irq_buf(interrupt_firq_3_c) <= csr.mie_firqe(3) and (trap_ctrl.irq_buf(interrupt_firq_3_c) or trap_ctrl.firq_sync(3)) and (not (trap_ctrl.irq_ack(interrupt_firq_3_c) or csr.mip_clear(interrupt_firq_3_c)));
|
|
trap_ctrl.irq_buf(interrupt_firq_4_c) <= csr.mie_firqe(4) and (trap_ctrl.irq_buf(interrupt_firq_4_c) or trap_ctrl.firq_sync(4)) and (not (trap_ctrl.irq_ack(interrupt_firq_4_c) or csr.mip_clear(interrupt_firq_4_c)));
|
|
trap_ctrl.irq_buf(interrupt_firq_5_c) <= csr.mie_firqe(5) and (trap_ctrl.irq_buf(interrupt_firq_5_c) or trap_ctrl.firq_sync(5)) and (not (trap_ctrl.irq_ack(interrupt_firq_5_c) or csr.mip_clear(interrupt_firq_5_c)));
|
|
trap_ctrl.irq_buf(interrupt_firq_6_c) <= csr.mie_firqe(6) and (trap_ctrl.irq_buf(interrupt_firq_6_c) or trap_ctrl.firq_sync(6)) and (not (trap_ctrl.irq_ack(interrupt_firq_6_c) or csr.mip_clear(interrupt_firq_6_c)));
|
|
trap_ctrl.irq_buf(interrupt_firq_7_c) <= csr.mie_firqe(7) and (trap_ctrl.irq_buf(interrupt_firq_7_c) or trap_ctrl.firq_sync(7)) and (not (trap_ctrl.irq_ack(interrupt_firq_7_c) or csr.mip_clear(interrupt_firq_7_c)));
|
-- 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 -- exception/IRQ detected!
|
((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))) then -- sample IRQs in EXECUTE or TRAP state only to continue execution even if 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)
|
Line 1625... |
Line 1639... |
trap_ctrl.irq_fire <= or_all_f(trap_ctrl.irq_buf) and csr.mstatus_mie; -- interrupts CAN be masked
|
trap_ctrl.irq_fire <= or_all_f(trap_ctrl.irq_buf) and csr.mstatus_mie; -- interrupts CAN be masked
|
|
|
-- current pending interrupts (for CSR.MIP register) --
|
-- current pending interrupts (for CSR.MIP register) --
|
csr.mip_status <= trap_ctrl.irq_buf;
|
csr.mip_status <= trap_ctrl.irq_buf;
|
|
|
|
-- acknowledge mask output --
|
|
firq_ack_o <= trap_ctrl.irq_ack(interrupt_firq_7_c downto interrupt_firq_0_c);
|
|
|
|
|
-- Trap Priority Encoder ------------------------------------------------------------------
|
-- Trap Priority Encoder ------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
trap_priority: process(trap_ctrl)
|
trap_priority: process(trap_ctrl)
|
begin
|
begin
|
Line 1673... |
Line 1690... |
-- interrupt: 1.19 fast interrupt channel 3 --
|
-- interrupt: 1.19 fast interrupt channel 3 --
|
elsif (trap_ctrl.irq_buf(interrupt_firq_3_c) = '1') then
|
elsif (trap_ctrl.irq_buf(interrupt_firq_3_c) = '1') then
|
trap_ctrl.cause_nxt <= trap_firq3_c;
|
trap_ctrl.cause_nxt <= trap_firq3_c;
|
trap_ctrl.irq_ack_nxt(interrupt_firq_3_c) <= '1';
|
trap_ctrl.irq_ack_nxt(interrupt_firq_3_c) <= '1';
|
|
|
|
-- interrupt: 1.20 fast interrupt channel 4 --
|
|
elsif (trap_ctrl.irq_buf(interrupt_firq_4_c) = '1') then
|
|
trap_ctrl.cause_nxt <= trap_firq4_c;
|
|
trap_ctrl.irq_ack_nxt(interrupt_firq_4_c) <= '1';
|
|
|
|
-- interrupt: 1.21 fast interrupt channel 5 --
|
|
elsif (trap_ctrl.irq_buf(interrupt_firq_5_c) = '1') then
|
|
trap_ctrl.cause_nxt <= trap_firq5_c;
|
|
trap_ctrl.irq_ack_nxt(interrupt_firq_5_c) <= '1';
|
|
|
|
-- interrupt: 1.22 fast interrupt channel 6 --
|
|
elsif (trap_ctrl.irq_buf(interrupt_firq_6_c) = '1') then
|
|
trap_ctrl.cause_nxt <= trap_firq6_c;
|
|
trap_ctrl.irq_ack_nxt(interrupt_firq_6_c) <= '1';
|
|
|
|
-- interrupt: 1.23 fast interrupt channel 7 --
|
|
elsif (trap_ctrl.irq_buf(interrupt_firq_7_c) = '1') then
|
|
trap_ctrl.cause_nxt <= trap_firq7_c;
|
|
trap_ctrl.irq_ack_nxt(interrupt_firq_7_c) <= '1';
|
|
|
|
|
-- the following traps are caused by *synchronous* exceptions (= 'classic' exceptions)
|
-- the following traps are caused by *synchronous* exceptions (= 'classic' exceptions)
|
-- here we do not need a specific acknowledge mask since only one exception (the one
|
-- here we do not need a specific acknowledge mask since only one exception (the one
|
-- with highest priority) is evaluated at once
|
-- with highest priority) is evaluated at once
|
|
|
Line 1852... |
Line 1889... |
--
|
--
|
csr.mie_firqe(0) <= csr.wdata(16); -- fast interrupt channel 0
|
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(1) <= csr.wdata(17); -- fast interrupt channel 1
|
csr.mie_firqe(2) <= csr.wdata(18); -- fast interrupt channel 2
|
csr.mie_firqe(2) <= csr.wdata(18); -- fast interrupt channel 2
|
csr.mie_firqe(3) <= csr.wdata(19); -- fast interrupt channel 3
|
csr.mie_firqe(3) <= csr.wdata(19); -- fast interrupt channel 3
|
|
csr.mie_firqe(4) <= csr.wdata(20); -- fast interrupt channel 4
|
|
csr.mie_firqe(5) <= csr.wdata(21); -- fast interrupt channel 5
|
|
csr.mie_firqe(6) <= csr.wdata(22); -- fast interrupt channel 6
|
|
csr.mie_firqe(7) <= csr.wdata(22); -- fast interrupt channel 7
|
when csr_mtvec_c => -- 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.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]
|
Line 1881... |
Line 1922... |
--
|
--
|
csr.mip_clear(interrupt_firq_0_c) <= not csr.wdata(16);
|
csr.mip_clear(interrupt_firq_0_c) <= not csr.wdata(16);
|
csr.mip_clear(interrupt_firq_1_c) <= not csr.wdata(17);
|
csr.mip_clear(interrupt_firq_1_c) <= not csr.wdata(17);
|
csr.mip_clear(interrupt_firq_2_c) <= not csr.wdata(18);
|
csr.mip_clear(interrupt_firq_2_c) <= not csr.wdata(18);
|
csr.mip_clear(interrupt_firq_3_c) <= not csr.wdata(19);
|
csr.mip_clear(interrupt_firq_3_c) <= not csr.wdata(19);
|
|
csr.mip_clear(interrupt_firq_4_c) <= not csr.wdata(20);
|
|
csr.mip_clear(interrupt_firq_5_c) <= not csr.wdata(21);
|
|
csr.mip_clear(interrupt_firq_6_c) <= not csr.wdata(22);
|
|
csr.mip_clear(interrupt_firq_7_c) <= not csr.wdata(23);
|
|
|
-- 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 =>
|
Line 1936... |
Line 1981... |
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
|
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"
|
end if;
|
end if;
|
end loop; -- i (CSRs)
|
end loop; -- i (CSRs)
|
|
|
-- undefined --
|
-- undefined --
|
-- --------------------------------------------------------------------
|
-- --------------------------------------------------------------------
|
Line 1974... |
Line 2020... |
csr.mtval <= execute_engine.last_pc(data_width_c-1 downto 1) & '0'; -- address of breakpoint instruction
|
csr.mtval <= execute_engine.last_pc(data_width_c-1 downto 1) & '0'; -- address of breakpoint instruction
|
when trap_lma_c | trap_lbe_c | trap_sma_c | trap_sbe_c => -- misaligned load/store address OR load/store access error
|
when trap_lma_c | trap_lbe_c | trap_sma_c | trap_sbe_c => -- misaligned load/store address OR load/store access error
|
csr.mtval <= mar_i; -- faulting data access address
|
csr.mtval <= mar_i; -- faulting data access address
|
when trap_iil_c => -- illegal instruction
|
when trap_iil_c => -- illegal instruction
|
csr.mtval <= execute_engine.i_reg_last; -- faulting instruction itself
|
csr.mtval <= execute_engine.i_reg_last; -- faulting instruction itself
|
when others => -- everything else including interrupts
|
when others => -- everything else including all interrupts
|
csr.mtval <= (others => '0');
|
csr.mtval <= (others => '0');
|
end case;
|
end case;
|
end if;
|
end if;
|
|
|
-- mstatus: context switch --
|
-- mstatus: context switch --
|
Line 2119... |
Line 2165... |
-- (HPM) Counter Event Control ------------------------------------------------------------
|
-- (HPM) Counter Event Control ------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
hpmcnt_ctrl: process(clk_i)
|
hpmcnt_ctrl: process(clk_i)
|
begin
|
begin
|
if rising_edge(clk_i) then
|
if rising_edge(clk_i) then
|
|
-- buffer event sources --
|
cnt_event <= cnt_event_nxt;
|
cnt_event <= cnt_event_nxt;
|
|
-- enable selected triggers by ANDing actual events and according CSR configuration bits --
|
|
-- OR everything to see if counter should increment --
|
hpmcnt_trigger <= (others => '0'); -- default
|
hpmcnt_trigger <= (others => '0'); -- default
|
for i in 0 to HPM_NUM_CNTS-1 loop
|
for i in 0 to HPM_NUM_CNTS-1 loop
|
-- enable selected triggers by ANDing events and configuration bits --
|
hpmcnt_trigger(i) <= or_all_f(cnt_event and csr.mhpmevent(i)(cnt_event'left downto 0));
|
-- OR everything to see if counter should increment --
|
|
-- AND with inverted sleep flag to increment only when CPU is awake --
|
|
hpmcnt_trigger(i) <= (or_all_f(cnt_event and csr.mhpmevent(i)(cnt_event'left downto 0))) and (not execute_engine.sleep);
|
|
end loop; -- i
|
end loop; -- i
|
end if;
|
end if;
|
end process hpmcnt_ctrl;
|
end process hpmcnt_ctrl;
|
|
|
-- counter event trigger - RISC-V specific --
|
-- counter event trigger - RISC-V specific --
|
Line 2192... |
Line 2238... |
--
|
--
|
csr.rdata(16) <= csr.mie_firqe(0); -- fast interrupt channel 0
|
csr.rdata(16) <= csr.mie_firqe(0); -- fast interrupt channel 0
|
csr.rdata(17) <= csr.mie_firqe(1); -- fast interrupt channel 1
|
csr.rdata(17) <= csr.mie_firqe(1); -- fast interrupt channel 1
|
csr.rdata(18) <= csr.mie_firqe(2); -- fast interrupt channel 2
|
csr.rdata(18) <= csr.mie_firqe(2); -- fast interrupt channel 2
|
csr.rdata(19) <= csr.mie_firqe(3); -- fast interrupt channel 3
|
csr.rdata(19) <= csr.mie_firqe(3); -- fast interrupt channel 3
|
|
csr.rdata(20) <= csr.mie_firqe(4); -- fast interrupt channel 4
|
|
csr.rdata(21) <= csr.mie_firqe(5); -- fast interrupt channel 5
|
|
csr.rdata(22) <= csr.mie_firqe(6); -- fast interrupt channel 6
|
|
csr.rdata(23) <= csr.mie_firqe(7); -- fast interrupt channel 7
|
when csr_mtvec_c => -- 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
|
csr.rdata <= csr.mtvec(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.rdata(0) <= csr.mcounteren_cy; -- enable user-level access to cycle[h]
|
csr.rdata(0) <= csr.mcounteren_cy; -- enable user-level access to cycle[h]
|
csr.rdata(1) <= csr.mcounteren_tm; -- enable user-level access to time[h]
|
csr.rdata(1) <= csr.mcounteren_tm; -- enable user-level access to time[h]
|
Line 2218... |
Line 2268... |
--
|
--
|
csr.rdata(16) <= csr.mip_status(interrupt_firq_0_c);
|
csr.rdata(16) <= csr.mip_status(interrupt_firq_0_c);
|
csr.rdata(17) <= csr.mip_status(interrupt_firq_1_c);
|
csr.rdata(17) <= csr.mip_status(interrupt_firq_1_c);
|
csr.rdata(18) <= csr.mip_status(interrupt_firq_2_c);
|
csr.rdata(18) <= csr.mip_status(interrupt_firq_2_c);
|
csr.rdata(19) <= csr.mip_status(interrupt_firq_3_c);
|
csr.rdata(19) <= csr.mip_status(interrupt_firq_3_c);
|
|
csr.rdata(20) <= csr.mip_status(interrupt_firq_4_c);
|
|
csr.rdata(21) <= csr.mip_status(interrupt_firq_5_c);
|
|
csr.rdata(22) <= csr.mip_status(interrupt_firq_6_c);
|
|
csr.rdata(23) <= csr.mip_status(interrupt_firq_7_c);
|
|
|
-- physical memory protection - configuration --
|
-- physical memory protection - configuration --
|
when csr_pmpcfg0_c => csr.rdata <= csr.pmpcfg_rd(03) & csr.pmpcfg_rd(02) & csr.pmpcfg_rd(01) & csr.pmpcfg_rd(00); -- R/W: pmpcfg0
|
when csr_pmpcfg0_c => csr.rdata <= csr.pmpcfg_rd(03) & csr.pmpcfg_rd(02) & csr.pmpcfg_rd(01) & csr.pmpcfg_rd(00); -- R/W: pmpcfg0
|
when csr_pmpcfg1_c => csr.rdata <= csr.pmpcfg_rd(07) & csr.pmpcfg_rd(06) & csr.pmpcfg_rd(05) & csr.pmpcfg_rd(04); -- R/W: pmpcfg1
|
when csr_pmpcfg1_c => csr.rdata <= csr.pmpcfg_rd(07) & csr.pmpcfg_rd(06) & csr.pmpcfg_rd(05) & csr.pmpcfg_rd(04); -- R/W: pmpcfg1
|
when csr_pmpcfg2_c => csr.rdata <= csr.pmpcfg_rd(11) & csr.pmpcfg_rd(10) & csr.pmpcfg_rd(09) & csr.pmpcfg_rd(08); -- R/W: pmpcfg2
|
when csr_pmpcfg2_c => csr.rdata <= csr.pmpcfg_rd(11) & csr.pmpcfg_rd(10) & csr.pmpcfg_rd(09) & csr.pmpcfg_rd(08); -- R/W: pmpcfg2
|