mirror of
https://github.com/lowRISC/ibex.git
synced 2025-04-24 05:47:36 -04:00
Update lowrisc_ip to lowRISC/opentitan@3a672eb36
This commit also adds memory manipulation package in ibex repository. Update code from upstream repository https://github.com/lowRISC/opentitan to revision 3a672eb36aee5942d0912a15d15055b1d21c33d6 * [mubi] Fix path in auto-gen header (Rupert Swarbrick) * [dv] Allow using memutil_dpi_scrambled even without prim_ram_1p_scr (Rupert Swarbrick) * [prim] Fix prim_ram_1p_scr Dependencies (Canberk Topal) * [dv/clk_rst_if] Split clk_rst_if jitter to 2 different values (Eitan Shapira) * [dv] Add external hjson path support in ralgen (Srikrishna Iyer) * [dv] Add sub RAL block creation knobs (Srikrishna Iyer) * [pwrmgr] Make rom_ctrl check signals multi-bit (Timothy Chen) * [dv/alert_handler] Randomize mubi input (Cindy Chen) * [flash_ctrl] Fix bank erase / info partition issue (Timothy Chen) * [ci] Fix CI failure (Weicai Yang) * [Cleanup] Remove lc_tx_e type and replace it with lc_tx_t (Weicai Yang) * [aes] Add gtech synthesis setup (Michael Schaffner) * [mubi] Enhance mubi_sync with stability check (Timothy Chen) * [prim] Fix prim_packer_fifo when ClearOnRead is false (Rupert Swarbrick) * [cleanup] Remove mubi4_e and replace it with mubi4_t (Weicai Yang) * [dv] Fix shape calculations for replicated ECC (Rupert Swarbrick) * [dv/alert] Support LPG in alert_sender/receiver pair (Cindy Chen) * [dv] Add a ReadWithIntegrity method to Ecc32MemArea (Rupert Swarbrick) * [dv] Simplify Ecc32MemArea read/write functions (Rupert Swarbrick) * [prim] Add option to not clear the packer FIFO upon read (Pirmin Vogel) * [dv] Change intg_err test from V3 to V2S (Weicai Yang) * [util] Delete generate_prim_mubi.py (Rupert Swarbrick) * [dv] Slightly generalise run_stress_all_with_rand_reset_vseq (Rupert Swarbrick) * [fpv] Fix some assumptions in prim_count (Cindy Chen) * [prim] quick path to prim_count assertion (Timothy Chen) * [dv] Support Multiple EDN Interfaces in OpenTitan (Canberk Topal) * [prim] Add xoshiro256pp primitive. (Vladimir Rozic) * [dv/prim_alert] Fix async fatal alert regression error (Cindy Chen) * [prim] Add missing include to prim_xilinx_pad_wrapper (Rupert Swarbrick) * [prim] Add missing include to prim_mubi_dec* (Rupert Swarbrick) * [dv/prim_alert_receiver] Fix assertion that consumes large mem (Cindy Chen) * [prim] Remove extra semicolon (Weicai Yang) * [chip,dv] Refactor CSR exclusion method (Srikrishna Iyer) * [top, all] update connects for mubi (Timothy Chen) * [flash_ctrl] Add plain text integrity in flash (Timothy Chen) * [prim] Add time-out functionality to prim_clock_meas (Timothy Chen) * [prim] Fix DC sythesis error (Weicai Yang) * [fpv] Fix regression failures (Cindy Chen) * [dv/ralgen] Update `dv_base_names` input from a string to a list (Cindy Chen) * [dv/ralgen] Update the `dv-base-prefix` optional input (Cindy Chen) * [doc] Add D2S and V2S checklist items to all checklists (Michael Schaffner) * [dv] Test security countermeasures (Weicai Yang) * [dv] Fix ASSERT_INIT race condition (Weicai Yang) * [syn/aes/otbn] Minor fixes to fix block level synthesis (Michael Schaffner) * [all] updated assert rtl ifdef (Timothy Chen) * [dv] Update TL intg testplan (Weicai Yang) * [prim] Add prim_fifo_async_sram_adapter to FPV list (Eunchan Kim) * [spi_device] Upload Cmd/Addr FIFO status revision (Eunchan Kim) * [dvsim] Modify resolve_branch to handle branch names with forward slash. (Todd Broch) * [prim_clock_inv] Add option to disable FPGA BUFG (Michael Schaffner) * [ralgen] Be more explicit which tool is called (Philipp Wagner) * [prim] Tweak prim_sync_reqack_data assertion so it can be disabled (Rupert Swarbrick) * [verible] Rename rule file (Philipp Wagner) * [dv/base_monitor] Cleaned up base monitor (Rasmus Madsen) * [fpv] prim_counter_fpv (Cindy Chen) * [dv/shadow_reg] Cross shadow reg error sequence with csr rw (Cindy Chen) * [dv] Fix scb multi-ral (Weicai Yang) * [dvsim] Enabling glob-style patterns for -i switch (Srikrishna Iyer) * [dv] Split sec_cm_testplan into multiple testplans (Weicai Yang) * [dv/dsim] Remove dsim's system_lib from library path (Guillermo Maturana) * [prim_packer] Resolve width mismatch (Philipp Wagner) * [prim] Fix lint error in prim_util_memload (Philipp Wagner) * [prim] Minor fix to make conn checks easy (Srikrishna Iyer) * [fpv] prim_secded FPV testbench updates bind file naming (Cindy Chen) * [dv_macros.svh] minor cleanup (Srikrishna Iyer) * [dv,xcelium] minor cleanup (Srikrishna Iyer) * [dv/shadowed_reset] Add a shadowed_rst_n interface (Cindy Chen) * [fpv] Update FPV file naming (Cindy Chen) * [top] Convert to mubi usage in some areas (Timothy Chen) * [entropy_src] mubi updates (Timothy Chen) * [prim] Add test for mubi invalid (Timothy Chen) * [prim_double_lfsr] Add duplicated LFSR primitive (Michael Schaffner) * [dv] Fix shadow reg backdoor path and enable csr_reset sequence (Weicai Yang) * [prim] Fix unused net (Timothy Chen) * [dv, clk_rst_if] Improve jitter and add scaling (Srikrishna Iyer) * [prim] Anchor buffers around register flip flops (Timothy Chen) * [alert_handler/top] Lint fixes and lc_tx_t to mubi4_t conversions (Michael Schaffner) * [prim_mubi] Replace true/false_value() functions with parameter (Michael Schaffner) * [dv/dsim] Get dsim to work at full chip (Guillermo Maturana) * [prim] Fixes for prim_count (Timothy Chen) * [top] Add various anchor points to modules (Timothy Chen) * [dv/pwrmgr] Add wakeup test sequence (Guillermo Maturana) * [reggen] Add mubi support into hjson (Timothy Chen) * [dv/shadow_reg] Fix aes shadow reg failure (Cindy Chen) * [dv/cdc] CDC simulation model (Udi Jonnalagadda) * [prim_lfsr/lint] Add temporary waiver for LOOP_VAR_OP lint error (Michael Schaffner) * [prim_clock_buf] Add lint waiver for unused parameter (Michael Schaffner) * [dvsim] Correctly set self_dir for included Hjson files (Philipp Wagner) * [util] Add tooling support for V2S milestone (Srikrishna Iyer) * [prim_mubi] Add decoder module similar to prim_lc_dec (Michael Schaffner) * [prim_mubi] Add mubi sender and sync primitives (Michael Schaffner) * [prim_mubi_pkg] Switch to True/False terminology (Michael Schaffner) * [prim] Minor work-around for xcelium (Timothy Chen) Signed-off-by: Canberk Topal <ctopal@lowrisc.org>
This commit is contained in:
parent
1bbe27effe
commit
53b1732b19
187 changed files with 5467 additions and 1183 deletions
2
vendor/lowrisc_ip.lock.hjson
vendored
2
vendor/lowrisc_ip.lock.hjson
vendored
|
@ -9,6 +9,6 @@
|
|||
upstream:
|
||||
{
|
||||
url: https://github.com/lowRISC/opentitan
|
||||
rev: ad629e3e6e70c5eaa3c2dd68457b0a020448b35f
|
||||
rev: 3a672eb36aee5942d0912a15d15055b1d21c33d6
|
||||
}
|
||||
}
|
||||
|
|
1
vendor/lowrisc_ip.vendor.hjson
vendored
1
vendor/lowrisc_ip.vendor.hjson
vendored
|
@ -15,6 +15,7 @@
|
|||
{from: "hw/dv/sv/csr_utils", to: "dv/sv/csr_utils"},
|
||||
{from: "hw/dv/sv/dv_base_reg", to: "dv/sv/dv_base_reg"},
|
||||
{from: "hw/dv/sv/mem_model", to: "dv/sv/mem_model"},
|
||||
{from: "hw/dv/sv/mem_bkdr_util", to: "dv/sv/mem_bkdr_util"},
|
||||
{from: "hw/dv/sv/str_utils", to: "dv/sv/str_utils"},
|
||||
|
||||
// We apply a patch to fix the bus_params_pkg core file name when
|
||||
|
|
185
vendor/lowrisc_ip/dv/sv/common_ifs/clk_rst_if.sv
vendored
185
vendor/lowrisc_ip/dv/sv/common_ifs/clk_rst_if.sv
vendored
|
@ -26,23 +26,75 @@ interface clk_rst_if #(
|
|||
import uvm_pkg::*;
|
||||
`endif
|
||||
|
||||
bit drive_clk; // enable clk generation
|
||||
logic o_clk; // output clk
|
||||
// Enables clock to be generated and driven by this interface.
|
||||
bit drive_clk;
|
||||
|
||||
bit drive_rst_n; // enable rst_n generation
|
||||
logic o_rst_n; // output rst_n
|
||||
// The internal output clock value.
|
||||
logic o_clk;
|
||||
|
||||
// clk params
|
||||
bit clk_gate = 1'b0; // clk gate signal
|
||||
int clk_period_ps = 20_000; // 50MHz default
|
||||
real clk_freq_mhz = 50; // 50MHz default
|
||||
int duty_cycle = 50; // 50% default
|
||||
int max_jitter_ps = 1000; // 1ns default
|
||||
bit recompute = 1'b1; // compute half periods when period/freq/duty are changed
|
||||
int clk_hi_ps; // half period hi in ps
|
||||
int clk_lo_ps; // half period lo in ps
|
||||
int jitter_chance_pc = 0; // jitter chance in percentage on clock edge - disabled by default
|
||||
bit sole_clock = 1'b0; // if true, this is the only clock in the system
|
||||
// Enables the rst_n to be generated and driven by this interface.
|
||||
bit drive_rst_n;
|
||||
|
||||
// The internal output reset value.
|
||||
logic o_rst_n;
|
||||
|
||||
// Applies clock gating.
|
||||
bit clk_gate = 1'b0;
|
||||
|
||||
// The nominal (chosen) frequency (as period in ps) of the driven clock (50MHz by default).
|
||||
int clk_period_ps = 20_000;
|
||||
|
||||
// The variation of clock period (mimics uncalibrated clocks), to scale the nominal frequency
|
||||
// down. If set to non-zero value, the clock frequency is scaled randomly on every edge.
|
||||
int clk_freq_scaling_pc = 0;
|
||||
|
||||
// The percentage chance of freq scaled down randomly on each edge.
|
||||
int clk_freq_scaling_chance_pc = 50;
|
||||
|
||||
// Clock frequency is scaled down. This enables the frequency to be randomly scaled up as well.
|
||||
//
|
||||
// Note: If set, the randomness of the clock frequency being scaled up or down may result in a
|
||||
// bigger frequency distribution than the intended clk_freq_scaling_pc setting. For example, 50MHz
|
||||
// with 10% scaling may result in pulses that are < 45MHz and > 55MHz wide as well.
|
||||
bit clk_freq_scale_up = 1'b0;
|
||||
|
||||
// The computed clock frequency in MHz.
|
||||
real clk_freq_mhz = 50;
|
||||
|
||||
// The duty cycle of the clock period as percentage. If jitter and scaling is applied, then the
|
||||
// duty cycle will not be maintained.
|
||||
int duty_cycle = 50;
|
||||
|
||||
// Maximum jitter applied to each period of the clock - this is expected to be about 20% or less
|
||||
// than the clock period.
|
||||
// The jitter is divided to two values - plus-jitter and minus-jitter.
|
||||
// Plus jitter is the possible time can be added to the clock period, while the minus jittter is
|
||||
// the possible time can be subtracted from the clock period.
|
||||
// _________
|
||||
// _____:_| : : |_:_______
|
||||
//
|
||||
// The actual jitter value is picked randomly within the window
|
||||
// {[-max_minus_jitter_ps:max_plus_jitter_ps]}
|
||||
// and is added to the time to next edge.
|
||||
int max_plus_jitter_ps = 1000;
|
||||
int max_minus_jitter_ps = 1000;
|
||||
|
||||
// The percentage chance of jitter occurring on each edge. If 0 (default value), then jitter is
|
||||
// disabled altogether. If 100, jitter is computed and applied at every edge.
|
||||
int jitter_chance_pc = 0;
|
||||
|
||||
// Internal signal indicating the clock half periods need to be recomputed.
|
||||
bit recompute = 1'b1;
|
||||
|
||||
// Internal signal indicating the amount of time for which the clock stays high / lo in the next
|
||||
// cycle.
|
||||
int clk_hi_ps;
|
||||
int clk_lo_ps;
|
||||
real clk_hi_modified_ps;
|
||||
real clk_lo_modified_ps;
|
||||
|
||||
// If true, this is the only clock in the system; there is no need to add initial jitter.
|
||||
bit sole_clock = 1'b0;
|
||||
|
||||
// use IfName as a part of msgs to indicate which clk_rst_vif instance
|
||||
string msg_id = {"clk_rst_if::", IfName};
|
||||
|
@ -81,6 +133,22 @@ interface clk_rst_if #(
|
|||
set_freq_khz(freq_mhz * 1000);
|
||||
endfunction
|
||||
|
||||
// Set the clk frequency scaling, chance in percentage and scaling up.
|
||||
//
|
||||
// freq_scaling_pc is a positive integer that determines by what amount (as percentage of the
|
||||
// nominal frequency) is the frequency scaled (jittered) down.
|
||||
// freq_scaling_chance_pc is a percentage number between 0 and 100 that determines how often is
|
||||
// the scaling randomly recomputed and applied.
|
||||
// freq_scale_up is a bit that enables the random scaling up of the frequency as well.
|
||||
function automatic void set_freq_scaling(int freq_scaling_pc, int freq_scaling_chance_pc = 50,
|
||||
bit freq_scale_up = 1'b0);
|
||||
`DV_CHECK_FATAL(freq_scaling_pc >= 0, , msg_id)
|
||||
`DV_CHECK_FATAL(freq_scaling_chance_pc inside {[0:100]}, , msg_id)
|
||||
clk_freq_scaling_pc = freq_scaling_pc;
|
||||
clk_freq_scaling_chance_pc = freq_scaling_chance_pc;
|
||||
clk_freq_scale_up = freq_scale_up;
|
||||
endfunction
|
||||
|
||||
// call this function at t=0 (from tb top) to enable clk and rst_n to be driven
|
||||
function automatic void set_active(bit drive_clk_val = 1'b1, bit drive_rst_n_val = 1'b1);
|
||||
time t = $time;
|
||||
|
@ -89,11 +157,7 @@ interface clk_rst_if #(
|
|||
drive_rst_n = drive_rst_n_val;
|
||||
end
|
||||
else begin
|
||||
`ifdef VERILATOR
|
||||
$error({msg_id, "this function can only be called at t=0"});
|
||||
`else
|
||||
`uvm_fatal(msg_id, "this function can only be called at t=0")
|
||||
`endif
|
||||
`dv_fatal("This function can only be called at t=0", msg_id)
|
||||
end
|
||||
endfunction
|
||||
|
||||
|
@ -106,32 +170,23 @@ interface clk_rst_if #(
|
|||
|
||||
// set the duty cycle (1-99)
|
||||
function automatic void set_duty_cycle(int duty);
|
||||
if (!(duty inside {[1:99]})) begin
|
||||
`ifdef VERILATOR
|
||||
$error({msg_id, $sformatf("duty cycle %0d is not inside [1:99]", duty)});
|
||||
`else
|
||||
`uvm_fatal(msg_id, $sformatf("duty cycle %0d is not inside [1:99]", duty))
|
||||
`endif
|
||||
end
|
||||
`DV_CHECK_FATAL(duty inside {[1:99]}, , msg_id)
|
||||
duty_cycle = duty;
|
||||
recompute = 1'b1;
|
||||
endfunction
|
||||
|
||||
// set maximum jitter in ps
|
||||
function automatic void set_max_jitter_ps(int jitter_ps);
|
||||
max_jitter_ps = jitter_ps;
|
||||
// set maximum jitter in ps, separating the plus jitter and the minus jitter.
|
||||
// In default the plus and minus jitters are the same.
|
||||
function automatic void set_max_jitter_ps(int plus_jitter_ps,
|
||||
int minus_jitter_ps = plus_jitter_ps);
|
||||
max_plus_jitter_ps = plus_jitter_ps;
|
||||
max_minus_jitter_ps = minus_jitter_ps;
|
||||
endfunction
|
||||
|
||||
// set jitter chance in percentage (0 - 100)
|
||||
// 0 - dont add any jitter; 100 - add jitter on every clock edge
|
||||
function automatic void set_jitter_chance_pc(int jitter_chance);
|
||||
if (!(jitter_chance inside {[0:100]})) begin
|
||||
`ifdef VERILATOR
|
||||
$error({msg_id, $sformatf("jitter_chance %0d is not inside [0:100]", jitter_chance)});
|
||||
`else
|
||||
`uvm_fatal(msg_id, $sformatf("jitter_chance %0d is not inside [0:100]", jitter_chance))
|
||||
`endif
|
||||
end
|
||||
`DV_CHECK_FATAL(jitter_chance inside {[0:100]}, , msg_id)
|
||||
jitter_chance_pc = jitter_chance;
|
||||
endfunction
|
||||
|
||||
|
@ -153,22 +208,36 @@ interface clk_rst_if #(
|
|||
clk_gate = 1'b1;
|
||||
endfunction
|
||||
|
||||
// add jitter to clk_hi and clk_lo half periods based on jitter_chance_pc
|
||||
function automatic void add_jitter();
|
||||
int jitter_ps;
|
||||
// Scales the clock frequency up and down on every edge.
|
||||
function automatic void apply_freq_scaling();
|
||||
real scaling;
|
||||
real mult = $urandom_range(0, clk_freq_scale_up) ? 1.0 : -1.0;
|
||||
|
||||
if ($urandom_range(1, 100) <= clk_freq_scaling_chance_pc) begin
|
||||
scaling = 1.0 + mult * real'($urandom_range(0, clk_freq_scaling_pc)) / 100;
|
||||
clk_hi_modified_ps = clk_hi_ps * scaling;
|
||||
scaling = 1.0 + mult * real'($urandom_range(0, clk_freq_scaling_pc)) / 100;
|
||||
clk_lo_modified_ps = clk_lo_ps * scaling;
|
||||
end
|
||||
endfunction
|
||||
|
||||
// Applies jitter to clk_hi and clk_lo half periods based on jitter_chance_pc.
|
||||
function automatic void apply_jitter();
|
||||
int jitter;
|
||||
int plus_jitter;
|
||||
int minus_jitter;
|
||||
|
||||
if ($urandom_range(1, 100) <= jitter_chance_pc) begin
|
||||
`ifndef VERILATOR
|
||||
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(jitter_ps,
|
||||
jitter_ps inside {[-1*max_jitter_ps:max_jitter_ps]};, "", msg_id)
|
||||
`endif
|
||||
clk_hi_ps += jitter_ps;
|
||||
plus_jitter = $urandom_range(0, max_plus_jitter_ps/2);
|
||||
minus_jitter = $urandom_range(0, max_minus_jitter_ps/2);
|
||||
jitter = ($urandom_range(0, 1) ? plus_jitter : (-1 * minus_jitter));
|
||||
clk_hi_modified_ps = clk_hi_ps + jitter;
|
||||
end
|
||||
if ($urandom_range(1, 100) <= jitter_chance_pc) begin
|
||||
`ifndef VERILATOR
|
||||
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(jitter_ps,
|
||||
jitter_ps inside {[-1*max_jitter_ps:max_jitter_ps]};, "", msg_id)
|
||||
`endif
|
||||
clk_lo_ps += jitter_ps;
|
||||
plus_jitter = $urandom_range(0, max_plus_jitter_ps/2);
|
||||
minus_jitter = $urandom_range(0, max_minus_jitter_ps/2);
|
||||
jitter = ($urandom_range(0, 1) ? plus_jitter : (-1 * minus_jitter));
|
||||
clk_lo_modified_ps = clk_lo_ps + jitter;
|
||||
end
|
||||
endfunction
|
||||
|
||||
|
@ -215,11 +284,7 @@ interface clk_rst_if #(
|
|||
o_rst_n <= 1'b1;
|
||||
end
|
||||
default: begin
|
||||
`ifdef VERILATOR
|
||||
$error({msg_id, $sformatf("rst_n_scheme %0d not supported", rst_n_scheme)});
|
||||
`else
|
||||
`uvm_fatal(msg_id, $sformatf("rst_n_scheme %0d not supported", rst_n_scheme))
|
||||
`endif
|
||||
`dv_fatal($sformatf("rst_n_scheme %0d not supported", rst_n_scheme), msg_id)
|
||||
end
|
||||
endcase
|
||||
wait_clks(post_reset_dly_clks);
|
||||
|
@ -252,13 +317,15 @@ interface clk_rst_if #(
|
|||
if (recompute) begin
|
||||
clk_hi_ps = clk_period_ps * duty_cycle / 100;
|
||||
clk_lo_ps = clk_period_ps - clk_hi_ps;
|
||||
clk_hi_modified_ps = clk_hi_ps;
|
||||
clk_lo_modified_ps = clk_lo_ps;
|
||||
recompute = 1'b0;
|
||||
end
|
||||
if (jitter_chance_pc != 0) add_jitter();
|
||||
#(clk_lo_ps * 1ps);
|
||||
// wiggle output clk if not gated
|
||||
if (clk_freq_scaling_pc && clk_freq_scaling_chance_pc) apply_freq_scaling();
|
||||
if (jitter_chance_pc) apply_jitter();
|
||||
#(clk_lo_modified_ps * 1ps);
|
||||
if (!clk_gate) o_clk = 1'b1;
|
||||
#(clk_hi_ps * 1ps);
|
||||
#(clk_hi_modified_ps * 1ps);
|
||||
o_clk = 1'b0;
|
||||
end
|
||||
end
|
||||
|
|
17
vendor/lowrisc_ip/dv/sv/common_ifs/rst_shadowed_if.core
vendored
Normal file
17
vendor/lowrisc_ip/dv/sv/common_ifs/rst_shadowed_if.core
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
CAPI=2:
|
||||
# Copyright lowRISC contributors.
|
||||
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
name: "lowrisc:dv:rst_shadowed_if"
|
||||
description: "Shadowed reset pin interfaces used in DV"
|
||||
|
||||
filesets:
|
||||
files_dv:
|
||||
files:
|
||||
- rst_shadowed_if.sv
|
||||
file_type: systemVerilogSource
|
||||
|
||||
targets:
|
||||
default:
|
||||
filesets:
|
||||
- files_dv
|
39
vendor/lowrisc_ip/dv/sv/common_ifs/rst_shadowed_if.sv
vendored
Normal file
39
vendor/lowrisc_ip/dv/sv/common_ifs/rst_shadowed_if.sv
vendored
Normal file
|
@ -0,0 +1,39 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//
|
||||
// Interface: rst_shadowed_if
|
||||
// An interface to drive rst_shadowed_n pin
|
||||
// By default, the `rst_shadowed_n` pin is directly connected to `rst_n` pin from the IP.
|
||||
// This interface provide methods to drive `rst_shadowed_n` pin when `drive_shadow_rst_pin()` task is
|
||||
// called, and can use `reconnect_shadowed_rst_n_to_rst_n()` to reconnect to `rst_n` pin.
|
||||
interface rst_shadowed_if (
|
||||
input rst_n,
|
||||
output rst_shadowed_n
|
||||
);
|
||||
|
||||
`ifndef VERILATOR
|
||||
// include macros and import pkgs
|
||||
`include "dv_macros.svh"
|
||||
`include "uvm_macros.svh"
|
||||
import uvm_pkg::*;
|
||||
`endif
|
||||
|
||||
bit drive_shadowed_rst_en;
|
||||
logic shadowed_rst_n;
|
||||
|
||||
// If set `drive_shadowed_rst_en` bit to 0, the `rst_shadowed_n` output will be the same as IP
|
||||
// level reset pin.
|
||||
function automatic void reconnect_shadowed_rst_n_to_rst_n();
|
||||
drive_shadowed_rst_en = 0;
|
||||
endfunction
|
||||
|
||||
task automatic drive_shadow_rst_pin(logic val);
|
||||
shadowed_rst_n = val;
|
||||
drive_shadowed_rst_en = 1;
|
||||
endtask
|
||||
|
||||
assign rst_shadowed_n = drive_shadowed_rst_en ? shadowed_rst_n : rst_n;
|
||||
|
||||
endinterface
|
30
vendor/lowrisc_ip/dv/sv/csr_utils/csr_seq_lib.sv
vendored
30
vendor/lowrisc_ip/dv/sv/csr_utils/csr_seq_lib.sv
vendored
|
@ -142,7 +142,17 @@ class csr_hw_reset_seq extends csr_base_seq;
|
|||
test_csrs[i].get_full_name()), UVM_MEDIUM)
|
||||
|
||||
compare_mask = get_mask_excl_fields(test_csrs[i], CsrExclInitCheck, CsrHwResetTest);
|
||||
// Read twice, one from backdoor, the other from frontdoor.
|
||||
// Reading from backdoor can ensure that we deposit value into the storage rather than just
|
||||
// a net. If we mistakenly deposit to a net, reset can't clear it and this check will fail.
|
||||
csr_rd_check(.ptr (test_csrs[i]),
|
||||
.backdoor (1),
|
||||
.compare (!external_checker),
|
||||
.compare_vs_ral(1'b1),
|
||||
.compare_mask (compare_mask));
|
||||
// same read but using frontdoor
|
||||
csr_rd_check(.ptr (test_csrs[i]),
|
||||
.backdoor (0),
|
||||
.blocking (0),
|
||||
.compare (!external_checker),
|
||||
.compare_vs_ral(1'b1),
|
||||
|
@ -208,7 +218,25 @@ class csr_write_seq extends csr_base_seq;
|
|||
backdoor dist {0 :/ 7, 1 :/ 3};)
|
||||
end
|
||||
|
||||
csr_wr(.ptr(test_csrs[i]), .value(wdata), .blocking(0), .backdoor(backdoor));
|
||||
if (backdoor) begin
|
||||
string str_kinds[$];
|
||||
|
||||
test_csrs[i].get_hdl_path_kinds(str_kinds);
|
||||
str_kinds.shuffle();
|
||||
|
||||
foreach (str_kinds[j]) begin
|
||||
bkdr_reg_path_e enum_kind;
|
||||
// Convert string name to an enum
|
||||
`DV_CHECK_FATAL(uvm_enum_wrapper#(bkdr_reg_path_e)::from_name(str_kinds[j], enum_kind))
|
||||
|
||||
csr_poke(.ptr(test_csrs[i]), .value(wdata), .kind(enum_kind));
|
||||
|
||||
`DV_CHECK_STD_RANDOMIZE_FATAL(wdata)
|
||||
wdata = get_csr_wdata_with_write_excl(test_csrs[i], wdata, CsrHwResetTest);
|
||||
end
|
||||
end else begin
|
||||
csr_wr(.ptr(test_csrs[i]), .value(wdata), .blocking(0));
|
||||
end
|
||||
end
|
||||
endtask
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ package csr_utils_pkg;
|
|||
import uvm_pkg::*;
|
||||
import dv_utils_pkg::*;
|
||||
import dv_base_reg_pkg::*;
|
||||
export dv_base_reg_pkg::csr_field_t, dv_base_reg_pkg::decode_csr_or_field;
|
||||
|
||||
// macro includes
|
||||
`include "uvm_macros.svh"
|
||||
|
@ -22,14 +23,6 @@ package csr_utils_pkg;
|
|||
bit under_reset = 0;
|
||||
int max_outstanding_accesses = 100;
|
||||
|
||||
// csr field struct - hold field specific params
|
||||
typedef struct {
|
||||
uvm_reg csr;
|
||||
uvm_reg_field field;
|
||||
uvm_reg_data_t mask;
|
||||
uint shift;
|
||||
} csr_field_t;
|
||||
|
||||
function automatic void increment_outstanding_access();
|
||||
outstanding_accesses++;
|
||||
endfunction
|
||||
|
@ -75,7 +68,7 @@ package csr_utils_pkg;
|
|||
return mem.get_access();
|
||||
endfunction
|
||||
|
||||
// This fucntion return mirrored value of reg/field of given RAL
|
||||
// This function return mirrored value of reg/field of given RAL
|
||||
function automatic uvm_reg_data_t get_reg_fld_mirror_value(uvm_reg_block ral,
|
||||
string reg_name,
|
||||
string field_name = "");
|
||||
|
@ -97,34 +90,6 @@ package csr_utils_pkg;
|
|||
return result;
|
||||
endfunction : get_reg_fld_mirror_value
|
||||
|
||||
// This function attempts to cast a given uvm_object ptr into uvm_reg or uvm_reg_field. If cast
|
||||
// is successful on either, then set the appropriate csr_field_t return values.
|
||||
function automatic csr_field_t decode_csr_or_field(input uvm_object ptr);
|
||||
uvm_reg csr;
|
||||
uvm_reg_field fld;
|
||||
csr_field_t result;
|
||||
string msg_id = {csr_utils_pkg::msg_id, "::decode_csr_or_field"};
|
||||
|
||||
if ($cast(csr, ptr)) begin
|
||||
// return csr object with null field; set the mask to all 1s and shift to 0
|
||||
result.csr = csr;
|
||||
result.mask = '1;
|
||||
result.shift = 0;
|
||||
end
|
||||
else if ($cast(fld, ptr)) begin
|
||||
// return csr field object; return the appropriate mask and shift values
|
||||
result.csr = fld.get_parent();
|
||||
result.field = fld;
|
||||
result.mask = (1 << fld.get_n_bits()) - 1;
|
||||
result.shift = fld.get_lsb_pos();
|
||||
end
|
||||
else begin
|
||||
`uvm_fatal(msg_id, $sformatf("ptr %0s is not of type uvm_reg or uvm_reg_field",
|
||||
ptr.get_full_name()))
|
||||
end
|
||||
return result;
|
||||
endfunction : decode_csr_or_field
|
||||
|
||||
// get updated reg value by using new specific field value
|
||||
function automatic uvm_reg_data_t get_csr_val_with_updated_field(uvm_reg_field field,
|
||||
uvm_reg_data_t csr_value,
|
||||
|
@ -726,20 +691,29 @@ package csr_utils_pkg;
|
|||
return wdata;
|
||||
endfunction
|
||||
|
||||
// Returns the CSR exclusion item associated with the provided object.
|
||||
//
|
||||
// If an exclusion item for the immediate block (parent of the CSR if ptr is a CSR or a field) is
|
||||
// not found, it recurses through the block's ancestors to find an available exclusion item.
|
||||
// arg ptr: An extention of one of dv_base_reg{, _block or _field} classes.
|
||||
function automatic csr_excl_item get_excl_item(uvm_object ptr);
|
||||
csr_field_t csr_or_fld;
|
||||
dv_base_reg_block blk;
|
||||
|
||||
csr_or_fld = decode_csr_or_field(ptr);
|
||||
`downcast(blk, csr_or_fld.csr.get_parent(), , , msg_id)
|
||||
|
||||
// csr_excl is at the highest level of reg block
|
||||
while (blk.csr_excl == null) begin
|
||||
`downcast(blk, blk.get_parent(), , , msg_id)
|
||||
`DV_CHECK_NE_FATAL(blk, null, "", msg_id)
|
||||
// Attempt cast to blk. If it fails, then attempt to cast to CSR or field.
|
||||
if (!$cast(blk, ptr)) begin
|
||||
csr_field_t csr_or_fld = decode_csr_or_field(ptr);
|
||||
`downcast(blk, csr_or_fld.csr.get_parent(), , , msg_id)
|
||||
end
|
||||
return blk.csr_excl;
|
||||
|
||||
// Recurse through block's ancestors.
|
||||
do begin
|
||||
csr_excl_item csr_excl = blk.get_excl_item();
|
||||
if (csr_excl != null) return csr_excl;
|
||||
`downcast(blk, blk.get_parent(), , , msg_id)
|
||||
end while (blk != null);
|
||||
return null;
|
||||
endfunction
|
||||
|
||||
// sources
|
||||
`include "csr_seq_lib.sv"
|
||||
|
||||
|
|
150
vendor/lowrisc_ip/dv/sv/dv_base_reg/csr_excl_item.sv
vendored
150
vendor/lowrisc_ip/dv/sv/dv_base_reg/csr_excl_item.sv
vendored
|
@ -9,6 +9,7 @@ class csr_excl_item extends uvm_object;
|
|||
`uvm_object_utils(csr_excl_item)
|
||||
|
||||
typedef struct {
|
||||
bit enable;
|
||||
int csr_test_type;
|
||||
csr_excl_type_e csr_excl_type;
|
||||
} csr_excl_s;
|
||||
|
@ -16,87 +17,133 @@ class csr_excl_item extends uvm_object;
|
|||
|
||||
`uvm_object_new
|
||||
|
||||
// add exclusion for an individual block, csr or field
|
||||
// arg obj: this is the hierarchical path name to the block, csr or field - passing * and ?
|
||||
// wildcards for glob style matching is allowed. User needs to take care that wildcards does not
|
||||
// end up inadvertently matching more that what was desired. Examples:
|
||||
// To exclude ral.ctrl.tx field from writes, obj can be "ral.ctrl.tx" or "*.ctrl.tx"; passing
|
||||
// "*.tx" might be too generic
|
||||
// Adds an exclusion for an individual block, register or field.
|
||||
//
|
||||
// arg obj: Hierarchical path to the block, csr or field as string. Passing * and ? wildcards for
|
||||
// glob style matching is allowed. User needs to take care the wildcards don't match more
|
||||
// than desired. For example, for the ral.ctrl.tx field:
|
||||
// obj = "ral.ctrl.tx" or "*.ctrl.tx" should work; "*.tx" might be too generic.
|
||||
// arg csr_excl_type: The desired exclusion type.
|
||||
// arg csr_test_type: The desired test type for which the exclusion is in effect.
|
||||
virtual function void add_excl(string obj,
|
||||
csr_excl_type_e csr_excl_type,
|
||||
csr_test_type_e csr_test_type = CsrAllTests);
|
||||
bit [2:0] val = CsrNoExcl;
|
||||
bit [NUM_CSR_TESTS-1:0] test = CsrInvalidTest;
|
||||
|
||||
if (csr_test_type == CsrInvalidTest) begin
|
||||
`uvm_fatal(`gfn, $sformatf("add %s exclusion without a test", obj))
|
||||
`DV_CHECK_NE_FATAL(csr_test_type, CsrInvalidTest,
|
||||
$sformatf("Test type not specified for the exclusion of %0s.", obj))
|
||||
|
||||
if (!exclusions.exists(obj)) begin
|
||||
exclusions[obj] = '{enable:1'b1, csr_test_type:csr_test_type, csr_excl_type:csr_excl_type};
|
||||
return;
|
||||
end
|
||||
|
||||
if (!exclusions.exists(obj)) exclusions[obj] = '{default:CsrNoExcl};
|
||||
val = csr_excl_type | exclusions[obj].csr_excl_type;
|
||||
test = csr_test_type | exclusions[obj].csr_test_type;
|
||||
exclusions[obj].csr_excl_type = csr_excl_type_e'(val);
|
||||
exclusions[obj].csr_test_type = test;
|
||||
endfunction
|
||||
|
||||
// function to check if given blk / csr or field AND its parent has been excluded with the
|
||||
// supplied exclusion type
|
||||
// arg uvm_object obj: given blk, csr or field
|
||||
// arg csr_excl_type_e csr_excl_type: exclusion type
|
||||
// Turns exclusion on or off for a block, register or field.
|
||||
//
|
||||
// The originally set exclusions are untouched. This method only enables or disables the
|
||||
// application of the exclusions temporarily.
|
||||
//
|
||||
// obj: The hierarchical path to block, register or field.
|
||||
// enable: Bit indicating whether to enable or disable the application of exclusion.
|
||||
// throw_error: Bit indicating whether to throw error if exclusions associated with obj do not
|
||||
// exist.
|
||||
virtual function void enable_excl(string obj, bit enable = 1'b1, bit throw_error = 1'b1);
|
||||
string index;
|
||||
if (get_excl_index(obj, index)) begin
|
||||
exclusions[index].enable = enable;
|
||||
return;
|
||||
end
|
||||
if (throw_error) begin
|
||||
`uvm_fatal(`gfn, $sformatf("No exclusions found for %0s.", obj))
|
||||
end
|
||||
endfunction
|
||||
|
||||
// Checks if the given block, register or field is excluded.
|
||||
//
|
||||
// arg obj: The given block, register or field.
|
||||
// arg csr_excl_type: The exclusion checked against.
|
||||
// arg csr_test_type: The type of test for which the exclusion is in effect.
|
||||
function bit is_excl(uvm_object obj,
|
||||
csr_excl_type_e csr_excl_type,
|
||||
csr_test_type_e csr_test_type);
|
||||
uvm_reg_block blk;
|
||||
uvm_reg csr;
|
||||
|
||||
// if supplied obj is a uvm_reg_block or uvm_reg, then its parent is a uvm_reg_block
|
||||
// check if obj's parent is excluded
|
||||
if ($cast(blk, obj)) begin
|
||||
if (blk.get_parent() != null) begin
|
||||
blk = blk.get_parent();
|
||||
if (has_excl(blk.`gfn, csr_excl_type, csr_test_type)) return 1'b1;
|
||||
// Attempt cast to block. If it fails, then attempt to cast to CSR or field.
|
||||
if (!$cast(blk, obj)) begin
|
||||
csr_field_t csr_or_fld = decode_csr_or_field(obj);
|
||||
if (csr_or_fld.field != null) begin
|
||||
if (has_excl(csr_or_fld.field.`gfn, csr_excl_type, csr_test_type, is_excl)) return is_excl;
|
||||
end else begin
|
||||
if (has_excl(csr_or_fld.csr.`gfn, csr_excl_type, csr_test_type, is_excl)) return is_excl;
|
||||
end
|
||||
`downcast(blk, csr_or_fld.csr.get_parent(), , , msg_id)
|
||||
end
|
||||
if ($cast(csr, obj)) begin
|
||||
blk = csr.get_parent();
|
||||
if (has_excl(blk.`gfn, csr_excl_type, csr_test_type)) return 1'b1;
|
||||
end
|
||||
// TODO: check if any parent in the hierarchy above is excluded
|
||||
// check if obj is excluded
|
||||
return (has_excl(obj.`gfn, csr_excl_type, csr_test_type));
|
||||
|
||||
// Recurse through block's ancestors.
|
||||
do begin
|
||||
if (has_excl(blk.`gfn, csr_excl_type, csr_test_type, is_excl)) return is_excl;
|
||||
blk = blk.get_parent();
|
||||
end while (blk != null);
|
||||
return 1'b0;
|
||||
endfunction
|
||||
|
||||
// check if applied string obj has a match in existing exclusions lookup in defined csr_test_type
|
||||
// function is to not be called externally
|
||||
local function bit has_excl(string obj,
|
||||
csr_excl_type_e csr_excl_type,
|
||||
csr_test_type_e csr_test_type);
|
||||
// check if obj exists verbatim
|
||||
// Retrieves the string index of the exclusions data structure.
|
||||
//
|
||||
// The provided object for lookup is a string itself. It however, may or may
|
||||
// not exist verbatim as an associative array index in the `exclusions` data
|
||||
// structure, since glob-style wildcards are supported when adding the
|
||||
// exclusions. The provided object must hence be a fully resolved
|
||||
// hierarchical path to the CSR block, register or field.
|
||||
//
|
||||
// Returns 1 if index is found, else 0.
|
||||
// Returns the actual index as output arg.
|
||||
local function bit get_excl_index(input string obj, output string index);
|
||||
// If obj is a index of exclusions, return it, else loop through available
|
||||
// keys to find a glob match.
|
||||
if (exclusions.exists(obj)) begin
|
||||
`uvm_info(`gfn, $sformatf("has_excl: found exact excl match for %0s: %0s",
|
||||
obj, exclusions[obj].csr_excl_type.name()), UVM_DEBUG)
|
||||
// check if bit(s) corresponding to csr_excl_type are set in defined csr_test_type
|
||||
if ((exclusions[obj].csr_test_type & csr_test_type) != CsrInvalidTest) begin
|
||||
if ((exclusions[obj].csr_excl_type & csr_excl_type) != CsrNoExcl) return 1'b1;
|
||||
end
|
||||
end
|
||||
else begin
|
||||
// attempt glob style matching
|
||||
index = obj;
|
||||
return 1'b1;
|
||||
end else begin
|
||||
foreach (exclusions[str]) begin
|
||||
if (!uvm_re_match(str, obj)) begin
|
||||
`uvm_info(`gfn, $sformatf("has_excl: found glob excl match for %0s(%0s): %0s",
|
||||
obj, str, exclusions[str].csr_excl_type.name()), UVM_DEBUG)
|
||||
// check if bit(s) corresponding to csr_excl_type are set in defined csr_test_type
|
||||
if ((exclusions[str].csr_test_type & csr_test_type) != CsrInvalidTest) begin
|
||||
if ((exclusions[str].csr_excl_type & csr_excl_type) != CsrNoExcl) return 1'b1;
|
||||
end
|
||||
index = str;
|
||||
return 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
return 1'b0;
|
||||
endfunction
|
||||
|
||||
// print all exclusions for ease of debug (call this ideally after adding all exclusions)
|
||||
// Checks if a particular exclusion for an object for a test is in effect.
|
||||
//
|
||||
// arg obj: The given block, register or field as string lookup.
|
||||
// arg csr_excl_type: The exclusion checked against.
|
||||
// arg csr_test_type: The type of test for which the exclusion is in effect.
|
||||
// arg is_excl: Bit indicating the object is excluded.
|
||||
//
|
||||
// Returns 1 if an associated exclusion is found, else 0.
|
||||
local function bit has_excl(input string obj,
|
||||
input csr_excl_type_e csr_excl_type,
|
||||
input csr_test_type_e csr_test_type,
|
||||
output bit is_excl);
|
||||
string index;
|
||||
if (get_excl_index(obj, index)) begin
|
||||
is_excl = exclusions[index].enable &&
|
||||
((exclusions[index].csr_test_type & csr_test_type) != CsrInvalidTest) &&
|
||||
((exclusions[index].csr_excl_type & csr_excl_type) != CsrNoExcl);
|
||||
return 1'b1;
|
||||
end
|
||||
return 1'b0;
|
||||
endfunction
|
||||
|
||||
// Prints all exclusions for ease of debug.
|
||||
virtual function void print_exclusions(uvm_verbosity verbosity = UVM_HIGH);
|
||||
string test_names;
|
||||
for (int i = NUM_CSR_TESTS - 1; i >= 0; i--) begin
|
||||
|
@ -104,8 +151,9 @@ class csr_excl_item extends uvm_object;
|
|||
test_names = {test_names, csr_test.name(), (i > 0) ? " " : ""};
|
||||
end
|
||||
foreach (exclusions[item]) begin
|
||||
`uvm_info(`gfn, $sformatf("CSR/field [%0s] excluded with %0s in csr_tests: {%s} = {%0b}",
|
||||
item, exclusions[item].csr_excl_type.name(), test_names,
|
||||
string enabled = exclusions[item].enable ? "[enabled]" : "[disabled]";
|
||||
`uvm_info(`gfn, $sformatf("CSR/field [%s] exclusion %s %s in csr_tests: {%s} = {%0b}",
|
||||
item, exclusions[item].csr_excl_type.name(), enabled, test_names,
|
||||
exclusions[item].csr_test_type), verbosity)
|
||||
end
|
||||
endfunction
|
||||
|
|
|
@ -152,6 +152,7 @@ class dv_base_reg extends uvm_reg;
|
|||
if (is_shadowed) begin
|
||||
if (shadow_wr_staged) `uvm_info(`gfn, "clear shadow_wr_staged", UVM_HIGH)
|
||||
shadow_wr_staged = 0;
|
||||
clear_shadow_update_err();
|
||||
end
|
||||
endfunction
|
||||
|
||||
|
@ -317,7 +318,7 @@ class dv_base_reg extends uvm_reg;
|
|||
if (kind == "BkdrRegPathRtlShadow") begin
|
||||
flds[i].update_shadowed_val(get_field_val(flds[i], value));
|
||||
backdoor_write_shadow_val = 1;
|
||||
end else if (kind == "BkdrRegPathRtlCommitted") begin
|
||||
end else if (kind == "BkdrRegPathRtl") begin
|
||||
flds[i].update_committed_val(get_field_val(flds[i], value));
|
||||
backdoor_write_shadow_val = 1;
|
||||
end
|
||||
|
@ -334,13 +335,6 @@ class dv_base_reg extends uvm_reg;
|
|||
end
|
||||
endfunction
|
||||
|
||||
// Callback function to update shadowed values according to specific design.
|
||||
// Should only be called after post-write.
|
||||
// If a shadow reg is locked due to fatal error, this function will return without updates
|
||||
virtual function void update_shadowed_val(uvm_reg_data_t val, bit do_predict = 1);
|
||||
// TODO: find a better way to support for AES.
|
||||
endfunction
|
||||
|
||||
virtual function void reset(string kind = "HARD");
|
||||
super.reset(kind);
|
||||
if (is_shadowed) begin
|
||||
|
|
|
@ -12,7 +12,8 @@ class dv_base_reg_block extends uvm_reg_block;
|
|||
// name as {ip_name}_{alert_name}. Hence, we need this ip_name in reg_block
|
||||
local string ip_name;
|
||||
|
||||
csr_excl_item csr_excl;
|
||||
// CSR exclusion object that holds exclusion tags for the sub-blocks, CSRs and fields.
|
||||
protected csr_excl_item csr_excl;
|
||||
|
||||
// The address mask for the register block specific to a map. This will be (1 << K) - 1 for some
|
||||
// K. All relative offsets in the register block have addresses less than (1 << K), so an address
|
||||
|
@ -46,6 +47,11 @@ class dv_base_reg_block extends uvm_reg_block;
|
|||
return ip_name;
|
||||
endfunction
|
||||
|
||||
// Returns the CSR exclusion item attached to the block.
|
||||
virtual function csr_excl_item get_excl_item();
|
||||
return csr_excl;
|
||||
endfunction
|
||||
|
||||
// provide build function to supply base addr
|
||||
virtual function void build(uvm_reg_addr_t base_addr,
|
||||
csr_excl_item csr_excl = null);
|
||||
|
|
|
@ -13,6 +13,15 @@ package dv_base_reg_pkg;
|
|||
|
||||
// global paramters for number of csr tests (including memory test)
|
||||
parameter uint NUM_CSR_TESTS = 4;
|
||||
string msg_id = "dv_base_reg_pkg";
|
||||
|
||||
// csr field struct - hold field specific params
|
||||
typedef struct {
|
||||
uvm_reg csr;
|
||||
uvm_reg_field field;
|
||||
uvm_reg_data_t mask;
|
||||
uint shift;
|
||||
} csr_field_t;
|
||||
|
||||
// csr exclusion indications
|
||||
typedef enum bit [2:0] {
|
||||
|
@ -38,23 +47,45 @@ package dv_base_reg_pkg;
|
|||
} csr_test_type_e;
|
||||
|
||||
typedef enum bit[2:0] {
|
||||
// If it's a shadow reg, BkdrRegPathRtl is the path to committed reg
|
||||
BkdrRegPathRtl, // backdoor path for reg's val in RTL
|
||||
BkdrRegPathRtlCommitted, // backdoor path for shadow reg's committed val in RTL
|
||||
BkdrRegPathRtlShadow, // backdoor path for shadow reg's shadow val in RTL
|
||||
BkdrRegPathGls, // backdoor path for reg's val in GLS
|
||||
BkdrRegPathGlsCommitted, // backdoor path for shadow reg's committed val in GLS
|
||||
BkdrRegPathGlsShdow // backdoor path for shadow reg's shadow val in GLS
|
||||
} bkdr_reg_path_e;
|
||||
|
||||
// Forward-declare class types for the functions below.
|
||||
typedef class dv_base_reg_block;
|
||||
typedef class dv_base_reg;
|
||||
typedef class dv_base_reg_field;
|
||||
|
||||
`include "csr_excl_item.sv"
|
||||
`include "dv_base_reg_field.sv"
|
||||
`include "dv_base_reg.sv"
|
||||
`include "dv_base_mem.sv"
|
||||
`include "dv_base_reg_block.sv"
|
||||
`include "dv_base_reg_map.sv"
|
||||
// This function attempts to cast a given uvm_object ptr into uvm_reg or uvm_reg_field. If cast
|
||||
// is successful on either, then set the appropriate csr_field_t return values.
|
||||
function automatic csr_field_t decode_csr_or_field(input uvm_object ptr);
|
||||
uvm_reg csr;
|
||||
uvm_reg_field fld;
|
||||
csr_field_t result;
|
||||
string msg_id = {dv_base_reg_pkg::msg_id, "::decode_csr_or_field"};
|
||||
|
||||
if ($cast(csr, ptr)) begin
|
||||
// return csr object with null field; set the mask to all 1s and shift to 0
|
||||
result.csr = csr;
|
||||
result.mask = '1;
|
||||
result.shift = 0;
|
||||
end
|
||||
else if ($cast(fld, ptr)) begin
|
||||
// return csr field object; return the appropriate mask and shift values
|
||||
result.csr = fld.get_parent();
|
||||
result.field = fld;
|
||||
result.mask = (1 << fld.get_n_bits()) - 1;
|
||||
result.shift = fld.get_lsb_pos();
|
||||
end
|
||||
else begin
|
||||
`uvm_fatal(msg_id, $sformatf("ptr %0s is not of type uvm_reg or uvm_reg_field",
|
||||
ptr.get_full_name()))
|
||||
end
|
||||
return result;
|
||||
endfunction : decode_csr_or_field
|
||||
|
||||
function automatic void get_flds_from_uvm_object(input uvm_object obj,
|
||||
input string msg = "dv_base_reg_pkg",
|
||||
|
@ -71,7 +102,7 @@ package dv_base_reg_pkg;
|
|||
`uvm_fatal(msg, $sformatf("obj %0s is not of type uvm_reg or uvm_reg_field",
|
||||
obj.get_full_name()))
|
||||
end
|
||||
endfunction
|
||||
endfunction : get_flds_from_uvm_object
|
||||
|
||||
// mask and shift data to extract the value specific to that supplied field
|
||||
function automatic uvm_reg_data_t get_field_val(uvm_reg_field field,
|
||||
|
@ -79,6 +110,13 @@ package dv_base_reg_pkg;
|
|||
uvm_reg_data_t mask = (1 << field.get_n_bits()) - 1;
|
||||
uint shift = field.get_lsb_pos();
|
||||
get_field_val = (value >> shift) & mask;
|
||||
endfunction
|
||||
endfunction : get_field_val
|
||||
|
||||
`include "csr_excl_item.sv"
|
||||
`include "dv_base_reg_field.sv"
|
||||
`include "dv_base_reg.sv"
|
||||
`include "dv_base_mem.sv"
|
||||
`include "dv_base_reg_block.sv"
|
||||
`include "dv_base_reg_map.sv"
|
||||
|
||||
endpackage
|
||||
|
|
|
@ -85,10 +85,18 @@ class dv_base_env_cfg #(type RAL_T = dv_base_reg_block) extends uvm_object;
|
|||
end
|
||||
endfunction
|
||||
|
||||
// ral flow is limited in terms of setting correct field access policies and reset values
|
||||
// We apply those fixes here - please note these fixes need to be reflected in the scoreboard
|
||||
protected virtual function void apply_ral_fixes();
|
||||
// fix access policies & reset values
|
||||
// Set pre-build RAL knobs.
|
||||
//
|
||||
// This method enables setting pre-build config knobs that can be used to control how the RAL
|
||||
// sub-structures are created.
|
||||
protected virtual function void pre_build_ral_settings(dv_base_reg_block ral);
|
||||
endfunction
|
||||
|
||||
// Perform post-build, pre-lock modifications to the RAL.
|
||||
//
|
||||
// For some registers / fields, the correct access policies or reset values may not be set. Fixes
|
||||
// like those can be made with this method.
|
||||
protected virtual function void post_build_ral_settings(dv_base_reg_block ral);
|
||||
endfunction
|
||||
|
||||
virtual function void reset_asserted();
|
||||
|
@ -112,8 +120,9 @@ class dv_base_env_cfg #(type RAL_T = dv_base_reg_block) extends uvm_object;
|
|||
|
||||
// Build the register block with an arbitrary base address (we choose 0). We'll change it
|
||||
// later.
|
||||
pre_build_ral_settings(reg_blk);
|
||||
reg_blk.build(.base_addr(0), .csr_excl(null));
|
||||
apply_ral_fixes();
|
||||
post_build_ral_settings(reg_blk);
|
||||
reg_blk.lock_model();
|
||||
|
||||
// Now the model is locked, we know its layout. Set the base address for the register block.
|
||||
|
|
|
@ -77,7 +77,7 @@ class dv_base_monitor #(type ITEM_T = uvm_sequence_item,
|
|||
end
|
||||
|
||||
// Start the timer only when ok_to_end is asserted.
|
||||
wait(ok_to_end);
|
||||
wait (ok_to_end);
|
||||
`uvm_info(`gfn, $sformatf("watchdog_ok_to_end: starting the timer (count: %0d)",
|
||||
watchdog_restart_count++), UVM_MEDIUM)
|
||||
fork
|
||||
|
@ -88,16 +88,12 @@ class dv_base_monitor #(type ITEM_T = uvm_sequence_item,
|
|||
#(cfg.ok_to_end_delay_ns * 1ns);
|
||||
watchdog_done = 1'b1;
|
||||
end
|
||||
@(ok_to_end);
|
||||
wait (!ok_to_end);
|
||||
join_any
|
||||
disable fork;
|
||||
end: isolation_fork
|
||||
join
|
||||
|
||||
// The #0 delay ensures that we sample the stabilized value of ok_to_end in the condition
|
||||
// below in case it toggles more than once in the same simulation time-step.
|
||||
#0;
|
||||
|
||||
// If ok_to_end stayed high throughout the watchdog timer expiry, then drop the objection.
|
||||
if (ok_to_end && watchdog_done) begin
|
||||
`uvm_info(`gfn, "watchdog_ok_to_end: dropping objection", UVM_MEDIUM)
|
||||
|
@ -105,7 +101,7 @@ class dv_base_monitor #(type ITEM_T = uvm_sequence_item,
|
|||
objection_raised = 1'b0;
|
||||
|
||||
// Wait for ok_to_end to de-assert again in future.
|
||||
wait(!ok_to_end);
|
||||
wait (!ok_to_end);
|
||||
end
|
||||
end
|
||||
endtask
|
||||
|
|
|
@ -140,7 +140,7 @@ class dv_base_vseq #(type RAL_T = dv_base_reg_block,
|
|||
endtask
|
||||
|
||||
// This is called after apply_reset in this class and after apply_resets_concurrently
|
||||
// in cip_base_vseq::run_stress_all_with_rand_reset_vseq.
|
||||
// in cip_base_vseq::run_seq_with_rand_reset_vseq.
|
||||
virtual task post_apply_reset(string reset_kind = "HARD");
|
||||
endtask
|
||||
|
||||
|
@ -205,6 +205,12 @@ class dv_base_vseq #(type RAL_T = dv_base_reg_block,
|
|||
default : `uvm_fatal(`gfn, $sformatf("specified opt is invalid: +csr_%0s", csr_test_type))
|
||||
endcase
|
||||
|
||||
// Print the list of available exclusions that are in effect for debug.
|
||||
foreach (cfg.ral_models[i]) begin
|
||||
csr_excl_item csr_excl = csr_utils_pkg::get_excl_item(cfg.ral_models[i]);
|
||||
if (csr_excl != null) csr_excl.print_exclusions();
|
||||
end
|
||||
|
||||
// if hw_reset test, then write all CSRs first and reset the whole dut
|
||||
if (csr_test_type == "hw_reset" && do_rand_wr_and_reset) begin
|
||||
string reset_type = "HARD";
|
||||
|
|
|
@ -76,6 +76,10 @@
|
|||
`define DV_STRINGIFY(I_) `"I_`"
|
||||
`endif
|
||||
|
||||
`ifndef DUT_HIER_STR
|
||||
`define DUT_HIER_STR `DV_STRINGIFY(`DUT_HIER)
|
||||
`endif
|
||||
|
||||
// Common check macros used by DV_CHECK error and fatal macros.
|
||||
// Note: Should not be called by user code
|
||||
`ifndef DV_CHECK
|
||||
|
@ -390,7 +394,7 @@
|
|||
// SCOPE_ : Hierarchical string path to the testbench where this macro is invoked, example: %m.
|
||||
// ID_ : Identifier string used for UVM logs.
|
||||
`ifndef DV_ASSERT_CTRL
|
||||
`define DV_ASSERT_CTRL(LABEL_, HIER_, LEVELS_ = 0, SCOPE_ = "", ID_ = "%m") \
|
||||
`define DV_ASSERT_CTRL(LABEL_, HIER_, LEVELS_ = 0, SCOPE_ = "", ID_ = $sformatf("%m")) \
|
||||
initial begin \
|
||||
bit assert_en; \
|
||||
forever begin \
|
||||
|
|
19
vendor/lowrisc_ip/dv/sv/mem_bkdr_util/README.md
vendored
Normal file
19
vendor/lowrisc_ip/dv/sv/mem_bkdr_util/README.md
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
## Memory backdoor utility class
|
||||
The `mem_bkdr_util` class provides a way to manipulate the memory array directly via backdoor.
|
||||
It includes a set of functions to backdoor read or write any address location within the memory.
|
||||
The class instance is created in the testbench module and passed to the UVM environment via `uvm_config_db`.
|
||||
|
||||
### Methods
|
||||
This interface supports basic backdoor methods to access memory. Useful methods are:
|
||||
* `is_addr_valid`: Check if input address is valid
|
||||
The input address is assumed to be the byte addressable address into memory
|
||||
starting at 0. It is user's responsibility to mask the upper bits.
|
||||
* `read8`, `read16`, `read32`, `read64`: Functions to read one byte, two bytes, four bytes, and eight bytes respectively
|
||||
at specified input address
|
||||
* `write8`, `write16`, `write32`, `write64`: Functions to write one byte, two bytes, four bytes, and eight bytes respectively
|
||||
with input data at specified input address
|
||||
* `load_mem_from_file`: Load memory from a file specified by input string
|
||||
* `print_mem`: Print the content of the memory
|
||||
* `clear_mem`: Clear the memory to all 0s
|
||||
* `set_mem`: Set the memory to all 1s
|
||||
* `randomize_mem`: Randomize contents of the memory
|
31
vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util.core
vendored
Normal file
31
vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util.core
vendored
Normal file
|
@ -0,0 +1,31 @@
|
|||
CAPI=2:
|
||||
# Copyright lowRISC contributors.
|
||||
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
name: "lowrisc:dv:mem_bkdr_util"
|
||||
description: "Backdoor read/write memory for DV"
|
||||
|
||||
filesets:
|
||||
files_dv:
|
||||
depend:
|
||||
- lowrisc:opentitan:bus_params_pkg
|
||||
- lowrisc:dv:dv_utils
|
||||
- lowrisc:dv:crypto_dpi_prince:0.1
|
||||
- lowrisc:dv:crypto_dpi_present:0.1
|
||||
- lowrisc:prim:cipher_pkg:0.1
|
||||
- lowrisc:prim:secded:0.1
|
||||
- lowrisc:ip:otp_ctrl_pkg:0.1
|
||||
files:
|
||||
- otp_scrambler_pkg.sv
|
||||
- sram_scrambler_pkg.sv
|
||||
- mem_bkdr_util_pkg.sv
|
||||
- mem_bkdr_util.sv: {is_include_file: true}
|
||||
- mem_bkdr_util__otp.sv: {is_include_file: true}
|
||||
- mem_bkdr_util__rom.sv: {is_include_file: true}
|
||||
- mem_bkdr_util__sram.sv: {is_include_file: true}
|
||||
file_type: systemVerilogSource
|
||||
|
||||
targets:
|
||||
default:
|
||||
filesets:
|
||||
- files_dv
|
542
vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util.sv
vendored
Normal file
542
vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util.sv
vendored
Normal file
|
@ -0,0 +1,542 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Provides a mechanism to manipulate and access a memory instance in the design via backdoor.
|
||||
//
|
||||
// This is a class based implementation, which on initialization (`new()`) takes the path to the
|
||||
// memory hierarchy, the size in bits, the depth, integrity protection and scrambling needs as
|
||||
// arguments. All memory specifics are set / computed at runtime. There are no parameterizations, so
|
||||
// that the implementation is flexible, extensible, and easy to use.
|
||||
//
|
||||
// Create an instance of this class in the testbench module itself, so that the hierarchical path to
|
||||
// the memory element and its size and depth information is available. Pass the instance to the UVM
|
||||
// side via uvm_config_db.
|
||||
class mem_bkdr_util extends uvm_object;
|
||||
// Hierarchical path to the memory.
|
||||
protected string path;
|
||||
|
||||
// The depth of the memory.
|
||||
protected uint32_t depth;
|
||||
|
||||
// The width of the memory.
|
||||
protected uint32_t width;
|
||||
|
||||
// Indicates the error detection scheme implemented for this memory.
|
||||
protected err_detection_e err_detection_scheme = ErrDetectionNone;
|
||||
|
||||
// Convenience macro to check if ECC / parity is enabled.
|
||||
`define HAS_ECC (!(err_detection_scheme inside {ErrDetectionNone, ParityEven, ParityOdd}))
|
||||
`define HAS_PARITY (err_detection_scheme inside {ParityEven, ParityOdd})
|
||||
|
||||
// TODO: Indicates whether the memory implements scrambling.
|
||||
|
||||
// Other memory specifics derived from the settings above.
|
||||
protected uint32_t data_width; // ignoring ECC bits
|
||||
protected uint32_t byte_width;
|
||||
protected uint32_t bytes_per_word; // addressable bytes
|
||||
protected uint32_t size_bytes; // addressable bytes
|
||||
protected uint32_t addr_lsb;
|
||||
protected uint32_t addr_width;
|
||||
protected uint32_t byte_addr_width;
|
||||
|
||||
// Indicates the maximum number of errors that can be injected.
|
||||
//
|
||||
// If parity is enabled, this limit applies to a single byte in the memory width. We cannot inject
|
||||
// more than 1 error per each byte of data. In case of ECC, it applies to the entire width.
|
||||
protected uint32_t max_errors;
|
||||
|
||||
// File operations.
|
||||
//
|
||||
// We unfortunately cannot use the system tasks $readmemh and $writememh due to class based
|
||||
// implementation. This is done externally in the testbench module where the class instance is
|
||||
// created instead. The following signals and events are used by the testbench to know when to
|
||||
// read or write the memory with the contents of the file.
|
||||
protected string file;
|
||||
event readmemh_event;
|
||||
event writememh_event;
|
||||
|
||||
// Initialize the class instance.
|
||||
function new(string name = "", string path, int unsigned depth,
|
||||
longint unsigned n_bits, err_detection_e err_detection_scheme);
|
||||
|
||||
bit res;
|
||||
super.new(name);
|
||||
`DV_CHECK_FATAL(!(n_bits % depth), "n_bits must be divisible by depth.")
|
||||
res = uvm_hdl_check_path(path);
|
||||
`DV_CHECK_EQ_FATAL(res, 1, $sformatf("Hierarchical path %0s appears to be invalid.", path))
|
||||
|
||||
this.path = path;
|
||||
this.depth = depth;
|
||||
this.width = n_bits / depth;
|
||||
this.err_detection_scheme = err_detection_scheme;
|
||||
|
||||
if (`HAS_ECC) begin
|
||||
import prim_secded_pkg::prim_secded_e;
|
||||
import prim_secded_pkg::get_ecc_data_width;
|
||||
import prim_secded_pkg::get_ecc_parity_width;
|
||||
|
||||
prim_secded_e secded_eds = prim_secded_e'(err_detection_scheme);
|
||||
int non_ecc_bits_per_subword = get_ecc_data_width(secded_eds);
|
||||
int ecc_bits_per_subword = get_ecc_parity_width(secded_eds);
|
||||
int bits_per_subword = non_ecc_bits_per_subword + ecc_bits_per_subword;
|
||||
int subwords_per_word;
|
||||
|
||||
// We shouldn't truncate the actual data word. This check ensures that err_detection_scheme
|
||||
// and width are related sensibly. This only checks we've got enough space for one data word
|
||||
// and at least one check bit. The next check will make sure that we don't truncate if there
|
||||
// are multiple subwords.
|
||||
`DV_CHECK_FATAL(non_ecc_bits_per_subword < this.width)
|
||||
|
||||
// Normally, we'd want width to be divisible by bits_per_subword, which means that we get a
|
||||
// whole number of subwords in a word. As a special case, we also allow a having exactly one
|
||||
// subword and only keeping some of the bits. This is used by the flash controller.
|
||||
`DV_CHECK_FATAL((this.width < bits_per_subword) || (this.width % bits_per_subword == 0),
|
||||
"With multiple subwords, mem width must be a multiple of the ECC width")
|
||||
|
||||
subwords_per_word = (width + bits_per_subword - 1) / bits_per_subword;
|
||||
this.data_width = subwords_per_word * non_ecc_bits_per_subword;
|
||||
end else begin
|
||||
this.data_width = width;
|
||||
end
|
||||
|
||||
byte_width = `HAS_PARITY ? 9 : 8;
|
||||
bytes_per_word = data_width / byte_width;
|
||||
`DV_CHECK_LE_FATAL(bytes_per_word, 32, "data width > 32 bytes is not supported")
|
||||
size_bytes = depth * bytes_per_word;
|
||||
addr_lsb = $clog2(bytes_per_word);
|
||||
addr_width = $clog2(depth);
|
||||
byte_addr_width = addr_width + addr_lsb;
|
||||
max_errors = width;
|
||||
if (name == "") set_name({path, "::mem_bkdr_util"});
|
||||
`uvm_info(`gfn, this.convert2string(), UVM_MEDIUM)
|
||||
endfunction
|
||||
|
||||
virtual function string convert2string();
|
||||
return {"\n",
|
||||
$sformatf("path = %0s\n", path),
|
||||
$sformatf("depth = %0d\n", depth),
|
||||
$sformatf("width = %0d\n", width),
|
||||
$sformatf("err_detection_scheme = %0s\n", err_detection_scheme.name),
|
||||
$sformatf("data_width = %0d\n", data_width),
|
||||
$sformatf("byte_width = %0d\n", byte_width),
|
||||
$sformatf("bytes_per_word = %0d\n", bytes_per_word),
|
||||
$sformatf("size_bytes = 0x%0h\n", size_bytes),
|
||||
$sformatf("addr_lsb = %0d\n", addr_lsb),
|
||||
$sformatf("addr_width = %0d\n", addr_width),
|
||||
$sformatf("byte_addr_width = %0d\n", byte_addr_width),
|
||||
$sformatf("max_errors = %0d\n", max_errors)};
|
||||
endfunction
|
||||
|
||||
function string get_path();
|
||||
return path;
|
||||
endfunction
|
||||
|
||||
function uint32_t get_depth();
|
||||
return depth;
|
||||
endfunction
|
||||
|
||||
function uint32_t get_width();
|
||||
return width;
|
||||
endfunction
|
||||
|
||||
function err_detection_e get_err_detection_scheme();
|
||||
return err_detection_scheme;
|
||||
endfunction
|
||||
|
||||
function uint32_t get_data_width();
|
||||
return data_width;
|
||||
endfunction
|
||||
|
||||
function uint32_t get_byte_width();
|
||||
return byte_width;
|
||||
endfunction
|
||||
|
||||
function uint32_t get_bytes_per_word();
|
||||
return bytes_per_word;
|
||||
endfunction
|
||||
|
||||
function uint32_t get_size_bytes();
|
||||
return size_bytes;
|
||||
endfunction
|
||||
|
||||
function uint32_t get_addr_lsb();
|
||||
return addr_lsb;
|
||||
endfunction
|
||||
|
||||
function uint32_t get_addr_width();
|
||||
return addr_width;
|
||||
endfunction
|
||||
|
||||
function uint32_t get_byte_addr_width();
|
||||
return byte_addr_width;
|
||||
endfunction
|
||||
|
||||
function string get_file();
|
||||
return file;
|
||||
endfunction
|
||||
|
||||
// Returns 1 if the given address falls within the memory's range, else 0.
|
||||
//
|
||||
// If addr is invalid, it throws UVM error before returning 0.
|
||||
protected virtual function bit check_addr_valid(bit [bus_params_pkg::BUS_AW-1:0] addr);
|
||||
if (addr >= size_bytes) begin
|
||||
`uvm_error(`gfn, $sformatf("addr %0h is out of bounds: size = %0h", addr, size_bytes))
|
||||
return 1'b0;
|
||||
end
|
||||
return 1'b1;
|
||||
endfunction
|
||||
|
||||
// Read the entire word at the given address.
|
||||
//
|
||||
// addr is the byte address starting at offset 0. Mask the upper address bits as needed before
|
||||
// invocation.
|
||||
//
|
||||
// Returns the entire width of the memory at the given address, including the ECC bits. The data
|
||||
// returned is 'raw' i.e. it includes the parity bits. It also does not de-scramble the data if
|
||||
// encryption is enabled.
|
||||
//
|
||||
// TODO: Factor in encryption into this function itself?
|
||||
virtual function uvm_hdl_data_t read(bit [bus_params_pkg::BUS_AW-1:0] addr);
|
||||
bit res;
|
||||
uint32_t index;
|
||||
uvm_hdl_data_t data;
|
||||
if (!check_addr_valid(addr)) return 'x;
|
||||
index = addr >> addr_lsb;
|
||||
res = uvm_hdl_read($sformatf("%0s[%0d]", path, index), data);
|
||||
`DV_CHECK_EQ(res, 1, $sformatf("uvm_hdl_read failed at index %0d", index))
|
||||
return data;
|
||||
endfunction
|
||||
|
||||
// Convenience macro to check the addr for each flavor of read and write functions.
|
||||
`define _ACCESS_CHECKS(_ADDR, _DW) \
|
||||
`DV_CHECK_EQ_FATAL(_ADDR % (_DW / 8), 0, $sformatf("addr 0x%0h not ``_DW``-bit aligned", _ADDR))
|
||||
|
||||
// Read a single byte at specified address.
|
||||
//
|
||||
// The data returned does not include the parity bits.
|
||||
virtual function logic [7:0] read8(bit [bus_params_pkg::BUS_AW-1:0] addr);
|
||||
uvm_hdl_data_t data = read(addr);
|
||||
int byte_offset = addr % bytes_per_word;
|
||||
return (data >> (byte_offset * byte_width)) & 8'hff;
|
||||
endfunction
|
||||
|
||||
virtual function logic [15:0] read16(bit [bus_params_pkg::BUS_AW-1:0] addr);
|
||||
`_ACCESS_CHECKS(addr, 16)
|
||||
return {read8(addr + 1), read8(addr)};
|
||||
endfunction
|
||||
|
||||
virtual function logic [31:0] read32(bit [bus_params_pkg::BUS_AW-1:0] addr);
|
||||
`_ACCESS_CHECKS(addr, 32)
|
||||
return {read16(addr + 2), read16(addr)};
|
||||
endfunction
|
||||
|
||||
// this is used to read 32bit of data plus 7 raw integrity bits.
|
||||
virtual function logic [38:0] read39integ(bit [bus_params_pkg::BUS_AW-1:0] addr);
|
||||
`_ACCESS_CHECKS(addr, 32) // this is essentially an aligned 32bit access.
|
||||
return read(addr) & 39'h7fffffffff;
|
||||
endfunction
|
||||
|
||||
virtual function logic [63:0] read64(bit [bus_params_pkg::BUS_AW-1:0] addr);
|
||||
`_ACCESS_CHECKS(addr, 64)
|
||||
return {read32(addr + 4), read32(addr)};
|
||||
endfunction
|
||||
|
||||
virtual function logic [127:0] read128(bit [bus_params_pkg::BUS_AW-1:0] addr);
|
||||
`_ACCESS_CHECKS(addr, 128)
|
||||
return {read64(addr + 8), read64(addr)};
|
||||
endfunction
|
||||
|
||||
virtual function logic [255:0] read256(bit [bus_params_pkg::BUS_AW-1:0] addr);
|
||||
`_ACCESS_CHECKS(addr, 256)
|
||||
return {read128(addr + 16), read128(addr)};
|
||||
endfunction
|
||||
|
||||
// Write the entire word at the given address with the specified data.
|
||||
//
|
||||
// addr is the byte address starting at offset 0. Mask the upper address bits as needed before
|
||||
// invocation.
|
||||
//
|
||||
// Updates the entire width of the memory at the given address, including the ECC bits.
|
||||
virtual function void write(bit [bus_params_pkg::BUS_AW-1:0] addr, uvm_hdl_data_t data);
|
||||
bit res;
|
||||
uint32_t index;
|
||||
if (!check_addr_valid(addr)) return;
|
||||
index = addr >> addr_lsb;
|
||||
res = uvm_hdl_deposit($sformatf("%0s[%0d]", path, index), data);
|
||||
`DV_CHECK_EQ(res, 1, $sformatf("uvm_hdl_deposit failed at index %0d", index))
|
||||
endfunction
|
||||
|
||||
// Write a single byte at specified address.
|
||||
//
|
||||
// Does a read-modify-write on the whole word. It updates the byte at the given address and
|
||||
// computes the parity and ECC bits as applicable.
|
||||
virtual function void write8(bit [bus_params_pkg::BUS_AW-1:0] addr, logic [7:0] data);
|
||||
uvm_hdl_data_t rw_data;
|
||||
uint32_t word_idx;
|
||||
uint32_t byte_idx;
|
||||
|
||||
if (!check_addr_valid(addr)) return;
|
||||
|
||||
rw_data = read(addr);
|
||||
word_idx = addr >> addr_lsb;
|
||||
byte_idx = addr - (word_idx << addr_lsb);
|
||||
|
||||
if (`HAS_PARITY) begin
|
||||
bit parity = (err_detection_scheme == ParityOdd) ? ~(^data) : (^data);
|
||||
rw_data[byte_idx * 9 +: 9] = {parity, data};
|
||||
write(addr, rw_data);
|
||||
return;
|
||||
end
|
||||
|
||||
rw_data[byte_idx * 8 +: 8] = data;
|
||||
case (err_detection_scheme)
|
||||
ErrDetectionNone: ;
|
||||
Ecc_22_16: begin
|
||||
rw_data = prim_secded_pkg::prim_secded_22_16_enc(rw_data[15:0]);
|
||||
end
|
||||
EccHamming_22_16: begin
|
||||
rw_data = prim_secded_pkg::prim_secded_hamming_22_16_enc(rw_data[15:0]);
|
||||
end
|
||||
Ecc_39_32: begin
|
||||
rw_data = prim_secded_pkg::prim_secded_39_32_enc(rw_data[31:0]);
|
||||
end
|
||||
EccHamming_39_32: begin
|
||||
rw_data = prim_secded_pkg::prim_secded_hamming_39_32_enc(rw_data[31:0]);
|
||||
end
|
||||
Ecc_72_64: begin
|
||||
rw_data = prim_secded_pkg::prim_secded_72_64_enc(rw_data[63:0]);
|
||||
end
|
||||
EccHamming_72_64: begin
|
||||
rw_data = prim_secded_pkg::prim_secded_hamming_72_64_enc(rw_data[63:0]);
|
||||
end
|
||||
EccHamming_76_68: begin
|
||||
rw_data = prim_secded_pkg::prim_secded_hamming_76_68_enc(rw_data[63:0]);
|
||||
end
|
||||
default: begin
|
||||
`uvm_error(`gfn, $sformatf("ECC scheme %0s is unsupported.", err_detection_scheme))
|
||||
end
|
||||
endcase
|
||||
write(addr, rw_data);
|
||||
endfunction
|
||||
|
||||
virtual function void write16(bit [bus_params_pkg::BUS_AW-1:0] addr, logic [15:0] data);
|
||||
`_ACCESS_CHECKS(addr, 16)
|
||||
if (!check_addr_valid(addr)) return;
|
||||
write8(addr, data[7:0]);
|
||||
write8(addr + 1, data[15:8]);
|
||||
endfunction
|
||||
|
||||
virtual function void write32(bit [bus_params_pkg::BUS_AW-1:0] addr, logic [31:0] data);
|
||||
`_ACCESS_CHECKS(addr, 32)
|
||||
if (!check_addr_valid(addr)) return;
|
||||
write16(addr, data[15:0]);
|
||||
write16(addr + 2, data[31:16]);
|
||||
endfunction
|
||||
|
||||
// this is used to write 32bit of data plus 7 raw integrity bits.
|
||||
virtual function void write39integ(bit [bus_params_pkg::BUS_AW-1:0] addr, logic [38:0] data);
|
||||
`_ACCESS_CHECKS(addr, 32) // this is essentially an aligned 32bit access.
|
||||
if (!check_addr_valid(addr)) return;
|
||||
write(addr, data);
|
||||
endfunction
|
||||
|
||||
virtual function void write64(bit [bus_params_pkg::BUS_AW-1:0] addr, logic [63:0] data);
|
||||
`_ACCESS_CHECKS(addr, 64)
|
||||
if (!check_addr_valid(addr)) return;
|
||||
write32(addr, data[31:0]);
|
||||
write32(addr + 4, data[63:32]);
|
||||
endfunction
|
||||
|
||||
virtual function void write128(bit [bus_params_pkg::BUS_AW-1:0] addr, logic [127:0] data);
|
||||
`_ACCESS_CHECKS(addr, 128)
|
||||
if (!check_addr_valid(addr)) return;
|
||||
write64(addr, data[63:0]);
|
||||
write64(addr + 8, data[127:63]);
|
||||
endfunction
|
||||
|
||||
virtual function void write256(bit [bus_params_pkg::BUS_AW-1:0] addr, logic [255:0] data);
|
||||
`_ACCESS_CHECKS(addr, 256)
|
||||
if (!check_addr_valid(addr)) return;
|
||||
write128(addr, data[127:0]);
|
||||
write128(addr + 16, data[255:128]);
|
||||
endfunction
|
||||
|
||||
`undef _ACCESS_CHECKS
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
// Wrapper functions for memory reads with ECC enabled //
|
||||
/////////////////////////////////////////////////////////
|
||||
// Some notes:
|
||||
// - ECC isn't supported for 8-bit wide memories
|
||||
// - (28, 22) and (64, 57) ECC configurations aren't supported
|
||||
|
||||
// Intended for use with memories which have data width of 16 bits and 6 ECC bits.
|
||||
virtual function secded_22_16_t ecc_read16(bit [bus_params_pkg::BUS_AW-1:0] addr);
|
||||
uvm_hdl_data_t data;
|
||||
if (!check_addr_valid(addr)) return 'x;
|
||||
data = read(addr);
|
||||
case (err_detection_scheme)
|
||||
Ecc_22_16: begin
|
||||
return prim_secded_pkg::prim_secded_22_16_dec(data);
|
||||
end
|
||||
EccHamming_22_16: begin
|
||||
return prim_secded_pkg::prim_secded_hamming_22_16_dec(data);
|
||||
end
|
||||
default: return 'x;
|
||||
endcase
|
||||
endfunction
|
||||
|
||||
// Intended for use with memories which have data width of 32 bits and 7 ECC bits.
|
||||
virtual function secded_39_32_t ecc_read32(bit [bus_params_pkg::BUS_AW-1:0] addr);
|
||||
uvm_hdl_data_t data;
|
||||
if (!check_addr_valid(addr)) return 'x;
|
||||
data = read(addr);
|
||||
case (err_detection_scheme)
|
||||
Ecc_39_32: begin
|
||||
return prim_secded_pkg::prim_secded_39_32_dec(data);
|
||||
end
|
||||
EccHamming_39_32: begin
|
||||
return prim_secded_pkg::prim_secded_hamming_39_32_dec(data);
|
||||
end
|
||||
default: return 'x;
|
||||
endcase
|
||||
endfunction
|
||||
|
||||
// Intended for use with memories which have data width of 64 bits and 8 ECC bits.
|
||||
virtual function secded_72_64_t ecc_read64(bit [bus_params_pkg::BUS_AW-1:0] addr);
|
||||
uvm_hdl_data_t data;
|
||||
if (!check_addr_valid(addr)) return 'x;
|
||||
data = read(addr);
|
||||
case (err_detection_scheme)
|
||||
Ecc_72_64: begin
|
||||
return prim_secded_pkg::prim_secded_72_64_dec(data);
|
||||
end
|
||||
EccHamming_72_64: begin
|
||||
return prim_secded_pkg::prim_secded_hamming_72_64_dec(data);
|
||||
end
|
||||
default: return 'x;
|
||||
endcase
|
||||
endfunction
|
||||
|
||||
// check if input file is read/writable
|
||||
virtual function void check_file(string file, string mode);
|
||||
int fh = $fopen(file, mode);
|
||||
if (!fh) begin
|
||||
`uvm_fatal(`gfn, $sformatf("file %0s could not be opened for %0s mode", file, mode))
|
||||
end
|
||||
$fclose(fh);
|
||||
endfunction
|
||||
|
||||
// load mem from file
|
||||
virtual function void load_mem_from_file(string file);
|
||||
check_file(file, "r");
|
||||
this.file = file;
|
||||
->readmemh_event;
|
||||
endfunction
|
||||
|
||||
// save mem contents to file
|
||||
virtual function void write_mem_to_file(string file);
|
||||
check_file(file, "w");
|
||||
this.file = file;
|
||||
->writememh_event;
|
||||
endfunction
|
||||
|
||||
// print mem
|
||||
virtual function void print_mem();
|
||||
for (int i = 0; i < depth; i++) begin
|
||||
`uvm_info(`gfn, $sformatf("mem[%0d] = 0x%0h", i, read(i)), UVM_LOW)
|
||||
end
|
||||
endfunction
|
||||
|
||||
// clear or set memory
|
||||
virtual function void clear_mem();
|
||||
`uvm_info(`gfn, "Clear memory", UVM_LOW)
|
||||
for (int i = 0; i < size_bytes; i++) begin
|
||||
write8(i, '0);
|
||||
end
|
||||
endfunction
|
||||
|
||||
virtual function void set_mem();
|
||||
`uvm_info(`gfn, "Set memory", UVM_LOW)
|
||||
for (int i = 0; i < size_bytes; i++) begin
|
||||
write8(i, '1);
|
||||
end
|
||||
endfunction
|
||||
|
||||
// randomize the memory
|
||||
virtual function void randomize_mem();
|
||||
logic [7:0] rand_val;
|
||||
`uvm_info(`gfn, "Randomizing mem contents", UVM_LOW)
|
||||
for (int i = 0; i < size_bytes; i++) begin
|
||||
`DV_CHECK_STD_RANDOMIZE_FATAL(rand_val, "Randomization failed!", path)
|
||||
write8(i, rand_val);
|
||||
end
|
||||
endfunction
|
||||
|
||||
// invalidate the memory.
|
||||
virtual function void invalidate_mem();
|
||||
`uvm_info(`gfn, "Invalidating (Xs) mem contents", UVM_LOW)
|
||||
for (int i = 0; i < size_bytes; i++) begin
|
||||
write8(i, 'x);
|
||||
end
|
||||
endfunction
|
||||
|
||||
// Inject ECC or parity errors to the memory word at the given address.
|
||||
virtual function void inject_errors(bit [bus_params_pkg::BUS_AW-1:0] addr,
|
||||
uint32_t inject_num_errors);
|
||||
uvm_hdl_data_t rw_data, err_mask;
|
||||
if (!check_addr_valid(addr)) return;
|
||||
`DV_CHECK_LE_FATAL(inject_num_errors, max_errors)
|
||||
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(err_mask,
|
||||
$countones(err_mask) == inject_num_errors;
|
||||
(err_mask >> width) == '0;)
|
||||
rw_data = read(addr);
|
||||
write(addr, rw_data ^ err_mask);
|
||||
`uvm_info(`gfn, $sformatf(
|
||||
"Addr: %0h, original data: %0h, error_mask: %0h, backdoor inject data: %0h",
|
||||
addr, rw_data, err_mask, rw_data ^ err_mask), UVM_HIGH)
|
||||
endfunction
|
||||
|
||||
// Wrapper function for backdoor write OTP partitions.
|
||||
`include "mem_bkdr_util__otp.sv"
|
||||
|
||||
// Wrapper functions for encrypted SRAM reads and writes.
|
||||
`include "mem_bkdr_util__sram.sv"
|
||||
|
||||
// Wrapper function for encrypted ROM reads.
|
||||
`include "mem_bkdr_util__rom.sv"
|
||||
|
||||
`undef HAS_ECC
|
||||
`undef HAS_PARITY
|
||||
|
||||
endclass
|
||||
|
||||
// Convenience macro to enable file operations on the memory.
|
||||
//
|
||||
// The class based approach prevents us from invoking the system tasks $readmemh and $writememh
|
||||
// directly. This macro is invoked in the top level testbench where the instance of the backdoor
|
||||
// accessor is created, within an initial block. It forks off two threads that monitor separately
|
||||
// events when the UVM sequences invoke either the task `load_mem_from_file()` to write to the
|
||||
// memory with the contents of the file and `write_mem_to_file()` methods, to read the contents of
|
||||
// the memory into the file.
|
||||
//
|
||||
// inst is the mem_bkdr_util instance created in the tesbench module.
|
||||
// path is the raw path to the memory element in the design.
|
||||
`define MEM_BKDR_UTIL_FILE_OP(inst, path) \
|
||||
fork \
|
||||
forever begin \
|
||||
string file; \
|
||||
@(inst.readmemh_event); \
|
||||
file = inst.get_file(); \
|
||||
`uvm_info(inst.`gfn, $sformatf("Loading mem from file:\n%0s", file), UVM_LOW) \
|
||||
$readmemh(file, path); \
|
||||
end \
|
||||
forever begin \
|
||||
string file; \
|
||||
@(inst.writememh_event); \
|
||||
file = inst.get_file(); \
|
||||
`uvm_info(inst.`gfn, $sformatf("Writing mem to file:\n%0s", file), UVM_LOW) \
|
||||
$writememh(file, path); \
|
||||
end \
|
||||
join_none
|
40
vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util__otp.sv
vendored
Normal file
40
vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util__otp.sv
vendored
Normal file
|
@ -0,0 +1,40 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Wrapper functions to write different partitions in OTP.
|
||||
// This file is included in `mem_bkdr_util.sv` as a continuation of `mem_bkdr_util` class.
|
||||
|
||||
virtual function void otp_write_lc_partition(lc_ctrl_state_pkg::lc_state_e lc_state);
|
||||
for (int i = 0; i < LcStateSize; i+=4) begin
|
||||
write32(i + LcStateOffset, lc_state[i*8+:32]);
|
||||
end
|
||||
endfunction
|
||||
|
||||
// The following steps are needed to backdoor write a secret partition:
|
||||
// 1). Scramble the RAW input data.
|
||||
// 2). Backdoor write the scrambled input data to OTP memory.
|
||||
// 3). Calculate the correct digest for the secret partition.
|
||||
// 4). Backdoor write digest data to OTP memory.
|
||||
virtual function void otp_write_secret0_partition(bit [TestUnlockTokenSize*8-1:0] unlock_token,
|
||||
bit [TestExitTokenSize*8-1:0] exit_token);
|
||||
bit [Secret0DigestSize*8-1:0] digest;
|
||||
|
||||
bit [TestUnlockTokenSize*8-1:0] scrambled_unlock_token;
|
||||
bit [TestExitTokenSize*8-1:0] scrambled_exit_token;
|
||||
bit [bus_params_pkg::BUS_DW-1:0] secret_data[$];
|
||||
|
||||
for (int i = 0; i < TestUnlockTokenSize; i+=8) begin
|
||||
scrambled_unlock_token[i*8+:64] = scramble_data(unlock_token[i*8+:64], Secret0Idx);
|
||||
write64(i + TestUnlockTokenOffset, scrambled_unlock_token[i*8+:64]);
|
||||
end
|
||||
for (int i = 0; i < TestExitTokenSize; i+=8) begin
|
||||
scrambled_exit_token[i*8+:64] = scramble_data(exit_token[i*8+:64], Secret0Idx);
|
||||
write64(i + TestExitTokenOffset, scrambled_exit_token[i*8+:64]);
|
||||
end
|
||||
|
||||
secret_data = {<<32 {scrambled_exit_token, scrambled_unlock_token}};
|
||||
digest = cal_digest(Secret0Idx, secret_data);
|
||||
|
||||
write64(Secret0DigestOffset, digest);
|
||||
endfunction
|
68
vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util__rom.sv
vendored
Normal file
68
vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util__rom.sv
vendored
Normal file
|
@ -0,0 +1,68 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Wrapper functions for ROM's encrypted read operation.
|
||||
// This file is included in `mem_bkdr_util.sv` as a continuation of `mem_bkdr_util` class.
|
||||
|
||||
// The data decoding is different from SRAM, but most of the underlying SRAM functions are reused
|
||||
// Also note that this function returns the raw data rather than data + syndrome + error because
|
||||
// the rom_ctrl testbench needs this for checking.
|
||||
virtual function bit [38:0] rom_encrypt_read32(bit [bus_params_pkg::BUS_AW-1:0] addr,
|
||||
logic [SRAM_KEY_WIDTH-1:0] key,
|
||||
logic [SRAM_BLOCK_WIDTH-1:0] nonce,
|
||||
bit unscramble_data);
|
||||
|
||||
logic [bus_params_pkg::BUS_AW-1:0] mem_addr = '0;
|
||||
logic [38:0] data = '0;
|
||||
|
||||
logic addr_arr [] = new[addr_width];
|
||||
logic scrambled_addr[] = new[addr_width];
|
||||
logic data_arr [] = new[39];
|
||||
logic key_arr [] = new[SRAM_KEY_WIDTH];
|
||||
logic nonce_arr [] = new[SRAM_BLOCK_WIDTH];
|
||||
logic keystream [] = new[SRAM_BLOCK_WIDTH];
|
||||
logic zero_key [] = new[39];
|
||||
|
||||
key_arr = {<<{key}};
|
||||
nonce_arr = {<<{nonce}};
|
||||
|
||||
for (int i = 0; i < addr_width; i++) begin
|
||||
addr_arr[i] = addr[addr_lsb + i];
|
||||
end
|
||||
|
||||
// Calculate the scrambled address
|
||||
scrambled_addr = sram_scrambler_pkg::encrypt_sram_addr(addr_arr, addr_width, nonce_arr);
|
||||
|
||||
for (int i = 0; i < addr_width; i++) begin
|
||||
mem_addr[i] = scrambled_addr[i];
|
||||
end
|
||||
|
||||
// Read memory and get the encrypted data
|
||||
if (!check_addr_valid(mem_addr << addr_lsb)) begin
|
||||
return 'x;
|
||||
end
|
||||
|
||||
// 39-bit memory word includes 32-bit data + 7-bit ECC
|
||||
data = read(mem_addr << addr_lsb);
|
||||
|
||||
if (!unscramble_data) begin
|
||||
return data;
|
||||
end
|
||||
|
||||
data_arr = {<<{data}};
|
||||
|
||||
// Generate the keystream
|
||||
keystream = sram_scrambler_pkg::gen_keystream(addr_arr, addr_width, key_arr, nonce_arr);
|
||||
|
||||
for (int i = 0; i < 39; i++) begin
|
||||
zero_key[i] = '0;
|
||||
end
|
||||
|
||||
data_arr = sram_scrambler_pkg::sp_decrypt(data_arr, 39, zero_key);
|
||||
for (int i = 0; i < 39; i++) begin
|
||||
data[i] = data_arr[i] ^ keystream[i];
|
||||
end
|
||||
|
||||
return data;
|
||||
endfunction
|
423
vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util__sram.sv
vendored
Normal file
423
vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util__sram.sv
vendored
Normal file
|
@ -0,0 +1,423 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Wrapper functions for SRAM's encrypted read/write operations.
|
||||
// This file is included in `mem_bkdr_util.sv` as a continuation of `mem_bkdr_util` class.
|
||||
|
||||
virtual function logic [7:0] sram_encrypt_read8(logic [bus_params_pkg::BUS_AW-1:0] addr,
|
||||
logic [SRAM_KEY_WIDTH-1:0] key,
|
||||
logic [SRAM_BLOCK_WIDTH-1:0] nonce);
|
||||
logic [bus_params_pkg::BUS_AW-1:0] bus_addr = '0;
|
||||
logic [7:0] rdata = '0;
|
||||
|
||||
logic rdata_arr [] = new[8];
|
||||
logic scrambled_addr[] = new[addr_width];
|
||||
logic sram_addr [] = new[addr_width];
|
||||
logic key_arr [] = new[SRAM_KEY_WIDTH];
|
||||
logic nonce_arr [] = new[SRAM_BLOCK_WIDTH];
|
||||
|
||||
key_arr = {<<{key}};
|
||||
nonce_arr = {<<{nonce}};
|
||||
|
||||
for (int i = 0; i < addr_width; i++) begin
|
||||
sram_addr[i] = addr[addr_lsb + i];
|
||||
end
|
||||
|
||||
// Calculate the scrambled address
|
||||
scrambled_addr = sram_scrambler_pkg::encrypt_sram_addr(sram_addr, addr_width, nonce_arr);
|
||||
|
||||
// Construct bus representation of the address
|
||||
for (int i = 0; i < addr_lsb; i++) begin
|
||||
bus_addr[i] = addr[i];
|
||||
end
|
||||
for (int i = 0; i < addr_width; i++) begin
|
||||
bus_addr[addr_lsb + i] = scrambled_addr[i];
|
||||
end
|
||||
|
||||
// Read memory, and return the decrypted data
|
||||
rdata = read8(bus_addr);
|
||||
rdata_arr = {<<{rdata}};
|
||||
rdata_arr = sram_scrambler_pkg::decrypt_sram_data(
|
||||
rdata_arr, 8, 1, sram_addr, addr_width, key_arr, nonce_arr
|
||||
);
|
||||
rdata = {<<{rdata_arr}};
|
||||
return rdata;
|
||||
endfunction
|
||||
|
||||
virtual function logic [15:0] sram_encrypt_read16(logic [bus_params_pkg::BUS_AW-1:0] addr,
|
||||
logic [SRAM_KEY_WIDTH-1:0] key,
|
||||
logic [SRAM_BLOCK_WIDTH-1:0] nonce);
|
||||
logic [bus_params_pkg::BUS_AW-1:0] bus_addr = '0;
|
||||
logic [15:0] rdata = '0;
|
||||
|
||||
logic rdata_arr [] = new[16];
|
||||
logic scrambled_addr[] = new[addr_width];
|
||||
logic sram_addr [] = new[addr_width];
|
||||
logic key_arr [] = new[SRAM_KEY_WIDTH];
|
||||
logic nonce_arr [] = new[SRAM_BLOCK_WIDTH];
|
||||
|
||||
key_arr = {<<{key}};
|
||||
nonce_arr = {<<{nonce}};
|
||||
|
||||
for (int i = 0; i < addr_width; i++) begin
|
||||
sram_addr[i] = addr[addr_lsb + i];
|
||||
end
|
||||
|
||||
// Calculate the scrambled address
|
||||
scrambled_addr = sram_scrambler_pkg::encrypt_sram_addr(sram_addr, addr_width, nonce_arr);
|
||||
|
||||
// Construct bus representation of the address
|
||||
for (int i = 0; i < addr_lsb; i++) begin
|
||||
bus_addr[i] = addr[i];
|
||||
end
|
||||
for (int i = 0; i < addr_width; i++) begin
|
||||
bus_addr[addr_lsb + i] = scrambled_addr[i];
|
||||
end
|
||||
|
||||
// Read memory and return the decrypted data
|
||||
rdata = read16(bus_addr);
|
||||
rdata_arr = {<<{rdata}};
|
||||
rdata_arr = sram_scrambler_pkg::decrypt_sram_data(
|
||||
rdata_arr, 16, 1, sram_addr, addr_width, key_arr, nonce_arr
|
||||
);
|
||||
rdata = {<<{rdata_arr}};
|
||||
return rdata;
|
||||
endfunction
|
||||
|
||||
virtual function logic [31:0] sram_encrypt_read32(logic [bus_params_pkg::BUS_AW-1:0] addr,
|
||||
logic [SRAM_KEY_WIDTH-1:0] key,
|
||||
logic [SRAM_BLOCK_WIDTH-1:0] nonce);
|
||||
logic [bus_params_pkg::BUS_AW-1:0] bus_addr = '0;
|
||||
logic [31:0] rdata = '0;
|
||||
|
||||
logic rdata_arr [] = new[32];
|
||||
logic scrambled_addr[] = new[addr_width];
|
||||
logic sram_addr [] = new[addr_width];
|
||||
logic key_arr [] = new[SRAM_KEY_WIDTH];
|
||||
logic nonce_arr [] = new[SRAM_BLOCK_WIDTH];
|
||||
|
||||
key_arr = {<<{key}};
|
||||
nonce_arr = {<<{nonce}};
|
||||
for (int i = 0; i < addr_width; i++) begin
|
||||
sram_addr[i] = addr[addr_lsb + i];
|
||||
end
|
||||
|
||||
// Calculate the scrambled address
|
||||
scrambled_addr = sram_scrambler_pkg::encrypt_sram_addr(sram_addr, addr_width, nonce_arr);
|
||||
|
||||
// Construct bus representation of the address
|
||||
for (int i = 0; i < addr_lsb; i++) begin
|
||||
bus_addr[i] = addr[i];
|
||||
end
|
||||
for (int i = 0; i < addr_width; i++) begin
|
||||
bus_addr[addr_lsb + i] = scrambled_addr[i];
|
||||
end
|
||||
|
||||
// Read memory and return the decrypted data
|
||||
rdata = read32(bus_addr);
|
||||
rdata_arr = {<<{rdata}};
|
||||
rdata_arr = sram_scrambler_pkg::decrypt_sram_data(
|
||||
rdata_arr, 32, 1, sram_addr, addr_width, key_arr, nonce_arr
|
||||
);
|
||||
rdata = {<<{rdata_arr}};
|
||||
return rdata;
|
||||
|
||||
endfunction
|
||||
|
||||
virtual function logic [38:0] sram_encrypt_read32_integ(logic [bus_params_pkg::BUS_AW-1:0] addr,
|
||||
logic [SRAM_KEY_WIDTH-1:0] key,
|
||||
logic [SRAM_BLOCK_WIDTH-1:0] nonce);
|
||||
logic [bus_params_pkg::BUS_AW-1:0] bus_addr = '0;
|
||||
logic [38:0] rdata = '0;
|
||||
|
||||
logic rdata_arr [] = new[39];
|
||||
logic scrambled_addr[] = new[addr_width];
|
||||
logic sram_addr [] = new[addr_width];
|
||||
logic key_arr [] = new[SRAM_KEY_WIDTH];
|
||||
logic nonce_arr [] = new[SRAM_BLOCK_WIDTH];
|
||||
|
||||
key_arr = {<<{key}};
|
||||
nonce_arr = {<<{nonce}};
|
||||
for (int i = 0; i < addr_width; i++) begin
|
||||
sram_addr[i] = addr[addr_lsb + i];
|
||||
end
|
||||
|
||||
// Calculate the scrambled address
|
||||
scrambled_addr = sram_scrambler_pkg::encrypt_sram_addr(sram_addr, addr_width, nonce_arr);
|
||||
|
||||
// Construct bus representation of the address
|
||||
for (int i = 0; i < addr_lsb; i++) begin
|
||||
bus_addr[i] = addr[i];
|
||||
end
|
||||
for (int i = 0; i < addr_width; i++) begin
|
||||
bus_addr[addr_lsb + i] = scrambled_addr[i];
|
||||
end
|
||||
|
||||
// Read memory and return the decrypted data
|
||||
rdata = read39integ(bus_addr);
|
||||
`uvm_info(`gfn, $sformatf("scr data: 0x%0x", rdata), UVM_HIGH)
|
||||
rdata_arr = {<<{rdata}};
|
||||
rdata_arr = sram_scrambler_pkg::decrypt_sram_data(
|
||||
rdata_arr, 39, 0, sram_addr, addr_width, key_arr, nonce_arr
|
||||
);
|
||||
rdata = {<<{rdata_arr}};
|
||||
// Only return the data payload without ECC bits.
|
||||
return rdata[31:0];
|
||||
|
||||
endfunction
|
||||
|
||||
virtual function logic [63:0] sram_encrypt_read64(logic [bus_params_pkg::BUS_AW-1:0] addr,
|
||||
logic [SRAM_KEY_WIDTH-1:0] key,
|
||||
logic [SRAM_BLOCK_WIDTH-1:0] nonce);
|
||||
logic [bus_params_pkg::BUS_AW-1:0] bus_addr = '0;
|
||||
logic [63:0] rdata = '0;
|
||||
|
||||
logic rdata_arr [] = new[64];
|
||||
logic scrambled_addr[] = new[addr_width];
|
||||
logic sram_addr [] = new[addr_width];
|
||||
logic key_arr [] = new[SRAM_KEY_WIDTH];
|
||||
logic nonce_arr [] = new[SRAM_BLOCK_WIDTH];
|
||||
|
||||
key_arr = {<<{key}};
|
||||
nonce_arr = {<<{nonce}};
|
||||
|
||||
for (int i = 0; i < addr_width; i++) begin
|
||||
sram_addr[i] = addr[addr_lsb + i];
|
||||
end
|
||||
|
||||
// Calculate the scrambled address
|
||||
scrambled_addr = sram_scrambler_pkg::encrypt_sram_addr(sram_addr, addr_width, nonce_arr);
|
||||
|
||||
// Construct bus representation of the address
|
||||
for (int i = 0; i < addr_lsb; i++) begin
|
||||
bus_addr[i] = addr[i];
|
||||
end
|
||||
for (int i = 0; i < addr_width; i++) begin
|
||||
bus_addr[addr_lsb + i] = scrambled_addr[i];
|
||||
end
|
||||
|
||||
// Read memory and return the decrypted data
|
||||
rdata = read64(bus_addr);
|
||||
rdata_arr = {<<{rdata}};
|
||||
rdata_arr = sram_scrambler_pkg::decrypt_sram_data(
|
||||
rdata_arr, 64, 1, sram_addr, addr_width, key_arr, nonce_arr
|
||||
);
|
||||
rdata = {<<{rdata_arr}};
|
||||
return rdata;
|
||||
|
||||
endfunction
|
||||
|
||||
virtual function void sram_encrypt_write8(logic [bus_params_pkg::BUS_AW-1:0] addr,
|
||||
logic [7:0] data,
|
||||
logic [SRAM_KEY_WIDTH-1:0] key,
|
||||
logic [SRAM_BLOCK_WIDTH-1:0] nonce);
|
||||
logic [bus_params_pkg::BUS_AW-1:0] bus_addr = '0;
|
||||
logic [7:0] scrambled_data;
|
||||
|
||||
logic wdata_arr [] = new[8];
|
||||
logic scrambled_addr [] = new[addr_width];
|
||||
logic sram_addr [] = new[addr_width];
|
||||
logic key_arr [] = new[SRAM_KEY_WIDTH];
|
||||
logic nonce_arr [] = new[SRAM_BLOCK_WIDTH];
|
||||
|
||||
key_arr = {<<{key}};
|
||||
nonce_arr = {<<{nonce}};
|
||||
|
||||
for (int i = 0; i < addr_width; i++) begin
|
||||
sram_addr[i] = addr[addr_lsb + i];
|
||||
end
|
||||
|
||||
// Calculate the scrambled address
|
||||
scrambled_addr = sram_scrambler_pkg::encrypt_sram_addr(sram_addr, addr_width, nonce_arr);
|
||||
|
||||
// Calculate the scrambled data
|
||||
wdata_arr = {<<{data}};
|
||||
wdata_arr = sram_scrambler_pkg::encrypt_sram_data(
|
||||
wdata_arr, 8, 1, sram_addr, addr_width, key_arr, nonce_arr
|
||||
);
|
||||
scrambled_data = {<<{wdata_arr}};
|
||||
|
||||
// Construct bus representation of the address
|
||||
for (int i = 0; i < addr_lsb; i++) begin
|
||||
bus_addr[i] = addr[i];
|
||||
end
|
||||
for (int i = 0; i < addr_width; i++) begin
|
||||
bus_addr[addr_lsb + i] = scrambled_addr[i];
|
||||
end
|
||||
|
||||
// Write the scrambled data to memory
|
||||
write8(bus_addr, scrambled_data);
|
||||
endfunction
|
||||
|
||||
virtual function void sram_encrypt_write16(logic [bus_params_pkg::BUS_AW-1:0] addr,
|
||||
logic [15:0] data,
|
||||
logic [SRAM_KEY_WIDTH-1:0] key,
|
||||
logic [SRAM_BLOCK_WIDTH-1:0] nonce);
|
||||
logic [bus_params_pkg::BUS_AW-1:0] bus_addr = '0;
|
||||
logic [15:0] scrambled_data;
|
||||
|
||||
logic wdata_arr [] = new[16];
|
||||
logic scrambled_addr [] = new[addr_width];
|
||||
logic sram_addr [] = new[addr_width];
|
||||
logic key_arr [] = new[SRAM_KEY_WIDTH];
|
||||
logic nonce_arr [] = new[SRAM_BLOCK_WIDTH];
|
||||
|
||||
key_arr = {<<{key}};
|
||||
nonce_arr = {<<{nonce}};
|
||||
|
||||
for (int i = 0; i < addr_width; i++) begin
|
||||
sram_addr[i] = addr[addr_lsb + i];
|
||||
end
|
||||
|
||||
// Calculate the scrambled address
|
||||
scrambled_addr = sram_scrambler_pkg::encrypt_sram_addr(sram_addr, addr_width, nonce_arr);
|
||||
|
||||
// Calculate the scrambled data
|
||||
wdata_arr = {<<{data}};
|
||||
wdata_arr = sram_scrambler_pkg::encrypt_sram_data(
|
||||
wdata_arr, 16, 1, sram_addr, addr_width, key_arr, nonce_arr
|
||||
);
|
||||
scrambled_data = {<<{wdata_arr}};
|
||||
|
||||
// Construct bus representation of the address
|
||||
for (int i = 0; i < addr_lsb; i++) begin
|
||||
bus_addr[i] = addr[i];
|
||||
end
|
||||
for (int i = 0; i < addr_width; i++) begin
|
||||
bus_addr[addr_lsb + i] = scrambled_addr[i];
|
||||
end
|
||||
|
||||
// Write the scrambled data to memory
|
||||
write16(bus_addr, scrambled_data);
|
||||
endfunction
|
||||
|
||||
virtual function void sram_encrypt_write32(logic [bus_params_pkg::BUS_AW-1:0] addr,
|
||||
logic [31:0] data,
|
||||
logic [SRAM_KEY_WIDTH-1:0] key,
|
||||
logic [SRAM_BLOCK_WIDTH-1:0] nonce);
|
||||
logic [bus_params_pkg::BUS_AW-1:0] bus_addr = '0;
|
||||
logic [31:0] scrambled_data;
|
||||
|
||||
logic wdata_arr [] = new[32];
|
||||
logic scrambled_addr [] = new[addr_width];
|
||||
logic sram_addr [] = new[addr_width];
|
||||
logic key_arr [] = new[SRAM_KEY_WIDTH];
|
||||
logic nonce_arr [] = new[SRAM_BLOCK_WIDTH];
|
||||
|
||||
key_arr = {<<{key}};
|
||||
nonce_arr = {<<{nonce}};
|
||||
|
||||
for (int i = 0; i < addr_width; i++) begin
|
||||
sram_addr[i] = addr[addr_lsb + i];
|
||||
end
|
||||
|
||||
// Calculate the scrambled address
|
||||
scrambled_addr = sram_scrambler_pkg::encrypt_sram_addr(sram_addr, addr_width, nonce_arr);
|
||||
|
||||
// Calculate the scrambled data
|
||||
wdata_arr = {<<{data}};
|
||||
wdata_arr = sram_scrambler_pkg::encrypt_sram_data(
|
||||
wdata_arr, 32, 1, sram_addr, addr_width, key_arr, nonce_arr
|
||||
);
|
||||
scrambled_data = {<<{wdata_arr}};
|
||||
|
||||
// Construct bus representation of the address
|
||||
for (int i = 0; i < addr_lsb; i++) begin
|
||||
bus_addr[i] = addr[i];
|
||||
end
|
||||
for (int i = 0; i < addr_width; i++) begin
|
||||
bus_addr[addr_lsb + i] = scrambled_addr[i];
|
||||
end
|
||||
|
||||
// Write the scrambled data to memory
|
||||
write32(bus_addr, scrambled_data);
|
||||
endfunction
|
||||
|
||||
virtual function void sram_encrypt_write32_integ(logic [bus_params_pkg::BUS_AW-1:0] addr,
|
||||
logic [31:0] data,
|
||||
logic [SRAM_KEY_WIDTH-1:0] key,
|
||||
logic [SRAM_BLOCK_WIDTH-1:0] nonce);
|
||||
logic [bus_params_pkg::BUS_AW-1:0] bus_addr = '0;
|
||||
logic [38:0] integ_data;
|
||||
logic [38:0] scrambled_data;
|
||||
|
||||
logic wdata_arr [] = new[39];
|
||||
logic scrambled_addr [] = new[addr_width];
|
||||
logic sram_addr [] = new[addr_width];
|
||||
logic key_arr [] = new[SRAM_KEY_WIDTH];
|
||||
logic nonce_arr [] = new[SRAM_BLOCK_WIDTH];
|
||||
|
||||
key_arr = {<<{key}};
|
||||
nonce_arr = {<<{nonce}};
|
||||
|
||||
for (int i = 0; i < addr_width; i++) begin
|
||||
sram_addr[i] = addr[addr_lsb + i];
|
||||
end
|
||||
|
||||
// Calculate the scrambled address
|
||||
scrambled_addr = sram_scrambler_pkg::encrypt_sram_addr(sram_addr, addr_width, nonce_arr);
|
||||
|
||||
// Calculate the integrity constant
|
||||
integ_data = prim_secded_pkg::prim_secded_39_32_enc(data);
|
||||
|
||||
// Calculate the scrambled data
|
||||
wdata_arr = {<<{integ_data}};
|
||||
wdata_arr = sram_scrambler_pkg::encrypt_sram_data(
|
||||
wdata_arr, 39, 0, sram_addr, addr_width, key_arr, nonce_arr
|
||||
);
|
||||
scrambled_data = {<<{wdata_arr}};
|
||||
|
||||
// Construct bus representation of the address
|
||||
for (int i = 0; i < addr_lsb; i++) begin
|
||||
bus_addr[i] = addr[i];
|
||||
end
|
||||
for (int i = 0; i < addr_width; i++) begin
|
||||
bus_addr[addr_lsb + i] = scrambled_addr[i];
|
||||
end
|
||||
|
||||
// Write the scrambled data to memory
|
||||
write39integ(bus_addr, scrambled_data);
|
||||
endfunction
|
||||
|
||||
virtual function void sram_encrypt_write64(logic [bus_params_pkg::BUS_AW-1:0] addr,
|
||||
logic [63:0] data,
|
||||
logic [SRAM_KEY_WIDTH-1:0] key,
|
||||
logic [SRAM_BLOCK_WIDTH-1:0] nonce);
|
||||
logic [bus_params_pkg::BUS_AW-1:0] bus_addr = '0;
|
||||
logic [63:0] scrambled_data;
|
||||
|
||||
logic wdata_arr [] = new[64];
|
||||
logic scrambled_addr [] = new[addr_width];
|
||||
logic sram_addr [] = new[addr_width];
|
||||
logic key_arr [] = new[SRAM_KEY_WIDTH];
|
||||
logic nonce_arr [] = new[SRAM_BLOCK_WIDTH];
|
||||
|
||||
key_arr = {<<{key}};
|
||||
nonce_arr = {<<{nonce}};
|
||||
|
||||
for (int i = 0; i < addr_width; i++) begin
|
||||
sram_addr[i] = addr[addr_lsb + i];
|
||||
end
|
||||
|
||||
// Calculate the scrambled address
|
||||
scrambled_addr = sram_scrambler_pkg::encrypt_sram_addr(sram_addr, addr_width, nonce_arr);
|
||||
|
||||
// Calculate the scrambled data
|
||||
wdata_arr = {<<{data}};
|
||||
wdata_arr = sram_scrambler_pkg::encrypt_sram_data(
|
||||
wdata_arr, 64, 1, sram_addr, addr_width, key_arr, nonce_arr
|
||||
);
|
||||
scrambled_data = {<<{wdata_arr}};
|
||||
|
||||
// Construct bus representation of the address
|
||||
for (int i = 0; i < addr_lsb; i++) begin
|
||||
bus_addr[i] = addr[i];
|
||||
end
|
||||
for (int i = 0; i < addr_width; i++) begin
|
||||
bus_addr[addr_lsb + i] = scrambled_addr[i];
|
||||
end
|
||||
|
||||
// Write the scrambled data to memory
|
||||
write64(bus_addr, scrambled_data);
|
||||
endfunction
|
40
vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util_pkg.sv
vendored
Normal file
40
vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util_pkg.sv
vendored
Normal file
|
@ -0,0 +1,40 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package mem_bkdr_util_pkg;
|
||||
// dep packages
|
||||
import bus_params_pkg::BUS_AW;
|
||||
import dv_utils_pkg::uint32_t;
|
||||
import lc_ctrl_state_pkg::*;
|
||||
import otp_ctrl_part_pkg::*;
|
||||
import otp_ctrl_reg_pkg::*;
|
||||
import otp_scrambler_pkg::*;
|
||||
import prim_secded_pkg::*;
|
||||
import sram_scrambler_pkg::*;
|
||||
import uvm_pkg::*;
|
||||
|
||||
// Represents the various forms of error detection / correction supported.
|
||||
typedef enum int {
|
||||
ErrDetectionNone = prim_secded_pkg::SecdedNone,
|
||||
Ecc_22_16 = prim_secded_pkg::Secded_22_16,
|
||||
Ecc_28_22 = prim_secded_pkg::Secded_28_22,
|
||||
Ecc_39_32 = prim_secded_pkg::Secded_39_32,
|
||||
Ecc_64_57 = prim_secded_pkg::Secded_64_57,
|
||||
Ecc_72_64 = prim_secded_pkg::Secded_72_64,
|
||||
EccHamming_22_16 = prim_secded_pkg::SecdedHamming_22_16,
|
||||
EccHamming_39_32 = prim_secded_pkg::SecdedHamming_39_32,
|
||||
EccHamming_72_64 = prim_secded_pkg::SecdedHamming_72_64,
|
||||
EccHamming_76_68 = prim_secded_pkg::SecdedHamming_76_68,
|
||||
ParityEven,
|
||||
ParityOdd
|
||||
} err_detection_e;
|
||||
|
||||
// macro includes
|
||||
`include "uvm_macros.svh"
|
||||
`include "dv_macros.svh"
|
||||
|
||||
// sources
|
||||
`include "mem_bkdr_util.sv"
|
||||
|
||||
endpackage
|
95
vendor/lowrisc_ip/dv/sv/mem_bkdr_util/otp_scrambler_pkg.sv
vendored
Normal file
95
vendor/lowrisc_ip/dv/sv/mem_bkdr_util/otp_scrambler_pkg.sv
vendored
Normal file
|
@ -0,0 +1,95 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
// OTP secret data and digest scrambling logic //
|
||||
/////////////////////////////////////////////////
|
||||
|
||||
package otp_scrambler_pkg;
|
||||
|
||||
import uvm_pkg::*;
|
||||
import otp_ctrl_reg_pkg::*;
|
||||
import otp_ctrl_part_pkg::*;
|
||||
import bus_params_pkg::*;
|
||||
|
||||
`include "uvm_macros.svh"
|
||||
|
||||
parameter int SCRAMBLE_DATA_SIZE = 64;
|
||||
parameter int SCRAMBLE_KEY_SIZE = 128;
|
||||
parameter int NUM_ROUND = 31;
|
||||
string path = "otp_scrambler_pkg";
|
||||
|
||||
// When secret data write into otp_array, it will be scrambled.
|
||||
function automatic bit [SCRAMBLE_DATA_SIZE-1:0] scramble_data(
|
||||
bit [SCRAMBLE_DATA_SIZE-1:0] input_data,
|
||||
int part_idx
|
||||
);
|
||||
|
||||
int secret_idx = part_idx - Secret0Idx;
|
||||
bit [NUM_ROUND-1:0][SCRAMBLE_DATA_SIZE-1:0] output_data;
|
||||
crypto_dpi_present_pkg::sv_dpi_present_encrypt(input_data,
|
||||
RndCnstKey[secret_idx],
|
||||
SCRAMBLE_KEY_SIZE == 80,
|
||||
output_data);
|
||||
scramble_data = output_data[NUM_ROUND-1];
|
||||
endfunction
|
||||
|
||||
// When secret data read out of otp_array, it will be descrambled.
|
||||
function automatic bit [SCRAMBLE_DATA_SIZE-1:0] descramble_data(
|
||||
bit [SCRAMBLE_DATA_SIZE-1:0] input_data,
|
||||
int part_idx
|
||||
);
|
||||
|
||||
int secret_idx = part_idx - Secret0Idx;
|
||||
bit [NUM_ROUND-1:0][SCRAMBLE_DATA_SIZE-1:0] output_data;
|
||||
bit [NUM_ROUND-1:0][SCRAMBLE_DATA_SIZE-1:0] padded_input;
|
||||
|
||||
padded_input[NUM_ROUND-1] = input_data;
|
||||
crypto_dpi_present_pkg::sv_dpi_present_decrypt(padded_input,
|
||||
RndCnstKey[secret_idx],
|
||||
SCRAMBLE_KEY_SIZE == 80,
|
||||
output_data);
|
||||
descramble_data = output_data[NUM_ROUND-1];
|
||||
if (input_data != 0) begin
|
||||
end
|
||||
endfunction
|
||||
|
||||
function automatic bit [SCRAMBLE_DATA_SIZE-1:0] cal_digest(int part_idx,
|
||||
ref bit [BUS_DW-1:0] mem_q[$]);
|
||||
int array_size = mem_q.size();
|
||||
real key_factor = SCRAMBLE_KEY_SIZE / BUS_DW;
|
||||
bit [NUM_ROUND-1:0] [SCRAMBLE_DATA_SIZE-1:0] enc_array;
|
||||
bit [SCRAMBLE_DATA_SIZE-1:0] init_vec = RndCnstDigestIV[0];
|
||||
bit [SCRAMBLE_DATA_SIZE-1:0] digest;
|
||||
|
||||
for (int i = 0; i < $ceil(array_size / key_factor); i++) begin
|
||||
bit [SCRAMBLE_DATA_SIZE-1:0] input_data = (i == 0) ? init_vec : digest;
|
||||
bit [SCRAMBLE_KEY_SIZE-1:0] key;
|
||||
|
||||
// Pad 32-bit partition data into 128-bit key input.
|
||||
// Because the mem_q size is a multiple of 64-bit, so if the last round only has 64-bits key,
|
||||
// it will repeat the last 64-bits twice.
|
||||
for (int j = 0; j < key_factor; j++) begin
|
||||
int index = i * key_factor + j;
|
||||
key |= ((index >= array_size ? mem_q[index-2] : mem_q[index]) << (j * BUS_DW));
|
||||
end
|
||||
|
||||
// Trigger 32 round of PRESENT encrypt.
|
||||
crypto_dpi_present_pkg::sv_dpi_present_encrypt(input_data, key, SCRAMBLE_KEY_SIZE == 80,
|
||||
enc_array);
|
||||
// XOR the previous state into the digest result according to the Davies-Meyer scheme.
|
||||
digest = enc_array[NUM_ROUND-1] ^ input_data;
|
||||
end
|
||||
|
||||
// Last 32 round of digest is calculated with a digest constant.
|
||||
crypto_dpi_present_pkg::sv_dpi_present_encrypt(digest,
|
||||
RndCnstDigestConst[0],
|
||||
SCRAMBLE_KEY_SIZE == 80,
|
||||
enc_array);
|
||||
// XOR the previous state into the digest result according to the Davies-Meyer scheme.
|
||||
digest ^= enc_array[NUM_ROUND-1];
|
||||
return digest;
|
||||
endfunction
|
||||
|
||||
endpackage
|
298
vendor/lowrisc_ip/dv/sv/mem_bkdr_util/sram_scrambler_pkg.sv
vendored
Normal file
298
vendor/lowrisc_ip/dv/sv/mem_bkdr_util/sram_scrambler_pkg.sv
vendored
Normal file
|
@ -0,0 +1,298 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
////////////////////////////////////////////
|
||||
// SRAM address and data scrambling logic //
|
||||
///////////////////////////////////////////
|
||||
//
|
||||
// There are a few general things to note here:
|
||||
//
|
||||
// - SRAM data scrambling relies on a reduced-round PRINCE cipher, plus a custom substitution
|
||||
// and permutation network loosely based off of PRESENT.
|
||||
//
|
||||
// - SRAM address scrambling relies solely on the custom substitution and permutation network.
|
||||
//
|
||||
// - The custom subst/perm network used for data scrambling operates at byte granularity,
|
||||
// while for address scrambling it operates at a granularity of the address width.
|
||||
//
|
||||
// - For DV purposes we can safely rely on the PRESENT sboxes, as nightly regressions are
|
||||
// completely passing plus the sboxes in `prim_cipher_pkg` are copied directly from the
|
||||
// PRESENT specifications.
|
||||
// This has the side effect of allowing us to avoid duplication of the sboxes, which lowers the
|
||||
// probability of an error in translation.
|
||||
|
||||
package sram_scrambler_pkg;
|
||||
|
||||
import uvm_pkg::*;
|
||||
import bus_params_pkg::BUS_AW;
|
||||
import crypto_dpi_prince_pkg::*;
|
||||
import prim_cipher_pkg::*;
|
||||
|
||||
`include "uvm_macros.svh"
|
||||
|
||||
string path = "sram_scrambler_pkg";
|
||||
|
||||
// Fixed key size - PRINCE cipher operates on a 128-bit key,
|
||||
// and the same key is used for all parallel cipher instances.
|
||||
parameter int SRAM_KEY_WIDTH = 128;
|
||||
|
||||
// Fixed data block size - PRINCE cipher operates on 64-bit data blocks.
|
||||
parameter int SRAM_BLOCK_WIDTH = 64;
|
||||
|
||||
parameter int NUM_ROUNDS = 2;
|
||||
|
||||
// Create a generic typedef for dynamic array of logic to be able to return these values.
|
||||
typedef logic state_t[];
|
||||
|
||||
// The sboxes operate on nibbles.
|
||||
//
|
||||
// If `WIDTH % 4 != 0`, the uppermost bits will get shifted to lower positions
|
||||
// during either the `flip_vector` or `perm_layer` stage of the network,
|
||||
// so it is guaranted that all bits will eventually go through an sbox.
|
||||
function automatic state_t sbox_layer(state_t state, int width, bit inv);
|
||||
logic state_out[] = new[width](state);
|
||||
logic [3:0] sbox_in;
|
||||
logic [3:0] sbox_out;
|
||||
for (int i = 0; i < width / 4; i++) begin
|
||||
// `with` syntax is currently unsupported by Verible,
|
||||
// uncomment once support has been added
|
||||
//
|
||||
//sbox_in = {<< {state with [i*4 +: 4]}};
|
||||
for (int j = 0; j < 4; j++) begin
|
||||
sbox_in[j] = state[i*4 + j];
|
||||
end
|
||||
|
||||
if (inv) begin
|
||||
sbox_out = prim_cipher_pkg::PRESENT_SBOX4_INV[sbox_in];
|
||||
end else begin
|
||||
sbox_out = prim_cipher_pkg::PRESENT_SBOX4[sbox_in];
|
||||
end
|
||||
|
||||
for (int j = 0; j < 4; j++) begin
|
||||
state_out[i*4 + j] = sbox_out[j];
|
||||
end
|
||||
end
|
||||
return state_out;
|
||||
endfunction : sbox_layer
|
||||
|
||||
// Reverse the input bit vector.
|
||||
function automatic state_t flip_vector(state_t state);
|
||||
return {<< {state}};
|
||||
endfunction : flip_vector
|
||||
|
||||
// Permutation layer - all even indexed bits move to the lower half,
|
||||
// and all odd indexed bits move to the top half.
|
||||
function automatic state_t perm_layer(state_t state, int width, bit inv);
|
||||
logic state_out[] = new[width](state);
|
||||
for (int i = 0; i < width / 2; i++) begin
|
||||
if (inv) begin
|
||||
state_out[i * 2] = state[i];
|
||||
state_out[i * 2 + 1] = state[i + width / 2];
|
||||
end else begin
|
||||
state_out[i] = state[i * 2];
|
||||
state_out[i + width / 2] = state[i * 2 + 1];
|
||||
end
|
||||
end
|
||||
return state_out;
|
||||
endfunction : perm_layer
|
||||
|
||||
// Performs NUM_ROUNDS full encryption rounds
|
||||
function automatic state_t sp_encrypt(state_t data, int width, state_t key);
|
||||
logic state[] = new[width](data);
|
||||
for (int i = 0; i < NUM_ROUNDS; i++) begin
|
||||
// xor the data and key
|
||||
for (int j = 0; j < width; j++) begin
|
||||
state[j] = state[j] ^ key[j];
|
||||
end
|
||||
// sbox layer
|
||||
state = sbox_layer(state, width, 0);
|
||||
// flip the bit vector
|
||||
state = flip_vector(state);
|
||||
// permutation layer
|
||||
state = perm_layer(state, width, 0);
|
||||
end
|
||||
// final xor
|
||||
for (int i = 0; i < width; i++) begin
|
||||
state[i] = state[i] ^ key[i];
|
||||
end
|
||||
return state;
|
||||
endfunction : sp_encrypt
|
||||
|
||||
// Performs NUM_ROUNDS full decryption rounds
|
||||
function automatic state_t sp_decrypt(state_t data, int width, state_t key);
|
||||
logic state[] = new[width](data);
|
||||
for (int i = 0; i < NUM_ROUNDS; i++) begin
|
||||
// xor data and key
|
||||
for (int j = 0; j < width; j++) begin
|
||||
state[j] = state[j] ^ key[j];
|
||||
end
|
||||
// permutation layer
|
||||
state = perm_layer(state, width, 1);
|
||||
// flip bit vector
|
||||
state = flip_vector(state);
|
||||
// sbox layer
|
||||
state = sbox_layer(state, width, 1'b1);
|
||||
end
|
||||
// final xor
|
||||
for (int i = 0; i < width; i++) begin
|
||||
state[i] = state[i] ^ key[i];
|
||||
end
|
||||
return state;
|
||||
endfunction : sp_decrypt
|
||||
|
||||
// Generates the 64-bit keystream that is XORed with the data to obtain a ciphertext.
|
||||
// Assumes that the data is at most 64 bits wide.
|
||||
//
|
||||
// Should not be called directly.
|
||||
function automatic state_t gen_keystream(logic addr[], int addr_width,
|
||||
logic key[], logic nonce[]);
|
||||
logic [NUM_ROUNDS-1:0][SRAM_BLOCK_WIDTH-1:0] prince_result_arr;
|
||||
|
||||
logic [SRAM_BLOCK_WIDTH-1:0] prince_plaintext;
|
||||
logic [SRAM_KEY_WIDTH-1:0] prince_key;
|
||||
logic [SRAM_BLOCK_WIDTH-1:0] prince_result;
|
||||
|
||||
logic iv[] = new[SRAM_BLOCK_WIDTH];
|
||||
logic key_out[] = new[SRAM_BLOCK_WIDTH];
|
||||
|
||||
// IV is composed of nonce concatenated with address
|
||||
for (int i = 0; i < addr_width; i++) begin
|
||||
iv[i] = addr[i];
|
||||
end
|
||||
for (int i = 0; i < SRAM_BLOCK_WIDTH - addr_width; i++) begin
|
||||
iv[addr_width + i] = nonce[i];
|
||||
end
|
||||
|
||||
//for (int i = 0; i < SRAM_BLOCK_WIDTH - addr_width; i++) begin
|
||||
// iv[addr_width + i] = nonce[i];
|
||||
//end
|
||||
|
||||
// convert arrays to packed vectors before invoking prince DPI model
|
||||
prince_plaintext = {<< {iv}};
|
||||
// `with` syntax is currently unsupported by Verible,
|
||||
// uncomment once support has been added
|
||||
//
|
||||
// prince_key = {<< {key with [0 +: SRAM_KEY_WIDTH]}};
|
||||
for (int i = 0; i < SRAM_KEY_WIDTH; i++) begin
|
||||
prince_key[i] = key[i];
|
||||
end
|
||||
|
||||
crypto_dpi_prince_pkg::sv_dpi_prince_encrypt(.plaintext(prince_plaintext),
|
||||
.key(prince_key),
|
||||
.old_key_schedule(0),
|
||||
.ciphertext(prince_result_arr));
|
||||
prince_result = prince_result_arr[NUM_ROUNDS-1];
|
||||
|
||||
key_out = {<< {prince_result}};
|
||||
|
||||
return key_out;
|
||||
endfunction : gen_keystream
|
||||
|
||||
// Encrypts the target SRAM address using the custom S&P network.
|
||||
function automatic state_t encrypt_sram_addr(logic addr[], int addr_width,
|
||||
logic full_nonce[]);
|
||||
|
||||
logic nonce[] = new[addr_width];
|
||||
logic encrypted_addr[] = new[addr_width];
|
||||
|
||||
// The address encryption nonce is the same width as the address,
|
||||
// and is constructed from the top addr_width bits of the full nonce.
|
||||
//
|
||||
// `with` syntax is currently unsupported by Verible,
|
||||
// uncomment once support has been added
|
||||
//
|
||||
// nonce = {>> {full_nonce with [SRAM_BLOCK_WIDTH - addr_width +: addr_width]}};
|
||||
for (int i = 0; i < addr_width; i++) begin
|
||||
nonce[i] = full_nonce[SRAM_BLOCK_WIDTH - addr_width + i];
|
||||
end
|
||||
|
||||
encrypted_addr = sp_encrypt(addr, addr_width, nonce);
|
||||
return encrypted_addr;
|
||||
|
||||
endfunction : encrypt_sram_addr
|
||||
|
||||
// SRAM data encryption is more involved, we need to run 2 rounds of PRINCE on the nonce and key
|
||||
// and then XOR the result with the data.
|
||||
//
|
||||
// After that, the XORed data neeeds to them be passed through the S&P network one byte at a time.
|
||||
//
|
||||
// TODO: We currently do not support data size of >64bits.
|
||||
function automatic state_t encrypt_sram_data(logic data[], int data_width, bit byte_diff,
|
||||
logic addr[], int addr_width,
|
||||
logic key[], logic nonce[]);
|
||||
// Generate the keystream
|
||||
logic keystream[] = new[SRAM_BLOCK_WIDTH];
|
||||
logic data_enc[] = new[data_width];
|
||||
logic byte_to_enc[] = new[8];
|
||||
logic enc_byte[] = new[8];
|
||||
logic zero_key[] = new[data_width];
|
||||
|
||||
// the key used for byte diffusion is all-zero.
|
||||
for (int i = 0; i < data_width; i++) begin
|
||||
zero_key[i] = '0;
|
||||
end
|
||||
|
||||
// Generate the keystream
|
||||
keystream = gen_keystream(addr, addr_width, key, nonce);
|
||||
|
||||
// XOR keystream with input data
|
||||
// Assumes data width <= 64.
|
||||
for (int i = 0; i < data_width; i++) begin
|
||||
data_enc[i] = data[i] ^ keystream[i];
|
||||
end
|
||||
|
||||
// pass each byte of the encoded result through the subst/perm network
|
||||
if (byte_diff) begin
|
||||
for (int i = 0; i < data_width / 8; i++) begin
|
||||
byte_to_enc = data_enc[i*8 +: 8];
|
||||
enc_byte = sp_encrypt(byte_to_enc, 8, zero_key);
|
||||
data_enc[i*8 +: 8] = enc_byte;
|
||||
end
|
||||
// pass the entire word through the subst/perm network
|
||||
end else begin
|
||||
data_enc = sp_encrypt(data_enc, data_width, zero_key);
|
||||
end
|
||||
return data_enc;
|
||||
|
||||
endfunction : encrypt_sram_data
|
||||
|
||||
function automatic state_t decrypt_sram_data(logic data[], int data_width, bit byte_diff,
|
||||
logic addr[], int addr_width,
|
||||
logic key[], logic nonce[]);
|
||||
logic keystream[] = new[SRAM_BLOCK_WIDTH];
|
||||
logic data_dec[] = new[data_width];
|
||||
logic byte_to_dec[] = new[8];
|
||||
logic dec_byte[] = new[8];
|
||||
logic zero_key[] = new[data_width];
|
||||
|
||||
// the key used for byte diffusion is all-zero.
|
||||
for (int i = 0; i < data_width; i++) begin
|
||||
zero_key[i] = '0;
|
||||
end
|
||||
|
||||
// Generate the keystream
|
||||
keystream = gen_keystream(addr, addr_width, key, nonce);
|
||||
|
||||
// pass each byte of the data through the subst/perm network
|
||||
if (byte_diff) begin
|
||||
for (int i = 0; i < data_width / 8; i++) begin
|
||||
byte_to_dec = data[i*8 +: 8];
|
||||
dec_byte = sp_decrypt(byte_to_dec, 8, zero_key);
|
||||
data_dec[i*8 +: 8] = dec_byte;
|
||||
end
|
||||
// pass the entire word through the subst/perm network
|
||||
end else begin
|
||||
data_dec = sp_decrypt(data, data_width, zero_key);
|
||||
end
|
||||
|
||||
// XOR result data with the keystream
|
||||
for (int i = 0; i < data_width; i++) begin
|
||||
data_dec[i] = data_dec[i] ^ keystream[i];
|
||||
end
|
||||
|
||||
return data_dec;
|
||||
|
||||
endfunction : decrypt_sram_data
|
||||
|
||||
endpackage : sram_scrambler_pkg
|
|
@ -66,7 +66,8 @@
|
|||
"+define+UVM_REG_ADDR_WIDTH={tl_aw}",
|
||||
"+define+UVM_REG_DATA_WIDTH={tl_dw}",
|
||||
"+define+UVM_REG_BYTENABLE_WIDTH={tl_dbw}",
|
||||
"+define+SIMULATION"]
|
||||
"+define+SIMULATION",
|
||||
"+define+DUT_HIER={dut_instance}"]
|
||||
|
||||
run_opts: ["+UVM_NO_RELNOTES",
|
||||
"+UVM_VERBOSITY={expand_uvm_verbosity_{verbosity}}"]
|
||||
|
|
6
vendor/lowrisc_ip/dv/tools/dvsim/dsim.hjson
vendored
6
vendor/lowrisc_ip/dv/tools/dvsim/dsim.hjson
vendored
|
@ -14,7 +14,9 @@
|
|||
"+incdir+{UVM_HOME}/src",
|
||||
"{UVM_HOME}/src/uvm_pkg.sv",
|
||||
// Add dpi/vpi include path.
|
||||
"-c-opts -I{DSIM_HOME}/include",
|
||||
"-c-opts -I{DSIM_HOME}/../../include",
|
||||
// Needed for including "secded_enc.h".
|
||||
"-c-opts -I{build_dir}/src/lowrisc_dv_secded_enc_0",
|
||||
"-timescale 1ns/1ps",
|
||||
"-f {sv_flist}",
|
||||
// List multiple tops for the simulation. Prepend each top level with `-top`.
|
||||
|
@ -80,7 +82,7 @@
|
|||
// Vars that need to exported to the env.
|
||||
exports: [
|
||||
{ PATH: "{DSIM_HOME}:{PATH}" }
|
||||
{ LD_LIBRARY_PATH: "{DSIM_HOME}/lib:{DSIM_HOME}/system_lib:{LD_LIBRARY_PATH}" }
|
||||
{ LD_LIBRARY_PATH: "{DSIM_HOME}/lib:{LD_LIBRARY_PATH}" }
|
||||
]
|
||||
|
||||
// Defaults for DSim
|
||||
|
|
29
vendor/lowrisc_ip/dv/tools/dvsim/testplans/sec_cm_count_testplan.hjson
vendored
Normal file
29
vendor/lowrisc_ip/dv/tools/dvsim/testplans/sec_cm_count_testplan.hjson
vendored
Normal file
|
@ -0,0 +1,29 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
{
|
||||
testpoints: [
|
||||
{
|
||||
name: prim_count_check
|
||||
desc: ''' Verify that violating prim_count counter properties generate a fatal alert.
|
||||
|
||||
Stimulus:
|
||||
- At the falling edge (non-active edge), force the counter to a different value than
|
||||
expected.
|
||||
- Randomly force the counter back to a normal value to ensure the error is latched and
|
||||
won't go away until reset.
|
||||
- Within the next few cycles, the violation of hardened counter property should
|
||||
generate a fatal alert.
|
||||
- Repeat for ALL prim_count instances in the DUT.
|
||||
|
||||
Checks:
|
||||
- Check that fatal alert is triggered.
|
||||
- Check that err_code/fault_status is updated correctly and preserved until reset.
|
||||
- Verify any operations that follow fail (as applicable).
|
||||
'''
|
||||
milestone: V2S
|
||||
tests: ["{name}_sec_cm"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
28
vendor/lowrisc_ip/dv/tools/dvsim/testplans/sec_cm_fsm_testplan.hjson
vendored
Normal file
28
vendor/lowrisc_ip/dv/tools/dvsim/testplans/sec_cm_fsm_testplan.hjson
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
{
|
||||
testpoints: [
|
||||
{
|
||||
name: prim_fsm_check
|
||||
desc: ''' Verify that entering to an undefined state generates a fatal alert.
|
||||
|
||||
Stimulus:
|
||||
- Backdoor force the FSM to any of the undefined values.
|
||||
- Randomly force the FSM back to a defined state to ensure the error is latched and
|
||||
won't go away until reset.
|
||||
- Within the next few cycles, the FSM landing in an invalid state should trigger a
|
||||
fatal alert.
|
||||
- Repeat for ALL prim_fsm instances in the DUT.
|
||||
|
||||
Checks:
|
||||
- Check that fatal alert is triggered.
|
||||
- Check that err_code/fault_status is updated correctly and preserved until reset.
|
||||
- Verify any operations that follow fail (as applicable).
|
||||
'''
|
||||
milestone: V2S
|
||||
tests: ["{name}_sec_cm"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
29
vendor/lowrisc_ip/dv/tools/dvsim/testplans/sec_cm_one_hot_testplan.hjson
vendored
Normal file
29
vendor/lowrisc_ip/dv/tools/dvsim/testplans/sec_cm_one_hot_testplan.hjson
vendored
Normal file
|
@ -0,0 +1,29 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
{
|
||||
testpoints: [
|
||||
{
|
||||
name: prim_one_hot_check
|
||||
desc: ''' Verify that violating one-hot property generates a fatal alert.
|
||||
|
||||
One-hot encoded signals are captured in `prim_one_hot` module.
|
||||
Stimulus:
|
||||
- Backdoor force the one-hot coding signals with multiple bits set.
|
||||
- Randomly force the value to one-hot to ensure the error is latched and won't go away
|
||||
until reset.
|
||||
- Within the next few cycles, the violation of one-hot property should generate a fatal
|
||||
alert.
|
||||
- Repeat for ALL prim_one_hot instances in the DUT.
|
||||
|
||||
Checks:
|
||||
- Check that fatal alert is triggered.
|
||||
- Check that err_code/fault_status is updated correctly and preserved until reset.
|
||||
- Verify any operations that follow fail (as applicable).
|
||||
'''
|
||||
milestone: V2S
|
||||
tests: ["{name}_sec_cm"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
{
|
||||
// TODO, split this into several testplan for each CM
|
||||
testpoints: [
|
||||
{
|
||||
name: one_hot_check
|
||||
desc: ''' Verify design behavior is correct when one-hot coding is violated.
|
||||
|
||||
Stimulus:
|
||||
- Backdoor force one-hot coding signals to not one-hot.
|
||||
- Randomly flip the value back to ensure the error is latched and won't go away until
|
||||
reset.
|
||||
|
||||
Checks:
|
||||
- Check that fatal alert is triggered.
|
||||
- Check that err_code/fault_status is updated correctly and preserved until reset.
|
||||
- Check the following operation should be failed if applicable.'''
|
||||
milestone: V2
|
||||
tests: ["{name}_sec_cm"]
|
||||
}
|
||||
{
|
||||
name: redundant_coding_fsm_check
|
||||
desc: ''' Verify design behavior is correct when the redundant FSM enters an invalid state.
|
||||
|
||||
Stimulus:
|
||||
- Backdoor force the FSM to any of the undefined values.
|
||||
- Randomly flip the value back to a defined state to ensure the error is latched and
|
||||
won't go away until reset.
|
||||
|
||||
Same checks as `one_hot_check`'''
|
||||
milestone: V2
|
||||
tests: ["{name}_sec_cm"]
|
||||
}
|
||||
{
|
||||
name: hardened_counter_check
|
||||
desc: ''' Verify design behavior is correct when the harden counter is changed to an
|
||||
unexpected value.
|
||||
|
||||
Stimulus:
|
||||
- At the falling edge (non-active edge), force the counter to a different value.
|
||||
- Randomly flip the value back to any other value to ensure the error is latched and
|
||||
won't go away until reset.
|
||||
|
||||
Same checks as `one_hot_check`'''
|
||||
milestone: V2
|
||||
tests: ["{name}_sec_cm"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -51,5 +51,36 @@
|
|||
milestone: V1
|
||||
tests: ["{name}_shadow_reg_errors"]
|
||||
}
|
||||
|
||||
{
|
||||
name: shadowed_reset_glitch
|
||||
desc: '''Verify toggle shadowed_rst_n pin can trigger storage error.
|
||||
|
||||
- Randomly drive `shadowed_rst_n` pin to low or `rst_n` pin to low.
|
||||
- check if any registers have been written before the reset. If so check if storage
|
||||
error fatal alert is triggered.
|
||||
- Check status register.
|
||||
- Drive `shadowed_rst_n` pin or `rst_n` pin back to high.
|
||||
- If fatal alert is triggered, reset the DUT.
|
||||
- Read all CSRs to ensure the DUT is properly reset.
|
||||
- Repeat the above steps a bunch of times.
|
||||
'''
|
||||
milestone: V1
|
||||
tests: ["{name}_shadow_reg_errors"]
|
||||
}
|
||||
|
||||
{
|
||||
// this testplan should be imported by all IPs containing shadowed CSRs
|
||||
name: shadow_reg_update_error_with_csr_rw
|
||||
desc: '''Run shadow_reg_update_error sequence in parallel with csr_rw sequence.
|
||||
|
||||
- Randomly select one of the above sequences.
|
||||
- Apply csr_rw sequence in parallel but disable the `csr_access_abort` to ensure all
|
||||
shadowed registers' write/read to be executed without aborting.
|
||||
- Repeat the above steps a bunch of times.
|
||||
'''
|
||||
milestone: V1
|
||||
tests: ["{name}_shadow_reg_errors_with_csr_rw"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@
|
|||
|
||||
Randomly inject errors on the control, data, or the ECC bits during CSR accesses.
|
||||
Verify that triggers the correct fatal alert.'''
|
||||
milestone: V3
|
||||
milestone: V2S
|
||||
tests: ["{name}_tl_intg_err"]
|
||||
}
|
||||
]
|
||||
|
@ -76,12 +76,8 @@
|
|||
name: tl_intg_err_cg
|
||||
desc: '''Cover all kinds of integrity errors (command, data or both) and cover number of
|
||||
error bits on each integrity check.
|
||||
'''
|
||||
}
|
||||
{
|
||||
name: tl_intg_err_mem_subword_cg
|
||||
desc: '''Cover the kinds of integrity errors with byte enabled write on memory.
|
||||
|
||||
Cover the kinds of integrity errors with byte enabled write on memory if applicable:
|
||||
Some memories store the integrity values. When there is a subword write, design
|
||||
re-calculate the integrity with full word data and update integrity in the memory.
|
||||
This coverage ensures that memory byte write has been issued and the related design
|
||||
|
|
13
vendor/lowrisc_ip/dv/tools/dvsim/tests/sec_cm_tests.hjson
vendored
Normal file
13
vendor/lowrisc_ip/dv/tools/dvsim/tests/sec_cm_tests.hjson
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
{
|
||||
tests: [
|
||||
{
|
||||
name: "{name}_sec_cm"
|
||||
uvm_test_seq: "{name}_common_vseq"
|
||||
run_opts: ["+run_sec_cm_fi", "+en_scb=0"]
|
||||
reseed: 5
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// this hjson should be imported by all IPs containing shadowed CSRs
|
||||
{
|
||||
build_modes: [
|
||||
{
|
||||
|
@ -18,11 +20,18 @@
|
|||
|
||||
tests: [
|
||||
{
|
||||
// this hjson should be imported by all IPs containing shadowed CSRs
|
||||
name: "{name}_shadow_reg_errors"
|
||||
build_mode: "cover_reg_top"
|
||||
run_opts: ["+run_shadow_reg_errors"]
|
||||
en_run_modes: ["csr_tests_mode"]
|
||||
reseed: 20
|
||||
}
|
||||
{
|
||||
name: "{name}_shadow_reg_errors_with_csr_rw"
|
||||
build_mode: "cover_reg_top"
|
||||
run_opts: ["+run_shadow_reg_errors_with_csr_rw"]
|
||||
en_run_modes: ["csr_tests_mode"]
|
||||
reseed: 20
|
||||
}
|
||||
]
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
build_cmd: "{job_prefix} xrun"
|
||||
run_cmd: "{job_prefix} xrun"
|
||||
|
||||
build_db_dir: "{build_dir}/xcelium.d"
|
||||
|
||||
build_opts: ["-elaborate -64bit -sv",
|
||||
"-licqueue",
|
||||
// TODO: duplicate primitives between OT and Ibex #1231
|
||||
|
@ -13,7 +15,7 @@
|
|||
"-timescale 1ns/1ps",
|
||||
"-f {sv_flist}",
|
||||
"-uvmhome CDNS-1.2",
|
||||
"-xmlibdirname {build_dir}/xcelium.d",
|
||||
"-xmlibdirname {build_db_dir}",
|
||||
// List multiple tops for the simulation. Prepend each top level with `-top`.
|
||||
"{eval_cmd} echo {sim_tops} | sed -E 's/(\\S+)/-top \\1/g'",
|
||||
// Set the top level elaborated entity (snapshot name) correctly since there are
|
||||
|
@ -37,7 +39,7 @@
|
|||
|
||||
run_opts: ["-input {run_script}",
|
||||
"-licqueue",
|
||||
"-64bit -xmlibdirname {build_dir}/xcelium.d",
|
||||
"-64bit -xmlibdirname {build_db_dir}",
|
||||
// Use the same snapshot name set during the build step.
|
||||
"-r {tb}",
|
||||
"+SVSEED={seed}",
|
||||
|
@ -145,7 +147,7 @@
|
|||
// what metrics to use
|
||||
"-jg_coverage {cov_metrics}",
|
||||
"-64bit",
|
||||
"-xmlibdirname {build_dir}/xcelium.d",
|
||||
"-xmlibdirname {build_db_dir}",
|
||||
// overwrite previous results
|
||||
"-covoverwrite",
|
||||
"-inst_top {dut_instance}",
|
||||
|
|
24
vendor/lowrisc_ip/dv/tools/ralgen/README.md
vendored
24
vendor/lowrisc_ip/dv/tools/ralgen/README.md
vendored
|
@ -15,10 +15,20 @@ The adjoining `ralgen.core` file registers the `ralgen` generator. The FuseSoC
|
|||
core file that 'calls' the generator adds it as a dependency. When calling the
|
||||
generator, the following parameters are set:
|
||||
* **name (mandatory)**: Name of the RAL package (typically, same is the IP).
|
||||
* **dv_base_prefix (optional)**: The prefix added to the base classes from
|
||||
which the register classes are derived. Set this option to derive the register
|
||||
classes not from the default `dv_base_reg`, but from user defined custom
|
||||
class definitions.
|
||||
* **dv_base_names (optional)**: The base class names from which the register
|
||||
classes are derived. Set this option to derive the register classes not from
|
||||
the default `dv_base_reg`, but from user defined custom class definitions.
|
||||
This argument follows the following format:
|
||||
`--dv-base-names block:type:entity-name block:type:entity-name ...`.
|
||||
`block`: can be any block names.
|
||||
`type`: can be `block`, `reg`, `field`, `pkg`, `mem`, or use `all` to override
|
||||
all types within the block.
|
||||
`entity_name`: the name of the base class / package. If the `type` is set to `all`,
|
||||
then this represents the prefix of the bass class / package. The suffixes
|
||||
`_reg_block`, `_reg`, `_reg_field`, `_mem`, `_reg_pkg` are applied to infer the
|
||||
actual base class / package names from which the generated DV classes will extend.
|
||||
Note that we assume the fusesoc core file naming convention follows the package
|
||||
name without the `_pkg` suffix.
|
||||
* **ip_hjson**: Path to the hjson specification written for an IP which includes
|
||||
the register descriptions. This needs to be a valid input for `reggen`.
|
||||
* **top_hjson**: Path to the hjson specification for a top level design. This
|
||||
|
@ -35,7 +45,9 @@ generate:
|
|||
parameters:
|
||||
name: <name>
|
||||
ip_hjson|top_hjson: <path-to-hjson-spec>
|
||||
[dv_base_prefix: my_base]
|
||||
[dv_base_names:
|
||||
- block_1:type:entity_name_1
|
||||
- block_2:type:entity_name_2]
|
||||
|
||||
|
||||
targets:
|
||||
|
@ -73,7 +85,7 @@ The generated core file adds **`lowrisc:dv:dv_base_reg`** as a dependency for
|
|||
the generated RAL package. This is required because our DV register block,
|
||||
register and field models are derived from the
|
||||
[DV library]({{< relref "hw/dv/sv/dv_lib/README.md" >}}) of classes. This
|
||||
ensures the right compilation order is maintained. If the `dv_base_prefix`
|
||||
ensures the right compilation order is maintained. If the `dv_base_names`
|
||||
argument is set, then it adds **`lowrisc:dv:my_base_reg`** as an extra
|
||||
dependency, where `my_base` is the value of the argument as shown in the
|
||||
example above. This core file and the associated sources are assumed to be
|
||||
|
|
49
vendor/lowrisc_ip/dv/tools/ralgen/ralgen.py
vendored
49
vendor/lowrisc_ip/dv/tools/ralgen/ralgen.py
vendored
|
@ -6,8 +6,10 @@ r"""FuseSoc generator for UVM RAL package created with either regtool or
|
|||
topgen tools.
|
||||
"""
|
||||
import os
|
||||
import shlex
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import yaml
|
||||
|
||||
|
@ -21,15 +23,6 @@ except ImportError:
|
|||
REPO_ROOT = "../../../.."
|
||||
|
||||
|
||||
# Given a root dir and partial path, this function returns the full path.
|
||||
def get_full_path(root_dir, partial_path):
|
||||
full_path = os.path.abspath(os.path.join(root_dir, partial_path))
|
||||
if not os.path.exists(full_path):
|
||||
print("Error: path appears to be invalid: {}".format(full_path))
|
||||
sys.exit(1)
|
||||
return full_path
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 2:
|
||||
print("ERROR: This script takes a single YAML file as input argument")
|
||||
|
@ -38,17 +31,17 @@ def main():
|
|||
gapi_filepath = sys.argv[1]
|
||||
gapi = yaml.load(open(gapi_filepath), Loader=YamlLoader)
|
||||
|
||||
# This is just a wrapper around the reggen and topgen tools, which
|
||||
# are referenced from proj_root area.
|
||||
self_path = os.path.dirname(os.path.realpath(__file__))
|
||||
util_path = os.path.abspath(os.path.join(self_path, REPO_ROOT, "util"))
|
||||
# The reggen and topgen tools live in REPO_ROOT/util area.
|
||||
util_path = Path(__file__).parent / REPO_ROOT / "util"
|
||||
|
||||
# Retrieve the parameters from the yml.
|
||||
root_dir = gapi['files_root']
|
||||
root_dir = Path(gapi['files_root'])
|
||||
name = gapi['parameters'].get('name')
|
||||
ip_hjson = gapi['parameters'].get('ip_hjson')
|
||||
top_hjson = gapi['parameters'].get('top_hjson')
|
||||
dv_base_prefix = gapi['parameters'].get('dv_base_prefix')
|
||||
dv_base_names = gapi['parameters'].get('dv_base_names')
|
||||
hjson_path = gapi['parameters'].get('hjson_path')
|
||||
|
||||
if not name or (bool(ip_hjson) == bool(top_hjson)):
|
||||
print("Error: ralgen requires the \"name\" and exactly one of "
|
||||
"{\"ip_hjson\" and \"top_hjson\"} parameters to be set.")
|
||||
|
@ -56,24 +49,28 @@ def main():
|
|||
|
||||
# Generate the RAL pkg.
|
||||
if ip_hjson:
|
||||
ral_spec = get_full_path(root_dir, ip_hjson)
|
||||
cmd = os.path.join(util_path, "regtool.py")
|
||||
args = [cmd, "-s", "-t", ".", ral_spec]
|
||||
ral_spec = root_dir / ip_hjson
|
||||
cmd = util_path / "regtool.py"
|
||||
args = [cmd, "-s", "-t", os.getcwd(), ral_spec]
|
||||
else:
|
||||
ral_spec = get_full_path(root_dir, top_hjson)
|
||||
cmd = os.path.join(util_path, "topgen.py")
|
||||
args = [cmd, "-r", "-o", ".", "-t", ral_spec]
|
||||
ral_spec = root_dir / top_hjson
|
||||
cmd = util_path / "topgen.py"
|
||||
args = [cmd, "-r", "-o", os.getcwd(), "-t", ral_spec]
|
||||
if hjson_path:
|
||||
args += ["--hjson-path", root_dir / hjson_path]
|
||||
|
||||
if dv_base_prefix and dv_base_prefix != "dv_base":
|
||||
args.extend(["--dv-base-prefix", dv_base_prefix])
|
||||
if dv_base_names:
|
||||
args += ["--dv-base-names"] + dv_base_names
|
||||
|
||||
cmd_str = ' '.join([shlex.quote(str(arg)) for arg in args])
|
||||
print(f"Calling tool in ralgen.py: {cmd_str}")
|
||||
try:
|
||||
subprocess.run(args, check=True)
|
||||
except subprocess.CalledProcessError as e:
|
||||
print("Error: RAL pkg generation failed:\n{}".format(str(e)))
|
||||
print(f"Error: RAL pkg generation failed:\n{e}")
|
||||
sys.exit(e.returncode)
|
||||
print("RAL pkg for {} block written to {}"
|
||||
.format(name, os.path.abspath('.')))
|
||||
|
||||
print(f"RAL pkg for {name} written to {Path.cwd()}.")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
24
vendor/lowrisc_ip/dv/tools/vcs/cover.cfg
vendored
24
vendor/lowrisc_ip/dv/tools/vcs/cover.cfg
vendored
|
@ -28,12 +28,28 @@ begin tgl
|
|||
end
|
||||
|
||||
begin assert
|
||||
// These three assertions in prim_lc_sync check when `lc_ctrl_pkg::lc_tx_e` input is neither `On`
|
||||
// or `Off`, it is interrupted to the correct `On` or `Off` after one clock cycle. This behavior
|
||||
// is implemented outside of IP level design thus these assertions are not covered in IP level
|
||||
// testbenchs.
|
||||
// These three assertions in prim_lc_sync and prim_mubi* check when `lc_ctrl_pkg::lc_tx_t` or
|
||||
// `mubi*_t` input are neither `On` or `Off`, it is interrupted to the correct `On` or `Off`
|
||||
// after one clock cycle. This behavior is implemented outside of IP level design thus these
|
||||
// assertions are not covered in IP level testbenchs.
|
||||
// TODO: check these assertions in top-level or FPV.
|
||||
-assert PrimLcSyncCheckTransients_A
|
||||
-assert PrimLcSyncCheckTransients0_A
|
||||
-assert PrimLcSyncCheckTransients1_A
|
||||
|
||||
-assert PrimMubi4SyncCheckTransients_A
|
||||
-assert PrimMubi4SyncCheckTransients0_A
|
||||
-assert PrimMubi4SyncCheckTransients1_A
|
||||
|
||||
-assert PrimMubi8SyncCheckTransients_A
|
||||
-assert PrimMubi8SyncCheckTransients0_A
|
||||
-assert PrimMubi8SyncCheckTransients1_A
|
||||
|
||||
-assert PrimMubi12SyncCheckTransients_A
|
||||
-assert PrimMubi12SyncCheckTransients0_A
|
||||
-assert PrimMubi12SyncCheckTransients1_A
|
||||
|
||||
-assert PrimMubi16SyncCheckTransients_A
|
||||
-assert PrimMubi16SyncCheckTransients0_A
|
||||
-assert PrimMubi16SyncCheckTransients1_A
|
||||
end
|
||||
|
|
25
vendor/lowrisc_ip/dv/tools/xcelium/cover.ccf
vendored
25
vendor/lowrisc_ip/dv/tools/xcelium/cover.ccf
vendored
|
@ -24,3 +24,28 @@ select_coverage -toggle -module prim_esc_sender
|
|||
select_coverage -toggle -module prim_esc_receiver
|
||||
select_coverage -toggle -module prim_prince
|
||||
select_coverage -toggle -module prim_lfsr
|
||||
|
||||
// These three assertions in prim_lc_sync and prim_mubi* check when `lc_ctrl_pkg::lc_tx_t` or
|
||||
// `mubi*_t` input are neither `On` or `Off`, it is interrupted to the correct `On` or `Off`
|
||||
// after one clock cycle. This behavior is implemented outside of IP level design thus these
|
||||
// assertions are not covered in IP level testbenchs.
|
||||
// TODO: check these assertions in top-level or FPV.
|
||||
deselect_coverage -assertion *.PrimLcSyncCheckTransients_A
|
||||
deselect_coverage -assertion *.PrimLcSyncCheckTransients0_A
|
||||
deselect_coverage -assertion *.PrimLcSyncCheckTransients1_A
|
||||
|
||||
deselect_coverage -assertion *.PrimMubi4SyncCheckTransients_A
|
||||
deselect_coverage -assertion *.PrimMubi4SyncCheckTransients0_A
|
||||
deselect_coverage -assertion *.PrimMubi4SyncCheckTransients1_A
|
||||
|
||||
deselect_coverage -assertion PrimMubi8SyncCheckTransients_A
|
||||
deselect_coverage -assertion PrimMubi8SyncCheckTransients0_A
|
||||
deselect_coverage -assertion PrimMubi8SyncCheckTransients1_A
|
||||
|
||||
deselect_coverage -assertion PrimMubi12SyncCheckTransients_A
|
||||
deselect_coverage -assertion PrimMubi12SyncCheckTransients0_A
|
||||
deselect_coverage -assertion PrimMubi12SyncCheckTransients1_A
|
||||
|
||||
deselect_coverage -assertion PrimMubi16SyncCheckTransients_A
|
||||
deselect_coverage -assertion PrimMubi16SyncCheckTransients0_A
|
||||
deselect_coverage -assertion PrimMubi16SyncCheckTransients1_A
|
||||
|
|
221
vendor/lowrisc_ip/dv/verilator/cpp/ecc32_mem_area.cc
vendored
221
vendor/lowrisc_ip/dv/verilator/cpp/ecc32_mem_area.cc
vendored
|
@ -29,122 +29,133 @@ void Ecc32MemArea::LoadVmem(const std::string &path) const {
|
|||
"vmem files are not supported for memories with ECC bits");
|
||||
}
|
||||
|
||||
Ecc32MemArea::EccWords Ecc32MemArea::ReadWithIntegrity(
|
||||
uint32_t word_offset, uint32_t num_words) const {
|
||||
assert(word_offset + num_words <= num_words_);
|
||||
|
||||
// See MemArea::Write for an explanation for this buffer.
|
||||
uint8_t minibuf[SV_MEM_WIDTH_BYTES];
|
||||
memset(minibuf, 0, sizeof minibuf);
|
||||
assert(width_byte_ <= sizeof minibuf);
|
||||
|
||||
EccWords ret;
|
||||
ret.reserve(num_words);
|
||||
|
||||
for (uint32_t i = 0; i < num_words; ++i) {
|
||||
uint32_t src_word = word_offset + i;
|
||||
uint32_t phys_addr = ToPhysAddr(src_word);
|
||||
|
||||
ReadToMinibuf(minibuf, phys_addr);
|
||||
ReadBufferWithIntegrity(ret, minibuf, src_word);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Add bits to buf at bit_idx
|
||||
//
|
||||
// buf is assumed to be little-endian, so bit_idx 0 will refer to the bottom
|
||||
// bit of buf[0] and bit_idx 15 will refer to the top bit of buf[1].
|
||||
//
|
||||
// This takes the bottom count bits from new_bits (where count <= 8). It
|
||||
// assumes that the relevant place in buf is zeroed (simplifying the
|
||||
// read-modify-write cycle).
|
||||
static void insert_bits(uint8_t *buf, unsigned bit_idx, uint8_t new_bits,
|
||||
unsigned count) {
|
||||
assert(count <= 8);
|
||||
|
||||
buf += bit_idx / 8;
|
||||
bit_idx = bit_idx % 8;
|
||||
|
||||
while (count) {
|
||||
unsigned space_avail = 8 - bit_idx;
|
||||
unsigned to_take = std::min(space_avail, count);
|
||||
|
||||
uint8_t masked = ((1 << to_take) - 1) & new_bits;
|
||||
uint8_t shifted = masked << bit_idx;
|
||||
|
||||
*buf |= shifted;
|
||||
|
||||
++buf;
|
||||
bit_idx = 0;
|
||||
count -= to_take;
|
||||
new_bits >>= to_take;
|
||||
}
|
||||
}
|
||||
|
||||
// Extract bits from buf at bit_idx
|
||||
static uint8_t extract_bits(const uint8_t *buf, unsigned bit_idx,
|
||||
unsigned count) {
|
||||
assert(count <= 8);
|
||||
|
||||
uint8_t ret = 0;
|
||||
unsigned out_idx = 0;
|
||||
|
||||
buf += bit_idx / 8;
|
||||
bit_idx = bit_idx % 8;
|
||||
|
||||
while (count) {
|
||||
unsigned bits_avail = 8 - bit_idx;
|
||||
unsigned to_take = std::min(bits_avail, count);
|
||||
|
||||
uint8_t shifted = *buf >> bit_idx;
|
||||
uint8_t masked = shifted & ((1 << to_take) - 1);
|
||||
|
||||
ret |= masked << out_idx;
|
||||
|
||||
++buf;
|
||||
bit_idx = 0;
|
||||
count -= to_take;
|
||||
out_idx += to_take;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Ecc32MemArea::WriteBuffer(uint8_t buf[SV_MEM_WIDTH_BYTES],
|
||||
const std::vector<uint8_t> &data,
|
||||
size_t start_idx, uint32_t dst_word) const {
|
||||
int log_width_32 = width_byte_ / 4;
|
||||
int phy_width_bits = 39 * log_width_32;
|
||||
int phy_width_bytes = (phy_width_bits + 7) / 8;
|
||||
// The insert_bits routine assumes that the buffer will have been zeroed, so
|
||||
// do that here. Note that this buffer has (width_byte_ / 4) words, each of
|
||||
// which is 39 bits long. Divide this by 8, rounding up.
|
||||
size_t phys_size_bytes = (39 * (width_byte_ / 4) + 7) / 8;
|
||||
memset(buf, 0, phys_size_bytes);
|
||||
|
||||
// Start by collecting our width_byte_ input bytes into (width_byte_ / 4)
|
||||
// 32-bit groupings and adding check bits. (Eventually, we'll be adding
|
||||
// proper ECC check bits here but, since we're not checking yet, let's
|
||||
// zero-pad for now).
|
||||
//
|
||||
// TODO: Add proper ECC check bits here!
|
||||
struct expanded_t {
|
||||
uint8_t bytes[5];
|
||||
};
|
||||
|
||||
std::vector<expanded_t> expanded(log_width_32);
|
||||
for (int i = 0; i < log_width_32; ++i) {
|
||||
// Store things little-endian, so the "real bits" go in bytes 0 to 3 and
|
||||
// the check bits go in byte 4. Bytes 5 to 7 are zero.
|
||||
expanded_t next;
|
||||
memcpy(next.bytes, &data[start_idx + 4 * i], 4);
|
||||
next.bytes[4] = enc_secded_39_32(next.bytes);
|
||||
expanded[i] = next;
|
||||
}
|
||||
|
||||
// Now write to buf, one output byte at a time.
|
||||
for (int i = 0; i < phy_width_bytes; ++i) {
|
||||
int out_bit = i * 8;
|
||||
|
||||
// Acc is the accumulator we're building up for the byte that should be
|
||||
// written out. out_lsb is the LSB in acc to which we're writing at the
|
||||
// moment.
|
||||
uint8_t acc = 0;
|
||||
int out_lsb = 0;
|
||||
|
||||
// in_word_idx is the input word that we're reading from and in_word_lsb is
|
||||
// the first bit of that word that we're reading.
|
||||
int in_word_idx = out_bit / 39;
|
||||
int in_word_lsb = out_bit % 39;
|
||||
|
||||
// bits_left is the number of bits that we need to read for this byte. It's
|
||||
// usually initialised to 8, except for the last byte of the output word,
|
||||
// which might just have a few bits to contribute.
|
||||
int bits_left = std::min(8, phy_width_bits - out_bit);
|
||||
while (bits_left) {
|
||||
// in_byte_idx is the index of the byte within the (expanded_t) input
|
||||
// word that we're reading from. in_byte_lsb is the bit position within
|
||||
// that byte.
|
||||
int in_byte_idx = in_word_lsb / 8;
|
||||
int in_byte_lsb = in_word_lsb % 8;
|
||||
|
||||
// Most of the bytes in the expanded_t hold 8 bits of data, except the
|
||||
// top one, which only holds 7 (bits 39:32). bits_at_byte is the number
|
||||
// of bits that we're reading from this input byte, constrained by the
|
||||
// number of bits available and the number of bits that we want.
|
||||
int in_byte_width = (in_byte_idx == 4) ? 7 : 8;
|
||||
int bits_at_byte = std::min(in_byte_width - in_byte_lsb, bits_left);
|
||||
|
||||
// Extract bits_at_byte bits of input data from the relevant input byte,
|
||||
// starting at in_byte_lsb.
|
||||
uint8_t in_data = expanded[in_word_idx].bytes[in_byte_idx] >> in_byte_lsb;
|
||||
uint8_t in_mask = (((uint32_t)1 << bits_at_byte) - 1) & 0xff;
|
||||
uint8_t masked = in_data & in_mask;
|
||||
|
||||
// Add the extracted bits to acc, shifting them into position and
|
||||
// updating out_lsb for next time around.
|
||||
acc |= masked << out_lsb;
|
||||
out_lsb += bits_at_byte;
|
||||
|
||||
// Update input pointers to step over the byte we just consumed.
|
||||
if (in_byte_idx == 4) {
|
||||
++in_word_idx;
|
||||
in_word_lsb = 0;
|
||||
} else {
|
||||
in_word_lsb += bits_at_byte;
|
||||
}
|
||||
|
||||
// Subtract the bits we just read from the count we're expecting to read.
|
||||
bits_left -= bits_at_byte;
|
||||
for (int i = 0; i < width_byte_ / 4; ++i) {
|
||||
uint8_t check_bits = enc_secded_39_32(&data[start_idx + 4 * i]);
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
insert_bits(buf, 39 * i + 8 * j, data[start_idx + 4 * i + j], 8);
|
||||
}
|
||||
buf[i] = acc;
|
||||
insert_bits(buf, 39 * i + 32, check_bits, 7);
|
||||
}
|
||||
}
|
||||
|
||||
void Ecc32MemArea::ReadBuffer(std::vector<uint8_t> &data,
|
||||
const uint8_t buf[SV_MEM_WIDTH_BYTES],
|
||||
uint32_t src_word) const {
|
||||
for (int i = 0; i < width_byte_; ++i) {
|
||||
int in_word = i / 4;
|
||||
|
||||
int in_idx = (7 * in_word + 8 * i) / 8;
|
||||
int in_lsb = (7 * in_word + 8 * i) % 8;
|
||||
|
||||
uint8_t acc = 0;
|
||||
|
||||
int bits_left = 8;
|
||||
int out_lsb = 0;
|
||||
|
||||
while (bits_left) {
|
||||
uint8_t in_data = buf[in_idx] >> in_lsb;
|
||||
|
||||
int bits_at_idx = std::min(8 - in_lsb, bits_left);
|
||||
|
||||
// The mask for the bits to take from in_data.
|
||||
uint8_t in_mask = ((1u << bits_at_idx) - 1) & 0xff;
|
||||
|
||||
acc |= (in_data & in_mask) << out_lsb;
|
||||
|
||||
in_lsb = 0;
|
||||
out_lsb += bits_at_idx;
|
||||
bits_left -= bits_at_idx;
|
||||
++in_idx;
|
||||
for (int i = 0; i < width_byte_ / 4; ++i) {
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
data.push_back(extract_bits(buf, 39 * i + 8 * j, 8));
|
||||
}
|
||||
|
||||
data.push_back(acc);
|
||||
}
|
||||
}
|
||||
|
||||
void Ecc32MemArea::ReadBufferWithIntegrity(
|
||||
EccWords &data, const uint8_t buf[SV_MEM_WIDTH_BYTES],
|
||||
uint32_t src_word) const {
|
||||
for (int i = 0; i < width_byte_ / 4; ++i) {
|
||||
uint8_t buf32[4];
|
||||
uint32_t w32 = 0;
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
uint8_t byte = extract_bits(buf, 39 * i + 8 * j, 8);
|
||||
buf32[j] = byte;
|
||||
w32 |= (uint32_t)byte << 8 * j;
|
||||
}
|
||||
|
||||
uint8_t exp_check_bits = enc_secded_39_32(buf32);
|
||||
uint8_t check_bits = extract_bits(buf, 39 * i + 32, 7);
|
||||
bool good = check_bits == exp_check_bits;
|
||||
|
||||
data.push_back(std::make_pair(good, w32));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,22 @@ class Ecc32MemArea : public MemArea {
|
|||
|
||||
void LoadVmem(const std::string &path) const override;
|
||||
|
||||
typedef std::pair<bool, uint32_t> EccWord;
|
||||
typedef std::vector<EccWord> EccWords;
|
||||
|
||||
/** Read data with validity bits, starting at the given offset.
|
||||
*
|
||||
* This is equivalent to MemArea's Read method, but returns 32 bit
|
||||
* words, each with a boolean saying whether the integrity bits for
|
||||
* that word are valid or not.
|
||||
*
|
||||
* @param word_offset The offset, in words, of the first word that should be
|
||||
* read.
|
||||
*
|
||||
* @param num_words The number of words to read.
|
||||
*/
|
||||
EccWords ReadWithIntegrity(uint32_t word_offset, uint32_t num_words) const;
|
||||
|
||||
protected:
|
||||
void WriteBuffer(uint8_t buf[SV_MEM_WIDTH_BYTES],
|
||||
const std::vector<uint8_t> &data, size_t start_idx,
|
||||
|
@ -32,6 +48,20 @@ class Ecc32MemArea : public MemArea {
|
|||
void ReadBuffer(std::vector<uint8_t> &data,
|
||||
const uint8_t buf[SV_MEM_WIDTH_BYTES],
|
||||
uint32_t src_word) const override;
|
||||
|
||||
/** Extract the logical words corresponding to the physical memory contents
|
||||
* in \p buf, together with validity bits. Append them to \p data.
|
||||
*
|
||||
* @param data The target, onto which the extracted memory words should
|
||||
* be appended.
|
||||
*
|
||||
* @param buf Source buffer (physical memory bits)
|
||||
*
|
||||
* @param src_word Logical address of the location being read
|
||||
*/
|
||||
virtual void ReadBufferWithIntegrity(EccWords &data,
|
||||
const uint8_t buf[SV_MEM_WIDTH_BYTES],
|
||||
uint32_t src_word) const;
|
||||
};
|
||||
|
||||
#endif // OPENTITAN_HW_DV_VERILATOR_CPP_ECC32_MEM_AREA_H_
|
||||
|
|
26
vendor/lowrisc_ip/dv/verilator/cpp/mem_area.cc
vendored
26
vendor/lowrisc_ip/dv/verilator/cpp/mem_area.cc
vendored
|
@ -81,21 +81,7 @@ std::vector<uint8_t> MemArea::Read(uint32_t word_offset,
|
|||
uint32_t src_word = word_offset + i;
|
||||
uint32_t phys_addr = ToPhysAddr(src_word);
|
||||
|
||||
{
|
||||
// Both ToPhysAddr and ReadBuffer might set the scope with `SVScoped`.
|
||||
// Keep the `SVScoped` here confined to an inner scope so they don't
|
||||
// interact causing incorrect relative path behaviour. If this fails to
|
||||
// set scope, it will throw an error which should be caught at this
|
||||
// function's callsite.
|
||||
SVScoped scoped(scope_);
|
||||
if (!simutil_get_mem(phys_addr, (svBitVecVal *)minibuf)) {
|
||||
std::ostringstream oss;
|
||||
oss << "Could not read memory at byte offset 0x" << std::hex
|
||||
<< src_word * width_byte_ << ".";
|
||||
throw std::runtime_error(oss.str());
|
||||
}
|
||||
}
|
||||
|
||||
ReadToMinibuf(minibuf, phys_addr);
|
||||
ReadBuffer(ret, minibuf, src_word);
|
||||
}
|
||||
|
||||
|
@ -126,3 +112,13 @@ void MemArea::ReadBuffer(std::vector<uint8_t> &data,
|
|||
std::copy_n(reinterpret_cast<const char *>(buf), width_byte_,
|
||||
std::back_inserter(data));
|
||||
}
|
||||
|
||||
void MemArea::ReadToMinibuf(uint8_t *minibuf, uint32_t phys_addr) const {
|
||||
SVScoped scoped(scope_);
|
||||
if (!simutil_get_mem(phys_addr, (svBitVecVal *)minibuf)) {
|
||||
std::ostringstream oss;
|
||||
oss << "Could not read memory word at physical index 0x" << std::hex
|
||||
<< phys_addr << ".";
|
||||
throw std::runtime_error(oss.str());
|
||||
}
|
||||
}
|
||||
|
|
12
vendor/lowrisc_ip/dv/verilator/cpp/mem_area.h
vendored
12
vendor/lowrisc_ip/dv/verilator/cpp/mem_area.h
vendored
|
@ -109,10 +109,11 @@ class MemArea {
|
|||
* across. Other implementations might undo scrambling, remove ECC bits or
|
||||
* similar.
|
||||
*
|
||||
* @param data The target, onto which the extracted memory contents should
|
||||
* be appended.
|
||||
* @param data The target, onto which the extracted memory contents
|
||||
* should be appended.
|
||||
*
|
||||
* @param buf Source buffer (physical memory bits)
|
||||
*
|
||||
* @param src_word Logical address of the location being read
|
||||
*/
|
||||
virtual void ReadBuffer(std::vector<uint8_t> &data,
|
||||
|
@ -129,6 +130,13 @@ class MemArea {
|
|||
virtual uint32_t ToPhysAddr(uint32_t logical_addr) const {
|
||||
return logical_addr;
|
||||
}
|
||||
|
||||
/** Read the memory word at phys_addr into minibuf
|
||||
*
|
||||
* minibuf should be at least SV_MEM_WIDTH_BYTES in size. See the
|
||||
* implementation of MemArea::Write() for the details.
|
||||
*/
|
||||
void ReadToMinibuf(uint8_t *minibuf, uint32_t phys_addr) const;
|
||||
};
|
||||
|
||||
#endif // OPENTITAN_HW_DV_VERILATOR_CPP_MEM_AREA_H_
|
||||
|
|
|
@ -81,12 +81,27 @@ static uint32_t vbits(uint32_t size) {
|
|||
return width;
|
||||
}
|
||||
|
||||
// These functions come from SV code, exposed over DPI. They are defined inside
|
||||
// a module (prim_ram1p_scr) and, awkwardly, if a design doesn't happen to use
|
||||
// that module then some simulators (Verilator!) will discard it, together with
|
||||
// the DPI functions.
|
||||
//
|
||||
// We'd like to be able to use the memutil_dpi_scrambled.core whether or not we
|
||||
// actually instantiated prim_ram1p_scr: we'll just spit out an error if we
|
||||
// call GetScrambleKey() or GetScrambleNonce() if we didn't instantiate it. To
|
||||
// make this work, we mark both symbols weak.
|
||||
extern "C" {
|
||||
int simutil_get_scramble_key(svBitVecVal *key);
|
||||
int simutil_get_scramble_nonce(svBitVecVal *nonce);
|
||||
int __attribute__((weak)) simutil_get_scramble_key(svBitVecVal *key);
|
||||
int __attribute__((weak)) simutil_get_scramble_nonce(svBitVecVal *nonce);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> ScrambledEcc32MemArea::GetScrambleKey() const {
|
||||
if (!simutil_get_scramble_key) {
|
||||
throw std::runtime_error(
|
||||
"No definition of simutil_get_scramble_key. "
|
||||
"Does the design actually use prim_ram1p_scr?");
|
||||
}
|
||||
|
||||
SVScoped scoped(scr_scope_);
|
||||
svBitVecVal key_minibuf[((kPrinceWidthByte * 2) + 3) / 4];
|
||||
|
||||
|
@ -102,6 +117,12 @@ std::vector<uint8_t> ScrambledEcc32MemArea::GetScrambleKey() const {
|
|||
std::vector<uint8_t> ScrambledEcc32MemArea::GetScrambleNonce() const {
|
||||
assert(GetNonceWidthByte() <= kScrMaxNonceWidthByte);
|
||||
|
||||
if (!simutil_get_scramble_nonce) {
|
||||
throw std::runtime_error(
|
||||
"No definition of simutil_get_scramble_nonce. "
|
||||
"Does the design actually use prim_ram1p_scr?");
|
||||
}
|
||||
|
||||
SVScoped scoped(scr_scope_);
|
||||
svBitVecVal nonce_minibuf[(kScrMaxNonceWidthByte + 3) / 4];
|
||||
|
||||
|
@ -169,20 +190,30 @@ void ScrambledEcc32MemArea::WriteBuffer(uint8_t buf[SV_MEM_WIDTH_BYTES],
|
|||
std::copy(scramble_buf.begin(), scramble_buf.end(), &buf[0]);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> ScrambledEcc32MemArea::ReadUnscrambled(
|
||||
const uint8_t buf[SV_MEM_WIDTH_BYTES], uint32_t src_word) const {
|
||||
std::vector<uint8_t> scrambled_data(buf, buf + GetPhysWidthByte());
|
||||
return scramble_decrypt_data(
|
||||
scrambled_data, GetPhysWidth(), 39, AddrIntToBytes(src_word, addr_width_),
|
||||
addr_width_, GetScrambleNonce(), GetScrambleKey(), repeat_keystream_);
|
||||
}
|
||||
|
||||
void ScrambledEcc32MemArea::ReadBuffer(std::vector<uint8_t> &data,
|
||||
const uint8_t buf[SV_MEM_WIDTH_BYTES],
|
||||
uint32_t src_word) const {
|
||||
// Unscramble data from read buffer
|
||||
std::vector<uint8_t> scrambled_data =
|
||||
std::vector<uint8_t>(buf, buf + GetPhysWidthByte());
|
||||
std::vector<uint8_t> unscrambled_data = scramble_decrypt_data(
|
||||
scrambled_data, GetPhysWidth(), 39, AddrIntToBytes(src_word, addr_width_),
|
||||
addr_width_, GetScrambleNonce(), GetScrambleKey(), repeat_keystream_);
|
||||
|
||||
std::vector<uint8_t> unscrambled_data = ReadUnscrambled(buf, src_word);
|
||||
// Strip integrity to give final result
|
||||
Ecc32MemArea::ReadBuffer(data, &unscrambled_data[0], src_word);
|
||||
}
|
||||
|
||||
void ScrambledEcc32MemArea::ReadBufferWithIntegrity(
|
||||
EccWords &data, const uint8_t buf[SV_MEM_WIDTH_BYTES],
|
||||
uint32_t src_word) const {
|
||||
std::vector<uint8_t> unscrambled_data = ReadUnscrambled(buf, src_word);
|
||||
// Strip integrity to give final result
|
||||
Ecc32MemArea::ReadBufferWithIntegrity(data, &unscrambled_data[0], src_word);
|
||||
}
|
||||
|
||||
uint32_t ScrambledEcc32MemArea::ToPhysAddr(uint32_t logical_addr) const {
|
||||
// Scramble logical address to get physical address
|
||||
return AddrBytesToInt(scramble_addr(AddrIntToBytes(logical_addr, addr_width_),
|
||||
|
|
|
@ -37,10 +37,17 @@ class ScrambledEcc32MemArea : public Ecc32MemArea {
|
|||
const std::vector<uint8_t> &data, size_t start_idx,
|
||||
uint32_t dst_word) const override;
|
||||
|
||||
std::vector<uint8_t> ReadUnscrambled(const uint8_t buf[SV_MEM_WIDTH_BYTES],
|
||||
uint32_t src_word) const;
|
||||
|
||||
void ReadBuffer(std::vector<uint8_t> &data,
|
||||
const uint8_t buf[SV_MEM_WIDTH_BYTES],
|
||||
uint32_t src_word) const override;
|
||||
|
||||
void ReadBufferWithIntegrity(EccWords &data,
|
||||
const uint8_t buf[SV_MEM_WIDTH_BYTES],
|
||||
uint32_t src_word) const override;
|
||||
|
||||
uint32_t ToPhysAddr(uint32_t logical_addr) const override;
|
||||
|
||||
uint32_t GetPhysWidth() const;
|
||||
|
|
|
@ -40,5 +40,14 @@
|
|||
"-I{build_dir}/src/{scramble_model_dir}",
|
||||
"-lelf"]
|
||||
}
|
||||
|
||||
{
|
||||
name: dsim_memutil_dpi_scrambled_build_opts
|
||||
build_opts: ["-c-opts -I{build_dir}/src/{memutil_dpi_src_dir}/cpp",
|
||||
"-c-opts -I{build_dir}/src/{memutil_dpi_scrambled_src_dir}/cpp",
|
||||
"-c-opts -I{build_dir}/src/{prince_ref_src_dir}",
|
||||
"-c-opts -I{build_dir}/src/{scramble_model_dir}",
|
||||
"-ld-opts -lelf"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
158
vendor/lowrisc_ip/ip/prim/data/prim_mubi_pkg.sv.tpl
vendored
158
vendor/lowrisc_ip/ip/prim/data/prim_mubi_pkg.sv.tpl
vendored
|
@ -1,158 +0,0 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
// ------------------- W A R N I N G: A U T O - G E N E R A T E D C O D E !! -------------------//
|
||||
// PLEASE DO NOT HAND-EDIT THIS FILE. IT HAS BEEN AUTO-GENERATED WITH THE FOLLOWING COMMAND:
|
||||
//
|
||||
// hw/ip/prim/util/generate_prim_mubi_pkg.py hw/ip/prim/data/prim_mubi_pkg.sv.tpl >
|
||||
// hw/ip/prim/rtl/prim_mubi_pkg.sv
|
||||
//
|
||||
// This package defines common multibit signal types, active high and active low values and
|
||||
// the corresponding functions to test whether the values are set or not.
|
||||
|
||||
package prim_mubi_pkg;
|
||||
|
||||
% for n in range(1, n_max_nibbles + 1):
|
||||
<%
|
||||
nbits = n * 4
|
||||
hi_val = ''
|
||||
lo_val = ''
|
||||
for k in range(1,n+1):
|
||||
hi_val = ('5' if (k % 2) else 'A') + hi_val
|
||||
lo_val = ('A' if (k % 2) else '5') + lo_val
|
||||
%>\
|
||||
//////////////////////////////////////////////
|
||||
// ${nbits} Bit Multibit Type and Functions //
|
||||
//////////////////////////////////////////////
|
||||
|
||||
parameter int MuBi${nbits}Width = ${nbits};
|
||||
typedef enum logic [MuBi${nbits}Width-1:0] {
|
||||
MuBi${nbits}Hi = ${nbits}'h${hi_val}, // enabled
|
||||
MuBi${nbits}Lo = ${nbits}'h${lo_val} // disabled
|
||||
} mubi${nbits}_e;
|
||||
|
||||
// make a typedef such that this can be used as an intersignal type as well
|
||||
typedef mubi${nbits}_e mubi${nbits}_t;
|
||||
|
||||
// Return the multibit value to signal "enabled".
|
||||
function automatic mubi${nbits}_e mubi${nbits}_hi_value();
|
||||
return MuBi${nbits}Hi;
|
||||
endfunction : mubi${nbits}_hi_value
|
||||
|
||||
// Return the multibit value to signal "disabled".
|
||||
function automatic mubi${nbits}_e mubi${nbits}_lo_value();
|
||||
return MuBi${nbits}Lo;
|
||||
endfunction : mubi${nbits}_lo_value
|
||||
|
||||
// Test whether the multibit value signals an "enabled" condition.
|
||||
// The strict version of this function requires
|
||||
// the multibit value to equal Hi.
|
||||
function automatic logic mubi${nbits}_tst_hi_strict(mubi${nbits}_e val);
|
||||
return MuBi${nbits}Hi == val;
|
||||
endfunction : mubi${nbits}_tst_hi_strict
|
||||
|
||||
// Test whether the multibit value signals a "disabled" condition.
|
||||
// The strict version of this function requires
|
||||
// the multibit value to equal Lo.
|
||||
function automatic logic mubi${nbits}_tst_lo_strict(mubi${nbits}_e val);
|
||||
return MuBi${nbits}Lo == val;
|
||||
endfunction : mubi${nbits}_tst_lo_strict
|
||||
|
||||
// Test whether the multibit value signals an "enabled" condition.
|
||||
// The loose version of this function interprets all
|
||||
// values other than Lo as "enabled".
|
||||
function automatic logic mubi${nbits}_tst_hi_loose(mubi${nbits}_e val);
|
||||
return MuBi${nbits}Lo != val;
|
||||
endfunction : mubi${nbits}_tst_hi_loose
|
||||
|
||||
// Test whether the multibit value signals a "disabled" condition.
|
||||
// The loose version of this function interprets all
|
||||
// values other than Hi as "disabled".
|
||||
function automatic logic mubi${nbits}_tst_lo_loose(mubi${nbits}_e val);
|
||||
return MuBi${nbits}Hi != val;
|
||||
endfunction : mubi${nbits}_tst_lo_loose
|
||||
|
||||
|
||||
// Performs a logical OR operation between two multibit values.
|
||||
// This treats "act" as logical 1, and all other values are
|
||||
// treated as 0. Truth table:
|
||||
//
|
||||
// A | B | OUT
|
||||
//------+------+-----
|
||||
// !act | !act | !act
|
||||
// act | !act | act
|
||||
// !act | act | act
|
||||
// act | act | act
|
||||
//
|
||||
function automatic mubi${nbits}_e mubi${nbits}_or(mubi${nbits}_e a, mubi${nbits}_e b, mubi${nbits}_e act);
|
||||
logic [MuBi${nbits}Width-1:0] a_in, b_in, act_in, out;
|
||||
a_in = a;
|
||||
b_in = b;
|
||||
act_in = act;
|
||||
for (int k = 0; k < MuBi${nbits}Width; k++) begin
|
||||
if (act_in[k]) begin
|
||||
out[k] = a_in[k] || b_in[k];
|
||||
end else begin
|
||||
out[k] = a_in[k] && b_in[k];
|
||||
end
|
||||
end
|
||||
return mubi${nbits}_e'(out);
|
||||
endfunction : mubi${nbits}_or
|
||||
|
||||
// Performs a logical AND operation between two multibit values.
|
||||
// This treats "act" as logical 1, and all other values are
|
||||
// treated as 0. Truth table:
|
||||
//
|
||||
// A | B | OUT
|
||||
//------+------+-----
|
||||
// !act | !act | !act
|
||||
// act | !act | !act
|
||||
// !act | act | !act
|
||||
// act | act | act
|
||||
//
|
||||
function automatic mubi${nbits}_e mubi${nbits}_and(mubi${nbits}_e a, mubi${nbits}_e b, mubi${nbits}_e act);
|
||||
logic [MuBi${nbits}Width-1:0] a_in, b_in, act_in, out;
|
||||
a_in = a;
|
||||
b_in = b;
|
||||
act_in = act;
|
||||
for (int k = 0; k < MuBi${nbits}Width; k++) begin
|
||||
if (act_in[k]) begin
|
||||
out[k] = a_in[k] && b_in[k];
|
||||
end else begin
|
||||
out[k] = a_in[k] || b_in[k];
|
||||
end
|
||||
end
|
||||
return mubi${nbits}_e'(out);
|
||||
endfunction : mubi${nbits}_and
|
||||
|
||||
// Performs a logical OR operation between two multibit values.
|
||||
// This treats "Hi" as logical 1, and all other values are
|
||||
// treated as 0.
|
||||
function automatic mubi${nbits}_e mubi${nbits}_or_hi(mubi${nbits}_e a, mubi${nbits}_e b);
|
||||
return mubi${nbits}_or(a, b, MuBi${nbits}Hi);
|
||||
endfunction : mubi${nbits}_or_hi
|
||||
|
||||
// Performs a logical AND operation between two multibit values.
|
||||
// This treats "Hi" as logical 1, and all other values are
|
||||
// treated as 0.
|
||||
function automatic mubi${nbits}_e mubi${nbits}_and_hi(mubi${nbits}_e a, mubi${nbits}_e b);
|
||||
return mubi${nbits}_and(a, b, MuBi${nbits}Hi);
|
||||
endfunction : mubi${nbits}_and_hi
|
||||
|
||||
// Performs a logical OR operation between two multibit values.
|
||||
// This treats "Lo" as logical 1, and all other values are
|
||||
// treated as 0.
|
||||
function automatic mubi${nbits}_e mubi${nbits}_or_lo(mubi${nbits}_e a, mubi${nbits}_e b);
|
||||
return mubi${nbits}_or(a, b, MuBi${nbits}Lo);
|
||||
endfunction : mubi${nbits}_or_lo
|
||||
|
||||
// Performs a logical AND operation between two multibit values.
|
||||
// Tlos treats "Lo" as logical 1, and all other values are
|
||||
// treated as 0.
|
||||
function automatic mubi${nbits}_e mubi${nbits}_and_lo(mubi${nbits}_e a, mubi${nbits}_e b);
|
||||
return mubi${nbits}_and(a, b, MuBi${nbits}Lo);
|
||||
endfunction : mubi${nbits}_and_lo
|
||||
|
||||
% endfor
|
||||
endpackage : prim_mubi_pkg
|
76
vendor/lowrisc_ip/ip/prim/doc/prim_xoshiro256pp.md
vendored
Normal file
76
vendor/lowrisc_ip/ip/prim/doc/prim_xoshiro256pp.md
vendored
Normal file
|
@ -0,0 +1,76 @@
|
|||
---
|
||||
title: "Primitive Component: XoShiRo256++"
|
||||
---
|
||||
|
||||
# Overviewtitle
|
||||
|
||||
`prim_xoshiro256pp` is a PRNG with 256 bit state.
|
||||
For more information refer to [this page](https://arxiv.org/pdf/1805.01407.pdf).
|
||||
|
||||
## Parameters
|
||||
|
||||
Name | type | Description
|
||||
-------------|--------|----------------------------------------------------------
|
||||
OutputDw | int | Width of the PRNG output. Must be a multiple of 64.
|
||||
DefaultSeed | logic | Initial 256-bit state of the PRNG, must be nonzero.
|
||||
|
||||
## Signal Interfaces
|
||||
|
||||
Name | In/Out | Description
|
||||
---------------------|--------|---------------------------------
|
||||
seed_en_i | input | External seed input enable
|
||||
seed_i[256] | input | External seed input
|
||||
xoshiro_en_i | input | PRNG enable
|
||||
entropy_i[256] | input | Entropy input
|
||||
data_o[OutputDw] | output | PRNG output
|
||||
all_zero_o | output | Impossible all-zero state
|
||||
|
||||
# Theory of Operations
|
||||
|
||||
```
|
||||
/----------------\
|
||||
seed_en_i | |
|
||||
------------>| xoshiro256++ |
|
||||
seed_i | | data_o
|
||||
=====/======>| |=====/=======>
|
||||
[256] | | [OutputDw]
|
||||
xoshiro_en_i | |
|
||||
------------>| OutputDw |
|
||||
entropy_i | DefaultSeed | all_zero_o
|
||||
=====/======>| |------------->
|
||||
[256] | |
|
||||
| |
|
||||
\----------------/
|
||||
```
|
||||
|
||||
Xoshiro256++ PRNG consists of:
|
||||
* 256b state
|
||||
* A single-cycle state-update function.
|
||||
* A state output function.
|
||||
|
||||
The basic xoshiro256++ PRNG has a 64 bit output.
|
||||
This implementation enables the output size to be any multiple of 64 bits.
|
||||
The output size controlled using the `OutputDW` parameter.
|
||||
|
||||
The xoshiro256++ module has an enable input and an additional entropy input that is
|
||||
XOR'ed into the PRNG state (connect to zero if this feature is unused).
|
||||
As the PRNG may jump into the all-zero state (e.g. due to an active attack), the PRNG
|
||||
state-update function contains a lockup protection which re-seeds the state with
|
||||
`DefaultSeed` and raises the alert signal `all_zero_o`, once this condition is detected.
|
||||
|
||||
When the seed enable signal `seed_en_i` is raised, the internal state of xoshiro256++ is updated
|
||||
with the value provided at the 256b input 'seed_i'.
|
||||
The state is internaly updated in every clock cycle whenever the enable signal `xoshiro_en_i` is raised.
|
||||
The timing diagram below visualizes this process.
|
||||
|
||||
{{< wavejson >}}
|
||||
{
|
||||
signal: [
|
||||
{name: 'clk', wave: 'p......|....'},
|
||||
{name: 'xoshiro_en_i', wave: '0...1..|..0.'},
|
||||
{name: 'seed_en_i', wave: '010....|....'},
|
||||
{name:'seed_i', wave: '3..x...|....', data: 'Seed' },
|
||||
{name: 'state', wave: 'x.3..45|678.', data: 'Seed'}
|
||||
]
|
||||
}
|
||||
{{< /wavejson >}}
|
|
@ -34,6 +34,24 @@
|
|||
"prim_sync_fatal_alert"]
|
||||
}
|
||||
|
||||
{
|
||||
name: prim_alert_init_trigger_test
|
||||
desc: '''Verify init_trigger input from prim_alert_receiver.
|
||||
|
||||
Based on the prim_alert_test, this test adds a parallel sequence to randomly drive
|
||||
init_trigger_i in prim_alert_receiver.
|
||||
|
||||
Check if alert sender/receiver pairs can resume normal handshake after init_trigger_i
|
||||
is set.
|
||||
For fatal alert, check if fatal alerts keep firing until reset is issued.
|
||||
'''
|
||||
milestone: V1
|
||||
tests: ["prim_async_alert",
|
||||
"prim_async_fatal_alert",
|
||||
"prim_sync_alert",
|
||||
"prim_sync_fatal_alert"]
|
||||
}
|
||||
|
||||
{
|
||||
name: prim_alert_ping_request_test
|
||||
desc: '''Verify ping request from prim_alert_sender.
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
import_cfgs: ["{proj_root}/hw/dv/tools/dvsim/common_sim_cfg.hjson"]
|
||||
|
||||
// Default iterations for all tests - each test entry can override this.
|
||||
reseed: 1
|
||||
reseed: 20
|
||||
|
||||
build_modes: [
|
||||
{
|
||||
|
|
|
@ -39,6 +39,9 @@ module prim_alert_tb;
|
|||
// The main concern here is the minimal wait cycles between each handshake.
|
||||
localparam int MinHandshakeWait = 2 + WaitCycle;
|
||||
|
||||
// Clock cycles for alert init handshake to finish.
|
||||
localparam int WaitAlertInitDone = 30;
|
||||
|
||||
typedef enum bit [3:0]{
|
||||
AlertSet,
|
||||
AlertAckSet,
|
||||
|
@ -71,7 +74,7 @@ module prim_alert_tb;
|
|||
logic ping_req, ping_ok, integ_fail, alert_o;
|
||||
prim_alert_pkg::alert_rx_t alert_rx;
|
||||
prim_alert_pkg::alert_tx_t alert_tx;
|
||||
|
||||
prim_mubi_pkg::mubi4_t init_trig = prim_mubi_pkg::MuBi4False;
|
||||
prim_alert_sender #(
|
||||
.AsyncOn(IsAsync),
|
||||
.IsFatal(IsFatal)
|
||||
|
@ -91,8 +94,7 @@ module prim_alert_tb;
|
|||
) i_alert_receiver (
|
||||
.clk_i(clk),
|
||||
.rst_ni(rst_n),
|
||||
// TODO: randomly trigger this
|
||||
.init_trig_i(lc_ctrl_pkg::Off),
|
||||
.init_trig_i(init_trig),
|
||||
.ping_req_i(ping_req),
|
||||
.ping_ok_o(ping_ok),
|
||||
.integ_fail_o(integ_fail),
|
||||
|
@ -203,35 +205,54 @@ module prim_alert_tb;
|
|||
main_clk.apply_reset();
|
||||
|
||||
// Wait for initialization sequence to end
|
||||
// This should take no more than 20 cycles
|
||||
// if the sender / receiver clocks are on
|
||||
// the same clock domain.
|
||||
main_clk.wait_clks(20);
|
||||
main_clk.wait_clks(WaitAlertInitDone);
|
||||
|
||||
// Sequence 1). Alert request sequence.
|
||||
main_clk.wait_clks($urandom_range(0, 10));
|
||||
alert_req = 1;
|
||||
fork
|
||||
begin
|
||||
for (int num_trans = 1; num_trans <= 10; num_trans++) begin
|
||||
int rand_wait_alert_req = $urandom_range(MinHandshakeWait, 10);
|
||||
int rand_wait_init_trig = $urandom_range(0, 30);
|
||||
fork
|
||||
begin
|
||||
main_clk.wait_clks(rand_wait_alert_req);
|
||||
alert_req = 1;
|
||||
fork
|
||||
begin
|
||||
main_clk.wait_clks(1);
|
||||
check_alert_handshake(.exp_ping_value(0));
|
||||
end
|
||||
// While waiting to check alert handshake, reset alert_req as soon as alert is acked to
|
||||
// avoid triggering multiple alert requests.
|
||||
begin
|
||||
wait (alert_ack == 1);
|
||||
alert_req = 0;
|
||||
end
|
||||
join
|
||||
end
|
||||
begin
|
||||
main_clk.wait_clks(rand_wait_init_trig);
|
||||
init_trig = prim_mubi_pkg::MuBi4True;
|
||||
end
|
||||
join_any
|
||||
disable fork;
|
||||
if (init_trig == prim_mubi_pkg::MuBi4True) begin
|
||||
alert_req = 0;
|
||||
main_clk.wait_clks($urandom_range(0, 10));
|
||||
init_trig = prim_mubi_pkg::MuBi4False;
|
||||
main_clk.wait_clks(WaitAlertInitDone);
|
||||
end
|
||||
// For fatal alert, ensure alert keeps firing until reset.
|
||||
// This check is valid if the alert is fatal, and alert is requested before init request.
|
||||
if (IsFatal && (rand_wait_alert_req + 1) <= rand_wait_init_trig) begin
|
||||
main_clk.wait_clks($urandom_range(10, 100));
|
||||
wait (alert_tx.alert_p == 0);
|
||||
wait (alert_tx.alert_p == 1);
|
||||
main_clk.wait_clks(1);
|
||||
check_alert_handshake(.exp_ping_value(0));
|
||||
main_clk.apply_reset();
|
||||
main_clk.wait_clks(WaitAlertInitDone);
|
||||
end
|
||||
begin
|
||||
wait (alert_ack == 1);
|
||||
alert_req = 0;
|
||||
end
|
||||
join
|
||||
|
||||
// If alert is fatal, check alert will continuously fire until reset.
|
||||
if (IsFatal) begin
|
||||
main_clk.wait_clks($urandom_range(10, 1000));
|
||||
wait (alert_tx.alert_p == 0);
|
||||
wait (alert_tx.alert_p == 1);
|
||||
main_clk.wait_clks(1);
|
||||
check_alert_handshake(.exp_ping_value(0));
|
||||
main_clk.apply_reset();
|
||||
$display("Alert request sequence %0d/10 finished!", num_trans);
|
||||
end
|
||||
$display("Alert request sequence finished!");
|
||||
|
||||
// Sequence 2). Alert test sequence.
|
||||
main_clk.wait_clks($urandom_range(MinHandshakeWait, 10));
|
||||
|
|
|
@ -11,7 +11,7 @@ filesets:
|
|||
- lowrisc:prim:alert
|
||||
files:
|
||||
- vip/prim_alert_rxtx_async_assert_fpv.sv
|
||||
- tb/prim_alert_rxtx_async_fatal_fpv.sv
|
||||
- tb/prim_alert_rxtx_async_fatal_tb.sv
|
||||
- tb/prim_alert_rxtx_async_fatal_bind_fpv.sv
|
||||
file_type: systemVerilogSource
|
||||
|
||||
|
@ -23,7 +23,7 @@ targets:
|
|||
filesets:
|
||||
- files_formal
|
||||
toplevel:
|
||||
- prim_alert_rxtx_async_fatal_fpv
|
||||
- prim_alert_rxtx_async_fatal_tb
|
||||
|
||||
formal:
|
||||
<<: *default_target
|
||||
|
|
|
@ -11,7 +11,7 @@ filesets:
|
|||
- lowrisc:prim:alert
|
||||
files:
|
||||
- vip/prim_alert_rxtx_async_assert_fpv.sv
|
||||
- tb/prim_alert_rxtx_async_fpv.sv
|
||||
- tb/prim_alert_rxtx_async_tb.sv
|
||||
- tb/prim_alert_rxtx_async_bind_fpv.sv
|
||||
file_type: systemVerilogSource
|
||||
|
||||
|
@ -23,7 +23,7 @@ targets:
|
|||
filesets:
|
||||
- files_formal
|
||||
toplevel:
|
||||
- prim_alert_rxtx_async_fpv
|
||||
- prim_alert_rxtx_async_tb
|
||||
|
||||
formal:
|
||||
<<: *default_target
|
||||
|
|
|
@ -11,7 +11,7 @@ filesets:
|
|||
- lowrisc:prim:alert
|
||||
files:
|
||||
- vip/prim_alert_rxtx_assert_fpv.sv
|
||||
- tb/prim_alert_rxtx_fatal_fpv.sv
|
||||
- tb/prim_alert_rxtx_fatal_tb.sv
|
||||
- tb/prim_alert_rxtx_fatal_bind_fpv.sv
|
||||
file_type: systemVerilogSource
|
||||
|
||||
|
@ -23,7 +23,7 @@ targets:
|
|||
filesets:
|
||||
- files_formal
|
||||
toplevel:
|
||||
- prim_alert_rxtx_fatal_fpv
|
||||
- prim_alert_rxtx_fatal_tb
|
||||
|
||||
formal:
|
||||
<<: *default_target
|
||||
|
|
|
@ -11,7 +11,7 @@ filesets:
|
|||
- lowrisc:prim:alert
|
||||
files:
|
||||
- vip/prim_alert_rxtx_assert_fpv.sv
|
||||
- tb/prim_alert_rxtx_fpv.sv
|
||||
- tb/prim_alert_rxtx_tb.sv
|
||||
- tb/prim_alert_rxtx_bind_fpv.sv
|
||||
file_type: systemVerilogSource
|
||||
|
||||
|
@ -23,7 +23,7 @@ targets:
|
|||
filesets:
|
||||
- files_formal
|
||||
toplevel:
|
||||
- prim_alert_rxtx_fpv
|
||||
- prim_alert_rxtx_tb
|
||||
|
||||
formal:
|
||||
<<: *default_target
|
||||
|
|
|
@ -9,7 +9,7 @@ filesets:
|
|||
depend:
|
||||
- lowrisc:prim:all
|
||||
files:
|
||||
- tb/prim_arbiter_fixed_fpv.sv
|
||||
- tb/prim_arbiter_fixed_tb.sv
|
||||
file_type: systemVerilogSource
|
||||
|
||||
targets:
|
||||
|
@ -19,7 +19,7 @@ targets:
|
|||
default_tool: icarus
|
||||
filesets:
|
||||
- files_formal
|
||||
toplevel: prim_arbiter_fixed_fpv
|
||||
toplevel: prim_arbiter_fixed_tb
|
||||
|
||||
formal:
|
||||
<<: *default_target
|
||||
|
|
|
@ -9,7 +9,7 @@ filesets:
|
|||
depend:
|
||||
- lowrisc:prim:all
|
||||
files:
|
||||
- tb/prim_arbiter_ppc_fpv.sv
|
||||
- tb/prim_arbiter_ppc_tb.sv
|
||||
file_type: systemVerilogSource
|
||||
|
||||
targets:
|
||||
|
@ -19,7 +19,7 @@ targets:
|
|||
default_tool: icarus
|
||||
filesets:
|
||||
- files_formal
|
||||
toplevel: prim_arbiter_ppc_fpv
|
||||
toplevel: prim_arbiter_ppc_tb
|
||||
|
||||
formal:
|
||||
<<: *default_target
|
||||
|
|
|
@ -9,7 +9,7 @@ filesets:
|
|||
depend:
|
||||
- lowrisc:prim:all
|
||||
files:
|
||||
- tb/prim_arbiter_tree_fpv.sv
|
||||
- tb/prim_arbiter_tree_tb.sv
|
||||
file_type: systemVerilogSource
|
||||
|
||||
targets:
|
||||
|
@ -19,7 +19,7 @@ targets:
|
|||
default_tool: icarus
|
||||
filesets:
|
||||
- files_formal
|
||||
toplevel: prim_arbiter_tree_fpv
|
||||
toplevel: prim_arbiter_tree_tb
|
||||
|
||||
formal:
|
||||
<<: *default_target
|
||||
|
|
29
vendor/lowrisc_ip/ip/prim/fpv/prim_count_fpv.core
vendored
Normal file
29
vendor/lowrisc_ip/ip/prim/fpv/prim_count_fpv.core
vendored
Normal file
|
@ -0,0 +1,29 @@
|
|||
CAPI=2:
|
||||
# Copyright lowRISC contributors.
|
||||
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
name: "lowrisc:fpv:prim_count_fpv:0.1"
|
||||
description: "prim_count FPV target"
|
||||
filesets:
|
||||
files_formal:
|
||||
depend:
|
||||
- lowrisc:prim:all
|
||||
- lowrisc:prim:count
|
||||
files:
|
||||
- tb/prim_count_tb.sv
|
||||
file_type: systemVerilogSource
|
||||
|
||||
|
||||
targets:
|
||||
default: &default_target
|
||||
# Note this setting is just used to generate a file list for jg.
|
||||
default_tool: icarus
|
||||
filesets:
|
||||
- files_formal
|
||||
toplevel: prim_count_tb
|
||||
|
||||
formal:
|
||||
<<: *default_target
|
||||
|
||||
lint:
|
||||
<<: *default_target
|
|
@ -12,7 +12,7 @@ filesets:
|
|||
files:
|
||||
- vip/prim_esc_rxtx_assert_fpv.sv
|
||||
- tb/prim_esc_rxtx_bind_fpv.sv
|
||||
- tb/prim_esc_rxtx_fpv.sv
|
||||
- tb/prim_esc_rxtx_tb.sv
|
||||
file_type: systemVerilogSource
|
||||
|
||||
targets:
|
||||
|
@ -23,7 +23,7 @@ targets:
|
|||
filesets:
|
||||
- files_formal
|
||||
toplevel:
|
||||
- prim_esc_rxtx_fpv
|
||||
- prim_esc_rxtx_tb
|
||||
|
||||
formal:
|
||||
<<: *default_target
|
||||
|
|
|
@ -10,7 +10,7 @@ filesets:
|
|||
- lowrisc:prim:all
|
||||
- lowrisc:prim:ram_2p_async_adv
|
||||
files:
|
||||
- tb/prim_fifo_async_sram_adapter_fpv.sv
|
||||
- tb/prim_fifo_async_sram_adapter_tb.sv
|
||||
file_type: systemVerilogSource
|
||||
|
||||
targets:
|
||||
|
@ -18,7 +18,7 @@ targets:
|
|||
default_tool: icarus
|
||||
filesets:
|
||||
- files_formal
|
||||
toplevel: prim_fifo_async_sram_adapter_fpv
|
||||
toplevel: prim_fifo_async_sram_adapter_tb
|
||||
|
||||
formal:
|
||||
<<: *default_target
|
||||
|
|
|
@ -11,7 +11,7 @@ filesets:
|
|||
files:
|
||||
- vip/prim_fifo_sync_assert_fpv.sv
|
||||
- tb/prim_fifo_sync_bind_fpv.sv
|
||||
- tb/prim_fifo_sync_fpv.sv
|
||||
- tb/prim_fifo_sync_tb.sv
|
||||
file_type: systemVerilogSource
|
||||
|
||||
targets:
|
||||
|
@ -21,7 +21,7 @@ targets:
|
|||
default_tool: icarus
|
||||
filesets:
|
||||
- files_formal
|
||||
toplevel: prim_fifo_sync_fpv
|
||||
toplevel: prim_fifo_sync_tb
|
||||
|
||||
formal:
|
||||
<<: *default_target
|
||||
|
|
|
@ -9,7 +9,7 @@ filesets:
|
|||
depend:
|
||||
- lowrisc:prim:all
|
||||
files:
|
||||
- tb/prim_keccak_fpv.sv
|
||||
- tb/prim_keccak_tb.sv
|
||||
file_type: systemVerilogSource
|
||||
|
||||
targets:
|
||||
|
@ -20,7 +20,7 @@ targets:
|
|||
filesets:
|
||||
- files_fpv
|
||||
toplevel:
|
||||
- prim_keccak_fpv
|
||||
- prim_keccak_tb
|
||||
|
||||
lint:
|
||||
<<: *default_target
|
||||
|
|
|
@ -9,7 +9,7 @@ filesets:
|
|||
depend:
|
||||
- lowrisc:prim:lfsr
|
||||
files:
|
||||
- tb/prim_lfsr_fpv.sv
|
||||
- tb/prim_lfsr_tb.sv
|
||||
file_type: systemVerilogSource
|
||||
|
||||
targets:
|
||||
|
@ -20,7 +20,7 @@ targets:
|
|||
filesets:
|
||||
- files_formal
|
||||
toplevel:
|
||||
- prim_lfsr_fpv
|
||||
- prim_lfsr_tb
|
||||
|
||||
formal:
|
||||
<<: *default_target
|
||||
|
|
|
@ -10,7 +10,7 @@ filesets:
|
|||
depend:
|
||||
- lowrisc:prim:all
|
||||
files:
|
||||
- tb/prim_packer_fpv.sv
|
||||
- tb/prim_packer_tb.sv
|
||||
file_type: systemVerilogSource
|
||||
|
||||
targets:
|
||||
|
@ -20,7 +20,7 @@ targets:
|
|||
default_tool: icarus
|
||||
filesets:
|
||||
- files_formal
|
||||
toplevel: prim_packer_fpv
|
||||
toplevel: prim_packer_tb
|
||||
|
||||
formal:
|
||||
<<: *default_target
|
||||
|
|
|
@ -11,7 +11,7 @@ filesets:
|
|||
- lowrisc:prim:secded
|
||||
files:
|
||||
- vip/prim_secded_22_16_assert_fpv.sv
|
||||
- tb/prim_secded_22_16_fpv.sv
|
||||
- tb/prim_secded_22_16_tb.sv
|
||||
- tb/prim_secded_22_16_bind_fpv.sv
|
||||
file_type: systemVerilogSource
|
||||
|
||||
|
@ -23,7 +23,7 @@ targets:
|
|||
filesets:
|
||||
- files_formal
|
||||
toplevel:
|
||||
- prim_secded_22_16_fpv
|
||||
- prim_secded_22_16_tb
|
||||
|
||||
formal:
|
||||
<<: *default_target
|
||||
|
|
|
@ -11,7 +11,7 @@ filesets:
|
|||
- lowrisc:prim:secded
|
||||
files:
|
||||
- vip/prim_secded_28_22_assert_fpv.sv
|
||||
- tb/prim_secded_28_22_fpv.sv
|
||||
- tb/prim_secded_28_22_tb.sv
|
||||
- tb/prim_secded_28_22_bind_fpv.sv
|
||||
file_type: systemVerilogSource
|
||||
|
||||
|
@ -23,7 +23,7 @@ targets:
|
|||
filesets:
|
||||
- files_formal
|
||||
toplevel:
|
||||
- prim_secded_28_22_fpv
|
||||
- prim_secded_28_22_tb
|
||||
|
||||
formal:
|
||||
<<: *default_target
|
||||
|
|
|
@ -11,7 +11,7 @@ filesets:
|
|||
- lowrisc:prim:secded
|
||||
files:
|
||||
- vip/prim_secded_39_32_assert_fpv.sv
|
||||
- tb/prim_secded_39_32_fpv.sv
|
||||
- tb/prim_secded_39_32_tb.sv
|
||||
- tb/prim_secded_39_32_bind_fpv.sv
|
||||
file_type: systemVerilogSource
|
||||
|
||||
|
@ -23,7 +23,7 @@ targets:
|
|||
filesets:
|
||||
- files_formal
|
||||
toplevel:
|
||||
- prim_secded_39_32_fpv
|
||||
- prim_secded_39_32_tb
|
||||
|
||||
formal:
|
||||
<<: *default_target
|
||||
|
|
|
@ -11,7 +11,7 @@ filesets:
|
|||
- lowrisc:prim:secded
|
||||
files:
|
||||
- vip/prim_secded_64_57_assert_fpv.sv
|
||||
- tb/prim_secded_64_57_fpv.sv
|
||||
- tb/prim_secded_64_57_tb.sv
|
||||
- tb/prim_secded_64_57_bind_fpv.sv
|
||||
file_type: systemVerilogSource
|
||||
|
||||
|
@ -23,7 +23,7 @@ targets:
|
|||
filesets:
|
||||
- files_formal
|
||||
toplevel:
|
||||
- prim_secded_64_57_fpv
|
||||
- prim_secded_64_57_tb
|
||||
|
||||
formal:
|
||||
<<: *default_target
|
||||
|
|
|
@ -11,7 +11,7 @@ filesets:
|
|||
- lowrisc:prim:secded
|
||||
files:
|
||||
- vip/prim_secded_72_64_assert_fpv.sv
|
||||
- tb/prim_secded_72_64_fpv.sv
|
||||
- tb/prim_secded_72_64_tb.sv
|
||||
- tb/prim_secded_72_64_bind_fpv.sv
|
||||
file_type: systemVerilogSource
|
||||
|
||||
|
@ -23,7 +23,7 @@ targets:
|
|||
filesets:
|
||||
- files_formal
|
||||
toplevel:
|
||||
- prim_secded_72_64_fpv
|
||||
- prim_secded_72_64_tb
|
||||
|
||||
formal:
|
||||
<<: *default_target
|
||||
|
|
|
@ -11,7 +11,7 @@ filesets:
|
|||
- lowrisc:prim:secded
|
||||
files:
|
||||
- vip/prim_secded_hamming_22_16_assert_fpv.sv
|
||||
- tb/prim_secded_hamming_22_16_fpv.sv
|
||||
- tb/prim_secded_hamming_22_16_tb.sv
|
||||
- tb/prim_secded_hamming_22_16_bind_fpv.sv
|
||||
file_type: systemVerilogSource
|
||||
|
||||
|
@ -23,7 +23,7 @@ targets:
|
|||
filesets:
|
||||
- files_formal
|
||||
toplevel:
|
||||
- prim_secded_hamming_22_16_fpv
|
||||
- prim_secded_hamming_22_16_tb
|
||||
|
||||
formal:
|
||||
<<: *default_target
|
||||
|
|
|
@ -11,7 +11,7 @@ filesets:
|
|||
- lowrisc:prim:secded
|
||||
files:
|
||||
- vip/prim_secded_hamming_39_32_assert_fpv.sv
|
||||
- tb/prim_secded_hamming_39_32_fpv.sv
|
||||
- tb/prim_secded_hamming_39_32_tb.sv
|
||||
- tb/prim_secded_hamming_39_32_bind_fpv.sv
|
||||
file_type: systemVerilogSource
|
||||
|
||||
|
@ -23,7 +23,7 @@ targets:
|
|||
filesets:
|
||||
- files_formal
|
||||
toplevel:
|
||||
- prim_secded_hamming_39_32_fpv
|
||||
- prim_secded_hamming_39_32_tb
|
||||
|
||||
formal:
|
||||
<<: *default_target
|
||||
|
|
|
@ -11,7 +11,7 @@ filesets:
|
|||
- lowrisc:prim:secded
|
||||
files:
|
||||
- vip/prim_secded_hamming_72_64_assert_fpv.sv
|
||||
- tb/prim_secded_hamming_72_64_fpv.sv
|
||||
- tb/prim_secded_hamming_72_64_tb.sv
|
||||
- tb/prim_secded_hamming_72_64_bind_fpv.sv
|
||||
file_type: systemVerilogSource
|
||||
|
||||
|
@ -23,7 +23,7 @@ targets:
|
|||
filesets:
|
||||
- files_formal
|
||||
toplevel:
|
||||
- prim_secded_hamming_72_64_fpv
|
||||
- prim_secded_hamming_72_64_tb
|
||||
|
||||
formal:
|
||||
<<: *default_target
|
||||
|
|
33
vendor/lowrisc_ip/ip/prim/fpv/prim_secded_hamming_76_68_fpv.core
vendored
Normal file
33
vendor/lowrisc_ip/ip/prim/fpv/prim_secded_hamming_76_68_fpv.core
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
CAPI=2:
|
||||
# Copyright lowRISC contributors.
|
||||
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
name: "lowrisc:fpv:prim_secded_hamming_76_68_fpv:0.1"
|
||||
description: "SECDED FPV target"
|
||||
filesets:
|
||||
files_formal:
|
||||
depend:
|
||||
- lowrisc:prim:all
|
||||
- lowrisc:prim:secded
|
||||
files:
|
||||
- vip/prim_secded_hamming_76_68_assert_fpv.sv
|
||||
- tb/prim_secded_hamming_76_68_tb.sv
|
||||
- tb/prim_secded_hamming_76_68_bind_fpv.sv
|
||||
file_type: systemVerilogSource
|
||||
|
||||
targets:
|
||||
default: &default_target
|
||||
# note, this setting is just used
|
||||
# to generate a file list for jg
|
||||
default_tool: icarus
|
||||
filesets:
|
||||
- files_formal
|
||||
toplevel:
|
||||
- prim_secded_hamming_76_68_tb
|
||||
|
||||
formal:
|
||||
<<: *default_target
|
||||
|
||||
lint:
|
||||
<<: *default_target
|
||||
|
|
@ -5,31 +5,32 @@
|
|||
// Testbench module for alert sender/receiver pair. Intended to use with
|
||||
// a formal tool.
|
||||
|
||||
module prim_alert_rxtx_async_fatal_fpv
|
||||
module prim_alert_rxtx_async_fatal_tb
|
||||
import prim_alert_pkg::*;
|
||||
import prim_mubi_pkg::mubi4_t;
|
||||
(
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
// for sigint error and skew injection only
|
||||
input ping_err_pi,
|
||||
input ping_err_ni,
|
||||
input [1:0] ping_skew_i,
|
||||
input ack_err_pi,
|
||||
input ack_err_ni,
|
||||
input [1:0] ack_skew_i,
|
||||
input alert_err_pi,
|
||||
input alert_err_ni,
|
||||
input [1:0] alert_skew_i,
|
||||
input ping_err_pi,
|
||||
input ping_err_ni,
|
||||
input [1:0] ping_skew_i,
|
||||
input ack_err_pi,
|
||||
input ack_err_ni,
|
||||
input [1:0] ack_skew_i,
|
||||
input alert_err_pi,
|
||||
input alert_err_ni,
|
||||
input [1:0] alert_skew_i,
|
||||
// normal I/Os
|
||||
input alert_test_i,
|
||||
input alert_req_i,
|
||||
input lc_ctrl_pkg::lc_tx_t init_trig_i,
|
||||
input ping_req_i,
|
||||
output logic alert_ack_o,
|
||||
output logic alert_state_o,
|
||||
output logic ping_ok_o,
|
||||
output logic integ_fail_o,
|
||||
output logic alert_o
|
||||
input alert_test_i,
|
||||
input alert_req_i,
|
||||
input mubi4_t init_trig_i,
|
||||
input ping_req_i,
|
||||
output logic alert_ack_o,
|
||||
output logic alert_state_o,
|
||||
output logic ping_ok_o,
|
||||
output logic integ_fail_o,
|
||||
output logic alert_o
|
||||
);
|
||||
|
||||
// asynchronous case
|
||||
|
@ -115,4 +116,4 @@ module prim_alert_rxtx_async_fatal_fpv
|
|||
end
|
||||
end
|
||||
|
||||
endmodule : prim_alert_rxtx_async_fatal_fpv
|
||||
endmodule : prim_alert_rxtx_async_fatal_tb
|
|
@ -5,8 +5,9 @@
|
|||
// Testbench module for alert sender/receiver pair. Intended to use with
|
||||
// a formal tool.
|
||||
|
||||
module prim_alert_rxtx_async_fpv
|
||||
module prim_alert_rxtx_async_tb
|
||||
import prim_alert_pkg::*;
|
||||
import prim_mubi_pkg::mubi4_t;
|
||||
(
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
|
@ -23,7 +24,7 @@ module prim_alert_rxtx_async_fpv
|
|||
// normal I/Os
|
||||
input alert_test_i,
|
||||
input alert_req_i,
|
||||
input lc_ctrl_pkg::lc_tx_t init_trig_i,
|
||||
input mubi4_t init_trig_i,
|
||||
input ping_req_i,
|
||||
output logic alert_ack_o,
|
||||
output logic alert_state_o,
|
||||
|
@ -116,4 +117,4 @@ module prim_alert_rxtx_async_fpv
|
|||
end
|
||||
end
|
||||
|
||||
endmodule : prim_alert_rxtx_async_fpv
|
||||
endmodule : prim_alert_rxtx_async_tb
|
|
@ -5,8 +5,9 @@
|
|||
// Testbench module for alert sender/receiver pair. Intended to use with
|
||||
// a formal tool.
|
||||
|
||||
module prim_alert_rxtx_fatal_fpv
|
||||
module prim_alert_rxtx_fatal_tb
|
||||
import prim_alert_pkg::*;
|
||||
import prim_mubi_pkg::mubi4_t;
|
||||
(
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
|
@ -20,7 +21,7 @@ module prim_alert_rxtx_fatal_fpv
|
|||
// normal I/Os
|
||||
input alert_test_i,
|
||||
input alert_req_i,
|
||||
input lc_ctrl_pkg::lc_tx_t init_trig_i,
|
||||
input mubi4_t init_trig_i,
|
||||
input ping_req_i,
|
||||
output logic alert_ack_o,
|
||||
output logic alert_state_o,
|
||||
|
@ -72,4 +73,4 @@ module prim_alert_rxtx_fatal_fpv
|
|||
.alert_tx_i ( alert_tx_in )
|
||||
);
|
||||
|
||||
endmodule : prim_alert_rxtx_fatal_fpv
|
||||
endmodule : prim_alert_rxtx_fatal_tb
|
|
@ -5,8 +5,9 @@
|
|||
// Testbench module for alert sender/receiver pair. Intended to use with
|
||||
// a formal tool.
|
||||
|
||||
module prim_alert_rxtx_fpv
|
||||
module prim_alert_rxtx_tb
|
||||
import prim_alert_pkg::*;
|
||||
import prim_mubi_pkg::mubi4_t;
|
||||
(
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
|
@ -20,7 +21,7 @@ module prim_alert_rxtx_fpv
|
|||
// normal I/Os
|
||||
input alert_test_i,
|
||||
input alert_req_i,
|
||||
input lc_ctrl_pkg::lc_tx_t init_trig_i,
|
||||
input mubi4_t init_trig_i,
|
||||
input ping_req_i,
|
||||
output logic alert_ack_o,
|
||||
output logic alert_state_o,
|
||||
|
@ -72,4 +73,4 @@ module prim_alert_rxtx_fpv
|
|||
.alert_tx_i ( alert_tx_in )
|
||||
);
|
||||
|
||||
endmodule : prim_alert_rxtx_fpv
|
||||
endmodule : prim_alert_rxtx_tb
|
|
@ -5,7 +5,7 @@
|
|||
// Testbench module for prim_arbiter_fixed.
|
||||
// Intended to be used with a formal tool.
|
||||
|
||||
module prim_arbiter_fixed_fpv #(
|
||||
module prim_arbiter_fixed_tb #(
|
||||
parameter int N = 8,
|
||||
parameter int DW = 32,
|
||||
parameter bit EnDataPort = 1,
|
||||
|
@ -40,4 +40,4 @@ module prim_arbiter_fixed_fpv #(
|
|||
);
|
||||
|
||||
|
||||
endmodule : prim_arbiter_fixed_fpv
|
||||
endmodule : prim_arbiter_fixed_tb
|
|
@ -5,7 +5,7 @@
|
|||
// Testbench module for prim_arbiter_ppc.
|
||||
// Intended to be used with a formal tool.
|
||||
|
||||
module prim_arbiter_ppc_fpv #(
|
||||
module prim_arbiter_ppc_tb #(
|
||||
parameter int unsigned N = 8,
|
||||
parameter int unsigned DW = 32,
|
||||
parameter bit EnDataPort = 1,
|
||||
|
@ -15,12 +15,10 @@ module prim_arbiter_ppc_fpv #(
|
|||
input rst_ni,
|
||||
|
||||
input req_chk_i,
|
||||
|
||||
input [ N-1:0] req_i,
|
||||
input [DW-1:0] data_i [N],
|
||||
output logic [ N-1:0] gnt_o,
|
||||
output logic [IdxW-1:0] idx_o,
|
||||
|
||||
output logic valid_o,
|
||||
output logic [DW-1:0] data_o,
|
||||
input ready_i
|
||||
|
@ -45,4 +43,4 @@ module prim_arbiter_ppc_fpv #(
|
|||
);
|
||||
|
||||
|
||||
endmodule : prim_arbiter_ppc_fpv
|
||||
endmodule : prim_arbiter_ppc_tb
|
|
@ -5,7 +5,7 @@
|
|||
// Testbench module for prim_arbiter_tree.
|
||||
// Intended to be used with a formal tool.
|
||||
|
||||
module prim_arbiter_tree_fpv #(
|
||||
module prim_arbiter_tree_tb #(
|
||||
parameter int N = 8,
|
||||
parameter int DW = 32,
|
||||
parameter bit EnDataPort = 1,
|
||||
|
@ -15,12 +15,10 @@ module prim_arbiter_tree_fpv #(
|
|||
input rst_ni,
|
||||
|
||||
input req_chk_i,
|
||||
|
||||
input [ N-1:0] req_i,
|
||||
input [DW-1:0] data_i [N],
|
||||
output logic [ N-1:0] gnt_o,
|
||||
output logic [IdxW-1:0] idx_o,
|
||||
|
||||
output logic valid_o,
|
||||
output logic [DW-1:0] data_o,
|
||||
input ready_i
|
||||
|
@ -45,4 +43,4 @@ module prim_arbiter_tree_fpv #(
|
|||
);
|
||||
|
||||
|
||||
endmodule : prim_arbiter_tree_fpv
|
||||
endmodule : prim_arbiter_tree_tb
|
41
vendor/lowrisc_ip/ip/prim/fpv/tb/prim_count_tb.sv
vendored
Normal file
41
vendor/lowrisc_ip/ip/prim/fpv/tb/prim_count_tb.sv
vendored
Normal file
|
@ -0,0 +1,41 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
// Testbench module for prim_count.
|
||||
// Intended to be used with a formal tool.
|
||||
|
||||
module prim_count_tb
|
||||
import prim_count_pkg::*; #(
|
||||
parameter int Width = 2,
|
||||
parameter bit OutSelDnCnt = 1, // 0 selects up count
|
||||
parameter prim_count_style_e CntStyle = CrossCnt
|
||||
) (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
input clr_i,
|
||||
input set_i,
|
||||
input [Width-1:0] set_cnt_i,
|
||||
input en_i,
|
||||
input [Width-1:0] step_i,
|
||||
output logic[Width-1:0] cnt_o,
|
||||
output logic err_o
|
||||
);
|
||||
|
||||
prim_count #(
|
||||
.Width(Width),
|
||||
.OutSelDnCnt(OutSelDnCnt),
|
||||
.CntStyle(CntStyle)
|
||||
) u_counter (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.clr_i,
|
||||
.set_i,
|
||||
.set_cnt_i,
|
||||
.en_i,
|
||||
.step_i,
|
||||
.cnt_o,
|
||||
.err_o
|
||||
);
|
||||
|
||||
endmodule : prim_count_tb
|
|
@ -5,7 +5,7 @@
|
|||
// Testbench module for escalation sender/receiver pair. Intended to use with
|
||||
// a formal tool.
|
||||
|
||||
module prim_esc_rxtx_fpv
|
||||
module prim_esc_rxtx_tb
|
||||
import prim_esc_pkg::*;
|
||||
(
|
||||
input clk_i,
|
||||
|
@ -54,4 +54,4 @@ module prim_esc_rxtx_fpv
|
|||
.esc_tx_i ( esc_tx_in )
|
||||
);
|
||||
|
||||
endmodule : prim_esc_rxtx_fpv
|
||||
endmodule : prim_esc_rxtx_tb
|
|
@ -4,7 +4,7 @@
|
|||
//
|
||||
// Testbench module for prim_fifo_sram_async
|
||||
|
||||
module prim_fifo_async_sram_adapter_fpv #(
|
||||
module prim_fifo_async_sram_adapter_tb #(
|
||||
parameter int unsigned Width = 32,
|
||||
parameter int unsigned Depth = 16,
|
||||
|
||||
|
@ -201,4 +201,4 @@ end // !FpgaSram
|
|||
clk_rd_i, !rst_ni)
|
||||
`endif // FPV_ON
|
||||
|
||||
endmodule : prim_fifo_async_sram_adapter_fpv
|
||||
endmodule : prim_fifo_async_sram_adapter_tb
|
|
@ -14,7 +14,7 @@
|
|||
// Data/depth value checks are enabled up to depth 8 in order to constrain the
|
||||
// runtime.
|
||||
|
||||
module prim_fifo_sync_fpv #(
|
||||
module prim_fifo_sync_tb #(
|
||||
// number of DUTs instantiated in this FPV testbench
|
||||
parameter int unsigned NumDuts = 11,
|
||||
// fifo params
|
||||
|
@ -233,4 +233,4 @@ module prim_fifo_sync_fpv #(
|
|||
.depth_o(depth_o[10][4:0])
|
||||
);
|
||||
|
||||
endmodule : prim_fifo_sync_fpv
|
||||
endmodule : prim_fifo_sync_tb
|
|
@ -4,7 +4,7 @@
|
|||
//
|
||||
// Testbench module for prim_keccak. Intended to be used with a formal tool.
|
||||
|
||||
module prim_keccak_fpv #(
|
||||
module prim_keccak_tb #(
|
||||
parameter int Width = 1600
|
||||
) (
|
||||
input clk_i,
|
|
@ -4,7 +4,7 @@
|
|||
//
|
||||
// Testbench module for prim_lfsr. Intended to be used with a formal tool.
|
||||
|
||||
module prim_lfsr_fpv #(
|
||||
module prim_lfsr_tb #(
|
||||
// LFSR entropy and output bitwidths (set to 1 here as they are unused)
|
||||
parameter int unsigned EntropyDw = 1,
|
||||
parameter int unsigned StateOutDw = 1,
|
||||
|
@ -120,4 +120,4 @@ module prim_lfsr_fpv #(
|
|||
);
|
||||
end
|
||||
|
||||
endmodule : prim_lfsr_fpv
|
||||
endmodule : prim_lfsr_tb
|
|
@ -5,7 +5,7 @@
|
|||
// Testbench module for prim_packer. Intended to be used with a formal tool.
|
||||
// To reduce the runtime for prim_packer, we limited the width parameter.
|
||||
|
||||
module prim_packer_fpv #(
|
||||
module prim_packer_tb #(
|
||||
parameter int unsigned MaxInW = 64,
|
||||
parameter int unsigned MaxOutW = 64
|
||||
) (
|
||||
|
@ -60,4 +60,4 @@ module prim_packer_fpv #(
|
|||
.flush_done_o
|
||||
);
|
||||
|
||||
endmodule : prim_packer_fpv
|
||||
endmodule : prim_packer_tb
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
module prim_secded_22_16_bind_fpv;
|
||||
|
||||
bind prim_secded_22_16_fpv
|
||||
bind prim_secded_22_16_tb
|
||||
prim_secded_22_16_assert_fpv prim_secded_22_16_assert_fpv (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
//
|
||||
// SECDED FPV testbench generated by util/design/secded_gen.py
|
||||
|
||||
module prim_secded_22_16_fpv (
|
||||
module prim_secded_22_16_tb (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
input [15:0] data_i,
|
||||
|
@ -28,4 +28,4 @@ module prim_secded_22_16_fpv (
|
|||
.err_o
|
||||
);
|
||||
|
||||
endmodule : prim_secded_22_16_fpv
|
||||
endmodule : prim_secded_22_16_tb
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
module prim_secded_28_22_bind_fpv;
|
||||
|
||||
bind prim_secded_28_22_fpv
|
||||
bind prim_secded_28_22_tb
|
||||
prim_secded_28_22_assert_fpv prim_secded_28_22_assert_fpv (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
//
|
||||
// SECDED FPV testbench generated by util/design/secded_gen.py
|
||||
|
||||
module prim_secded_28_22_fpv (
|
||||
module prim_secded_28_22_tb (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
input [21:0] data_i,
|
||||
|
@ -28,4 +28,4 @@ module prim_secded_28_22_fpv (
|
|||
.err_o
|
||||
);
|
||||
|
||||
endmodule : prim_secded_28_22_fpv
|
||||
endmodule : prim_secded_28_22_tb
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
module prim_secded_39_32_bind_fpv;
|
||||
|
||||
bind prim_secded_39_32_fpv
|
||||
bind prim_secded_39_32_tb
|
||||
prim_secded_39_32_assert_fpv prim_secded_39_32_assert_fpv (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
//
|
||||
// SECDED FPV testbench generated by util/design/secded_gen.py
|
||||
|
||||
module prim_secded_39_32_fpv (
|
||||
module prim_secded_39_32_tb (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
input [31:0] data_i,
|
||||
|
@ -28,4 +28,4 @@ module prim_secded_39_32_fpv (
|
|||
.err_o
|
||||
);
|
||||
|
||||
endmodule : prim_secded_39_32_fpv
|
||||
endmodule : prim_secded_39_32_tb
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
module prim_secded_64_57_bind_fpv;
|
||||
|
||||
bind prim_secded_64_57_fpv
|
||||
bind prim_secded_64_57_tb
|
||||
prim_secded_64_57_assert_fpv prim_secded_64_57_assert_fpv (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
//
|
||||
// SECDED FPV testbench generated by util/design/secded_gen.py
|
||||
|
||||
module prim_secded_64_57_fpv (
|
||||
module prim_secded_64_57_tb (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
input [56:0] data_i,
|
||||
|
@ -28,4 +28,4 @@ module prim_secded_64_57_fpv (
|
|||
.err_o
|
||||
);
|
||||
|
||||
endmodule : prim_secded_64_57_fpv
|
||||
endmodule : prim_secded_64_57_tb
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
module prim_secded_72_64_bind_fpv;
|
||||
|
||||
bind prim_secded_72_64_fpv
|
||||
bind prim_secded_72_64_tb
|
||||
prim_secded_72_64_assert_fpv prim_secded_72_64_assert_fpv (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
//
|
||||
// SECDED FPV testbench generated by util/design/secded_gen.py
|
||||
|
||||
module prim_secded_72_64_fpv (
|
||||
module prim_secded_72_64_tb (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
input [63:0] data_i,
|
||||
|
@ -28,4 +28,4 @@ module prim_secded_72_64_fpv (
|
|||
.err_o
|
||||
);
|
||||
|
||||
endmodule : prim_secded_72_64_fpv
|
||||
endmodule : prim_secded_72_64_tb
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
module prim_secded_hamming_22_16_bind_fpv;
|
||||
|
||||
bind prim_secded_hamming_22_16_fpv
|
||||
bind prim_secded_hamming_22_16_tb
|
||||
prim_secded_hamming_22_16_assert_fpv prim_secded_hamming_22_16_assert_fpv (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
//
|
||||
// SECDED FPV testbench generated by util/design/secded_gen.py
|
||||
|
||||
module prim_secded_hamming_22_16_fpv (
|
||||
module prim_secded_hamming_22_16_tb (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
input [15:0] data_i,
|
||||
|
@ -28,4 +28,4 @@ module prim_secded_hamming_22_16_fpv (
|
|||
.err_o
|
||||
);
|
||||
|
||||
endmodule : prim_secded_hamming_22_16_fpv
|
||||
endmodule : prim_secded_hamming_22_16_tb
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue