Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .github/scripts/run_regression_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,17 @@ run_regression_test(){
COMMON_PARAMS="-set lockstep_enable=1 -set lockstep_regfile_enable=1 ${COMMON_PARAMS}"
fi

# ICCM_ADDR_XOR may not be set
set +u
if [[ -z "${ICCM_ADDR_XOR}" ]]; then
ICCM_ADDR_XOR="0"
fi
set -u

if [[ "${ICCM_ADDR_XOR}" == "1" ]]; then
COMMON_PARAMS="-set iccm_addr_xor=1 ${COMMON_PARAMS}"
fi

COMMON_PARAMS="-set=icache_waypack=${ICACHE_WAYPACK} ${COMMON_PARAMS}"

if [[ "${BUS}" == "axi" ]]; then
Expand Down
59 changes: 59 additions & 0 deletions .github/workflows/test-regression-dcls.yml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,65 @@ jobs:
export TB_EXTRA_ARGS="${{ matrix.tb_extra_args }}"
.github/scripts/run_regression_test.sh $TEST_PATH ${{ matrix.bus }} ${{ matrix.test}} ${{ matrix.coverage }} ${{ matrix.priv }} 0

regression-tests-iccm-addr-xor:
name: Regression tests (DCLS + ICCM address-XOR)
runs-on: ubuntu-latest
container: ghcr.io/antmicro/cores-veer-el2:20250411084921
strategy:
matrix:
bus: ["axi", "ahb"]
# ICCM-exercising subset, built with DCLS + RV_ICCM_ADDR_XOR enabled. The XOR feature
# only affects the ICCM data path and is privilege-independent, so a single priv level
# of these ICCM/ECC tests is enough to exercise it without re-running the full matrix.
test: ["hello_world_iccm", "hello_world", "ecc"]
coverage: ["all"]
priv: ["0"]
tb_extra_args: [""]
env:
DEBIAN_FRONTEND: "noninteractive"
CCACHE_DIR: "/opt/regression/.cache/"
DCLS_ENABLE: "1"
ICCM_ADDR_XOR: "1"

steps:
- name: Install utils
run: |
echo "deb http://archive.ubuntu.com/ubuntu/ noble main universe" | sudo tee -a /etc/apt/sources.list > /dev/null
echo "debconf debconf/frontend select Noninteractive" | sudo debconf-set-selections
sudo apt -qqy update && sudo apt -qqy --no-install-recommends install \
git python3 python3-pip build-essential ninja-build ccache \
gcc-riscv64-unknown-elf
pip3 install meson --break-system-packages

- name: Setup repository
uses: actions/checkout@v4
with:
submodules: recursive

- name: Install coverage dependencies
run: |
python3 -m venv .venv
source .venv/bin/activate
pip install -r .github/scripts/requirements-coverage.txt
echo "PATH=$PATH" >> $GITHUB_ENV

- name: Setup environment
run: |
echo "/opt/verilator/bin" >> $GITHUB_PATH
RV_ROOT=`pwd`
echo "RV_ROOT=$RV_ROOT" >> $GITHUB_ENV
PYTHONUNBUFFERED=1
echo "PYTHONUNBUFFERED=$PYTHONUNBUFFERED" >> $GITHUB_ENV
TEST_PATH=$RV_ROOT/test_results
echo "TEST_PATH=$TEST_PATH" >> $GITHUB_ENV

- name: Run tests
run: |
export PATH=/opt/verilator/bin:$PATH
export RV_ROOT=`pwd`
export TB_EXTRA_ARGS="${{ matrix.tb_extra_args }}"
.github/scripts/run_regression_test.sh $TEST_PATH ${{ matrix.bus }} ${{ matrix.test}} ${{ matrix.coverage }} ${{ matrix.priv }} 0

custom-regression-tests:
name: Custom regression tests
if: inputs.run_custom
Expand Down
8 changes: 8 additions & 0 deletions configs/veer.config
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,9 @@ Parameters that can be set by the end user:
Fast interrupt redirect mechanism
-set=iccm_enable = { 0, 1 }
whether or not ICCM is enabled
-set=iccm_addr_xor = { 0, 1 }
FI hardening: XOR the (replicated) ICCM word address into the stored data so a
misdirected access is caught by ECC and a garbled instruction
-set=icache_enable = { 0, 1 }
whether or not icache is enabled
-set=icache_waypack = { 0, 1 }
Expand Down Expand Up @@ -249,6 +252,7 @@ my $icache_ecc;
my $iccm_region;
my $iccm_offset;
my $iccm_size;
my $iccm_addr_xor;
my $icache_size;
my $pic_2cycle;
my $pic_region;
Expand Down Expand Up @@ -317,6 +321,7 @@ $top_align_iccm = 1;
$iccm_offset="0xe000000"; #0x380*256*1024
$iccm_size=64;
$iccm_num_banks=4;
$iccm_addr_xor=0;
$iccm_ecc_width=7;
$icache_enable=1;
$icache_waypack=1;
Expand Down Expand Up @@ -377,6 +382,7 @@ GetOptions(
"iccm_region=s" => \$iccm_region,
"iccm_offset=s" => \$iccm_offset,
"iccm_size=s" => \$iccm_size,
"iccm_addr_xor=s" => \$iccm_addr_xor,
"lsu_stbuf_depth" => \$lsu_stbuf_depth,
"lsu_num_nbload" => \$lsu_num_nbload,
"pic_2cycle=s" => \$pic_2cycle,
Expand Down Expand Up @@ -973,6 +979,7 @@ our %config = (#{{{
"iccm_offset" => "$iccm_offset", # Design Parm, Overridable
"iccm_size" => "$iccm_size", # Design Parm, Overridable
"iccm_num_banks" => "$iccm_num_banks", # Design Parm, Overridable
"iccm_addr_xor" => "$iccm_addr_xor", # Design Parm, Overridable
"iccm_bank_bits" => 'derived',
"iccm_index_bits" => 'derived',
"iccm_rows" => 'derived',
Expand Down Expand Up @@ -2026,6 +2033,7 @@ $c=$config{core}{div_new}; if ($c==0 && !grep(/div_new=1/, @sets))
# not needed
#$c=$config{core}{div_bit}; if ($c==0 && !grep(/div_bit=1/, @sets)) { delete $config{"core"}{"div_bit"}; }
$c=$config{iccm}{iccm_enable}; if ($c==0 && !grep(/iccm_enable=1/, @sets)) { delete $config{"iccm"}{"iccm_enable"}; }
$c=$config{iccm}{iccm_addr_xor}; if ($c==0 && !grep(/iccm_addr_xor=1/, @sets)) { delete $config{"iccm"}{"iccm_addr_xor"}; }
$c=$config{btb}{btb_enable}; if ($c==0 && !grep(/btb_enable=1/, @sets)) { delete $config{"btb"}{"btb_enable"}; }
$c=$config{dccm}{dccm_enable}; if ($c==0 && !grep(/dccm_enable=1/, @sets)) { delete $config{"dccm"}{"dccm_enable"}; }
$c=$config{icache}{icache_waypack}; if ($c==0 && !grep(/icache_waypack=1/, @sets)) { delete $config{"icache"}{"icache_waypack"}; }
Expand Down
1 change: 0 additions & 1 deletion design/el2_lockstep_pkg.sv
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,6 @@ package el2_lockstep_pkg;
logic mpc_reset_run_req;
logic [pt.DCCM_FDATA_WIDTH-1:0] dccm_rd_data_lo;
logic [pt.DCCM_FDATA_WIDTH-1:0] dccm_rd_data_hi;
logic [63:0] iccm_rd_data;
logic [77:0] iccm_rd_data_ecc;
logic [63:0] ic_rd_data;
logic [70:0] ic_debug_rd_data;
Expand Down
3 changes: 0 additions & 3 deletions design/el2_mem.sv
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ import el2_pkg::*;
input logic [2:0] iccm_wr_size,
input logic [77:0] iccm_wr_data,

output logic [63:0] iccm_rd_data,
output logic [77:0] iccm_rd_data_ecc,

// Icache and Itag Ports
Expand Down Expand Up @@ -169,12 +168,10 @@ if (pt.ICCM_ENABLE) begin : iccm
el2_ifu_iccm_mem #(.pt(pt)) iccm (.*,
.clk_override(icm_clk_override),
.iccm_rw_addr(iccm_rw_addr[pt.ICCM_BITS-1:1]),
.iccm_rd_data(iccm_rd_data[63:0]),
.iccm_mem_export(mem_export_local.veer_iccm)
);
end
else begin
assign iccm_rd_data = '0 ;
assign iccm_rd_data_ecc = '0 ;
assign mem_export_local.iccm_addr_bank = '0;
assign mem_export_local.iccm_bank_wr_data = '0;
Expand Down
1 change: 0 additions & 1 deletion design/el2_veer.sv
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,6 @@ import el2_pkg::*;
output logic iccm_buf_correct_ecc,
output logic iccm_correction_state,

input logic [63:0] iccm_rd_data,
input logic [77:0] iccm_rd_data_ecc,

// ICache , ITAG ports
Expand Down
3 changes: 0 additions & 3 deletions design/el2_veer_lockstep.sv
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ module el2_veer_lockstep
input logic iccm_buf_correct_ecc,
input logic iccm_correction_state,

input logic [63:0] iccm_rd_data,
input logic [77:0] iccm_rd_data_ecc,

// ICache , ITAG ports
Expand Down Expand Up @@ -416,7 +415,6 @@ module el2_veer_lockstep
assign main_core_inputs.mpc_reset_run_req = mpc_reset_run_req;
assign main_core_inputs.dccm_rd_data_lo = dccm_rd_data_lo;
assign main_core_inputs.dccm_rd_data_hi = dccm_rd_data_hi;
assign main_core_inputs.iccm_rd_data = iccm_rd_data;
assign main_core_inputs.iccm_rd_data_ecc = iccm_rd_data_ecc;
assign main_core_inputs.ic_rd_data = ic_rd_data;
assign main_core_inputs.ic_debug_rd_data = ic_debug_rd_data;
Expand Down Expand Up @@ -848,7 +846,6 @@ module el2_veer_lockstep
.iccm_wr_data(shadow_core_outputs.iccm_wr_data),
.iccm_buf_correct_ecc(shadow_core_outputs.iccm_buf_correct_ecc),
.iccm_correction_state(shadow_core_outputs.iccm_correction_state),
.iccm_rd_data(shadow_core_inputs.iccm_rd_data),
.iccm_rd_data_ecc(shadow_core_inputs.iccm_rd_data_ecc),

.ic_rw_addr(shadow_core_outputs.ic_rw_addr),
Expand Down
1 change: 0 additions & 1 deletion design/el2_veer_wrapper.sv
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,6 @@ import el2_pkg::*;
logic iccm_buf_correct_ecc;
logic iccm_correction_state;

logic [63:0] iccm_rd_data;
logic [77:0] iccm_rd_data_ecc;

logic core_rst_l; // Core reset including rst_l and dbg_rst_l
Expand Down
1 change: 0 additions & 1 deletion design/ifu/el2_ifu.sv
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,6 @@ import el2_pkg::*;
output logic [77:0] iccm_wr_data, // ICCM write data.
output logic [2:0] iccm_wr_size, // ICCM write location within DW.

input logic [63:0] iccm_rd_data, // Data read from ICCM.
input logic [77:0] iccm_rd_data_ecc, // Data + ECC read from ICCM.

// ICCM ECC status
Expand Down
6 changes: 0 additions & 6 deletions design/ifu/el2_ifu_iccm_mem.sv
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ import el2_pkg::*;

el2_mem_if.veer_iccm iccm_mem_export, // RAM repositioned in testbench and connected by this interface

output logic [63:0] iccm_rd_data, // ICCM read data
output logic [77:0] iccm_rd_data_ecc, // ICCM read ecc
// Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core.
/*pragma coverage off*/
Expand All @@ -60,8 +59,6 @@ import el2_pkg::*;
logic [pt.ICCM_BITS-1:1] addr_bank_inc;
logic [pt.ICCM_BANK_HI : 2] iccm_rd_addr_hi_q;
logic [pt.ICCM_BANK_HI : 1] iccm_rd_addr_lo_q;
logic [63:0] iccm_rd_data_pre;
logic [63:0] iccm_data;
logic [1:0] addr_incr;
logic [pt.ICCM_NUM_BANKS-1:0] [38:0] iccm_bank_wr_data_vec;

Expand Down Expand Up @@ -217,9 +214,6 @@ import el2_pkg::*;
rvdffs #(pt.ICCM_BANK_HI) rd_addr_lo_ff (.*, .clk(active_clk), .din(iccm_rw_addr [pt.ICCM_BANK_HI:1]), .dout(iccm_rd_addr_lo_q[pt.ICCM_BANK_HI:1]), .en(1'b1)); // bit 0 of address is always 0
rvdffs #(pt.ICCM_BANK_BITS) rd_addr_hi_ff (.*, .clk(active_clk), .din(addr_bank_inc[pt.ICCM_BANK_HI:2]), .dout(iccm_rd_addr_hi_q[pt.ICCM_BANK_HI:2]), .en(1'b1));

assign iccm_rd_data_pre[63:0] = {iccm_bank_dout_fn[iccm_rd_addr_hi_q][31:0], iccm_bank_dout_fn[iccm_rd_addr_lo_q[pt.ICCM_BANK_HI:2]][31:0]};
assign iccm_data[63:0] = 64'({16'b0, (iccm_rd_data_pre[63:0] >> (16*iccm_rd_addr_lo_q[1]))});
assign iccm_rd_data[63:0] = {iccm_data[63:0]};
assign iccm_rd_data_ecc[77:0] = {iccm_bank_dout_fn[iccm_rd_addr_hi_q][38:0], iccm_bank_dout_fn[iccm_rd_addr_lo_q[pt.ICCM_BANK_HI:2]][38:0]};

