mirror of
https://github.com/lowRISC/ibex.git
synced 2025-04-20 03:47:15 -04:00
[RTL] - Add PMP module
- Instantiate generic PMP module - Wire up I-side and D-side PMP faults - The output of the PMP check is used to gate external bus requests from the I-side and LSU - Each of those units progresses with their request as-if it was granted externally and registers the PMP error - The error is then sent to the controller at the appropriate time to trigger an exception
This commit is contained in:
parent
6ecf83124a
commit
892ad8a621
15 changed files with 574 additions and 23 deletions
|
@ -34,6 +34,18 @@ Ibex implements all the Control and Status Registers (CSRs) listed in the follow
|
|||
+---------+--------------------+--------+-----------------------------------------------+
|
||||
| 0x344 | ``mip`` | R | Machine Interrupt Pending Register |
|
||||
+---------+--------------------+--------+-----------------------------------------------+
|
||||
| 0x3A0 | ``pmpcfg0`` | WARL | PMP Configuration Register |
|
||||
+---------+--------------------+--------+-----------------------------------------------+
|
||||
| . . . . |
|
||||
+---------+--------------------+--------+-----------------------------------------------+
|
||||
| 0x3A3 | ``pmpcfg3`` | WARL | PMP Configuration Register |
|
||||
+---------+--------------------+--------+-----------------------------------------------+
|
||||
| 0x3B0 | ``pmpaddr0`` | WARL | PMP Address Register |
|
||||
+---------+--------------------+--------+-----------------------------------------------+
|
||||
| . . . . |
|
||||
+---------+--------------------+--------+-----------------------------------------------+
|
||||
| 0x3BF | ``pmpaddr15`` | WARL | PMP Address Register |
|
||||
+---------+--------------------+--------+-----------------------------------------------+
|
||||
| 0x7B0 | ``dcsr`` | RW | Debug Control and Status Register |
|
||||
+---------+--------------------+--------+-----------------------------------------------+
|
||||
| 0x7B1 | ``dpc`` | RW | Debug PC |
|
||||
|
@ -212,6 +224,57 @@ A particular bit in the register reads as one if the corresponding interrupt inp
|
|||
| 3 | **Machine Software Interrupt Pending (MSIP):** if set, ``irq_software_i`` is pending. |
|
||||
+-------+---------------------------------------------------------------------------------------+
|
||||
|
||||
PMP Configuration Register (pmpcfgx)
|
||||
----------------------------------------
|
||||
|
||||
CSR Address: ``0x3A0 - 0x3A3``
|
||||
|
||||
Reset Value: ``0x0000_0000``
|
||||
|
||||
``pmpcfgx`` are registers to configure PMP regions. Each register configures 4 PMP regions.
|
||||
|
||||
+---------------------------------------+
|
||||
| 31:24 | 23:16 | 15:8 | 7:0 |
|
||||
+---------------------------------------+
|
||||
| pmp3cfg | pmp2cfg | pmp1cfg | pmp0cfg |
|
||||
+---------------------------------------+
|
||||
|
||||
The configuration fields for each region are as follows:
|
||||
|
||||
+-------+--------------------------+
|
||||
| Bit# | Definition |
|
||||
+-------+--------------------------+
|
||||
| 7 | Lock |
|
||||
+-------+--------------------------+
|
||||
| 6:5 | Reserved (Read as zero) |
|
||||
+-------+--------------------------+
|
||||
| 4:3 | Mode |
|
||||
+-------+--------------------------+
|
||||
| 2 | Execute permission |
|
||||
+-------+--------------------------+
|
||||
| 1 | Write permission |
|
||||
+-------+--------------------------+
|
||||
| 0 | Read permission |
|
||||
+-------+--------------------------+
|
||||
|
||||
Details of these configuration bits can be found in the RISC-V Privileged Specification, version 1.11 (see Physical Memory Protection CSRs, Section 3.6.1).
|
||||
|
||||
Note that the combination of Write permission = 1, Read permission = 0 is reserved, and will be treated by the core as Read/Write permission = 0.
|
||||
|
||||
PMP Address Register (pmpaddrx)
|
||||
----------------------------------------
|
||||
|
||||
CSR Address: ``0x3B0 - 0x3BF``
|
||||
|
||||
Reset Value: ``0x0000_0000``
|
||||
|
||||
``pmpaddrx`` are registers to set address matching for PMP regions.
|
||||
|
||||
+----------------+
|
||||
| 31:0 |
|
||||
+----------------+
|
||||
| address[33:2] |
|
||||
+----------------+
|
||||
|
||||
.. _csr-mhartid:
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ Ibex User Manual
|
|||
cs_registers
|
||||
performance_counters
|
||||
exception_interrupts
|
||||
pmp
|
||||
debug
|
||||
tracer
|
||||
rvfi
|
||||
|
|
|
@ -12,6 +12,9 @@ Instantiation Template
|
|||
.. code-block:: verilog
|
||||
|
||||
ibex_core #(
|
||||
.PMPEnable (0),
|
||||
.PMPGranularity (0),
|
||||
.PMPNumRegions (4),
|
||||
.MHPMCounterNum (0),
|
||||
.MHPMCounterWidth (40),
|
||||
.RV32E (0),
|
||||
|
@ -68,6 +71,12 @@ Parameters
|
|||
+-----------------------+-------------+------------+-----------------------------------------------------------------+
|
||||
| Name | Type/Range | Default | Description |
|
||||
+=======================+=============+============+=================================================================+
|
||||
| ``PMPEnable`` | bit | 0 | Enable PMP support |
|
||||
+-----------------------+-------------+------------+-----------------------------------------------------------------+
|
||||
| ``PMPGranularity`` | int (0..31) | 0 | Minimum granularity of PMP address matching |
|
||||
+-----------------------+-------------+------------+-----------------------------------------------------------------+
|
||||
| ``PMPNumRegions`` | int (1..16) | 4 | Number implemented PMP regions (ignored if PMPEnable == 0) |
|
||||
+-----------------------+-------------+------------+-----------------------------------------------------------------+
|
||||
| ``MHPMCounterNum`` | int (0..8) | 0 | Number of performance monitor event counters |
|
||||
+-----------------------+-------------+------------+-----------------------------------------------------------------+
|
||||
| ``MHPMCounterWidth`` | int (64..1) | 40 | Bit width of performance monitor event counters |
|
||||
|
|
|
@ -82,6 +82,7 @@ The two register-file flavors are described in :ref:`register-file`.
|
|||
The control and status registers are explained in :ref:`cs-registers`.
|
||||
:ref:`performance-counters` gives an overview of the performance monitors and event counters available in Ibex.
|
||||
:ref:`exceptions-interrupts` deals with the infrastructure for handling exceptions and interrupts,
|
||||
:ref:`pmp` gives a brief overview of PMP support.
|
||||
:ref:`debug-support` gives a brief overview on the debug infrastructure.
|
||||
:ref:`tracer` gives a brief overview of the tracer module.
|
||||
For information regarding formal verification support, check out :ref:`rvfi`.
|
||||
|
|
33
doc/pmp.rst
Normal file
33
doc/pmp.rst
Normal file
|
@ -0,0 +1,33 @@
|
|||
.. _pmp:
|
||||
|
||||
Physical Memory Protection (PMP)
|
||||
================================
|
||||
|
||||
The Physical Memory Protection (PMP) unit implements region-based memory access checking in-accordance with the RISC-V Privileged Specification, version 1.11.
|
||||
The following configuration parameters are available to control PMP checking:
|
||||
|
||||
+----------------+---------------+-------------------------------------------------+
|
||||
| Parameter | Default value | Description |
|
||||
+================+===============+=================================================+
|
||||
| PMPEnable | 0 | PMP support enabled |
|
||||
+----------------+---------------+-------------------------------------------------+
|
||||
| PMPNumRegions | 4 | Number of implemented regions (1 - 16) |
|
||||
+----------------+---------------+-------------------------------------------------+
|
||||
| PMPGranularity | 0 | Minimum match granularity 2^G\+2 bytes (0 - 31) |
|
||||
+----------------+---------------+-------------------------------------------------+
|
||||
|
||||
When PMPEnable is zero, the PMP module is not instantiated and all PMP registers read as zero (regardless of the value of PMPNumRegions)
|
||||
|
||||
PMP Integration
|
||||
---------------
|
||||
|
||||
Addresses from the instruction fetch unit and load-store unit are passed to the PMP module for checking, and the output of the PMP check is used to gate the external request.
|
||||
To maintain consistency with external errors, the instruction fetch unit and load-store unit progress with their request as if it was granted externally.
|
||||
The PMP error is registered and consumed by the core when the data would have been consumed.
|
||||
|
||||
PMP Granularity
|
||||
---------------
|
||||
|
||||
The PMP granularity parameter is used to reduce the size of the address matching comparators by increasing the minimum region size.
|
||||
When the granularity is greater than zero, NA4 mode is not available and will be treated as OFF mode.
|
||||
|
|
@ -21,6 +21,7 @@ filesets:
|
|||
- rtl/ibex_multdiv_fast.sv
|
||||
- rtl/ibex_multdiv_slow.sv
|
||||
- rtl/ibex_prefetch_buffer.sv
|
||||
- rtl/ibex_pmp.sv
|
||||
# XXX: Figure out the best way to switch these two implementations
|
||||
# dynamically on the target.
|
||||
# - rtl/ibex_register_file_latch.sv # ASIC
|
||||
|
|
|
@ -24,7 +24,7 @@ lint_off -msg UNUSED -file "*/rtl/ibex_if_stage.sv" -lines 40
|
|||
|
||||
// Bits of signal are not used: fetch_addr_n[0]
|
||||
// cleaner to write all bits even if not all are used
|
||||
lint_off -msg UNUSED -file "*/rtl/ibex_if_stage.sv" -lines 79
|
||||
lint_off -msg UNUSED -file "*/rtl/ibex_if_stage.sv" -lines 80
|
||||
|
||||
// Bits of signal are not used: shift_right_result_ext[32]
|
||||
// cleaner to write all bits even if not all are used
|
||||
|
@ -46,6 +46,26 @@ lint_off -msg UNUSED -file "*/rtl/ibex_multdiv_fast.sv" -lines 68
|
|||
// testability signal
|
||||
lint_off -msg UNUSED -file "*/rtl/ibex_register_file_ff.sv" -lines 21
|
||||
|
||||
// Signal is not used: clk_i
|
||||
// leaving clk and reset connected in-case we want to add assertions
|
||||
lint_off -msg UNUSED -file "*/rtl/ibex_pmp.sv" -lines 15
|
||||
|
||||
// Signal is not used: rst_ni
|
||||
// leaving clk and reset connected in-case we want to add assertions
|
||||
lint_off -msg UNUSED -file "*/rtl/ibex_pmp.sv" -lines 16
|
||||
|
||||
// Signal is not used: csr_pmp_addr
|
||||
// Signal not connected when PMP is not configured
|
||||
lint_off -msg UNUSED -file "*/rtl/ibex_core.sv" -lines 188
|
||||
|
||||
// Signal is not used: csr_pmp_cfg
|
||||
// Signal not connected when PMP is not configured
|
||||
lint_off -msg UNUSED -file "*/rtl/ibex_core.sv" -lines 189
|
||||
|
||||
// Signal is not used: priv_mode
|
||||
// Signal not connected when PMP is not configured
|
||||
lint_off -msg UNUSED -file "*/rtl/ibex_core.sv" -lines 201
|
||||
|
||||
// Signal unoptimizable: Feedback to clock or circular logic:
|
||||
// ibex_core.id_stage_i.controller_i.ctrl_fsm_cs
|
||||
// Issue lowrisc/ibex#211
|
||||
|
@ -54,4 +74,4 @@ lint_off -msg UNOPTFLAT -file "*/rtl/ibex_controller.sv" -lines 97
|
|||
// Signal unoptimizable: Feedback to clock or circular logic:
|
||||
// ibex_core.cs_registers_i.mie_q
|
||||
// Issue lowrisc/ibex#212
|
||||
lint_off -msg UNOPTFLAT -file "*/rtl/ibex_cs_registers.sv" -lines 141
|
||||
lint_off -msg UNOPTFLAT -file "*/rtl/ibex_cs_registers.sv" -lines 149
|
||||
|
|
|
@ -11,6 +11,9 @@
|
|||
* Top level module of the ibex RISC-V core
|
||||
*/
|
||||
module ibex_core #(
|
||||
parameter bit PMPEnable = 0,
|
||||
parameter int unsigned PMPGranularity = 0,
|
||||
parameter int unsigned PMPNumRegions = 4,
|
||||
parameter int unsigned MHPMCounterNum = 0,
|
||||
parameter int unsigned MHPMCounterWidth = 40,
|
||||
parameter bit RV32E = 0,
|
||||
|
@ -92,6 +95,8 @@ module ibex_core #(
|
|||
|
||||
import ibex_pkg::*;
|
||||
|
||||
localparam int unsigned PMP_NUM_CHAN = 2;
|
||||
|
||||
// IF/ID signals
|
||||
logic instr_valid_id;
|
||||
logic instr_new_id;
|
||||
|
@ -179,6 +184,13 @@ module ibex_core #(
|
|||
logic csr_mstatus_mie;
|
||||
logic [31:0] csr_mepc, csr_depc;
|
||||
|
||||
// PMP signals
|
||||
logic [33:0] csr_pmp_addr [PMPNumRegions];
|
||||
pmp_cfg_t csr_pmp_cfg [PMPNumRegions];
|
||||
logic pmp_req_err [PMP_NUM_CHAN];
|
||||
logic instr_req_out;
|
||||
logic data_req_out;
|
||||
|
||||
logic csr_save_if;
|
||||
logic csr_save_id;
|
||||
logic csr_restore_mret_id;
|
||||
|
@ -186,6 +198,7 @@ module ibex_core #(
|
|||
logic csr_mtvec_init;
|
||||
logic [31:0] csr_mtvec;
|
||||
logic [31:0] csr_mtval;
|
||||
priv_lvl_e priv_mode;
|
||||
|
||||
// debug mode and dcsr configuration
|
||||
dbg_cause_e debug_cause;
|
||||
|
@ -287,12 +300,13 @@ module ibex_core #(
|
|||
.req_i ( instr_req_int ), // instruction request control
|
||||
|
||||
// instruction cache interface
|
||||
.instr_req_o ( instr_req_o ),
|
||||
.instr_req_o ( instr_req_out ),
|
||||
.instr_addr_o ( instr_addr_o ),
|
||||
.instr_gnt_i ( instr_gnt_i ),
|
||||
.instr_rvalid_i ( instr_rvalid_i ),
|
||||
.instr_rdata_i ( instr_rdata_i ),
|
||||
.instr_err_i ( instr_err_i ),
|
||||
.instr_pmp_err_i ( pmp_req_err[PMP_I] ),
|
||||
|
||||
// outputs to ID stage
|
||||
.instr_valid_id_o ( instr_valid_id ),
|
||||
|
@ -328,6 +342,8 @@ module ibex_core #(
|
|||
.perf_imiss_o ( perf_imiss )
|
||||
);
|
||||
|
||||
// Qualify the instruction request with PMP error
|
||||
assign instr_req_o = instr_req_out & ~pmp_req_err[PMP_I];
|
||||
|
||||
//////////////
|
||||
// ID stage //
|
||||
|
@ -485,15 +501,18 @@ module ibex_core #(
|
|||
// Load/store unit //
|
||||
/////////////////////
|
||||
|
||||
assign data_req_o = data_req_out & ~pmp_req_err[PMP_D];
|
||||
|
||||
ibex_load_store_unit load_store_unit_i (
|
||||
.clk_i ( clk ),
|
||||
.rst_ni ( rst_ni ),
|
||||
|
||||
// data interface
|
||||
.data_req_o ( data_req_o ),
|
||||
.data_req_o ( data_req_out ),
|
||||
.data_gnt_i ( data_gnt_i ),
|
||||
.data_rvalid_i ( data_rvalid_i ),
|
||||
.data_err_i ( data_err_i ),
|
||||
.data_pmp_err_i ( pmp_req_err[PMP_D] ),
|
||||
|
||||
.data_addr_o ( data_addr_o ),
|
||||
.data_we_o ( data_we_o ),
|
||||
|
@ -537,6 +556,8 @@ module ibex_core #(
|
|||
ibex_cs_registers #(
|
||||
.MHPMCounterNum ( MHPMCounterNum ),
|
||||
.MHPMCounterWidth ( MHPMCounterWidth ),
|
||||
.PMPGranularity ( PMPGranularity ),
|
||||
.PMPNumRegions ( PMPNumRegions ),
|
||||
.RV32E ( RV32E ),
|
||||
.RV32M ( RV32M )
|
||||
) cs_registers_i (
|
||||
|
@ -546,6 +567,7 @@ module ibex_core #(
|
|||
// Core and Cluster ID from outside
|
||||
.core_id_i ( core_id_i ),
|
||||
.cluster_id_i ( cluster_id_i ),
|
||||
.priv_mode_o ( priv_mode ),
|
||||
|
||||
// mtvec
|
||||
.csr_mtvec_o ( csr_mtvec ),
|
||||
|
@ -572,6 +594,10 @@ module ibex_core #(
|
|||
.csr_mstatus_mie_o ( csr_mstatus_mie ),
|
||||
.csr_mepc_o ( csr_mepc ),
|
||||
|
||||
// PMP
|
||||
.csr_pmp_cfg_o ( csr_pmp_cfg ),
|
||||
.csr_pmp_addr_o ( csr_pmp_addr ),
|
||||
|
||||
// debug
|
||||
.csr_depc_o ( csr_depc ),
|
||||
.debug_cause_i ( debug_cause ),
|
||||
|
@ -605,6 +631,36 @@ module ibex_core #(
|
|||
.lsu_busy_i ( lsu_busy )
|
||||
);
|
||||
|
||||
if (PMPEnable) begin : g_pmp
|
||||
logic [33:0] pmp_req_addr [PMP_NUM_CHAN];
|
||||
pmp_req_e pmp_req_type [PMP_NUM_CHAN];
|
||||
|
||||
assign pmp_req_addr[PMP_I] = {2'b00,instr_addr_o[31:0]};
|
||||
assign pmp_req_type[PMP_I] = PMP_ACC_EXEC;
|
||||
assign pmp_req_addr[PMP_D] = {2'b00,data_addr_o[31:0]};
|
||||
assign pmp_req_type[PMP_D] = data_we_o ? PMP_ACC_WRITE : PMP_ACC_READ;
|
||||
|
||||
ibex_pmp #(
|
||||
.PMPGranularity ( PMPGranularity ),
|
||||
.PMPNumChan ( PMP_NUM_CHAN ),
|
||||
.PMPNumRegions ( PMPNumRegions )
|
||||
) pmp_i (
|
||||
.clk_i ( clk ),
|
||||
.rst_ni ( rst_ni ),
|
||||
// Interface to CSRs
|
||||
.csr_pmp_cfg_i ( csr_pmp_cfg ),
|
||||
.csr_pmp_addr_i ( csr_pmp_addr ),
|
||||
.priv_mode_i ( priv_mode ),
|
||||
// Access checking channels
|
||||
.pmp_req_addr_i ( pmp_req_addr ),
|
||||
.pmp_req_type_i ( pmp_req_type ),
|
||||
.pmp_req_err_o ( pmp_req_err )
|
||||
);
|
||||
end else begin : g_no_pmp
|
||||
assign pmp_req_err[PMP_I] = 1'b0;
|
||||
assign pmp_req_err[PMP_D] = 1'b0;
|
||||
end
|
||||
|
||||
`ifdef RVFI
|
||||
always_ff @(posedge clk or negedge rst_ni) begin
|
||||
if (!rst_ni) begin
|
||||
|
|
|
@ -12,6 +12,9 @@
|
|||
module ibex_cs_registers #(
|
||||
parameter int unsigned MHPMCounterNum = 8,
|
||||
parameter int unsigned MHPMCounterWidth = 40,
|
||||
parameter bit PMPEnable = 0,
|
||||
parameter int unsigned PMPGranularity = 0,
|
||||
parameter int unsigned PMPNumRegions = 4,
|
||||
parameter bit RV32E = 0,
|
||||
parameter bit RV32M = 0
|
||||
) (
|
||||
|
@ -22,6 +25,7 @@ module ibex_cs_registers #(
|
|||
// Core and Cluster ID
|
||||
input logic [3:0] core_id_i,
|
||||
input logic [5:0] cluster_id_i,
|
||||
output ibex_pkg::priv_lvl_e priv_mode_o,
|
||||
|
||||
// mtvec
|
||||
output logic [31:0] csr_mtvec_o,
|
||||
|
@ -48,6 +52,10 @@ module ibex_cs_registers #(
|
|||
output logic csr_mstatus_mie_o,
|
||||
output logic [31:0] csr_mepc_o,
|
||||
|
||||
// PMP
|
||||
output ibex_pkg::pmp_cfg_t csr_pmp_cfg_o [PMPNumRegions],
|
||||
output logic [33:0] csr_pmp_addr_o [PMPNumRegions],
|
||||
|
||||
// debug
|
||||
input ibex_pkg::dbg_cause_e debug_cause_i,
|
||||
input logic debug_csr_save_i,
|
||||
|
@ -156,6 +164,10 @@ module ibex_cs_registers #(
|
|||
logic [31:0] mstack_epc_q, mstack_epc_d;
|
||||
logic [5:0] mstack_cause_q, mstack_cause_d;
|
||||
|
||||
// PMP Signals
|
||||
logic [31:0] pmp_addr_rdata [PMP_MAX_REGIONS];
|
||||
logic [PMP_CFG_W-1:0] pmp_cfg_rdata [PMP_MAX_REGIONS];
|
||||
|
||||
// Hardware performance monitor signals
|
||||
logic [31:0] mcountinhibit_d, mcountinhibit_q, mcountinhibit;
|
||||
logic [31:0] mcountinhibit_force;
|
||||
|
@ -254,6 +266,32 @@ module ibex_cs_registers #(
|
|||
csr_rdata_int[CSR_MFIX_BIT_HIGH:CSR_MFIX_BIT_LOW] = mip.irq_fast;
|
||||
end
|
||||
|
||||
// PMP registers
|
||||
CSR_PMPCFG0: csr_rdata_int = {pmp_cfg_rdata[3], pmp_cfg_rdata[2],
|
||||
pmp_cfg_rdata[1], pmp_cfg_rdata[0]};
|
||||
CSR_PMPCFG1: csr_rdata_int = {pmp_cfg_rdata[7], pmp_cfg_rdata[6],
|
||||
pmp_cfg_rdata[5], pmp_cfg_rdata[4]};
|
||||
CSR_PMPCFG2: csr_rdata_int = {pmp_cfg_rdata[11], pmp_cfg_rdata[10],
|
||||
pmp_cfg_rdata[9], pmp_cfg_rdata[8]};
|
||||
CSR_PMPCFG3: csr_rdata_int = {pmp_cfg_rdata[15], pmp_cfg_rdata[14],
|
||||
pmp_cfg_rdata[13], pmp_cfg_rdata[12]};
|
||||
CSR_PMPADDR0: csr_rdata_int = pmp_addr_rdata[0];
|
||||
CSR_PMPADDR1: csr_rdata_int = pmp_addr_rdata[1];
|
||||
CSR_PMPADDR2: csr_rdata_int = pmp_addr_rdata[2];
|
||||
CSR_PMPADDR3: csr_rdata_int = pmp_addr_rdata[3];
|
||||
CSR_PMPADDR4: csr_rdata_int = pmp_addr_rdata[4];
|
||||
CSR_PMPADDR5: csr_rdata_int = pmp_addr_rdata[5];
|
||||
CSR_PMPADDR6: csr_rdata_int = pmp_addr_rdata[6];
|
||||
CSR_PMPADDR7: csr_rdata_int = pmp_addr_rdata[7];
|
||||
CSR_PMPADDR8: csr_rdata_int = pmp_addr_rdata[8];
|
||||
CSR_PMPADDR9: csr_rdata_int = pmp_addr_rdata[9];
|
||||
CSR_PMPADDR10: csr_rdata_int = pmp_addr_rdata[10];
|
||||
CSR_PMPADDR11: csr_rdata_int = pmp_addr_rdata[11];
|
||||
CSR_PMPADDR12: csr_rdata_int = pmp_addr_rdata[12];
|
||||
CSR_PMPADDR13: csr_rdata_int = pmp_addr_rdata[13];
|
||||
CSR_PMPADDR14: csr_rdata_int = pmp_addr_rdata[14];
|
||||
CSR_PMPADDR15: csr_rdata_int = pmp_addr_rdata[15];
|
||||
|
||||
CSR_DCSR: csr_rdata_int = dcsr_q;
|
||||
CSR_DPC: csr_rdata_int = depc_q;
|
||||
CSR_DSCRATCH0: csr_rdata_int = dscratch0_q;
|
||||
|
@ -511,7 +549,7 @@ module ibex_cs_registers #(
|
|||
end
|
||||
|
||||
// only write CSRs during one clock cycle
|
||||
assign csr_we_int = csr_wreq & instr_new_id_i;
|
||||
assign csr_we_int = csr_wreq & ~illegal_csr_priv & instr_new_id_i;
|
||||
|
||||
assign csr_rdata_o = csr_rdata_int;
|
||||
|
||||
|
@ -584,6 +622,131 @@ module ibex_cs_registers #(
|
|||
end
|
||||
end
|
||||
|
||||
assign priv_mode_o = mstatus_q.mpp;
|
||||
|
||||
// -----------------
|
||||
// PMP registers
|
||||
// -----------------
|
||||
|
||||
if (PMPEnable) begin : g_pmp_registers
|
||||
pmp_cfg_t pmp_cfg [PMPNumRegions];
|
||||
pmp_cfg_t pmp_cfg_wdata [PMPNumRegions];
|
||||
logic [31:0] pmp_addr [PMPNumRegions];
|
||||
logic [PMPNumRegions-1:0] pmp_cfg_we;
|
||||
logic [PMPNumRegions-1:0] pmp_addr_we;
|
||||
|
||||
// Expanded / qualified register read data
|
||||
for (genvar i = 0; i < PMP_MAX_REGIONS; i++) begin : g_exp_rd_data
|
||||
if (i < PMPNumRegions) begin : g_implemented_regions
|
||||
// Add in zero padding for reserved fields
|
||||
assign pmp_cfg_rdata[i] = {pmp_cfg[i].lock, 2'b00, pmp_cfg[i].mode,
|
||||
pmp_cfg[i].exec, pmp_cfg[i].write, pmp_cfg[i].read};
|
||||
|
||||
// Address field read data depends on the current programmed mode and the granularity
|
||||
// See RISC-V Privileged Specification, version 1.11, Section 3.6.1
|
||||
if (PMPGranularity == 0) begin : g_pmp_g0
|
||||
// If G == 0, read data is unmodified
|
||||
assign pmp_addr_rdata[i] = pmp_addr[i];
|
||||
|
||||
end else if (PMPGranularity == 1) begin : g_pmp_g1
|
||||
// If G == 1, bit [G-1] reads as zero in TOR or OFF mode
|
||||
always_comb begin
|
||||
pmp_addr_rdata[i] = pmp_addr[i];
|
||||
if ((pmp_cfg[i].mode == PMP_MODE_OFF) || (pmp_cfg[i].mode == PMP_MODE_TOR)) begin
|
||||
pmp_addr_rdata[i][PMPGranularity-1:0] = '0;
|
||||
end
|
||||
end
|
||||
|
||||
end else begin
|
||||
// For G >= 2, bits are masked to one or zero depending on the mode
|
||||
always_comb begin
|
||||
pmp_addr_rdata[i] = pmp_addr[i];
|
||||
if ((pmp_cfg[i].mode == PMP_MODE_OFF) || (pmp_cfg[i].mode == PMP_MODE_TOR)) begin
|
||||
// In TOR or OFF mode, bits [G-1:0] must read as zero
|
||||
pmp_addr_rdata[i][PMPGranularity-1:0] = '0;
|
||||
end else if (pmp_cfg[i].mode == PMP_MODE_NAPOT) begin
|
||||
// In NAPOT mode, bits [G-2:0] must read as one
|
||||
pmp_addr_rdata[i][PMPGranularity-2:0] = '1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end else begin : g_other_regions
|
||||
// Non-implemented regions read as zero
|
||||
assign pmp_cfg_rdata[i] = '0;
|
||||
assign pmp_addr_rdata[i] = '0;
|
||||
end
|
||||
end
|
||||
|
||||
// Write data calculation
|
||||
for (genvar i = 0; i < PMPNumRegions; i++) begin : g_pmp_csrs
|
||||
// -------------------------
|
||||
// Instantiate cfg registers
|
||||
// -------------------------
|
||||
assign pmp_cfg_we[i] = csr_we_int & ~pmp_cfg[i].lock &
|
||||
(csr_addr == (CSR_OFF_PMP_CFG + (i[11:0] >> 2)));
|
||||
|
||||
// Select the correct WDATA (each CSR contains 4 CFG fields, each with 2 RES bits)
|
||||
assign pmp_cfg_wdata[i].lock = csr_wdata_int[(i%4)*PMP_CFG_W+7];
|
||||
// NA4 mode is not selectable when G > 0, mode is treated as OFF
|
||||
always_comb begin
|
||||
unique case (csr_wdata_int[(i%4)*PMP_CFG_W+3+:2])
|
||||
2'b00 : pmp_cfg_wdata[i].mode = PMP_MODE_OFF;
|
||||
2'b01 : pmp_cfg_wdata[i].mode = PMP_MODE_TOR;
|
||||
2'b10 : pmp_cfg_wdata[i].mode = (PMPGranularity == 0) ? PMP_MODE_NA4:
|
||||
PMP_MODE_OFF;
|
||||
2'b11 : pmp_cfg_wdata[i].mode = PMP_MODE_NAPOT;
|
||||
default : pmp_cfg_wdata[i].mode = pmp_cfg_mode_e'('X);
|
||||
endcase
|
||||
end
|
||||
assign pmp_cfg_wdata[i].exec = csr_wdata_int[(i%4)*PMP_CFG_W+2];
|
||||
// W = 1, R = 0 is a reserved combination. For now, we force W to 0 if R == 0
|
||||
assign pmp_cfg_wdata[i].write = &csr_wdata_int[(i%4)*PMP_CFG_W+:2];
|
||||
assign pmp_cfg_wdata[i].read = csr_wdata_int[(i%4)*PMP_CFG_W];
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if (!rst_ni) begin
|
||||
pmp_cfg[i] <= pmp_cfg_t'('b0);
|
||||
end else if (pmp_cfg_we[i]) begin
|
||||
pmp_cfg[i] <= pmp_cfg_wdata[i];
|
||||
end
|
||||
end
|
||||
|
||||
// --------------------------
|
||||
// Instantiate addr registers
|
||||
// --------------------------
|
||||
if (i < PMPNumRegions - 1) begin : g_lower
|
||||
assign pmp_addr_we[i] = csr_we_int & ~pmp_cfg[i].lock &
|
||||
(pmp_cfg[i+1].mode != PMP_MODE_TOR) &
|
||||
(csr_addr == (CSR_OFF_PMP_ADDR + i[11:0]));
|
||||
end else begin : g_upper
|
||||
assign pmp_addr_we[i] = csr_we_int & ~pmp_cfg[i].lock &
|
||||
(csr_addr == (CSR_OFF_PMP_ADDR + i[11:0]));
|
||||
end
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if (!rst_ni) begin
|
||||
pmp_addr[i] <= 'b0;
|
||||
end else if (pmp_addr_we[i]) begin
|
||||
pmp_addr[i] <= csr_wdata_int;
|
||||
end
|
||||
end
|
||||
assign csr_pmp_cfg_o[i] = pmp_cfg[i];
|
||||
assign csr_pmp_addr_o[i] = {pmp_addr[i],2'b00};
|
||||
end
|
||||
|
||||
end else begin : g_no_pmp_tieoffs
|
||||
// Generate tieoffs when PMP is not configured
|
||||
for (genvar i = 0; i < PMP_MAX_REGIONS; i++) begin : g_rdata
|
||||
assign pmp_addr_rdata[i] = '0;
|
||||
assign pmp_cfg_rdata[i] = '0;
|
||||
end
|
||||
for (genvar i = 0; i < PMPNumRegions; i++) begin : g_outputs
|
||||
assign csr_pmp_cfg_o[i] = pmp_cfg_t'('0);
|
||||
assign csr_pmp_addr_o[i] = '0;
|
||||
end
|
||||
end
|
||||
|
||||
//////////////////////////
|
||||
// Performance monitor //
|
||||
//////////////////////////
|
||||
|
|
|
@ -26,6 +26,7 @@ module ibex_if_stage #(
|
|||
input logic instr_rvalid_i,
|
||||
input logic [31:0] instr_rdata_i,
|
||||
input logic instr_err_i,
|
||||
input logic instr_pmp_err_i,
|
||||
|
||||
// output of ID stage
|
||||
output logic instr_valid_id_o, // instr in IF-ID is valid
|
||||
|
@ -150,6 +151,7 @@ module ibex_if_stage #(
|
|||
.instr_rvalid_i ( instr_rvalid_i ),
|
||||
.instr_rdata_i ( instr_rdata_i ),
|
||||
.instr_err_i ( instr_err_i ),
|
||||
.instr_pmp_err_i ( instr_pmp_err_i ),
|
||||
|
||||
// Prefetch Buffer Status
|
||||
.busy_o ( prefetch_busy )
|
||||
|
|
|
@ -18,6 +18,7 @@ module ibex_load_store_unit (
|
|||
input logic data_gnt_i,
|
||||
input logic data_rvalid_i,
|
||||
input logic data_err_i,
|
||||
input logic data_pmp_err_i,
|
||||
|
||||
output logic [31:0] data_addr_o,
|
||||
output logic data_we_o,
|
||||
|
@ -54,6 +55,7 @@ module ibex_load_store_unit (
|
|||
logic [31:0] data_addr_w_aligned;
|
||||
logic [31:0] addr_last_q, addr_last_d;
|
||||
|
||||
logic data_update;
|
||||
logic [31:0] rdata_q, rdata_d;
|
||||
logic [1:0] rdata_offset_q, rdata_offset_d;
|
||||
logic [1:0] data_type_q, data_type_d;
|
||||
|
@ -74,6 +76,8 @@ module ibex_load_store_unit (
|
|||
logic split_misaligned_access;
|
||||
logic handle_misaligned_q, handle_misaligned_d; // high after receiving grant for first
|
||||
// part of a misaligned access
|
||||
logic pmp_err_q;
|
||||
logic data_or_pmp_err;
|
||||
|
||||
typedef enum logic [2:0] {
|
||||
IDLE, WAIT_GNT_MIS, WAIT_RVALID_MIS, WAIT_GNT, WAIT_RVALID
|
||||
|
@ -168,10 +172,16 @@ module ibex_load_store_unit (
|
|||
end
|
||||
|
||||
// update control signals for next read data upon receiving grant
|
||||
assign rdata_offset_d = data_gnt_i ? data_addr[1:0] : rdata_offset_q;
|
||||
assign data_type_d = data_gnt_i ? data_type_ex_i : data_type_q;
|
||||
assign data_sign_ext_d = data_gnt_i ? data_sign_ext_ex_i : data_sign_ext_q;
|
||||
assign data_we_d = data_gnt_i ? data_we_ex_i : data_we_q;
|
||||
// This must also be set for a pmp error (which might not actually be granted) to force
|
||||
// data_we_q to update in order to signal the correct exception type (load or store)
|
||||
// Note that we can use the registered pmp_err_q here since we will always take an
|
||||
// extra cycle to progress to the RVALID state
|
||||
assign data_update = data_gnt_i | pmp_err_q;
|
||||
|
||||
assign rdata_offset_d = data_update ? data_addr[1:0] : rdata_offset_q;
|
||||
assign data_type_d = data_update ? data_type_ex_i : data_type_q;
|
||||
assign data_sign_ext_d = data_update ? data_sign_ext_ex_i : data_sign_ext_q;
|
||||
assign data_we_d = data_update ? data_we_ex_i : data_we_q;
|
||||
|
||||
// registers for rdata alignment and sign-extension
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
|
@ -310,6 +320,7 @@ module ibex_load_store_unit (
|
|||
data_valid_o = 1'b0;
|
||||
addr_incr_req_o = 1'b0;
|
||||
handle_misaligned_d = handle_misaligned_q;
|
||||
data_or_pmp_err = 1'b0;
|
||||
|
||||
unique case (ls_fsm_cs)
|
||||
|
||||
|
@ -327,7 +338,7 @@ module ibex_load_store_unit (
|
|||
|
||||
WAIT_GNT_MIS: begin
|
||||
data_req_o = 1'b1;
|
||||
if (data_gnt_i) begin
|
||||
if (data_gnt_i || pmp_err_q) begin
|
||||
handle_misaligned_d = 1'b1;
|
||||
ls_fsm_ns = WAIT_RVALID_MIS;
|
||||
end
|
||||
|
@ -336,11 +347,14 @@ module ibex_load_store_unit (
|
|||
WAIT_RVALID_MIS: begin
|
||||
// tell ID/EX stage to update the address
|
||||
addr_incr_req_o = 1'b1;
|
||||
if (data_rvalid_i) begin
|
||||
// first part rvalid is received
|
||||
if (data_err_i) begin
|
||||
// first part rvalid is received, or gets a pmp error
|
||||
// pmp_err_i will hold stable until the address is updated, and
|
||||
// therefore pmp_err_q is valid in both WAIT_GNT_MIS and WAIT_RVALID_MIS states
|
||||
if (data_rvalid_i || pmp_err_q) begin
|
||||
if (pmp_err_q || data_err_i) begin
|
||||
// first part created an error, abort transaction
|
||||
data_valid_o = 1'b1;
|
||||
data_or_pmp_err = 1'b1;
|
||||
handle_misaligned_d = 1'b0;
|
||||
ls_fsm_ns = IDLE;
|
||||
end else begin
|
||||
|
@ -364,15 +378,18 @@ module ibex_load_store_unit (
|
|||
// tell ID/EX stage to update the address
|
||||
addr_incr_req_o = handle_misaligned_q;
|
||||
data_req_o = 1'b1;
|
||||
if (data_gnt_i) begin
|
||||
if (data_gnt_i || pmp_err_q) begin
|
||||
ls_fsm_ns = WAIT_RVALID;
|
||||
end
|
||||
end
|
||||
|
||||
WAIT_RVALID: begin
|
||||
data_req_o = 1'b0;
|
||||
if (data_rvalid_i) begin
|
||||
// pmp_err_i will hold stable until the address is updated, and
|
||||
// therefore pmp_err_q is valid in both WAIT_GNT and WAIT_RVALID states
|
||||
if (data_rvalid_i || pmp_err_q) begin
|
||||
data_valid_o = 1'b1;
|
||||
data_or_pmp_err = data_err_i | pmp_err_q;
|
||||
handle_misaligned_d = 1'b0;
|
||||
ls_fsm_ns = IDLE;
|
||||
end else begin
|
||||
|
@ -402,10 +419,12 @@ module ibex_load_store_unit (
|
|||
ls_fsm_cs <= IDLE;
|
||||
addr_last_q <= '0;
|
||||
handle_misaligned_q <= '0;
|
||||
pmp_err_q <= '0;
|
||||
end else begin
|
||||
ls_fsm_cs <= ls_fsm_ns;
|
||||
addr_last_q <= addr_last_d;
|
||||
handle_misaligned_q <= handle_misaligned_d;
|
||||
pmp_err_q <= data_pmp_err_i;
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -428,10 +447,9 @@ module ibex_load_store_unit (
|
|||
// output to ID stage: mtval + AGU for misaligned transactions
|
||||
assign addr_last_o = addr_last_q;
|
||||
|
||||
// to know what kind of error to signal, we need to know the type of the transaction to which
|
||||
// the outsanding rvalid belongs.
|
||||
assign load_err_o = data_err_i & data_rvalid_i & ~data_we_q;
|
||||
assign store_err_o = data_err_i & data_rvalid_i & data_we_q;
|
||||
// Signal a load or store error depending on the transaction type outstanding
|
||||
assign load_err_o = data_or_pmp_err & ~data_we_q;
|
||||
assign store_err_o = data_or_pmp_err & data_we_q;
|
||||
|
||||
assign busy_o = (ls_fsm_cs == WAIT_RVALID) | (data_req_o == 1'b1);
|
||||
|
||||
|
|
|
@ -192,6 +192,36 @@ typedef enum logic [2:0] {
|
|||
DBG_CAUSE_STEP = 3'h4
|
||||
} dbg_cause_e;
|
||||
|
||||
// PMP constants
|
||||
parameter int unsigned PMP_MAX_REGIONS = 16;
|
||||
parameter int unsigned PMP_CFG_W = 8;
|
||||
|
||||
// PMP acces type
|
||||
parameter int unsigned PMP_I = 0;
|
||||
parameter int unsigned PMP_D = 1;
|
||||
|
||||
typedef enum logic [1:0] {
|
||||
PMP_ACC_EXEC = 2'b00,
|
||||
PMP_ACC_WRITE = 2'b01,
|
||||
PMP_ACC_READ = 2'b10
|
||||
} pmp_req_e;
|
||||
|
||||
// PMP cfg structures
|
||||
typedef enum logic [1:0] {
|
||||
PMP_MODE_OFF = 2'b00,
|
||||
PMP_MODE_TOR = 2'b01,
|
||||
PMP_MODE_NA4 = 2'b10,
|
||||
PMP_MODE_NAPOT = 2'b11
|
||||
} pmp_cfg_mode_e;
|
||||
|
||||
typedef struct packed {
|
||||
logic lock;
|
||||
pmp_cfg_mode_e mode;
|
||||
logic exec;
|
||||
logic write;
|
||||
logic read;
|
||||
} pmp_cfg_t;
|
||||
|
||||
// CSRs
|
||||
typedef enum logic[11:0] {
|
||||
// Machine information
|
||||
|
@ -210,6 +240,28 @@ typedef enum logic[11:0] {
|
|||
CSR_MTVAL = 12'h343,
|
||||
CSR_MIP = 12'h344,
|
||||
|
||||
// Physical memory protection
|
||||
CSR_PMPCFG0 = 12'h3A0,
|
||||
CSR_PMPCFG1 = 12'h3A1,
|
||||
CSR_PMPCFG2 = 12'h3A2,
|
||||
CSR_PMPCFG3 = 12'h3A3,
|
||||
CSR_PMPADDR0 = 12'h3B0,
|
||||
CSR_PMPADDR1 = 12'h3B1,
|
||||
CSR_PMPADDR2 = 12'h3B2,
|
||||
CSR_PMPADDR3 = 12'h3B3,
|
||||
CSR_PMPADDR4 = 12'h3B4,
|
||||
CSR_PMPADDR5 = 12'h3B5,
|
||||
CSR_PMPADDR6 = 12'h3B6,
|
||||
CSR_PMPADDR7 = 12'h3B7,
|
||||
CSR_PMPADDR8 = 12'h3B8,
|
||||
CSR_PMPADDR9 = 12'h3B9,
|
||||
CSR_PMPADDR10 = 12'h3BA,
|
||||
CSR_PMPADDR11 = 12'h3BB,
|
||||
CSR_PMPADDR12 = 12'h3BC,
|
||||
CSR_PMPADDR13 = 12'h3BD,
|
||||
CSR_PMPADDR14 = 12'h3BE,
|
||||
CSR_PMPADDR15 = 12'h3BF,
|
||||
|
||||
// Debug/trace
|
||||
CSR_DCSR = 12'h7b0,
|
||||
CSR_DPC = 12'h7b1,
|
||||
|
@ -226,6 +278,10 @@ typedef enum logic[11:0] {
|
|||
CSR_MINSTRETH = 12'hB82
|
||||
} csr_num_e;
|
||||
|
||||
// CSR pmp-related offsets
|
||||
parameter logic [11:0] CSR_OFF_PMP_CFG = 12'h3A0; // pmp_cfg @ 12'h3a0 - 12'h3a3
|
||||
parameter logic [11:0] CSR_OFF_PMP_ADDR = 12'h3B0; // pmp_addr @ 12'h3b0 - 12'h3bf
|
||||
|
||||
// CSR mhpmcounter-related offsets and mask
|
||||
parameter logic [11:0] CSR_OFF_MCOUNTER_SETUP = 12'h320; // mcounter_setup @ 12'h323 - 12'h33F
|
||||
parameter logic [11:0] CSR_OFF_MCOUNTER = 12'hB00; // mcounter @ 12'hB03 - 12'hB1F
|
||||
|
|
113
rtl/ibex_pmp.sv
Normal file
113
rtl/ibex_pmp.sv
Normal file
|
@ -0,0 +1,113 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
module ibex_pmp #(
|
||||
// Granularity of NAPOT access,
|
||||
// 0 = No restriction, 1 = 8 byte, 2 = 16 byte, 3 = 32 byte, etc.
|
||||
parameter int unsigned PMPGranularity = 0,
|
||||
// Number of access channels (e.g. i-side + d-side)
|
||||
parameter int unsigned PMPNumChan = 2,
|
||||
// Number of implemented regions
|
||||
parameter int unsigned PMPNumRegions = 4
|
||||
) (
|
||||
// Clock and Reset
|
||||
input logic clk_i,
|
||||
input logic rst_ni,
|
||||
|
||||
// Interface to CSRs
|
||||
input ibex_pkg::pmp_cfg_t csr_pmp_cfg_i [PMPNumRegions],
|
||||
input logic [33:0] csr_pmp_addr_i [PMPNumRegions],
|
||||
|
||||
input ibex_pkg::priv_lvl_e priv_mode_i, // Current priv mode, assumed to
|
||||
// be the same for all channels
|
||||
// Access checking channels
|
||||
input logic [33:0] pmp_req_addr_i [PMPNumChan],
|
||||
input ibex_pkg::pmp_req_e pmp_req_type_i [PMPNumChan],
|
||||
output logic pmp_req_err_o [PMPNumChan]
|
||||
|
||||
);
|
||||
|
||||
import ibex_pkg::*;
|
||||
|
||||
// Access Checking Signals
|
||||
logic [33:0] region_start_addr [PMPNumRegions];
|
||||
logic [33:PMPGranularity+2] region_addr_mask [PMPNumRegions];
|
||||
logic [PMPNumChan-1:0][PMPNumRegions-1:0] region_match_high;
|
||||
logic [PMPNumChan-1:0][PMPNumRegions-1:0] region_match_low;
|
||||
logic [PMPNumChan-1:0][PMPNumRegions-1:0] region_match_both;
|
||||
logic [PMPNumChan-1:0][PMPNumRegions-1:0] region_match_partial;
|
||||
logic [PMPNumChan-1:0][PMPNumRegions-1:0] region_perm_check;
|
||||
logic [PMPNumChan-1:0][PMPNumRegions-1:0] machine_access_fault;
|
||||
logic [PMPNumChan-1:0][PMPNumRegions-1:0] user_access_allowed;
|
||||
logic [PMPNumChan-1:0] access_fault;
|
||||
|
||||
|
||||
// ---------------
|
||||
// Access checking
|
||||
// ---------------
|
||||
|
||||
for (genvar r = 0; r < PMPNumRegions; r++) begin : g_addr_exp
|
||||
// Start address for TOR matching
|
||||
if (r == 0) begin : g_entry0
|
||||
assign region_start_addr[r] = (csr_pmp_cfg_i[r].mode == PMP_MODE_TOR) ? 34'h000000000 :
|
||||
csr_pmp_addr_i[r];
|
||||
end else begin : g_oth
|
||||
assign region_start_addr[r] = (csr_pmp_cfg_i[r].mode == PMP_MODE_TOR) ? csr_pmp_addr_i[r-1] :
|
||||
csr_pmp_addr_i[r];
|
||||
end
|
||||
// Address mask for NA matching
|
||||
for (genvar b = PMPGranularity+2; b < 34; b++) begin : g_bitmask
|
||||
if (b == PMPGranularity+2) begin : g_bit0
|
||||
// Always mask bit (G+2) for NAPOT
|
||||
assign region_addr_mask[r][b] = (csr_pmp_cfg_i[r].mode != PMP_MODE_NAPOT);
|
||||
end else begin : g_others
|
||||
// We will mask this bit if it is within the programmed granule
|
||||
// i.e. addr = yyyy 0111
|
||||
// ^
|
||||
// | This bit pos is the top of the mask, all lower bits set
|
||||
// thus mask = 1111 0000
|
||||
assign region_addr_mask[r][b] = (csr_pmp_cfg_i[r].mode != PMP_MODE_NAPOT) |
|
||||
~&csr_pmp_addr_i[r][b-1:PMPGranularity+2];
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for (genvar c = 0; c < PMPNumChan; c++) begin : g_access_check
|
||||
for (genvar r = 0; r < PMPNumRegions; r++) begin : g_regions
|
||||
// TOR Region high/low matching is reused for all match types
|
||||
assign region_match_low[c][r] = (pmp_req_addr_i[c][33:PMPGranularity+2] >=
|
||||
// Comparators are sized according to granularity
|
||||
(region_start_addr[r][33:PMPGranularity+2] &
|
||||
region_addr_mask[r]));
|
||||
assign region_match_high[c][r] = (pmp_req_addr_i[c][33:PMPGranularity+2] <=
|
||||
(csr_pmp_addr_i[r][33:PMPGranularity+2] &
|
||||
region_addr_mask[r]));
|
||||
assign region_match_both[c][r] = region_match_low[c][r] & region_match_high[c][r] &
|
||||
(csr_pmp_cfg_i[r].mode != PMP_MODE_OFF);
|
||||
assign region_match_partial[c][r] = (region_match_low[c][r] ^ region_match_high[c][r]) &
|
||||
(csr_pmp_cfg_i[r].mode != PMP_MODE_OFF);
|
||||
// Check specific required permissions
|
||||
assign region_perm_check[c][r] =
|
||||
((pmp_req_type_i[c] == PMP_ACC_EXEC) & csr_pmp_cfg_i[r].exec) |
|
||||
((pmp_req_type_i[c] == PMP_ACC_WRITE) & csr_pmp_cfg_i[r].write) |
|
||||
((pmp_req_type_i[c] == PMP_ACC_READ) & csr_pmp_cfg_i[r].read);
|
||||
// In machine mode, any match to a locked region without sufficient permissions is a fault
|
||||
assign machine_access_fault[c][r] = region_match_both[c][r] & csr_pmp_cfg_i[r].lock &
|
||||
~region_perm_check[c][r];
|
||||
if (r == 0) begin : g_region0
|
||||
// In any other mode, any access should fault unless is matches a region
|
||||
assign user_access_allowed[c][r] = region_match_both[c][r] & region_perm_check[c][r];
|
||||
end else begin : g_oth_regions
|
||||
assign user_access_allowed[c][r] = region_match_both[c][r] & region_perm_check[c][r] &
|
||||
// any higher priority (lower region number) partial match should also cause a fault
|
||||
~|region_match_partial[c][r-1:0];
|
||||
end
|
||||
end
|
||||
assign access_fault[c] = (priv_mode_i == PRIV_LVL_M) ? |machine_access_fault[c] :
|
||||
~|user_access_allowed[c];
|
||||
|
||||
assign pmp_req_err_o[c] = access_fault[c];
|
||||
end
|
||||
|
||||
endmodule
|
|
@ -32,6 +32,7 @@ module ibex_prefetch_buffer (
|
|||
output logic [31:0] instr_addr_o,
|
||||
input logic [31:0] instr_rdata_i,
|
||||
input logic instr_err_i,
|
||||
input logic instr_pmp_err_i,
|
||||
input logic instr_rvalid_i,
|
||||
|
||||
// Prefetch Buffer Status
|
||||
|
@ -47,6 +48,8 @@ module ibex_prefetch_buffer (
|
|||
logic [31:0] instr_addr_q, fetch_addr;
|
||||
logic [31:0] instr_addr, instr_addr_w_aligned;
|
||||
logic addr_valid;
|
||||
logic pmp_err_q;
|
||||
logic instr_or_pmp_err;
|
||||
|
||||
logic fifo_valid;
|
||||
logic fifo_ready;
|
||||
|
@ -62,6 +65,10 @@ module ibex_prefetch_buffer (
|
|||
// Fetch fifo - consumes addresses and data //
|
||||
//////////////////////////////////////////////
|
||||
|
||||
// Instruction fetch errors are valid on the data phase of a request
|
||||
// PMP errors are generated in the address phase, and registered into a fake data phase
|
||||
assign instr_or_pmp_err = instr_err_i | pmp_err_q;
|
||||
|
||||
ibex_fetch_fifo fifo_i (
|
||||
.clk_i ( clk_i ),
|
||||
.rst_ni ( rst_ni ),
|
||||
|
@ -70,7 +77,7 @@ module ibex_prefetch_buffer (
|
|||
|
||||
.in_addr_i ( instr_addr_q ),
|
||||
.in_rdata_i ( instr_rdata_i ),
|
||||
.in_err_i ( instr_err_i ),
|
||||
.in_err_i ( instr_or_pmp_err ),
|
||||
.in_valid_i ( fifo_valid ),
|
||||
.in_ready_o ( fifo_ready ),
|
||||
|
||||
|
@ -134,7 +141,10 @@ module ibex_prefetch_buffer (
|
|||
end
|
||||
|
||||
//~> granted request or not
|
||||
pf_fsm_ns = instr_gnt_i ? WAIT_RVALID : WAIT_GNT;
|
||||
// If the instruction generated a PMP error, we may or may not
|
||||
// get granted (the external valid is suppressed by the error)
|
||||
// but we proceed to WAIT_RVALID to push the error to the fifo
|
||||
pf_fsm_ns = (instr_gnt_i || pmp_err_q) ? WAIT_RVALID : WAIT_GNT;
|
||||
end // case: WAIT_GNT
|
||||
|
||||
// we wait for rvalid, after that we are ready to serve a new request
|
||||
|
@ -148,7 +158,8 @@ module ibex_prefetch_buffer (
|
|||
if (req_i && (fifo_ready || branch_i)) begin
|
||||
// prepare for next request
|
||||
|
||||
if (instr_rvalid_i) begin
|
||||
// Fake the rvalid for PMP errors to push the error to the fifo
|
||||
if (instr_rvalid_i || pmp_err_q) begin
|
||||
instr_req_o = 1'b1;
|
||||
fifo_valid = 1'b1;
|
||||
addr_valid = 1'b1;
|
||||
|
@ -166,7 +177,8 @@ module ibex_prefetch_buffer (
|
|||
end else begin
|
||||
// just wait for rvalid and go back to IDLE, no new request
|
||||
|
||||
if (instr_rvalid_i) begin
|
||||
// Fake the rvalid for PMP errors to push the error to the fifo
|
||||
if (instr_rvalid_i || pmp_err_q) begin
|
||||
fifo_valid = 1'b1;
|
||||
pf_fsm_ns = IDLE;
|
||||
end
|
||||
|
@ -207,11 +219,13 @@ module ibex_prefetch_buffer (
|
|||
if (!rst_ni) begin
|
||||
pf_fsm_cs <= IDLE;
|
||||
instr_addr_q <= '0;
|
||||
pmp_err_q <= '0;
|
||||
end else begin
|
||||
pf_fsm_cs <= pf_fsm_ns;
|
||||
|
||||
if (addr_valid) begin
|
||||
instr_addr_q <= instr_addr;
|
||||
pmp_err_q <= instr_pmp_err_i;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -17,6 +17,7 @@ ibex:
|
|||
rtl/ibex_multdiv_fast.sv,
|
||||
rtl/ibex_prefetch_buffer.sv,
|
||||
rtl/ibex_fetch_fifo.sv,
|
||||
rtl/ibex_pmp.sv,
|
||||
rtl/ibex_core.sv,
|
||||
]
|
||||
ibex_vip_rtl:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue