[rtl] Add bus integrity checking

Extra bits are added alongside read/write data for the instruction and
data buses to facilitate data integrity checking.

Ibex testbench extended to generate the expected bits.

All other top-levels modified to add the new signals (which are mostly
ignored).

Signed-off-by: Tom Roberts <tomroberts@lowrisc.org>
This commit is contained in:
Tom Roberts 2021-08-02 16:16:19 +01:00 committed by Tom Roberts
parent 14115ea3a8
commit 48f11c6733
20 changed files with 341 additions and 206 deletions

View file

@ -35,51 +35,54 @@ Instantiation Template
.DmExceptionAddr ( 32'h1A110808 )
) u_top (
// Clock and reset
.clk_i (),
.rst_ni (),
.test_en_i (),
.scan_rst_ni (),
.ram_cfg_i (),
.clk_i (),
.rst_ni (),
.test_en_i (),
.scan_rst_ni (),
.ram_cfg_i (),
// Configuration
.hart_id_i (),
.boot_addr_i (),
.hart_id_i (),
.boot_addr_i (),
// Instruction memory interface
.instr_req_o (),
.instr_gnt_i (),
.instr_rvalid_i (),
.instr_addr_o (),
.instr_rdata_i (),
.instr_err_i (),
.instr_req_o (),
.instr_gnt_i (),
.instr_rvalid_i (),
.instr_addr_o (),
.instr_rdata_i (),
.instr_rdata_intg_i (),
.instr_err_i (),
// Data memory interface
.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_err_i (),
.data_req_o (),
.data_gnt_i (),
.data_rvalid_i (),
.data_we_o (),
.data_be_o (),
.data_addr_o (),
.data_wdata_o (),
.data_wdata_intg_o (),
.data_rdata_i (),
.data_rdata_intg_i (),
.data_err_i (),
// Interrupt inputs
.irq_software_i (),
.irq_timer_i (),
.irq_external_i (),
.irq_fast_i (),
.irq_nm_i (),
.irq_software_i (),
.irq_timer_i (),
.irq_external_i (),
.irq_fast_i (),
.irq_nm_i (),
// Debug interface
.debug_req_i (),
.crash_dump_o (),
.debug_req_i (),
.crash_dump_o (),
// Special control signals
.fetch_enable_i (),
.alert_minor_o (),
.alert_major_o (),
.core_sleep_o ()
.fetch_enable_i (),
.alert_minor_o (),
.alert_major_o (),
.core_sleep_o ()
);
Parameters

View file

@ -45,26 +45,28 @@ The main difference is that the instruction interface does not allow for write t
.. tabularcolumns:: |p{4cm}|l|p{9cm}|
+-------------------------+-----------+-----------------------------------------------+
| Signal | Direction | Description |
+=========================+===========+===============================================+
| ``instr_req_o`` | output | Request valid, must stay high until |
| | | ``instr_gnt_i`` is high for one cycle |
+-------------------------+-----------+-----------------------------------------------+
| ``instr_addr_o[31:0]`` | output | Address, word aligned |
+-------------------------+-----------+-----------------------------------------------+
| ``instr_gnt_i`` | input | The other side accepted the request. |
| | | ``instr_req_o`` may be deasserted in the next |
| | | cycle. |
+-------------------------+-----------+-----------------------------------------------+
| ``instr_rvalid_i`` | input | ``instr_rdata_i`` holds valid data when |
| | | ``instr_rvalid_i`` is high. This signal will |
| | | be high for exactly one cycle per request. |
+-------------------------+-----------+-----------------------------------------------+
| ``instr_rdata_i[31:0]`` | input | Data read from memory |
+-------------------------+-----------+-----------------------------------------------+
| ``instr_err_i`` | input | Memory access error |
+-------------------------+-----------+-----------------------------------------------+
+-----------------------------+-----------+-----------------------------------------------+
| Signal | Direction | Description |
+=============================+===========+===============================================+
| ``instr_req_o`` | output | Request valid, must stay high until |
| | | ``instr_gnt_i`` is high for one cycle |
+-----------------------------+-----------+-----------------------------------------------+
| ``instr_addr_o[31:0]`` | output | Address, word aligned |
+-----------------------------+-----------+-----------------------------------------------+
| ``instr_gnt_i`` | input | The other side accepted the request. |
| | | ``instr_req_o`` may be deasserted in the next |
| | | cycle. |
+-----------------------------+-----------+-----------------------------------------------+
| ``instr_rvalid_i`` | input | ``instr_rdata_i`` holds valid data when |
| | | ``instr_rvalid_i`` is high. This signal will |
| | | be high for exactly one cycle per request. |
+-----------------------------+-----------+-----------------------------------------------+
| ``instr_rdata_i[31:0]`` | input | Data read from memory |
+-----------------------------+-----------+-----------------------------------------------+
| ``instr_rdata_intg_i[6:0]`` | input | Data integrity bits from memory |
+-----------------------------+-----------+-----------------------------------------------+
| ``instr_err_i`` | input | Memory access error |
+-----------------------------+-----------+-----------------------------------------------+
Misaligned Accesses