endmodule // el2_ifu_iccm_mem
53 changes: 49 additions & 4 deletions design/ifu/el2_ifu_mem_ctl.sv
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,6 @@ import el2_pkg::*;
output logic [77:0] iccm_wr_data, // ICCM write data.
output logic [2:0] iccm_wr_size, // ICCM write location within DW.

input logic [63:0] iccm_rd_data, // Data read from ICCM.
input logic [77:0] iccm_rd_data_ecc, // Data + ECC read from ICCM.
input logic [1:0] ifu_fetch_val,
// IFU control signals
Expand Down Expand Up @@ -447,6 +446,14 @@ import el2_pkg::*;
logic ifu_bus_rvalid_unq;
logic bus_cmd_beat_en;

// ICCM address-XOR data masks used for the XOR infection feature.
logic [31:0] iccm_wr_xor_mask_w0, iccm_wr_xor_mask_w1;
logic [31:0] iccm_rd_xor_mask_w0, iccm_rd_xor_mask_w1;

// iccm_rd_data is equivalent to iccm_rd_data_ecc except:
// - the ECC bits are stripped
// - half-word shifted to match the instruction request alignment
logic [63:0] iccm_rd_data;

// ---- Clock gating section -----
// c1 clock enables
Expand Down Expand Up @@ -1266,8 +1273,18 @@ ifc_dma_access_ok_prev,dma_iccm_req_f})
.din(dma_mem_wdata[63:32]),
.ecc_out(dma_mem_ecc[13:7]));

assign iccm_wr_data[77:0] = (iccm_correct_ecc & ~(ifc_dma_access_q_ok & dma_iccm_req)) ? {iccm_ecc_corr_data_ff[38:0], iccm_ecc_corr_data_ff[38:0]} :
{dma_mem_ecc[13:7],dma_mem_wdata[63:32], dma_mem_ecc[6:0],dma_mem_wdata[31:0]};
// ICCM address-XOR infection. The (replicated) word address is XORed
// into the stored DATA bits; the ECC stays the plain encode(original data). On
// read the address is removed before ECC decode and before the instruction is
// formed. A read/write address mismatch, the address is not correctly removed, i.e.,
// an ECC error is triggered as well as garbles the instruction itself.
logic [77:0] iccm_wr_data_pre;
assign iccm_wr_data_pre[77:0] = (iccm_correct_ecc & ~(ifc_dma_access_q_ok & dma_iccm_req)) ? {iccm_ecc_corr_data_ff[38:0], iccm_ecc_corr_data_ff[38:0]} :
{dma_mem_ecc[13:7],dma_mem_wdata[63:32], dma_mem_ecc[6:0],dma_mem_wdata[31:0]};
assign iccm_wr_data[31:0] = iccm_wr_data_pre[31:0] ^ iccm_wr_xor_mask_w0[31:0]; // word0 data ^ addr mask
assign iccm_wr_data[38:32] = iccm_wr_data_pre[38:32]; // word0 ecc (plain)
assign iccm_wr_data[70:39] = iccm_wr_data_pre[70:39] ^ iccm_wr_xor_mask_w1[31:0]; // word1 data ^ addr mask
assign iccm_wr_data[77:71] = iccm_wr_data_pre[77:71]; // word1 ecc (plain)

