diff --git a/doc/02_user/integration.rst b/doc/02_user/integration.rst index 019638d0..88902553 100644 --- a/doc/02_user/integration.rst +++ b/doc/02_user/integration.rst @@ -26,6 +26,7 @@ Instantiation Template .RegFile ( ibex_pkg::RegFileFF ), .ICache ( 0 ), .ICacheECC ( 0 ), + .ICacheScramble ( 0 ), .BranchPrediction ( 0 ), .SecureIbex ( 0 ), .RndCnstLfsrSeed ( ibex_pkg::RndCnstLfsrSeedDefault ), @@ -131,6 +132,9 @@ Parameters | ``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 | +------------------------------+---------------------+------------+-----------------------------------------------------------------------+ | ``SecureIbex`` | bit | 0 | *EXPERIMENTAL* Enable various additional features targeting | @@ -193,6 +197,8 @@ Interfaces | ``data_*`` | Load-store unit interface, see :ref:`load-store-unit` | +-------------------------+------------------------------------------------------------------------+ | ``irq_*`` | Interrupt inputs, see :ref:`exceptions-interrupts` | ++-------------------------+-------------------------+-----+----------------------------------------+ +| ``scramble_*`` | Scrambling key interface, see :ref:`icache` | +-------------------------+------------------------------------------------------------------------+ | ``debug_*`` | Debug interface, see :ref:`debug-support` | +-------------------------+------------------------------------------------------------------------+ diff --git a/doc/03_reference/icache.rst b/doc/03_reference/icache.rst index 1e55de98..b47b53f8 100644 --- a/doc/03_reference/icache.rst +++ b/doc/03_reference/icache.rst @@ -93,6 +93,12 @@ Indicative RAM sizes for common configurations are given in the table below: | 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 -------------------- diff --git a/dv/riscv_compliance/ibex_riscv_compliance.core b/dv/riscv_compliance/ibex_riscv_compliance.core index edc7fcbf..919b483b 100644 --- a/dv/riscv_compliance/ibex_riscv_compliance.core +++ b/dv/riscv_compliance/ibex_riscv_compliance.core @@ -5,24 +5,23 @@ CAPI=2: name: "lowrisc:ibex:ibex_riscv_compliance:0.1" description: "Ibex simulation for RISC-V compliance testing (using Verilator)" filesets: - files_sim_verilator: + files_sim: depend: - - lowrisc:dv_verilator:memutil_verilator - - lowrisc:dv_verilator:simutil_verilator - lowrisc:ibex:ibex_top_tracing - lowrisc:ibex:sim_shared - files: - rtl/ibex_riscv_compliance.sv - - ibex_riscv_compliance.cc: { file_type: cppSource } - rtl/riscv_testutil.sv file_type: systemVerilogSource - files_verilator_waiver: + files_verilator: + depend: + - lowrisc:dv_verilator:memutil_verilator + - lowrisc:dv_verilator:simutil_verilator files: + - ibex_riscv_compliance.cc: { file_type: cppSource } - lint/verilator_waiver.vlt: {file_type: vlt} - parameters: RV32E: datatype: int @@ -102,12 +101,18 @@ parameters: default: 0 description: "Enables security hardening features (EXPERIMENTAL) [0/1]" + ICacheScramble: + datatype: int + paramtype: vlogparam + default: 0 + description: "Enables ICache scrambling feature (EXPERIMENTAL) [0/1]" + targets: sim: default_tool: verilator filesets: - - tool_verilator ? (files_verilator_waiver) - - files_sim_verilator + - files_sim + - tool_verilator ? (files_verilator) parameters: - RV32E - RV32M @@ -122,6 +127,7 @@ targets: - PMPGranularity - PMPNumRegions - SecureIbex + - ICacheScramble toplevel: ibex_riscv_compliance tools: verilator: diff --git a/dv/riscv_compliance/rtl/ibex_riscv_compliance.sv b/dv/riscv_compliance/rtl/ibex_riscv_compliance.sv index 5441a135..0782aa15 100644 --- a/dv/riscv_compliance/rtl/ibex_riscv_compliance.sv +++ b/dv/riscv_compliance/rtl/ibex_riscv_compliance.sv @@ -28,6 +28,7 @@ module ibex_riscv_compliance ( parameter bit ICacheECC = 1'b0; parameter bit BranchPredictor = 1'b0; parameter bit SecureIbex = 1'b0; + parameter bit ICacheScramble = 1'b0; logic clk_sys, rst_sys_n; @@ -80,7 +81,6 @@ module ibex_riscv_compliance ( assign cfg_device_addr_base[TestUtilDevice] = 32'h20000; assign cfg_device_addr_mask[TestUtilDevice] = ~32'h3FF; // 1 kB - bus #( .NrDevices (NrDevices), .NrHosts (NrHosts ), @@ -127,53 +127,59 @@ module ibex_riscv_compliance ( .ICacheECC (ICacheECC ), .BranchPredictor (BranchPredictor ), .SecureIbex (SecureIbex ), + .ICacheScramble (ICacheScramble ), .DmHaltAddr (32'h00000000 ), .DmExceptionAddr (32'h00000000 ) ) u_top ( - .clk_i (clk_sys ), - .rst_ni (rst_sys_n ), + .clk_i (clk_sys ), + .rst_ni (rst_sys_n ), - .test_en_i ('b0 ), - .scan_rst_ni (1'b1 ), - .ram_cfg_i ('b0 ), + .test_en_i ('b0 ), + .scan_rst_ni (1'b1 ), + .ram_cfg_i ('b0 ), - .hart_id_i (32'b0 ), + .hart_id_i (32'b0 ), // First instruction executed is at 0x0 + 0x80 - .boot_addr_i (32'h00000000 ), + .boot_addr_i (32'h00000000 ), - .instr_req_o (host_req[CoreI] ), - .instr_gnt_i (host_gnt[CoreI] ), - .instr_rvalid_i (host_rvalid[CoreI]), - .instr_addr_o (host_addr[CoreI] ), - .instr_rdata_i (host_rdata[CoreI] ), - .instr_rdata_intg_i ('0 ), - .instr_err_i (host_err[CoreI] ), + .instr_req_o (host_req[CoreI] ), + .instr_gnt_i (host_gnt[CoreI] ), + .instr_rvalid_i (host_rvalid[CoreI]), + .instr_addr_o (host_addr[CoreI] ), + .instr_rdata_i (host_rdata[CoreI] ), + .instr_rdata_intg_i ('0 ), + .instr_err_i (host_err[CoreI] ), - .data_req_o (host_req[CoreD] ), - .data_gnt_i (host_gnt[CoreD] ), - .data_rvalid_i (host_rvalid[CoreD]), - .data_we_o (host_we[CoreD] ), - .data_be_o (host_be[CoreD] ), - .data_addr_o (host_addr[CoreD] ), - .data_wdata_o (host_wdata[CoreD] ), - .data_wdata_intg_o ( ), - .data_rdata_i (host_rdata[CoreD] ), - .data_rdata_intg_i ('0 ), - .data_err_i (host_err[CoreD] ), + .data_req_o (host_req[CoreD] ), + .data_gnt_i (host_gnt[CoreD] ), + .data_rvalid_i (host_rvalid[CoreD]), + .data_we_o (host_we[CoreD] ), + .data_be_o (host_be[CoreD] ), + .data_addr_o (host_addr[CoreD] ), + .data_wdata_o (host_wdata[CoreD] ), + .data_wdata_intg_o ( ), + .data_rdata_i (host_rdata[CoreD] ), + .data_rdata_intg_i ('0 ), + .data_err_i (host_err[CoreD] ), - .irq_software_i (1'b0 ), - .irq_timer_i (1'b0 ), - .irq_external_i (1'b0 ), - .irq_fast_i (15'b0 ), - .irq_nm_i (1'b0 ), + .irq_software_i (1'b0 ), + .irq_timer_i (1'b0 ), + .irq_external_i (1'b0 ), + .irq_fast_i (15'b0 ), + .irq_nm_i (1'b0 ), - .debug_req_i ('b0 ), - .crash_dump_o ( ), + .scramble_key_valid_i ('0 ), + .scramble_key_i ('0 ), + .scramble_nonce_i ('0 ), + .scramble_req_o ( ), - .fetch_enable_i ('b1 ), - .alert_minor_o ( ), - .alert_major_o ( ), - .core_sleep_o ( ) + .debug_req_i ('b0 ), + .crash_dump_o ( ), + + .fetch_enable_i ('b1 ), + .alert_minor_o ( ), + .alert_major_o ( ), + .core_sleep_o ( ) ); // SRAM block for instruction and data storage diff --git a/dv/uvm/core_ibex/ibex_dv.f b/dv/uvm/core_ibex/ibex_dv.f index 4cee39c3..e678c143 100644 --- a/dv/uvm/core_ibex/ibex_dv.f +++ b/dv/uvm/core_ibex/ibex_dv.f @@ -24,13 +24,34 @@ ${PRJ_DIR}/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_inv_39_32_enc.sv ${PRJ_DIR}/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_inv_39_32_dec.sv ${PRJ_DIR}/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_inv_72_64_enc.sv ${PRJ_DIR}/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_inv_72_64_dec.sv +${PRJ_DIR}/vendor/lowrisc_ip/ip/prim/rtl/prim_prince.sv +${PRJ_DIR}/vendor/lowrisc_ip/ip/prim/rtl/prim_subst_perm.sv +${PRJ_DIR}/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_28_22_enc.sv +${PRJ_DIR}/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_28_22_dec.sv +${PRJ_DIR}/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_39_32_enc.sv +${PRJ_DIR}/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_39_32_dec.sv +${PRJ_DIR}/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_72_64_enc.sv +${PRJ_DIR}/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_72_64_dec.sv // Until this list is generated by FuseSoC, we have to use manually generated // wrappers around the prim_* modules to instantiate the prim_generic_* ones, // see https://github.com/lowRISC/ibex/issues/893. ${PRJ_DIR}/dv/uvm/core_ibex/common/prim/prim_pkg.sv +${PRJ_DIR}/vendor/lowrisc_ip/ip/prim/rtl/prim_util_pkg.sv ${PRJ_DIR}/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_pkg.sv +${PRJ_DIR}/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_22_16_dec.sv +${PRJ_DIR}/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_22_16_enc.sv +${PRJ_DIR}/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_64_57_dec.sv +${PRJ_DIR}/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_64_57_enc.sv +${PRJ_DIR}/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_hamming_22_16_dec.sv +${PRJ_DIR}/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_hamming_22_16_enc.sv +${PRJ_DIR}/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_hamming_39_32_dec.sv +${PRJ_DIR}/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_hamming_39_32_enc.sv +${PRJ_DIR}/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_hamming_72_64_dec.sv +${PRJ_DIR}/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_hamming_72_64_enc.sv ${PRJ_DIR}/vendor/lowrisc_ip/ip/prim/rtl/prim_ram_1p_pkg.sv +${PRJ_DIR}/vendor/lowrisc_ip/ip/prim/rtl/prim_ram_1p_adv.sv +${PRJ_DIR}/vendor/lowrisc_ip/ip/prim/rtl/prim_ram_1p_scr.sv ${PRJ_DIR}/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_ram_1p.sv ${PRJ_DIR}/dv/uvm/core_ibex/common/prim/prim_ram_1p.sv ${PRJ_DIR}/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_clock_gating.sv diff --git a/dv/uvm/core_ibex/tb/core_ibex_tb_top.sv b/dv/uvm/core_ibex/tb/core_ibex_tb_top.sv index d971a575..c916db39 100644 --- a/dv/uvm/core_ibex/tb/core_ibex_tb_top.sv +++ b/dv/uvm/core_ibex/tb/core_ibex_tb_top.sv @@ -10,6 +10,7 @@ module core_ibex_tb_top; import core_ibex_test_pkg::*; wire clk; + wire scramble_req; wire rst_n; clk_rst_if ibex_clk_if(.clk(clk), .rst_n(rst_n)); @@ -63,6 +64,7 @@ module core_ibex_tb_top; parameter bit ICacheECC = 1'b0; parameter bit BranchPredictor = 1'b0; parameter bit SecureIbex = 1'b0; + parameter bit ICacheScramble = 1'b0; ibex_top_tracing #( .DmHaltAddr (32'h`BOOT_ADDR + 'h0 ), @@ -79,6 +81,7 @@ module core_ibex_tb_top; .ICache (ICache ), .ICacheECC (ICacheECC ), .SecureIbex (SecureIbex ), + .ICacheScramble (ICacheScramble ), .BranchPredictor (BranchPredictor ) ) dut ( .clk_i (clk ), @@ -91,39 +94,44 @@ module core_ibex_tb_top; .hart_id_i (32'b0 ), .boot_addr_i (32'h`BOOT_ADDR ), // align with spike boot address - .instr_req_o (instr_mem_vif.request), - .instr_gnt_i (instr_mem_vif.grant ), - .instr_rvalid_i (instr_mem_vif.rvalid ), - .instr_addr_o (instr_mem_vif.addr ), - .instr_rdata_i (instr_mem_vif.rdata ), - .instr_rdata_intg_i (instr_mem_vif.rintg ), - .instr_err_i (instr_mem_vif.error ), + .instr_req_o (instr_mem_vif.request ), + .instr_gnt_i (instr_mem_vif.grant ), + .instr_rvalid_i (instr_mem_vif.rvalid ), + .instr_addr_o (instr_mem_vif.addr ), + .instr_rdata_i (instr_mem_vif.rdata ), + .instr_rdata_intg_i (instr_mem_vif.rintg ), + .instr_err_i (instr_mem_vif.error ), - .data_req_o (data_mem_vif.request ), - .data_gnt_i (data_mem_vif.grant ), - .data_rvalid_i (data_mem_vif.rvalid ), - .data_addr_o (data_mem_vif.addr ), - .data_we_o (data_mem_vif.we ), - .data_be_o (data_mem_vif.be ), - .data_rdata_i (data_mem_vif.rdata ), - .data_rdata_intg_i (data_mem_vif.rintg ), - .data_wdata_o (data_mem_vif.wdata ), - .data_wdata_intg_o (data_mem_vif.wintg ), - .data_err_i (data_mem_vif.error ), + .data_req_o (data_mem_vif.request ), + .data_gnt_i (data_mem_vif.grant ), + .data_rvalid_i (data_mem_vif.rvalid ), + .data_addr_o (data_mem_vif.addr ), + .data_we_o (data_mem_vif.we ), + .data_be_o (data_mem_vif.be ), + .data_rdata_i (data_mem_vif.rdata ), + .data_rdata_intg_i (data_mem_vif.rintg ), + .data_wdata_o (data_mem_vif.wdata ), + .data_wdata_intg_o (data_mem_vif.wintg ), + .data_err_i (data_mem_vif.error ), - .irq_software_i (irq_vif.irq_software ), - .irq_timer_i (irq_vif.irq_timer ), - .irq_external_i (irq_vif.irq_external ), - .irq_fast_i (irq_vif.irq_fast ), - .irq_nm_i (irq_vif.irq_nm ), + .irq_software_i (irq_vif.irq_software ), + .irq_timer_i (irq_vif.irq_timer ), + .irq_external_i (irq_vif.irq_external ), + .irq_fast_i (irq_vif.irq_fast ), + .irq_nm_i (irq_vif.irq_nm ), - .debug_req_i (dut_if.debug_req ), - .crash_dump_o ( ), + .scramble_key_valid_i ('0 ), + .scramble_key_i ('0 ), + .scramble_nonce_i ('0 ), + .scramble_req_o ( ), - .fetch_enable_i (dut_if.fetch_enable ), - .alert_minor_o (dut_if.alert_minor ), - .alert_major_o (dut_if.alert_major ), - .core_sleep_o (dut_if.core_sleep ) + .debug_req_i (dut_if.debug_req ), + .crash_dump_o ( ), + + .fetch_enable_i (dut_if.fetch_enable ), + .alert_minor_o (dut_if.alert_minor ), + .alert_major_o (dut_if.alert_major ), + .core_sleep_o (dut_if.core_sleep ) ); // We should never see any alerts triggered in normal testing diff --git a/dv/uvm/icache/dv/ibex_icache_sim.core b/dv/uvm/icache/dv/ibex_icache_sim.core index 56268f62..378446c9 100644 --- a/dv/uvm/icache/dv/ibex_icache_sim.core +++ b/dv/uvm/icache/dv/ibex_icache_sim.core @@ -15,6 +15,7 @@ filesets: files_dv: depend: - lowrisc:dv:ibex_icache_test + - lowrisc:prim:ram_1p_scr files: - tb/tb.sv file_type: systemVerilogSource diff --git a/dv/uvm/icache/dv/ibex_icache_sim_cfg.hjson b/dv/uvm/icache/dv/ibex_icache_sim_cfg.hjson index d0eecea9..dc3e2051 100644 --- a/dv/uvm/icache/dv/ibex_icache_sim_cfg.hjson +++ b/dv/uvm/icache/dv/ibex_icache_sim_cfg.hjson @@ -23,17 +23,19 @@ // Import additional common sim cfg files. import_cfgs: [ // Project wide common sim cfg file - "{proj_root}/vendor/lowrisc_ip/dv/tools/dvsim/common_sim_cfg.hjson" + "{proj_root}/vendor/lowrisc_ip/dv/tools/dvsim/common_sim_cfg.hjson", + "{proj_root}/vendor/lowrisc_ip/dv/verilator/memutil_dpi_scrambled_opts.hjson" ] build_modes: [ { name: default - en_build_modes: ["{tool}_icache_ecc"] + en_build_modes: ["{tool}_icache_ecc", + "{tool}_memutil_dpi_scrambled_build_opts"] } { name: vcs_icache_ecc - build_opts: ["-gv tb.ICacheECC=1"] + build_opts: ["-gv tb.ICacheECC=1 -gv tb.ICacheScramble=0"] } { name: riviera_icache_ecc diff --git a/dv/uvm/icache/dv/tb/ic_top.sv b/dv/uvm/icache/dv/tb/ic_top.sv index fb31267b..f6432db2 100644 --- a/dv/uvm/icache/dv/tb/ic_top.sv +++ b/dv/uvm/icache/dv/tb/ic_top.sv @@ -2,7 +2,10 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 // -module ic_top import ibex_pkg::*; #(parameter bit ICacheECC = 1'b0) ( +module ic_top import ibex_pkg::*; #( + parameter bit ICacheECC = 1'b0, + parameter bit ICacheScramble = 1'b0 +) ( input logic clk_i, input logic rst_ni, input logic req_i, @@ -23,6 +26,12 @@ module ic_top import ibex_pkg::*; #(parameter bit ICacheECC = 1'b0) ( input logic instr_err_i, input logic instr_rvalid_i, + // 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, + input logic icache_enable_i, input logic icache_inval_i, output logic busy_o @@ -31,7 +40,8 @@ module ic_top import ibex_pkg::*; #(parameter bit ICacheECC = 1'b0) ( 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; - + localparam int unsigned NumAddrScrRounds = ICacheScramble ? 2 : 0; + localparam int unsigned NumDiffRounds = NumAddrScrRounds; // RAM IO logic [IC_NUM_WAYS-1:0] ic_tag_req; logic ic_tag_write; @@ -43,6 +53,12 @@ module ic_top import ibex_pkg::*; #(parameter bit ICacheECC = 1'b0) ( 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]; + // Scramble signals + logic [SCRAMBLE_KEY_W-1:0] scramble_key_q, scramble_key_d; + logic [SCRAMBLE_NONCE_W-1:0] scramble_nonce_q, scramble_nonce_d; + logic scramble_key_valid_d, scramble_key_valid_q; + logic scramble_req_d, scramble_req_q; + // DUT ibex_icache #( @@ -85,43 +101,135 @@ module ic_top import ibex_pkg::*; #(parameter bit ICacheECC = 1'b0) ( .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 ), .icache_enable_i ( icache_enable_i ), .icache_inval_i ( icache_inval_i ), .busy_o ( busy_o ) ); + + /////////////////////////////// + // Scrambling Infrastructure // + /////////////////////////////// + + if (ICacheScramble) begin : gen_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_i ? 1'b0 : + scramble_key_valid_q; + + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + scramble_key_q <= 128'hDDDDDDDDEEEEEEEEAAAAAAAADDDDDDDD; + scramble_nonce_q <= 64'hBBBBEEEEEEEEFFFF; + 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_i; + assign scramble_req_o = scramble_req_q; + + end else begin : gen_noscramble + + logic unused_scramble_inputs = scramble_key_valid_i & (|scramble_key_i) & + (|scramble_nonce_i) & scramble_req_q & icache_inval_i; + + assign scramble_req_d = 1'b0; + assign scramble_req_q = 1'b0; + assign scramble_req_o = 1'b0; + assign scramble_key_d = '0; + assign scramble_key_q = '0; + assign scramble_nonce_d = '0; + assign scramble_nonce_q = '0; + assign scramble_key_valid_q = 1'b1; + assign scramble_key_valid_d = 1'b1; + end + // RAMs for (genvar way = 0; way < IC_NUM_WAYS; way++) begin : gen_rams // Tag RAM instantiation - prim_ram_1p #( - .Width (TagSizeECC), - .Depth (IC_NUM_LINES), - .DataBitsPerMask (TagSizeECC) + prim_ram_1p_scr #( + .Width (TagSizeECC), + .Depth (IC_NUM_LINES), + .DataBitsPerMask (TagSizeECC), + .EnableParity (0), + .DiffWidth (TagSizeECC), + .NumAddrScrRounds (NumAddrScrRounds), + .NumDiffRounds (NumDiffRounds) ) tag_bank ( - .clk_i (clk_i), - .req_i (ic_tag_req[way]), - .cfg_i ('0), - .write_i (ic_tag_write), - .wmask_i ({TagSizeECC{1'b1}}), - .addr_i (ic_tag_addr), - .wdata_i (ic_tag_wdata), - .rdata_o (ic_tag_rdata[way]) + .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 ('0) ); + // Data RAM instantiation - prim_ram_1p #( - .Width (LineSizeECC), - .Depth (IC_NUM_LINES), - .DataBitsPerMask (LineSizeECC) + prim_ram_1p_scr #( + .Width (LineSizeECC), + .Depth (IC_NUM_LINES), + .DataBitsPerMask (LineSizeECC), + .EnableParity (0), + .ReplicateKeyStream (1), + .DiffWidth (LineSizeECC), + .NumAddrScrRounds (NumAddrScrRounds), + .NumDiffRounds (NumDiffRounds) ) data_bank ( - .clk_i (clk_i), - .req_i (ic_data_req[way]), - .cfg_i ('0), - .write_i (ic_data_write), - .wmask_i ({LineSizeECC{1'b1}}), - .addr_i (ic_data_addr), - .wdata_i (ic_data_wdata), - .rdata_o (ic_data_rdata[way]) + .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 ('0) ); end + endmodule diff --git a/dv/uvm/icache/dv/tb/tb.sv b/dv/uvm/icache/dv/tb/tb.sv index 61ea776b..e2614f37 100644 --- a/dv/uvm/icache/dv/tb/tb.sv +++ b/dv/uvm/icache/dv/tb/tb.sv @@ -2,7 +2,10 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 // -module tb #(parameter bit ICacheECC = 1'b0); +module tb #( + parameter bit ICacheECC = 1'b0, + parameter bit ICacheScramble = 1'b0 + ); // dep packages import uvm_pkg::*; import dv_utils_pkg::*; @@ -21,66 +24,93 @@ module tb #(parameter bit ICacheECC = 1'b0); ibex_icache_core_if core_if (.clk(clk), .rst_n(rst_n)); ibex_icache_mem_if mem_if (.clk(clk), .rst_n(rst_n)); + logic scramble_key_valid, scramble_req; + logic [127:0] scramble_key; + logic [63:0] scramble_nonce; + // dut ic_top #( - .ICacheECC (ICacheECC) + .ICacheECC (ICacheECC), + .ICacheScramble(ICacheScramble) ) dut ( .clk_i (clk), .rst_ni (rst_n), // Connect icache <-> core interface - .req_i (core_if.req), - .branch_i (core_if.branch), - .branch_mispredict_i (1'b0), - .mispredict_addr_i (32'b0), - .addr_i (core_if.branch_addr), - .ready_i (core_if.ready), - .valid_o (core_if.valid), - .rdata_o (core_if.rdata), - .addr_o (core_if.addr), - .err_o (core_if.err), - .err_plus2_o (core_if.err_plus2), - .icache_enable_i (core_if.enable), - .icache_inval_i (core_if.invalidate), - .busy_o (core_if.busy), + .req_i (core_if.req), + .branch_i (core_if.branch), + .branch_mispredict_i (1'b0), + .mispredict_addr_i (32'b0), + .addr_i (core_if.branch_addr), + .ready_i (core_if.ready), + .valid_o (core_if.valid), + .rdata_o (core_if.rdata), + .addr_o (core_if.addr), + .err_o (core_if.err), + .err_plus2_o (core_if.err_plus2), + .icache_enable_i (core_if.enable), + .icache_inval_i (core_if.invalidate), + .busy_o (core_if.busy), + .scramble_key_valid_i (scramble_key_valid), + .scramble_key_i (scramble_key), + .scramble_nonce_i (scramble_nonce), + .scramble_req_o (scramble_req), // Connect icache <-> instruction bus interface - .instr_req_o (mem_if.req), - .instr_gnt_i (mem_if.gnt), - .instr_addr_o (mem_if.addr), - .instr_rdata_i (mem_if.rdata), - .instr_err_i (mem_if.err), - .instr_rvalid_i (mem_if.rvalid) + .instr_req_o (mem_if.req), + .instr_gnt_i (mem_if.gnt), + .instr_addr_o (mem_if.addr), + .instr_rdata_i (mem_if.rdata), + .instr_err_i (mem_if.err), + .instr_rvalid_i (mem_if.rvalid) ); + // If the ICacheECC parameter is set in the DUT, generate another interface for each tag ram and // each data ram, binding them into the RAMs themselves. ECC tests can use these to insert errors // into memory lookups. generate if (dut.ICacheECC) begin : gen_ecc for (genvar w = 0; w < ibex_pkg::IC_NUM_WAYS; w++) begin : gen_ecc_ifs - bind dut.gen_rams[w].tag_bank.gen_badbit.u_impl_badbit ibex_icache_ecc_if tag_bank_if (.*); - bind dut.gen_rams[w].data_bank.gen_badbit.u_impl_badbit ibex_icache_ecc_if data_bank_if (.*); + bind dut.gen_rams[w].tag_bank.u_prim_ram_1p_adv.u_mem.gen_badbit.u_impl_badbit + ibex_icache_ecc_if tag_bank_if (.*); + bind dut.gen_rams[w].data_bank.u_prim_ram_1p_adv.u_mem.gen_badbit.u_impl_badbit + ibex_icache_ecc_if data_bank_if (.*); initial begin uvm_config_db#(virtual ibex_icache_ecc_if):: set(null, $sformatf("*.env.ecc_tag_agents[%0d]*", w), "vif", - dut.gen_rams[w].tag_bank.gen_badbit.u_impl_badbit.tag_bank_if); + dut.gen_rams[w].tag_bank.u_prim_ram_1p_adv. + u_mem.gen_badbit.u_impl_badbit.tag_bank_if); uvm_config_db#(virtual ibex_icache_ecc_if):: set(null, $sformatf("*.env.ecc_data_agents[%0d]*", w), "vif", - dut.gen_rams[w].data_bank.gen_badbit.u_impl_badbit.data_bank_if); + dut.gen_rams[w].data_bank.u_prim_ram_1p_adv. + u_mem.gen_badbit.u_impl_badbit.data_bank_if); end end end endgenerate + always @(posedge scramble_req) begin + scramble_key_valid = 1'b0; + #(20 * $urandom_range(1, 10)) + scramble_key = {$urandom(),$urandom(),$urandom(),$urandom()}; + scramble_nonce = {$urandom(),$urandom()}; + scramble_key_valid = 1'b1; + #20 + scramble_key_valid = 1'b0; + end + initial begin // drive clk and rst_n from clk_if clk_rst_if.set_active(); + scramble_key = {$urandom(),$urandom(),$urandom(),$urandom()}; + scramble_nonce = {$urandom(),$urandom()}; + scramble_key_valid = 1'b0; // Store virtual interfaces into the UVM config database. ECC interfaces are done separately // above because otherwise you have to repeat the (verbose) generate loop. diff --git a/dv/verilator/simple_system_cosim/ibex_simple_system_cosim.core b/dv/verilator/simple_system_cosim/ibex_simple_system_cosim.core index bc9acfca..9b7326f1 100644 --- a/dv/verilator/simple_system_cosim/ibex_simple_system_cosim.core +++ b/dv/verilator/simple_system_cosim/ibex_simple_system_cosim.core @@ -100,6 +100,12 @@ parameters: paramtype: vlogparam description: "Number of PMP regions" + ICacheScramble: + datatype: int + default: 0 + paramtype: vlogparam + description: "Enables ICache scrambling feature (EXPERIMENTAL) [0/1]" + targets: default: &default_target filesets: @@ -119,6 +125,7 @@ targets: - PMPEnable - PMPGranularity - PMPNumRegions + - ICacheScramble - SRAMInitFile lint: diff --git a/examples/simple_system/ibex_simple_system.core b/examples/simple_system/ibex_simple_system.core index 1813bab0..a74ceee3 100644 --- a/examples/simple_system/ibex_simple_system.core +++ b/examples/simple_system/ibex_simple_system.core @@ -72,6 +72,12 @@ parameters: paramtype: vlogparam description: "Enables security hardening features (EXPERIMENTAL) [0/1]" + ICacheScramble: + datatype: int + default: 0 + paramtype: vlogparam + description: "Enables ICache scrambling feature (EXPERIMENTAL) [0/1]" + BranchPredictor: datatype: int paramtype: vlogparam @@ -107,6 +113,7 @@ targets: - RV32B - RegFile - ICache + - ICacheScramble - ICacheECC - BranchTargetALU - WritebackStage diff --git a/examples/simple_system/ibex_simple_system_core.core b/examples/simple_system/ibex_simple_system_core.core index 84c298ad..86a82749 100644 --- a/examples/simple_system/ibex_simple_system_core.core +++ b/examples/simple_system/ibex_simple_system_core.core @@ -30,7 +30,6 @@ filesets: targets: default: filesets: - - tool_verilator ? (files_verilator) - tool_veriblelint ? (files_lint_verible) - files_sim - - files_verilator + - tool_verilator ? (files_verilator) diff --git a/examples/simple_system/rtl/ibex_simple_system.sv b/examples/simple_system/rtl/ibex_simple_system.sv index f54a8983..b61a2930 100644 --- a/examples/simple_system/rtl/ibex_simple_system.sv +++ b/examples/simple_system/rtl/ibex_simple_system.sv @@ -36,6 +36,7 @@ module ibex_simple_system ( ); parameter bit SecureIbex = 1'b0; + parameter bit ICacheScramble = 1'b0; parameter bit PMPEnable = 1'b0; parameter int unsigned PMPGranularity = 0; parameter int unsigned PMPNumRegions = 4; @@ -163,6 +164,7 @@ module ibex_simple_system ( ibex_top_tracing #( .SecureIbex ( SecureIbex ), + .ICacheScramble ( ICacheScramble ), .PMPEnable ( PMPEnable ), .PMPGranularity ( PMPGranularity ), .PMPNumRegions ( PMPNumRegions ), @@ -216,6 +218,11 @@ module ibex_simple_system ( .irq_fast_i (15'b0), .irq_nm_i (1'b0), + .scramble_key_valid_i ('0), + .scramble_key_i ('0), + .scramble_nonce_i ('0), + .scramble_req_o (), + .debug_req_i ('b0), .crash_dump_o (), diff --git a/ibex_configs.yaml b/ibex_configs.yaml index a9d3172a..ccaa01d2 100644 --- a/ibex_configs.yaml +++ b/ibex_configs.yaml @@ -21,6 +21,7 @@ small: PMPGranularity : 0 PMPNumRegions : 4 SecureIbex : 0 + ICacheScramble : 0 # Configuration to match that used in the OpenTitan project opentitan: @@ -37,6 +38,7 @@ opentitan: PMPGranularity : 0 PMPNumRegions : 16 SecureIbex : 1 + ICacheScramble : 0 # =============================== # * EXPERIMENTAL CONFIGURATIONS * @@ -59,6 +61,7 @@ experimental-maxperf: PMPGranularity : 0 PMPNumRegions : 4 SecureIbex : 0 + ICacheScramble : 0 # experimental-maxperf config above plus PMP enabled with 16 regions. experimental-maxperf-pmp: @@ -75,6 +78,7 @@ experimental-maxperf-pmp: PMPGranularity : 0 PMPNumRegions : 16 SecureIbex : 0 + ICacheScramble : 0 # experimental-maxperf-pmp config above with balanced bitmanip extension experimental-maxperf-pmp-bmbalanced: @@ -91,6 +95,7 @@ experimental-maxperf-pmp-bmbalanced: PMPGranularity : 0 PMPNumRegions : 16 SecureIbex : 0 + ICacheScramble : 0 # experimental-maxperf-pmp config above with full bitmanip extension experimental-maxperf-pmp-bmfull: @@ -107,6 +112,7 @@ experimental-maxperf-pmp-bmfull: PMPGranularity : 0 PMPNumRegions : 16 SecureIbex : 0 + ICacheScramble : 0 # experimental-maxperf-pmp-bmfull config above with icache enabled experimental-maxperf-pmp-bmfull-icache: @@ -123,6 +129,7 @@ experimental-maxperf-pmp-bmfull-icache: PMPGranularity : 0 PMPNumRegions : 16 SecureIbex : 0 + ICacheScramble : 0 # 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 @@ -142,4 +149,5 @@ experimental-branch-predictor: PMPGranularity : 0 PMPNumRegions : 4 SecureIbex : 0 + ICacheScramble : 0 diff --git a/ibex_icache.core b/ibex_icache.core index 5445bdc4..ca343617 100644 --- a/ibex_icache.core +++ b/ibex_icache.core @@ -8,7 +8,6 @@ filesets: files_rtl: depend: - lowrisc:prim:secded - - lowrisc:prim:ram_1p - lowrisc:prim:assert - lowrisc:ibex:ibex_pkg files: diff --git a/ibex_top.core b/ibex_top.core index 234311ec..7bd0b89d 100644 --- a/ibex_top.core +++ b/ibex_top.core @@ -13,6 +13,7 @@ filesets: - lowrisc:prim:buf - lowrisc:prim:clock_mux2 - lowrisc:prim:flop + - lowrisc:prim:ram_1p_scr files: - rtl/ibex_register_file_ff.sv # generic FF-based - rtl/ibex_register_file_fpga.sv # FPGA @@ -107,6 +108,12 @@ parameters: paramtype: vlogparam description: "Enables security hardening features (EXPERIMENTAL) [0/1]" + ICacheScramble: + datatype: int + default: 0 + paramtype: vlogparam + description: "Enables ICache scrambling feature (EXPERIMENTAL) [0/1]" + PMPEnable: datatype: int default: 0 diff --git a/ibex_top_tracing.core b/ibex_top_tracing.core index 550e5a18..ef4dab5d 100644 --- a/ibex_top_tracing.core +++ b/ibex_top_tracing.core @@ -83,6 +83,12 @@ parameters: paramtype: vlogparam description: "Enables security hardening features (EXPERIMENTAL) [0/1]" + ICacheScramble: + datatype: int + default: 0 + paramtype: vlogparam + description: "Enables ICache scrambling feature (EXPERIMENTAL) [0/1]" + PMPEnable: datatype: int default: 0 @@ -124,6 +130,7 @@ targets: - WritebackStage - BranchPredictor - SecureIbex + - ICacheScramble - PMPEnable - PMPGranularity - PMPNumRegions diff --git a/rtl/ibex_core.sv b/rtl/ibex_core.sv index 136648df..5f18ab2b 100644 --- a/rtl/ibex_core.sv +++ b/rtl/ibex_core.sv @@ -88,6 +88,7 @@ module ibex_core import ibex_pkg::*; #( 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 input logic irq_software_i, @@ -138,6 +139,7 @@ module ibex_core import ibex_pkg::*; #( input logic fetch_enable_i, output logic alert_minor_o, output logic alert_major_o, + output logic icache_inval_o, output logic core_busy_o ); @@ -383,16 +385,17 @@ module ibex_core import ibex_pkg::*; #( .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_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 .instr_valid_id_o (instr_valid_id), @@ -608,6 +611,7 @@ module ibex_core import ibex_pkg::*; #( .instr_id_done_o (instr_id_done) ); + assign icache_inval_o = icache_inval; // for RVFI only assign unused_illegal_insn_id = illegal_insn_id; diff --git a/rtl/ibex_icache.sv b/rtl/ibex_icache.sv index f5e6a952..e4f4ed2d 100644 --- a/rtl/ibex_icache.sv +++ b/rtl/ibex_icache.sv @@ -59,6 +59,7 @@ module ibex_icache import ibex_pkg::*; #( 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, // Cache status input logic icache_enable_i, @@ -184,6 +185,7 @@ module ibex_icache import ibex_pkg::*; #( logic output_err; // Invalidations logic start_inval, inval_done; + logic inval_lock, inval_req_d, inval_req_q; logic reset_inval_q; logic inval_prog_d, inval_prog_q; logic [IC_INDEX_W-1:0] inval_index_d, inval_index_q; @@ -252,7 +254,8 @@ module ibex_icache import ibex_pkg::*; #( assign fill_grant_ic0 = fill_req_ic0 & ~lookup_req_ic0 & ~inval_prog_q & ~ecc_write_req; // Qualified lookup grant to mask ram signals in IC1 if access was not made - assign lookup_actual_ic0 = lookup_grant_ic0 & icache_enable_i & ~inval_prog_q & ~start_inval; + assign lookup_actual_ic0 = lookup_grant_ic0 & icache_enable_i & ~inval_prog_q & + ~icache_inval_i & ~inval_lock & ~start_inval; // Tagram assign tag_req_ic0 = lookup_req_ic0 | fill_req_ic0 | inval_prog_q | ecc_write_req; @@ -530,7 +533,7 @@ module ibex_icache import ibex_pkg::*; #( end assign fill_cache_new = (branch_i | (|cache_cnt_q)) & icache_enable_i & - ~icache_inval_i & ~inval_prog_q; + ~icache_inval_i & ~inval_lock & ~inval_prog_q; end else begin : gen_cache_all @@ -598,7 +601,7 @@ module ibex_icache import ibex_pkg::*; #( // Any invalidation or disabling of the cache while the buffer is busy will stop allocation assign fill_cache_d[fb] = (fill_alloc[fb] & fill_cache_new) | (fill_cache_q[fb] & fill_busy_q[fb] & - icache_enable_i & ~icache_inval_i); + icache_enable_i & ~icache_inval_i & ~inval_lock); // Record whether the request hit in the cache assign fill_hit_ic1[fb] = lookup_valid_ic1 & fill_in_ic1[fb] & tag_hit_ic1 & ~ecc_err_ic1; assign fill_hit_d[fb] = fill_hit_ic1[fb] | (fill_hit_q[fb] & fill_busy_q[fb]); @@ -784,19 +787,11 @@ module ibex_icache import ibex_pkg::*; #( end end - if (ResetAll) begin : g_fill_way_ra - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - fill_way_q[fb] <= '0; - end else if (fill_way_en[fb]) begin - fill_way_q[fb] <= sel_way_ic1; - end - end - end else begin : g_fill_way_nr - always_ff @(posedge clk_i) begin - if (fill_way_en[fb]) begin - fill_way_q[fb] <= sel_way_ic1; - end + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + fill_way_q[fb] <= '0; + end else if (fill_way_en[fb]) begin + fill_way_q[fb] <= sel_way_ic1; end end @@ -1065,13 +1060,31 @@ module ibex_icache import ibex_pkg::*; #( // Invalidations // /////////////////// + + // We need to save the invalidation request inside a register. That way we can wait + // until we have a valid scrambling key to do it. Since the key itself is needed for + // starting to fill in the RAMs and read from them, ICache also needs to stop operating. + assign inval_req_d = (inval_req_q | icache_inval_i) & ~(inval_done & inval_prog_q); + + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + inval_req_q <= 1'b0; + end else begin + inval_req_q <= inval_req_d; + end + end + + // This will act like a lock mechanism. + // Main idea is to lock the invalidation request until we got a valid scrambling key. + assign inval_lock = inval_req_d & ~ic_scr_key_valid_i; + // Invalidate on reset, or when instructed. If an invalidation request is received while a - // previous invalidation is ongoing, it does not need to be restarted. - assign start_inval = (~reset_inval_q | icache_inval_i) & ~inval_prog_q; - assign inval_prog_d = start_inval | (inval_prog_q & ~inval_done); + // previous invalidation is ongoing, it does not need to be restarted. Do not start + // this process until inval lock is removed meaning the scrambling key is valid. + assign start_inval = ~inval_lock & (~reset_inval_q | inval_req_q) & ~inval_prog_q ; + assign inval_prog_d = ~inval_lock & (start_inval | (inval_prog_q & ~inval_done)); assign inval_done = &inval_index_q; - assign inval_index_d = start_inval ? '0 : - (inval_index_q + {{IC_INDEX_W-1{1'b0}},1'b1}); + assign inval_index_d = start_inval ? '0 : (inval_index_q + {{IC_INDEX_W-1{1'b0}},1'b1}); always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) begin @@ -1105,7 +1118,7 @@ module ibex_icache import ibex_pkg::*; #( // Only busy (for WFI purposes) while an invalidation is in-progress, or external requests are // outstanding. - assign busy_o = inval_prog_q | (|(fill_busy_q & ~fill_rvd_done)); + assign busy_o = inval_req_q | (|(fill_busy_q & ~fill_rvd_done)); //////////////// // Assertions // diff --git a/rtl/ibex_if_stage.sv b/rtl/ibex_if_stage.sv index 7f9f4d86..4cd3faf4 100644 --- a/rtl/ibex_if_stage.sv +++ b/rtl/ibex_if_stage.sv @@ -52,6 +52,7 @@ module ibex_if_stage import ibex_pkg::*; #( 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 logic instr_valid_id_o, // instr in IF-ID is valid @@ -246,6 +247,7 @@ module ibex_if_stage import ibex_pkg::*; #( .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 ), @@ -283,13 +285,14 @@ module ibex_if_stage import ibex_pkg::*; #( .busy_o ( prefetch_busy ) ); // ICache tieoffs - logic unused_icen, unused_icinv; + 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; diff --git a/rtl/ibex_lockstep.sv b/rtl/ibex_lockstep.sv index bbd07ba0..da01d3ea 100644 --- a/rtl/ibex_lockstep.sv +++ b/rtl/ibex_lockstep.sv @@ -81,6 +81,7 @@ module ibex_lockstep import ibex_pkg::*; #( 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, @@ -95,6 +96,7 @@ module ibex_lockstep import ibex_pkg::*; #( input logic fetch_enable_i, output logic alert_minor_o, output logic alert_major_o, + input logic icache_inval_i, input logic core_busy_i, input logic test_en_i, input logic scan_rst_ni @@ -178,6 +180,7 @@ module ibex_lockstep import ibex_pkg::*; #( logic irq_nm; logic debug_req; logic fetch_enable; + logic ic_scr_key_valid; } delayed_inputs_t; delayed_inputs_t [LockstepOffset-1:0] shadow_inputs_q; @@ -188,23 +191,24 @@ module ibex_lockstep import ibex_pkg::*; #( 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.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 @@ -290,6 +294,7 @@ module ibex_lockstep import ibex_pkg::*; #( logic [LineSizeECC-1:0] ic_data_wdata; logic irq_pending; crash_dump_t crash_dump; + logic icache_inval; logic core_busy; } delayed_outputs_t; @@ -321,6 +326,7 @@ module ibex_lockstep import ibex_pkg::*; #( 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.icache_inval = icache_inval_i; assign core_outputs_in.core_busy = core_busy_i; // Delay the outputs @@ -366,58 +372,59 @@ module ibex_lockstep import ibex_pkg::*; #( .DmHaltAddr ( DmHaltAddr ), .DmExceptionAddr ( DmExceptionAddr ) ) u_shadow_core ( - .clk_i (clk_i), - .rst_ni (rst_shadow_n), + .clk_i (clk_i), + .rst_ni (rst_shadow_n), - .hart_id_i (hart_id_i), - .boot_addr_i (boot_addr_i), + .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), + .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), + .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), + .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_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), + .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), + .debug_req_i (shadow_inputs_q[0].debug_req), + .crash_dump_o (shadow_outputs_d.crash_dump), `ifdef RVFI .rvfi_valid (), @@ -452,6 +459,7 @@ module ibex_lockstep import ibex_pkg::*; #( .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) ); diff --git a/rtl/ibex_pkg.sv b/rtl/ibex_pkg.sv index c6aac9cb..9c236572 100644 --- a/rtl/ibex_pkg.sv +++ b/rtl/ibex_pkg.sv @@ -330,22 +330,25 @@ package ibex_pkg; } 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 + 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 parameter int unsigned PMP_MAX_REGIONS = 16; @@ -599,5 +602,8 @@ package ibex_pkg; 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; endpackage diff --git a/rtl/ibex_top.sv b/rtl/ibex_top.sv index 71bc1ba7..20419ff0 100644 --- a/rtl/ibex_top.sv +++ b/rtl/ibex_top.sv @@ -30,10 +30,14 @@ module ibex_top import ibex_pkg::*; #( parameter bit DbgTriggerEn = 1'b0, 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 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 input logic clk_i, @@ -74,6 +78,12 @@ module ibex_top import ibex_pkg::*; #( input logic [14:0] irq_fast_i, 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 input logic debug_req_i, output crash_dump_t crash_dump_o, @@ -130,6 +140,9 @@ module ibex_top import ibex_pkg::*; #( 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 + localparam int unsigned NumAddrScrRounds = ICacheScramble ? 2 : 0; + localparam int unsigned NumDiffRounds = NumAddrScrRounds; // Clock signals logic clk; @@ -159,6 +172,12 @@ module ibex_top import ibex_pkg::*; #( // Alert signals logic core_alert_major, core_alert_minor; logic lockstep_alert_major, 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; ///////////////////// // Main clock gate // @@ -247,16 +266,17 @@ module ibex_top import ibex_pkg::*; #( .rf_rdata_a_ecc_i (rf_rdata_a_ecc), .rf_rdata_b_ecc_i (rf_rdata_b_ecc), - .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_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_timer_i, @@ -299,9 +319,10 @@ module ibex_top import ibex_pkg::*; #( `endif .fetch_enable_i, - .alert_minor_o(core_alert_minor), - .alert_major_o(core_alert_major), - .core_busy_o (core_busy_d) + .alert_minor_o (core_alert_minor), + .alert_major_o (core_alert_major), + .icache_inval_o(icache_inval), + .core_busy_o (core_busy_d) ); ///////////////////////////////// @@ -373,6 +394,58 @@ module ibex_top import ibex_pkg::*; #( ); end + /////////////////////////////// + // Scrambling Infrastructure // + /////////////////////////////// + + if (ICacheScramble) begin : gen_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 // //////////////////////// @@ -380,35 +453,72 @@ module ibex_top import ibex_pkg::*; #( if (ICache) begin : gen_rams for (genvar way = 0; way < IC_NUM_WAYS; way++) begin : gen_rams_inner + // Tag RAM instantiation - prim_ram_1p #( - .Width (TagSizeECC), - .Depth (IC_NUM_LINES), - .DataBitsPerMask(TagSizeECC) + prim_ram_1p_scr #( + .Width (TagSizeECC), + .Depth (IC_NUM_LINES), + .DataBitsPerMask (TagSizeECC), + .EnableParity (0), + .DiffWidth (TagSizeECC), + .NumAddrScrRounds (NumAddrScrRounds), + .NumDiffRounds (NumDiffRounds) ) tag_bank ( - .clk_i (clk_i), - .req_i (ic_tag_req[way]), - .cfg_i (ram_cfg_i), - .write_i(ic_tag_write), - .wmask_i({TagSizeECC{1'b1}}), - .addr_i (ic_tag_addr), - .wdata_i(ic_tag_wdata), - .rdata_o(ic_tag_rdata[way]) + .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 #( - .Width (LineSizeECC), - .Depth (IC_NUM_LINES), - .DataBitsPerMask(LineSizeECC) + 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 (clk_i), - .req_i (ic_data_req[way]), - .cfg_i (ram_cfg_i), - .write_i(ic_data_write), - .wmask_i({LineSizeECC{1'b1}}), - .addr_i (ic_data_addr), - .wdata_i(ic_data_wdata), - .rdata_o(ic_data_rdata[way]) + .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 @@ -419,7 +529,11 @@ module ibex_top import ibex_pkg::*; #( assign unused_ram_cfg = ram_cfg_i; assign unused_ram_inputs = (|ic_tag_req) & ic_tag_write & (|ic_tag_addr) & (|ic_tag_wdata) & - (|ic_data_req) & ic_data_write & (|ic_data_addr) & (|ic_data_wdata); + (|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}; @@ -469,6 +583,7 @@ module ibex_top import ibex_pkg::*; #( ic_data_write, ic_data_addr, ic_data_wdata, + scramble_key_valid_i, irq_software_i, irq_timer_i, irq_external_i, @@ -478,6 +593,7 @@ module ibex_top import ibex_pkg::*; #( debug_req_i, crash_dump_o, fetch_enable_i, + icache_inval, core_busy_d }); @@ -523,6 +639,7 @@ module ibex_top import ibex_pkg::*; #( 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; @@ -535,6 +652,7 @@ module ibex_top import ibex_pkg::*; #( crash_dump_t crash_dump_local; logic fetch_enable_local; + logic icache_inval_local; logic core_busy_local; assign buf_in = { @@ -573,6 +691,7 @@ module ibex_top import ibex_pkg::*; #( ic_data_write, ic_data_addr, ic_data_wdata, + scramble_key_valid_q, irq_software_i, irq_timer_i, irq_external_i, @@ -582,6 +701,7 @@ module ibex_top import ibex_pkg::*; #( debug_req_i, crash_dump_o, fetch_enable_i, + icache_inval, core_busy_d }; @@ -621,6 +741,7 @@ module ibex_top import ibex_pkg::*; #( 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, @@ -630,6 +751,7 @@ module ibex_top import ibex_pkg::*; #( debug_req_local, crash_dump_local, fetch_enable_local, + icache_inval_local, core_busy_local } = buf_out; @@ -727,6 +849,7 @@ module ibex_top import ibex_pkg::*; #( .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), @@ -741,6 +864,7 @@ module ibex_top import ibex_pkg::*; #( .fetch_enable_i (fetch_enable_local), .alert_minor_o (lockstep_alert_minor_local), .alert_major_o (lockstep_alert_major_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) diff --git a/rtl/ibex_top_tracing.sv b/rtl/ibex_top_tracing.sv index c08fc184..85d6e200 100644 --- a/rtl/ibex_top_tracing.sv +++ b/rtl/ibex_top_tracing.sv @@ -24,6 +24,7 @@ module ibex_top_tracing import ibex_pkg::*; #( parameter bit DbgTriggerEn = 1'b0, 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, @@ -70,6 +71,12 @@ module ibex_top_tracing import ibex_pkg::*; #( input logic [14:0] irq_fast_i, 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 input logic debug_req_i, output crash_dump_t crash_dump_o, @@ -145,6 +152,7 @@ module ibex_top_tracing import ibex_pkg::*; #( .DbgHwBreakNum ( DbgHwBreakNum ), .WritebackStage ( WritebackStage ), .SecureIbex ( SecureIbex ), + .ICacheScramble ( ICacheScramble ), .RndCnstLfsrSeed ( RndCnstLfsrSeed ), .RndCnstLfsrPerm ( RndCnstLfsrPerm ), .DmHaltAddr ( DmHaltAddr ), @@ -186,6 +194,11 @@ module ibex_top_tracing import ibex_pkg::*; #( .irq_fast_i, .irq_nm_i, + .scramble_key_valid_i, + .scramble_key_i, + .scramble_nonce_i, + .scramble_req_o, + .debug_req_i, .crash_dump_o,