View file

@ -14,39 +14,56 @@ Data-Side Memory Interface
Signals that are used by the LSU:
+-------------------------+-----------+-----------------------------------------------+
| Signal | Direction | Description |
+=========================+===========+===============================================+
| ``data_req_o`` | output | Request valid, must stay high until |
| | | ``data_gnt_i`` is high for one cycle |
+-------------------------+-----------+-----------------------------------------------+
| ``data_addr_o[31:0]`` | output | Address, word aligned |
+-------------------------+-----------+-----------------------------------------------+
| ``data_we_o`` | output | Write Enable, high for writes, low for |
| | | reads. Sent together with ``data_req_o`` |
+-------------------------+-----------+-----------------------------------------------+
| ``data_be_o[3:0]`` | output | Byte Enable. Is set for the bytes to |
| | | write/read, sent together with ``data_req_o`` |
+-------------------------+-----------+-----------------------------------------------+
| ``data_wdata_o[31:0]`` | output | Data to be written to memory, sent together |
| | | with ``data_req_o`` |
+-------------------------+-----------+-----------------------------------------------+
| ``data_gnt_i`` | input | The other side accepted the request. |
| | | Outputs may change in the next cycle. |
+-------------------------+-----------+-----------------------------------------------+
| ``data_rvalid_i`` | input | ``data_err_i`` and ``data_rdata_i`` hold |
| | | valid data when ``data_rvalid_i`` is high. |
| | | This signal will be high for exactly one |
| | | cycle per request. |
+-------------------------+-----------+-----------------------------------------------+
| ``data_err_i`` | input | Error response from the bus or the memory: |
| | | request cannot be handled. High in case of an |
| | | error. |
+-------------------------+-----------+-----------------------------------------------+
| ``data_rdata_i[31:0]`` | input | Data read from memory |
+-------------------------+-----------+-----------------------------------------------+
+----------------------------+-----------+-----------------------------------------------+
| Signal | Direction | Description |
+============================+===========+===============================================+
| ``data_req_o`` | output | Request valid, must stay high until |
| | | ``data_gnt_i`` is high for one cycle |
+----------------------------+-----------+-----------------------------------------------+
| ``data_addr_o[31:0]`` | output | Address, word aligned |
+----------------------------+-----------+-----------------------------------------------+
| ``data_we_o`` | output | Write Enable, high for writes, low for |
| | | reads. Sent together with ``data_req_o`` |
+----------------------------+-----------+-----------------------------------------------+
| ``data_be_o[3:0]`` | output | Byte Enable. Is set for the bytes to |
| | | write/read, sent together with ``data_req_o`` |
+----------------------------+-----------+-----------------------------------------------+
| ``data_wdata_o[31:0]`` | output | Data to be written to memory, sent together |
| | | with ``data_req_o`` |
+----------------------------+-----------+-----------------------------------------------+
| ``data_wdata_intg_o[6:0]`` | output | Integrity bits to be written to memory, sent |
| | | together with ``data_req_o`` (not used unless |
| | | the SecureIbex parameter is set) |
+----------------------------+-----------+-----------------------------------------------+
| ``data_gnt_i`` | input | The other side accepted the request. |
| | | Outputs may change in the next cycle. |
+----------------------------+-----------+-----------------------------------------------+
| ``data_rvalid_i`` | input | ``data_err_i`` and ``data_rdata_i`` hold |
| | | valid data when ``data_rvalid_i`` is high. |
| | | This signal will be high for exactly one |
| | | cycle per request. |
+----------------------------+-----------+-----------------------------------------------+
| ``data_err_i`` | input | Error response from the bus or the memory: |
| | | request cannot be handled. High in case of an |
| | | error. |
+----------------------------+-----------+-----------------------------------------------+
| ``data_rdata_i[31:0]`` | input | Data read from memory |
+----------------------------+-----------+-----------------------------------------------+
| ``data_rdata_intg_i[6:0]`` | input | Integrity bits read from memory (ignored |
| | | unless the SecureIbex parameter is set) |
+----------------------------+-----------+-----------------------------------------------+
Bus Integrity Checking
----------------------
The core can optionally generate and verify check bits sent alongside the data for memory accesses.
Checkbits are generated and checked using a 39/32 Hsaio code (see :file:`vendor/lowrisc_ip/ip/prim/rtl/prim_secded_39_32_enc.sv`).
When this feature is used, any mismatch in checkbits will generate a major alert.
This feature is only used if the core is configured with the SecureIbex parameter set.
For all other configurations, the integrity signals can be ignored.
Misaligned Accesses
-------------------