assign iccm_dma_rdata_1_muxed[31:0] = dma_mem_addr_ff[2] ? iccm_corrected_data[0][31:0] : iccm_corrected_data[1][31:0] ;
assign iccm_dma_rdata_in[63:0] = iccm_dma_ecc_error_in ? {2{dma_mem_addr[31:0]}} : {iccm_dma_rdata_1_muxed[31:0], iccm_corrected_data[0]};
Expand All @@ -1294,6 +1311,27 @@ ifc_dma_access_ok_prev,dma_iccm_req_f})
assign iccm_dma_rd_ecc_single_err = iccm_dma_sb_error;
assign iccm_dma_rd_ecc_double_err = iccm_dma_rvalid && iccm_dma_ecc_error;

// ICCM address-XOR mask generation.
`ifdef RV_ICCM_ADDR_XOR
logic [pt.ICCM_BITS-1:2] iccm_wr_wa_w0, iccm_wr_wa_w1, iccm_rd_wa_w0, iccm_rd_wa_w1;
// Write addresses.
assign iccm_wr_wa_w0 = {iccm_rw_addr[pt.ICCM_BITS-1:3], 1'b0};
assign iccm_wr_wa_w1 = {iccm_rw_addr[pt.ICCM_BITS-1:3], 1'b1};
// Read addresses.
assign iccm_rd_wa_w0 = iccm_rw_addr_f[pt.ICCM_BITS-1:2];
assign iccm_rd_wa_w1 = iccm_rw_addr_f[pt.ICCM_BITS-1:2] + 1'b1;
// Mask assembly.
assign iccm_wr_xor_mask_w0 = 32'({iccm_wr_wa_w0, iccm_wr_wa_w0});
assign iccm_wr_xor_mask_w1 = 32'({iccm_wr_wa_w1, iccm_wr_wa_w1});
assign iccm_rd_xor_mask_w0 = 32'({iccm_rd_wa_w0, iccm_rd_wa_w0});
assign iccm_rd_xor_mask_w1 = 32'({iccm_rd_wa_w1, iccm_rd_wa_w1});
`else
assign iccm_wr_xor_mask_w0 = '0;
assign iccm_wr_xor_mask_w1 = '0;
assign iccm_rd_xor_mask_w0 = '0;
assign iccm_rd_xor_mask_w1 = '0;
`endif


/////////////////////////////////////////////////////////////////////////////////////
// ECC checking logic for ICCM data. //
Expand All @@ -1304,7 +1342,14 @@ ifc_dma_access_ok_prev,dma_iccm_req_f})
assign ic_fetch_val_int_f[3:0] = {2'b00 , ic_fetch_val_f[1:0] } ;
assign ic_fetch_val_shift_right[3:0] = {ic_fetch_val_int_f << ifu_fetch_addr_int_f[1] } ;

assign iccm_rdmux_data[77:0] = iccm_rd_data_ecc[77:0];
// ICCM address-XOR: remove the address from the DATA bits before ECC decode, using the
// registered read address.
assign iccm_rdmux_data[31:0] = iccm_rd_data_ecc[31:0] ^ iccm_rd_xor_mask_w0[31:0]; // word0 data de-XOR
assign iccm_rdmux_data[38:32] = iccm_rd_data_ecc[38:32]; // word0 ecc (plain)
assign iccm_rdmux_data[70:39] = iccm_rd_data_ecc[70:39] ^ iccm_rd_xor_mask_w1[31:0]; // word1 data de-XOR
assign iccm_rdmux_data[77:71] = iccm_rd_data_ecc[77:71]; // word1 ecc (plain)
// Remove the ECC and align by the fetch halfword.
assign iccm_rd_data[63:0] = 64'({iccm_rdmux_data[70:39], iccm_rdmux_data[31:0]} >> (16*ifu_fetch_addr_int_f[1]));
for (genvar i=0; i < 2 ; i++) begin : ICCM_ECC_CHECK
assign iccm_ecc_word_enable[i] = ((|ic_fetch_val_shift_right[(2*i+1):(2*i)] & ~exu_flush_final & sel_iccm_data) | iccm_dma_rvalid_in) & ~dec_tlu_core_ecc_disable;
rvecc_decode ecc_decode (
Expand Down
3 changes: 0 additions & 3 deletions docs/source/dual-core-lock-step.md
Original file line number Diff line number Diff line change
Expand Up @@ -904,9 +904,6 @@ Refer to {ref}`tab-shadow-core-tracked-signals` for list of ports routed to the
* - iccm_ecc_single_error
-
-
* - iccm_rd_data
-
-
* - iccm_rd_data_ecc
-
-
Expand Down
13 changes: 13 additions & 0 deletions docs/source/error-protection.md
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,19 @@ General comments:
[^fn-error-protection-6]: For load/store accesses, the corrected data is written back to the DCCM and counted only if the load/store instruction retires (i.e., access is non-speculative and has no exception).
[^fn-error-protection-7]: For non-speculative accesses only.

## ICCM Address Infection

Optionally (build argument `iccm_addr_xor`), the ICCM write word address is XORed into the data that gets stored into the ICCM.
On a read, the ICCM read word address is XORed on the fetched data from ICCM.
If both addresses match, the plain data is retrieved.

If the read address does not match the write address, the address does not cancel.
As after the read XOR the ECC check happens, the mismatch is detected by an ECC error.
In addition, as the data is garbled, the instruction is corrupted as well.

Note that the XOR happens within the [Dual-Core Lock-Step](dual-core-lock-step.md) domain.
Firmware or backdoor loaders that write the ICCM directly must apply the same address XOR.

## Core Error Counter/Threshold Registers

A summary of platform-specific core error counter/threshold control/status registers in CSR space:
Expand Down
Loading
Loading