diff --git a/doc/02_user/integration.rst b/doc/02_user/integration.rst index ad7e4518..8b9211f1 100644 --- a/doc/02_user/integration.rst +++ b/doc/02_user/integration.rst @@ -208,9 +208,12 @@ Interfaces +----------------------------+------------------------------------------------------------------------+ | ``double_fault_seen_o`` | A double fault was observed, see :ref:`double-fault-detect` | +----------------------------+-------------------------+-----+----------------------------------------+ -| ``fetch_enable_i`` | 1 | in | Allow the core to fetch instructions. | +| ``fetch_enable_i`` | 4 | in | Allow the core to fetch instructions. | | | | | If this bit is set low, the core will | -| | | | pause fetching new instructions. | +| | | | pause fetching new instructions. A | +| | | | multi-bit encoding scheme is used. See | +| | | | `FetchEnableOn` / `FetchEnableOff` in | +| | | | :file:`rtl/ibex_pkg.sv` | +----------------------------+-------------------------+-----+----------------------------------------+ | ``core_sleep_o`` | 1 | out | Core in WFI with no outstanding data | | | | | or instruction accesses. Deasserts | diff --git a/dv/riscv_compliance/rtl/ibex_riscv_compliance.sv b/dv/riscv_compliance/rtl/ibex_riscv_compliance.sv index 46831944..485399d6 100644 --- a/dv/riscv_compliance/rtl/ibex_riscv_compliance.sv +++ b/dv/riscv_compliance/rtl/ibex_riscv_compliance.sv @@ -131,57 +131,57 @@ module ibex_riscv_compliance ( .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 ), - .scramble_key_valid_i ('0 ), - .scramble_key_i ('0 ), - .scramble_nonce_i ('0 ), - .scramble_req_o ( ), + .scramble_key_valid_i ('0 ), + .scramble_key_i ('0 ), + .scramble_nonce_i ('0 ), + .scramble_req_o ( ), - .debug_req_i ('b0 ), - .crash_dump_o ( ), - .double_fault_seen_o ( ), + .debug_req_i ('b0 ), + .crash_dump_o ( ), + .double_fault_seen_o ( ), - .fetch_enable_i ('b1 ), - .alert_minor_o ( ), - .alert_major_internal_o ( ), - .alert_major_bus_o ( ), - .core_sleep_o ( ) + .fetch_enable_i (ibex_pkg::FetchEnableOn), + .alert_minor_o ( ), + .alert_major_internal_o ( ), + .alert_major_bus_o ( ), + .core_sleep_o ( ) ); // SRAM block for instruction and data storage diff --git a/dv/uvm/core_ibex/env/core_ibex_dut_probe_if.sv b/dv/uvm/core_ibex/env/core_ibex_dut_probe_if.sv index 07015ab6..43cab77f 100644 --- a/dv/uvm/core_ibex/env/core_ibex_dut_probe_if.sv +++ b/dv/uvm/core_ibex/env/core_ibex_dut_probe_if.sv @@ -4,20 +4,20 @@ // Interface to probe DUT internal signal interface core_ibex_dut_probe_if(input logic clk); - logic reset; - logic illegal_instr; - logic ecall; - logic wfi; - logic ebreak; - logic dret; - logic mret; - logic fetch_enable; - logic core_sleep; - logic alert_minor; - logic alert_major_internal; - logic alert_major_bus; - logic debug_req; - ibex_pkg::priv_lvl_e priv_mode; + logic reset; + logic illegal_instr; + logic ecall; + logic wfi; + logic ebreak; + logic dret; + logic mret; + ibex_pkg::fetch_enable_t fetch_enable; + logic core_sleep; + logic alert_minor; + logic alert_major_internal; + logic alert_major_bus; + logic debug_req; + ibex_pkg::priv_lvl_e priv_mode; clocking dut_cb @(posedge clk); output fetch_enable; diff --git a/dv/uvm/core_ibex/tests/core_ibex_base_test.sv b/dv/uvm/core_ibex/tests/core_ibex_base_test.sv index 560ef0e9..aa1b96ba 100644 --- a/dv/uvm/core_ibex/tests/core_ibex_base_test.sv +++ b/dv/uvm/core_ibex/tests/core_ibex_base_test.sv @@ -132,10 +132,10 @@ class core_ibex_base_test extends uvm_test; enable_irq_seq = cfg.enable_irq_single_seq || cfg.enable_irq_multiple_seq; phase.raise_objection(this); cur_run_phase = phase; - dut_vif.dut_cb.fetch_enable <= 1'b0; + dut_vif.dut_cb.fetch_enable <= ibex_pkg::FetchEnableOff; clk_vif.wait_clks(100); load_binary_to_mem(); - dut_vif.dut_cb.fetch_enable <= 1'b1; + dut_vif.dut_cb.fetch_enable <= ibex_pkg::FetchEnableOn; send_stimulus(); wait_for_test_done(); cur_run_phase = null; @@ -194,7 +194,7 @@ class core_ibex_base_test extends uvm_test; check_perf_stats(); // De-assert fetch enable to finish the test clk_vif.wait_clks(10); - dut_vif.dut_cb.fetch_enable <= 1'b0; + dut_vif.dut_cb.fetch_enable <= ibex_pkg::FetchEnableOff; end // Wait some time for the remaining instruction to finish clk_vif.wait_clks(3000); diff --git a/dv/uvm/core_ibex/tests/core_ibex_test_lib.sv b/dv/uvm/core_ibex/tests/core_ibex_test_lib.sv index 817b2884..dc974b69 100644 --- a/dv/uvm/core_ibex/tests/core_ibex_test_lib.sv +++ b/dv/uvm/core_ibex/tests/core_ibex_test_lib.sv @@ -47,7 +47,7 @@ class core_ibex_reset_test extends core_ibex_base_test; clk_vif.wait_clks($urandom_range(0, 50000)); fork begin - dut_vif.dut_cb.fetch_enable <= 1'b0; + dut_vif.dut_cb.fetch_enable <= ibex_pkg::FetchEnableOff; clk_vif.apply_reset(.reset_width_clks (100)); end begin @@ -61,7 +61,7 @@ class core_ibex_reset_test extends core_ibex_base_test; end join // Assert fetch_enable to have the core start executing from boot address - dut_vif.dut_cb.fetch_enable <= 1'b1; + dut_vif.dut_cb.fetch_enable <= ibex_pkg::FetchEnableOn; end endtask diff --git a/examples/simple_system/rtl/ibex_simple_system.sv b/examples/simple_system/rtl/ibex_simple_system.sv index 7131b5d1..227dae01 100644 --- a/examples/simple_system/rtl/ibex_simple_system.sv +++ b/examples/simple_system/rtl/ibex_simple_system.sv @@ -227,7 +227,7 @@ module ibex_simple_system ( .crash_dump_o (), .double_fault_seen_o (), - .fetch_enable_i ('b1), + .fetch_enable_i (ibex_pkg::FetchEnableOn), .alert_minor_o (), .alert_major_internal_o (), .alert_major_bus_o (), diff --git a/rtl/ibex_core.sv b/rtl/ibex_core.sv index 2b6f52c5..1963731f 100644 --- a/rtl/ibex_core.sv +++ b/rtl/ibex_core.sv @@ -137,7 +137,7 @@ module ibex_core import ibex_pkg::*; #( `endif // CPU Control Signals - input logic fetch_enable_i, + input fetch_enable_t fetch_enable_i, output logic alert_minor_o, output logic alert_major_o, output logic icache_inval_o, @@ -450,8 +450,25 @@ module ibex_core import ibex_pkg::*; #( // available 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 + // 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 - assign instr_req_gated = instr_req_int & fetch_enable_i; + 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 + 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 + logic unused_fetch_enable; + 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 ////////////// // ID stage // diff --git a/rtl/ibex_lockstep.sv b/rtl/ibex_lockstep.sv index 3b17f077..1f441676 100644 --- a/rtl/ibex_lockstep.sv +++ b/rtl/ibex_lockstep.sv @@ -94,7 +94,7 @@ module ibex_lockstep import ibex_pkg::*; #( input crash_dump_t crash_dump_i, input logic double_fault_seen_i, - input logic fetch_enable_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, @@ -182,7 +182,7 @@ module ibex_lockstep import ibex_pkg::*; #( logic [14:0] irq_fast; logic irq_nm; logic debug_req; - logic fetch_enable; + fetch_enable_t fetch_enable; logic ic_scr_key_valid; } delayed_inputs_t; diff --git a/rtl/ibex_pkg.sv b/rtl/ibex_pkg.sv index 9c236572..fec80fdf 100644 --- a/rtl/ibex_pkg.sv +++ b/rtl/ibex_pkg.sv @@ -606,4 +606,15 @@ package ibex_pkg; 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 + // `ibex_core` may need adjusting. + parameter fetch_enable_t FetchEnableOn = 4'b1001; + parameter fetch_enable_t FetchEnableOff = 4'b0110; endpackage diff --git a/rtl/ibex_top.sv b/rtl/ibex_top.sv index bd948230..3e857f17 100644 --- a/rtl/ibex_top.sv +++ b/rtl/ibex_top.sv @@ -123,7 +123,7 @@ module ibex_top import ibex_pkg::*; #( `endif // CPU Control Signals - input logic fetch_enable_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, @@ -182,6 +182,8 @@ module ibex_top import ibex_pkg::*; #( 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 // ///////////////////// @@ -208,6 +210,12 @@ module ibex_top import ibex_pkg::*; #( // Core instantiation // //////////////////////// + // Buffer fetch_enable_i to prevent synthesis optimising away multi-bit signal + prim_buf #(.Width($bits(fetch_enable_t))) u_fetch_enable_buf ( + .in_i (fetch_enable_i), + .out_o(fetch_enable_buf) + ); + ibex_core #( .PMPEnable (PMPEnable), .PMPGranularity (PMPGranularity), @@ -322,7 +330,7 @@ module ibex_top import ibex_pkg::*; #( .rvfi_ext_mcycle, `endif - .fetch_enable_i, + .fetch_enable_i(fetch_enable_buf), .alert_minor_o (core_alert_minor), .alert_major_o (core_alert_major), .icache_inval_o(icache_inval), @@ -656,7 +664,7 @@ module ibex_top import ibex_pkg::*; #( logic debug_req_local; crash_dump_t crash_dump_local; logic double_fault_seen_local; - logic fetch_enable_local; + fetch_enable_t fetch_enable_local; logic icache_inval_local; logic core_busy_local; diff --git a/rtl/ibex_top_tracing.sv b/rtl/ibex_top_tracing.sv index b97e78ad..f4384653 100644 --- a/rtl/ibex_top_tracing.sv +++ b/rtl/ibex_top_tracing.sv @@ -83,7 +83,7 @@ module ibex_top_tracing import ibex_pkg::*; #( output logic double_fault_seen_o, // CPU Control Signals - input logic fetch_enable_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,