View file

@ -57,6 +57,13 @@ This will make the insertion interval of dummy instructions much harder for an a
Note that the dummy instruction feature inserts multiply and divide instructions.
The core must be configured with a multiplier (`RV32M != ibex_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 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
-----------------
@ -78,6 +85,7 @@ 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 a 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
------------------

View file

@ -130,47 +130,50 @@ 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_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_rdata_i (host_rdata[CoreD] ),
.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 ( ),
.debug_req_i ('b0 ),
.crash_dump_o ( ),
.fetch_enable_i ('b1 ),
.alert_minor_o ( ),
.alert_major_o ( ),
.core_sleep_o ( )
.fetch_enable_i ('b1 ),
.alert_minor_o ( ),
.alert_major_o ( ),
.core_sleep_o ( )
);
// SRAM block for instruction and data storage

View file

@ -4,7 +4,8 @@
interface ibex_mem_intf#(
parameter int ADDR_WIDTH = 32,
parameter int DATA_WIDTH = 32
parameter int DATA_WIDTH = 32,
parameter int INTG_WIDTH = 7
) (
input clk
);
@ -17,7 +18,9 @@ interface ibex_mem_intf#(
wire [DATA_WIDTH/8-1:0] be;
wire rvalid;
wire [DATA_WIDTH-1:0] wdata;
wire [INTG_WIDTH-1:0] wintg;
wire [DATA_WIDTH-1:0] rdata;
wire [INTG_WIDTH-1:0] rintg;
wire error;
clocking request_driver_cb @(posedge clk);
@ -29,7 +32,9 @@ interface ibex_mem_intf#(
output be;
input rvalid;
output wdata;
output wintg;
input rdata;
input rintg;
input error;
endclocking
@ -42,7 +47,9 @@ interface ibex_mem_intf#(
input be;
output rvalid;
input wdata;
input wintg;
output rdata;
output rintg;
output error;
endclocking
@ -55,7 +62,9 @@ interface ibex_mem_intf#(
input be;
input rvalid;
input wdata;
input wintg;
input rdata;
input rintg;
input error;
endclocking

View file

@ -9,6 +9,7 @@ package ibex_mem_intf_agent_pkg;
parameter int DATA_WIDTH = 32;
parameter int ADDR_WIDTH = 32;
parameter int INTG_WIDTH = 7;
typedef enum { READ, WRITE } rw_e;

View file

@ -60,6 +60,7 @@ class ibex_mem_intf_monitor extends uvm_monitor;
if(vif.monitor_cb.we) begin
trans_collected.read_write = WRITE;
trans_collected.data = vif.monitor_cb.wdata;
trans_collected.intg = vif.monitor_cb.wintg;
end else begin
trans_collected.read_write = READ;
end
@ -81,6 +82,7 @@ class ibex_mem_intf_monitor extends uvm_monitor;
vif.wait_clks(1);
while(vif.monitor_cb.rvalid === 0);
trans_collected.data = vif.monitor_cb.rdata;
trans_collected.intg = vif.monitor_cb.rintg;
item_collected_port.write(trans_collected);
end
endtask : collect_data_phase

View file

@ -49,6 +49,7 @@ class ibex_mem_intf_request_driver extends uvm_driver #(ibex_mem_intf_seq_item);
vif.request_driver_cb.request <= 'h0;
vif.request_driver_cb.addr <= 'hz;
vif.request_driver_cb.wdata <= 'hz;
vif.request_driver_cb.wintg <= 'hz;
vif.request_driver_cb.be <= 'bz;
vif.request_driver_cb.we <= 'bz;
end
@ -63,11 +64,13 @@ class ibex_mem_intf_request_driver extends uvm_driver #(ibex_mem_intf_seq_item);
vif.request_driver_cb.be <= trans.be;
vif.request_driver_cb.we <= trans.read_write;
vif.request_driver_cb.wdata <= trans.data;
vif.request_driver_cb.wintg <= trans.intg;
wait (vif.request_driver_cb.grant === 1'b1);
vif.wait_clks(1);
vif.request_driver_cb.request <= 'h0;
vif.request_driver_cb.addr <= 'hz;
vif.request_driver_cb.wdata <= 'hz;
vif.request_driver_cb.wintg <= 'hz;
vif.request_driver_cb.be <= 'bz;
vif.request_driver_cb.we <= 'bz;
rdata_queue.put(trans);
@ -81,6 +84,7 @@ class ibex_mem_intf_request_driver extends uvm_driver #(ibex_mem_intf_seq_item);
while(vif.rvalid !== 1'b1) vif.wait_clks(1);
if(tr.read_write == READ)
tr.data = vif.request_driver_cb.rdata;
tr.intg = vif.request_driver_cb.rintg;
seq_item_port.put_response(tr);
end
endtask : collect_response

View file

@ -59,6 +59,7 @@ class ibex_mem_intf_response_driver extends uvm_driver #(ibex_mem_intf_seq_item)
vif.response_driver_cb.rvalid <= 1'b0;
vif.response_driver_cb.grant <= 1'b0;
vif.response_driver_cb.rdata <= 'b0;
vif.response_driver_cb.rintg <= 'b0;
vif.response_driver_cb.error <= 1'b0;
endtask : reset_signals
@ -113,7 +114,8 @@ class ibex_mem_intf_response_driver extends uvm_driver #(ibex_mem_intf_seq_item)
vif.wait_clks(1);
vif.response_driver_cb.rvalid <= 1'b0;
vif.response_driver_cb.rdata <= 'x;
vif.response_driver_cb.error <= 1'b0;
vif.response_driver_cb.rintg <= 'x;
vif.response_driver_cb.error <= 'x;
rdata_queue.get(tr);
if(vif.response_driver_cb.reset) continue;
vif.wait_clks(tr.rvalid_delay);
@ -121,6 +123,7 @@ class ibex_mem_intf_response_driver extends uvm_driver #(ibex_mem_intf_seq_item)
vif.response_driver_cb.rvalid <= 1'b1;
vif.response_driver_cb.error <= tr.error;
vif.response_driver_cb.rdata <= tr.data;
vif.response_driver_cb.rintg <= tr.intg;
end
end
endtask : send_read_data

View file

@ -31,6 +31,7 @@ class ibex_mem_intf_response_seq extends uvm_sequence #(ibex_mem_intf_seq_item);
bit [ADDR_WIDTH-1:0] aligned_addr;
bit [DATA_WIDTH-1:0] rand_data;
bit [DATA_WIDTH-1:0] read_data;
bit [INTG_WIDTH-1:0] read_intg;
p_sequencer.addr_ph_port.get(item);
req = ibex_mem_intf_seq_item::type_id::create("req");
error_synch = 1'b0;
@ -38,6 +39,7 @@ class ibex_mem_intf_response_seq extends uvm_sequence #(ibex_mem_intf_seq_item);
addr == item.addr;
read_write == item.read_write;
data == item.data;
intg == item.intg;
be == item.be;
rvalid_delay dist {
min_rvalid_delay :/ 5,
@ -69,6 +71,8 @@ class ibex_mem_intf_response_seq extends uvm_sequence #(ibex_mem_intf_seq_item);
end
end
end
// Add correct integrity bits
{req.intg, req.data} = prim_secded_pkg::prim_secded_39_32_enc(req.data);
`uvm_info(get_full_name(), $sformatf("Response transfer:\n%0s", req.sprint()), UVM_HIGH)
start_item(req);
finish_item(req);

View file

@ -11,6 +11,7 @@ class ibex_mem_intf_seq_item extends uvm_sequence_item;
rand bit [ADDR_WIDTH-1:0] addr;
rand rw_e read_write;
rand bit [DATA_WIDTH-1:0] data;
rand bit [INTG_WIDTH-1:0] intg;
rand bit [DATA_WIDTH/8-1:0] be;
rand bit [3:0] gnt_delay;
rand bit [3:0] req_delay;
@ -22,6 +23,7 @@ class ibex_mem_intf_seq_item extends uvm_sequence_item;
`uvm_field_enum (rw_e, read_write, UVM_DEFAULT)
`uvm_field_int (be, UVM_DEFAULT)
`uvm_field_int (data, UVM_DEFAULT)
`uvm_field_int (intg, UVM_DEFAULT)
`uvm_field_int (gnt_delay, UVM_DEFAULT)
`uvm_field_int (rvalid_delay, UVM_DEFAULT)
`uvm_field_int (error, UVM_DEFAULT)

View file

@ -28,6 +28,7 @@ ${PRJ_DIR}/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_72_64_dec.sv
// 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_secded_pkg.sv
${PRJ_DIR}/vendor/lowrisc_ip/ip/prim/rtl/prim_ram_1p_pkg.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

View file

@ -77,46 +77,49 @@ module core_ibex_tb_top;
.SecureIbex (SecureIbex ),
.BranchPredictor (BranchPredictor )
) dut (
.clk_i (clk ),
.rst_ni (rst_n ),
.clk_i (clk ),
.rst_ni (rst_n ),
.test_en_i (1'b0 ),
.scan_rst_ni (1'b1 ),
.ram_cfg_i ('b0 ),
.test_en_i (1'b0 ),
.scan_rst_ni (1'b1 ),
.ram_cfg_i ('b0 ),
.hart_id_i (32'b0 ),
.boot_addr_i (32'h`BOOT_ADDR ), // align with spike boot address
.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_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_wdata_o (data_mem_vif.wdata ),
.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 ( ),
.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 )
.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

View file

@ -53,6 +53,7 @@ module top_artya7 (
.instr_rvalid_i (instr_rvalid),
.instr_addr_o (instr_addr),
.instr_rdata_i (instr_rdata),
.instr_rdata_intg_i ('0),
.instr_err_i ('b0),
.data_req_o (data_req),
@ -62,7 +63,9 @@ module top_artya7 (
.data_be_o (data_be),
.data_addr_o (data_addr),
.data_wdata_o (data_wdata),
.data_wdata_intg_o (),
.data_rdata_i (data_rdata),
.data_rdata_intg_i ('0),
.data_err_i ('b0),
.irq_software_i (1'b0),

View file

@ -195,6 +195,7 @@ module ibex_simple_system (
.instr_rvalid_i (instr_rvalid),
.instr_addr_o (instr_addr),
.instr_rdata_i (instr_rdata),
.instr_rdata_intg_i ('0),
.instr_err_i (instr_err),
.data_req_o (host_req[CoreD]),
@ -204,7 +205,9 @@ module ibex_simple_system (
.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),

View file

@ -846,7 +846,6 @@ module ibex_core import ibex_pkg::*; #(
assign rf_ecc_err_comb = 1'b0;
end
///////////////////////
// Crash dump output //
///////////////////////

View file

@ -47,6 +47,7 @@ module ibex_lockstep import ibex_pkg::*; #(
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,
@ -56,7 +57,9 @@ module ibex_lockstep import ibex_pkg::*; #(
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,
@ -156,6 +159,7 @@ module ibex_lockstep import ibex_pkg::*; #(
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];
@ -182,12 +186,16 @@ module ibex_lockstep import ibex_pkg::*; #(
// 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];
@ -199,6 +207,38 @@ module ibex_lockstep import ibex_pkg::*; #(
end
end
////////////////////////////
// Bus integrity checking //
////////////////////////////
logic bus_intg_err;
logic [1:0] instr_intg_err, data_intg_err;
logic [31:0] unused_wdata;
// Checks on incoming data
prim_secded_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_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_39_32_enc u_data_gen (
.data_i (data_wdata_i),
.data_o ({data_wdata_intg_o, unused_wdata})
);
///////////////////
// Output delays //
///////////////////
@ -400,7 +440,7 @@ module ibex_lockstep import ibex_pkg::*; #(
logic outputs_mismatch;
assign outputs_mismatch = enable_cmp_q & (shadow_outputs_q != core_outputs_q[0]);
assign alert_major_o = outputs_mismatch | shadow_alert_major;
assign alert_major_o = outputs_mismatch | shadow_alert_major | bus_intg_err;
assign alert_minor_o = shadow_alert_minor;
endmodule

View file

@ -51,6 +51,7 @@ module ibex_top import ibex_pkg::*; #(
input logic instr_rvalid_i,
output logic [31:0] instr_addr_o,
input logic [31:0] instr_rdata_i,
input logic [6:0] instr_rdata_intg_i,
input logic instr_err_i,
// Data memory interface
@ -61,7 +62,9 @@ module ibex_top import ibex_pkg::*; #(
output logic [3:0] data_be_o,
output logic [31:0] data_addr_o,
output logic [31:0] data_wdata_o,
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,
// Interrupt inputs
@ -427,6 +430,7 @@ module ibex_top import ibex_pkg::*; #(
instr_rvalid_i,
instr_addr_o,
instr_rdata_i,
instr_rdata_intg_i,
instr_err_i,
data_req_o,
data_gnt_i,
@ -436,6 +440,7 @@ module ibex_top import ibex_pkg::*; #(
data_addr_o,
data_wdata_o,
data_rdata_i,
data_rdata_intg_i,
data_err_i,
dummy_instr_id,
rf_raddr_a,
@ -475,6 +480,7 @@ module ibex_top import ibex_pkg::*; #(
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;
@ -484,7 +490,9 @@ module ibex_top import ibex_pkg::*; #(
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;
@ -526,6 +534,7 @@ module ibex_top import ibex_pkg::*; #(
instr_rvalid_i,
instr_addr_o,
instr_rdata_i,
instr_rdata_intg_i,
instr_err_i,
data_req_o,
data_gnt_i,
@ -535,6 +544,7 @@ module ibex_top import ibex_pkg::*; #(
data_addr_o,
data_wdata_o,
data_rdata_i,
data_rdata_intg_i,
data_err_i,
dummy_instr_id,
rf_raddr_a,
@ -572,6 +582,7 @@ module ibex_top import ibex_pkg::*; #(
instr_rvalid_local,
instr_addr_local,
instr_rdata_local,
instr_rdata_intg_local,
instr_err_local,
data_req_local,
data_gnt_local,
@ -581,6 +592,7 @@ module ibex_top import ibex_pkg::*; #(
data_addr_local,
data_wdata_local,
data_rdata_local,
data_rdata_intg_local,
data_err_local,
dummy_instr_id_local,
rf_raddr_a_local,
@ -659,68 +671,76 @@ module ibex_top import ibex_pkg::*; #(
.DmHaltAddr ( DmHaltAddr ),
.DmExceptionAddr ( DmExceptionAddr )
) u_ibex_lockstep (
.clk_i (clk),
.rst_ni (rst_ni),
.clk_i (clk),
.rst_ni (rst_ni),
.hart_id_i (hart_id_local),
.boot_addr_i (boot_addr_local),
.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_err_i (instr_err_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_rdata_i (data_rdata_local),
.data_err_i (data_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),
.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_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),
.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),
.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),
.debug_req_i (debug_req_local),
.crash_dump_i (crash_dump_local),
.fetch_enable_i (fetch_enable_local),
.alert_minor_o (lockstep_alert_minor_local),
.alert_major_o (lockstep_alert_major_local),
.core_busy_i (core_busy_local),
.test_en_i (test_en_i),
.scan_rst_ni (scan_rst_ni)
.fetch_enable_i (fetch_enable_local),
.alert_minor_o (lockstep_alert_minor_local),
.alert_major_o (lockstep_alert_major_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)
@ -734,8 +754,10 @@ module ibex_top import ibex_pkg::*; #(
end else begin : gen_no_lockstep
assign lockstep_alert_major = 1'b0;
assign lockstep_alert_minor = 1'b0;
logic unused_scan;
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_o = core_alert_major | lockstep_alert_major;

View file

@ -47,6 +47,7 @@ module ibex_top_tracing import ibex_pkg::*; #(
input logic instr_rvalid_i,
output logic [31:0] instr_addr_o,
input logic [31:0] instr_rdata_i,
input logic [6:0] instr_rdata_intg_i,
input logic instr_err_i,
// Data memory interface
@ -57,7 +58,9 @@ module ibex_top_tracing import ibex_pkg::*; #(
output logic [3:0] data_be_o,
output logic [31:0] data_addr_o,
output logic [31:0] data_wdata_o,
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,
// Interrupt inputs
@ -144,6 +147,7 @@ module ibex_top_tracing import ibex_pkg::*; #(
.instr_rvalid_i,
.instr_addr_o,
.instr_rdata_i,
.instr_rdata_intg_i,
.instr_err_i,
.data_req_o,
@ -153,7 +157,9 @@ module ibex_top_tracing import ibex_pkg::*; #(
.data_be_o,
.data_addr_o,
.data_wdata_o,
.data_wdata_intg_o,
.data_rdata_i,
.data_rdata_intg_i,
.data_err_i,
.irq_software_i,