mirror of
https://github.com/openhwgroup/cve2.git
synced 2025-06-28 09:39:26 -04:00
Feature/remove security (#52)
* Remove ResetAll parameter Signed-off-by: Szymon Bieganski <szymon.bieganski@oss.nxp.com> * remove ICache and related paramters Signed-off-by: Szymon Bieganski <szymon.bieganski@oss.nxp.com> * Remove reference to the deleted parameterd from the documentation Signed-off-by: Szymon Bieganski <szymon.bieganski@oss.nxp.com> * Remove references to the removed parameters from the example configurations Signed-off-by: Szymon Bieganski <szymon.bieganski@oss.nxp.com> * remove security features, and related code Signed-off-by: Szymon Bieganski <szymon.bieganski@oss.nxp.com> * Remove complete security section from Reference documentation sub-page Signed-off-by: Szymon Bieganski <szymon.bieganski@oss.nxp.com> * Remove references to deleted security features Signed-off-by: Szymon Bieganski <szymon.bieganski@oss.nxp.com> * Remove reference to the removed dummy_instr.sv Signed-off-by: Szymon Bieganski <szymon.bieganski@oss.nxp.com> * Remove Lockstep Signed-off-by: Szymon Bieganski <szymon.bieganski@oss.nxp.com> * Remove DummyInstruction related code Signed-off-by: Szymon Bieganski <szymon.bieganski@oss.nxp.com> * Remove references to SecureIbex in documentation Signed-off-by: Szymon Bieganski <szymon.bieganski@oss.nxp.com> * Remove related and dead code to security features Signed-off-by: Szymon Bieganski <szymon.bieganski@oss.nxp.com> * Remove Security option from example configurations Signed-off-by: Szymon Bieganski <szymon.bieganski@oss.nxp.com> * Remove security related signals and CSR register Signed-off-by: Szymon Bieganski <szymon.bieganski@oss.nxp.com> --------- Signed-off-by: Szymon Bieganski <szymon.bieganski@oss.nxp.com> Co-authored-by: Szymon Bieganski <szymon.bieganski@oss.nxp.com>
This commit is contained in:
parent
2aa3bf8b2d
commit
d6f0e2ccff
32 changed files with 58 additions and 5284 deletions
|
@ -56,7 +56,6 @@ ${DESIGN_RTL_DIR}/cve2_prefetch_buffer.sv
|
||||||
${DESIGN_RTL_DIR}/cve2_pmp.sv
|
${DESIGN_RTL_DIR}/cve2_pmp.sv
|
||||||
${DESIGN_RTL_DIR}/cve2_register_file_ff.sv
|
${DESIGN_RTL_DIR}/cve2_register_file_ff.sv
|
||||||
${DESIGN_RTL_DIR}/cve2_wb_stage.sv
|
${DESIGN_RTL_DIR}/cve2_wb_stage.sv
|
||||||
${DESIGN_RTL_DIR}/cve2_dummy_instr.sv
|
|
||||||
${DESIGN_RTL_DIR}/cve2_core.sv
|
${DESIGN_RTL_DIR}/cve2_core.sv
|
||||||
${DESIGN_RTL_DIR}/cve2_top.sv
|
${DESIGN_RTL_DIR}/cve2_top.sv
|
||||||
${DESIGN_RTL_DIR}/cve2_top_tracing.sv
|
${DESIGN_RTL_DIR}/cve2_top_tracing.sv
|
||||||
|
|
|
@ -13,14 +13,10 @@ small:
|
||||||
RV32B : "cve2_pkg::RV32BNone"
|
RV32B : "cve2_pkg::RV32BNone"
|
||||||
RegFile : "cve2_pkg::RegFileFF"
|
RegFile : "cve2_pkg::RegFileFF"
|
||||||
WritebackStage : 0
|
WritebackStage : 0
|
||||||
ICache : 0
|
|
||||||
ICacheECC : 0
|
|
||||||
BranchPredictor : 0
|
BranchPredictor : 0
|
||||||
PMPEnable : 0
|
PMPEnable : 0
|
||||||
PMPGranularity : 0
|
PMPGranularity : 0
|
||||||
PMPNumRegions : 4
|
PMPNumRegions : 4
|
||||||
SecureCVE2 : 0
|
|
||||||
ICacheScramble : 0
|
|
||||||
|
|
||||||
# Configuration to match that used in the OpenTitan project
|
# Configuration to match that used in the OpenTitan project
|
||||||
opentitan:
|
opentitan:
|
||||||
|
@ -29,14 +25,10 @@ opentitan:
|
||||||
RV32B : "cve2_pkg::RV32BOTEarlGrey"
|
RV32B : "cve2_pkg::RV32BOTEarlGrey"
|
||||||
RegFile : "cve2_pkg::RegFileFF"
|
RegFile : "cve2_pkg::RegFileFF"
|
||||||
WritebackStage : 1
|
WritebackStage : 1
|
||||||
ICache : 1
|
|
||||||
ICacheECC : 1
|
|
||||||
BranchPredictor : 0
|
BranchPredictor : 0
|
||||||
PMPEnable : 1
|
PMPEnable : 1
|
||||||
PMPGranularity : 0
|
PMPGranularity : 0
|
||||||
PMPNumRegions : 16
|
PMPNumRegions : 16
|
||||||
SecureCVE2 : 1
|
|
||||||
ICacheScramble : 0
|
|
||||||
|
|
||||||
# ===============================
|
# ===============================
|
||||||
# * EXPERIMENTAL CONFIGURATIONS *
|
# * EXPERIMENTAL CONFIGURATIONS *
|
||||||
|
@ -51,14 +43,10 @@ experimental-maxperf:
|
||||||
RV32B : "cve2_pkg::RV32BNone"
|
RV32B : "cve2_pkg::RV32BNone"
|
||||||
RegFile : "cve2_pkg::RegFileFF"
|
RegFile : "cve2_pkg::RegFileFF"
|
||||||
WritebackStage : 1
|
WritebackStage : 1
|
||||||
ICache : 0
|
|
||||||
ICacheECC : 0
|
|
||||||
BranchPredictor : 0
|
BranchPredictor : 0
|
||||||
PMPEnable : 0
|
PMPEnable : 0
|
||||||
PMPGranularity : 0
|
PMPGranularity : 0
|
||||||
PMPNumRegions : 4
|
PMPNumRegions : 4
|
||||||
SecureCVE2 : 0
|
|
||||||
ICacheScramble : 0
|
|
||||||
|
|
||||||
# experimental-maxperf config above plus PMP enabled with 16 regions.
|
# experimental-maxperf config above plus PMP enabled with 16 regions.
|
||||||
experimental-maxperf-pmp:
|
experimental-maxperf-pmp:
|
||||||
|
@ -67,14 +55,10 @@ experimental-maxperf-pmp:
|
||||||
RV32B : "cve2_pkg::RV32BNone"
|
RV32B : "cve2_pkg::RV32BNone"
|
||||||
RegFile : "cve2_pkg::RegFileFF"
|
RegFile : "cve2_pkg::RegFileFF"
|
||||||
WritebackStage : 1
|
WritebackStage : 1
|
||||||
ICache : 0
|
|
||||||
ICacheECC : 0
|
|
||||||
BranchPredictor : 0
|
BranchPredictor : 0
|
||||||
PMPEnable : 1
|
PMPEnable : 1
|
||||||
PMPGranularity : 0
|
PMPGranularity : 0
|
||||||
PMPNumRegions : 16
|
PMPNumRegions : 16
|
||||||
SecureCVE2 : 0
|
|
||||||
ICacheScramble : 0
|
|
||||||
|
|
||||||
# experimental-maxperf-pmp config above with balanced bitmanip extension
|
# experimental-maxperf-pmp config above with balanced bitmanip extension
|
||||||
experimental-maxperf-pmp-bmbalanced:
|
experimental-maxperf-pmp-bmbalanced:
|
||||||
|
@ -83,14 +67,10 @@ experimental-maxperf-pmp-bmbalanced:
|
||||||
RV32B : "cve2_pkg::RV32BBalanced"
|
RV32B : "cve2_pkg::RV32BBalanced"
|
||||||
RegFile : "cve2_pkg::RegFileFF"
|
RegFile : "cve2_pkg::RegFileFF"
|
||||||
WritebackStage : 1
|
WritebackStage : 1
|
||||||
ICache : 0
|
|
||||||
ICacheECC : 0
|
|
||||||
BranchPredictor : 0
|
BranchPredictor : 0
|
||||||
PMPEnable : 1
|
PMPEnable : 1
|
||||||
PMPGranularity : 0
|
PMPGranularity : 0
|
||||||
PMPNumRegions : 16
|
PMPNumRegions : 16
|
||||||
SecureCVE2 : 0
|
|
||||||
ICacheScramble : 0
|
|
||||||
|
|
||||||
# experimental-maxperf-pmp config above with full bitmanip extension
|
# experimental-maxperf-pmp config above with full bitmanip extension
|
||||||
experimental-maxperf-pmp-bmfull:
|
experimental-maxperf-pmp-bmfull:
|
||||||
|
@ -99,30 +79,10 @@ experimental-maxperf-pmp-bmfull:
|
||||||
RV32B : "cve2_pkg::RV32BFull"
|
RV32B : "cve2_pkg::RV32BFull"
|
||||||
RegFile : "cve2_pkg::RegFileFF"
|
RegFile : "cve2_pkg::RegFileFF"
|
||||||
WritebackStage : 1
|
WritebackStage : 1
|
||||||
ICache : 0
|
|
||||||
ICacheECC : 0
|
|
||||||
BranchPredictor : 0
|
BranchPredictor : 0
|
||||||
PMPEnable : 1
|
PMPEnable : 1
|
||||||
PMPGranularity : 0
|
PMPGranularity : 0
|
||||||
PMPNumRegions : 16
|
PMPNumRegions : 16
|
||||||
SecureCVE2 : 0
|
|
||||||
ICacheScramble : 0
|
|
||||||
|
|
||||||
# experimental-maxperf-pmp-bmfull config above with icache enabled
|
|
||||||
experimental-maxperf-pmp-bmfull-icache:
|
|
||||||
RV32E : 0
|
|
||||||
RV32M : "cve2_pkg::RV32MSingleCycle"
|
|
||||||
RV32B : "cve2_pkg::RV32BFull"
|
|
||||||
RegFile : "cve2_pkg::RegFileFF"
|
|
||||||
WritebackStage : 1
|
|
||||||
ICache : 1
|
|
||||||
ICacheECC : 1
|
|
||||||
BranchPredictor : 0
|
|
||||||
PMPEnable : 1
|
|
||||||
PMPGranularity : 0
|
|
||||||
PMPNumRegions : 16
|
|
||||||
SecureCVE2 : 0
|
|
||||||
ICacheScramble : 0
|
|
||||||
|
|
||||||
# experimental-maxperf with branch predictor switched on. This exists to allow
|
# experimental-maxperf with branch predictor switched on. This exists to allow
|
||||||
# easy use of Ibex with the branch predictor in particular for CI runs. The
|
# easy use of Ibex with the branch predictor in particular for CI runs. The
|
||||||
|
@ -134,12 +94,8 @@ experimental-branch-predictor:
|
||||||
RV32B : "cve2_pkg::RV32BNone"
|
RV32B : "cve2_pkg::RV32BNone"
|
||||||
RegFile : "cve2_pkg::RegFileFF"
|
RegFile : "cve2_pkg::RegFileFF"
|
||||||
WritebackStage : 1
|
WritebackStage : 1
|
||||||
ICache : 0
|
|
||||||
ICacheECC : 0
|
|
||||||
BranchPredictor : 1
|
BranchPredictor : 1
|
||||||
PMPEnable : 0
|
PMPEnable : 0
|
||||||
PMPGranularity : 0
|
PMPGranularity : 0
|
||||||
PMPNumRegions : 4
|
PMPNumRegions : 4
|
||||||
SecureCVE2 : 0
|
|
||||||
ICacheScramble : 0
|
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,6 @@ filesets:
|
||||||
- rtl/cve2_register_file_ff.sv # generic FF-based
|
- rtl/cve2_register_file_ff.sv # generic FF-based
|
||||||
- rtl/cve2_register_file_fpga.sv # FPGA
|
- rtl/cve2_register_file_fpga.sv # FPGA
|
||||||
- rtl/cve2_register_file_latch.sv # ASIC
|
- rtl/cve2_register_file_latch.sv # ASIC
|
||||||
- rtl/cve2_lockstep.sv
|
|
||||||
- rtl/cve2_top.sv
|
- rtl/cve2_top.sv
|
||||||
file_type: systemVerilogSource
|
file_type: systemVerilogSource
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@ Core Integration
|
||||||
|
|
||||||
The main module is named ``cve2_top`` and can be found in ``cve2_top.sv``.
|
The main module is named ``cve2_top`` and can be found in ``cve2_top.sv``.
|
||||||
Note that the core logic is split-out from the register file and RAMs under ``cve2_top``.
|
Note that the core logic is split-out from the register file and RAMs under ``cve2_top``.
|
||||||
This is to facilitate a dual-core lockstep implementation (see :ref:`security`).
|
|
||||||
|
|
||||||
Below, the instantiation template is given and the parameters and interfaces are described.
|
Below, the instantiation template is given and the parameters and interfaces are described.
|
||||||
|
|
||||||
|
@ -20,11 +19,7 @@ Instantiation Template
|
||||||
.RV32E ( 0 ),
|
.RV32E ( 0 ),
|
||||||
.RV32M ( cve2_pkg::RV32MFast ),
|
.RV32M ( cve2_pkg::RV32MFast ),
|
||||||
.RegFile ( cve2_pkg::RegFileFF ),
|
.RegFile ( cve2_pkg::RegFileFF ),
|
||||||
.ICache ( 0 ),
|
|
||||||
.ICacheECC ( 0 ),
|
|
||||||
.ICacheScramble ( 0 ),
|
|
||||||
.BranchPrediction ( 0 ),
|
.BranchPrediction ( 0 ),
|
||||||
.SecureIbex ( 0 ),
|
|
||||||
.RndCnstLfsrSeed ( cve2_pkg::RndCnstLfsrSeedDefault ),
|
.RndCnstLfsrSeed ( cve2_pkg::RndCnstLfsrSeedDefault ),
|
||||||
.RndCnstLfsrPerm ( cve2_pkg::RndCnstLfsrPermDefault ),
|
.RndCnstLfsrPerm ( cve2_pkg::RndCnstLfsrPermDefault ),
|
||||||
.DmHaltAddr ( 32'h1A110800 ),
|
.DmHaltAddr ( 32'h1A110800 ),
|
||||||
|
@ -108,27 +103,8 @@ Parameters
|
||||||
| ``WritebackStage`` | bit | 0 | *EXPERIMENTAL* - Enables third pipeline stage (writeback) |
|
| ``WritebackStage`` | bit | 0 | *EXPERIMENTAL* - Enables third pipeline stage (writeback) |
|
||||||
| | | | improving performance of loads and stores |
|
| | | | improving performance of loads and stores |
|
||||||
+------------------------------+---------------------+------------+-----------------------------------------------------------------------+
|
+------------------------------+---------------------+------------+-----------------------------------------------------------------------+
|
||||||
| ``ICache`` | bit | 0 | *EXPERIMENTAL* Enable instruction cache instead of prefetch |
|
|
||||||
| | | | buffer |
|
|
||||||
+------------------------------+---------------------+------------+-----------------------------------------------------------------------+
|
|
||||||
| ``ICacheECC`` | bit | 0 | *EXPERIMENTAL* Enable SECDED ECC protection in ICache (if |
|
|
||||||
| | | | ICache == 1) |
|
|
||||||
+------------------------------+---------------------+------------+-----------------------------------------------------------------------+
|
|
||||||
| ``ICacheScramble`` | bit | 0 | *EXPERIMENTAL* Enabling this parameter replaces tag and data RAMs of |
|
|
||||||
| | | | ICache with scrambling RAM primitives. |
|
|
||||||
+------------------------------+---------------------+------------+-----------------------------------------------------------------------+
|
|
||||||
| ``BranchPrediction`` | bit | 0 | *EXPERIMENTAL* Enable Static branch prediction |
|
| ``BranchPrediction`` | bit | 0 | *EXPERIMENTAL* Enable Static branch prediction |
|
||||||
+------------------------------+---------------------+------------+-----------------------------------------------------------------------+
|
+------------------------------+---------------------+------------+-----------------------------------------------------------------------+
|
||||||
| ``SecureIbex`` | bit | 0 | *EXPERIMENTAL* Enable various additional features targeting |
|
|
||||||
| | | | secure code execution. Note: SecureIbex == 1'b1 and |
|
|
||||||
| | | | RV32M == cve2_pkg::RV32MNone is an illegal combination. |
|
|
||||||
+------------------------------+---------------------+------------+-----------------------------------------------------------------------+
|
|
||||||
| ``RndCnstLfsrSeed`` | lfsr_seed_t | see above | Set the starting seed of the LFSR used to generate dummy instructions |
|
|
||||||
| | | | (only relevant when SecureIbex == 1'b1) |
|
|
||||||
+------------------------------+---------------------+------------+-----------------------------------------------------------------------+
|
|
||||||
| ``RndCnstLfsrPerm`` | lfsr_perm_t | see above | Set the permutation applied to the output of the LFSR used to |
|
|
||||||
| | | | generate dummy instructions (only relevant when SecureIbex == 1'b1) |
|
|
||||||
+------------------------------+---------------------+------------+-----------------------------------------------------------------------+
|
|
||||||
| ``DmHaltAddr`` | int | 0x1A110800 | Address to jump to when entering Debug Mode |
|
| ``DmHaltAddr`` | int | 0x1A110800 | Address to jump to when entering Debug Mode |
|
||||||
+------------------------------+---------------------+------------+-----------------------------------------------------------------------+
|
+------------------------------+---------------------+------------+-----------------------------------------------------------------------+
|
||||||
| ``DmExceptionAddr`` | int | 0x1A110808 | Address to jump to when an exception occurs while in Debug Mode |
|
| ``DmExceptionAddr`` | int | 0x1A110808 | Address to jump to when an exception occurs while in Debug Mode |
|
||||||
|
@ -162,9 +138,6 @@ Interfaces
|
||||||
| ``scan_rst_ni`` | 1 | in | Test controlled reset. If DFT not |
|
| ``scan_rst_ni`` | 1 | in | Test controlled reset. If DFT not |
|
||||||
| | | | used, tie off to 1. |
|
| | | | used, tie off to 1. |
|
||||||
+----------------------------+-------------------------+-----+----------------------------------------+
|
+----------------------------+-------------------------+-----+----------------------------------------+
|
||||||
| ``ram_cfg_i`` | 10 | in | RAM configuration inputs, routed to |
|
|
||||||
| | | | the icache RAMs |
|
|
||||||
+----------------------------+-------------------------+-----+----------------------------------------+
|
|
||||||
| ``hart_id_i`` | 32 | in | Hart ID, usually static, can be read |
|
| ``hart_id_i`` | 32 | in | Hart ID, usually static, can be read |
|
||||||
| | | | from :ref:`csr-mhartid` CSR |
|
| | | | from :ref:`csr-mhartid` CSR |
|
||||||
+----------------------------+-------------------------+-----+----------------------------------------+
|
+----------------------------+-------------------------+-----+----------------------------------------+
|
||||||
|
@ -178,8 +151,6 @@ Interfaces
|
||||||
+----------------------------+------------------------------------------------------------------------+
|
+----------------------------+------------------------------------------------------------------------+
|
||||||
| ``irq_*`` | Interrupt inputs, see :ref:`exceptions-interrupts` |
|
| ``irq_*`` | Interrupt inputs, see :ref:`exceptions-interrupts` |
|
||||||
+----------------------------+-------------------------+-----+----------------------------------------+
|
+----------------------------+-------------------------+-----+----------------------------------------+
|
||||||
| ``scramble_*`` | Scrambling key interface, see :ref:`icache` |
|
|
||||||
+----------------------------+------------------------------------------------------------------------+
|
|
||||||
| ``debug_*`` | Debug interface, see :ref:`debug-support` |
|
| ``debug_*`` | Debug interface, see :ref:`debug-support` |
|
||||||
+----------------------------+------------------------------------------------------------------------+
|
+----------------------------+------------------------------------------------------------------------+
|
||||||
| ``crash_dump_o`` | A set of signals that can be captured on reset to aid crash debugging. |
|
| ``crash_dump_o`` | A set of signals that can be captured on reset to aid crash debugging. |
|
||||||
|
|
|
@ -46,7 +46,7 @@ Ibex implements all the Control and Status Registers (CSRs) listed in the follow
|
||||||
+---------+--------------------+--------+-----------------------------------------------+
|
+---------+--------------------+--------+-----------------------------------------------+
|
||||||
| 0x3BF | ``pmpaddr15`` | WARL | PMP Address Register |
|
| 0x3BF | ``pmpaddr15`` | WARL | PMP Address Register |
|
||||||
+---------+--------------------+--------+-----------------------------------------------+
|
+---------+--------------------+--------+-----------------------------------------------+
|
||||||
| 0x747 | ``mseccfg`` | WARL | Machine Security Configuration |
|
| . . . . |
|
||||||
+---------+--------------------+--------+-----------------------------------------------+
|
+---------+--------------------+--------+-----------------------------------------------+
|
||||||
| 0x757 | ``mseccfgh`` | WARL | Upper 32 bits of ``mseccfg`` |
|
| 0x757 | ``mseccfgh`` | WARL | Upper 32 bits of ``mseccfg`` |
|
||||||
+---------+--------------------+--------+-----------------------------------------------+
|
+---------+--------------------+--------+-----------------------------------------------+
|
||||||
|
@ -72,7 +72,7 @@ Ibex implements all the Control and Status Registers (CSRs) listed in the follow
|
||||||
+---------+--------------------+--------+-----------------------------------------------+
|
+---------+--------------------+--------+-----------------------------------------------+
|
||||||
| 0x7C0 | ``cpuctrl`` | WARL | CPU Control Register (Custom CSR) |
|
| 0x7C0 | ``cpuctrl`` | WARL | CPU Control Register (Custom CSR) |
|
||||||
+---------+--------------------+--------+-----------------------------------------------+
|
+---------+--------------------+--------+-----------------------------------------------+
|
||||||
| 0x7C1 | ``secureseed`` | WARL | Security feature random seed (Custom CSR) |
|
| . . . . |
|
||||||
+---------+--------------------+--------+-----------------------------------------------+
|
+---------+--------------------+--------+-----------------------------------------------+
|
||||||
| 0xB00 | ``mcycle`` | RW | Machine Cycle Counter |
|
| 0xB00 | ``mcycle`` | RW | Machine Cycle Counter |
|
||||||
+---------+--------------------+--------+-----------------------------------------------+
|
+---------+--------------------+--------+-----------------------------------------------+
|
||||||
|
@ -308,29 +308,6 @@ Reset Value: ``0x0000_0000``
|
||||||
| address[33:2] |
|
| address[33:2] |
|
||||||
+----------------+
|
+----------------+
|
||||||
|
|
||||||
Machine Security Configuration (mseccfg/mseccfgh)
|
|
||||||
-------------------------------------------------
|
|
||||||
|
|
||||||
CSR Address: ``mseccfg``: ``0x747`` ``mseccfg``: ``0x757``
|
|
||||||
|
|
||||||
Reset Value: ``0x0000_0000_0000_0000``
|
|
||||||
|
|
||||||
+------+-----------------------------------------------------------------------------------------------------------------------------------+
|
|
||||||
| Bit# | Definition |
|
|
||||||
+------+-----------------------------------------------------------------------------------------------------------------------------------+
|
|
||||||
| 2 | **Rule Locking Bypass (RLB):** If set locked PMP entries can be modified |
|
|
||||||
+------+-----------------------------------------------------------------------------------------------------------------------------------+
|
|
||||||
| 1 | **Machine Mode Whitelist Policy (MMWP):** If set default policy for PMP is deny for M-Mode accesses that don't match a PMP region |
|
|
||||||
+------+-----------------------------------------------------------------------------------------------------------------------------------+
|
|
||||||
| 0 | **Machine Mode Lockdown (MML):** Alters behaviour of ``pmpcfgX`` bits |
|
|
||||||
+------+-----------------------------------------------------------------------------------------------------------------------------------+
|
|
||||||
|
|
||||||
``mseccfg`` is specified in the Trusted Execution Environment (TEE) working group proposal `PMP Enhancements for memory access and execution prevention on Machine mode (Smepmp) version 0.9.3 <https://github.com/riscv/riscv-tee/blob/61455747230a26002d741f64879dd78cc9689323/Smepmp/Smepmp.pdf>`_, which gives the full details of it's functionality including the new PMP behaviour when ``mseccfg.MML`` is set.
|
|
||||||
Note that the reset value means PMP behavior out of reset matches the RISC-V Privileged Architecture.
|
|
||||||
A write to ``mseccfg`` is required to change it.
|
|
||||||
Note ``mseccfgh`` reads as all 0s and ignores all writes.
|
|
||||||
Any access to ``mseccfg`` or ``mseccfgh`` when using an Ibex configuration without PMP (localparam ``PMPEnable`` set to 0) will trigger an illegal instruction exception.
|
|
||||||
|
|
||||||
.. _csr-tselect:
|
.. _csr-tselect:
|
||||||
|
|
||||||
Trigger Select Register (tselect)
|
Trigger Select Register (tselect)
|
||||||
|
@ -547,39 +524,12 @@ Other bit fields read as zero.
|
||||||
| | | This flag is cleared when ``mret`` is executed. |
|
| | | This flag is cleared when ``mret`` is executed. |
|
||||||
| | | (see :ref:`double-fault-detect`). |
|
| | | (see :ref:`double-fault-detect`). |
|
||||||
+-------+------+------------------------------------------------------------------+
|
+-------+------+------------------------------------------------------------------+
|
||||||
| 5:3 | WARL | **dummy_instr_mask:** Mask to control frequency of dummy |
|
| 5:3 | WARL | This field will always read as zero. |
|
||||||
| | | instruction insertion. If the core has not been configured with |
|
|
||||||
| | | security features (SecureIbex parameter == 0), this field will |
|
|
||||||
| | | always read as zero (see :ref:`security`). |
|
|
||||||
+-------+------+------------------------------------------------------------------+
|
+-------+------+------------------------------------------------------------------+
|
||||||
| 2 | WARL | **dummy_instr_en:** Enable (1) or disable (0) dummy instruction |
|
| 2 | WARL | This field will always read as zero. |
|
||||||
| | | insertion features. If the core has not been configured with |
|
|
||||||
| | | security features (SecureIbex parameter == 0), this field will |
|
|
||||||
| | | always read as zero (see :ref:`security`). |
|
|
||||||
+-------+------+------------------------------------------------------------------+
|
+-------+------+------------------------------------------------------------------+
|
||||||
| 1 | WARL | **data_ind_timing:** Enable (1) or disable (0) data-independent |
|
| 1 | WARL | This field will always read as zero. |
|
||||||
| | | timing features. If the core has not been configured with |
|
|
||||||
| | | security features (SecureIbex parameter == 0), this field will |
|
|
||||||
| | | always read as zero. |
|
|
||||||
+-------+------+------------------------------------------------------------------+
|
+-------+------+------------------------------------------------------------------+
|
||||||
| 0 | WARL | **icache_enable:** Enable (1) or disable (0) the instruction |
|
|
||||||
| | | cache. If the instruction cache has not been configured (ICache |
|
|
||||||
| | | parameter == 0), this field will always read as zero. |
|
|
||||||
+-------+------+------------------------------------------------------------------+
|
|
||||||
|
|
||||||
Security Feature Seed Register (secureseed)
|
|
||||||
-------------------------------------------
|
|
||||||
|
|
||||||
CSR Address: ``0x7C1``
|
|
||||||
|
|
||||||
Reset Value: ``0x0000_0000``
|
|
||||||
|
|
||||||
Accessible in Machine Mode only.
|
|
||||||
|
|
||||||
Custom CSR to allow re-seeding of security-related pseudo-random number generators.
|
|
||||||
A write to this register will update the seeding of pseudo-random number generators inside the design.
|
|
||||||
This allows software to improve the randomness, and therefore security, of certain features by periodically reading from a true random number generator peripheral.
|
|
||||||
Seed values are not actually stored in a register and so reads to this register will always return zero.
|
|
||||||
|
|
||||||
Time Registers (time(h))
|
Time Registers (time(h))
|
||||||
------------------------
|
------------------------
|
||||||
|
|
|
@ -1,278 +0,0 @@
|
||||||
.. _icache:
|
|
||||||
|
|
||||||
Instruction Cache
|
|
||||||
=================
|
|
||||||
:file:`rtl/cve2_icache.sv.`
|
|
||||||
|
|
||||||
NOTE - This module is currently DRAFT
|
|
||||||
|
|
||||||
The optional Instruction Cache (I$) is designed to improve CPU performance in systems with high instruction memory latency.
|
|
||||||
The I$ integrates into the CPU by replacing the prefetch buffer, interfacing directly between the bus and IF stage.
|
|
||||||
|
|
||||||
High-level operation
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
The I$ passes instructions to the core using a ready / valid interface.
|
|
||||||
Inside the cache is an address counter, which increments for every instruction fetched (by 2 or 4 bytes, depending on whether the instruction contents show it to be compressed).
|
|
||||||
When the core takes a branch, it resets the counter to a new address by raising the ``branch_i`` signal and supplying the new address on ``addr_i``.
|
|
||||||
The next instruction returned by the cache will be the instruction at this new address.
|
|
||||||
|
|
||||||
The I$ communicates with instruction memory using an interface that matches the IF stage (allowing the cache to be enabled or disabled without needing to change the Ibex toplevel's interface). For more details of this interface, see :ref:`instruction-fetch`.
|
|
||||||
|
|
||||||
To avoid the cache fetching needlessly when the core is asleep (after a ``wfi`` instruction), it has a ``req_i`` input. Shortly after this goes low, the cache will stop making memory transactions.
|
|
||||||
|
|
||||||
If the ``icache_enable_i`` input is low, the cache operates in pass-through mode, where every requested instruction is fetched from memory and no results are cached.
|
|
||||||
|
|
||||||
In order to invalidate the cache, the core can raise the ``icache_inval_i`` line for one or more cycles, which will start an internal cache invalidation.
|
|
||||||
No fetches are cached while the invalidation is taking place (behaving as if ``icache_enable_i`` is low).
|
|
||||||
|
|
||||||
While the I$ is busy, either (pre)fetching data or invalidating its memory, it raises the ``busy_o`` signal.
|
|
||||||
This can be used to avoid the cache's clock being gated when it is doing something.
|
|
||||||
|
|
||||||
|
|
||||||
Configuration options
|
|
||||||
---------------------
|
|
||||||
|
|
||||||
The following table describes the available configuration parameters.
|
|
||||||
|
|
||||||
+-------------------------+-----------+-----------------------------------------------+
|
|
||||||
| Parameter | Default | Description |
|
|
||||||
+=========================+===========+===============================================+
|
|
||||||
| ``BusWidth`` | ``32`` | Width of instruction bus. Note, this is fixed |
|
|
||||||
| | | at 32 for Ibex at the moment. |
|
|
||||||
+-------------------------+-----------+-----------------------------------------------+
|
|
||||||
| ``CacheSizeBytes`` | ``4kB`` | Size of cache in bytes. |
|
|
||||||
+-------------------------+-----------+-----------------------------------------------+
|
|
||||||
| ``CacheECC`` | ``1'b0`` | Enable SECDED ECC protection in tag and data |
|
|
||||||
| | | RAMs. |
|
|
||||||
+-------------------------+-----------+-----------------------------------------------+
|
|
||||||
| ``LineSize`` | ``64`` | The width of one cache line in bits. |
|
|
||||||
| | | Line sizes smaller than 64 bits may give |
|
|
||||||
| | | compilation errors. |
|
|
||||||
+-------------------------+-----------+-----------------------------------------------+
|
|
||||||
| ``NumWays`` | ``2`` | The number of ways. |
|
|
||||||
+-------------------------+-----------+-----------------------------------------------+
|
|
||||||
| ``BranchCache`` | ``1'b0`` | When set, the cache will only allocate the |
|
|
||||||
| | | targets of branches + two subsequent cache |
|
|
||||||
| | | lines. This gives improved performance in |
|
|
||||||
| | | systems with moderate latency by not |
|
|
||||||
| | | polluting the cache with data that can be |
|
|
||||||
| | | prefetched instead. |
|
|
||||||
| | | When not set, all misses are allocated. |
|
|
||||||
+-------------------------+-----------+-----------------------------------------------+
|
|
||||||
|
|
||||||
Performance notes
|
|
||||||
-----------------
|
|
||||||
|
|
||||||
Note that although larger cache line sizes allow for better area efficiency (lower tagram area overhead), there is a performance penalty.
|
|
||||||
When the core branches to an address that is not aligned to the bottom of a cache line (and the request misses in the cache), the I$ will attempt to fetch this address first from the bus.
|
|
||||||
The I$ will then fetch the rest of the remaining beats of data in wrapping address order to complete the cache line (in order to allocate it to the cache).
|
|
||||||
While these lower addresses are being fetched, the core is starved of data.
|
|
||||||
Based on current experimental results, a line size of 64 bits gives the best performance.
|
|
||||||
|
|
||||||
In cases where the core branches to addresses currently being prefetched, the same line can end up allocated to the cache in multiple ways.
|
|
||||||
This causes a minor performance inefficiency, but should not happen often in practice.
|
|
||||||
|
|
||||||
RAM Arrangement
|
|
||||||
---------------
|
|
||||||
|
|
||||||
The data RAMs are arranged as ``NumWays`` banks of ``LineSize`` width.
|
|
||||||
If ECC is configured, the tag and data banks will be wider to accomodate the extra checkbits.
|
|
||||||
|
|
||||||
Indicative RAM sizes for common configurations are given in the table below:
|
|
||||||
|
|
||||||
+------------------------------+-----------------+------------------+
|
|
||||||
| Cache config | Tag RAMs | Data RAMs |
|
|
||||||
+==============================+=================+==================+
|
|
||||||
| 4kB, 2 way, 64bit line | 2 x 256 x 22bit | 2 x 256 x 64bit |
|
|
||||||
+------------------------------+-----------------+------------------+
|
|
||||||
| 4kB, 2 way, 64bit line w/ECC | 2 x 256 x 28bit | 2 x 256 x 72bit |
|
|
||||||
+------------------------------+-----------------+------------------+
|
|
||||||
| 4kB, 2 way, 128bit line | 2 x 128 x 22bit | 2 x 128 x 128bit |
|
|
||||||
+------------------------------+-----------------+------------------+
|
|
||||||
| 4kB, 4 way, 64bit line | 4 x 128 x 22bit | 4 x 128 x 64bit |
|
|
||||||
+------------------------------+-----------------+------------------+
|
|
||||||
|
|
||||||
If ICacheScramble parameter is enabled, all RAM primitives are replaced with scrambling RAM primitive.
|
|
||||||
For more information about how scrambling works internally (see :file:`vendor/lowrisc_ip/ip/prim/doc/prim_ram_1p_scr.md`).
|
|
||||||
Interface for receiving scrambling key follows req / ack protocol.
|
|
||||||
Ibex first requests a new ephemeral key by asserting the request (``scramble_req_o``) and when a fresh valid key is indicated by ``scramble_key_valid_i``, it deasserts the request.
|
|
||||||
Note that in current implementation, it is assumed req/ack protocol is synchronized before arriving to Ibex top level.
|
|
||||||
|
|
||||||
Sub Unit Description
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
.. figure:: images/icache_block.svg
|
|
||||||
:name: icache_block
|
|
||||||
:align: center
|
|
||||||
|
|
||||||
Instruction Cache Block Diagram
|
|
||||||
|
|
||||||
Prefetch Address
|
|
||||||
^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
The prefetch address is updated to the branch target on every branch.
|
|
||||||
This address is then updated in cache-line increments each time a cache lookup is issued to the cache pipeline.
|
|
||||||
|
|
||||||
Cache Pipeline
|
|
||||||
^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
The cache pipeline consists of two stages, IC0 and IC1.
|
|
||||||
|
|
||||||
In IC0, lookup requests are arbitrated against cache allocation requests.
|
|
||||||
Lookup requests have highest priority since they naturally throttle themselves as fill buffer resources run out.
|
|
||||||
The arbitrated request is made to the RAMs in IC0.
|
|
||||||
|
|
||||||
In IC1, data from the RAMs are available and the cache hit status is determined.
|
|
||||||
Hit data is multiplexed from the data RAMs based on the hitting way.
|
|
||||||
If there was a cache miss, the victim way is chosen pseudo-randomly using a counter.
|
|
||||||
|
|
||||||
Fill buffers
|
|
||||||
^^^^^^^^^^^^
|
|
||||||
|
|
||||||
The fill buffers perform several functions in the I$ and constitute most of it's complexity.
|
|
||||||
|
|
||||||
* Since external requests can be made speculatively in parallel with the cache lookup, a fill buffer must be allocated in IC0 to track the request.
|
|
||||||
* The fill buffers are used as data storage for hitting requests as well as for miss tracking so all lookup requests require a fill buffer.
|
|
||||||
* A fill buffer makes multiple external requests to memory to fetch the required data to fill a cache line (tracked via ``fill_ext_cnt_q``).
|
|
||||||
* Returning data is tracked via ``fill_rvd_cnt_q``.
|
|
||||||
Not all requests will fetch all their data, since requests can be cancelled due to a cache hit or an intervening branch.
|
|
||||||
* If a fill buffer has not made any external requests it will be cancelled by an intervening branch, if it has made requests then the requests will be completed and the line allocated.
|
|
||||||
* Beats of data are supplied to the IF stage, tracked via ``fill_out_cnt_q``.
|
|
||||||
* If the line is due to be allocated into the cache, it will request for arbitration once all data has been received.
|
|
||||||
* Once all required actions are complete, the fill buffer releases and becomes available for a new request.
|
|
||||||
|
|
||||||
Since requests can perform actions out of order (cache hit in the shadow of an outstanding miss), and multiple requests can complete at the same time, the fill buffers are not a simple FIFO.
|
|
||||||
Each fill buffer maintains a matrix of which requests are older than it, and this is used for arbitrating between the fill buffers.
|
|
||||||
|
|
||||||
Data output
|
|
||||||
^^^^^^^^^^^
|
|
||||||
|
|
||||||
.. figure:: images/icache_mux.svg
|
|
||||||
:name: icache_mux
|
|
||||||
:align: center
|
|
||||||
|
|
||||||
Instruction Cache Data Multiplexing
|
|
||||||
|
|
||||||
Data supplied to the IF stage are multiplexed between cache-hit data, fill buffer data, and incoming memory data.
|
|
||||||
The fill buffers track which request should supply data, and where that data should come from.
|
|
||||||
Data from the cache and the fill buffers are of cache line width, which is multiplexed down to 32 bits and then multiplexed against data from the bus.
|
|
||||||
|
|
||||||
The fill buffers attempt to supply the relevant word of data to the IF stage as soon as possible.
|
|
||||||
Hitting requests will supply the first word directly from the RAMs in IC1 while demand misses will supply data directly from the bus.
|
|
||||||
The remaining data from hits is buffered in the fill buffer data storage and supplied to the IF stage as-required.
|
|
||||||
|
|
||||||
To deal with misalignment caused by compressed instructions, there is a 16bit skid buffer to store the upper halfword.
|
|
||||||
|
|
||||||
.. _icache-ecc:
|
|
||||||
|
|
||||||
Cache ECC protection
|
|
||||||
^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
When ECC protection is enabled, extra checkbits are appended to the top of the tag and data RAM write data as follows:
|
|
||||||
|
|
||||||
For the Tag RAMs (4kB cache):
|
|
||||||
|
|
||||||
+---------------+-----------+--------+
|
|
||||||
| ECC checkbits | Valid bit | Tag |
|
|
||||||
+---------------+-----------+--------+
|
|
||||||
| [27:22] | [21] | [20:0] |
|
|
||||||
+---------------+-----------+--------+
|
|
||||||
|
|
||||||
For the Data RAMs (64bit line):
|
|
||||||
|
|
||||||
+---------------+--------+
|
|
||||||
| ECC checkbits | Data |
|
|
||||||
+---------------+--------+
|
|
||||||
| [71:64] | [63:0] |
|
|
||||||
+---------------+--------+
|
|
||||||
|
|
||||||
The checkbits are generated by dedicated modules in IC0 before the RAMs are written.
|
|
||||||
In IC1, the RAM read data and checkbits are fed into dedicated modules which output whether there was an error.
|
|
||||||
Although the modules used have the required outputs to allow inline correction of single bit errors, the I$ does not make use of them since it never performs corrections.
|
|
||||||
|
|
||||||
Any error (single or double bit) in any RAM will effectively cancel a cache hit in IC1.
|
|
||||||
The request which observed an error will fetch it's data from the main instruction memory as normal for a cache miss.
|
|
||||||
The cache index and way (or ways) with errors are stored in IC1, and a cache write is forced the next cycle to invalidate that line.
|
|
||||||
Lookup requests will be blocked in IC0 while the invalidation write is performed.
|
|
||||||
If an ECC error is seen a minor alert will be signaled.
|
|
||||||
|
|
||||||
Cache invalidation
|
|
||||||
^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
After reset, and when requested by the core (due to a FENCE.I instruction), the whole cache is invalidated.
|
|
||||||
Requests are inserted to invalidate the tag RAM for all ways in each cache line in sequence.
|
|
||||||
While the invalidation is in-progress, lookups and instruction fetches can proceed, but nothing will be allocated to the cache.
|
|
||||||
|
|
||||||
Detailed behaviour
|
|
||||||
^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
This section describes the expected behaviour of the cache, in order to allow functional verification.
|
|
||||||
This isn't an attempt to describe the cache's performance characteristics.
|
|
||||||
|
|
||||||
The I$ has a single clock (``clk_i``) and asynchronous reset (``rst_ni``).
|
|
||||||
|
|
||||||
Data is requested from the instruction memory with the ports prefixed by ``instr_``. These work as described in :ref:`instruction-fetch`.
|
|
||||||
Note that there's one extra port on the I$, which doesn't appear at the ``cve2_top`` top-level.
|
|
||||||
This is ``instr_pmp_err_i``.
|
|
||||||
If the PMP block disallows a fetch for a certain address, it will squash the outgoing memory request entirely and set ``instr_pmp_err_i``.
|
|
||||||
If that happens, the cache drops ``instr_req_o`` and stops making any further requests for that cache line.
|
|
||||||
Note that it is possible for ``instr_gnt_i`` and ``instr_pmp_err_i`` to be high on the same cycle.
|
|
||||||
In that case, the error signal takes precedence.
|
|
||||||
|
|
||||||
Fetched instructions are returned to the core using ports ``ready_i``, ``valid_o``, ``rdata_o``, ``addr_o``, ``err_o`` and ``err_plus2_o``.
|
|
||||||
This interface uses a form of ready/valid handshaking.
|
|
||||||
A transaction is signalled by ready and valid being high.
|
|
||||||
If valid goes high, it will remain high and the other output signals will remain stable until the transaction goes through or is cancelled by ``branch_i`` being asserted.
|
|
||||||
The only exception is after an error is passed to the core. Once that has happened, there is no constraint on the values of ``valid_o``, ``rdata_o``, ``addr_o``, ``err_o`` and ``err_plus2_o`` until the next time ``branch_i`` is asserted.
|
|
||||||
There is no constraint on the behaviour of ``ready_i``.
|
|
||||||
|
|
||||||
The 32-bit wide ``rdata_o`` signal contains instruction data fetched from ``addr_o``.
|
|
||||||
An instruction is either 16 or 32 bits wide (called *compressed* or *uncompressed*, respectively).
|
|
||||||
The width of an instruction can be calculated from its bottom two bits: an instruction is uncompressed if they equal ``2'b11`` and compressed otherwise.
|
|
||||||
If there is a compressed instruction in the lower 16 bits, the upper 16 bits are unconstrained (and may change even after valid has been asserted).
|
|
||||||
The ``err_o`` signal will be high if the instruction fetch failed (either with ``instr_pmp_err_i`` or ``instr_err_i``); in this case ``rdata_o`` is not specified.
|
|
||||||
|
|
||||||
The ``req_i`` signal tells the cache that the core is awake and will start requesting instructions soon.
|
|
||||||
As well as the main cache memory, the I$ contains a prefetch buffer.
|
|
||||||
The cache fills this buffer by issuing fetches when ``req_i`` is high.
|
|
||||||
If ``req_i`` becomes false, the cache may do a few more instruction fetches to fill a cache line, but will stop fetching when that is done.
|
|
||||||
The cache will not do any instruction fetches after this until ``req_i`` goes high again.
|
|
||||||
A correctly behaving core should not not assert ``ready_i`` when ``req_i`` is low.
|
|
||||||
|
|
||||||
Inside the cache is an address counter.
|
|
||||||
If ``branch_i`` is asserted then the address counter will be set to ``addr_i`` and the next instruction that is passed to the core will be the one fetched from that address.
|
|
||||||
The address is required to be halfword aligned, so ``addr_i[0]`` must be zero.
|
|
||||||
The cache will also start reading into a new prefetch buffer, storing the current contents into the main cache memory or discarding it (see ``icache_enable_i`` below).
|
|
||||||
On cycles where ``branch_i`` is not asserted, the address counter will be incremented when an instruction is passed to the core.
|
|
||||||
This increment depends on the instruction data (visible at ``rdata_o``): it will be 2 if the instruction is compressed and 4 otherwise.
|
|
||||||
Since the contents of ``rdata_o`` are not specified if an instruction fetch has caused an error, the core must signal a branch before accepting another instruction after it sees ``err_o``.
|
|
||||||
|
|
||||||
There is an additional branch signal ``branch_spec_i`` which is a speculative version of the actual branch signal.
|
|
||||||
Internally, ``branch_spec_i`` is used to setup address multiplexing as it is available earlier in the cycle.
|
|
||||||
In cases where ``branch_spec_i`` is high, but ``branch_i`` is low, any lookup that might have been made that cycle is suppressed.
|
|
||||||
Note that if ``branch_i`` is high, ``branch_spec_i`` must also be high.
|
|
||||||
|
|
||||||
Because a single instruction can span two 32bit memory addresses, an extra signal (``err_plus2_o``) indicates when an error is caused by the second half of an unaligned uncompressed instruction.
|
|
||||||
This signal is only valid when ``valid_o`` and ``err_o`` are set, and will only be set for uncompressed instructions.
|
|
||||||
The core uses this signal to record the correct address in the ``mtval`` CSR upon an error.
|
|
||||||
|
|
||||||
Since the address counter is not initialised on reset, the behaviour of the I$ is unspecified unless ``branch_i`` is asserted on or before the first cycle that ``req_i`` is asserted after reset.
|
|
||||||
If that is not true, there's nothing to stop the cache fetching from random addresses.
|
|
||||||
|
|
||||||
The ``icache_enable_i`` signal controls whether the cache copies fetched data from the prefetch buffer to the main cache memory.
|
|
||||||
If the signal is false, fetched data will be discarded on a branch or after enough instructions have been consumed by the core.
|
|
||||||
On reset, or whenever ``icache_inval_i`` goes high, the cache will invalidate its stored data.
|
|
||||||
While doing this, the cache behaves as if ``icache_enable_i`` is false and will not store any fetched data.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
The rules for ``icache_enable_i`` and ``icache_inval_i`` mean that, in order to be completely sure of executing newly fetched code, the core should raise the ``icache_inval_i`` line for at least a cycle and then should branch. The Ibex core does this in response to a ``FENCE.I`` instruction, branching explicitly to the next PC.
|
|
||||||
|
|
||||||
The ``busy_o`` signal is guaranteed to be high while the cache is invalidating its internal memories or whenever it has a pending fetch on the instruction bus.
|
|
||||||
When the ``busy_o`` signal is low, it is safe to clock gate the cache.
|
|
||||||
|
|
||||||
The cache doesn't have circuitry to avoid inconsistent multi-way hits.
|
|
||||||
As such, the core must never fetch from an address with the cache enabled after modifying the data at that address, without first starting a cache invalidation.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
This is a constraint on *software*, not just on the core.
|
|
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 39 KiB |
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 39 KiB |
|
@ -9,7 +9,6 @@ It describes the design in detail, discusses the verification approach and the r
|
||||||
:caption: In this section
|
:caption: In this section
|
||||||
|
|
||||||
pipeline_details
|
pipeline_details
|
||||||
icache
|
|
||||||
instruction_fetch
|
instruction_fetch
|
||||||
instruction_decode_execute
|
instruction_decode_execute
|
||||||
load_store_unit
|
load_store_unit
|
||||||
|
@ -18,7 +17,6 @@ It describes the design in detail, discusses the verification approach and the r
|
||||||
performance_counters
|
performance_counters
|
||||||
exception_interrupts
|
exception_interrupts
|
||||||
pmp
|
pmp
|
||||||
security
|
|
||||||
debug
|
debug
|
||||||
tracer
|
tracer
|
||||||
verification
|
verification
|
||||||
|
|
|
@ -21,11 +21,6 @@ A localparam ``DEPTH`` gives a configurable depth which is set to 3 by default.
|
||||||
The top-level of the instruction fetch controls the prefetch buffer (in particular flushing it on branches/jumps/exception and beginning prefetching from the appropriate new PC) and supplies new instructions to the ID/EX stage along with their PC.
|
The top-level of the instruction fetch controls the prefetch buffer (in particular flushing it on branches/jumps/exception and beginning prefetching from the appropriate new PC) and supplies new instructions to the ID/EX stage along with their PC.
|
||||||
Compressed instructions are expanded by the IF stage so the decoder can always deal with uncompressed instructions (the ID stage still receives the compressed instruction for placing into ``mtval`` on an illegal instruction exception).
|
Compressed instructions are expanded by the IF stage so the decoder can always deal with uncompressed instructions (the ID stage still receives the compressed instruction for placing into ``mtval`` on an illegal instruction exception).
|
||||||
|
|
||||||
If Ibex has been configured with an instruction cache (parameter ICache == 1), then the prefetch buffer is replaced by the icache module (:ref:`icache`).
|
|
||||||
The interfaces of the icache module are the same as the prefetch buffer with two additions.
|
|
||||||
Firstly, a signal to enable the cache which is driven from a custom CSR.
|
|
||||||
Secondly a signal to the flush the cache which is set every time a ``fence.i`` instruction is executed.
|
|
||||||
|
|
||||||
Branch Prediction
|
Branch Prediction
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
|
|
@ -1,115 +0,0 @@
|
||||||
.. _security:
|
|
||||||
|
|
||||||
Security Features
|
|
||||||
=================
|
|
||||||
|
|
||||||
Ibex implements a set of extra features (when the SecureIbex parameter is set) to support security-critical applications.
|
|
||||||
All features are runtime configurable via bits in the **cpuctrl** custom CSR.
|
|
||||||
|
|
||||||
Outputs
|
|
||||||
-------
|
|
||||||
|
|
||||||
Ibex has three alert outputs for signalling security issues.
|
|
||||||
The internal major alert (**alert_major_internal_o**) indicates a critical security issue from which the core cannot recover which was detected internally in `cve2_top`.
|
|
||||||
The bus major alert (**alert_major_internal_o**) indicates a critical security issue from which the core cannot recover which was detected on incoming bus data.
|
|
||||||
The minor alert (**alert_minor_o**) indicates potential security issues which can be monitored over time by a system.
|
|
||||||
|
|
||||||
Data Independent Timing
|
|
||||||
-----------------------
|
|
||||||
|
|
||||||
When enabled (via the **data_ind_timing** control bit in the **cpuctrl** register), execution times and power consumption of all instructions shall be independent of input data.
|
|
||||||
This makes it more difficult for an external observer to infer secret data by observing power lines or exploiting timing side-channels.
|
|
||||||
|
|
||||||
In Ibex, most instructions already execute independent of their input operands.
|
|
||||||
When data-independent timing is enabled:
|
|
||||||
|
|
||||||
* Branches execute identically regardless of their taken/not-taken status
|
|
||||||
* Early completion of multiplication by zero/one is removed
|
|
||||||
* Early completion of divide by zero is removed
|
|
||||||
|
|
||||||
Note that data memory operations to unaligned addresses might result in multiple bus accesses being made.
|
|
||||||
This in turn could expose information about the address as a timing side-channel.
|
|
||||||
It is therefore recommended to stick to aligned memory accesses when using this feature for critical code regions.
|
|
||||||
|
|
||||||
When Ibex is configured to use an instruction cache, stalls on instruction fetch can see variable latency (depending on whether or not they hit in the cache).
|
|
||||||
Software that has need of data independent timing may wish to disable the instruction cache to avoid this or to carefully analyse execution to determine if variable latency introduced by the cache causes unacceptable leakage.
|
|
||||||
The instruction cache is controlled by the **icache_enable** bit in the **cpuctrl** register.
|
|
||||||
Precise details of fetch timing will depend upon the memory system Ibex is connected to.
|
|
||||||
|
|
||||||
Dummy Instruction Insertion
|
|
||||||
---------------------------
|
|
||||||
|
|
||||||
When enabled (via the **dummy_instr_en** control bit in the **cpuctrl** register), dummy instructions will be inserted at random intervals into the execution pipeline.
|
|
||||||
The dummy instructions have no functional impact on processor state, but add some difficult-to-predict timing and power disruption to executed code.
|
|
||||||
This disruption makes it more difficult for an attacker to infer what is being executed, and also makes it more difficult to execute precisely timed fault injection attacks.
|
|
||||||
|
|
||||||
The frequency of injected instructions can be tuned via the **dummy_instr_mask** bits in the **cpuctrl** register.
|
|
||||||
|
|
||||||
+----------------------+----------------------------------------------------------+
|
|
||||||
| **dummy_instr_mask** | Interval |
|
|
||||||
+----------------------+----------------------------------------------------------+
|
|
||||||
| 000 | Dummy instruction every 0 - 4 real instructions |
|
|
||||||
+----------------------+----------------------------------------------------------+
|
|
||||||
| 001 | Dummy instruction every 0 - 8 real instructions |
|
|
||||||
+----------------------+----------------------------------------------------------+
|
|
||||||
| 011 | Dummy instruction every 0 - 16 real instructions |
|
|
||||||
+----------------------+----------------------------------------------------------+
|
|
||||||
| 111 | Dummy instruction every 0 - 32 real instructions |
|
|
||||||
+----------------------+----------------------------------------------------------+
|
|
||||||
|
|
||||||
Other values of **dummy_instr_mask** are legal, but will have a less predictable impact.
|
|
||||||
|
|
||||||
The interval between instruction insertion is randomized in the core using an LFSR.
|
|
||||||
The initial seed and output permutation for this LFSR can be set using parameters from the top-level of Ibex.
|
|
||||||
Sofware can periodically re-seed this LFSR with true random numbers (if available) via the **secureseed** CSR.
|
|
||||||
This will make the insertion interval of dummy instructions much harder for an attacker to predict.
|
|
||||||
|
|
||||||
Note that the dummy instruction feature inserts multiply and divide instructions.
|
|
||||||
The core must be configured with a multiplier (`RV32M != cve2_pkg::RV32MNone`) or errors will occur using this feature.
|
|
||||||
|
|
||||||
Bus integrity checking
|
|
||||||
----------------------
|
|
||||||
|
|
||||||
Extra signals are available alongside the instruction and data side memory channels to support bus integrity checking.
|
|
||||||
When the SecureIbex parameter is set, incoming data will be checked against the supplied checkbits, and a bus major alert signalled if there is a mismatch.
|
|
||||||
Write data can be checked against the supplied checkbits at its destination to confirm integrity.
|
|
||||||
|
|
||||||
Register file ECC
|
|
||||||
-----------------
|
|
||||||
|
|
||||||
When Ibex is configured with the SecureIbex parameter, ECC checking is added to all reads of the register file.
|
|
||||||
This can be useful to detect fault injection attacks since the register file covers a reasonably large area.
|
|
||||||
No attempt is made to correct detected errors, but an internal major alert is signaled for the system to take action.
|
|
||||||
|
|
||||||
ICache ECC
|
|
||||||
----------
|
|
||||||
|
|
||||||
The ICache can be configured with ECC protection.
|
|
||||||
When an ECC error is detected a minor alert is signaled.
|
|
||||||
See :ref:`icache-ecc` for more information.
|
|
||||||
|
|
||||||
Hardened PC
|
|
||||||
-----------
|
|
||||||
|
|
||||||
This adds a check that the PC driven from the IF stage has not been modified.
|
|
||||||
A check is asserted that the current IF stage PC equals the previous PC plus the correct increment.
|
|
||||||
The check is disabled after branches and after reset.
|
|
||||||
If a mismatch is detected, an internal major alert is signaled.
|
|
||||||
|
|
||||||
Shadow CSRs
|
|
||||||
-----------
|
|
||||||
|
|
||||||
Certain critical CSRs (`mstatus`, `mtvec`, `cpuctrl`, `pmpcfg` and `pmpaddr`) have extra glitch detection enabled.
|
|
||||||
This creates a second copy of the register which stores a complemented version of the main CSR data.
|
|
||||||
A constant check is made that the two copies are consistent, and an internal major alert is signalled if not.
|
|
||||||
Note that this feature is not currently used when the SecureIbex parameter is set due to overlap with dual core lockstep.
|
|
||||||
|
|
||||||
Dual core lockstep
|
|
||||||
------------------
|
|
||||||
|
|
||||||
This configuration option instantiates a second copy of the core logic, referred to as the shadow core.
|
|
||||||
The shadow core executes using a delayed version of all inputs supplied to the main core.
|
|
||||||
All outputs of the shadow core are compared against a delayed version of the outputs of the main core.
|
|
||||||
Any mismatch between the two sets of outputs will trigger an internal major alert.
|
|
||||||
|
|
||||||
Note that the register file and icache RAMs are not duplicated since these units are covered by ECC protection.
|
|
|
@ -1,9 +1,5 @@
|
||||||
.. _testplan:
|
.. _testplan:
|
||||||
|
|
||||||
.. todo::
|
|
||||||
|
|
||||||
Add detail about security hardening verification.
|
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
This testplan is a work in progress still being implemented so this document may not match the implemented verification in the repository.
|
This testplan is a work in progress still being implemented so this document may not match the implemented verification in the repository.
|
||||||
|
@ -14,8 +10,7 @@ Test Plan
|
||||||
Goals
|
Goals
|
||||||
-----
|
-----
|
||||||
|
|
||||||
* Verify compliance with all the RISC-V specifications Ibex supports.
|
* Verify compliance with all the RISC-V specifications CVE2 supports.
|
||||||
* Verify Ibex's security hardening features.
|
|
||||||
* Ensure correct functionality is maintained across all possible behaviours of external interfaces (interrupts, memory responses, debug requests etc).
|
* Ensure correct functionality is maintained across all possible behaviours of external interfaces (interrupts, memory responses, debug requests etc).
|
||||||
* Hit all functional coverage points, described in :ref:`coverage-plan`.
|
* Hit all functional coverage points, described in :ref:`coverage-plan`.
|
||||||
|
|
||||||
|
|
167
rtl/cve2_core.sv
167
rtl/cve2_core.sv
|
@ -22,20 +22,9 @@ module cve2_core import cve2_pkg::*; #(
|
||||||
parameter rv32m_e RV32M = RV32MFast,
|
parameter rv32m_e RV32M = RV32MFast,
|
||||||
parameter rv32b_e RV32B = RV32BNone,
|
parameter rv32b_e RV32B = RV32BNone,
|
||||||
parameter bit WritebackStage = 1'b0,
|
parameter bit WritebackStage = 1'b0,
|
||||||
parameter bit ICache = 1'b0,
|
|
||||||
parameter bit ICacheECC = 1'b0,
|
|
||||||
parameter int unsigned BusSizeECC = BUS_SIZE,
|
|
||||||
parameter int unsigned TagSizeECC = IC_TAG_SIZE,
|
|
||||||
parameter int unsigned LineSizeECC = IC_LINE_SIZE,
|
|
||||||
parameter bit BranchPredictor = 1'b0,
|
parameter bit BranchPredictor = 1'b0,
|
||||||
parameter bit DbgTriggerEn = 1'b0,
|
parameter bit DbgTriggerEn = 1'b0,
|
||||||
parameter int unsigned DbgHwBreakNum = 1,
|
parameter int unsigned DbgHwBreakNum = 1,
|
||||||
parameter bit ResetAll = 1'b0,
|
|
||||||
parameter lfsr_seed_t RndCnstLfsrSeed = RndCnstLfsrSeedDefault,
|
|
||||||
parameter lfsr_perm_t RndCnstLfsrPerm = RndCnstLfsrPermDefault,
|
|
||||||
parameter bit SecureIbex = 1'b0,
|
|
||||||
parameter bit DummyInstructions = 1'b0,
|
|
||||||
parameter bit RegFileECC = 1'b0,
|
|
||||||
parameter int unsigned DmHaltAddr = 32'h1A110800,
|
parameter int unsigned DmHaltAddr = 32'h1A110800,
|
||||||
parameter int unsigned DmExceptionAddr = 32'h1A110808
|
parameter int unsigned DmExceptionAddr = 32'h1A110808
|
||||||
) (
|
) (
|
||||||
|
@ -66,7 +55,6 @@ module cve2_core import cve2_pkg::*; #(
|
||||||
input logic data_err_i,
|
input logic data_err_i,
|
||||||
|
|
||||||
// Register file interface
|
// Register file interface
|
||||||
output logic dummy_instr_id_o,
|
|
||||||
output logic [4:0] rf_raddr_a_o,
|
output logic [4:0] rf_raddr_a_o,
|
||||||
output logic [4:0] rf_raddr_b_o,
|
output logic [4:0] rf_raddr_b_o,
|
||||||
output logic [4:0] rf_waddr_wb_o,
|
output logic [4:0] rf_waddr_wb_o,
|
||||||
|
@ -75,19 +63,6 @@ module cve2_core import cve2_pkg::*; #(
|
||||||
input logic [31:0] rf_rdata_a_ecc_i,
|
input logic [31:0] rf_rdata_a_ecc_i,
|
||||||
input logic [31:0] rf_rdata_b_ecc_i,
|
input logic [31:0] rf_rdata_b_ecc_i,
|
||||||
|
|
||||||
// RAMs interface
|
|
||||||
output logic [IC_NUM_WAYS-1:0] ic_tag_req_o,
|
|
||||||
output logic ic_tag_write_o,
|
|
||||||
output logic [IC_INDEX_W-1:0] ic_tag_addr_o,
|
|
||||||
output logic [TagSizeECC-1:0] ic_tag_wdata_o,
|
|
||||||
input logic [TagSizeECC-1:0] ic_tag_rdata_i [IC_NUM_WAYS],
|
|
||||||
output logic [IC_NUM_WAYS-1:0] ic_data_req_o,
|
|
||||||
output logic ic_data_write_o,
|
|
||||||
output logic [IC_INDEX_W-1:0] ic_data_addr_o,
|
|
||||||
output logic [LineSizeECC-1:0] ic_data_wdata_o,
|
|
||||||
input logic [LineSizeECC-1:0] ic_data_rdata_i [IC_NUM_WAYS],
|
|
||||||
input logic ic_scr_key_valid_i,
|
|
||||||
|
|
||||||
// Interrupt inputs
|
// Interrupt inputs
|
||||||
input logic irq_software_i,
|
input logic irq_software_i,
|
||||||
input logic irq_timer_i,
|
input logic irq_timer_i,
|
||||||
|
@ -101,7 +76,6 @@ module cve2_core import cve2_pkg::*; #(
|
||||||
output crash_dump_t crash_dump_o,
|
output crash_dump_t crash_dump_o,
|
||||||
// SEC_CM: EXCEPTION.CTRL_FLOW.LOCAL_ESC
|
// SEC_CM: EXCEPTION.CTRL_FLOW.LOCAL_ESC
|
||||||
// SEC_CM: EXCEPTION.CTRL_FLOW.GLOBAL_ESC
|
// SEC_CM: EXCEPTION.CTRL_FLOW.GLOBAL_ESC
|
||||||
output logic double_fault_seen_o,
|
|
||||||
|
|
||||||
// RISC-V Formal Interface
|
// RISC-V Formal Interface
|
||||||
// Does not comply with the coding standards of _i/_o suffixes, but follows
|
// Does not comply with the coding standards of _i/_o suffixes, but follows
|
||||||
|
@ -138,21 +112,15 @@ module cve2_core import cve2_pkg::*; #(
|
||||||
|
|
||||||
// CPU Control Signals
|
// CPU Control Signals
|
||||||
// SEC_CM: FETCH.CTRL.LC_GATED
|
// SEC_CM: FETCH.CTRL.LC_GATED
|
||||||
input fetch_enable_t fetch_enable_i,
|
|
||||||
output logic alert_minor_o,
|
output logic alert_minor_o,
|
||||||
output logic alert_major_o,
|
output logic alert_major_o,
|
||||||
output logic icache_inval_o,
|
|
||||||
output logic core_busy_o
|
output logic core_busy_o
|
||||||
);
|
);
|
||||||
|
|
||||||
localparam int unsigned PMP_NUM_CHAN = 3;
|
localparam int unsigned PMP_NUM_CHAN = 3;
|
||||||
// SEC_CM: CORE.DATA_REG_SW.SCA
|
// SEC_CM: CORE.DATA_REG_SW.SCA
|
||||||
localparam bit DataIndTiming = SecureIbex;
|
|
||||||
localparam bit PCIncrCheck = SecureIbex;
|
|
||||||
localparam bit ShadowCSR = 1'b0;
|
|
||||||
|
|
||||||
// IF/ID signals
|
// IF/ID signals
|
||||||
logic dummy_instr_id;
|
|
||||||
logic instr_valid_id;
|
logic instr_valid_id;
|
||||||
logic instr_new_id;
|
logic instr_new_id;
|
||||||
logic [31:0] instr_rdata_id; // Instruction sampled inside IF stage
|
logic [31:0] instr_rdata_id; // Instruction sampled inside IF stage
|
||||||
|
@ -172,17 +140,6 @@ module cve2_core import cve2_pkg::*; #(
|
||||||
logic [33:0] imd_val_q_ex[2]; // Intermediate register for multicycle Ops
|
logic [33:0] imd_val_q_ex[2]; // Intermediate register for multicycle Ops
|
||||||
logic [1:0] imd_val_we_ex;
|
logic [1:0] imd_val_we_ex;
|
||||||
|
|
||||||
logic data_ind_timing;
|
|
||||||
logic dummy_instr_en;
|
|
||||||
logic [2:0] dummy_instr_mask;
|
|
||||||
logic dummy_instr_seed_en;
|
|
||||||
logic [31:0] dummy_instr_seed;
|
|
||||||
logic icache_enable;
|
|
||||||
logic icache_inval;
|
|
||||||
logic icache_ecc_error;
|
|
||||||
logic pc_mismatch_alert;
|
|
||||||
logic csr_shadow_err;
|
|
||||||
|
|
||||||
logic instr_first_cycle_id;
|
logic instr_first_cycle_id;
|
||||||
logic instr_valid_clear;
|
logic instr_valid_clear;
|
||||||
logic pc_set;
|
logic pc_set;
|
||||||
|
@ -360,16 +317,6 @@ module cve2_core import cve2_pkg::*; #(
|
||||||
cve2_if_stage #(
|
cve2_if_stage #(
|
||||||
.DmHaltAddr (DmHaltAddr),
|
.DmHaltAddr (DmHaltAddr),
|
||||||
.DmExceptionAddr (DmExceptionAddr),
|
.DmExceptionAddr (DmExceptionAddr),
|
||||||
.DummyInstructions(DummyInstructions),
|
|
||||||
.ICache (ICache),
|
|
||||||
.ICacheECC (ICacheECC),
|
|
||||||
.BusSizeECC (BusSizeECC),
|
|
||||||
.TagSizeECC (TagSizeECC),
|
|
||||||
.LineSizeECC (LineSizeECC),
|
|
||||||
.PCIncrCheck (PCIncrCheck),
|
|
||||||
.ResetAll ( ResetAll ),
|
|
||||||
.RndCnstLfsrSeed ( RndCnstLfsrSeed ),
|
|
||||||
.RndCnstLfsrPerm ( RndCnstLfsrPerm ),
|
|
||||||
.BranchPredictor (BranchPredictor)
|
.BranchPredictor (BranchPredictor)
|
||||||
) if_stage_i (
|
) if_stage_i (
|
||||||
.clk_i (clk_i),
|
.clk_i (clk_i),
|
||||||
|
@ -386,18 +333,6 @@ module cve2_core import cve2_pkg::*; #(
|
||||||
.instr_rdata_i (instr_rdata_i),
|
.instr_rdata_i (instr_rdata_i),
|
||||||
.instr_err_i (instr_err_i),
|
.instr_err_i (instr_err_i),
|
||||||
|
|
||||||
.ic_tag_req_o (ic_tag_req_o),
|
|
||||||
.ic_tag_write_o (ic_tag_write_o),
|
|
||||||
.ic_tag_addr_o (ic_tag_addr_o),
|
|
||||||
.ic_tag_wdata_o (ic_tag_wdata_o),
|
|
||||||
.ic_tag_rdata_i (ic_tag_rdata_i),
|
|
||||||
.ic_data_req_o (ic_data_req_o),
|
|
||||||
.ic_data_write_o (ic_data_write_o),
|
|
||||||
.ic_data_addr_o (ic_data_addr_o),
|
|
||||||
.ic_data_wdata_o (ic_data_wdata_o),
|
|
||||||
.ic_data_rdata_i (ic_data_rdata_i),
|
|
||||||
.ic_scr_key_valid_i(ic_scr_key_valid_i),
|
|
||||||
|
|
||||||
// outputs to ID stage
|
// outputs to ID stage
|
||||||
.instr_valid_id_o (instr_valid_id),
|
.instr_valid_id_o (instr_valid_id),
|
||||||
.instr_new_id_o (instr_new_id),
|
.instr_new_id_o (instr_new_id),
|
||||||
|
@ -409,7 +344,6 @@ module cve2_core import cve2_pkg::*; #(
|
||||||
.instr_fetch_err_o (instr_fetch_err),
|
.instr_fetch_err_o (instr_fetch_err),
|
||||||
.instr_fetch_err_plus2_o (instr_fetch_err_plus2),
|
.instr_fetch_err_plus2_o (instr_fetch_err_plus2),
|
||||||
.illegal_c_insn_id_o (illegal_c_insn_id),
|
.illegal_c_insn_id_o (illegal_c_insn_id),
|
||||||
.dummy_instr_id_o (dummy_instr_id),
|
|
||||||
.pc_if_o (pc_if),
|
.pc_if_o (pc_if),
|
||||||
.pc_id_o (pc_id),
|
.pc_id_o (pc_id),
|
||||||
.pmp_err_if_i (pmp_req_err[PMP_I]),
|
.pmp_err_if_i (pmp_req_err[PMP_I]),
|
||||||
|
@ -422,13 +356,6 @@ module cve2_core import cve2_pkg::*; #(
|
||||||
.nt_branch_mispredict_i(nt_branch_mispredict),
|
.nt_branch_mispredict_i(nt_branch_mispredict),
|
||||||
.exc_pc_mux_i (exc_pc_mux_id),
|
.exc_pc_mux_i (exc_pc_mux_id),
|
||||||
.exc_cause (exc_cause),
|
.exc_cause (exc_cause),
|
||||||
.dummy_instr_en_i (dummy_instr_en),
|
|
||||||
.dummy_instr_mask_i (dummy_instr_mask),
|
|
||||||
.dummy_instr_seed_en_i (dummy_instr_seed_en),
|
|
||||||
.dummy_instr_seed_i (dummy_instr_seed),
|
|
||||||
.icache_enable_i (icache_enable),
|
|
||||||
.icache_inval_i (icache_inval),
|
|
||||||
.icache_ecc_error_o (icache_ecc_error),
|
|
||||||
|
|
||||||
// branch targets
|
// branch targets
|
||||||
.branch_target_ex_i(branch_target_ex),
|
.branch_target_ex_i(branch_target_ex),
|
||||||
|
@ -443,7 +370,6 @@ module cve2_core import cve2_pkg::*; #(
|
||||||
// pipeline stalls
|
// pipeline stalls
|
||||||
.id_in_ready_i(id_in_ready),
|
.id_in_ready_i(id_in_ready),
|
||||||
|
|
||||||
.pc_mismatch_alert_o(pc_mismatch_alert),
|
|
||||||
.if_busy_o (if_busy)
|
.if_busy_o (if_busy)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -451,25 +377,9 @@ module cve2_core import cve2_pkg::*; #(
|
||||||
// available
|
// available
|
||||||
assign perf_iside_wait = id_in_ready & ~instr_valid_id;
|
assign perf_iside_wait = id_in_ready & ~instr_valid_id;
|
||||||
|
|
||||||
// Multi-bit fetch enable used when SecureIbex == 1. When SecureIbex == 0 only use the bottom-bit
|
begin : g_instr_req_gated_non_secure
|
||||||
// of fetch_enable_i. Ensure the multi-bit encoding has the bottom bit set for on and unset for
|
|
||||||
// off so FetchEnableOn/FetchEnableOff can be used without needing to know the value of
|
|
||||||
// SecureIbex.
|
|
||||||
`ASSERT_INIT(FetchEnableSecureOnBottomBitSet, FetchEnableOn[0] == 1'b1)
|
|
||||||
`ASSERT_INIT(FetchEnableSecureOffBottomBitClear, FetchEnableOff[0] == 1'b0)
|
|
||||||
|
|
||||||
// fetch_enable_i can be used to stop the core fetching new instructions
|
|
||||||
if (SecureIbex) begin : g_instr_req_gated_secure
|
|
||||||
// For secure Ibex fetch_enable_i must be a specific multi-bit pattern to enable instruction
|
|
||||||
// fetch
|
|
||||||
// SEC_CM: FETCH.CTRL.LC_GATED
|
|
||||||
assign instr_req_gated = instr_req_int & (fetch_enable_i == FetchEnableOn);
|
|
||||||
end else begin : g_instr_req_gated_non_secure
|
|
||||||
// For non secure Ibex only the bottom bit of fetch enable is considered
|
// For non secure Ibex only the bottom bit of fetch enable is considered
|
||||||
logic unused_fetch_enable;
|
assign instr_req_gated = instr_req_int;
|
||||||
assign unused_fetch_enable = ^fetch_enable_i[$bits(fetch_enable_t)-1:1];
|
|
||||||
|
|
||||||
assign instr_req_gated = instr_req_int & fetch_enable_i[0];
|
|
||||||
end
|
end
|
||||||
|
|
||||||
//////////////
|
//////////////
|
||||||
|
@ -480,7 +390,6 @@ module cve2_core import cve2_pkg::*; #(
|
||||||
.RV32E (RV32E),
|
.RV32E (RV32E),
|
||||||
.RV32M (RV32M),
|
.RV32M (RV32M),
|
||||||
.RV32B (RV32B),
|
.RV32B (RV32B),
|
||||||
.DataIndTiming (DataIndTiming),
|
|
||||||
.WritebackStage (WritebackStage),
|
.WritebackStage (WritebackStage),
|
||||||
.BranchPredictor(BranchPredictor)
|
.BranchPredictor(BranchPredictor)
|
||||||
) id_stage_i (
|
) id_stage_i (
|
||||||
|
@ -513,7 +422,6 @@ module cve2_core import cve2_pkg::*; #(
|
||||||
.nt_branch_addr_o (nt_branch_addr),
|
.nt_branch_addr_o (nt_branch_addr),
|
||||||
.exc_pc_mux_o (exc_pc_mux_id),
|
.exc_pc_mux_o (exc_pc_mux_id),
|
||||||
.exc_cause_o (exc_cause),
|
.exc_cause_o (exc_cause),
|
||||||
.icache_inval_o (icache_inval),
|
|
||||||
|
|
||||||
.instr_fetch_err_i (instr_fetch_err),
|
.instr_fetch_err_i (instr_fetch_err),
|
||||||
.instr_fetch_err_plus2_i(instr_fetch_err_plus2),
|
.instr_fetch_err_plus2_i(instr_fetch_err_plus2),
|
||||||
|
@ -557,7 +465,6 @@ module cve2_core import cve2_pkg::*; #(
|
||||||
.priv_mode_i (priv_mode_id),
|
.priv_mode_i (priv_mode_id),
|
||||||
.csr_mstatus_tw_i (csr_mstatus_tw),
|
.csr_mstatus_tw_i (csr_mstatus_tw),
|
||||||
.illegal_csr_insn_i (illegal_csr_insn_id),
|
.illegal_csr_insn_i (illegal_csr_insn_id),
|
||||||
.data_ind_timing_i (data_ind_timing),
|
|
||||||
|
|
||||||
// LSU
|
// LSU
|
||||||
.lsu_req_o (lsu_req), // to load store unit
|
.lsu_req_o (lsu_req), // to load store unit
|
||||||
|
@ -627,7 +534,6 @@ module cve2_core import cve2_pkg::*; #(
|
||||||
.instr_id_done_o (instr_id_done)
|
.instr_id_done_o (instr_id_done)
|
||||||
);
|
);
|
||||||
|
|
||||||
assign icache_inval_o = icache_inval;
|
|
||||||
// for RVFI only
|
// for RVFI only
|
||||||
assign unused_illegal_insn_id = illegal_insn_id;
|
assign unused_illegal_insn_id = illegal_insn_id;
|
||||||
|
|
||||||
|
@ -654,7 +560,6 @@ module cve2_core import cve2_pkg::*; #(
|
||||||
.multdiv_operand_a_i (multdiv_operand_a_ex),
|
.multdiv_operand_a_i (multdiv_operand_a_ex),
|
||||||
.multdiv_operand_b_i (multdiv_operand_b_ex),
|
.multdiv_operand_b_i (multdiv_operand_b_ex),
|
||||||
.multdiv_ready_id_i (multdiv_ready_id),
|
.multdiv_ready_id_i (multdiv_ready_id),
|
||||||
.data_ind_timing_i (data_ind_timing),
|
|
||||||
|
|
||||||
// Intermediate value register
|
// Intermediate value register
|
||||||
.imd_val_we_o(imd_val_we_ex),
|
.imd_val_we_o(imd_val_we_ex),
|
||||||
|
@ -725,7 +630,6 @@ module cve2_core import cve2_pkg::*; #(
|
||||||
);
|
);
|
||||||
|
|
||||||
cve2_wb_stage #(
|
cve2_wb_stage #(
|
||||||
.ResetAll ( ResetAll ),
|
|
||||||
.WritebackStage(WritebackStage)
|
.WritebackStage(WritebackStage)
|
||||||
) wb_stage_i (
|
) wb_stage_i (
|
||||||
.clk_i (clk_i),
|
.clk_i (clk_i),
|
||||||
|
@ -769,50 +673,12 @@ module cve2_core import cve2_pkg::*; #(
|
||||||
// Register file interface //
|
// Register file interface //
|
||||||
/////////////////////////////
|
/////////////////////////////
|
||||||
|
|
||||||
assign dummy_instr_id_o = dummy_instr_id;
|
|
||||||
assign rf_raddr_a_o = rf_raddr_a;
|
assign rf_raddr_a_o = rf_raddr_a;
|
||||||
assign rf_waddr_wb_o = rf_waddr_wb;
|
assign rf_waddr_wb_o = rf_waddr_wb;
|
||||||
assign rf_we_wb_o = rf_we_wb;
|
assign rf_we_wb_o = rf_we_wb;
|
||||||
assign rf_raddr_b_o = rf_raddr_b;
|
assign rf_raddr_b_o = rf_raddr_b;
|
||||||
|
|
||||||
if (RegFileECC) begin : gen_regfile_ecc
|
begin : gen_no_regfile_ecc
|
||||||
|
|
||||||
// SEC_CM: DATA_REG_SW.INTEGRITY
|
|
||||||
logic [1:0] rf_ecc_err_a, rf_ecc_err_b;
|
|
||||||
logic rf_ecc_err_a_id, rf_ecc_err_b_id;
|
|
||||||
|
|
||||||
// ECC checkbit generation for regiter file wdata
|
|
||||||
prim_secded_inv_39_32_enc regfile_ecc_enc (
|
|
||||||
.data_i(rf_wdata_wb),
|
|
||||||
.data_o(rf_wdata_wb_ecc_o)
|
|
||||||
);
|
|
||||||
|
|
||||||
// ECC checking on register file rdata
|
|
||||||
prim_secded_inv_39_32_dec regfile_ecc_dec_a (
|
|
||||||
.data_i (rf_rdata_a_ecc_i),
|
|
||||||
.data_o (),
|
|
||||||
.syndrome_o(),
|
|
||||||
.err_o (rf_ecc_err_a)
|
|
||||||
);
|
|
||||||
prim_secded_inv_39_32_dec regfile_ecc_dec_b (
|
|
||||||
.data_i (rf_rdata_b_ecc_i),
|
|
||||||
.data_o (),
|
|
||||||
.syndrome_o(),
|
|
||||||
.err_o (rf_ecc_err_b)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Assign read outputs - no error correction, just trigger an alert
|
|
||||||
assign rf_rdata_a = rf_rdata_a_ecc_i[31:0];
|
|
||||||
assign rf_rdata_b = rf_rdata_b_ecc_i[31:0];
|
|
||||||
|
|
||||||
// Calculate errors - qualify with WB forwarding to avoid xprop into the alert signal
|
|
||||||
assign rf_ecc_err_a_id = |rf_ecc_err_a & rf_ren_a & ~rf_rd_a_wb_match;
|
|
||||||
assign rf_ecc_err_b_id = |rf_ecc_err_b & rf_ren_b & ~rf_rd_b_wb_match;
|
|
||||||
|
|
||||||
// Combined error
|
|
||||||
assign rf_ecc_err_comb = instr_valid_id & (rf_ecc_err_a_id | rf_ecc_err_b_id);
|
|
||||||
|
|
||||||
end else begin : gen_no_regfile_ecc
|
|
||||||
logic unused_rf_ren_a, unused_rf_ren_b;
|
logic unused_rf_ren_a, unused_rf_ren_b;
|
||||||
logic unused_rf_rd_a_wb_match, unused_rf_rd_b_wb_match;
|
logic unused_rf_rd_a_wb_match, unused_rf_rd_b_wb_match;
|
||||||
|
|
||||||
|
@ -840,10 +706,10 @@ module cve2_core import cve2_pkg::*; #(
|
||||||
///////////////////
|
///////////////////
|
||||||
|
|
||||||
// Minor alert - core is in a recoverable state
|
// Minor alert - core is in a recoverable state
|
||||||
assign alert_minor_o = icache_ecc_error;
|
assign alert_minor_o = 1'b0;
|
||||||
|
|
||||||
// Major alert - core is unrecoverable
|
// Major alert - core is unrecoverable
|
||||||
assign alert_major_o = rf_ecc_err_comb | pc_mismatch_alert | csr_shadow_err;
|
assign alert_major_o = rf_ecc_err_comb;
|
||||||
|
|
||||||
// Explict INC_ASSERT block to avoid unused signal lint warnings were asserts are not included
|
// Explict INC_ASSERT block to avoid unused signal lint warnings were asserts are not included
|
||||||
`ifdef INC_ASSERT
|
`ifdef INC_ASSERT
|
||||||
|
@ -901,10 +767,6 @@ module cve2_core import cve2_pkg::*; #(
|
||||||
cve2_cs_registers #(
|
cve2_cs_registers #(
|
||||||
.DbgTriggerEn (DbgTriggerEn),
|
.DbgTriggerEn (DbgTriggerEn),
|
||||||
.DbgHwBreakNum (DbgHwBreakNum),
|
.DbgHwBreakNum (DbgHwBreakNum),
|
||||||
.DataIndTiming (DataIndTiming),
|
|
||||||
.DummyInstructions(DummyInstructions),
|
|
||||||
.ShadowCSR (ShadowCSR),
|
|
||||||
.ICache (ICache),
|
|
||||||
.MHPMCounterNum (MHPMCounterNum),
|
.MHPMCounterNum (MHPMCounterNum),
|
||||||
.MHPMCounterWidth (MHPMCounterWidth),
|
.MHPMCounterWidth (MHPMCounterWidth),
|
||||||
.PMPEnable (PMPEnable),
|
.PMPEnable (PMPEnable),
|
||||||
|
@ -966,14 +828,6 @@ module cve2_core import cve2_pkg::*; #(
|
||||||
.pc_id_i(pc_id),
|
.pc_id_i(pc_id),
|
||||||
.pc_wb_i(pc_wb),
|
.pc_wb_i(pc_wb),
|
||||||
|
|
||||||
.data_ind_timing_o (data_ind_timing),
|
|
||||||
.dummy_instr_en_o (dummy_instr_en),
|
|
||||||
.dummy_instr_mask_o (dummy_instr_mask),
|
|
||||||
.dummy_instr_seed_en_o(dummy_instr_seed_en),
|
|
||||||
.dummy_instr_seed_o (dummy_instr_seed),
|
|
||||||
.icache_enable_o (icache_enable),
|
|
||||||
.csr_shadow_err_o (csr_shadow_err),
|
|
||||||
|
|
||||||
.csr_save_if_i (csr_save_if),
|
.csr_save_if_i (csr_save_if),
|
||||||
.csr_save_id_i (csr_save_id),
|
.csr_save_id_i (csr_save_id),
|
||||||
.csr_save_wb_i (csr_save_wb),
|
.csr_save_wb_i (csr_save_wb),
|
||||||
|
@ -984,8 +838,6 @@ module cve2_core import cve2_pkg::*; #(
|
||||||
.csr_mtval_i (csr_mtval),
|
.csr_mtval_i (csr_mtval),
|
||||||
.illegal_csr_insn_o(illegal_csr_insn_id),
|
.illegal_csr_insn_o(illegal_csr_insn_id),
|
||||||
|
|
||||||
.double_fault_seen_o,
|
|
||||||
|
|
||||||
// performance counter related signals
|
// performance counter related signals
|
||||||
.instr_ret_i (perf_instr_ret_wb),
|
.instr_ret_i (perf_instr_ret_wb),
|
||||||
.instr_ret_compressed_i (perf_instr_ret_compressed_wb),
|
.instr_ret_compressed_i (perf_instr_ret_compressed_wb),
|
||||||
|
@ -1209,7 +1061,7 @@ module cve2_core import cve2_pkg::*; #(
|
||||||
// awaiting instruction retirement and RF Write data/Mem read data whilst instruction is in WB
|
// awaiting instruction retirement and RF Write data/Mem read data whilst instruction is in WB
|
||||||
// So first stage becomes valid when instruction leaves ID/EX stage and remains valid until
|
// So first stage becomes valid when instruction leaves ID/EX stage and remains valid until
|
||||||
// instruction leaves WB
|
// instruction leaves WB
|
||||||
assign rvfi_stage_valid_d[0] = (rvfi_id_done & ~dummy_instr_id) |
|
assign rvfi_stage_valid_d[0] = rvfi_id_done |
|
||||||
(rvfi_stage_valid[0] & ~rvfi_wb_done);
|
(rvfi_stage_valid[0] & ~rvfi_wb_done);
|
||||||
// Second stage is output stage so simple valid cycle after instruction leaves WB (and so has
|
// Second stage is output stage so simple valid cycle after instruction leaves WB (and so has
|
||||||
// retired)
|
// retired)
|
||||||
|
@ -1237,7 +1089,7 @@ module cve2_core import cve2_pkg::*; #(
|
||||||
end else begin : gen_rvfi_no_wb_stage
|
end else begin : gen_rvfi_no_wb_stage
|
||||||
// Without writeback stage first RVFI stage is output stage so simply valid the cycle after
|
// Without writeback stage first RVFI stage is output stage so simply valid the cycle after
|
||||||
// instruction leaves ID/EX (and so has retired)
|
// instruction leaves ID/EX (and so has retired)
|
||||||
assign rvfi_stage_valid_d[0] = rvfi_id_done & ~dummy_instr_id;
|
assign rvfi_stage_valid_d[0] = rvfi_id_done;
|
||||||
// Without writeback stage signal new instr_new_wb when instruction enters ID/EX to correctly
|
// Without writeback stage signal new instr_new_wb when instruction enters ID/EX to correctly
|
||||||
// setup register write signals
|
// setup register write signals
|
||||||
assign rvfi_instr_new_wb = instr_new_id;
|
assign rvfi_instr_new_wb = instr_new_id;
|
||||||
|
@ -1246,7 +1098,7 @@ module cve2_core import cve2_pkg::*; #(
|
||||||
assign rvfi_wb_done = instr_done_wb;
|
assign rvfi_wb_done = instr_done_wb;
|
||||||
end
|
end
|
||||||
|
|
||||||
assign rvfi_stage_order_d = dummy_instr_id ? rvfi_stage_order[0] : rvfi_stage_order[0] + 64'd1;
|
assign rvfi_stage_order_d = rvfi_stage_order[0] + 64'd1;
|
||||||
|
|
||||||
// For interrupts and debug Ibex will take the relevant trap as soon as whatever instruction in ID
|
// For interrupts and debug Ibex will take the relevant trap as soon as whatever instruction in ID
|
||||||
// finishes or immediately if the ID stage is empty. The rvfi_ext interface provides the DV
|
// finishes or immediately if the ID stage is empty. The rvfi_ext interface provides the DV
|
||||||
|
@ -1573,7 +1425,4 @@ module cve2_core import cve2_pkg::*; #(
|
||||||
assign unused_instr_done_wb = instr_done_wb;
|
assign unused_instr_done_wb = instr_done_wb;
|
||||||
`endif
|
`endif
|
||||||
|
|
||||||
// Certain parameter combinations are not supported
|
|
||||||
`ASSERT_INIT(IllegalParamSecure, !(SecureIbex && (RV32M == RV32MNone)))
|
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
|
@ -15,10 +15,6 @@
|
||||||
module cve2_cs_registers #(
|
module cve2_cs_registers #(
|
||||||
parameter bit DbgTriggerEn = 0,
|
parameter bit DbgTriggerEn = 0,
|
||||||
parameter int unsigned DbgHwBreakNum = 1,
|
parameter int unsigned DbgHwBreakNum = 1,
|
||||||
parameter bit DataIndTiming = 1'b0,
|
|
||||||
parameter bit DummyInstructions = 1'b0,
|
|
||||||
parameter bit ShadowCSR = 1'b0,
|
|
||||||
parameter bit ICache = 1'b0,
|
|
||||||
parameter int unsigned MHPMCounterNum = 10,
|
parameter int unsigned MHPMCounterNum = 10,
|
||||||
parameter int unsigned MHPMCounterWidth = 40,
|
parameter int unsigned MHPMCounterWidth = 40,
|
||||||
parameter bit PMPEnable = 0,
|
parameter bit PMPEnable = 0,
|
||||||
|
@ -83,15 +79,6 @@ module cve2_cs_registers #(
|
||||||
input logic [31:0] pc_id_i,
|
input logic [31:0] pc_id_i,
|
||||||
input logic [31:0] pc_wb_i,
|
input logic [31:0] pc_wb_i,
|
||||||
|
|
||||||
// CPU control bits
|
|
||||||
output logic data_ind_timing_o,
|
|
||||||
output logic dummy_instr_en_o,
|
|
||||||
output logic [2:0] dummy_instr_mask_o,
|
|
||||||
output logic dummy_instr_seed_en_o,
|
|
||||||
output logic [31:0] dummy_instr_seed_o,
|
|
||||||
output logic icache_enable_o,
|
|
||||||
output logic csr_shadow_err_o,
|
|
||||||
|
|
||||||
// Exception save/restore
|
// Exception save/restore
|
||||||
input logic csr_save_if_i,
|
input logic csr_save_if_i,
|
||||||
input logic csr_save_id_i,
|
input logic csr_save_id_i,
|
||||||
|
@ -104,7 +91,6 @@ module cve2_cs_registers #(
|
||||||
output logic illegal_csr_insn_o, // access to non-existent CSR,
|
output logic illegal_csr_insn_o, // access to non-existent CSR,
|
||||||
// with wrong priviledge level, or
|
// with wrong priviledge level, or
|
||||||
// missing write permissions
|
// missing write permissions
|
||||||
output logic double_fault_seen_o,
|
|
||||||
// Performance Counters
|
// Performance Counters
|
||||||
input logic instr_ret_i, // instr retired in ID/EX stage
|
input logic instr_ret_i, // instr retired in ID/EX stage
|
||||||
input logic instr_ret_compressed_i, // compressed instr retired
|
input logic instr_ret_compressed_i, // compressed instr retired
|
||||||
|
@ -174,16 +160,6 @@ module cve2_cs_registers #(
|
||||||
priv_lvl_e prv;
|
priv_lvl_e prv;
|
||||||
} dcsr_t;
|
} dcsr_t;
|
||||||
|
|
||||||
// CPU control register fields
|
|
||||||
typedef struct packed {
|
|
||||||
logic double_fault_seen;
|
|
||||||
logic sync_exc_seen;
|
|
||||||
logic [2:0] dummy_instr_mask;
|
|
||||||
logic dummy_instr_en;
|
|
||||||
logic data_ind_timing;
|
|
||||||
logic icache_enable;
|
|
||||||
} cpu_ctrl_t;
|
|
||||||
|
|
||||||
// Interrupt and exception control signals
|
// Interrupt and exception control signals
|
||||||
logic [31:0] exception_pc;
|
logic [31:0] exception_pc;
|
||||||
|
|
||||||
|
@ -253,11 +229,6 @@ module cve2_cs_registers #(
|
||||||
logic [31:0] tmatch_control_rdata;
|
logic [31:0] tmatch_control_rdata;
|
||||||
logic [31:0] tmatch_value_rdata;
|
logic [31:0] tmatch_value_rdata;
|
||||||
|
|
||||||
// CPU control bits
|
|
||||||
cpu_ctrl_t cpuctrl_q, cpuctrl_d, cpuctrl_wdata_raw, cpuctrl_wdata;
|
|
||||||
logic cpuctrl_we;
|
|
||||||
logic cpuctrl_err;
|
|
||||||
|
|
||||||
// CSR update logic
|
// CSR update logic
|
||||||
logic [31:0] csr_wdata_int;
|
logic [31:0] csr_wdata_int;
|
||||||
logic [31:0] csr_rdata_int;
|
logic [31:0] csr_rdata_int;
|
||||||
|
@ -486,11 +457,6 @@ module cve2_cs_registers #(
|
||||||
illegal_csr = ~DbgTriggerEn;
|
illegal_csr = ~DbgTriggerEn;
|
||||||
end
|
end
|
||||||
|
|
||||||
// Custom CSR for controlling CPU features
|
|
||||||
CSR_CPUCTRL: begin
|
|
||||||
csr_rdata_int = {{32 - $bits(cpu_ctrl_t) {1'b0}}, cpuctrl_q};
|
|
||||||
end
|
|
||||||
|
|
||||||
// Custom CSR for LFSR re-seeding (cannot be read)
|
// Custom CSR for LFSR re-seeding (cannot be read)
|
||||||
CSR_SECURESEED: begin
|
CSR_SECURESEED: begin
|
||||||
csr_rdata_int = '0;
|
csr_rdata_int = '0;
|
||||||
|
@ -539,11 +505,6 @@ module cve2_cs_registers #(
|
||||||
mhpmcounter_we = '0;
|
mhpmcounter_we = '0;
|
||||||
mhpmcounterh_we = '0;
|
mhpmcounterh_we = '0;
|
||||||
|
|
||||||
cpuctrl_we = 1'b0;
|
|
||||||
cpuctrl_d = cpuctrl_q;
|
|
||||||
|
|
||||||
double_fault_seen_o = 1'b0;
|
|
||||||
|
|
||||||
if (csr_we_int) begin
|
if (csr_we_int) begin
|
||||||
unique case (csr_addr_i)
|
unique case (csr_addr_i)
|
||||||
// mstatus: IE bit
|
// mstatus: IE bit
|
||||||
|
@ -641,11 +602,6 @@ module cve2_cs_registers #(
|
||||||
mhpmcounterh_we[mhpmcounter_idx] = 1'b1;
|
mhpmcounterh_we[mhpmcounter_idx] = 1'b1;
|
||||||
end
|
end
|
||||||
|
|
||||||
CSR_CPUCTRL: begin
|
|
||||||
cpuctrl_d = cpuctrl_wdata;
|
|
||||||
cpuctrl_we = 1'b1;
|
|
||||||
end
|
|
||||||
|
|
||||||
default:;
|
default:;
|
||||||
endcase
|
endcase
|
||||||
end
|
end
|
||||||
|
@ -695,17 +651,6 @@ module cve2_cs_registers #(
|
||||||
// save previous status for recoverable NMI
|
// save previous status for recoverable NMI
|
||||||
mstack_en = 1'b1;
|
mstack_en = 1'b1;
|
||||||
|
|
||||||
if (!mcause_d[5]) begin
|
|
||||||
// SEC_CM: EXCEPTION.CTRL_FLOW.LOCAL_ESC
|
|
||||||
// SEC_CM: EXCEPTION.CTRL_FLOW.GLOBAL_ESC
|
|
||||||
cpuctrl_we = 1'b1;
|
|
||||||
|
|
||||||
cpuctrl_d.sync_exc_seen = 1'b1;
|
|
||||||
if (cpuctrl_q.sync_exc_seen) begin
|
|
||||||
double_fault_seen_o = 1'b1;
|
|
||||||
cpuctrl_d.double_fault_seen = 1'b1;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end // csr_save_cause_i
|
end // csr_save_cause_i
|
||||||
|
|
||||||
|
@ -720,8 +665,6 @@ module cve2_cs_registers #(
|
||||||
|
|
||||||
// SEC_CM: EXCEPTION.CTRL_FLOW.LOCAL_ESC
|
// SEC_CM: EXCEPTION.CTRL_FLOW.LOCAL_ESC
|
||||||
// SEC_CM: EXCEPTION.CTRL_FLOW.GLOBAL_ESC
|
// SEC_CM: EXCEPTION.CTRL_FLOW.GLOBAL_ESC
|
||||||
cpuctrl_we = 1'b1;
|
|
||||||
cpuctrl_d.sync_exc_seen = 1'b0;
|
|
||||||
|
|
||||||
if (nmi_mode_i) begin
|
if (nmi_mode_i) begin
|
||||||
// when returning from an NMI restore state from mstack CSR
|
// when returning from an NMI restore state from mstack CSR
|
||||||
|
@ -803,7 +746,6 @@ module cve2_cs_registers #(
|
||||||
tw: 1'b0};
|
tw: 1'b0};
|
||||||
cve2_csr #(
|
cve2_csr #(
|
||||||
.Width ($bits(status_t)),
|
.Width ($bits(status_t)),
|
||||||
.ShadowCopy(ShadowCSR),
|
|
||||||
.ResetValue({MSTATUS_RST_VAL})
|
.ResetValue({MSTATUS_RST_VAL})
|
||||||
) u_mstatus_csr (
|
) u_mstatus_csr (
|
||||||
.clk_i (clk_i),
|
.clk_i (clk_i),
|
||||||
|
@ -891,7 +833,6 @@ module cve2_cs_registers #(
|
||||||
// MTVEC
|
// MTVEC
|
||||||
cve2_csr #(
|
cve2_csr #(
|
||||||
.Width (32),
|
.Width (32),
|
||||||
.ShadowCopy(ShadowCSR),
|
|
||||||
.ResetValue(32'd1)
|
.ResetValue(32'd1)
|
||||||
) u_mtvec_csr (
|
) u_mtvec_csr (
|
||||||
.clk_i (clk_i),
|
.clk_i (clk_i),
|
||||||
|
@ -1104,7 +1045,6 @@ module cve2_cs_registers #(
|
||||||
|
|
||||||
cve2_csr #(
|
cve2_csr #(
|
||||||
.Width ($bits(pmp_cfg_t)),
|
.Width ($bits(pmp_cfg_t)),
|
||||||
.ShadowCopy(ShadowCSR),
|
|
||||||
.ResetValue(pmp_cfg_rst[i])
|
.ResetValue(pmp_cfg_rst[i])
|
||||||
) u_pmp_cfg_csr (
|
) u_pmp_cfg_csr (
|
||||||
.clk_i (clk_i),
|
.clk_i (clk_i),
|
||||||
|
@ -1133,7 +1073,6 @@ module cve2_cs_registers #(
|
||||||
|
|
||||||
cve2_csr #(
|
cve2_csr #(
|
||||||
.Width (PMPAddrWidth),
|
.Width (PMPAddrWidth),
|
||||||
.ShadowCopy(ShadowCSR),
|
|
||||||
.ResetValue(pmp_addr_rst[i][33-:PMPAddrWidth])
|
.ResetValue(pmp_addr_rst[i][33-:PMPAddrWidth])
|
||||||
) u_pmp_addr_csr (
|
) u_pmp_addr_csr (
|
||||||
.clk_i (clk_i),
|
.clk_i (clk_i),
|
||||||
|
@ -1166,7 +1105,6 @@ module cve2_cs_registers #(
|
||||||
|
|
||||||
cve2_csr #(
|
cve2_csr #(
|
||||||
.Width ($bits(pmp_mseccfg_t)),
|
.Width ($bits(pmp_mseccfg_t)),
|
||||||
.ShadowCopy(ShadowCSR),
|
|
||||||
.ResetValue(pmp_mseccfg_rst)
|
.ResetValue(pmp_mseccfg_rst)
|
||||||
) u_pmp_mseccfg (
|
) u_pmp_mseccfg (
|
||||||
.clk_i (clk_i),
|
.clk_i (clk_i),
|
||||||
|
@ -1501,88 +1439,12 @@ module cve2_cs_registers #(
|
||||||
// CPU control register //
|
// CPU control register //
|
||||||
//////////////////////////
|
//////////////////////////
|
||||||
|
|
||||||
// Cast register write data
|
// Removed
|
||||||
assign cpuctrl_wdata_raw = cpu_ctrl_t'(csr_wdata_int[$bits(cpu_ctrl_t)-1:0]);
|
|
||||||
|
|
||||||
// Generate fixed time execution bit
|
|
||||||
if (DataIndTiming) begin : gen_dit
|
|
||||||
// SEC_CM: CORE.DATA_REG_SW.SCA
|
|
||||||
assign cpuctrl_wdata.data_ind_timing = cpuctrl_wdata_raw.data_ind_timing;
|
|
||||||
|
|
||||||
end else begin : gen_no_dit
|
|
||||||
// tieoff for the unused bit
|
|
||||||
logic unused_dit;
|
|
||||||
assign unused_dit = cpuctrl_wdata_raw.data_ind_timing;
|
|
||||||
|
|
||||||
// field will always read as zero if not configured
|
|
||||||
assign cpuctrl_wdata.data_ind_timing = 1'b0;
|
|
||||||
end
|
|
||||||
|
|
||||||
assign data_ind_timing_o = cpuctrl_q.data_ind_timing;
|
|
||||||
|
|
||||||
// Generate dummy instruction signals
|
|
||||||
if (DummyInstructions) begin : gen_dummy
|
|
||||||
// SEC_CM: CTRL_FLOW.UNPREDICTABLE
|
|
||||||
assign cpuctrl_wdata.dummy_instr_en = cpuctrl_wdata_raw.dummy_instr_en;
|
|
||||||
assign cpuctrl_wdata.dummy_instr_mask = cpuctrl_wdata_raw.dummy_instr_mask;
|
|
||||||
|
|
||||||
// Signal a write to the seed register
|
|
||||||
assign dummy_instr_seed_en_o = csr_we_int && (csr_addr == CSR_SECURESEED);
|
|
||||||
assign dummy_instr_seed_o = csr_wdata_int;
|
|
||||||
|
|
||||||
end else begin : gen_no_dummy
|
|
||||||
// tieoff for the unused bit
|
|
||||||
logic unused_dummy_en;
|
|
||||||
logic [2:0] unused_dummy_mask;
|
|
||||||
assign unused_dummy_en = cpuctrl_wdata_raw.dummy_instr_en;
|
|
||||||
assign unused_dummy_mask = cpuctrl_wdata_raw.dummy_instr_mask;
|
|
||||||
|
|
||||||
// field will always read as zero if not configured
|
|
||||||
assign cpuctrl_wdata.dummy_instr_en = 1'b0;
|
|
||||||
assign cpuctrl_wdata.dummy_instr_mask = 3'b000;
|
|
||||||
assign dummy_instr_seed_en_o = 1'b0;
|
|
||||||
assign dummy_instr_seed_o = '0;
|
|
||||||
end
|
|
||||||
|
|
||||||
assign dummy_instr_en_o = cpuctrl_q.dummy_instr_en;
|
|
||||||
assign dummy_instr_mask_o = cpuctrl_q.dummy_instr_mask;
|
|
||||||
|
|
||||||
// Generate icache enable bit
|
|
||||||
if (ICache) begin : gen_icache_enable
|
|
||||||
assign cpuctrl_wdata.icache_enable = cpuctrl_wdata_raw.icache_enable;
|
|
||||||
end else begin : gen_no_icache
|
|
||||||
// tieoff for the unused icen bit
|
|
||||||
logic unused_icen;
|
|
||||||
assign unused_icen = cpuctrl_wdata_raw.icache_enable;
|
|
||||||
|
|
||||||
// icen field will always read as zero if ICache not configured
|
|
||||||
assign cpuctrl_wdata.icache_enable = 1'b0;
|
|
||||||
end
|
|
||||||
|
|
||||||
assign cpuctrl_wdata.double_fault_seen = cpuctrl_wdata_raw.double_fault_seen;
|
|
||||||
assign cpuctrl_wdata.sync_exc_seen = cpuctrl_wdata_raw.sync_exc_seen;
|
|
||||||
|
|
||||||
assign icache_enable_o = cpuctrl_q.icache_enable;
|
|
||||||
|
|
||||||
cve2_csr #(
|
|
||||||
.Width ($bits(cpu_ctrl_t)),
|
|
||||||
.ShadowCopy(ShadowCSR),
|
|
||||||
.ResetValue('0)
|
|
||||||
) u_cpuctrl_csr (
|
|
||||||
.clk_i (clk_i),
|
|
||||||
.rst_ni (rst_ni),
|
|
||||||
.wr_data_i ({cpuctrl_d}),
|
|
||||||
.wr_en_i (cpuctrl_we),
|
|
||||||
.rd_data_o (cpuctrl_q),
|
|
||||||
.rd_error_o(cpuctrl_err)
|
|
||||||
);
|
|
||||||
|
|
||||||
assign csr_shadow_err_o = mstatus_err | mtvec_err | pmp_csr_err | cpuctrl_err;
|
|
||||||
|
|
||||||
////////////////
|
////////////////
|
||||||
// Assertions //
|
// Assertions //
|
||||||
////////////////
|
////////////////
|
||||||
|
|
||||||
`ASSERT(IbexCsrOpEnRequiresAccess, csr_op_en_i |-> csr_access_i)
|
`ASSERT(CVE2CsrOpEnRequiresAccess, csr_op_en_i |-> csr_access_i)
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
|
@ -30,8 +30,6 @@ module cve2_decoder #(
|
||||||
output logic ecall_insn_o, // syscall instr encountered
|
output logic ecall_insn_o, // syscall instr encountered
|
||||||
output logic wfi_insn_o, // wait for interrupt instr encountered
|
output logic wfi_insn_o, // wait for interrupt instr encountered
|
||||||
output logic jump_set_o, // jump taken set signal
|
output logic jump_set_o, // jump taken set signal
|
||||||
input logic branch_taken_i, // registered branch decision
|
|
||||||
output logic icache_inval_o,
|
|
||||||
|
|
||||||
// from IF-ID pipeline register
|
// from IF-ID pipeline register
|
||||||
input logic instr_first_cycle_i, // instruction read is in its first cycle
|
input logic instr_first_cycle_i, // instruction read is in its first cycle
|
||||||
|
@ -203,7 +201,6 @@ module cve2_decoder #(
|
||||||
jump_in_dec_o = 1'b0;
|
jump_in_dec_o = 1'b0;
|
||||||
jump_set_o = 1'b0;
|
jump_set_o = 1'b0;
|
||||||
branch_in_dec_o = 1'b0;
|
branch_in_dec_o = 1'b0;
|
||||||
icache_inval_o = 1'b0;
|
|
||||||
|
|
||||||
multdiv_operator_o = MD_OP_MULL;
|
multdiv_operator_o = MD_OP_MULL;
|
||||||
multdiv_signed_mode_o = 2'b00;
|
multdiv_signed_mode_o = 2'b00;
|
||||||
|
@ -569,14 +566,12 @@ module cve2_decoder #(
|
||||||
// FENCE.I is implemented as a jump to the next PC, this gives the required flushing
|
// FENCE.I is implemented as a jump to the next PC, this gives the required flushing
|
||||||
// behaviour (iside prefetch buffer flushed and response to any outstanding iside
|
// behaviour (iside prefetch buffer flushed and response to any outstanding iside
|
||||||
// requests will be ignored).
|
// requests will be ignored).
|
||||||
// If present, the ICache will also be flushed.
|
|
||||||
jump_in_dec_o = 1'b1;
|
jump_in_dec_o = 1'b1;
|
||||||
|
|
||||||
rf_we = 1'b0;
|
rf_we = 1'b0;
|
||||||
|
|
||||||
if (instr_first_cycle_i) begin
|
if (instr_first_cycle_i) begin
|
||||||
jump_set_o = 1'b1;
|
jump_set_o = 1'b1;
|
||||||
icache_inval_o = 1'b1;
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
default: begin
|
default: begin
|
||||||
|
@ -743,7 +738,7 @@ module cve2_decoder #(
|
||||||
alu_op_a_mux_sel_o = OP_A_CURRPC;
|
alu_op_a_mux_sel_o = OP_A_CURRPC;
|
||||||
alu_op_b_mux_sel_o = OP_B_IMM;
|
alu_op_b_mux_sel_o = OP_B_IMM;
|
||||||
// Not-taken branch will jump to next instruction (used in secure mode)
|
// Not-taken branch will jump to next instruction (used in secure mode)
|
||||||
imm_b_mux_sel_o = branch_taken_i ? IMM_B_B : IMM_B_INCR_PC;
|
imm_b_mux_sel_o = IMM_B_B;
|
||||||
alu_operator_o = ALU_ADD;
|
alu_operator_o = ALU_ADD;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,150 +0,0 @@
|
||||||
// Copyright lowRISC contributors.
|
|
||||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Dummy instruction module
|
|
||||||
*
|
|
||||||
* Provides pseudo-randomly inserted fake instructions for secure code obfuscation
|
|
||||||
*/
|
|
||||||
|
|
||||||
// SEC_CM: CTRL_FLOW.UNPREDICTABLE
|
|
||||||
module cve2_dummy_instr import cve2_pkg::*; #(
|
|
||||||
parameter lfsr_seed_t RndCnstLfsrSeed = RndCnstLfsrSeedDefault,
|
|
||||||
parameter lfsr_perm_t RndCnstLfsrPerm = RndCnstLfsrPermDefault
|
|
||||||
) (
|
|
||||||
// Clock and reset
|
|
||||||
input logic clk_i,
|
|
||||||
input logic rst_ni,
|
|
||||||
|
|
||||||
// Interface to CSRs
|
|
||||||
input logic dummy_instr_en_i,
|
|
||||||
input logic [2:0] dummy_instr_mask_i,
|
|
||||||
input logic dummy_instr_seed_en_i,
|
|
||||||
input logic [31:0] dummy_instr_seed_i,
|
|
||||||
|
|
||||||
// Interface to IF stage
|
|
||||||
input logic fetch_valid_i,
|
|
||||||
input logic id_in_ready_i,
|
|
||||||
output logic insert_dummy_instr_o,
|
|
||||||
output logic [31:0] dummy_instr_data_o
|
|
||||||
);
|
|
||||||
|
|
||||||
localparam int unsigned TIMEOUT_CNT_W = 5;
|
|
||||||
localparam int unsigned OP_W = 5;
|
|
||||||
|
|
||||||
typedef enum logic [1:0] {
|
|
||||||
DUMMY_ADD = 2'b00,
|
|
||||||
DUMMY_MUL = 2'b01,
|
|
||||||
DUMMY_DIV = 2'b10,
|
|
||||||
DUMMY_AND = 2'b11
|
|
||||||
} dummy_instr_e;
|
|
||||||
|
|
||||||
typedef struct packed {
|
|
||||||
dummy_instr_e instr_type;
|
|
||||||
logic [OP_W-1:0] op_b;
|
|
||||||
logic [OP_W-1:0] op_a;
|
|
||||||
logic [TIMEOUT_CNT_W-1:0] cnt;
|
|
||||||
} lfsr_data_t;
|
|
||||||
localparam int unsigned LFSR_OUT_W = $bits(lfsr_data_t);
|
|
||||||
|
|
||||||
lfsr_data_t lfsr_data;
|
|
||||||
logic [TIMEOUT_CNT_W-1:0] dummy_cnt_incr, dummy_cnt_threshold;
|
|
||||||
logic [TIMEOUT_CNT_W-1:0] dummy_cnt_d, dummy_cnt_q;
|
|
||||||
logic dummy_cnt_en;
|
|
||||||
logic lfsr_en;
|
|
||||||
logic [LFSR_OUT_W-1:0] lfsr_state;
|
|
||||||
logic insert_dummy_instr;
|
|
||||||
logic [6:0] dummy_set;
|
|
||||||
logic [2:0] dummy_opcode;
|
|
||||||
logic [31:0] dummy_instr;
|
|
||||||
logic [31:0] dummy_instr_seed_q, dummy_instr_seed_d;
|
|
||||||
|
|
||||||
// Shift the LFSR every time we insert an instruction
|
|
||||||
assign lfsr_en = insert_dummy_instr & id_in_ready_i;
|
|
||||||
|
|
||||||
assign dummy_instr_seed_d = dummy_instr_seed_q ^ dummy_instr_seed_i;
|
|
||||||
|
|
||||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
|
||||||
if (!rst_ni) begin
|
|
||||||
dummy_instr_seed_q <= '0;
|
|
||||||
end else if (dummy_instr_seed_en_i) begin
|
|
||||||
dummy_instr_seed_q <= dummy_instr_seed_d;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
prim_lfsr #(
|
|
||||||
.LfsrDw ( LfsrWidth ),
|
|
||||||
.StateOutDw ( LFSR_OUT_W ),
|
|
||||||
.DefaultSeed ( RndCnstLfsrSeed ),
|
|
||||||
.StatePermEn ( 1'b1 ),
|
|
||||||
.StatePerm ( RndCnstLfsrPerm )
|
|
||||||
) lfsr_i (
|
|
||||||
.clk_i ( clk_i ),
|
|
||||||
.rst_ni ( rst_ni ),
|
|
||||||
.seed_en_i ( dummy_instr_seed_en_i ),
|
|
||||||
.seed_i ( dummy_instr_seed_d ),
|
|
||||||
.lfsr_en_i ( lfsr_en ),
|
|
||||||
.entropy_i ( '0 ),
|
|
||||||
.state_o ( lfsr_state )
|
|
||||||
);
|
|
||||||
|
|
||||||
// Extract fields from LFSR
|
|
||||||
assign lfsr_data = lfsr_data_t'(lfsr_state);
|
|
||||||
|
|
||||||
// Set count threshold for inserting a new instruction. This is the pseudo-random value from the
|
|
||||||
// LFSR with a mask applied (based on CSR config data) to shorten the period if required.
|
|
||||||
assign dummy_cnt_threshold = lfsr_data.cnt & {dummy_instr_mask_i,{TIMEOUT_CNT_W-3{1'b1}}};
|
|
||||||
assign dummy_cnt_incr = dummy_cnt_q + {{TIMEOUT_CNT_W-1{1'b0}},1'b1};
|
|
||||||
// Clear the counter everytime a new instruction is inserted
|
|
||||||
assign dummy_cnt_d = insert_dummy_instr ? '0 : dummy_cnt_incr;
|
|
||||||
// Increment the counter for each executed instruction while dummy instuctions are
|
|
||||||
// enabled.
|
|
||||||
assign dummy_cnt_en = dummy_instr_en_i & id_in_ready_i &
|
|
||||||
(fetch_valid_i | insert_dummy_instr);
|
|
||||||
|
|
||||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
|
||||||
if (!rst_ni) begin
|
|
||||||
dummy_cnt_q <= '0;
|
|
||||||
end else if (dummy_cnt_en) begin
|
|
||||||
dummy_cnt_q <= dummy_cnt_d;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
// Insert a dummy instruction each time the counter hits the threshold
|
|
||||||
assign insert_dummy_instr = dummy_instr_en_i & (dummy_cnt_q == dummy_cnt_threshold);
|
|
||||||
|
|
||||||
// Encode instruction
|
|
||||||
always_comb begin
|
|
||||||
unique case (lfsr_data.instr_type)
|
|
||||||
DUMMY_ADD: begin
|
|
||||||
dummy_set = 7'b0000000;
|
|
||||||
dummy_opcode = 3'b000;
|
|
||||||
end
|
|
||||||
DUMMY_MUL: begin
|
|
||||||
dummy_set = 7'b0000001;
|
|
||||||
dummy_opcode = 3'b000;
|
|
||||||
end
|
|
||||||
DUMMY_DIV: begin
|
|
||||||
dummy_set = 7'b0000001;
|
|
||||||
dummy_opcode = 3'b100;
|
|
||||||
end
|
|
||||||
DUMMY_AND: begin
|
|
||||||
dummy_set = 7'b0000000;
|
|
||||||
dummy_opcode = 3'b111;
|
|
||||||
end
|
|
||||||
default: begin
|
|
||||||
dummy_set = 7'b0000000;
|
|
||||||
dummy_opcode = 3'b000;
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
|
|
||||||
// SET RS2 RS1 OP RD
|
|
||||||
assign dummy_instr = {dummy_set, lfsr_data.op_b, lfsr_data.op_a, dummy_opcode, 5'h00, 7'h33};
|
|
||||||
|
|
||||||
// Assign outputs
|
|
||||||
assign insert_dummy_instr_o = insert_dummy_instr;
|
|
||||||
assign dummy_instr_data_o = dummy_instr;
|
|
||||||
|
|
||||||
endmodule
|
|
|
@ -31,7 +31,6 @@ module cve2_ex_block #(
|
||||||
input logic [31:0] multdiv_operand_a_i,
|
input logic [31:0] multdiv_operand_a_i,
|
||||||
input logic [31:0] multdiv_operand_b_i,
|
input logic [31:0] multdiv_operand_b_i,
|
||||||
input logic multdiv_ready_id_i,
|
input logic multdiv_ready_id_i,
|
||||||
input logic data_ind_timing_i,
|
|
||||||
|
|
||||||
// intermediate val reg
|
// intermediate val reg
|
||||||
output logic [1:0] imd_val_we_o,
|
output logic [1:0] imd_val_we_o,
|
||||||
|
@ -135,7 +134,6 @@ module cve2_ex_block #(
|
||||||
.alu_adder_ext_i (alu_adder_result_ext),
|
.alu_adder_ext_i (alu_adder_result_ext),
|
||||||
.alu_adder_i (alu_adder_result_ex_o),
|
.alu_adder_i (alu_adder_result_ex_o),
|
||||||
.equal_to_zero_i (alu_is_equal_result),
|
.equal_to_zero_i (alu_is_equal_result),
|
||||||
.data_ind_timing_i (data_ind_timing_i),
|
|
||||||
.valid_o (multdiv_valid),
|
.valid_o (multdiv_valid),
|
||||||
.alu_operand_a_o (multdiv_alu_operand_a),
|
.alu_operand_a_o (multdiv_alu_operand_a),
|
||||||
.alu_operand_b_o (multdiv_alu_operand_b),
|
.alu_operand_b_o (multdiv_alu_operand_b),
|
||||||
|
@ -164,7 +162,6 @@ module cve2_ex_block #(
|
||||||
.alu_adder_ext_i (alu_adder_result_ext),
|
.alu_adder_ext_i (alu_adder_result_ext),
|
||||||
.alu_adder_i (alu_adder_result_ex_o),
|
.alu_adder_i (alu_adder_result_ex_o),
|
||||||
.equal_to_zero_i (alu_is_equal_result),
|
.equal_to_zero_i (alu_is_equal_result),
|
||||||
.data_ind_timing_i (data_ind_timing_i),
|
|
||||||
.imd_val_q_i (imd_val_q_i),
|
.imd_val_q_i (imd_val_q_i),
|
||||||
.imd_val_d_o (multdiv_imd_val_d),
|
.imd_val_d_o (multdiv_imd_val_d),
|
||||||
.imd_val_we_o (multdiv_imd_val_we),
|
.imd_val_we_o (multdiv_imd_val_we),
|
||||||
|
|
|
@ -13,8 +13,7 @@
|
||||||
`include "prim_assert.sv"
|
`include "prim_assert.sv"
|
||||||
|
|
||||||
module cve2_fetch_fifo #(
|
module cve2_fetch_fifo #(
|
||||||
parameter int unsigned NUM_REQS = 2,
|
parameter int unsigned NUM_REQS = 2
|
||||||
parameter bit ResetAll = 1'b0
|
|
||||||
) (
|
) (
|
||||||
input logic clk_i,
|
input logic clk_i,
|
||||||
input logic rst_ni,
|
input logic rst_ni,
|
||||||
|
@ -149,7 +148,7 @@ module cve2_fetch_fifo #(
|
||||||
assign instr_addr_d = clear_i ? in_addr_i[31:1] :
|
assign instr_addr_d = clear_i ? in_addr_i[31:1] :
|
||||||
instr_addr_next;
|
instr_addr_next;
|
||||||
|
|
||||||
if (ResetAll) begin : g_instr_addr_ra
|
begin : g_instr_addr
|
||||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||||
if (!rst_ni) begin
|
if (!rst_ni) begin
|
||||||
instr_addr_q <= '0;
|
instr_addr_q <= '0;
|
||||||
|
@ -157,12 +156,6 @@ module cve2_fetch_fifo #(
|
||||||
instr_addr_q <= instr_addr_d;
|
instr_addr_q <= instr_addr_d;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end else begin : g_instr_addr_nr
|
|
||||||
always_ff @(posedge clk_i) begin
|
|
||||||
if (instr_addr_en) begin
|
|
||||||
instr_addr_q <= instr_addr_d;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
// Output PC of current instruction
|
// Output PC of current instruction
|
||||||
|
@ -234,7 +227,7 @@ module cve2_fetch_fifo #(
|
||||||
end
|
end
|
||||||
|
|
||||||
for (genvar i = 0; i < DEPTH; i++) begin : g_fifo_regs
|
for (genvar i = 0; i < DEPTH; i++) begin : g_fifo_regs
|
||||||
if (ResetAll) begin : g_rdata_ra
|
begin : g_rdata
|
||||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||||
if (!rst_ni) begin
|
if (!rst_ni) begin
|
||||||
rdata_q[i] <= '0;
|
rdata_q[i] <= '0;
|
||||||
|
@ -244,13 +237,6 @@ module cve2_fetch_fifo #(
|
||||||
err_q[i] <= err_d[i];
|
err_q[i] <= err_d[i];
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end else begin : g_rdata_nr
|
|
||||||
always_ff @(posedge clk_i) begin
|
|
||||||
if (entry_en[i]) begin
|
|
||||||
rdata_q[i] <= rdata_d[i];
|
|
||||||
err_q[i] <= err_d[i];
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
1165
rtl/cve2_icache.sv
1165
rtl/cve2_icache.sv
File diff suppressed because it is too large
Load diff
|
@ -21,7 +21,6 @@ module cve2_id_stage #(
|
||||||
parameter bit RV32E = 0,
|
parameter bit RV32E = 0,
|
||||||
parameter cve2_pkg::rv32m_e RV32M = cve2_pkg::RV32MFast,
|
parameter cve2_pkg::rv32m_e RV32M = cve2_pkg::RV32MFast,
|
||||||
parameter cve2_pkg::rv32b_e RV32B = cve2_pkg::RV32BNone,
|
parameter cve2_pkg::rv32b_e RV32B = cve2_pkg::RV32BNone,
|
||||||
parameter bit DataIndTiming = 1'b0,
|
|
||||||
parameter bit WritebackStage = 0,
|
parameter bit WritebackStage = 0,
|
||||||
parameter bit BranchPredictor = 0
|
parameter bit BranchPredictor = 0
|
||||||
) (
|
) (
|
||||||
|
@ -42,7 +41,6 @@ module cve2_id_stage #(
|
||||||
output logic instr_first_cycle_id_o,
|
output logic instr_first_cycle_id_o,
|
||||||
output logic instr_valid_clear_o, // kill instr in IF-ID reg
|
output logic instr_valid_clear_o, // kill instr in IF-ID reg
|
||||||
output logic id_in_ready_o, // ID stage is ready for next instr
|
output logic id_in_ready_o, // ID stage is ready for next instr
|
||||||
output logic icache_inval_o,
|
|
||||||
|
|
||||||
// Jumps and branches
|
// Jumps and branches
|
||||||
input logic branch_decision_i,
|
input logic branch_decision_i,
|
||||||
|
@ -99,7 +97,6 @@ module cve2_id_stage #(
|
||||||
input cve2_pkg::priv_lvl_e priv_mode_i,
|
input cve2_pkg::priv_lvl_e priv_mode_i,
|
||||||
input logic csr_mstatus_tw_i,
|
input logic csr_mstatus_tw_i,
|
||||||
input logic illegal_csr_insn_i,
|
input logic illegal_csr_insn_i,
|
||||||
input logic data_ind_timing_i,
|
|
||||||
|
|
||||||
// Interface to load store unit
|
// Interface to load store unit
|
||||||
output logic lsu_req_o,
|
output logic lsu_req_o,
|
||||||
|
@ -195,7 +192,6 @@ module cve2_id_stage #(
|
||||||
logic branch_set, branch_set_raw, branch_set_raw_d;
|
logic branch_set, branch_set_raw, branch_set_raw_d;
|
||||||
logic branch_jump_set_done_q, branch_jump_set_done_d;
|
logic branch_jump_set_done_q, branch_jump_set_done_d;
|
||||||
logic branch_not_set;
|
logic branch_not_set;
|
||||||
logic branch_taken;
|
|
||||||
logic jump_in_dec;
|
logic jump_in_dec;
|
||||||
logic jump_set_dec;
|
logic jump_set_dec;
|
||||||
logic jump_set, jump_set_raw;
|
logic jump_set, jump_set_raw;
|
||||||
|
@ -384,8 +380,6 @@ module cve2_id_stage #(
|
||||||
.ecall_insn_o (ecall_insn_dec),
|
.ecall_insn_o (ecall_insn_dec),
|
||||||
.wfi_insn_o (wfi_insn_dec),
|
.wfi_insn_o (wfi_insn_dec),
|
||||||
.jump_set_o (jump_set_dec),
|
.jump_set_o (jump_set_dec),
|
||||||
.branch_taken_i(branch_taken),
|
|
||||||
.icache_inval_o(icache_inval_o),
|
|
||||||
|
|
||||||
// from IF-ID pipeline register
|
// from IF-ID pipeline register
|
||||||
.instr_first_cycle_i(instr_first_cycle),
|
.instr_first_cycle_i(instr_first_cycle),
|
||||||
|
@ -642,30 +636,6 @@ module cve2_id_stage #(
|
||||||
assign jump_set = jump_set_raw & ~branch_jump_set_done_q;
|
assign jump_set = jump_set_raw & ~branch_jump_set_done_q;
|
||||||
assign branch_set = branch_set_raw & ~branch_jump_set_done_q;
|
assign branch_set = branch_set_raw & ~branch_jump_set_done_q;
|
||||||
|
|
||||||
// Branch condition is calculated in the first cycle and flopped for use in the second cycle
|
|
||||||
// (only used in fixed time execution mode to determine branch destination).
|
|
||||||
if (DataIndTiming) begin : g_sec_branch_taken
|
|
||||||
// SEC_CM: CORE.DATA_REG_SW.SCA
|
|
||||||
logic branch_taken_q;
|
|
||||||
|
|
||||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
|
||||||
if (!rst_ni) begin
|
|
||||||
branch_taken_q <= 1'b0;
|
|
||||||
end else begin
|
|
||||||
branch_taken_q <= branch_decision_i;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
assign branch_taken = ~data_ind_timing_i | branch_taken_q;
|
|
||||||
|
|
||||||
end else begin : g_nosec_branch_taken
|
|
||||||
|
|
||||||
// Signal unused without fixed time execution mode - only taken branches will trigger
|
|
||||||
// branch_set_raw
|
|
||||||
assign branch_taken = 1'b1;
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
// Holding branch_set/jump_set high for more than one cycle should not cause a functional issue.
|
// Holding branch_set/jump_set high for more than one cycle should not cause a functional issue.
|
||||||
// However it could generate needless prefetch buffer flushes and instruction fetches. The ID/EX
|
// However it could generate needless prefetch buffer flushes and instruction fetches. The ID/EX
|
||||||
// designs ensures that this never happens for non-predicted branches.
|
// designs ensures that this never happens for non-predicted branches.
|
||||||
|
@ -743,13 +713,13 @@ module cve2_id_stage #(
|
||||||
// All branches take two cycles in fixed time execution mode, regardless of branch
|
// All branches take two cycles in fixed time execution mode, regardless of branch
|
||||||
// condition.
|
// condition.
|
||||||
// SEC_CM: CORE.DATA_REG_SW.SCA
|
// SEC_CM: CORE.DATA_REG_SW.SCA
|
||||||
id_fsm_d = (data_ind_timing_i || branch_decision_i) ?
|
id_fsm_d = (branch_decision_i) ?
|
||||||
MULTI_CYCLE : FIRST_CYCLE;
|
MULTI_CYCLE : FIRST_CYCLE;
|
||||||
stall_branch = (branch_decision_i | data_ind_timing_i);
|
stall_branch = branch_decision_i;
|
||||||
branch_set_raw_d = (branch_decision_i | data_ind_timing_i);
|
branch_set_raw_d = branch_decision_i;
|
||||||
|
|
||||||
if (BranchPredictor) begin
|
if (BranchPredictor) begin
|
||||||
branch_not_set = ~branch_decision_i;
|
branch_not_set = 1'b1;
|
||||||
end
|
end
|
||||||
|
|
||||||
perf_branch_o = 1'b1;
|
perf_branch_o = 1'b1;
|
||||||
|
@ -1004,8 +974,6 @@ module cve2_id_stage #(
|
||||||
|
|
||||||
`DV_FCOV_SIGNAL_GEN_IF(logic, rf_rd_wb_hz,
|
`DV_FCOV_SIGNAL_GEN_IF(logic, rf_rd_wb_hz,
|
||||||
(gen_stall_mem.rf_rd_a_hz | gen_stall_mem.rf_rd_b_hz) & instr_valid_i, WritebackStage)
|
(gen_stall_mem.rf_rd_a_hz | gen_stall_mem.rf_rd_b_hz) & instr_valid_i, WritebackStage)
|
||||||
`DV_FCOV_SIGNAL(logic, branch_taken,
|
|
||||||
instr_executing & (id_fsm_q == FIRST_CYCLE) & branch_decision_i)
|
|
||||||
`DV_FCOV_SIGNAL(logic, branch_not_taken,
|
`DV_FCOV_SIGNAL(logic, branch_not_taken,
|
||||||
instr_executing & (id_fsm_q == FIRST_CYCLE) & ~branch_decision_i)
|
instr_executing & (id_fsm_q == FIRST_CYCLE) & ~branch_decision_i)
|
||||||
|
|
||||||
|
|
|
@ -15,16 +15,6 @@
|
||||||
module cve2_if_stage import cve2_pkg::*; #(
|
module cve2_if_stage import cve2_pkg::*; #(
|
||||||
parameter int unsigned DmHaltAddr = 32'h1A110800,
|
parameter int unsigned DmHaltAddr = 32'h1A110800,
|
||||||
parameter int unsigned DmExceptionAddr = 32'h1A110808,
|
parameter int unsigned DmExceptionAddr = 32'h1A110808,
|
||||||
parameter bit DummyInstructions = 1'b0,
|
|
||||||
parameter bit ICache = 1'b0,
|
|
||||||
parameter bit ICacheECC = 1'b0,
|
|
||||||
parameter int unsigned BusSizeECC = BUS_SIZE,
|
|
||||||
parameter int unsigned TagSizeECC = IC_TAG_SIZE,
|
|
||||||
parameter int unsigned LineSizeECC = IC_LINE_SIZE,
|
|
||||||
parameter bit PCIncrCheck = 1'b0,
|
|
||||||
parameter bit ResetAll = 1'b0,
|
|
||||||
parameter lfsr_seed_t RndCnstLfsrSeed = RndCnstLfsrSeedDefault,
|
|
||||||
parameter lfsr_perm_t RndCnstLfsrPerm = RndCnstLfsrPermDefault,
|
|
||||||
parameter bit BranchPredictor = 1'b0
|
parameter bit BranchPredictor = 1'b0
|
||||||
) (
|
) (
|
||||||
input logic clk_i,
|
input logic clk_i,
|
||||||
|
@ -41,19 +31,6 @@ module cve2_if_stage import cve2_pkg::*; #(
|
||||||
input logic [31:0] instr_rdata_i,
|
input logic [31:0] instr_rdata_i,
|
||||||
input logic instr_err_i,
|
input logic instr_err_i,
|
||||||
|
|
||||||
// ICache RAM IO
|
|
||||||
output logic [IC_NUM_WAYS-1:0] ic_tag_req_o,
|
|
||||||
output logic ic_tag_write_o,
|
|
||||||
output logic [IC_INDEX_W-1:0] ic_tag_addr_o,
|
|
||||||
output logic [TagSizeECC-1:0] ic_tag_wdata_o,
|
|
||||||
input logic [TagSizeECC-1:0] ic_tag_rdata_i [IC_NUM_WAYS],
|
|
||||||
output logic [IC_NUM_WAYS-1:0] ic_data_req_o,
|
|
||||||
output logic ic_data_write_o,
|
|
||||||
output logic [IC_INDEX_W-1:0] ic_data_addr_o,
|
|
||||||
output logic [LineSizeECC-1:0] ic_data_wdata_o,
|
|
||||||
input logic [LineSizeECC-1:0] ic_data_rdata_i [IC_NUM_WAYS],
|
|
||||||
input logic ic_scr_key_valid_i,
|
|
||||||
|
|
||||||
// output of ID stage
|
// output of ID stage
|
||||||
output logic instr_valid_id_o, // instr in IF-ID is valid
|
output logic instr_valid_id_o, // instr in IF-ID is valid
|
||||||
output logic instr_new_id_o, // instr in IF-ID is new
|
output logic instr_new_id_o, // instr in IF-ID is new
|
||||||
|
@ -71,7 +48,6 @@ module cve2_if_stage import cve2_pkg::*; #(
|
||||||
output logic instr_fetch_err_plus2_o, // bus error misaligned
|
output logic instr_fetch_err_plus2_o, // bus error misaligned
|
||||||
output logic illegal_c_insn_id_o, // compressed decoder thinks this
|
output logic illegal_c_insn_id_o, // compressed decoder thinks this
|
||||||
// is an invalid instr
|
// is an invalid instr
|
||||||
output logic dummy_instr_id_o, // Instruction is a dummy
|
|
||||||
output logic [31:0] pc_if_o,
|
output logic [31:0] pc_if_o,
|
||||||
output logic [31:0] pc_id_o,
|
output logic [31:0] pc_id_o,
|
||||||
input logic pmp_err_if_i,
|
input logic pmp_err_if_i,
|
||||||
|
@ -87,14 +63,6 @@ module cve2_if_stage import cve2_pkg::*; #(
|
||||||
input exc_pc_sel_e exc_pc_mux_i, // selects ISR address
|
input exc_pc_sel_e exc_pc_mux_i, // selects ISR address
|
||||||
input exc_cause_e exc_cause, // selects ISR address for
|
input exc_cause_e exc_cause, // selects ISR address for
|
||||||
// vectorized interrupt lines
|
// vectorized interrupt lines
|
||||||
input logic dummy_instr_en_i,
|
|
||||||
input logic [2:0] dummy_instr_mask_i,
|
|
||||||
input logic dummy_instr_seed_en_i,
|
|
||||||
input logic [31:0] dummy_instr_seed_i,
|
|
||||||
input logic icache_enable_i,
|
|
||||||
input logic icache_inval_i,
|
|
||||||
output logic icache_ecc_error_o,
|
|
||||||
|
|
||||||
// jump and branch target
|
// jump and branch target
|
||||||
input logic [31:0] branch_target_ex_i, // branch/jump target address
|
input logic [31:0] branch_target_ex_i, // branch/jump target address
|
||||||
|
|
||||||
|
@ -110,7 +78,6 @@ module cve2_if_stage import cve2_pkg::*; #(
|
||||||
input logic id_in_ready_i, // ID stage is ready for new instr
|
input logic id_in_ready_i, // ID stage is ready for new instr
|
||||||
|
|
||||||
// misc signals
|
// misc signals
|
||||||
output logic pc_mismatch_alert_o,
|
|
||||||
output logic if_busy_o // IF stage is busy fetching instr
|
output logic if_busy_o // IF stage is busy fetching instr
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -149,13 +116,6 @@ module cve2_if_stage import cve2_pkg::*; #(
|
||||||
|
|
||||||
logic if_id_pipe_reg_we; // IF-ID pipeline reg write enable
|
logic if_id_pipe_reg_we; // IF-ID pipeline reg write enable
|
||||||
|
|
||||||
// Dummy instruction signals
|
|
||||||
logic stall_dummy_instr;
|
|
||||||
logic [31:0] instr_out;
|
|
||||||
logic instr_is_compressed_out;
|
|
||||||
logic illegal_c_instr_out;
|
|
||||||
logic instr_err_out;
|
|
||||||
|
|
||||||
logic predict_branch_taken;
|
logic predict_branch_taken;
|
||||||
logic [31:0] predict_branch_pc;
|
logic [31:0] predict_branch_pc;
|
||||||
|
|
||||||
|
@ -205,60 +165,9 @@ module cve2_if_stage import cve2_pkg::*; #(
|
||||||
// tell CS register file to initialize mtvec on boot
|
// tell CS register file to initialize mtvec on boot
|
||||||
assign csr_mtvec_init_o = (pc_mux_i == PC_BOOT) & pc_set_i;
|
assign csr_mtvec_init_o = (pc_mux_i == PC_BOOT) & pc_set_i;
|
||||||
|
|
||||||
if (ICache) begin : gen_icache
|
begin : gen_prefetch_buffer
|
||||||
// Full I-Cache option
|
|
||||||
cve2_icache #(
|
|
||||||
.ICacheECC (ICacheECC),
|
|
||||||
.ResetAll (ResetAll),
|
|
||||||
.BusSizeECC (BusSizeECC),
|
|
||||||
.TagSizeECC (TagSizeECC),
|
|
||||||
.LineSizeECC (LineSizeECC)
|
|
||||||
) icache_i (
|
|
||||||
.clk_i ( clk_i ),
|
|
||||||
.rst_ni ( rst_ni ),
|
|
||||||
|
|
||||||
.req_i ( req_i ),
|
|
||||||
|
|
||||||
.branch_i ( branch_req ),
|
|
||||||
.branch_mispredict_i ( nt_branch_mispredict_i ),
|
|
||||||
.mispredict_addr_i ( nt_branch_addr_i ),
|
|
||||||
.addr_i ( {fetch_addr_n[31:1], 1'b0} ),
|
|
||||||
|
|
||||||
.ready_i ( fetch_ready ),
|
|
||||||
.valid_o ( fetch_valid ),
|
|
||||||
.rdata_o ( fetch_rdata ),
|
|
||||||
.addr_o ( fetch_addr ),
|
|
||||||
.err_o ( fetch_err ),
|
|
||||||
.err_plus2_o ( fetch_err_plus2 ),
|
|
||||||
|
|
||||||
.instr_req_o ( instr_req_o ),
|
|
||||||
.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 ),
|
|
||||||
|
|
||||||
.ic_tag_req_o ( ic_tag_req_o ),
|
|
||||||
.ic_tag_write_o ( ic_tag_write_o ),
|
|
||||||
.ic_tag_addr_o ( ic_tag_addr_o ),
|
|
||||||
.ic_tag_wdata_o ( ic_tag_wdata_o ),
|
|
||||||
.ic_tag_rdata_i ( ic_tag_rdata_i ),
|
|
||||||
.ic_data_req_o ( ic_data_req_o ),
|
|
||||||
.ic_data_write_o ( ic_data_write_o ),
|
|
||||||
.ic_data_addr_o ( ic_data_addr_o ),
|
|
||||||
.ic_data_wdata_o ( ic_data_wdata_o ),
|
|
||||||
.ic_data_rdata_i ( ic_data_rdata_i ),
|
|
||||||
.ic_scr_key_valid_i ( ic_scr_key_valid_i ),
|
|
||||||
|
|
||||||
.icache_enable_i ( icache_enable_i ),
|
|
||||||
.icache_inval_i ( icache_inval_i ),
|
|
||||||
.busy_o ( prefetch_busy ),
|
|
||||||
.ecc_error_o ( icache_ecc_error_o )
|
|
||||||
);
|
|
||||||
end else begin : gen_prefetch_buffer
|
|
||||||
// prefetch buffer, caches a fixed number of instructions
|
// prefetch buffer, caches a fixed number of instructions
|
||||||
cve2_prefetch_buffer #(
|
cve2_prefetch_buffer #(
|
||||||
.ResetAll (ResetAll)
|
|
||||||
) prefetch_buffer_i (
|
) prefetch_buffer_i (
|
||||||
.clk_i ( clk_i ),
|
.clk_i ( clk_i ),
|
||||||
.rst_ni ( rst_ni ),
|
.rst_ni ( rst_ni ),
|
||||||
|
@ -286,40 +195,6 @@ module cve2_if_stage import cve2_pkg::*; #(
|
||||||
|
|
||||||
.busy_o ( prefetch_busy )
|
.busy_o ( prefetch_busy )
|
||||||
);
|
);
|
||||||
// ICache tieoffs
|
|
||||||
logic unused_icen, unused_icinv, unused_scr_key_valid;
|
|
||||||
logic [TagSizeECC-1:0] unused_tag_ram_input [IC_NUM_WAYS];
|
|
||||||
logic [LineSizeECC-1:0] unused_data_ram_input [IC_NUM_WAYS];
|
|
||||||
assign unused_icen = icache_enable_i;
|
|
||||||
assign unused_icinv = icache_inval_i;
|
|
||||||
assign unused_tag_ram_input = ic_tag_rdata_i;
|
|
||||||
assign unused_data_ram_input = ic_data_rdata_i;
|
|
||||||
assign unused_scr_key_valid = ic_scr_key_valid_i;
|
|
||||||
assign ic_tag_req_o = 'b0;
|
|
||||||
assign ic_tag_write_o = 'b0;
|
|
||||||
assign ic_tag_addr_o = 'b0;
|
|
||||||
assign ic_tag_wdata_o = 'b0;
|
|
||||||
assign ic_data_req_o = 'b0;
|
|
||||||
assign ic_data_write_o = 'b0;
|
|
||||||
assign ic_data_addr_o = 'b0;
|
|
||||||
assign ic_data_wdata_o = 'b0;
|
|
||||||
assign icache_ecc_error_o = 'b0;
|
|
||||||
|
|
||||||
`ifndef SYNTHESIS
|
|
||||||
// If we don't instantiate an icache and this is a simulation then we have a problem because the
|
|
||||||
// simulator might discard the icache module entirely, including some DPI exports that it
|
|
||||||
// implies. This then causes problems for linking against C++ testbench code that expected them.
|
|
||||||
// As a slightly ugly hack, let's define the DPI functions here (the real versions are defined
|
|
||||||
// in prim_util_get_scramble_params.svh)
|
|
||||||
export "DPI-C" function simutil_get_scramble_key;
|
|
||||||
export "DPI-C" function simutil_get_scramble_nonce;
|
|
||||||
function automatic int simutil_get_scramble_key(output bit [127:0] val);
|
|
||||||
return 0;
|
|
||||||
endfunction
|
|
||||||
function automatic int simutil_get_scramble_nonce(output bit [319:0] nonce);
|
|
||||||
return 0;
|
|
||||||
endfunction
|
|
||||||
`endif
|
|
||||||
end
|
end
|
||||||
|
|
||||||
assign unused_fetch_addr_n0 = fetch_addr_n[0];
|
assign unused_fetch_addr_n0 = fetch_addr_n[0];
|
||||||
|
@ -357,66 +232,6 @@ module cve2_if_stage import cve2_pkg::*; #(
|
||||||
.illegal_instr_o(illegal_c_insn)
|
.illegal_instr_o(illegal_c_insn)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Dummy instruction insertion
|
|
||||||
if (DummyInstructions) begin : gen_dummy_instr
|
|
||||||
// SEC_CM: CTRL_FLOW.UNPREDICTABLE
|
|
||||||
logic insert_dummy_instr;
|
|
||||||
logic [31:0] dummy_instr_data;
|
|
||||||
|
|
||||||
cve2_dummy_instr #(
|
|
||||||
.RndCnstLfsrSeed (RndCnstLfsrSeed),
|
|
||||||
.RndCnstLfsrPerm (RndCnstLfsrPerm)
|
|
||||||
) dummy_instr_i (
|
|
||||||
.clk_i (clk_i),
|
|
||||||
.rst_ni (rst_ni),
|
|
||||||
.dummy_instr_en_i (dummy_instr_en_i),
|
|
||||||
.dummy_instr_mask_i (dummy_instr_mask_i),
|
|
||||||
.dummy_instr_seed_en_i(dummy_instr_seed_en_i),
|
|
||||||
.dummy_instr_seed_i (dummy_instr_seed_i),
|
|
||||||
.fetch_valid_i (fetch_valid),
|
|
||||||
.id_in_ready_i (id_in_ready_i),
|
|
||||||
.insert_dummy_instr_o (insert_dummy_instr),
|
|
||||||
.dummy_instr_data_o (dummy_instr_data)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Mux between actual instructions and dummy instructions
|
|
||||||
assign instr_out = insert_dummy_instr ? dummy_instr_data : instr_decompressed;
|
|
||||||
assign instr_is_compressed_out = insert_dummy_instr ? 1'b0 : instr_is_compressed;
|
|
||||||
assign illegal_c_instr_out = insert_dummy_instr ? 1'b0 : illegal_c_insn;
|
|
||||||
assign instr_err_out = insert_dummy_instr ? 1'b0 : if_instr_err;
|
|
||||||
|
|
||||||
// Stall the IF stage if we insert a dummy instruction. The dummy will execute between whatever
|
|
||||||
// is currently in the ID stage and whatever is valid from the prefetch buffer this cycle. The
|
|
||||||
// PC of the dummy instruction will match whatever is next from the prefetch buffer.
|
|
||||||
assign stall_dummy_instr = insert_dummy_instr;
|
|
||||||
|
|
||||||
// Register the dummy instruction indication into the ID stage
|
|
||||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
|
||||||
if (!rst_ni) begin
|
|
||||||
dummy_instr_id_o <= 1'b0;
|
|
||||||
end else if (if_id_pipe_reg_we) begin
|
|
||||||
dummy_instr_id_o <= insert_dummy_instr;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end else begin : gen_no_dummy_instr
|
|
||||||
logic unused_dummy_en;
|
|
||||||
logic [2:0] unused_dummy_mask;
|
|
||||||
logic unused_dummy_seed_en;
|
|
||||||
logic [31:0] unused_dummy_seed;
|
|
||||||
|
|
||||||
assign unused_dummy_en = dummy_instr_en_i;
|
|
||||||
assign unused_dummy_mask = dummy_instr_mask_i;
|
|
||||||
assign unused_dummy_seed_en = dummy_instr_seed_en_i;
|
|
||||||
assign unused_dummy_seed = dummy_instr_seed_i;
|
|
||||||
assign instr_out = instr_decompressed;
|
|
||||||
assign instr_is_compressed_out = instr_is_compressed;
|
|
||||||
assign illegal_c_instr_out = illegal_c_insn;
|
|
||||||
assign instr_err_out = if_instr_err;
|
|
||||||
assign stall_dummy_instr = 1'b0;
|
|
||||||
assign dummy_instr_id_o = 1'b0;
|
|
||||||
end
|
|
||||||
|
|
||||||
// The ID stage becomes valid as soon as any instruction is registered in the ID stage flops.
|
// The ID stage becomes valid as soon as any instruction is registered in the ID stage flops.
|
||||||
// Note that the current instruction is squashed by the incoming pc_set_i signal.
|
// Note that the current instruction is squashed by the incoming pc_set_i signal.
|
||||||
// Valid is held until it is explicitly cleared (due to an instruction completing or an exception)
|
// Valid is held until it is explicitly cleared (due to an instruction completing or an exception)
|
||||||
|
@ -441,7 +256,7 @@ module cve2_if_stage import cve2_pkg::*; #(
|
||||||
// IF-ID pipeline registers, frozen when the ID stage is stalled
|
// IF-ID pipeline registers, frozen when the ID stage is stalled
|
||||||
assign if_id_pipe_reg_we = instr_new_id_d;
|
assign if_id_pipe_reg_we = instr_new_id_d;
|
||||||
|
|
||||||
if (ResetAll) begin : g_instr_rdata_ra
|
begin : g_instr_rdata
|
||||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||||
if (!rst_ni) begin
|
if (!rst_ni) begin
|
||||||
instr_rdata_id_o <= '0;
|
instr_rdata_id_o <= '0;
|
||||||
|
@ -453,65 +268,17 @@ module cve2_if_stage import cve2_pkg::*; #(
|
||||||
illegal_c_insn_id_o <= '0;
|
illegal_c_insn_id_o <= '0;
|
||||||
pc_id_o <= '0;
|
pc_id_o <= '0;
|
||||||
end else if (if_id_pipe_reg_we) begin
|
end else if (if_id_pipe_reg_we) begin
|
||||||
instr_rdata_id_o <= instr_out;
|
instr_rdata_id_o <= instr_decompressed;
|
||||||
// To reduce fan-out and help timing from the instr_rdata_id flops they are replicated.
|
// To reduce fan-out and help timing from the instr_rdata_id flops they are replicated.
|
||||||
instr_rdata_alu_id_o <= instr_out;
|
instr_rdata_alu_id_o <= instr_decompressed;
|
||||||
instr_fetch_err_o <= instr_err_out;
|
instr_fetch_err_o <= if_instr_err;
|
||||||
instr_fetch_err_plus2_o <= if_instr_err_plus2;
|
instr_fetch_err_plus2_o <= if_instr_err_plus2;
|
||||||
instr_rdata_c_id_o <= if_instr_rdata[15:0];
|
instr_rdata_c_id_o <= if_instr_rdata[15:0];
|
||||||
instr_is_compressed_id_o <= instr_is_compressed_out;
|
instr_is_compressed_id_o <= instr_is_compressed;
|
||||||
illegal_c_insn_id_o <= illegal_c_instr_out;
|
illegal_c_insn_id_o <= illegal_c_insn;
|
||||||
pc_id_o <= pc_if_o;
|
pc_id_o <= pc_if_o;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end else begin : g_instr_rdata_nr
|
|
||||||
always_ff @(posedge clk_i) begin
|
|
||||||
if (if_id_pipe_reg_we) begin
|
|
||||||
instr_rdata_id_o <= instr_out;
|
|
||||||
// To reduce fan-out and help timing from the instr_rdata_id flops they are replicated.
|
|
||||||
instr_rdata_alu_id_o <= instr_out;
|
|
||||||
instr_fetch_err_o <= instr_err_out;
|
|
||||||
instr_fetch_err_plus2_o <= if_instr_err_plus2;
|
|
||||||
instr_rdata_c_id_o <= if_instr_rdata[15:0];
|
|
||||||
instr_is_compressed_id_o <= instr_is_compressed_out;
|
|
||||||
illegal_c_insn_id_o <= illegal_c_instr_out;
|
|
||||||
pc_id_o <= pc_if_o;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
// Check for expected increments of the PC when security hardening enabled
|
|
||||||
if (PCIncrCheck) begin : g_secure_pc
|
|
||||||
// SEC_CM: PC.CTRL_FLOW.CONSISTENCY
|
|
||||||
logic [31:0] prev_instr_addr_incr, prev_instr_addr_incr_buf;
|
|
||||||
logic prev_instr_seq_q, prev_instr_seq_d;
|
|
||||||
|
|
||||||
// Do not check for sequential increase after a branch, jump, exception, interrupt or debug
|
|
||||||
// request, all of which will set branch_req. Also do not check after reset or for dummys.
|
|
||||||
assign prev_instr_seq_d = (prev_instr_seq_q | instr_new_id_d) &
|
|
||||||
~branch_req & ~if_instr_err & ~stall_dummy_instr;
|
|
||||||
|
|
||||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
|
||||||
if (!rst_ni) begin
|
|
||||||
prev_instr_seq_q <= 1'b0;
|
|
||||||
end else begin
|
|
||||||
prev_instr_seq_q <= prev_instr_seq_d;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
assign prev_instr_addr_incr = pc_id_o + (instr_is_compressed_id_o ? 32'd2 : 32'd4);
|
|
||||||
|
|
||||||
// Buffer anticipated next PC address to ensure optimiser cannot remove the check.
|
|
||||||
prim_buf #(.Width(32)) u_prev_instr_addr_incr_buf (
|
|
||||||
.in_i (prev_instr_addr_incr),
|
|
||||||
.out_o(prev_instr_addr_incr_buf)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Check that the address equals the previous address +2/+4
|
|
||||||
assign pc_mismatch_alert_o = prev_instr_seq_q & (pc_if_o != prev_instr_addr_incr_buf);
|
|
||||||
|
|
||||||
end else begin : g_no_secure_pc
|
|
||||||
assign pc_mismatch_alert_o = 1'b0;
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if (BranchPredictor) begin : g_branch_predictor
|
if (BranchPredictor) begin : g_branch_predictor
|
||||||
|
@ -525,7 +292,7 @@ module cve2_if_stage import cve2_pkg::*; #(
|
||||||
logic predict_branch_taken_raw;
|
logic predict_branch_taken_raw;
|
||||||
|
|
||||||
// ID stages needs to know if branch was predicted taken so it can signal mispredicts
|
// ID stages needs to know if branch was predicted taken so it can signal mispredicts
|
||||||
if (ResetAll) begin : g_bp_taken_ra
|
begin : g_bp_taken
|
||||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||||
if (!rst_ni) begin
|
if (!rst_ni) begin
|
||||||
instr_bp_taken_q <= '0;
|
instr_bp_taken_q <= '0;
|
||||||
|
@ -533,12 +300,6 @@ module cve2_if_stage import cve2_pkg::*; #(
|
||||||
instr_bp_taken_q <= instr_bp_taken_d;
|
instr_bp_taken_q <= instr_bp_taken_d;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end else begin : g_bp_taken_nr
|
|
||||||
always_ff @(posedge clk_i) begin
|
|
||||||
if (if_id_pipe_reg_we) begin
|
|
||||||
instr_bp_taken_q <= instr_bp_taken_d;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
// When branch prediction is enabled a skid buffer between the IF and ID/EX stage is introduced.
|
// When branch prediction is enabled a skid buffer between the IF and ID/EX stage is introduced.
|
||||||
|
@ -551,7 +312,7 @@ module cve2_if_stage import cve2_pkg::*; #(
|
||||||
|
|
||||||
assign instr_skid_en = predict_branch_taken & ~pc_set_i & ~id_in_ready_i & ~instr_skid_valid_q;
|
assign instr_skid_en = predict_branch_taken & ~pc_set_i & ~id_in_ready_i & ~instr_skid_valid_q;
|
||||||
|
|
||||||
assign instr_skid_valid_d = (instr_skid_valid_q & ~id_in_ready_i & ~stall_dummy_instr) |
|
assign instr_skid_valid_d = (instr_skid_valid_q & ~id_in_ready_i) |
|
||||||
instr_skid_en;
|
instr_skid_en;
|
||||||
|
|
||||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||||
|
@ -562,7 +323,7 @@ module cve2_if_stage import cve2_pkg::*; #(
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if (ResetAll) begin : g_instr_skid_ra
|
begin : g_instr_skid
|
||||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||||
if (!rst_ni) begin
|
if (!rst_ni) begin
|
||||||
instr_skid_bp_taken_q <= '0;
|
instr_skid_bp_taken_q <= '0;
|
||||||
|
@ -574,14 +335,6 @@ module cve2_if_stage import cve2_pkg::*; #(
|
||||||
instr_skid_addr_q <= fetch_addr;
|
instr_skid_addr_q <= fetch_addr;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end else begin : g_instr_skid_nr
|
|
||||||
always_ff @(posedge clk_i) begin
|
|
||||||
if (instr_skid_en) begin
|
|
||||||
instr_skid_bp_taken_q <= predict_branch_taken;
|
|
||||||
instr_skid_data_q <= fetch_rdata;
|
|
||||||
instr_skid_addr_q <= fetch_addr;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
cve2_branch_predict branch_predict_i (
|
cve2_branch_predict branch_predict_i (
|
||||||
|
@ -610,7 +363,7 @@ module cve2_if_stage import cve2_pkg::*; #(
|
||||||
assign if_instr_bus_err = ~instr_skid_valid_q & fetch_err;
|
assign if_instr_bus_err = ~instr_skid_valid_q & fetch_err;
|
||||||
assign instr_bp_taken_d = instr_skid_valid_q ? instr_skid_bp_taken_q : predict_branch_taken;
|
assign instr_bp_taken_d = instr_skid_valid_q ? instr_skid_bp_taken_q : predict_branch_taken;
|
||||||
|
|
||||||
assign fetch_ready = id_in_ready_i & ~stall_dummy_instr & ~instr_skid_valid_q;
|
assign fetch_ready = id_in_ready_i & ~instr_skid_valid_q;
|
||||||
|
|
||||||
assign instr_bp_taken_o = instr_bp_taken_q;
|
assign instr_bp_taken_o = instr_bp_taken_q;
|
||||||
|
|
||||||
|
@ -625,7 +378,7 @@ module cve2_if_stage import cve2_pkg::*; #(
|
||||||
assign if_instr_rdata = fetch_rdata;
|
assign if_instr_rdata = fetch_rdata;
|
||||||
assign if_instr_addr = fetch_addr;
|
assign if_instr_addr = fetch_addr;
|
||||||
assign if_instr_bus_err = fetch_err;
|
assign if_instr_bus_err = fetch_err;
|
||||||
assign fetch_ready = id_in_ready_i & ~stall_dummy_instr;
|
assign fetch_ready = id_in_ready_i;
|
||||||
end
|
end
|
||||||
|
|
||||||
////////////////
|
////////////////
|
||||||
|
|
|
@ -1,487 +0,0 @@
|
||||||
// Copyright lowRISC contributors.
|
|
||||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
// Ibex lockstep module
|
|
||||||
// This module instantiates a second copy of the core logic, and compares it's outputs against
|
|
||||||
// those from the main core. The second core runs synchronously with the main core, delayed by
|
|
||||||
// LockstepOffset cycles.
|
|
||||||
|
|
||||||
// SEC_CM: LOGIC.SHADOW
|
|
||||||
module cve2_lockstep import cve2_pkg::*; #(
|
|
||||||
parameter int unsigned LockstepOffset = 2,
|
|
||||||
parameter bit PMPEnable = 1'b0,
|
|
||||||
parameter int unsigned PMPGranularity = 0,
|
|
||||||
parameter int unsigned PMPNumRegions = 4,
|
|
||||||
parameter int unsigned MHPMCounterNum = 0,
|
|
||||||
parameter int unsigned MHPMCounterWidth = 40,
|
|
||||||
parameter bit RV32E = 1'b0,
|
|
||||||
parameter rv32m_e RV32M = RV32MFast,
|
|
||||||
parameter rv32b_e RV32B = RV32BNone,
|
|
||||||
parameter bit WritebackStage = 1'b0,
|
|
||||||
parameter bit ICache = 1'b0,
|
|
||||||
parameter bit ICacheECC = 1'b0,
|
|
||||||
parameter int unsigned BusSizeECC = BUS_SIZE,
|
|
||||||
parameter int unsigned TagSizeECC = IC_TAG_SIZE,
|
|
||||||
parameter int unsigned LineSizeECC = IC_LINE_SIZE,
|
|
||||||
parameter bit BranchPredictor = 1'b0,
|
|
||||||
parameter bit DbgTriggerEn = 1'b0,
|
|
||||||
parameter int unsigned DbgHwBreakNum = 1,
|
|
||||||
parameter bit ResetAll = 1'b0,
|
|
||||||
parameter lfsr_seed_t RndCnstLfsrSeed = RndCnstLfsrSeedDefault,
|
|
||||||
parameter lfsr_perm_t RndCnstLfsrPerm = RndCnstLfsrPermDefault,
|
|
||||||
parameter bit SecureIbex = 1'b0,
|
|
||||||
parameter bit DummyInstructions = 1'b0,
|
|
||||||
parameter bit RegFileECC = 1'b0,
|
|
||||||
parameter int unsigned DmHaltAddr = 32'h1A110800,
|
|
||||||
parameter int unsigned DmExceptionAddr = 32'h1A110808
|
|
||||||
) (
|
|
||||||
input logic clk_i,
|
|
||||||
input logic rst_ni,
|
|
||||||
|
|
||||||
input logic [31:0] hart_id_i,
|
|
||||||
input logic [31:0] boot_addr_i,
|
|
||||||
|
|
||||||
input logic instr_req_i,
|
|
||||||
input logic instr_gnt_i,
|
|
||||||
input logic instr_rvalid_i,
|
|
||||||
input logic [31:0] instr_addr_i,
|
|
||||||
input logic [31:0] instr_rdata_i,
|
|
||||||
input logic [6:0] instr_rdata_intg_i,
|
|
||||||
input logic instr_err_i,
|
|
||||||
|
|
||||||
input logic data_req_i,
|
|
||||||
input logic data_gnt_i,
|
|
||||||
input logic data_rvalid_i,
|
|
||||||
input logic data_we_i,
|
|
||||||
input logic [3:0] data_be_i,
|
|
||||||
input logic [31:0] data_addr_i,
|
|
||||||
input logic [31:0] data_wdata_i,
|
|
||||||
output logic [6:0] data_wdata_intg_o,
|
|
||||||
input logic [31:0] data_rdata_i,
|
|
||||||
input logic [6:0] data_rdata_intg_i,
|
|
||||||
input logic data_err_i,
|
|
||||||
|
|
||||||
input logic dummy_instr_id_i,
|
|
||||||
input logic [4:0] rf_raddr_a_i,
|
|
||||||
input logic [4:0] rf_raddr_b_i,
|
|
||||||
input logic [4:0] rf_waddr_wb_i,
|
|
||||||
input logic rf_we_wb_i,
|
|
||||||
input logic [31:0] rf_wdata_wb_ecc_i,
|
|
||||||
input logic [31:0] rf_rdata_a_ecc_i,
|
|
||||||
input logic [31:0] rf_rdata_b_ecc_i,
|
|
||||||
|
|
||||||
input logic [IC_NUM_WAYS-1:0] ic_tag_req_i,
|
|
||||||
input logic ic_tag_write_i,
|
|
||||||
input logic [IC_INDEX_W-1:0] ic_tag_addr_i,
|
|
||||||
input logic [TagSizeECC-1:0] ic_tag_wdata_i,
|
|
||||||
input logic [TagSizeECC-1:0] ic_tag_rdata_i [IC_NUM_WAYS],
|
|
||||||
input logic [IC_NUM_WAYS-1:0] ic_data_req_i,
|
|
||||||
input logic ic_data_write_i,
|
|
||||||
input logic [IC_INDEX_W-1:0] ic_data_addr_i,
|
|
||||||
input logic [LineSizeECC-1:0] ic_data_wdata_i,
|
|
||||||
input logic [LineSizeECC-1:0] ic_data_rdata_i [IC_NUM_WAYS],
|
|
||||||
input logic ic_scr_key_valid_i,
|
|
||||||
|
|
||||||
input logic irq_software_i,
|
|
||||||
input logic irq_timer_i,
|
|
||||||
input logic irq_external_i,
|
|
||||||
input logic [14:0] irq_fast_i,
|
|
||||||
input logic irq_nm_i,
|
|
||||||
input logic irq_pending_i,
|
|
||||||
|
|
||||||
input logic debug_req_i,
|
|
||||||
input crash_dump_t crash_dump_i,
|
|
||||||
input logic double_fault_seen_i,
|
|
||||||
|
|
||||||
input fetch_enable_t fetch_enable_i,
|
|
||||||
output logic alert_minor_o,
|
|
||||||
output logic alert_major_internal_o,
|
|
||||||
output logic alert_major_bus_o,
|
|
||||||
input logic icache_inval_i,
|
|
||||||
input logic core_busy_i,
|
|
||||||
input logic test_en_i,
|
|
||||||
input logic scan_rst_ni
|
|
||||||
);
|
|
||||||
|
|
||||||
localparam int unsigned LockstepOffsetW = $clog2(LockstepOffset);
|
|
||||||
// Core outputs are delayed for an extra cycle due to shadow output registers
|
|
||||||
localparam int unsigned OutputsOffset = LockstepOffset + 1;
|
|
||||||
|
|
||||||
//////////////////////
|
|
||||||
// Reset generation //
|
|
||||||
//////////////////////
|
|
||||||
|
|
||||||
// Upon reset, the comparison is stopped and the shadow core is reset, both immediately. A
|
|
||||||
// counter is started. After LockstepOffset clock cycles:
|
|
||||||
// - The counter is stopped.
|
|
||||||
// - The reset of the shadow core is synchronously released.
|
|
||||||
// The comparison is started in the following clock cycle.
|
|
||||||
|
|
||||||
logic [LockstepOffsetW-1:0] rst_shadow_cnt_d, rst_shadow_cnt_q, rst_shadow_cnt_incr;
|
|
||||||
// Internally generated resets cause IMPERFECTSCH warnings
|
|
||||||
/* verilator lint_off IMPERFECTSCH */
|
|
||||||
logic rst_shadow_set_d, rst_shadow_set_q;
|
|
||||||
logic rst_shadow_n, enable_cmp_q;
|
|
||||||
/* verilator lint_on IMPERFECTSCH */
|
|
||||||
|
|
||||||
assign rst_shadow_cnt_incr = rst_shadow_cnt_q + LockstepOffsetW'(1);
|
|
||||||
|
|
||||||
assign rst_shadow_set_d = (rst_shadow_cnt_q == LockstepOffsetW'(LockstepOffset - 1));
|
|
||||||
assign rst_shadow_cnt_d = rst_shadow_set_d ? rst_shadow_cnt_q : rst_shadow_cnt_incr;
|
|
||||||
|
|
||||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
|
||||||
if (!rst_ni) begin
|
|
||||||
rst_shadow_cnt_q <= '0;
|
|
||||||
enable_cmp_q <= '0;
|
|
||||||
end else begin
|
|
||||||
rst_shadow_cnt_q <= rst_shadow_cnt_d;
|
|
||||||
enable_cmp_q <= rst_shadow_set_q;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
// The primitives below are used to place size-only constraints in order to prevent
|
|
||||||
// synthesis optimizations and preserve anchor points for constraining backend tools.
|
|
||||||
prim_flop #(
|
|
||||||
.Width(1),
|
|
||||||
.ResetValue(1'b0)
|
|
||||||
) u_prim_rst_shadow_set_flop (
|
|
||||||
.clk_i (clk_i),
|
|
||||||
.rst_ni(rst_ni),
|
|
||||||
.d_i (rst_shadow_set_d),
|
|
||||||
.q_o (rst_shadow_set_q)
|
|
||||||
);
|
|
||||||
|
|
||||||
prim_clock_mux2 #(
|
|
||||||
.NoFpgaBufG(1'b1)
|
|
||||||
) u_prim_rst_shadow_n_mux2 (
|
|
||||||
.clk0_i(rst_shadow_set_q),
|
|
||||||
.clk1_i(scan_rst_ni),
|
|
||||||
.sel_i (test_en_i),
|
|
||||||
.clk_o (rst_shadow_n)
|
|
||||||
);
|
|
||||||
|
|
||||||
//////////////////
|
|
||||||
// Input delays //
|
|
||||||
//////////////////
|
|
||||||
|
|
||||||
typedef struct packed {
|
|
||||||
logic instr_gnt;
|
|
||||||
logic instr_rvalid;
|
|
||||||
logic [31:0] instr_rdata;
|
|
||||||
logic instr_err;
|
|
||||||
logic data_gnt;
|
|
||||||
logic data_rvalid;
|
|
||||||
logic [31:0] data_rdata;
|
|
||||||
logic data_err;
|
|
||||||
logic [31:0] rf_rdata_a_ecc;
|
|
||||||
logic [31:0] rf_rdata_b_ecc;
|
|
||||||
logic irq_software;
|
|
||||||
logic irq_timer;
|
|
||||||
logic irq_external;
|
|
||||||
logic [14:0] irq_fast;
|
|
||||||
logic irq_nm;
|
|
||||||
logic debug_req;
|
|
||||||
fetch_enable_t fetch_enable;
|
|
||||||
logic ic_scr_key_valid;
|
|
||||||
} delayed_inputs_t;
|
|
||||||
|
|
||||||
delayed_inputs_t [LockstepOffset-1:0] shadow_inputs_q;
|
|
||||||
delayed_inputs_t shadow_inputs_in;
|
|
||||||
logic [6:0] instr_rdata_intg_q, data_rdata_intg_q;
|
|
||||||
// Packed arrays must be dealt with separately
|
|
||||||
logic [TagSizeECC-1:0] shadow_tag_rdata_q [IC_NUM_WAYS][LockstepOffset];
|
|
||||||
logic [LineSizeECC-1:0] shadow_data_rdata_q [IC_NUM_WAYS][LockstepOffset];
|
|
||||||
|
|
||||||
// Assign the inputs to the delay structure
|
|
||||||
assign shadow_inputs_in.instr_gnt = instr_gnt_i;
|
|
||||||
assign shadow_inputs_in.instr_rvalid = instr_rvalid_i;
|
|
||||||
assign shadow_inputs_in.instr_rdata = instr_rdata_i;
|
|
||||||
assign shadow_inputs_in.instr_err = instr_err_i;
|
|
||||||
assign shadow_inputs_in.data_gnt = data_gnt_i;
|
|
||||||
assign shadow_inputs_in.data_rvalid = data_rvalid_i;
|
|
||||||
assign shadow_inputs_in.data_rdata = data_rdata_i;
|
|
||||||
assign shadow_inputs_in.data_err = data_err_i;
|
|
||||||
assign shadow_inputs_in.rf_rdata_a_ecc = rf_rdata_a_ecc_i;
|
|
||||||
assign shadow_inputs_in.rf_rdata_b_ecc = rf_rdata_b_ecc_i;
|
|
||||||
assign shadow_inputs_in.irq_software = irq_software_i;
|
|
||||||
assign shadow_inputs_in.irq_timer = irq_timer_i;
|
|
||||||
assign shadow_inputs_in.irq_external = irq_external_i;
|
|
||||||
assign shadow_inputs_in.irq_fast = irq_fast_i;
|
|
||||||
assign shadow_inputs_in.irq_nm = irq_nm_i;
|
|
||||||
assign shadow_inputs_in.debug_req = debug_req_i;
|
|
||||||
assign shadow_inputs_in.fetch_enable = fetch_enable_i;
|
|
||||||
assign shadow_inputs_in.ic_scr_key_valid = ic_scr_key_valid_i;
|
|
||||||
|
|
||||||
// Delay the inputs
|
|
||||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
|
||||||
if (!rst_ni) begin
|
|
||||||
instr_rdata_intg_q <= '0;
|
|
||||||
data_rdata_intg_q <= '0;
|
|
||||||
for (int unsigned i = 0; i < LockstepOffset; i++) begin
|
|
||||||
shadow_inputs_q[i] <= delayed_inputs_t'('0);
|
|
||||||
shadow_tag_rdata_q[i] <= '{default: 0};
|
|
||||||
shadow_data_rdata_q[i] <= '{default: 0};
|
|
||||||
end
|
|
||||||
end else begin
|
|
||||||
instr_rdata_intg_q <= instr_rdata_intg_i;
|
|
||||||
data_rdata_intg_q <= data_rdata_intg_i;
|
|
||||||
for (int unsigned i = 0; i < LockstepOffset - 1; i++) begin
|
|
||||||
shadow_inputs_q[i] <= shadow_inputs_q[i+1];
|
|
||||||
shadow_tag_rdata_q[i] <= shadow_tag_rdata_q[i+1];
|
|
||||||
shadow_data_rdata_q[i] <= shadow_data_rdata_q[i+1];
|
|
||||||
end
|
|
||||||
shadow_inputs_q[LockstepOffset-1] <= shadow_inputs_in;
|
|
||||||
shadow_tag_rdata_q[LockstepOffset-1] <= ic_tag_rdata_i;
|
|
||||||
shadow_data_rdata_q[LockstepOffset-1] <= ic_data_rdata_i;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
////////////////////////////
|
|
||||||
// Bus integrity checking //
|
|
||||||
////////////////////////////
|
|
||||||
|
|
||||||
// SEC_CM: BUS.INTEGRITY
|
|
||||||
logic bus_intg_err;
|
|
||||||
logic [1:0] instr_intg_err, data_intg_err;
|
|
||||||
logic [31:0] unused_wdata;
|
|
||||||
|
|
||||||
// Checks on incoming data
|
|
||||||
prim_secded_inv_39_32_dec u_instr_intg_dec (
|
|
||||||
.data_i ({instr_rdata_intg_q, shadow_inputs_q[LockstepOffset-1].instr_rdata}),
|
|
||||||
.data_o (),
|
|
||||||
.syndrome_o (),
|
|
||||||
.err_o (instr_intg_err)
|
|
||||||
);
|
|
||||||
|
|
||||||
prim_secded_inv_39_32_dec u_data_intg_dec (
|
|
||||||
.data_i ({data_rdata_intg_q, shadow_inputs_q[LockstepOffset-1].data_rdata}),
|
|
||||||
.data_o (),
|
|
||||||
.syndrome_o (),
|
|
||||||
.err_o (data_intg_err)
|
|
||||||
);
|
|
||||||
|
|
||||||
assign bus_intg_err = (shadow_inputs_q[LockstepOffset-1].instr_rvalid & |instr_intg_err) |
|
|
||||||
(shadow_inputs_q[LockstepOffset-1].data_rvalid & |data_intg_err);
|
|
||||||
|
|
||||||
// Generate integrity bits
|
|
||||||
prim_secded_inv_39_32_enc u_data_gen (
|
|
||||||
.data_i (data_wdata_i),
|
|
||||||
.data_o ({data_wdata_intg_o, unused_wdata})
|
|
||||||
);
|
|
||||||
|
|
||||||
///////////////////
|
|
||||||
// Output delays //
|
|
||||||
///////////////////
|
|
||||||
|
|
||||||
typedef struct packed {
|
|
||||||
logic instr_req;
|
|
||||||
logic [31:0] instr_addr;
|
|
||||||
logic data_req;
|
|
||||||
logic data_we;
|
|
||||||
logic [3:0] data_be;
|
|
||||||
logic [31:0] data_addr;
|
|
||||||
logic [31:0] data_wdata;
|
|
||||||
logic dummy_instr_id;
|
|
||||||
logic [4:0] rf_raddr_a;
|
|
||||||
logic [4:0] rf_raddr_b;
|
|
||||||
logic [4:0] rf_waddr_wb;
|
|
||||||
logic rf_we_wb;
|
|
||||||
logic [31:0] rf_wdata_wb_ecc;
|
|
||||||
logic [IC_NUM_WAYS-1:0] ic_tag_req;
|
|
||||||
logic ic_tag_write;
|
|
||||||
logic [IC_INDEX_W-1:0] ic_tag_addr;
|
|
||||||
logic [TagSizeECC-1:0] ic_tag_wdata;
|
|
||||||
logic [IC_NUM_WAYS-1:0] ic_data_req;
|
|
||||||
logic ic_data_write;
|
|
||||||
logic [IC_INDEX_W-1:0] ic_data_addr;
|
|
||||||
logic [LineSizeECC-1:0] ic_data_wdata;
|
|
||||||
logic irq_pending;
|
|
||||||
crash_dump_t crash_dump;
|
|
||||||
logic double_fault_seen;
|
|
||||||
logic icache_inval;
|
|
||||||
logic core_busy;
|
|
||||||
} delayed_outputs_t;
|
|
||||||
|
|
||||||
delayed_outputs_t [OutputsOffset-1:0] core_outputs_q;
|
|
||||||
delayed_outputs_t core_outputs_in;
|
|
||||||
delayed_outputs_t shadow_outputs_d, shadow_outputs_q;
|
|
||||||
|
|
||||||
// Assign core outputs to the structure
|
|
||||||
assign core_outputs_in.instr_req = instr_req_i;
|
|
||||||
assign core_outputs_in.instr_addr = instr_addr_i;
|
|
||||||
assign core_outputs_in.data_req = data_req_i;
|
|
||||||
assign core_outputs_in.data_we = data_we_i;
|
|
||||||
assign core_outputs_in.data_be = data_be_i;
|
|
||||||
assign core_outputs_in.data_addr = data_addr_i;
|
|
||||||
assign core_outputs_in.data_wdata = data_wdata_i;
|
|
||||||
assign core_outputs_in.dummy_instr_id = dummy_instr_id_i;
|
|
||||||
assign core_outputs_in.rf_raddr_a = rf_raddr_a_i;
|
|
||||||
assign core_outputs_in.rf_raddr_b = rf_raddr_b_i;
|
|
||||||
assign core_outputs_in.rf_waddr_wb = rf_waddr_wb_i;
|
|
||||||
assign core_outputs_in.rf_we_wb = rf_we_wb_i;
|
|
||||||
assign core_outputs_in.rf_wdata_wb_ecc = rf_wdata_wb_ecc_i;
|
|
||||||
assign core_outputs_in.ic_tag_req = ic_tag_req_i;
|
|
||||||
assign core_outputs_in.ic_tag_write = ic_tag_write_i;
|
|
||||||
assign core_outputs_in.ic_tag_addr = ic_tag_addr_i;
|
|
||||||
assign core_outputs_in.ic_tag_wdata = ic_tag_wdata_i;
|
|
||||||
assign core_outputs_in.ic_data_req = ic_data_req_i;
|
|
||||||
assign core_outputs_in.ic_data_write = ic_data_write_i;
|
|
||||||
assign core_outputs_in.ic_data_addr = ic_data_addr_i;
|
|
||||||
assign core_outputs_in.ic_data_wdata = ic_data_wdata_i;
|
|
||||||
assign core_outputs_in.irq_pending = irq_pending_i;
|
|
||||||
assign core_outputs_in.crash_dump = crash_dump_i;
|
|
||||||
assign core_outputs_in.double_fault_seen = double_fault_seen_i;
|
|
||||||
assign core_outputs_in.icache_inval = icache_inval_i;
|
|
||||||
assign core_outputs_in.core_busy = core_busy_i;
|
|
||||||
|
|
||||||
// Delay the outputs
|
|
||||||
always_ff @(posedge clk_i) begin
|
|
||||||
for (int unsigned i = 0; i < OutputsOffset - 1; i++) begin
|
|
||||||
core_outputs_q[i] <= core_outputs_q[i+1];
|
|
||||||
end
|
|
||||||
core_outputs_q[OutputsOffset-1] <= core_outputs_in;
|
|
||||||
end
|
|
||||||
|
|
||||||
///////////////////////////////
|
|
||||||
// Shadow core instantiation //
|
|
||||||
///////////////////////////////
|
|
||||||
|
|
||||||
logic shadow_alert_minor, shadow_alert_major;
|
|
||||||
|
|
||||||
cve2_core #(
|
|
||||||
.PMPEnable ( PMPEnable ),
|
|
||||||
.PMPGranularity ( PMPGranularity ),
|
|
||||||
.PMPNumRegions ( PMPNumRegions ),
|
|
||||||
.MHPMCounterNum ( MHPMCounterNum ),
|
|
||||||
.MHPMCounterWidth ( MHPMCounterWidth ),
|
|
||||||
.RV32E ( RV32E ),
|
|
||||||
.RV32M ( RV32M ),
|
|
||||||
.RV32B ( RV32B ),
|
|
||||||
.ICache ( ICache ),
|
|
||||||
.ICacheECC ( ICacheECC ),
|
|
||||||
.BusSizeECC ( BusSizeECC ),
|
|
||||||
.TagSizeECC ( TagSizeECC ),
|
|
||||||
.LineSizeECC ( LineSizeECC ),
|
|
||||||
.BranchPredictor ( BranchPredictor ),
|
|
||||||
.DbgTriggerEn ( DbgTriggerEn ),
|
|
||||||
.DbgHwBreakNum ( DbgHwBreakNum ),
|
|
||||||
.WritebackStage ( WritebackStage ),
|
|
||||||
.ResetAll ( ResetAll ),
|
|
||||||
.RndCnstLfsrSeed ( RndCnstLfsrSeed ),
|
|
||||||
.RndCnstLfsrPerm ( RndCnstLfsrPerm ),
|
|
||||||
.SecureIbex ( SecureIbex ),
|
|
||||||
.DummyInstructions ( DummyInstructions ),
|
|
||||||
.RegFileECC ( RegFileECC ),
|
|
||||||
.DmHaltAddr ( DmHaltAddr ),
|
|
||||||
.DmExceptionAddr ( DmExceptionAddr )
|
|
||||||
) u_shadow_core (
|
|
||||||
.clk_i (clk_i),
|
|
||||||
.rst_ni (rst_shadow_n),
|
|
||||||
|
|
||||||
.hart_id_i (hart_id_i),
|
|
||||||
.boot_addr_i (boot_addr_i),
|
|
||||||
|
|
||||||
.instr_req_o (shadow_outputs_d.instr_req),
|
|
||||||
.instr_gnt_i (shadow_inputs_q[0].instr_gnt),
|
|
||||||
.instr_rvalid_i (shadow_inputs_q[0].instr_rvalid),
|
|
||||||
.instr_addr_o (shadow_outputs_d.instr_addr),
|
|
||||||
.instr_rdata_i (shadow_inputs_q[0].instr_rdata),
|
|
||||||
.instr_err_i (shadow_inputs_q[0].instr_err),
|
|
||||||
|
|
||||||
.data_req_o (shadow_outputs_d.data_req),
|
|
||||||
.data_gnt_i (shadow_inputs_q[0].data_gnt),
|
|
||||||
.data_rvalid_i (shadow_inputs_q[0].data_rvalid),
|
|
||||||
.data_we_o (shadow_outputs_d.data_we),
|
|
||||||
.data_be_o (shadow_outputs_d.data_be),
|
|
||||||
.data_addr_o (shadow_outputs_d.data_addr),
|
|
||||||
.data_wdata_o (shadow_outputs_d.data_wdata),
|
|
||||||
.data_rdata_i (shadow_inputs_q[0].data_rdata),
|
|
||||||
.data_err_i (shadow_inputs_q[0].data_err),
|
|
||||||
|
|
||||||
.dummy_instr_id_o (shadow_outputs_d.dummy_instr_id),
|
|
||||||
.rf_raddr_a_o (shadow_outputs_d.rf_raddr_a),
|
|
||||||
.rf_raddr_b_o (shadow_outputs_d.rf_raddr_b),
|
|
||||||
.rf_waddr_wb_o (shadow_outputs_d.rf_waddr_wb),
|
|
||||||
.rf_we_wb_o (shadow_outputs_d.rf_we_wb),
|
|
||||||
.rf_wdata_wb_ecc_o (shadow_outputs_d.rf_wdata_wb_ecc),
|
|
||||||
.rf_rdata_a_ecc_i (shadow_inputs_q[0].rf_rdata_a_ecc),
|
|
||||||
.rf_rdata_b_ecc_i (shadow_inputs_q[0].rf_rdata_b_ecc),
|
|
||||||
|
|
||||||
.ic_tag_req_o (shadow_outputs_d.ic_tag_req),
|
|
||||||
.ic_tag_write_o (shadow_outputs_d.ic_tag_write),
|
|
||||||
.ic_tag_addr_o (shadow_outputs_d.ic_tag_addr),
|
|
||||||
.ic_tag_wdata_o (shadow_outputs_d.ic_tag_wdata),
|
|
||||||
.ic_tag_rdata_i (shadow_tag_rdata_q[0]),
|
|
||||||
.ic_data_req_o (shadow_outputs_d.ic_data_req),
|
|
||||||
.ic_data_write_o (shadow_outputs_d.ic_data_write),
|
|
||||||
.ic_data_addr_o (shadow_outputs_d.ic_data_addr),
|
|
||||||
.ic_data_wdata_o (shadow_outputs_d.ic_data_wdata),
|
|
||||||
.ic_data_rdata_i (shadow_data_rdata_q[0]),
|
|
||||||
.ic_scr_key_valid_i (shadow_inputs_q[0].ic_scr_key_valid),
|
|
||||||
|
|
||||||
.irq_software_i (shadow_inputs_q[0].irq_software),
|
|
||||||
.irq_timer_i (shadow_inputs_q[0].irq_timer),
|
|
||||||
.irq_external_i (shadow_inputs_q[0].irq_external),
|
|
||||||
.irq_fast_i (shadow_inputs_q[0].irq_fast),
|
|
||||||
.irq_nm_i (shadow_inputs_q[0].irq_nm),
|
|
||||||
.irq_pending_o (shadow_outputs_d.irq_pending),
|
|
||||||
|
|
||||||
.debug_req_i (shadow_inputs_q[0].debug_req),
|
|
||||||
.crash_dump_o (shadow_outputs_d.crash_dump),
|
|
||||||
.double_fault_seen_o (shadow_outputs_d.double_fault_seen),
|
|
||||||
|
|
||||||
`ifdef RVFI
|
|
||||||
.rvfi_valid (),
|
|
||||||
.rvfi_order (),
|
|
||||||
.rvfi_insn (),
|
|
||||||
.rvfi_trap (),
|
|
||||||
.rvfi_halt (),
|
|
||||||
.rvfi_intr (),
|
|
||||||
.rvfi_mode (),
|
|
||||||
.rvfi_ixl (),
|
|
||||||
.rvfi_rs1_addr (),
|
|
||||||
.rvfi_rs2_addr (),
|
|
||||||
.rvfi_rs3_addr (),
|
|
||||||
.rvfi_rs1_rdata (),
|
|
||||||
.rvfi_rs2_rdata (),
|
|
||||||
.rvfi_rs3_rdata (),
|
|
||||||
.rvfi_rd_addr (),
|
|
||||||
.rvfi_rd_wdata (),
|
|
||||||
.rvfi_pc_rdata (),
|
|
||||||
.rvfi_pc_wdata (),
|
|
||||||
.rvfi_mem_addr (),
|
|
||||||
.rvfi_mem_rmask (),
|
|
||||||
.rvfi_mem_wmask (),
|
|
||||||
.rvfi_mem_rdata (),
|
|
||||||
.rvfi_mem_wdata (),
|
|
||||||
.rvfi_ext_mip (),
|
|
||||||
.rvfi_ext_nmi (),
|
|
||||||
.rvfi_ext_debug_req (),
|
|
||||||
.rvfi_ext_mcycle (),
|
|
||||||
`endif
|
|
||||||
|
|
||||||
.fetch_enable_i (shadow_inputs_q[0].fetch_enable),
|
|
||||||
.alert_minor_o (shadow_alert_minor),
|
|
||||||
.alert_major_o (shadow_alert_major),
|
|
||||||
.icache_inval_o (shadow_outputs_d.icache_inval),
|
|
||||||
.core_busy_o (shadow_outputs_d.core_busy)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Register the shadow core outputs
|
|
||||||
always_ff @(posedge clk_i) begin
|
|
||||||
shadow_outputs_q <= shadow_outputs_d;
|
|
||||||
end
|
|
||||||
|
|
||||||
/////////////////////////
|
|
||||||
// Compare the outputs //
|
|
||||||
/////////////////////////
|
|
||||||
|
|
||||||
logic outputs_mismatch;
|
|
||||||
|
|
||||||
assign outputs_mismatch = enable_cmp_q & (shadow_outputs_q != core_outputs_q[0]);
|
|
||||||
assign alert_major_internal_o = outputs_mismatch | shadow_alert_major;
|
|
||||||
assign alert_major_bus_o = bus_intg_err;
|
|
||||||
assign alert_minor_o = shadow_alert_minor;
|
|
||||||
|
|
||||||
endmodule
|
|
|
@ -30,7 +30,6 @@ module cve2_multdiv_fast #(
|
||||||
input logic [33:0] alu_adder_ext_i,
|
input logic [33:0] alu_adder_ext_i,
|
||||||
input logic [31:0] alu_adder_i,
|
input logic [31:0] alu_adder_i,
|
||||||
input logic equal_to_zero_i,
|
input logic equal_to_zero_i,
|
||||||
input logic data_ind_timing_i,
|
|
||||||
|
|
||||||
output logic [32:0] alu_operand_a_o,
|
output logic [32:0] alu_operand_a_o,
|
||||||
output logic [32:0] alu_operand_b_o,
|
output logic [32:0] alu_operand_b_o,
|
||||||
|
@ -424,7 +423,7 @@ module cve2_multdiv_fast #(
|
||||||
// normal and will naturally return -1
|
// normal and will naturally return -1
|
||||||
op_remainder_d = '1;
|
op_remainder_d = '1;
|
||||||
// SEC_CM: CORE.DATA_REG_SW.SCA
|
// SEC_CM: CORE.DATA_REG_SW.SCA
|
||||||
md_state_d = (!data_ind_timing_i && equal_to_zero_i) ? MD_FINISH : MD_ABS_A;
|
md_state_d = equal_to_zero_i ? MD_FINISH : MD_ABS_A;
|
||||||
// Record that this is a div by zero to stop the sign change at the end of the
|
// Record that this is a div by zero to stop the sign change at the end of the
|
||||||
// division (in data_ind_timing mode).
|
// division (in data_ind_timing mode).
|
||||||
div_by_zero_d = equal_to_zero_i;
|
div_by_zero_d = equal_to_zero_i;
|
||||||
|
@ -435,7 +434,7 @@ module cve2_multdiv_fast #(
|
||||||
// normal and will naturally return operand a
|
// normal and will naturally return operand a
|
||||||
op_remainder_d = {2'b0, op_a_i};
|
op_remainder_d = {2'b0, op_a_i};
|
||||||
// SEC_CM: CORE.DATA_REG_SW.SCA
|
// SEC_CM: CORE.DATA_REG_SW.SCA
|
||||||
md_state_d = (!data_ind_timing_i && equal_to_zero_i) ? MD_FINISH : MD_ABS_A;
|
md_state_d = equal_to_zero_i ? MD_FINISH : MD_ABS_A;
|
||||||
end
|
end
|
||||||
// 0 - B = 0 iff B == 0
|
// 0 - B = 0 iff B == 0
|
||||||
alu_operand_a_o = {32'h0 , 1'b1};
|
alu_operand_a_o = {32'h0 , 1'b1};
|
||||||
|
|
|
@ -26,7 +26,6 @@ module cve2_multdiv_slow
|
||||||
input logic [33:0] alu_adder_ext_i,
|
input logic [33:0] alu_adder_ext_i,
|
||||||
input logic [31:0] alu_adder_i,
|
input logic [31:0] alu_adder_i,
|
||||||
input logic equal_to_zero_i,
|
input logic equal_to_zero_i,
|
||||||
input logic data_ind_timing_i,
|
|
||||||
|
|
||||||
output logic [32:0] alu_operand_a_o,
|
output logic [32:0] alu_operand_a_o,
|
||||||
output logic [32:0] alu_operand_b_o,
|
output logic [32:0] alu_operand_b_o,
|
||||||
|
@ -191,7 +190,7 @@ module cve2_multdiv_slow
|
||||||
op_b_shift_d = op_b_ext >> 1;
|
op_b_shift_d = op_b_ext >> 1;
|
||||||
// Proceed with multiplication by 0/1 in data-independent time mode
|
// Proceed with multiplication by 0/1 in data-independent time mode
|
||||||
// SEC_CM: CORE.DATA_REG_SW.SCA
|
// SEC_CM: CORE.DATA_REG_SW.SCA
|
||||||
md_state_d = (!data_ind_timing_i && ((op_b_ext >> 1) == 0)) ? MD_LAST : MD_COMP;
|
md_state_d = ((op_b_ext >> 1) == 0) ? MD_LAST : MD_COMP;
|
||||||
end
|
end
|
||||||
MD_OP_MULH: begin
|
MD_OP_MULH: begin
|
||||||
op_a_shift_d = op_a_ext;
|
op_a_shift_d = op_a_ext;
|
||||||
|
@ -207,7 +206,7 @@ module cve2_multdiv_slow
|
||||||
// normal and will naturally return -1
|
// normal and will naturally return -1
|
||||||
accum_window_d = {33{1'b1}};
|
accum_window_d = {33{1'b1}};
|
||||||
// SEC_CM: CORE.DATA_REG_SW.SCA
|
// SEC_CM: CORE.DATA_REG_SW.SCA
|
||||||
md_state_d = (!data_ind_timing_i && equal_to_zero_i) ? MD_FINISH : MD_ABS_A;
|
md_state_d = equal_to_zero_i ? MD_FINISH : MD_ABS_A;
|
||||||
// Record that this is a div by zero to stop the sign change at the end of the
|
// Record that this is a div by zero to stop the sign change at the end of the
|
||||||
// division (in data_ind_timing mode).
|
// division (in data_ind_timing mode).
|
||||||
div_by_zero_d = equal_to_zero_i;
|
div_by_zero_d = equal_to_zero_i;
|
||||||
|
@ -219,7 +218,7 @@ module cve2_multdiv_slow
|
||||||
// normal and will naturally return operand a
|
// normal and will naturally return operand a
|
||||||
accum_window_d = op_a_ext;
|
accum_window_d = op_a_ext;
|
||||||
// SEC_CM: CORE.DATA_REG_SW.SCA
|
// SEC_CM: CORE.DATA_REG_SW.SCA
|
||||||
md_state_d = (!data_ind_timing_i && equal_to_zero_i) ? MD_FINISH : MD_ABS_A;
|
md_state_d = equal_to_zero_i ? MD_FINISH : MD_ABS_A;
|
||||||
end
|
end
|
||||||
default:;
|
default:;
|
||||||
endcase
|
endcase
|
||||||
|
@ -252,7 +251,7 @@ module cve2_multdiv_slow
|
||||||
// Multiplication is complete once op_b is zero, unless in data_ind_timing mode where
|
// Multiplication is complete once op_b is zero, unless in data_ind_timing mode where
|
||||||
// the maximum possible shift-add operations will be completed regardless of op_b
|
// the maximum possible shift-add operations will be completed regardless of op_b
|
||||||
// SEC_CM: CORE.DATA_REG_SW.SCA
|
// SEC_CM: CORE.DATA_REG_SW.SCA
|
||||||
md_state_d = ((!data_ind_timing_i && (op_b_shift_d == 0)) ||
|
md_state_d = ((op_b_shift_d == 0) ||
|
||||||
(multdiv_count_q == 5'd1)) ? MD_LAST : MD_COMP;
|
(multdiv_count_q == 5'd1)) ? MD_LAST : MD_COMP;
|
||||||
end
|
end
|
||||||
MD_OP_MULH: begin
|
MD_OP_MULH: begin
|
||||||
|
|
|
@ -329,27 +329,6 @@ package cve2_pkg;
|
||||||
DBG_CAUSE_STEP = 3'h4
|
DBG_CAUSE_STEP = 3'h4
|
||||||
} dbg_cause_e;
|
} dbg_cause_e;
|
||||||
|
|
||||||
// ICache constants
|
|
||||||
parameter int unsigned ADDR_W = 32;
|
|
||||||
parameter int unsigned BUS_SIZE = 32;
|
|
||||||
parameter int unsigned BUS_BYTES = BUS_SIZE/8;
|
|
||||||
parameter int unsigned BUS_W = $clog2(BUS_BYTES);
|
|
||||||
parameter int unsigned IC_SIZE_BYTES = 4096;
|
|
||||||
parameter int unsigned IC_NUM_WAYS = 2;
|
|
||||||
parameter int unsigned IC_LINE_SIZE = 64;
|
|
||||||
parameter int unsigned IC_LINE_BYTES = IC_LINE_SIZE/8;
|
|
||||||
parameter int unsigned IC_LINE_W = $clog2(IC_LINE_BYTES);
|
|
||||||
parameter int unsigned IC_NUM_LINES = IC_SIZE_BYTES / IC_NUM_WAYS / IC_LINE_BYTES;
|
|
||||||
parameter int unsigned IC_LINE_BEATS = IC_LINE_BYTES / BUS_BYTES;
|
|
||||||
parameter int unsigned IC_LINE_BEATS_W = $clog2(IC_LINE_BEATS);
|
|
||||||
parameter int unsigned IC_INDEX_W = $clog2(IC_NUM_LINES);
|
|
||||||
parameter int unsigned IC_INDEX_HI = IC_INDEX_W + IC_LINE_W - 1;
|
|
||||||
parameter int unsigned IC_TAG_SIZE = ADDR_W - IC_INDEX_W - IC_LINE_W + 1; // 1 valid bit
|
|
||||||
parameter int unsigned IC_OUTPUT_BEATS = (BUS_BYTES / 2); // number of halfwords
|
|
||||||
// ICache Scrambling Parameters
|
|
||||||
parameter int unsigned SCRAMBLE_KEY_W = 128;
|
|
||||||
parameter int unsigned SCRAMBLE_NONCE_W = 64;
|
|
||||||
|
|
||||||
// PMP constants
|
// PMP constants
|
||||||
parameter int unsigned PMP_MAX_REGIONS = 16;
|
parameter int unsigned PMP_MAX_REGIONS = 16;
|
||||||
parameter int unsigned PMP_CFG_W = 8;
|
parameter int unsigned PMP_CFG_W = 8;
|
||||||
|
@ -592,29 +571,5 @@ package cve2_pkg;
|
||||||
// version here using their own unique encoding (e.g. 32 bits of the git hash of the implemented
|
// version here using their own unique encoding (e.g. 32 bits of the git hash of the implemented
|
||||||
// commit).
|
// commit).
|
||||||
localparam logic [31:0] CSR_MIMPID_VALUE = 32'b0;
|
localparam logic [31:0] CSR_MIMPID_VALUE = 32'b0;
|
||||||
|
|
||||||
// These LFSR parameters have been generated with
|
|
||||||
// $ opentitan/util/design/gen-lfsr-seed.py --width 32 --seed 2480124384 --prefix ""
|
|
||||||
parameter int LfsrWidth = 32;
|
|
||||||
typedef logic [LfsrWidth-1:0] lfsr_seed_t;
|
|
||||||
typedef logic [LfsrWidth-1:0][$clog2(LfsrWidth)-1:0] lfsr_perm_t;
|
|
||||||
parameter lfsr_seed_t RndCnstLfsrSeedDefault = 32'hac533bf4;
|
|
||||||
parameter lfsr_perm_t RndCnstLfsrPermDefault = {
|
|
||||||
160'h1e35ecba467fd1b12e958152c04fa43878a8daed
|
|
||||||
};
|
|
||||||
parameter logic [SCRAMBLE_KEY_W-1:0] RndCnstIbexKeyDefault =
|
|
||||||
128'h14e8cecae3040d5e12286bb3cc113298;
|
|
||||||
parameter logic [SCRAMBLE_NONCE_W-1:0] RndCnstIbexNonceDefault =
|
|
||||||
64'hf79780bc735f3843;
|
|
||||||
|
|
||||||
// Fetch enable. Mult-bit signal used for security hardening. For non-secure implementation all
|
|
||||||
// bits other than the bottom bit are ignored.
|
|
||||||
typedef logic [3:0] fetch_enable_t;
|
|
||||||
|
|
||||||
// Note that if adjusting these parameters it is assumed the bottom bit is set for On and unset
|
|
||||||
// for Off. This allows the use of FetchEnableOn/FetchEnableOff to work for both secure and
|
|
||||||
// non-secure Ibex. If this assumption is broken the RTL that uses the fetch_enable signal within
|
|
||||||
// `cve2_core` may need adjusting.
|
|
||||||
parameter fetch_enable_t FetchEnableOn = 4'b1001;
|
|
||||||
parameter fetch_enable_t FetchEnableOff = 4'b0110;
|
|
||||||
endpackage
|
endpackage
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
* paths to the instruction cache.
|
* paths to the instruction cache.
|
||||||
*/
|
*/
|
||||||
module cve2_prefetch_buffer #(
|
module cve2_prefetch_buffer #(
|
||||||
parameter bit ResetAll = 1'b0
|
|
||||||
) (
|
) (
|
||||||
input logic clk_i,
|
input logic clk_i,
|
||||||
input logic rst_ni,
|
input logic rst_ni,
|
||||||
|
@ -95,8 +94,7 @@ module cve2_prefetch_buffer #(
|
||||||
assign fifo_ready = ~&(fifo_busy | rdata_outstanding_rev);
|
assign fifo_ready = ~&(fifo_busy | rdata_outstanding_rev);
|
||||||
|
|
||||||
cve2_fetch_fifo #(
|
cve2_fetch_fifo #(
|
||||||
.NUM_REQS (NUM_REQS),
|
.NUM_REQS (NUM_REQS)
|
||||||
.ResetAll (ResetAll)
|
|
||||||
) fifo_i (
|
) fifo_i (
|
||||||
.clk_i ( clk_i ),
|
.clk_i ( clk_i ),
|
||||||
.rst_ni ( rst_ni ),
|
.rst_ni ( rst_ni ),
|
||||||
|
@ -156,7 +154,7 @@ module cve2_prefetch_buffer #(
|
||||||
assign stored_addr_d = instr_addr;
|
assign stored_addr_d = instr_addr;
|
||||||
|
|
||||||
// CPU resets with a branch, so no need to reset these addresses
|
// CPU resets with a branch, so no need to reset these addresses
|
||||||
if (ResetAll) begin : g_stored_addr_ra
|
begin : g_stored_addr
|
||||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||||
if (!rst_ni) begin
|
if (!rst_ni) begin
|
||||||
stored_addr_q <= '0;
|
stored_addr_q <= '0;
|
||||||
|
@ -164,12 +162,6 @@ module cve2_prefetch_buffer #(
|
||||||
stored_addr_q <= stored_addr_d;
|
stored_addr_q <= stored_addr_d;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end else begin : g_stored_addr_nr
|
|
||||||
always_ff @(posedge clk_i) begin
|
|
||||||
if (stored_addr_en) begin
|
|
||||||
stored_addr_q <= stored_addr_d;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
// 2. fetch_addr_q
|
// 2. fetch_addr_q
|
||||||
|
|
||||||
|
@ -182,7 +174,7 @@ module cve2_prefetch_buffer #(
|
||||||
// Current address + 4
|
// Current address + 4
|
||||||
{{29{1'b0}},(valid_new_req & ~valid_req_q),2'b00};
|
{{29{1'b0}},(valid_new_req & ~valid_req_q),2'b00};
|
||||||
|
|
||||||
if (ResetAll) begin : g_fetch_addr_ra
|
begin : g_fetch_addr
|
||||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||||
if (!rst_ni) begin
|
if (!rst_ni) begin
|
||||||
fetch_addr_q <= '0;
|
fetch_addr_q <= '0;
|
||||||
|
@ -190,12 +182,6 @@ module cve2_prefetch_buffer #(
|
||||||
fetch_addr_q <= fetch_addr_d;
|
fetch_addr_q <= fetch_addr_d;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end else begin : g_fetch_addr_nr
|
|
||||||
always_ff @(posedge clk_i) begin
|
|
||||||
if (fetch_addr_en) begin
|
|
||||||
fetch_addr_q <= fetch_addr_d;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
// Address mux
|
// Address mux
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
module cve2_register_file_ff #(
|
module cve2_register_file_ff #(
|
||||||
parameter bit RV32E = 0,
|
parameter bit RV32E = 0,
|
||||||
parameter int unsigned DataWidth = 32,
|
parameter int unsigned DataWidth = 32,
|
||||||
parameter bit DummyInstructions = 0,
|
|
||||||
parameter logic [DataWidth-1:0] WordZeroVal = '0
|
parameter logic [DataWidth-1:0] WordZeroVal = '0
|
||||||
) (
|
) (
|
||||||
// Clock and Reset
|
// Clock and Reset
|
||||||
|
@ -21,7 +20,6 @@ module cve2_register_file_ff #(
|
||||||
input logic rst_ni,
|
input logic rst_ni,
|
||||||
|
|
||||||
input logic test_en_i,
|
input logic test_en_i,
|
||||||
input logic dummy_instr_id_i,
|
|
||||||
|
|
||||||
//Read port R1
|
//Read port R1
|
||||||
input logic [4:0] raddr_a_i,
|
input logic [4:0] raddr_a_i,
|
||||||
|
@ -63,31 +61,7 @@ module cve2_register_file_ff #(
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
// With dummy instructions enabled, R0 behaves as a real register but will always return 0 for
|
begin : g_normal_r0
|
||||||
// real instructions.
|
|
||||||
if (DummyInstructions) begin : g_dummy_r0
|
|
||||||
// SEC_CM: CTRL_FLOW.UNPREDICTABLE
|
|
||||||
logic we_r0_dummy;
|
|
||||||
logic [DataWidth-1:0] rf_r0_q;
|
|
||||||
|
|
||||||
// Write enable for dummy R0 register (waddr_a_i will always be 0 for dummy instructions)
|
|
||||||
assign we_r0_dummy = we_a_i & dummy_instr_id_i;
|
|
||||||
|
|
||||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
|
||||||
if (!rst_ni) begin
|
|
||||||
rf_r0_q <= WordZeroVal;
|
|
||||||
end else if (we_r0_dummy) begin
|
|
||||||
rf_r0_q <= wdata_a_i;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
// Output the dummy data for dummy instructions, otherwise R0 reads as zero
|
|
||||||
assign rf_reg[0] = dummy_instr_id_i ? rf_r0_q : WordZeroVal;
|
|
||||||
|
|
||||||
end else begin : g_normal_r0
|
|
||||||
logic unused_dummy_instr_id;
|
|
||||||
assign unused_dummy_instr_id = dummy_instr_id_i;
|
|
||||||
|
|
||||||
// R0 is nil
|
// R0 is nil
|
||||||
assign rf_reg[0] = WordZeroVal;
|
assign rf_reg[0] = WordZeroVal;
|
||||||
end
|
end
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
module cve2_register_file_fpga #(
|
module cve2_register_file_fpga #(
|
||||||
parameter bit RV32E = 0,
|
parameter bit RV32E = 0,
|
||||||
parameter int unsigned DataWidth = 32,
|
parameter int unsigned DataWidth = 32,
|
||||||
parameter bit DummyInstructions = 0,
|
|
||||||
parameter logic [DataWidth-1:0] WordZeroVal = '0
|
parameter logic [DataWidth-1:0] WordZeroVal = '0
|
||||||
) (
|
) (
|
||||||
// Clock and Reset
|
// Clock and Reset
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
module cve2_register_file_latch #(
|
module cve2_register_file_latch #(
|
||||||
parameter bit RV32E = 0,
|
parameter bit RV32E = 0,
|
||||||
parameter int unsigned DataWidth = 32,
|
parameter int unsigned DataWidth = 32,
|
||||||
parameter bit DummyInstructions = 0,
|
|
||||||
parameter logic [DataWidth-1:0] WordZeroVal = '0
|
parameter logic [DataWidth-1:0] WordZeroVal = '0
|
||||||
) (
|
) (
|
||||||
// Clock and Reset
|
// Clock and Reset
|
||||||
|
@ -119,35 +118,7 @@ module cve2_register_file_latch #(
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
// With dummy instructions enabled, R0 behaves as a real register but will always return 0 for
|
begin : g_normal_r0
|
||||||
// real instructions.
|
|
||||||
if (DummyInstructions) begin : g_dummy_r0
|
|
||||||
// SEC_CM: CTRL_FLOW.UNPREDICTABLE
|
|
||||||
logic we_r0_dummy;
|
|
||||||
logic r0_clock;
|
|
||||||
logic [DataWidth-1:0] mem_r0;
|
|
||||||
|
|
||||||
// Write enable for dummy R0 register (waddr_a_i will always be 0 for dummy instructions)
|
|
||||||
assign we_r0_dummy = we_a_i & dummy_instr_id_i;
|
|
||||||
|
|
||||||
// R0 clock gate
|
|
||||||
prim_clock_gating cg_i (
|
|
||||||
.clk_i ( clk_int ),
|
|
||||||
.en_i ( we_r0_dummy ),
|
|
||||||
.test_en_i ( test_en_i ),
|
|
||||||
.clk_o ( r0_clock )
|
|
||||||
);
|
|
||||||
|
|
||||||
always_latch begin : latch_wdata
|
|
||||||
if (r0_clock) begin
|
|
||||||
mem_r0 = wdata_a_q;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
// Output the dummy data for dummy instructions, otherwise R0 reads as zero
|
|
||||||
assign mem[0] = dummy_instr_id_i ? mem_r0 : WordZeroVal;
|
|
||||||
|
|
||||||
end else begin : g_normal_r0
|
|
||||||
logic unused_dummy_instr_id;
|
logic unused_dummy_instr_id;
|
||||||
assign unused_dummy_instr_id = dummy_instr_id_i;
|
assign unused_dummy_instr_id = dummy_instr_id_i;
|
||||||
|
|
||||||
|
|
612
rtl/cve2_top.sv
612
rtl/cve2_top.sv
|
@ -19,18 +19,9 @@ module cve2_top import cve2_pkg::*; #(
|
||||||
parameter rv32m_e RV32M = RV32MFast,
|
parameter rv32m_e RV32M = RV32MFast,
|
||||||
parameter regfile_e RegFile = RegFileFF,
|
parameter regfile_e RegFile = RegFileFF,
|
||||||
parameter bit WritebackStage = 1'b0,
|
parameter bit WritebackStage = 1'b0,
|
||||||
parameter bit ICache = 1'b0,
|
|
||||||
parameter bit ICacheECC = 1'b0,
|
|
||||||
parameter bit BranchPredictor = 1'b0,
|
parameter bit BranchPredictor = 1'b0,
|
||||||
parameter bit SecureIbex = 1'b0,
|
|
||||||
parameter bit ICacheScramble = 1'b0,
|
|
||||||
parameter lfsr_seed_t RndCnstLfsrSeed = RndCnstLfsrSeedDefault,
|
|
||||||
parameter lfsr_perm_t RndCnstLfsrPerm = RndCnstLfsrPermDefault,
|
|
||||||
parameter int unsigned DmHaltAddr = 32'h1A110800,
|
parameter int unsigned DmHaltAddr = 32'h1A110800,
|
||||||
parameter int unsigned DmExceptionAddr = 32'h1A110808,
|
parameter int unsigned DmExceptionAddr = 32'h1A110808
|
||||||
// Default seed and nonce for scrambling
|
|
||||||
parameter logic [SCRAMBLE_KEY_W-1:0] RndCnstIbexKey = RndCnstIbexKeyDefault,
|
|
||||||
parameter logic [SCRAMBLE_NONCE_W-1:0] RndCnstIbexNonce = RndCnstIbexNonceDefault
|
|
||||||
) (
|
) (
|
||||||
// Clock and Reset
|
// Clock and Reset
|
||||||
input logic clk_i,
|
input logic clk_i,
|
||||||
|
@ -71,16 +62,9 @@ module cve2_top import cve2_pkg::*; #(
|
||||||
input logic [14:0] irq_fast_i,
|
input logic [14:0] irq_fast_i,
|
||||||
input logic irq_nm_i, // non-maskeable interrupt
|
input logic irq_nm_i, // non-maskeable interrupt
|
||||||
|
|
||||||
// Scrambling Interface
|
|
||||||
input logic scramble_key_valid_i,
|
|
||||||
input logic [SCRAMBLE_KEY_W-1:0] scramble_key_i,
|
|
||||||
input logic [SCRAMBLE_NONCE_W-1:0] scramble_nonce_i,
|
|
||||||
output logic scramble_req_o,
|
|
||||||
|
|
||||||
// Debug Interface
|
// Debug Interface
|
||||||
input logic debug_req_i,
|
input logic debug_req_i,
|
||||||
output crash_dump_t crash_dump_o,
|
output crash_dump_t crash_dump_o,
|
||||||
output logic double_fault_seen_o,
|
|
||||||
|
|
||||||
// RISC-V Formal Interface
|
// RISC-V Formal Interface
|
||||||
// Does not comply with the coding standards of _i/_o suffixes, but follows
|
// Does not comply with the coding standards of _i/_o suffixes, but follows
|
||||||
|
@ -116,7 +100,6 @@ module cve2_top import cve2_pkg::*; #(
|
||||||
`endif
|
`endif
|
||||||
|
|
||||||
// CPU Control Signals
|
// CPU Control Signals
|
||||||
input fetch_enable_t fetch_enable_i,
|
|
||||||
output logic alert_minor_o,
|
output logic alert_minor_o,
|
||||||
output logic alert_major_internal_o,
|
output logic alert_major_internal_o,
|
||||||
output logic alert_major_bus_o,
|
output logic alert_major_bus_o,
|
||||||
|
@ -126,16 +109,8 @@ module cve2_top import cve2_pkg::*; #(
|
||||||
input logic scan_rst_ni
|
input logic scan_rst_ni
|
||||||
);
|
);
|
||||||
|
|
||||||
localparam bit Lockstep = SecureIbex;
|
|
||||||
localparam bit ResetAll = Lockstep;
|
|
||||||
localparam bit DummyInstructions = SecureIbex;
|
|
||||||
localparam bit RegFileECC = SecureIbex;
|
|
||||||
// Icache parameters
|
|
||||||
localparam int unsigned BusSizeECC = ICacheECC ? (BUS_SIZE + 7) : BUS_SIZE;
|
|
||||||
localparam int unsigned LineSizeECC = BusSizeECC * IC_LINE_BEATS;
|
|
||||||
localparam int unsigned TagSizeECC = ICacheECC ? (IC_TAG_SIZE + 6) : IC_TAG_SIZE;
|
|
||||||
// Scrambling Parameter
|
// Scrambling Parameter
|
||||||
localparam int unsigned NumAddrScrRounds = ICacheScramble ? 2 : 0;
|
localparam int unsigned NumAddrScrRounds = 0;
|
||||||
localparam int unsigned NumDiffRounds = NumAddrScrRounds;
|
localparam int unsigned NumDiffRounds = NumAddrScrRounds;
|
||||||
|
|
||||||
// Physical Memory Protection
|
// Physical Memory Protection
|
||||||
|
@ -156,7 +131,6 @@ module cve2_top import cve2_pkg::*; #(
|
||||||
logic clock_en;
|
logic clock_en;
|
||||||
logic irq_pending;
|
logic irq_pending;
|
||||||
// Core <-> Register file signals
|
// Core <-> Register file signals
|
||||||
logic dummy_instr_id;
|
|
||||||
logic [4:0] rf_raddr_a;
|
logic [4:0] rf_raddr_a;
|
||||||
logic [4:0] rf_raddr_b;
|
logic [4:0] rf_raddr_b;
|
||||||
logic [4:0] rf_waddr_wb;
|
logic [4:0] rf_waddr_wb;
|
||||||
|
@ -164,29 +138,8 @@ module cve2_top import cve2_pkg::*; #(
|
||||||
logic [31:0] rf_wdata_wb_ecc;
|
logic [31:0] rf_wdata_wb_ecc;
|
||||||
logic [31:0] rf_rdata_a_ecc, rf_rdata_a_ecc_buf;
|
logic [31:0] rf_rdata_a_ecc, rf_rdata_a_ecc_buf;
|
||||||
logic [31:0] rf_rdata_b_ecc, rf_rdata_b_ecc_buf;
|
logic [31:0] rf_rdata_b_ecc, rf_rdata_b_ecc_buf;
|
||||||
// Core <-> RAMs signals
|
|
||||||
logic [IC_NUM_WAYS-1:0] ic_tag_req;
|
|
||||||
logic ic_tag_write;
|
|
||||||
logic [IC_INDEX_W-1:0] ic_tag_addr;
|
|
||||||
logic [TagSizeECC-1:0] ic_tag_wdata;
|
|
||||||
logic [TagSizeECC-1:0] ic_tag_rdata [IC_NUM_WAYS];
|
|
||||||
logic [IC_NUM_WAYS-1:0] ic_data_req;
|
|
||||||
logic ic_data_write;
|
|
||||||
logic [IC_INDEX_W-1:0] ic_data_addr;
|
|
||||||
logic [LineSizeECC-1:0] ic_data_wdata;
|
|
||||||
logic [LineSizeECC-1:0] ic_data_rdata [IC_NUM_WAYS];
|
|
||||||
// Alert signals
|
// Alert signals
|
||||||
logic core_alert_major, core_alert_minor;
|
logic core_alert_major, core_alert_minor;
|
||||||
logic lockstep_alert_major_internal, lockstep_alert_major_bus;
|
|
||||||
logic lockstep_alert_minor;
|
|
||||||
// Scramble signals
|
|
||||||
logic icache_inval;
|
|
||||||
logic [SCRAMBLE_KEY_W-1:0] scramble_key_q;
|
|
||||||
logic [SCRAMBLE_NONCE_W-1:0] scramble_nonce_q;
|
|
||||||
logic scramble_key_valid_d, scramble_key_valid_q;
|
|
||||||
logic scramble_req_d, scramble_req_q;
|
|
||||||
|
|
||||||
fetch_enable_t fetch_enable_buf;
|
|
||||||
|
|
||||||
/////////////////////
|
/////////////////////
|
||||||
// Main clock gate //
|
// Main clock gate //
|
||||||
|
@ -214,12 +167,6 @@ module cve2_top import cve2_pkg::*; #(
|
||||||
// Core instantiation //
|
// Core instantiation //
|
||||||
////////////////////////
|
////////////////////////
|
||||||
|
|
||||||
// Buffer security critical signals to prevent synthesis optimisation removing them
|
|
||||||
prim_buf #(.Width($bits(fetch_enable_t))) u_fetch_enable_buf (
|
|
||||||
.in_i (fetch_enable_i),
|
|
||||||
.out_o(fetch_enable_buf)
|
|
||||||
);
|
|
||||||
|
|
||||||
prim_buf #(.Width(32)) u_rf_rdata_a_ecc_buf (
|
prim_buf #(.Width(32)) u_rf_rdata_a_ecc_buf (
|
||||||
.in_i (rf_rdata_a_ecc),
|
.in_i (rf_rdata_a_ecc),
|
||||||
.out_o(rf_rdata_a_ecc_buf)
|
.out_o(rf_rdata_a_ecc_buf)
|
||||||
|
@ -239,21 +186,10 @@ module cve2_top import cve2_pkg::*; #(
|
||||||
.RV32E (RV32E),
|
.RV32E (RV32E),
|
||||||
.RV32M (RV32M),
|
.RV32M (RV32M),
|
||||||
.RV32B (RV32B),
|
.RV32B (RV32B),
|
||||||
.ICache (ICache),
|
|
||||||
.ICacheECC (ICacheECC),
|
|
||||||
.BusSizeECC (BusSizeECC),
|
|
||||||
.TagSizeECC (TagSizeECC),
|
|
||||||
.LineSizeECC (LineSizeECC),
|
|
||||||
.BranchPredictor (BranchPredictor),
|
.BranchPredictor (BranchPredictor),
|
||||||
.DbgTriggerEn (DbgTriggerEn),
|
.DbgTriggerEn (DbgTriggerEn),
|
||||||
.DbgHwBreakNum (DbgHwBreakNum),
|
.DbgHwBreakNum (DbgHwBreakNum),
|
||||||
.WritebackStage (WritebackStage),
|
.WritebackStage (WritebackStage),
|
||||||
.ResetAll (ResetAll),
|
|
||||||
.RndCnstLfsrSeed (RndCnstLfsrSeed),
|
|
||||||
.RndCnstLfsrPerm (RndCnstLfsrPerm),
|
|
||||||
.SecureIbex (SecureIbex),
|
|
||||||
.DummyInstructions(DummyInstructions),
|
|
||||||
.RegFileECC (RegFileECC),
|
|
||||||
.DmHaltAddr (DmHaltAddr),
|
.DmHaltAddr (DmHaltAddr),
|
||||||
.DmExceptionAddr (DmExceptionAddr)
|
.DmExceptionAddr (DmExceptionAddr)
|
||||||
) u_cve2_core (
|
) u_cve2_core (
|
||||||
|
@ -280,26 +216,13 @@ module cve2_top import cve2_pkg::*; #(
|
||||||
.data_rdata_i,
|
.data_rdata_i,
|
||||||
.data_err_i,
|
.data_err_i,
|
||||||
|
|
||||||
.dummy_instr_id_o (dummy_instr_id),
|
|
||||||
.rf_raddr_a_o (rf_raddr_a),
|
.rf_raddr_a_o (rf_raddr_a),
|
||||||
.rf_raddr_b_o (rf_raddr_b),
|
.rf_raddr_b_o (rf_raddr_b),
|
||||||
.rf_waddr_wb_o (rf_waddr_wb),
|
.rf_waddr_wb_o (rf_waddr_wb),
|
||||||
.rf_we_wb_o (rf_we_wb),
|
.rf_we_wb_o (rf_we_wb),
|
||||||
.rf_wdata_wb_ecc_o(rf_wdata_wb_ecc),
|
.rf_wdata_wb_ecc_o(rf_wdata_wb_ecc),
|
||||||
.rf_rdata_a_ecc_i (rf_rdata_a_ecc_buf),
|
.rf_rdata_a_ecc_i (rf_rdata_a_ecc), //_buf),
|
||||||
.rf_rdata_b_ecc_i (rf_rdata_b_ecc_buf),
|
.rf_rdata_b_ecc_i (rf_rdata_b_ecc), //_buf),
|
||||||
|
|
||||||
.ic_tag_req_o (ic_tag_req),
|
|
||||||
.ic_tag_write_o (ic_tag_write),
|
|
||||||
.ic_tag_addr_o (ic_tag_addr),
|
|
||||||
.ic_tag_wdata_o (ic_tag_wdata),
|
|
||||||
.ic_tag_rdata_i (ic_tag_rdata),
|
|
||||||
.ic_data_req_o (ic_data_req),
|
|
||||||
.ic_data_write_o (ic_data_write),
|
|
||||||
.ic_data_addr_o (ic_data_addr),
|
|
||||||
.ic_data_wdata_o (ic_data_wdata),
|
|
||||||
.ic_data_rdata_i (ic_data_rdata),
|
|
||||||
.ic_scr_key_valid_i(scramble_key_valid_q),
|
|
||||||
|
|
||||||
.irq_software_i,
|
.irq_software_i,
|
||||||
.irq_timer_i,
|
.irq_timer_i,
|
||||||
|
@ -310,7 +233,6 @@ module cve2_top import cve2_pkg::*; #(
|
||||||
|
|
||||||
.debug_req_i,
|
.debug_req_i,
|
||||||
.crash_dump_o,
|
.crash_dump_o,
|
||||||
.double_fault_seen_o,
|
|
||||||
|
|
||||||
`ifdef RVFI
|
`ifdef RVFI
|
||||||
.rvfi_valid,
|
.rvfi_valid,
|
||||||
|
@ -342,10 +264,8 @@ module cve2_top import cve2_pkg::*; #(
|
||||||
.rvfi_ext_mcycle,
|
.rvfi_ext_mcycle,
|
||||||
`endif
|
`endif
|
||||||
|
|
||||||
.fetch_enable_i(fetch_enable_buf),
|
|
||||||
.alert_minor_o (core_alert_minor),
|
.alert_minor_o (core_alert_minor),
|
||||||
.alert_major_o (core_alert_major),
|
.alert_major_o (core_alert_major),
|
||||||
.icache_inval_o(icache_inval),
|
|
||||||
.core_busy_o (core_busy_d)
|
.core_busy_o (core_busy_d)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -357,14 +277,12 @@ module cve2_top import cve2_pkg::*; #(
|
||||||
cve2_register_file_ff #(
|
cve2_register_file_ff #(
|
||||||
.RV32E (RV32E),
|
.RV32E (RV32E),
|
||||||
.DataWidth (32),
|
.DataWidth (32),
|
||||||
.DummyInstructions(DummyInstructions),
|
|
||||||
.WordZeroVal (32'(prim_secded_pkg::SecdedInv3932ZeroWord))
|
.WordZeroVal (32'(prim_secded_pkg::SecdedInv3932ZeroWord))
|
||||||
) register_file_i (
|
) register_file_i (
|
||||||
.clk_i (clk),
|
.clk_i (clk),
|
||||||
.rst_ni(rst_ni),
|
.rst_ni(rst_ni),
|
||||||
|
|
||||||
.test_en_i (test_en_i),
|
.test_en_i (test_en_i),
|
||||||
.dummy_instr_id_i(dummy_instr_id),
|
|
||||||
|
|
||||||
.raddr_a_i(rf_raddr_a),
|
.raddr_a_i(rf_raddr_a),
|
||||||
.rdata_a_o(rf_rdata_a_ecc),
|
.rdata_a_o(rf_rdata_a_ecc),
|
||||||
|
@ -378,14 +296,12 @@ module cve2_top import cve2_pkg::*; #(
|
||||||
cve2_register_file_fpga #(
|
cve2_register_file_fpga #(
|
||||||
.RV32E (RV32E),
|
.RV32E (RV32E),
|
||||||
.DataWidth (32),
|
.DataWidth (32),
|
||||||
.DummyInstructions(DummyInstructions),
|
|
||||||
.WordZeroVal (32'(prim_secded_pkg::SecdedInv3932ZeroWord))
|
.WordZeroVal (32'(prim_secded_pkg::SecdedInv3932ZeroWord))
|
||||||
) register_file_i (
|
) register_file_i (
|
||||||
.clk_i (clk),
|
.clk_i (clk),
|
||||||
.rst_ni(rst_ni),
|
.rst_ni(rst_ni),
|
||||||
|
|
||||||
.test_en_i (test_en_i),
|
.test_en_i (test_en_i),
|
||||||
.dummy_instr_id_i(dummy_instr_id),
|
|
||||||
|
|
||||||
.raddr_a_i(rf_raddr_a),
|
.raddr_a_i(rf_raddr_a),
|
||||||
.rdata_a_o(rf_rdata_a_ecc),
|
.rdata_a_o(rf_rdata_a_ecc),
|
||||||
|
@ -399,14 +315,12 @@ module cve2_top import cve2_pkg::*; #(
|
||||||
cve2_register_file_latch #(
|
cve2_register_file_latch #(
|
||||||
.RV32E (RV32E),
|
.RV32E (RV32E),
|
||||||
.DataWidth (32),
|
.DataWidth (32),
|
||||||
.DummyInstructions(DummyInstructions),
|
|
||||||
.WordZeroVal (32'(prim_secded_pkg::SecdedInv3932ZeroWord))
|
.WordZeroVal (32'(prim_secded_pkg::SecdedInv3932ZeroWord))
|
||||||
) register_file_i (
|
) register_file_i (
|
||||||
.clk_i (clk),
|
.clk_i (clk),
|
||||||
.rst_ni(rst_ni),
|
.rst_ni(rst_ni),
|
||||||
|
|
||||||
.test_en_i (test_en_i),
|
.test_en_i (test_en_i),
|
||||||
.dummy_instr_id_i(dummy_instr_id),
|
|
||||||
|
|
||||||
.raddr_a_i(rf_raddr_a),
|
.raddr_a_i(rf_raddr_a),
|
||||||
.rdata_a_o(rf_rdata_a_ecc),
|
.rdata_a_o(rf_rdata_a_ecc),
|
||||||
|
@ -418,525 +332,23 @@ module cve2_top import cve2_pkg::*; #(
|
||||||
);
|
);
|
||||||
end
|
end
|
||||||
|
|
||||||
///////////////////////////////
|
|
||||||
// Scrambling Infrastructure //
|
|
||||||
///////////////////////////////
|
|
||||||
|
|
||||||
if (ICacheScramble) begin : gen_scramble
|
|
||||||
|
|
||||||
// SEC_CM: ICACHE.MEM.SCRAMBLE
|
|
||||||
// Scramble key valid starts with OTP returning new valid key and stays high
|
|
||||||
// until we request a new valid key.
|
|
||||||
assign scramble_key_valid_d = scramble_req_q ? scramble_key_valid_i :
|
|
||||||
icache_inval ? 1'b0 :
|
|
||||||
scramble_key_valid_q;
|
|
||||||
|
|
||||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
|
||||||
if (!rst_ni) begin
|
|
||||||
scramble_key_q <= RndCnstIbexKey;
|
|
||||||
scramble_nonce_q <= RndCnstIbexNonce;
|
|
||||||
end else if (scramble_key_valid_i) begin
|
|
||||||
scramble_key_q <= scramble_key_i;
|
|
||||||
scramble_nonce_q <= scramble_nonce_i;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
|
||||||
if (!rst_ni) begin
|
|
||||||
scramble_key_valid_q <= 1'b1;
|
|
||||||
scramble_req_q <= '0;
|
|
||||||
end else begin
|
|
||||||
scramble_key_valid_q <= scramble_key_valid_d;
|
|
||||||
scramble_req_q <= scramble_req_d;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
// Scramble key request starts with invalidate signal from ICache and stays high
|
|
||||||
// until we got a valid key.
|
|
||||||
assign scramble_req_d = scramble_req_q ? ~scramble_key_valid_i : icache_inval;
|
|
||||||
assign scramble_req_o = scramble_req_q;
|
|
||||||
|
|
||||||
end else begin : gen_noscramble
|
|
||||||
|
|
||||||
logic unused_scramble_inputs = scramble_key_valid_i & (|scramble_key_i) & (|RndCnstIbexKey) &
|
|
||||||
(|scramble_nonce_i) & (|RndCnstIbexNonce) & scramble_req_q &
|
|
||||||
icache_inval & scramble_key_valid_d & scramble_req_d;
|
|
||||||
|
|
||||||
assign scramble_req_d = 1'b0;
|
|
||||||
assign scramble_req_q = 1'b0;
|
|
||||||
assign scramble_req_o = 1'b0;
|
|
||||||
assign scramble_key_q = '0;
|
|
||||||
assign scramble_nonce_q = '0;
|
|
||||||
assign scramble_key_valid_q = 1'b1;
|
|
||||||
assign scramble_key_valid_d = 1'b1;
|
|
||||||
end
|
|
||||||
|
|
||||||
////////////////////////
|
////////////////////////
|
||||||
// Rams Instantiation //
|
// Rams Instantiation //
|
||||||
////////////////////////
|
////////////////////////
|
||||||
|
|
||||||
if (ICache) begin : gen_rams
|
begin : gen_norams
|
||||||
|
|
||||||
for (genvar way = 0; way < IC_NUM_WAYS; way++) begin : gen_rams_inner
|
|
||||||
|
|
||||||
// SEC_CM: ICACHE.MEM.SCRAMBLE
|
|
||||||
// Tag RAM instantiation
|
|
||||||
prim_ram_1p_scr #(
|
|
||||||
.Width (TagSizeECC),
|
|
||||||
.Depth (IC_NUM_LINES),
|
|
||||||
.DataBitsPerMask (TagSizeECC),
|
|
||||||
.EnableParity (0),
|
|
||||||
.DiffWidth (TagSizeECC),
|
|
||||||
.NumAddrScrRounds (NumAddrScrRounds),
|
|
||||||
.NumDiffRounds (NumDiffRounds)
|
|
||||||
) tag_bank (
|
|
||||||
.clk_i,
|
|
||||||
.rst_ni,
|
|
||||||
|
|
||||||
.key_valid_i (scramble_key_valid_q),
|
|
||||||
.key_i (scramble_key_q),
|
|
||||||
.nonce_i (scramble_nonce_q),
|
|
||||||
|
|
||||||
.req_i (ic_tag_req[way]),
|
|
||||||
|
|
||||||
.gnt_o (),
|
|
||||||
.write_i (ic_tag_write),
|
|
||||||
.addr_i (ic_tag_addr),
|
|
||||||
.wdata_i (ic_tag_wdata),
|
|
||||||
.wmask_i ({TagSizeECC{1'b1}}),
|
|
||||||
.intg_error_i(1'b0),
|
|
||||||
|
|
||||||
.rdata_o (ic_tag_rdata[way]),
|
|
||||||
.rvalid_o (),
|
|
||||||
.raddr_o (),
|
|
||||||
.rerror_o (),
|
|
||||||
.cfg_i (ram_cfg_i)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Data RAM instantiation
|
|
||||||
prim_ram_1p_scr #(
|
|
||||||
.Width (LineSizeECC),
|
|
||||||
.Depth (IC_NUM_LINES),
|
|
||||||
.DataBitsPerMask (LineSizeECC),
|
|
||||||
.ReplicateKeyStream (1),
|
|
||||||
.EnableParity (0),
|
|
||||||
.DiffWidth (LineSizeECC),
|
|
||||||
.NumAddrScrRounds (NumAddrScrRounds),
|
|
||||||
.NumDiffRounds (NumDiffRounds)
|
|
||||||
) data_bank (
|
|
||||||
.clk_i,
|
|
||||||
.rst_ni,
|
|
||||||
|
|
||||||
.key_valid_i (scramble_key_valid_q),
|
|
||||||
.key_i (scramble_key_q),
|
|
||||||
.nonce_i (scramble_nonce_q),
|
|
||||||
|
|
||||||
.req_i (ic_data_req[way]),
|
|
||||||
|
|
||||||
.gnt_o (),
|
|
||||||
.write_i (ic_data_write),
|
|
||||||
.addr_i (ic_data_addr),
|
|
||||||
.wdata_i (ic_data_wdata),
|
|
||||||
.wmask_i ({LineSizeECC{1'b1}}),
|
|
||||||
.intg_error_i(1'b0),
|
|
||||||
|
|
||||||
.rdata_o (ic_data_rdata[way]),
|
|
||||||
.rvalid_o (),
|
|
||||||
.raddr_o (),
|
|
||||||
.rerror_o (),
|
|
||||||
.cfg_i (ram_cfg_i)
|
|
||||||
);
|
|
||||||
end
|
|
||||||
|
|
||||||
end else begin : gen_norams
|
|
||||||
|
|
||||||
prim_ram_1p_pkg::ram_1p_cfg_t unused_ram_cfg;
|
prim_ram_1p_pkg::ram_1p_cfg_t unused_ram_cfg;
|
||||||
logic unused_ram_inputs;
|
logic unused_ram_inputs;
|
||||||
|
|
||||||
assign unused_ram_cfg = ram_cfg_i;
|
assign unused_ram_cfg = ram_cfg_i;
|
||||||
assign unused_ram_inputs = (|ic_tag_req) & ic_tag_write & (|ic_tag_addr) & (|ic_tag_wdata) &
|
assign unused_ram_inputs = (|NumAddrScrRounds);
|
||||||
(|ic_data_req) & ic_data_write & (|ic_data_addr) & (|ic_data_wdata) &
|
|
||||||
(|scramble_key_q) & (|scramble_nonce_q) & scramble_key_valid_q &
|
|
||||||
scramble_key_valid_d & (|scramble_nonce_q) &
|
|
||||||
(|NumAddrScrRounds);
|
|
||||||
|
|
||||||
assign ic_tag_rdata = '{default:'b0};
|
|
||||||
assign ic_data_rdata = '{default:'b0};
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
// Redundant lockstep core implementation
|
assign alert_major_internal_o = core_alert_major;
|
||||||
if (Lockstep) begin : gen_lockstep
|
assign alert_major_bus_o = 1'b0;
|
||||||
// SEC_CM: LOGIC.SHADOW
|
assign alert_minor_o = core_alert_minor;
|
||||||
// Note: certain synthesis tools like DC are very smart at optimizing away redundant logic.
|
|
||||||
// Hence, we have to insert an optimization barrier at the IOs of the lockstep Ibex.
|
|
||||||
// This is achieved by manually buffering each bit using prim_buf.
|
|
||||||
// Our Xilinx and DC synthesis flows make sure that these buffers cannot be optimized away
|
|
||||||
// using keep attributes (Vivado) and size_only constraints (DC).
|
|
||||||
|
|
||||||
localparam int NumBufferBits = $bits({
|
|
||||||
hart_id_i,
|
|
||||||
boot_addr_i,
|
|
||||||
instr_req_o,
|
|
||||||
instr_gnt_i,
|
|
||||||
instr_rvalid_i,
|
|
||||||
instr_addr_o,
|
|
||||||
instr_rdata_i,
|
|
||||||
instr_rdata_intg_i,
|
|
||||||
instr_err_i,
|
|
||||||
data_req_o,
|
|
||||||
data_gnt_i,
|
|
||||||
data_rvalid_i,
|
|
||||||
data_we_o,
|
|
||||||
data_be_o,
|
|
||||||
data_addr_o,
|
|
||||||
data_wdata_o,
|
|
||||||
data_rdata_i,
|
|
||||||
data_rdata_intg_i,
|
|
||||||
data_err_i,
|
|
||||||
dummy_instr_id,
|
|
||||||
rf_raddr_a,
|
|
||||||
rf_raddr_b,
|
|
||||||
rf_waddr_wb,
|
|
||||||
rf_we_wb,
|
|
||||||
rf_wdata_wb_ecc,
|
|
||||||
rf_rdata_a_ecc,
|
|
||||||
rf_rdata_b_ecc,
|
|
||||||
ic_tag_req,
|
|
||||||
ic_tag_write,
|
|
||||||
ic_tag_addr,
|
|
||||||
ic_tag_wdata,
|
|
||||||
ic_data_req,
|
|
||||||
ic_data_write,
|
|
||||||
ic_data_addr,
|
|
||||||
ic_data_wdata,
|
|
||||||
scramble_key_valid_i,
|
|
||||||
irq_software_i,
|
|
||||||
irq_timer_i,
|
|
||||||
irq_external_i,
|
|
||||||
irq_fast_i,
|
|
||||||
irq_nm_i,
|
|
||||||
irq_pending,
|
|
||||||
debug_req_i,
|
|
||||||
crash_dump_o,
|
|
||||||
double_fault_seen_o,
|
|
||||||
fetch_enable_i,
|
|
||||||
icache_inval,
|
|
||||||
core_busy_d
|
|
||||||
});
|
|
||||||
|
|
||||||
logic [NumBufferBits-1:0] buf_in, buf_out;
|
|
||||||
|
|
||||||
logic [31:0] hart_id_local;
|
|
||||||
logic [31:0] boot_addr_local;
|
|
||||||
|
|
||||||
logic instr_req_local;
|
|
||||||
logic instr_gnt_local;
|
|
||||||
logic instr_rvalid_local;
|
|
||||||
logic [31:0] instr_addr_local;
|
|
||||||
logic [31:0] instr_rdata_local;
|
|
||||||
logic [6:0] instr_rdata_intg_local;
|
|
||||||
logic instr_err_local;
|
|
||||||
|
|
||||||
logic data_req_local;
|
|
||||||
logic data_gnt_local;
|
|
||||||
logic data_rvalid_local;
|
|
||||||
logic data_we_local;
|
|
||||||
logic [3:0] data_be_local;
|
|
||||||
logic [31:0] data_addr_local;
|
|
||||||
logic [31:0] data_wdata_local;
|
|
||||||
logic [6:0] data_wdata_intg_local;
|
|
||||||
logic [31:0] data_rdata_local;
|
|
||||||
logic [6:0] data_rdata_intg_local;
|
|
||||||
logic data_err_local;
|
|
||||||
|
|
||||||
logic dummy_instr_id_local;
|
|
||||||
logic [4:0] rf_raddr_a_local;
|
|
||||||
logic [4:0] rf_raddr_b_local;
|
|
||||||
logic [4:0] rf_waddr_wb_local;
|
|
||||||
logic rf_we_wb_local;
|
|
||||||
logic [31:0] rf_wdata_wb_ecc_local;
|
|
||||||
logic [31:0] rf_rdata_a_ecc_local;
|
|
||||||
logic [31:0] rf_rdata_b_ecc_local;
|
|
||||||
|
|
||||||
logic [IC_NUM_WAYS-1:0] ic_tag_req_local;
|
|
||||||
logic ic_tag_write_local;
|
|
||||||
logic [IC_INDEX_W-1:0] ic_tag_addr_local;
|
|
||||||
logic [TagSizeECC-1:0] ic_tag_wdata_local;
|
|
||||||
logic [IC_NUM_WAYS-1:0] ic_data_req_local;
|
|
||||||
logic ic_data_write_local;
|
|
||||||
logic [IC_INDEX_W-1:0] ic_data_addr_local;
|
|
||||||
logic [LineSizeECC-1:0] ic_data_wdata_local;
|
|
||||||
logic scramble_key_valid_local;
|
|
||||||
|
|
||||||
logic irq_software_local;
|
|
||||||
logic irq_timer_local;
|
|
||||||
logic irq_external_local;
|
|
||||||
logic [14:0] irq_fast_local;
|
|
||||||
logic irq_nm_local;
|
|
||||||
logic irq_pending_local;
|
|
||||||
|
|
||||||
logic debug_req_local;
|
|
||||||
crash_dump_t crash_dump_local;
|
|
||||||
logic double_fault_seen_local;
|
|
||||||
fetch_enable_t fetch_enable_local;
|
|
||||||
|
|
||||||
logic icache_inval_local;
|
|
||||||
logic core_busy_local;
|
|
||||||
|
|
||||||
assign buf_in = {
|
|
||||||
hart_id_i,
|
|
||||||
boot_addr_i,
|
|
||||||
instr_req_o,
|
|
||||||
instr_gnt_i,
|
|
||||||
instr_rvalid_i,
|
|
||||||
instr_addr_o,
|
|
||||||
instr_rdata_i,
|
|
||||||
instr_rdata_intg_i,
|
|
||||||
instr_err_i,
|
|
||||||
data_req_o,
|
|
||||||
data_gnt_i,
|
|
||||||
data_rvalid_i,
|
|
||||||
data_we_o,
|
|
||||||
data_be_o,
|
|
||||||
data_addr_o,
|
|
||||||
data_wdata_o,
|
|
||||||
data_rdata_i,
|
|
||||||
data_rdata_intg_i,
|
|
||||||
data_err_i,
|
|
||||||
dummy_instr_id,
|
|
||||||
rf_raddr_a,
|
|
||||||
rf_raddr_b,
|
|
||||||
rf_waddr_wb,
|
|
||||||
rf_we_wb,
|
|
||||||
rf_wdata_wb_ecc,
|
|
||||||
rf_rdata_a_ecc,
|
|
||||||
rf_rdata_b_ecc,
|
|
||||||
ic_tag_req,
|
|
||||||
ic_tag_write,
|
|
||||||
ic_tag_addr,
|
|
||||||
ic_tag_wdata,
|
|
||||||
ic_data_req,
|
|
||||||
ic_data_write,
|
|
||||||
ic_data_addr,
|
|
||||||
ic_data_wdata,
|
|
||||||
scramble_key_valid_q,
|
|
||||||
irq_software_i,
|
|
||||||
irq_timer_i,
|
|
||||||
irq_external_i,
|
|
||||||
irq_fast_i,
|
|
||||||
irq_nm_i,
|
|
||||||
irq_pending,
|
|
||||||
debug_req_i,
|
|
||||||
crash_dump_o,
|
|
||||||
double_fault_seen_o,
|
|
||||||
fetch_enable_i,
|
|
||||||
icache_inval,
|
|
||||||
core_busy_d
|
|
||||||
};
|
|
||||||
|
|
||||||
assign {
|
|
||||||
hart_id_local,
|
|
||||||
boot_addr_local,
|
|
||||||
instr_req_local,
|
|
||||||
instr_gnt_local,
|
|
||||||
instr_rvalid_local,
|
|
||||||
instr_addr_local,
|
|
||||||
instr_rdata_local,
|
|
||||||
instr_rdata_intg_local,
|
|
||||||
instr_err_local,
|
|
||||||
data_req_local,
|
|
||||||
data_gnt_local,
|
|
||||||
data_rvalid_local,
|
|
||||||
data_we_local,
|
|
||||||
data_be_local,
|
|
||||||
data_addr_local,
|
|
||||||
data_wdata_local,
|
|
||||||
data_rdata_local,
|
|
||||||
data_rdata_intg_local,
|
|
||||||
data_err_local,
|
|
||||||
dummy_instr_id_local,
|
|
||||||
rf_raddr_a_local,
|
|
||||||
rf_raddr_b_local,
|
|
||||||
rf_waddr_wb_local,
|
|
||||||
rf_we_wb_local,
|
|
||||||
rf_wdata_wb_ecc_local,
|
|
||||||
rf_rdata_a_ecc_local,
|
|
||||||
rf_rdata_b_ecc_local,
|
|
||||||
ic_tag_req_local,
|
|
||||||
ic_tag_write_local,
|
|
||||||
ic_tag_addr_local,
|
|
||||||
ic_tag_wdata_local,
|
|
||||||
ic_data_req_local,
|
|
||||||
ic_data_write_local,
|
|
||||||
ic_data_addr_local,
|
|
||||||
ic_data_wdata_local,
|
|
||||||
scramble_key_valid_local,
|
|
||||||
irq_software_local,
|
|
||||||
irq_timer_local,
|
|
||||||
irq_external_local,
|
|
||||||
irq_fast_local,
|
|
||||||
irq_nm_local,
|
|
||||||
irq_pending_local,
|
|
||||||
debug_req_local,
|
|
||||||
crash_dump_local,
|
|
||||||
double_fault_seen_local,
|
|
||||||
fetch_enable_local,
|
|
||||||
icache_inval_local,
|
|
||||||
core_busy_local
|
|
||||||
} = buf_out;
|
|
||||||
|
|
||||||
// Manually buffer all input signals.
|
|
||||||
prim_buf #(.Width(NumBufferBits)) u_signals_prim_buf (
|
|
||||||
.in_i(buf_in),
|
|
||||||
.out_o(buf_out)
|
|
||||||
);
|
|
||||||
|
|
||||||
logic [TagSizeECC-1:0] ic_tag_rdata_local [IC_NUM_WAYS];
|
|
||||||
logic [LineSizeECC-1:0] ic_data_rdata_local [IC_NUM_WAYS];
|
|
||||||
for (genvar k = 0; k < IC_NUM_WAYS; k++) begin : gen_ways
|
|
||||||
prim_buf #(.Width(TagSizeECC)) u_tag_prim_buf (
|
|
||||||
.in_i(ic_tag_rdata[k]),
|
|
||||||
.out_o(ic_tag_rdata_local[k])
|
|
||||||
);
|
|
||||||
prim_buf #(.Width(LineSizeECC)) u_data_prim_buf (
|
|
||||||
.in_i(ic_data_rdata[k]),
|
|
||||||
.out_o(ic_data_rdata_local[k])
|
|
||||||
);
|
|
||||||
end
|
|
||||||
|
|
||||||
logic lockstep_alert_minor_local, lockstep_alert_major_internal_local;
|
|
||||||
logic lockstep_alert_major_bus_local;
|
|
||||||
|
|
||||||
cve2_lockstep #(
|
|
||||||
.PMPEnable (PMPEnable),
|
|
||||||
.PMPGranularity (PMPGranularity),
|
|
||||||
.PMPNumRegions (PMPNumRegions),
|
|
||||||
.MHPMCounterNum (MHPMCounterNum),
|
|
||||||
.MHPMCounterWidth (MHPMCounterWidth),
|
|
||||||
.RV32E (RV32E),
|
|
||||||
.RV32M (RV32M),
|
|
||||||
.RV32B (RV32B),
|
|
||||||
.ICache (ICache),
|
|
||||||
.ICacheECC (ICacheECC),
|
|
||||||
.BusSizeECC (BusSizeECC),
|
|
||||||
.TagSizeECC (TagSizeECC),
|
|
||||||
.LineSizeECC (LineSizeECC),
|
|
||||||
.BranchPredictor (BranchPredictor),
|
|
||||||
.DbgTriggerEn (DbgTriggerEn),
|
|
||||||
.DbgHwBreakNum (DbgHwBreakNum),
|
|
||||||
.WritebackStage (WritebackStage),
|
|
||||||
.ResetAll (ResetAll),
|
|
||||||
.RndCnstLfsrSeed (RndCnstLfsrSeed),
|
|
||||||
.RndCnstLfsrPerm (RndCnstLfsrPerm),
|
|
||||||
.SecureIbex (SecureIbex),
|
|
||||||
.DummyInstructions(DummyInstructions),
|
|
||||||
.RegFileECC (RegFileECC),
|
|
||||||
.DmHaltAddr (DmHaltAddr),
|
|
||||||
.DmExceptionAddr (DmExceptionAddr)
|
|
||||||
) u_cve2_lockstep (
|
|
||||||
.clk_i (clk),
|
|
||||||
.rst_ni (rst_ni),
|
|
||||||
|
|
||||||
.hart_id_i (hart_id_local),
|
|
||||||
.boot_addr_i (boot_addr_local),
|
|
||||||
|
|
||||||
.instr_req_i (instr_req_local),
|
|
||||||
.instr_gnt_i (instr_gnt_local),
|
|
||||||
.instr_rvalid_i (instr_rvalid_local),
|
|
||||||
.instr_addr_i (instr_addr_local),
|
|
||||||
.instr_rdata_i (instr_rdata_local),
|
|
||||||
.instr_rdata_intg_i (instr_rdata_intg_local),
|
|
||||||
.instr_err_i (instr_err_local),
|
|
||||||
|
|
||||||
.data_req_i (data_req_local),
|
|
||||||
.data_gnt_i (data_gnt_local),
|
|
||||||
.data_rvalid_i (data_rvalid_local),
|
|
||||||
.data_we_i (data_we_local),
|
|
||||||
.data_be_i (data_be_local),
|
|
||||||
.data_addr_i (data_addr_local),
|
|
||||||
.data_wdata_i (data_wdata_local),
|
|
||||||
.data_wdata_intg_o (data_wdata_intg_local),
|
|
||||||
.data_rdata_i (data_rdata_local),
|
|
||||||
.data_rdata_intg_i (data_rdata_intg_local),
|
|
||||||
.data_err_i (data_err_local),
|
|
||||||
|
|
||||||
.dummy_instr_id_i (dummy_instr_id_local),
|
|
||||||
.rf_raddr_a_i (rf_raddr_a_local),
|
|
||||||
.rf_raddr_b_i (rf_raddr_b_local),
|
|
||||||
.rf_waddr_wb_i (rf_waddr_wb_local),
|
|
||||||
.rf_we_wb_i (rf_we_wb_local),
|
|
||||||
.rf_wdata_wb_ecc_i (rf_wdata_wb_ecc_local),
|
|
||||||
.rf_rdata_a_ecc_i (rf_rdata_a_ecc_local),
|
|
||||||
.rf_rdata_b_ecc_i (rf_rdata_b_ecc_local),
|
|
||||||
|
|
||||||
.ic_tag_req_i (ic_tag_req_local),
|
|
||||||
.ic_tag_write_i (ic_tag_write_local),
|
|
||||||
.ic_tag_addr_i (ic_tag_addr_local),
|
|
||||||
.ic_tag_wdata_i (ic_tag_wdata_local),
|
|
||||||
.ic_tag_rdata_i (ic_tag_rdata_local),
|
|
||||||
.ic_data_req_i (ic_data_req_local),
|
|
||||||
.ic_data_write_i (ic_data_write_local),
|
|
||||||
.ic_data_addr_i (ic_data_addr_local),
|
|
||||||
.ic_data_wdata_i (ic_data_wdata_local),
|
|
||||||
.ic_data_rdata_i (ic_data_rdata_local),
|
|
||||||
.ic_scr_key_valid_i (scramble_key_valid_local),
|
|
||||||
|
|
||||||
.irq_software_i (irq_software_local),
|
|
||||||
.irq_timer_i (irq_timer_local),
|
|
||||||
.irq_external_i (irq_external_local),
|
|
||||||
.irq_fast_i (irq_fast_local),
|
|
||||||
.irq_nm_i (irq_nm_local),
|
|
||||||
.irq_pending_i (irq_pending_local),
|
|
||||||
|
|
||||||
.debug_req_i (debug_req_local),
|
|
||||||
.crash_dump_i (crash_dump_local),
|
|
||||||
.double_fault_seen_i (double_fault_seen_local),
|
|
||||||
|
|
||||||
.fetch_enable_i (fetch_enable_local),
|
|
||||||
.alert_minor_o (lockstep_alert_minor_local),
|
|
||||||
.alert_major_internal_o (lockstep_alert_major_internal_local),
|
|
||||||
.alert_major_bus_o (lockstep_alert_major_bus_local),
|
|
||||||
.icache_inval_i (icache_inval_local),
|
|
||||||
.core_busy_i (core_busy_local),
|
|
||||||
.test_en_i (test_en_i),
|
|
||||||
.scan_rst_ni (scan_rst_ni)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Manually buffer the output signals.
|
|
||||||
prim_buf #(.Width (7)) u_prim_buf_wdata_intg (
|
|
||||||
.in_i(data_wdata_intg_local),
|
|
||||||
.out_o(data_wdata_intg_o)
|
|
||||||
);
|
|
||||||
|
|
||||||
prim_buf u_prim_buf_alert_minor (
|
|
||||||
.in_i (lockstep_alert_minor_local),
|
|
||||||
.out_o(lockstep_alert_minor)
|
|
||||||
);
|
|
||||||
|
|
||||||
prim_buf u_prim_buf_alert_major_internal (
|
|
||||||
.in_i (lockstep_alert_major_internal_local),
|
|
||||||
.out_o(lockstep_alert_major_internal)
|
|
||||||
);
|
|
||||||
|
|
||||||
prim_buf u_prim_buf_alert_major_bus (
|
|
||||||
.in_i (lockstep_alert_major_bus_local),
|
|
||||||
.out_o(lockstep_alert_major_bus)
|
|
||||||
);
|
|
||||||
|
|
||||||
end else begin : gen_no_lockstep
|
|
||||||
assign lockstep_alert_major_internal = 1'b0;
|
|
||||||
assign lockstep_alert_major_bus = 1'b0;
|
|
||||||
assign lockstep_alert_minor = 1'b0;
|
|
||||||
assign data_wdata_intg_o = 'b0;
|
|
||||||
logic unused_scan, unused_intg;
|
|
||||||
assign unused_scan = scan_rst_ni;
|
|
||||||
assign unused_intg = |{instr_rdata_intg_i, data_rdata_intg_i};
|
|
||||||
end
|
|
||||||
|
|
||||||
assign alert_major_internal_o = core_alert_major | lockstep_alert_major_internal;
|
|
||||||
assign alert_major_bus_o = lockstep_alert_major_bus;
|
|
||||||
assign alert_minor_o = core_alert_minor | lockstep_alert_minor;
|
|
||||||
|
|
||||||
// X checks for top-level outputs
|
// X checks for top-level outputs
|
||||||
`ASSERT_KNOWN(IbexInstrReqX, instr_req_o)
|
`ASSERT_KNOWN(IbexInstrReqX, instr_req_o)
|
||||||
|
@ -946,8 +358,6 @@ module cve2_top import cve2_pkg::*; #(
|
||||||
`ASSERT_KNOWN_IF(IbexDataReqPayloadX,
|
`ASSERT_KNOWN_IF(IbexDataReqPayloadX,
|
||||||
{data_we_o, data_be_o, data_addr_o, data_wdata_o, data_wdata_intg_o}, data_req_o)
|
{data_we_o, data_be_o, data_addr_o, data_wdata_o, data_wdata_intg_o}, data_req_o)
|
||||||
|
|
||||||
`ASSERT_KNOWN(IbexScrambleReqX, scramble_req_o)
|
|
||||||
`ASSERT_KNOWN(IbexDoubleFaultSeenX, double_fault_seen_o)
|
|
||||||
`ASSERT_KNOWN(IbexAlertMinorX, alert_minor_o)
|
`ASSERT_KNOWN(IbexAlertMinorX, alert_minor_o)
|
||||||
`ASSERT_KNOWN(IbexAlertMajorInternalX, alert_major_internal_o)
|
`ASSERT_KNOWN(IbexAlertMajorInternalX, alert_major_internal_o)
|
||||||
`ASSERT_KNOWN(IbexAlertMajorBusX, alert_major_bus_o)
|
`ASSERT_KNOWN(IbexAlertMajorBusX, alert_major_bus_o)
|
||||||
|
@ -970,9 +380,5 @@ module cve2_top import cve2_pkg::*; #(
|
||||||
|
|
||||||
`ASSERT_KNOWN(IbexIrqX, {irq_software_i, irq_timer_i, irq_external_i, irq_fast_i, irq_nm_i})
|
`ASSERT_KNOWN(IbexIrqX, {irq_software_i, irq_timer_i, irq_external_i, irq_fast_i, irq_nm_i})
|
||||||
|
|
||||||
`ASSERT_KNOWN(IbexScrambleKeyValidX, scramble_key_valid_i)
|
|
||||||
`ASSERT_KNOWN_IF(IbexScramblePayloadX, {scramble_key_i, scramble_nonce_i}, scramble_key_valid_i)
|
|
||||||
|
|
||||||
`ASSERT_KNOWN(IbexDebugReqX, debug_req_i)
|
`ASSERT_KNOWN(IbexDebugReqX, debug_req_i)
|
||||||
`ASSERT_KNOWN(IbexFetchEnableX, fetch_enable_i)
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
|
@ -14,15 +14,9 @@ module cve2_top_tracing import cve2_pkg::*; #(
|
||||||
parameter rv32b_e RV32B = RV32BNone,
|
parameter rv32b_e RV32B = RV32BNone,
|
||||||
parameter regfile_e RegFile = RegFileFF,
|
parameter regfile_e RegFile = RegFileFF,
|
||||||
parameter bit WritebackStage = 1'b0,
|
parameter bit WritebackStage = 1'b0,
|
||||||
parameter bit ICache = 1'b0,
|
|
||||||
parameter bit ICacheECC = 1'b0,
|
|
||||||
parameter bit BranchPredictor = 1'b0,
|
parameter bit BranchPredictor = 1'b0,
|
||||||
parameter bit DbgTriggerEn = 1'b0,
|
parameter bit DbgTriggerEn = 1'b0,
|
||||||
parameter int unsigned DbgHwBreakNum = 1,
|
parameter int unsigned DbgHwBreakNum = 1,
|
||||||
parameter bit SecureIbex = 1'b0,
|
|
||||||
parameter bit ICacheScramble = 1'b0,
|
|
||||||
parameter lfsr_seed_t RndCnstLfsrSeed = RndCnstLfsrSeedDefault,
|
|
||||||
parameter lfsr_perm_t RndCnstLfsrPerm = RndCnstLfsrPermDefault,
|
|
||||||
parameter int unsigned DmHaltAddr = 32'h1A110800,
|
parameter int unsigned DmHaltAddr = 32'h1A110800,
|
||||||
parameter int unsigned DmExceptionAddr = 32'h1A110808
|
parameter int unsigned DmExceptionAddr = 32'h1A110808
|
||||||
) (
|
) (
|
||||||
|
@ -67,19 +61,11 @@ module cve2_top_tracing import cve2_pkg::*; #(
|
||||||
input logic [14:0] irq_fast_i,
|
input logic [14:0] irq_fast_i,
|
||||||
input logic irq_nm_i, // non-maskeable interrupt
|
input logic irq_nm_i, // non-maskeable interrupt
|
||||||
|
|
||||||
// Scrambling Interface
|
|
||||||
input logic scramble_key_valid_i,
|
|
||||||
input logic [SCRAMBLE_KEY_W-1:0] scramble_key_i,
|
|
||||||
input logic [SCRAMBLE_NONCE_W-1:0] scramble_nonce_i,
|
|
||||||
output logic scramble_req_o,
|
|
||||||
|
|
||||||
// Debug Interface
|
// Debug Interface
|
||||||
input logic debug_req_i,
|
input logic debug_req_i,
|
||||||
output crash_dump_t crash_dump_o,
|
output crash_dump_t crash_dump_o,
|
||||||
output logic double_fault_seen_o,
|
|
||||||
|
|
||||||
// CPU Control Signals
|
// CPU Control Signals
|
||||||
input fetch_enable_t fetch_enable_i,
|
|
||||||
output logic alert_minor_o,
|
output logic alert_minor_o,
|
||||||
output logic alert_major_internal_o,
|
output logic alert_major_internal_o,
|
||||||
output logic alert_major_bus_o,
|
output logic alert_major_bus_o,
|
||||||
|
@ -139,16 +125,10 @@ module cve2_top_tracing import cve2_pkg::*; #(
|
||||||
.RV32M ( RV32M ),
|
.RV32M ( RV32M ),
|
||||||
.RV32B ( RV32B ),
|
.RV32B ( RV32B ),
|
||||||
.RegFile ( RegFile ),
|
.RegFile ( RegFile ),
|
||||||
.ICache ( ICache ),
|
|
||||||
.ICacheECC ( ICacheECC ),
|
|
||||||
.BranchPredictor ( BranchPredictor ),
|
.BranchPredictor ( BranchPredictor ),
|
||||||
.DbgTriggerEn ( DbgTriggerEn ),
|
.DbgTriggerEn ( DbgTriggerEn ),
|
||||||
.DbgHwBreakNum ( DbgHwBreakNum ),
|
.DbgHwBreakNum ( DbgHwBreakNum ),
|
||||||
.WritebackStage ( WritebackStage ),
|
.WritebackStage ( WritebackStage ),
|
||||||
.SecureIbex ( SecureIbex ),
|
|
||||||
.ICacheScramble ( ICacheScramble ),
|
|
||||||
.RndCnstLfsrSeed ( RndCnstLfsrSeed ),
|
|
||||||
.RndCnstLfsrPerm ( RndCnstLfsrPerm ),
|
|
||||||
.DmHaltAddr ( DmHaltAddr ),
|
.DmHaltAddr ( DmHaltAddr ),
|
||||||
.DmExceptionAddr ( DmExceptionAddr )
|
.DmExceptionAddr ( DmExceptionAddr )
|
||||||
) u_cve2_top (
|
) u_cve2_top (
|
||||||
|
@ -188,14 +168,8 @@ module cve2_top_tracing import cve2_pkg::*; #(
|
||||||
.irq_fast_i,
|
.irq_fast_i,
|
||||||
.irq_nm_i,
|
.irq_nm_i,
|
||||||
|
|
||||||
.scramble_key_valid_i,
|
|
||||||
.scramble_key_i,
|
|
||||||
.scramble_nonce_i,
|
|
||||||
.scramble_req_o,
|
|
||||||
|
|
||||||
.debug_req_i,
|
.debug_req_i,
|
||||||
.crash_dump_o,
|
.crash_dump_o,
|
||||||
.double_fault_seen_o,
|
|
||||||
|
|
||||||
.rvfi_valid,
|
.rvfi_valid,
|
||||||
.rvfi_order,
|
.rvfi_order,
|
||||||
|
@ -225,7 +199,6 @@ module cve2_top_tracing import cve2_pkg::*; #(
|
||||||
.rvfi_ext_debug_req,
|
.rvfi_ext_debug_req,
|
||||||
.rvfi_ext_mcycle,
|
.rvfi_ext_mcycle,
|
||||||
|
|
||||||
.fetch_enable_i,
|
|
||||||
.alert_minor_o,
|
.alert_minor_o,
|
||||||
.alert_major_internal_o,
|
.alert_major_internal_o,
|
||||||
.alert_major_bus_o,
|
.alert_major_bus_o,
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
`include "dv_fcov_macros.svh"
|
`include "dv_fcov_macros.svh"
|
||||||
|
|
||||||
module cve2_wb_stage #(
|
module cve2_wb_stage #(
|
||||||
parameter bit ResetAll = 1'b0,
|
|
||||||
parameter bit WritebackStage = 1'b0
|
parameter bit WritebackStage = 1'b0
|
||||||
) (
|
) (
|
||||||
input logic clk_i,
|
input logic clk_i,
|
||||||
|
@ -95,7 +94,7 @@ module cve2_wb_stage #(
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if (ResetAll) begin : g_wb_regs_ra
|
begin : g_wb_regs
|
||||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||||
if (!rst_ni) begin
|
if (!rst_ni) begin
|
||||||
rf_we_wb_q <= '0;
|
rf_we_wb_q <= '0;
|
||||||
|
@ -115,18 +114,6 @@ module cve2_wb_stage #(
|
||||||
wb_count_q <= instr_perf_count_id_i;
|
wb_count_q <= instr_perf_count_id_i;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end else begin : g_wb_regs_nr
|
|
||||||
always_ff @(posedge clk_i) begin
|
|
||||||
if (en_wb_i) begin
|
|
||||||
rf_we_wb_q <= rf_we_id_i;
|
|
||||||
rf_waddr_wb_q <= rf_waddr_id_i;
|
|
||||||
rf_wdata_wb_q <= rf_wdata_id_i;
|
|
||||||
wb_instr_type_q <= instr_type_wb_i;
|
|
||||||
wb_pc_q <= pc_id_i;
|
|
||||||
wb_compressed_q <= instr_is_compressed_id_i;
|
|
||||||
wb_count_q <= instr_perf_count_id_i;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
assign rf_waddr_wb_o = rf_waddr_wb_q;
|
assign rf_waddr_wb_o = rf_waddr_wb_q;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue