mirror of
https://github.com/openhwgroup/cve2.git
synced 2025-04-22 13:07:46 -04:00
Update lowrisc_ip to lowRISC/opentitan@ad629e3e6
Update code from upstream repository https://github.com/lowRISC/opentitan to revision ad629e3e6e70c5eaa3c2dd68457b0a020448b35f * [dvsim] Introduce {self_dir} as variable (Philipp Wagner) * [dvsim] Small cleanups (Philipp Wagner) * [prim_lfsr] Minor lint fix (Michael Schaffner) * [dv] Update sec_cm testplan (Weicai Yang) * [prim/lint] Move waiver to correct waiver file (Michael Schaffner) * [prim_assert] Relocate waivers to dedicated prim_assert.waiver file (Michael Schaffner) * [alert_handler] Lint fixes and waiver updates (Michael Schaffner) * [prim_lc_receiver] Add parameter to select reset value (Michael Schaffner) * [lint] Add lint waiver for IP regfiles with shadow resets (Michael Schaffner) * [fpv] Fix Verible lint errors (Philipp Wagner) * [prim_lfsr] Minor lint fixes (Timothy Chen) * [clkmgr] Fix measurement control CDC (Timothy Chen) * [fpv/prim_counter] Pad one bit to include overflow case (Cindy Chen) * [fpv] Fix issue lowRISC#8371 (Zeeshan Rafique) * [flash_ctrl] Flash ctrl security hardening (Timothy Chen) * [dv] Fix CI error (Cindy Chen) * [prim_alert_*] Extend SVAs for FPV (Michael Schaffner) * [prim_alert_*] Update DV TB to respect initialization timing (Michael Schaffner) * [prim_alert_rxtx_fpv] Update FPV environment and fix SVAs (Michael Schaffner) * [prim_alert_sender] Update sender to support in-band reset mechanism (Michael Schaffner) * [prim_alert_sender] Simplify sender and clear ping req upon sigint (Michael Schaffner) * [prim_lc_sender] Add option to select reset value (Michael Schaffner) * [prim] Correct assertion valid term (Timothy Chen) * [prim_lc_combine] Align behavior of lc combine with mubi functions (Michael Schaffner) * [fpv/tool] Support GUI mode on dvsim (Cindy Chen) * [prim_lfsr] Further permutation refinements for SBox layer (Michael Schaffner) * [dv/shadow_reg] Shadow register write by field (Cindy Chen) * [prim] Fix the edge type (Eunchan Kim) * [checklist] Updates to checklist for D2 status (Tom Roberts) * [prim_mubi_pkg] Add a generic multibit type and associated functions (Michael Schaffner) * [prim] Minor fix and clarification to prim_count (Timothy Chen) * [keymgr/dv] Update testplan and covergroup plan (Weicai Yang) * [prim_lc_combine] Fix parameterization error (Michael Schaffner) * [fpv/prim_count] Small update on prim_count assertions (Cindy Chen) * [dv] Add ip_name in reg_block (Weicai Yang) * [keymgr] Finalize keymgr hardening (Timothy Chen) * [prim_lc_combine] Add a prim to compute logical AND/OR for LC signals (Michael Schaffner) * [dv] Remove common_cov_excl.el from unr.cfg (Weicai Yang) * [dv/top_level] Loop through the SW test multiple times (Cindy Chen) * [flash_ctrl] Various clean-up and updates (Timothy Chen) * [prim] Change prim_reg_cdc assertions (Timothy Chen) * [prim, keymgr] Migrate keymgr_cnt to prim_count (Timothy Chen) * [sw dv] Multi-site support for Verilator (Martin Lueker-Boden) * [dv/csr] Update write exclusion wdata value (Cindy Chen) * [dv/dv_base_reg] remove debug display (Cindy Chen) * [dv/shadow_reg] Fix alert shadow_reg regression error (Cindy Chen) * [top] Integrate ast into fpga (Timothy Chen) * [prim_lfsr] Improve statistics of non-linear output (Michael Schaffner) * [prim_esc_receiver] Fix response toggling corner case (Michael Schaffner) * option to use partner ast_pkg (Sharon Topaz) * [dv/prim_esc] Double the ping timeout cycles (Cindy Chen) * [dv] Use sed to add -elfile for each excl file (Weicai Yang) * [dv] Fix coverage report error (Weicai Yang) * [dv] Update common exclusion file (Weicai Yang) * [dv/prim_esc] Improve FSM coverage (Cindy Chen) * [reggen] Add a check to limit the swaccess type for shadow regs (Michael Schaffner) * [prim_subreg_shadow] Fix for W1S/W0C corner case (Michael Schaffner) * [prim_subreg_shadow] Disallow phase updates when storage err is present (Michael Schaffner) * [dvsim] Add passing count by milestone in reports (Srikrishna Iyer) * [dv/tool] Include toggle coverage for prim_alert_sender in cover_reg_top (Cindy Chen) * [clkmgr] Harden clock manager through frequency measurements (Timothy Chen) * [dv] Only enable VCS -kdb when dumping waves (Weicai Yang) * [dv] Fix shadow reg (Weicai Yang) * [dvsim] Allow non-integral values of --reseed-multiplier (Rupert Swarbrick) * [ast] Fixes for various ast issues (Timothy Chen) * [prim_esc_receiver] Assert escalation in case of sigint error (Michael Schaffner) * [prim_esc_receiver] Minor signal renaming for consistency (Michael Schaffner) * [dv/alert_handler] Support shadow register sequence (Cindy Chen) * [verilator] Use FileSz rather than MemSz when flattening ELF files (Michael Munday) * [prim_subreg_shadow] Only assert QE when committed_reg is written (Michael Schaffner) * [dv,verilator] Round up SV_MEM_WIDTH_BYTES to a multiple of 4 (Rupert Swarbrick) * [prim] Add missing include (Pirmin Vogel) * [dv/cover_cfg] Exclude prim_alert/esc from xcelium (Cindy Chen) * [dv/cover_cfg] Exclude prim_alert/esc pairs (Cindy Chen) * [clkmgr] Use local BUFHCE clock gates on FPGA (Pirmin Vogel) * [prim_prince] Mark "leaf" functions in prince_ref.h as static inline (Rupert Swarbrick) * [dv/shadow_reg] Check status after shadow_reg write (Cindy Chen) * [dv/shadwo_reg] Shadow reg common sequence update (Cindy Chen) * [otp_ctrl/lc_ctrl] Add 32bit OTP vendor test ctrl/status regs to LC TAP (Michael Schaffner) * [otp_ctrl] Add VENDOR_TEST partition (Michael Schaffner) * [prim] Edge Detector (Eunchan Kim) * [prim_diff_decode] Fix asynchronous assertions (Michael Schaffner) * [spi_device] Instantiate Upload module (Eunchan Kim) * [dv] Add sv_flist_gen_flags HJson var for FuseSoc (Srikrishna Iyer) * [dv, xcelium] Properly pass excl files to IMC (Srikrishna Iyer) * [reg] Fix shadow reg update during storage error (Timothy Chen) * [regfile] Refactor cdc handling to the reg level (Timothy Chen) * [dv/prim_esc] Add a testplan and increase coverage (Cindy Chen) * [dv] Update TLUL and EDN frequency (Weicai Yang) * [rstmgr, top] Add support for shadow resets (Timothy Chen) * [dv] Update Xcelium cover ccf (Srikrishna Iyer) * [dv] reduce seeds for CSR tests (Weicai Yang) * [usb/top] Remove AND gates on non-AON domain and rename 3.3V signal (Michael Schaffner) * [dv/prim_alert] Improvement on prim_alert tb (Cindy Chen) * [prim] FIFO SRAM Adapter fix (Eunchan Kim) * [prim] Add Write Mask port (Eunchan Kim) * [dv] Fix timescale issue with Xcelium (Weicai Yang) * [dv/prim_esc] Fix prim_esc regression error (Cindy Chen) * [dv/dv_base_reg] change from uvm_low to uvm_high (Cindy Chen) * [sram_ctrl] Harden initialization counter (Michael Schaffner) * [tools/uvmdvgen] Fix path in testplan inclusion (Guillermo Maturana) * [dv] Change stress_all_with_rand_reset to V3 (Weicai Yang) * [dv] fix tl error coverage (Weicai Yang) * [dv] Add macro DV_GET_ENUM_PLUSARG (Weicai Yang) * [prim] SRAM Async FIFO (Eunchan Kim) * [dv, xcelium] Fix statement coverage extraction (Srikrishna Iyer) * [dvsim] Minor fixes to coverage extraction (Srikrishna Iyer) * [prim_lfsr] Do not shadow |state| variable (Philipp Wagner) * [prim] Add non-linear out option to prim_lfsr (Timothy Chen) * [dv] Constrain TLUL to 24Mhz or higher (Weicai Yang) * [primgen] Instantiate tech libs in stable order (Philipp Wagner) * [primgen] Actually find the Verible Python wrapper (Philipp Wagner) * [dv/prim_esc] fix regression error (Cindy Chen) * [dv] Fix shadow reg predict (Weicai Yang) * [dv/common] Exclude assertion coverage from IP level testbench (Cindy Chen) * [dv/prince] hit additional toggle coverpoints (Udi Jonnalagadda) * [sram_ctrl] Update docs (Michael Schaffner) * [sram_ctrl] Absorb prim_ram_1p_scr (Michael Schaffner) * [dv/prim_alert/esc] Improvements for prim_alert/esc_tb (Cindy Chen) * [dv/dvsim] Add "testfile" grading option (Guillermo Maturana) * [dv/prim_esc] Direct test for prim_rx/tx (Cindy Chen) * [dv/utils] added 6MHz to clk_freq_mhz_e (Dror Kabely) * [prim_xor2/lint] Add waiver for .* use in generated prim (Michael Schaffner) * [dv, doc] Replace all 'dv.plan' with testplan (Srikrishna Iyer) * Fix the testplan link in dvsim code (Srikrishna Iyer) * [dv/dsim] Add dsim workaround for issue 242 (Guillermo Maturana) * [util, reggen] Support standardized cdc handling for regfile (Timothy Chen) * [dv/shadow_reg] Align shadow_reg field update behavior (Cindy Chen) * [dvsim] Fix publish report summary typo (Cindy Chen) * [rtl/prim_alert_sender] Allow ping_req to stay high without error (Cindy Chen) * [dvsim] Separate publish report from dvsim flow [PART3] (Cindy Chen) * [dv/prim_alert] Add a testbench for prim_alert (Cindy Chen) * [otp_ctrl] Connect test-related GPIO signal (Michael Schaffner) * [prim_subreg_shadow] Make local parameter a localparam (Philipp Wagner) * [prim_subreg] Make software access type an enum (Philipp Wagner) * [rtl/prim_diff_decode] Add prim_flop_2sync dependency (Cindy Chen) * [otp_ctrl] Update AscentLint waiver file (Michael Schaffner) * [edn] Add MaxLatency assertion (Eunchan Kim) * [prim_subreg_shadow] Correct write data signal usage (Michael Schaffner) * [script/dvsim] Separate publish report from dvsim flow [PART2] (Cindy Chen) * [prim_lfsr] Fix assertion issue occuring right after reset (Michael Schaffner) * [dv/shadow_reg] Handle CSR automated sequence write abort (Cindy Chen) * [dv/dv_lib] Add post_apply_reset for extra delay (Guillermo Maturana) * [dv] Add function coverage plan for tl_errors, tl_intg_err (Weicai Yang) * [dv] Remove tl_intg_err in top-level and increase seeds for tl_intg_err (Weicai Yang) * [dv/shadow_reg] Fix alert shadow reg regression error (Cindy Chen) Signed-off-by: Rupert Swarbrick <rswarbrick@lowrisc.org>
This commit is contained in:
parent
e70add7228
commit
b66f199151
151 changed files with 5374 additions and 883 deletions
|
@ -16,6 +16,7 @@
|
|||
// Shared lowRISC code
|
||||
+incdir+${PRJ_DIR}/vendor/lowrisc_ip/ip/prim/rtl
|
||||
${PRJ_DIR}/vendor/lowrisc_ip/ip/prim/rtl/prim_assert.sv
|
||||
${PRJ_DIR}/vendor/lowrisc_ip/ip/prim/rtl/prim_cipher_pkg.sv
|
||||
${PRJ_DIR}/vendor/lowrisc_ip/ip/prim/rtl/prim_lfsr.sv
|
||||
${PRJ_DIR}/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_28_22_enc.sv
|
||||
${PRJ_DIR}/vendor/lowrisc_ip/ip/prim/rtl/prim_secded_28_22_dec.sv
|
||||
|
|
2
dv/uvm/icache/dv/env/ibex_icache_env_cfg.sv
vendored
2
dv/uvm/icache/dv/env/ibex_icache_env_cfg.sv
vendored
|
@ -14,7 +14,7 @@ class ibex_icache_env_cfg extends dv_base_env_cfg;
|
|||
// Force the clock frequency to 50MHz. The clock frequency doesn't really matter for ICache
|
||||
// testing and 50MHz dumped waves are nice to read because clock edges are multiples of 10ns.
|
||||
constraint clk_freq_50_c {
|
||||
clk_freq_mhz == ClkFreq50Mhz;
|
||||
clk_freq_mhz == 50;
|
||||
}
|
||||
|
||||
// Config objects for ECC components (see create_ecc_agent_cfgs). Since these are created after
|
||||
|
|
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: da3ac7c4eb23a92194874ad2daf2e5f9e3330572
|
||||
rev: ad629e3e6e70c5eaa3c2dd68457b0a020448b35f
|
||||
}
|
||||
}
|
||||
|
|
15
vendor/lowrisc_ip/dv/sv/csr_utils/csr_seq_lib.sv
vendored
15
vendor/lowrisc_ip/dv/sv/csr_utils/csr_seq_lib.sv
vendored
|
@ -200,7 +200,7 @@ class csr_write_seq extends csr_base_seq;
|
|||
test_csrs[i].get_full_name()), UVM_MEDIUM)
|
||||
|
||||
`DV_CHECK_STD_RANDOMIZE_FATAL(wdata)
|
||||
wdata &= get_mask_excl_fields(test_csrs[i], CsrExclWrite, CsrHwResetTest);
|
||||
wdata = get_csr_wdata_with_write_excl(test_csrs[i], wdata, CsrHwResetTest);
|
||||
|
||||
`downcast(dv_csr, test_csrs[i])
|
||||
if (en_rand_backdoor_write && !dv_csr.get_is_ext_reg()) begin
|
||||
|
@ -232,6 +232,7 @@ class csr_rw_seq extends csr_base_seq;
|
|||
uvm_reg_data_t wdata;
|
||||
uvm_reg_data_t compare_mask;
|
||||
uvm_reg_field test_fields[$];
|
||||
dv_base_reg test_dv_csr;
|
||||
|
||||
// check if parent block or register is excluded from write
|
||||
if (is_excl(test_csrs[i], CsrExclWrite, CsrRwTest)) begin
|
||||
|
@ -244,7 +245,7 @@ class csr_rw_seq extends csr_base_seq;
|
|||
test_csrs[i].get_full_name()), UVM_MEDIUM)
|
||||
|
||||
`DV_CHECK_STD_RANDOMIZE_FATAL(wdata)
|
||||
wdata &= get_mask_excl_fields(test_csrs[i], CsrExclWrite, CsrRwTest);
|
||||
wdata = get_csr_wdata_with_write_excl(test_csrs[i], wdata, CsrRwTest);
|
||||
|
||||
// if external checker is not enabled and writes are made non-blocking, then we need to
|
||||
// pre-predict so that the mirrored value will be updated. if we dont, then csr_rd_check task
|
||||
|
@ -253,6 +254,14 @@ class csr_rw_seq extends csr_base_seq;
|
|||
// register is getting the updated access information.
|
||||
csr_wr(.ptr(test_csrs[i]), .value(wdata), .blocking(0), .predict(!external_checker));
|
||||
|
||||
// Shadow register requires two writes with the same value to write registers into DUT.
|
||||
// In `csr_wr` task, the `predict` task is triggered after two shadow writes are done.
|
||||
// To avoid non-blocking access where shadow register read might be triggered between two
|
||||
// consecutive shadow register write, we will wait until all outstanding accesses finish,
|
||||
// then issue a shadow register read.
|
||||
`downcast(test_dv_csr, test_csrs[i])
|
||||
if (test_dv_csr.get_is_shadowed) wait_no_outstanding_access();
|
||||
|
||||
do_check_csr_or_field_rd(.csr(test_csrs[i]),
|
||||
.blocking(0),
|
||||
.compare(!external_checker),
|
||||
|
@ -413,7 +422,7 @@ class csr_aliasing_seq extends csr_base_seq;
|
|||
test_csrs[i].get_full_name()), UVM_MEDIUM)
|
||||
|
||||
`DV_CHECK_STD_RANDOMIZE_FATAL(wdata)
|
||||
wdata &= get_mask_excl_fields(test_csrs[i], CsrExclWrite, CsrAliasingTest);
|
||||
wdata = get_csr_wdata_with_write_excl(test_csrs[i], wdata, CsrAliasingTest);
|
||||
csr_wr(.ptr(test_csrs[i]), .value(wdata), .blocking(0), .predict(!external_checker));
|
||||
|
||||
all_csrs.shuffle();
|
||||
|
|
160
vendor/lowrisc_ip/dv/sv/csr_utils/csr_utils_pkg.sv
vendored
160
vendor/lowrisc_ip/dv/sv/csr_utils/csr_utils_pkg.sv
vendored
|
@ -125,14 +125,6 @@ package csr_utils_pkg;
|
|||
return result;
|
||||
endfunction : decode_csr_or_field
|
||||
|
||||
// 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,
|
||||
uvm_reg_data_t value);
|
||||
uvm_reg_data_t mask = (1 << field.get_n_bits()) - 1;
|
||||
uint shift = field.get_lsb_pos();
|
||||
get_field_val = (value >> shift) & mask;
|
||||
endfunction
|
||||
|
||||
// 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,
|
||||
|
@ -152,6 +144,8 @@ package csr_utils_pkg;
|
|||
csr.get_full_name(), csr.m_is_busy), UVM_HIGH)
|
||||
endtask
|
||||
|
||||
// Use `csr_wr` to construct `csr_update` to avoid replicated codes to handle nonblocking,
|
||||
// shadow writes etc
|
||||
task automatic csr_update(input uvm_reg csr,
|
||||
input uvm_check_e check = default_csr_check,
|
||||
input uvm_path_e path = UVM_DEFAULT_PATH,
|
||||
|
@ -159,53 +153,21 @@ package csr_utils_pkg;
|
|||
input uint timeout_ns = default_timeout_ns,
|
||||
input uvm_reg_map map = null,
|
||||
input bit en_shadow_wr = 1);
|
||||
if (blocking) begin
|
||||
csr_update_sub(csr, check, path, timeout_ns, map, en_shadow_wr);
|
||||
end else begin
|
||||
fork
|
||||
csr_update_sub(csr, check, path, timeout_ns, map, en_shadow_wr);
|
||||
join_none
|
||||
// Add #0 to ensure that this thread starts executing before any subsequent call
|
||||
#0;
|
||||
uvm_reg_field fields[$];
|
||||
uvm_reg_data_t value;
|
||||
|
||||
// below is partial replication of the uvm_reg_field::update() logic in UVM1.2 source code
|
||||
if (!csr.needs_update()) return;
|
||||
csr.get_fields(fields);
|
||||
// Concatenate the write-to-update values from each field
|
||||
// Fields are stored in LSB or MSB order
|
||||
value = 0;
|
||||
foreach (fields[i]) begin
|
||||
value |= fields[i].XupdateX() << fields[i].get_lsb_pos();
|
||||
end
|
||||
endtask
|
||||
|
||||
// subroutine of csr_update, don't use it directly
|
||||
task automatic csr_update_sub(input uvm_reg csr,
|
||||
input uvm_check_e check = default_csr_check,
|
||||
input uvm_path_e path = UVM_DEFAULT_PATH,
|
||||
input uint timeout_ns = default_timeout_ns,
|
||||
input uvm_reg_map map = null,
|
||||
input bit en_shadow_wr = 1);
|
||||
fork
|
||||
begin : isolation_fork
|
||||
uvm_status_e status;
|
||||
string msg_id = {csr_utils_pkg::msg_id, "::csr_update"};
|
||||
|
||||
fork
|
||||
begin
|
||||
increment_outstanding_access();
|
||||
csr_pre_write_sub(csr, en_shadow_wr);
|
||||
csr.update(.status(status), .path(path), .map(map), .prior(100));
|
||||
csr_post_write_sub(csr, en_shadow_wr);
|
||||
// when reset occurs, all items will be dropped immediately. This may end up getting
|
||||
// d_error = 1 from previous item on the bus. Skip checking it during reset
|
||||
if (check == UVM_CHECK && !under_reset) begin
|
||||
`DV_CHECK_EQ(status, UVM_IS_OK,
|
||||
$sformatf("trying to update csr %0s", csr.get_full_name()),
|
||||
error, msg_id)
|
||||
end
|
||||
decrement_outstanding_access();
|
||||
end
|
||||
begin
|
||||
wait_timeout(timeout_ns, msg_id,
|
||||
$sformatf("Timeout waiting to csr_update %0s (addr=0x%0h)",
|
||||
csr.get_full_name(), csr.get_address()));
|
||||
end
|
||||
join_any
|
||||
disable fork;
|
||||
end : isolation_fork
|
||||
join
|
||||
csr_wr(.ptr(csr), .value(value), .check(check), .path(path), .blocking(blocking), .backdoor(0),
|
||||
.timeout_ns(timeout_ns), .predict(0), .map(map), .en_shadow_wr(en_shadow_wr));
|
||||
endtask
|
||||
|
||||
task automatic csr_wr(input uvm_object ptr,
|
||||
|
@ -254,25 +216,24 @@ package csr_utils_pkg;
|
|||
input bit en_shadow_wr = 1);
|
||||
fork
|
||||
begin : isolation_fork
|
||||
uvm_status_e status;
|
||||
string msg_id = {csr_utils_pkg::msg_id, "::csr_wr"};
|
||||
|
||||
fork
|
||||
begin
|
||||
dv_base_reg dv_reg;
|
||||
`downcast(dv_reg, csr, "", fatal, msg_id)
|
||||
|
||||
increment_outstanding_access();
|
||||
csr_pre_write_sub(csr, en_shadow_wr);
|
||||
csr.write(.status(status), .value(value), .path(path), .map(map), .prior(100));
|
||||
|
||||
csr_wr_and_predict_sub(.csr(csr), .value(value), .check(check), .path(path),
|
||||
.predict(predict), .map(map));
|
||||
if (en_shadow_wr && dv_reg.get_is_shadowed()) begin
|
||||
csr_wr_and_predict_sub(.csr(csr), .value(value), .check(check), .path(path),
|
||||
.predict(predict), .map(map));
|
||||
end
|
||||
|
||||
csr_post_write_sub(csr, en_shadow_wr);
|
||||
if (check == UVM_CHECK && !under_reset) begin
|
||||
`DV_CHECK_EQ(status, UVM_IS_OK,
|
||||
$sformatf("trying to write csr %0s", csr.get_full_name()),
|
||||
error, msg_id)
|
||||
end
|
||||
// Only update the predicted value if status is ok (otherwise the write isn't completed
|
||||
// successfully and the design shouldn't have accepted the written value)
|
||||
if (status == UVM_IS_OK && predict) begin
|
||||
void'(csr.predict(.value(value), .kind(UVM_PREDICT_WRITE)));
|
||||
end
|
||||
decrement_outstanding_access();
|
||||
end
|
||||
begin
|
||||
|
@ -286,27 +247,42 @@ package csr_utils_pkg;
|
|||
join
|
||||
endtask
|
||||
|
||||
task automatic csr_pre_write_sub(ref uvm_reg csr, bit en_shadow_wr);
|
||||
dv_base_reg dv_reg;
|
||||
`downcast(dv_reg, csr, "", fatal, msg_id)
|
||||
if (dv_reg.get_is_shadowed()) begin
|
||||
if (en_shadow_wr) increment_outstanding_access();
|
||||
dv_reg.atomic_en_shadow_wr.get(1);
|
||||
dv_reg.set_en_shadow_wr(en_shadow_wr);
|
||||
// internal task, don't use it directly
|
||||
task automatic csr_wr_and_predict_sub(uvm_reg csr,
|
||||
uvm_reg_data_t value,
|
||||
uvm_check_e check,
|
||||
uvm_path_e path,
|
||||
bit predict,
|
||||
uvm_reg_map map);
|
||||
uvm_status_e status;
|
||||
csr.write(.status(status), .value(value), .path(path), .map(map), .prior(100));
|
||||
|
||||
if (under_reset) return;
|
||||
if (check == UVM_CHECK) begin
|
||||
`DV_CHECK_EQ(status, UVM_IS_OK,
|
||||
$sformatf("trying to write csr %0s", csr.get_full_name()),
|
||||
error, msg_id)
|
||||
end
|
||||
// Only update the predicted value if status is ok (otherwise the write isn't completed
|
||||
// successfully and the design shouldn't have accepted the written value)
|
||||
if (status == UVM_IS_OK && predict) begin
|
||||
void'(csr.predict(.value(value), .kind(UVM_PREDICT_WRITE)));
|
||||
end
|
||||
endtask
|
||||
|
||||
task automatic csr_post_write_sub(ref uvm_reg csr, bit en_shadow_wr);
|
||||
task automatic csr_pre_write_sub(uvm_reg csr, bit en_shadow_wr);
|
||||
dv_base_reg dv_reg;
|
||||
`downcast(dv_reg, csr, "", fatal, msg_id)
|
||||
if (dv_reg.get_is_shadowed()) begin
|
||||
// try setting en_shadow_wr back to default value 1, this function will only work if the
|
||||
// shadow reg finished both writes
|
||||
dv_reg.set_en_shadow_wr(1);
|
||||
if (dv_reg.get_is_shadowed() && en_shadow_wr) begin
|
||||
dv_reg.atomic_en_shadow_wr.get(1);
|
||||
end
|
||||
endtask
|
||||
|
||||
task automatic csr_post_write_sub(uvm_reg csr, bit en_shadow_wr);
|
||||
dv_base_reg dv_reg;
|
||||
`downcast(dv_reg, csr, "", fatal, msg_id)
|
||||
if (dv_reg.get_is_shadowed() && en_shadow_wr) begin
|
||||
dv_reg.atomic_en_shadow_wr.put(1);
|
||||
if (en_shadow_wr) begin
|
||||
decrement_outstanding_access();
|
||||
end
|
||||
end
|
||||
endtask
|
||||
|
||||
|
@ -726,6 +702,30 @@ package csr_utils_pkg;
|
|||
end
|
||||
endfunction
|
||||
|
||||
// Returns the write data value masked with excluded fields.
|
||||
//
|
||||
// Some fields in the CSR may be excluded from writes. In that case, we need to revert those
|
||||
// fields to their mirrored values and write the rest of the fields with the given value.
|
||||
function automatic uvm_reg_data_t get_csr_wdata_with_write_excl(
|
||||
uvm_reg csr,
|
||||
uvm_reg_data_t wdata,
|
||||
csr_test_type_e csr_test_type,
|
||||
csr_excl_item m_csr_excl_item = get_excl_item(csr)
|
||||
);
|
||||
uvm_reg_field flds[$];
|
||||
csr.get_fields(flds);
|
||||
|
||||
foreach (flds[i]) begin
|
||||
if (m_csr_excl_item.is_excl(flds[i], CsrExclWrite, csr_test_type)) begin
|
||||
`uvm_info(msg_id, $sformatf(
|
||||
"Retain mirrored value 0x%0h for field %0s due to CsrExclWrite exclusion",
|
||||
`gmv(flds[i]), flds[i].get_full_name()), UVM_MEDIUM)
|
||||
wdata = get_csr_val_with_updated_field(flds[i], wdata, `gmv(flds[i]));
|
||||
end
|
||||
end
|
||||
return wdata;
|
||||
endfunction
|
||||
|
||||
function automatic csr_excl_item get_excl_item(uvm_object ptr);
|
||||
csr_field_t csr_or_fld;
|
||||
dv_base_reg_block blk;
|
||||
|
|
227
vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_reg.sv
vendored
227
vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_reg.sv
vendored
|
@ -8,20 +8,17 @@ class dv_base_reg extends uvm_reg;
|
|||
// hence, backdoor write isn't available
|
||||
local bit is_ext_reg;
|
||||
|
||||
local uvm_reg_data_t staged_shadow_val, committed_val, shadowed_val;
|
||||
local bit is_shadowed;
|
||||
local bit shadow_wr_staged; // stage the first shadow reg write
|
||||
local bit shadow_update_err;
|
||||
local bit en_shadow_wr = 1;
|
||||
// In certain shadow reg (e.g. in AES), fatal error can lock write access
|
||||
local bit backdoor_write_shadow_val; // flag to avoid predict `shadow_wr_staged`
|
||||
// Update internal shadow committed and shadowed values when register access is not `RW`.
|
||||
local bit do_update_shadow_vals;
|
||||
// In certain shadow reg (e.g. in AES), fatal error can lock write access.
|
||||
local bit shadow_fatal_lock;
|
||||
local string update_err_alert_name;
|
||||
local string storage_err_alert_name;
|
||||
|
||||
// atomic_shadow_wr: semaphore to guarantee atomicity of the two writes for shadowed registers.
|
||||
// In case a parallel thread writing a different value to the same reg causing an update_err
|
||||
semaphore atomic_shadow_wr;
|
||||
|
||||
// atomic_en_shadow_wr: semaphore to guarantee setting or resetting en_shadow_wr is unchanged
|
||||
// through the 1st/2nd (or both) writes
|
||||
semaphore atomic_en_shadow_wr;
|
||||
|
@ -31,13 +28,16 @@ class dv_base_reg extends uvm_reg;
|
|||
int has_coverage);
|
||||
super.new(name, n_bits, has_coverage);
|
||||
atomic_en_shadow_wr = new(1);
|
||||
atomic_shadow_wr = new(1);
|
||||
endfunction : new
|
||||
|
||||
function void get_dv_base_reg_fields(ref dv_base_reg_field dv_fields[$]);
|
||||
foreach (m_fields[i]) `downcast(dv_fields[i], m_fields[i])
|
||||
endfunction
|
||||
|
||||
function dv_base_reg_block get_dv_base_reg_block();
|
||||
`downcast(get_dv_base_reg_block, get_parent())
|
||||
endfunction
|
||||
|
||||
// get_n_bits will return number of all the bits in the csr
|
||||
// while this function will return actual number of bits used in reg field
|
||||
function uint get_n_used_bits();
|
||||
|
@ -65,6 +65,15 @@ class dv_base_reg extends uvm_reg;
|
|||
return dv_fld;
|
||||
endfunction
|
||||
|
||||
// Return a mask of valid bits in the register.
|
||||
virtual function uvm_reg_data_t get_reg_mask();
|
||||
dv_base_reg_field flds[$];
|
||||
this.get_dv_base_reg_fields(flds);
|
||||
foreach (flds[i]) begin
|
||||
get_reg_mask |= flds[i].get_field_mask();
|
||||
end
|
||||
endfunction
|
||||
|
||||
// this function can only be called when this reg is intr_state reg
|
||||
// Example: ral.intr_state.get_intr_pins_exp_value(). And it returns value of
|
||||
// intr_state & intr_enable, which represents value of interrupt pins
|
||||
|
@ -138,19 +147,12 @@ class dv_base_reg extends uvm_reg;
|
|||
is_shadowed = 1;
|
||||
endfunction
|
||||
|
||||
function uvm_reg_data_t get_staged_shadow_val();
|
||||
return staged_shadow_val;
|
||||
endfunction
|
||||
|
||||
function void set_en_shadow_wr(bit val);
|
||||
// do not update en_shadow_wr if shadow register write is in process
|
||||
if ((en_shadow_wr ^ val) && shadow_wr_staged) begin
|
||||
`uvm_info(`gfn,
|
||||
$sformatf("unable to %0s en_shadow_wr because register already completed first write",
|
||||
val ? "set" : "clear"), UVM_HIGH)
|
||||
return;
|
||||
// A helper function for shadow register or field read to clear the `shadow_wr_staged` flag.
|
||||
virtual function void clear_shadow_wr_staged();
|
||||
if (is_shadowed) begin
|
||||
if (shadow_wr_staged) `uvm_info(`gfn, "clear shadow_wr_staged", UVM_HIGH)
|
||||
shadow_wr_staged = 0;
|
||||
end
|
||||
en_shadow_wr = val;
|
||||
endfunction
|
||||
|
||||
function bit get_is_shadowed();
|
||||
|
@ -162,53 +164,71 @@ class dv_base_reg extends uvm_reg;
|
|||
endfunction
|
||||
|
||||
function bit get_shadow_storage_err();
|
||||
uvm_reg_data_t mask = (1'b1 << (get_msb_pos() + 1)) - 1;
|
||||
uvm_reg_data_t shadowed_val_temp = (~shadowed_val) & mask;
|
||||
uvm_reg_data_t committed_val_temp = committed_val & mask;
|
||||
`uvm_info(`gfn, $sformatf("shadow_val %0h, commmit_val %0h", shadowed_val_temp,
|
||||
committed_val_temp), UVM_DEBUG)
|
||||
return shadowed_val_temp != committed_val_temp;
|
||||
dv_base_reg_field flds[$];
|
||||
this.get_dv_base_reg_fields(flds);
|
||||
foreach (flds[i]) begin
|
||||
get_shadow_storage_err |= flds[i].get_shadow_storage_err();
|
||||
end
|
||||
endfunction
|
||||
|
||||
virtual function void clear_shadow_update_err();
|
||||
shadow_update_err = 0;
|
||||
endfunction
|
||||
|
||||
// post_write callback to handle special regs:
|
||||
// do_predict callback to handle special regs. This function doesn't update mirror values, but
|
||||
// update local variables used for the special regs.
|
||||
// - shadow register: shadow reg won't be updated until the second write has no error
|
||||
// - lock register: if wen_fld is set to 0, change access policy to all the lockable_flds
|
||||
// TODO: create an `enable_field_access_policy` variable and set the template code during
|
||||
// automation.
|
||||
virtual task post_write(uvm_reg_item rw);
|
||||
dv_base_reg_field fields[$];
|
||||
virtual function void pre_do_predict(uvm_reg_item rw, uvm_predict_e kind);
|
||||
|
||||
// no need to update shadow value or access type if access is not OK, as access is aborted
|
||||
if (rw.status != UVM_IS_OK) return;
|
||||
// Skip updating shadow value or access type if:
|
||||
// 1). Access is not OK, as access is aborted.
|
||||
// 2). The operation is not write.
|
||||
// 3). The update is triggered by backdoor poke.
|
||||
if (rw.status != UVM_IS_OK || kind != UVM_PREDICT_WRITE || backdoor_write_shadow_val) return;
|
||||
|
||||
if (is_shadowed && !shadow_fatal_lock) begin
|
||||
// first write
|
||||
if (!shadow_wr_staged) begin
|
||||
shadow_wr_staged = 1;
|
||||
// rw.value is a dynamic array
|
||||
staged_shadow_val = rw.value[0];
|
||||
return;
|
||||
end begin
|
||||
// second write
|
||||
shadow_wr_staged = 0;
|
||||
if (staged_shadow_val != rw.value[0]) begin
|
||||
shadow_update_err = 1;
|
||||
return;
|
||||
dv_base_reg_field flds[$];
|
||||
this.get_dv_base_reg_fields(flds);
|
||||
|
||||
foreach (flds[i]) begin
|
||||
// `rw.value` is a dynamic array.
|
||||
uvm_reg_data_t wr_data = get_field_val(flds[i], rw.value[0]);
|
||||
|
||||
// Skip updating shadow value or access type for this field if:
|
||||
// 1). A storage error is triggered, which means the field is locked to error status.
|
||||
// 2). The register is "RO". This condition is used to cover enable register locks shadowed
|
||||
// register's write access.
|
||||
if (flds[i].get_shadow_storage_err() || flds[i].get_access() == "RO") continue;
|
||||
|
||||
// first write
|
||||
if (!shadow_wr_staged) begin
|
||||
flds[i].update_staged_val(wr_data);
|
||||
continue;
|
||||
end begin
|
||||
// second write
|
||||
if (flds[i].get_staged_val() == wr_data) begin
|
||||
flds[i].update_committed_val(wr_data);
|
||||
flds[i].update_shadowed_val(~wr_data);
|
||||
end else begin
|
||||
shadow_update_err = 1;
|
||||
end
|
||||
end
|
||||
committed_val = staged_shadow_val;
|
||||
shadowed_val = ~committed_val;
|
||||
end
|
||||
if (!shadow_wr_staged) shadow_wr_staged = 1;
|
||||
else shadow_wr_staged = 0;
|
||||
|
||||
// Update committed and shadowed values if the field access is not "RW".
|
||||
// Used for register with special access policy such as `RW1S`.
|
||||
if (!shadow_wr_staged && flds[0].get_access() != "RW") do_update_shadow_vals = 1;
|
||||
end
|
||||
lock_lockable_flds(rw.value[0]);
|
||||
endtask
|
||||
endfunction
|
||||
|
||||
// shadow register read will clear its phase tracker
|
||||
virtual task post_read(uvm_reg_item rw);
|
||||
if (is_shadowed) shadow_wr_staged = 0;
|
||||
if (rw.status == UVM_IS_OK) clear_shadow_wr_staged();
|
||||
endtask
|
||||
|
||||
virtual function void set_is_ext_reg(bit is_ext);
|
||||
|
@ -219,42 +239,45 @@ class dv_base_reg extends uvm_reg;
|
|||
return is_ext_reg;
|
||||
endfunction
|
||||
|
||||
// if it is a shadowed register, and is enabled to write it twice, this task will write the
|
||||
// register twice with the same value and address.
|
||||
virtual task write(output uvm_status_e status,
|
||||
input uvm_reg_data_t value,
|
||||
input uvm_path_e path = UVM_DEFAULT_PATH,
|
||||
input uvm_reg_map map = null,
|
||||
input uvm_sequence_base parent=null,
|
||||
input int prior = -1,
|
||||
input uvm_object extension = null,
|
||||
input string fname = "",
|
||||
input int lineno = 0);
|
||||
if (is_shadowed) atomic_shadow_wr.get(1);
|
||||
super.write(status, value, path, map, parent, prior, extension, fname, lineno);
|
||||
if (is_shadowed && en_shadow_wr) begin
|
||||
super.write(status, value, path, map, parent, prior, extension, fname, lineno);
|
||||
end
|
||||
if (is_shadowed) atomic_shadow_wr.put(1);
|
||||
endtask
|
||||
|
||||
// Override do_predict function to support shadow_reg.
|
||||
// Skip predict in one of the following conditions:
|
||||
// 1). It is shadow_reg's first write.
|
||||
// 2). It is shadow_reg's second write with an update_err.
|
||||
// 2). The shadow_reg is locked due to fatal storage error and it is not a backdoor write.
|
||||
|
||||
// Note that if shadow_register write has update error, we only update the value with correct
|
||||
// fields.
|
||||
virtual function void do_predict(uvm_reg_item rw,
|
||||
uvm_predict_e kind = UVM_PREDICT_DIRECT,
|
||||
uvm_reg_byte_en_t be = -1);
|
||||
if (is_shadowed && kind != UVM_PREDICT_READ && (shadow_wr_staged || shadow_update_err ||
|
||||
(shadow_fatal_lock && rw.path != UVM_BACKDOOR))) begin
|
||||
`uvm_info(`gfn, $sformatf(
|
||||
"skip predict %s: due to shadow_reg_first_wr=%0b, update_err=%0b, shadow_fatal_lock=%0b",
|
||||
get_name(), shadow_wr_staged, shadow_update_err, shadow_fatal_lock), UVM_HIGH)
|
||||
return;
|
||||
pre_do_predict(rw, kind);
|
||||
if (is_shadowed && kind != UVM_PREDICT_READ) begin
|
||||
if (shadow_wr_staged || (shadow_fatal_lock && rw.path != UVM_BACKDOOR)) begin
|
||||
`uvm_info(`gfn, $sformatf(
|
||||
"skip predict %s: due to shadow_reg_first_wr=%0b, shadow_fatal_lock=%0b",
|
||||
get_name(), shadow_wr_staged, shadow_fatal_lock), UVM_HIGH)
|
||||
return;
|
||||
end else begin
|
||||
`uvm_info(`gfn, $sformatf(
|
||||
"Shadow reg %0s has update error, update rw.value from %0h to %0h",
|
||||
get_name(), rw.value[0], get_committed_val()), UVM_HIGH)
|
||||
rw.value[0] = get_committed_val();
|
||||
end
|
||||
end
|
||||
super.do_predict(rw, kind, be);
|
||||
|
||||
// For register with special access policies, update committed and shadowed value again with
|
||||
// the actual predicted value.
|
||||
if (do_update_shadow_vals) begin
|
||||
dv_base_reg_field flds[$];
|
||||
this.get_dv_base_reg_fields(flds);
|
||||
foreach (flds[i]) begin
|
||||
if (!flds[i].get_shadow_storage_err()) begin
|
||||
flds[i].update_committed_val(`gmv(flds[i]));
|
||||
flds[i].update_shadowed_val(~`gmv(flds[i]));
|
||||
end
|
||||
end
|
||||
do_update_shadow_vals = 0;
|
||||
end
|
||||
lock_lockable_flds(rw.value[0]);
|
||||
endfunction
|
||||
|
||||
// This function is used for wen_reg to lock its lockable flds by changing the lockable flds'
|
||||
|
@ -287,31 +310,35 @@ class dv_base_reg extends uvm_reg;
|
|||
input uvm_object extension = null,
|
||||
input string fname = "",
|
||||
input int lineno = 0);
|
||||
if (kind == "BkdrRegPathRtlShadow") shadowed_val = value;
|
||||
else if (kind == "BkdrRegPathRtlCommitted") committed_val = value;
|
||||
|
||||
dv_base_reg_field flds[$];
|
||||
this.get_dv_base_reg_fields(flds);
|
||||
foreach (flds[i]) begin
|
||||
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
|
||||
flds[i].update_committed_val(get_field_val(flds[i], value));
|
||||
backdoor_write_shadow_val = 1;
|
||||
end
|
||||
end
|
||||
super.poke(status, value, kind, parent, extension, fname, lineno);
|
||||
backdoor_write_shadow_val = 0;
|
||||
endtask
|
||||
|
||||
virtual function uvm_reg_data_t get_committed_val();
|
||||
dv_base_reg_field flds[$];
|
||||
this.get_dv_base_reg_fields(flds);
|
||||
foreach (flds[i]) begin
|
||||
get_committed_val |= flds[i].get_committed_val() << flds[i].get_lsb_pos();
|
||||
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);
|
||||
if (shadow_fatal_lock) return;
|
||||
if (shadow_wr_staged) begin
|
||||
// update value after first write
|
||||
staged_shadow_val = val;
|
||||
end else begin
|
||||
// update value after second write
|
||||
if (staged_shadow_val != val) begin
|
||||
shadow_update_err = 1;
|
||||
end else begin
|
||||
shadow_update_err = 0;
|
||||
committed_val = staged_shadow_val;
|
||||
shadowed_val = ~committed_val;
|
||||
end
|
||||
end
|
||||
if (do_predict) void'(predict(val));
|
||||
// TODO: find a better way to support for AES.
|
||||
endfunction
|
||||
|
||||
virtual function void reset(string kind = "HARD");
|
||||
|
@ -320,12 +347,8 @@ class dv_base_reg extends uvm_reg;
|
|||
shadow_update_err = 0;
|
||||
shadow_wr_staged = 0;
|
||||
shadow_fatal_lock = 0;
|
||||
committed_val = get_mirrored_value();
|
||||
shadowed_val = ~committed_val;
|
||||
// in case reset is issued during shadowed writes
|
||||
void'(atomic_shadow_wr.try_get(1));
|
||||
void'(atomic_en_shadow_wr.try_get(1));
|
||||
atomic_shadow_wr.put(1);
|
||||
atomic_en_shadow_wr.put(1);
|
||||
end
|
||||
endfunction
|
||||
|
@ -339,13 +362,11 @@ class dv_base_reg extends uvm_reg;
|
|||
endfunction
|
||||
|
||||
function string get_update_err_alert_name();
|
||||
string parent_name = this.get_parent().get_name();
|
||||
|
||||
// block level alert name is input alert name from hjson
|
||||
if (get_parent().get_parent() == null) return update_err_alert_name;
|
||||
|
||||
// top-level alert name is ${block_name} + alert name from hjson
|
||||
return ($sformatf("%0s_%0s", parent_name, update_err_alert_name));
|
||||
// top-level alert name is ${ip_name} + alert name from hjson
|
||||
return ($sformatf("%0s_%0s", get_dv_base_reg_block().get_ip_name(), update_err_alert_name));
|
||||
endfunction
|
||||
|
||||
function void lock_shadow_reg();
|
||||
|
@ -357,13 +378,13 @@ class dv_base_reg extends uvm_reg;
|
|||
endfunction
|
||||
|
||||
function string get_storage_err_alert_name();
|
||||
string parent_name = this.get_parent().get_name();
|
||||
string ip_name;
|
||||
|
||||
// block level alert name is input alert name from hjson
|
||||
if (get_parent().get_parent() == null) return storage_err_alert_name;
|
||||
|
||||
// top-level alert name is ${block_name} + alert name from hjson
|
||||
return ($sformatf("%0s_%0s", parent_name, storage_err_alert_name));
|
||||
// top-level alert name is ${ip_name} + alert name from hjson
|
||||
return ($sformatf("%0s_%0s", get_dv_base_reg_block().get_ip_name(), storage_err_alert_name));
|
||||
endfunction
|
||||
|
||||
endclass
|
||||
|
|
|
@ -6,6 +6,12 @@
|
|||
class dv_base_reg_block extends uvm_reg_block;
|
||||
`uvm_object_utils(dv_base_reg_block)
|
||||
|
||||
// Since an IP may contains more than one reg block we construct reg_block name as
|
||||
// {ip_name}_{reg_interface_name}.
|
||||
// All the reg_blocks in the IP share the same alert. In top-level, We construct the alert
|
||||
// name as {ip_name}_{alert_name}. Hence, we need this ip_name in reg_block
|
||||
local string ip_name;
|
||||
|
||||
csr_excl_item csr_excl;
|
||||
|
||||
// The address mask for the register block specific to a map. This will be (1 << K) - 1 for some
|
||||
|
@ -29,6 +35,17 @@ class dv_base_reg_block extends uvm_reg_block;
|
|||
super.new(name, has_coverage);
|
||||
endfunction
|
||||
|
||||
function void set_ip_name(string name);
|
||||
ip_name = name;
|
||||
endfunction
|
||||
|
||||
function string get_ip_name();
|
||||
// `DV_CHECK_NE_FATAL can't take "" as an input
|
||||
string empty_str = "";
|
||||
`DV_CHECK_NE_FATAL(ip_name, empty_str, "ip_name hasn't been set yet")
|
||||
return ip_name;
|
||||
endfunction
|
||||
|
||||
// provide build function to supply base addr
|
||||
virtual function void build(uvm_reg_addr_t base_addr,
|
||||
csr_excl_item csr_excl = null);
|
||||
|
@ -277,4 +294,13 @@ class dv_base_reg_block extends uvm_reg_block;
|
|||
return (word_aligned ? get_word_aligned_addr(byte_offset) : byte_offset) + map.get_base_addr();
|
||||
endfunction
|
||||
|
||||
// The design ignores the address bits that aren't enabled by addr_mask.
|
||||
// Normalize these ignored bits to enable locating which CSR/mem is at the returned address.
|
||||
function uvm_reg_addr_t get_normalized_addr(uvm_reg_addr_t byte_addr, uvm_reg_map map = null);
|
||||
if (map == null) map = get_default_map();
|
||||
return get_addr_from_offset(.byte_offset(byte_addr & addr_mask[map]),
|
||||
.word_aligned(1),
|
||||
.map(map));
|
||||
endfunction
|
||||
|
||||
endclass
|
||||
|
|
|
@ -7,6 +7,7 @@ class dv_base_reg_field extends uvm_reg_field;
|
|||
local string m_original_access;
|
||||
local dv_base_reg_field lockable_flds[$];
|
||||
local bit is_intr_test_fld;
|
||||
local uvm_reg_data_t staged_val, committed_val, shadowed_val;
|
||||
|
||||
`uvm_object_utils(dv_base_reg_field)
|
||||
`uvm_object_new
|
||||
|
@ -34,6 +35,7 @@ class dv_base_reg_field extends uvm_reg_field;
|
|||
value.rand_mode(is_rand);
|
||||
|
||||
is_intr_test_fld = !(uvm_re_match("intr_test*", get_parent().get_name()));
|
||||
shadowed_val = ~committed_val;
|
||||
endfunction
|
||||
|
||||
virtual function dv_base_reg get_dv_base_reg_parent();
|
||||
|
@ -126,11 +128,50 @@ class dv_base_reg_field extends uvm_reg_field;
|
|||
lockable_flds_q = lockable_flds;
|
||||
endfunction
|
||||
|
||||
// shadow register field read will clear its phase tracker
|
||||
virtual task post_read(uvm_reg_item rw);
|
||||
if (rw.status == UVM_IS_OK) begin
|
||||
dv_base_reg parent_csr = get_dv_base_reg_parent();
|
||||
parent_csr.clear_shadow_wr_staged();
|
||||
end
|
||||
endtask
|
||||
|
||||
function bit get_shadow_storage_err();
|
||||
uvm_reg_data_t mask = (1 << get_n_bits()) - 1;
|
||||
uvm_reg_data_t shadowed_val_temp = (~shadowed_val) & mask;
|
||||
uvm_reg_data_t committed_val_temp = committed_val & mask;
|
||||
`uvm_info(`gfn, $sformatf("shadow_val %0h, commmit_val %0h", shadowed_val_temp,
|
||||
committed_val_temp), UVM_HIGH)
|
||||
return shadowed_val_temp != committed_val_temp;
|
||||
endfunction
|
||||
|
||||
function void update_staged_val(uvm_reg_data_t val);
|
||||
staged_val = val;
|
||||
endfunction
|
||||
|
||||
function uvm_reg_data_t get_staged_val();
|
||||
return staged_val;
|
||||
endfunction
|
||||
|
||||
function void update_shadowed_val(uvm_reg_data_t val);
|
||||
shadowed_val = val;
|
||||
endfunction
|
||||
|
||||
function void update_committed_val(uvm_reg_data_t val);
|
||||
committed_val = val;
|
||||
endfunction
|
||||
|
||||
function uvm_reg_data_t get_committed_val();
|
||||
return committed_val;
|
||||
endfunction
|
||||
|
||||
// override RAL's reset function to support enable registers
|
||||
// when reset issued - the lockable field's access will be reset to original access
|
||||
virtual function void reset(string kind = "HARD");
|
||||
super.reset(kind);
|
||||
set_fld_access(0);
|
||||
committed_val = get_mirrored_value();
|
||||
shadowed_val = ~committed_val;
|
||||
endfunction
|
||||
|
||||
// this function can only be called when this reg is intr_test reg
|
||||
|
|
|
@ -73,4 +73,12 @@ package dv_base_reg_pkg;
|
|||
end
|
||||
endfunction
|
||||
|
||||
// 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,
|
||||
uvm_reg_data_t value);
|
||||
uvm_reg_data_t mask = (1 << field.get_n_bits()) - 1;
|
||||
uint shift = field.get_lsb_pos();
|
||||
get_field_val = (value >> shift) & mask;
|
||||
endfunction
|
||||
|
||||
endpackage
|
||||
|
|
|
@ -43,8 +43,15 @@ class dv_base_env_cfg #(type RAL_T = dv_base_reg_block) extends uvm_object;
|
|||
// clk_rst_vif and clk_freq_mhz can be found from the associative arrays
|
||||
virtual clk_rst_if clk_rst_vif;
|
||||
virtual clk_rst_if clk_rst_vifs[string];
|
||||
rand clk_freq_mhz_e clk_freq_mhz;
|
||||
rand clk_freq_mhz_e clk_freqs_mhz[string];
|
||||
rand uint clk_freq_mhz;
|
||||
rand uint clk_freqs_mhz[string];
|
||||
|
||||
constraint clk_freq_mhz_c {
|
||||
`DV_COMMON_CLK_CONSTRAINT(clk_freq_mhz)
|
||||
foreach (clk_freqs_mhz[i]) {
|
||||
`DV_COMMON_CLK_CONSTRAINT(clk_freqs_mhz[i])
|
||||
}
|
||||
}
|
||||
|
||||
`uvm_object_param_utils_begin(dv_base_env_cfg #(RAL_T))
|
||||
`uvm_field_int (is_active, UVM_DEFAULT)
|
||||
|
@ -74,7 +81,7 @@ class dv_base_env_cfg #(type RAL_T = dv_base_reg_block) extends uvm_object;
|
|||
|
||||
// add items to clk_freqs_mhz before randomizing it
|
||||
foreach (ral_model_names[i]) begin
|
||||
clk_freqs_mhz[ral_model_names[i]] = ClkFreq24Mhz;
|
||||
clk_freqs_mhz[ral_model_names[i]] = 0;
|
||||
end
|
||||
endfunction
|
||||
|
||||
|
|
11
vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_vseq.sv
vendored
11
vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_vseq.sv
vendored
|
@ -78,8 +78,10 @@ class dv_base_vseq #(type RAL_T = dv_base_reg_block,
|
|||
* startup, reset and shutdown related tasks
|
||||
*/
|
||||
virtual task dut_init(string reset_kind = "HARD");
|
||||
if (do_apply_reset) apply_reset(reset_kind);
|
||||
else if (do_wait_for_reset) wait_for_reset(reset_kind);
|
||||
if (do_apply_reset) begin
|
||||
apply_reset(reset_kind);
|
||||
post_apply_reset(reset_kind);
|
||||
end else if (do_wait_for_reset) wait_for_reset(reset_kind);
|
||||
// delay after reset for tl agent check seq_item_port empty
|
||||
#1ps;
|
||||
endtask
|
||||
|
@ -137,6 +139,11 @@ class dv_base_vseq #(type RAL_T = dv_base_reg_block,
|
|||
end
|
||||
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.
|
||||
virtual task post_apply_reset(string reset_kind = "HARD");
|
||||
endtask
|
||||
|
||||
virtual task wait_for_reset(string reset_kind = "HARD",
|
||||
bit wait_for_assert = 1,
|
||||
bit wait_for_deassert = 1);
|
||||
|
|
33
vendor/lowrisc_ip/dv/sv/dv_utils/dv_macros.svh
vendored
33
vendor/lowrisc_ip/dv/sv/dv_utils/dv_macros.svh
vendored
|
@ -409,6 +409,24 @@
|
|||
end
|
||||
`endif
|
||||
|
||||
// This macro converts a string input from plusarg to an enum variable
|
||||
// ENUM_: the name of enum type
|
||||
// PLUSARG_: the name of the plusargs, which is also the name of the enum variable
|
||||
// CHECK_EXIST_: set to 1, `$value$plusargs()` should return true
|
||||
`ifndef DV_GET_ENUM_PLUSARG
|
||||
`define DV_GET_ENUM_PLUSARG(ENUM_, PLUSARG_, CHECK_EXIST_ = 0, ID_ = `gfn) \
|
||||
begin \
|
||||
string str; \
|
||||
if ($value$plusargs("``PLUSARG_``=%0s", str)) begin \
|
||||
if (!uvm_enum_wrapper#(ENUM_)::from_name(str, PLUSARG_)) begin \
|
||||
`uvm_fatal(ID_, $sformatf("Cannot find %s from enum ``ENUM_``", PLUSARG_.name)) \
|
||||
end \
|
||||
end else if (CHECK_EXIST_) begin \
|
||||
`uvm_fatal(ID_, "Can't find plusargs ``PLUSARG_``") \
|
||||
end \
|
||||
end
|
||||
`endif
|
||||
|
||||
// Enable / disable assertions at a module hierarchy identified by LABEL_.
|
||||
//
|
||||
// This goes in conjunction with `DV_ASSERT_CTRL() macro above, but is invoked in the entity that is
|
||||
|
@ -492,3 +510,18 @@
|
|||
`endif
|
||||
|
||||
`endif // UVM
|
||||
|
||||
// Macros for constrain clk with common frequencies
|
||||
// constrain clock to run at 24Mhz - 100Mhz and use higher weights on 24, 25, 48, 50, 100
|
||||
`ifndef DV_COMMON_CLK_CONSTRAINT
|
||||
`define DV_COMMON_CLK_CONSTRAINT(FREQ_) \
|
||||
FREQ_ dist { \
|
||||
[24:25] :/ 2, \
|
||||
[26:47] :/ 1, \
|
||||
[48:50] :/ 2, \
|
||||
[51:95] :/ 1, \
|
||||
96 :/ 1, \
|
||||
[97:99] :/ 1, \
|
||||
100 :/ 1 \
|
||||
};
|
||||
`endif
|
||||
|
|
17
vendor/lowrisc_ip/dv/sv/dv_utils/dv_utils_pkg.sv
vendored
17
vendor/lowrisc_ip/dv/sv/dv_utils/dv_utils_pkg.sv
vendored
|
@ -44,15 +44,6 @@ package dv_utils_pkg;
|
|||
Device
|
||||
} if_mode_e;
|
||||
|
||||
// speed for the clock
|
||||
typedef enum int {
|
||||
ClkFreq24Mhz = 24,
|
||||
ClkFreq25Mhz = 25,
|
||||
ClkFreq48Mhz = 48,
|
||||
ClkFreq50Mhz = 50,
|
||||
ClkFreq100Mhz = 100
|
||||
} clk_freq_mhz_e;
|
||||
|
||||
// compare operator types
|
||||
typedef enum {
|
||||
CompareOpEq,
|
||||
|
@ -85,6 +76,14 @@ package dv_utils_pkg;
|
|||
HostReqReadWrite = 3
|
||||
} host_req_type_e;
|
||||
|
||||
// Enum representing clock frequency difference on 2 clocks
|
||||
typedef enum bit [1:0] {
|
||||
ClkFreqDiffNone,
|
||||
ClkFreqDiffSmall,
|
||||
ClkFreqDiffBig,
|
||||
ClkFreqDiffAny
|
||||
} clk_freq_diff_e;
|
||||
|
||||
string msg_id = "dv_utils_pkg";
|
||||
|
||||
// return the smaller value of 2 inputs
|
||||
|
|
|
@ -137,19 +137,19 @@
|
|||
// Project defaults for VCS
|
||||
vcs_cov_cfg_file: "{{build_mode}_vcs_cov_cfg_file}"
|
||||
vcs_unr_cfg_file: "{dv_root}/tools/vcs/unr.cfg"
|
||||
vcs_cov_excl_files: ["{dv_root}/tools/vcs/common_cov_excl.el"]
|
||||
vcs_cov_excl_files: []
|
||||
|
||||
// Build-specific coverage cfg files for VCS.
|
||||
default_vcs_cov_cfg_file: "-cm_hier {dv_root}/tools/vcs/cover.cfg"
|
||||
cover_reg_top_vcs_cov_cfg_file: "-cm_hier {dv_root}/tools/vcs/cover_reg_top.cfg"
|
||||
default_vcs_cov_cfg_file: "-cm_hier {dv_root}/tools/vcs/cover.cfg+{dv_root}/tools/vcs/common_cov_excl.cfg"
|
||||
cover_reg_top_vcs_cov_cfg_file: "-cm_hier {dv_root}/tools/vcs/cover_reg_top.cfg+{dv_root}/tools/vcs/common_cov_excl.cfg"
|
||||
|
||||
// Project defaults for Xcelium
|
||||
xcelium_cov_cfg_file: "{dv_root}/tools/xcelium/xcelium.ccf"
|
||||
xcelium_cov_refine_files: []
|
||||
xcelium_cov_cfg_file: "{{build_mode}_xcelium_cov_cfg_file}"
|
||||
xcelium_unr_cfg_file: "{dv_root}/tools/xcelium/unr.cfg"
|
||||
xcelium_common_excl_file: ["{dv_root}/tools/xcelium/exclude.tcl"]
|
||||
xcelium_cov_excl_script: "{dv_root}/tools/xcelium/common_cov_excl.tcl"
|
||||
xcelium_cov_refine_files: []
|
||||
|
||||
// Build-specific coverage cfg files for Xcelium.
|
||||
// default_xcelium_cov_cfg_file: "-covfile {dv_root}/tools/xcelium/cover.ccf"
|
||||
// cover_reg_top_xcelium_cov_cfg_file: "-covfile {dv_root}/tools/xcelium/cover_reg_top.ccf"
|
||||
default_xcelium_cov_cfg_file: "{dv_root}/tools/xcelium/cover.ccf"
|
||||
cover_reg_top_xcelium_cov_cfg_file: "{dv_root}/tools/xcelium/cover_reg_top.ccf"
|
||||
}
|
||||
|
|
3
vendor/lowrisc_ip/dv/tools/dvsim/dsim.hjson
vendored
3
vendor/lowrisc_ip/dv/tools/dvsim/dsim.hjson
vendored
|
@ -20,6 +20,9 @@
|
|||
// List multiple tops for the simulation. Prepend each top level with `-top`.
|
||||
"{eval_cmd} echo {sim_tops} | sed -E 's/(\\S+)/-top \\1/g'",
|
||||
"+incdir+{build_dir}",
|
||||
// TODO Remove buggy optimization when dsim fixes bug
|
||||
// https://gitlab.metrics.ca/google/google/-/issues/242.
|
||||
"-noopt-task-func",
|
||||
// Suppress following DSim errors and warnings:
|
||||
// EnumMustBePositive - UVM 1.2 violates this
|
||||
"-suppress EnumMustBePositive"]
|
||||
|
|
|
@ -6,11 +6,12 @@
|
|||
fusesoc_core_: "{eval_cmd} echo \"{fusesoc_core}\" | tr ':' '_'"
|
||||
sv_flist_gen_opts: ["{fusesoc_cores_root_dirs}",
|
||||
"run",
|
||||
"--flag=fileset_{design_level}",
|
||||
"{sv_flist_gen_flags}",
|
||||
"--target=sim",
|
||||
"--build-root={build_dir}",
|
||||
"--setup {fusesoc_core}"]
|
||||
fusesoc_cores_root_dirs: ["--cores-root {proj_root}"]
|
||||
sv_flist_gen_dir: "{build_dir}/sim-vcs"
|
||||
sv_flist: "{sv_flist_gen_dir}/{fusesoc_core_}.scr"
|
||||
sv_flist_gen_flags: ["--flag=fileset_{design_level}"]
|
||||
}
|
||||
|
|
52
vendor/lowrisc_ip/dv/tools/dvsim/testplans/sec_cm_testplan.hjson
vendored
Normal file
52
vendor/lowrisc_ip/dv/tools/dvsim/testplans/sec_cm_testplan.hjson
vendored
Normal file
|
@ -0,0 +1,52 @@
|
|||
// 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"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -5,23 +5,47 @@
|
|||
testpoints: [
|
||||
{
|
||||
// this testplan should be imported by all IPs containing shadowed CSRs
|
||||
name: shadow_reg_errors
|
||||
desc: '''
|
||||
Verify shadow registers' update and storage errors.
|
||||
- Issue reset at random to clear all the internal stored values and phases trackers
|
||||
in shadow registers.
|
||||
- Select all the shadow registers and a random amount of the rest of the non-excluded
|
||||
registers. Shuffle and write random values to the selected registers.
|
||||
For shadow registers, the second write is not enabled.
|
||||
There is a 50% possibility that the shadow register's write value is identical to its
|
||||
previous write value.
|
||||
If shadow register's second write value does not match the first write value,
|
||||
ensure that the update error alert is triggered.
|
||||
- Randomly inject storage errors by modifying the shadow register's staged or committed
|
||||
values via backdoor method. Ensure that the storage error alert is triggered.
|
||||
- Randomly decide to read all the non-excluded registers or fields. Then check the read
|
||||
values against predicted values.
|
||||
A read on a shadow register will clear its phase tracker.
|
||||
name: shadow_reg_update_error
|
||||
desc: '''Verify shadowed registers' update error.
|
||||
|
||||
- Randomly pick a shadowed register in the DUT.
|
||||
- Write it twice with different values.
|
||||
- Verify that the update error alert is triggered and the register value remains
|
||||
unchanged.
|
||||
- Verify the update_error status register field is set to 1.
|
||||
- Repeat the above steps a bunch of times.
|
||||
'''
|
||||
milestone: V1
|
||||
tests: ["{name}_shadow_reg_errors"]
|
||||
}
|
||||
|
||||
{
|
||||
name: shadow_reg_read_clear_staged_value
|
||||
desc: '''Verify reading a shadowed register will clear its staged value.
|
||||
|
||||
- Randomly pick a shadowed register in the DUT.
|
||||
- Write it once and read it back to clear the staged value.
|
||||
- Then write it twice with the same new value (but different from the previous step).
|
||||
- Read it back to verify the new value and ensure that the update error alert did not
|
||||
trigger.
|
||||
- Verify the update_error status register field remains the same value.
|
||||
- Repeat the above steps a bunch of times.
|
||||
'''
|
||||
milestone: V1
|
||||
tests: ["{name}_shadow_reg_errors"]
|
||||
}
|
||||
|
||||
{
|
||||
name: shadow_reg_storage_error
|
||||
desc: '''Verify shadowed registers' storage error.
|
||||
|
||||
- Randomly pick a shadowed register in the DUT.
|
||||
- Backdoor write to shadowed or committed flops to create a storage fatal alert.
|
||||
- Check if fatal alert continuously fires until reset.
|
||||
- Verify that all other frontdoor write attempts are blocked during the storage error.
|
||||
- Verify that storage_error status register field is set to 1.
|
||||
- Reset the DUT.
|
||||
- Read all CSRs to ensure the DUT is properly reset.
|
||||
- Repeat the above steps a bunch of times.
|
||||
'''
|
||||
milestone: V1
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
desc: '''This test runs 3 parallel threads - stress_all, tl_errors and random reset.
|
||||
After reset is asserted, the test will read and check all valid CSR registers.
|
||||
'''
|
||||
milestone: V2
|
||||
milestone: V3
|
||||
tests: ["{name}_stress_all_with_rand_reset"]
|
||||
}
|
||||
]
|
||||
|
|
|
@ -27,7 +27,8 @@
|
|||
- write a CSR with unaligned address, e.g. `a_address[1:0] != 0`
|
||||
- write a CSR less than its width, e.g. when CSR is 2 bytes wide, only write 1 byte
|
||||
- write a memory with `a_mask != '1` when it doesn't support partial accesses
|
||||
- read a WO (write-only) memory'''
|
||||
- read a WO (write-only) memory
|
||||
- write a RO (read-only) memory'''
|
||||
milestone: V2
|
||||
tests: ["{name}_tl_errors"]
|
||||
}
|
||||
|
@ -63,5 +64,30 @@
|
|||
tests: ["{name}_tl_intg_err"]
|
||||
}
|
||||
]
|
||||
covergroups: [
|
||||
{
|
||||
name: tl_errors_cg
|
||||
desc: '''Cover the following error cases on TL-UL bus:
|
||||
- TL-UL protocol error cases.
|
||||
- OpenTitan defined error cases, refer to testpoint `tl_d_illegal_access`.
|
||||
'''
|
||||
}
|
||||
{
|
||||
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.
|
||||
|
||||
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
|
||||
logic has been verfied.
|
||||
'''
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
build_mode: "cover_reg_top"
|
||||
run_opts: ["+csr_hw_reset"]
|
||||
en_run_modes: ["csr_tests_mode"]
|
||||
reseed: 5
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -29,6 +30,7 @@
|
|||
build_mode: "cover_reg_top"
|
||||
run_opts: ["+csr_rw"]
|
||||
en_run_modes: ["csr_tests_mode"]
|
||||
reseed: 20
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -36,6 +38,7 @@
|
|||
build_mode: "cover_reg_top"
|
||||
run_opts: ["+csr_bit_bash"]
|
||||
en_run_modes: ["csr_tests_mode"]
|
||||
reseed: 5
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -43,6 +46,7 @@
|
|||
build_mode: "cover_reg_top"
|
||||
run_opts: ["+csr_aliasing"]
|
||||
en_run_modes: ["csr_tests_mode"]
|
||||
reseed: 5
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -50,6 +54,7 @@
|
|||
build_mode: "cover_reg_top"
|
||||
run_opts: ["+run_same_csr_outstanding"]
|
||||
en_run_modes: ["csr_tests_mode"]
|
||||
reseed: 20
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -57,6 +62,7 @@
|
|||
build_mode: "cover_reg_top"
|
||||
run_opts: ["+run_csr_mem_rw_with_rand_reset", "+test_timeout_ns=10000000000"]
|
||||
en_run_modes: ["csr_tests_mode"]
|
||||
reseed: 20
|
||||
}
|
||||
]
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
name: mem_tests_mode
|
||||
uvm_test_seq: "{name}_common_vseq"
|
||||
run_opts: ["+en_scb=0"]
|
||||
reseed: 5
|
||||
}
|
||||
]
|
||||
|
||||
|
|
|
@ -21,9 +21,7 @@
|
|||
build_mode: "cover_reg_top"
|
||||
uvm_test_seq: "{name}_common_vseq"
|
||||
run_opts: ["+run_tl_intg_err", "+en_scb=0"]
|
||||
// TODO, lower the reseed to avoid having many failed tests in regression as not all the IPs
|
||||
// have the integrity alert connected
|
||||
reseed: 1
|
||||
reseed: 20
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
15
vendor/lowrisc_ip/dv/tools/dvsim/vcs.hjson
vendored
15
vendor/lowrisc_ip/dv/tools/dvsim/vcs.hjson
vendored
|
@ -6,7 +6,7 @@
|
|||
build_ex: "{build_dir}/simv"
|
||||
run_cmd: "{job_prefix} {build_ex}"
|
||||
|
||||
build_opts: ["-sverilog -full64 -licqueue -kdb -ntb_opts uvm-1.2",
|
||||
build_opts: ["-sverilog -full64 -licqueue -ntb_opts uvm-1.2",
|
||||
"-timescale=1ns/1ps",
|
||||
"-Mdir={build_ex}.csrc",
|
||||
"-o {build_ex}",
|
||||
|
@ -155,8 +155,10 @@
|
|||
"+urg+lic+wait",
|
||||
// Lists all the tests that covered a given object.
|
||||
"-show tests",
|
||||
// Enable test grading.
|
||||
"-grade index",
|
||||
// Enable test grading using the "index" scheme, and the
|
||||
// generation of the list of contributing tests with
|
||||
// "testfile".
|
||||
"-grade index testfile",
|
||||
// Use simple ratio of total covered bins over total bins across cps & crs,
|
||||
"-group ratio",
|
||||
// Compute overall coverage for per-instance covergroups individually rather
|
||||
|
@ -165,7 +167,8 @@
|
|||
"-dir {cov_merge_db_dir}",
|
||||
"-line nocasedef",
|
||||
"-format both",
|
||||
"-elfile {vcs_cov_excl_files}",
|
||||
// Prepend each el file with `-elfile`.
|
||||
"{eval_cmd} echo {vcs_cov_excl_files} | sed -E 's/(\\S+)/-elfile \\1/g'",
|
||||
"-report {cov_report_dir}"]
|
||||
cov_report_txt: "{cov_report_dir}/dashboard.txt"
|
||||
cov_report_page: "dashboard.html"
|
||||
|
@ -246,7 +249,9 @@
|
|||
{
|
||||
name: vcs_waves
|
||||
is_sim_mode: 1
|
||||
build_opts: ["-debug_access"]
|
||||
build_opts: [// Enable generating Verdi Knowledge Database
|
||||
"-kdb",
|
||||
"-debug_access"]
|
||||
}
|
||||
{
|
||||
name: vcs_cov
|
||||
|
|
25
vendor/lowrisc_ip/dv/tools/dvsim/xcelium.hjson
vendored
25
vendor/lowrisc_ip/dv/tools/dvsim/xcelium.hjson
vendored
|
@ -21,6 +21,9 @@
|
|||
"-snapshot {tb}",
|
||||
// for uvm_hdl_* used by csr backdoor
|
||||
"-access +rw",
|
||||
// This is to fix a timescale issue due to using `resetall to reset timescale and
|
||||
// `-sv` compile option. #7178
|
||||
"-enable_strict_timescale",
|
||||
// Use this to conditionally compile for Xcelium (example: LRM interpretations differ
|
||||
// across tools).
|
||||
"+define+XCELIUM",
|
||||
|
@ -76,8 +79,10 @@
|
|||
// Note that this needs to be set as -covfile <file>.
|
||||
xcelium_cov_cfg_file: ""
|
||||
|
||||
// Supply the cov refinement files.
|
||||
// Note that this needs to be set as -load_refinement <file>.
|
||||
// Supply the cov exclusion tcl script - passed on to IMC using the -init switch.
|
||||
xcelium_cov_excl_script: ""
|
||||
|
||||
// Supply the cov refinement files - passed on to IMC using the -load_refinement switch.
|
||||
xcelium_cov_refine_files: []
|
||||
|
||||
// Set the coverage directories.
|
||||
|
@ -103,8 +108,10 @@
|
|||
cov_report_cmd: "{job_prefix} imc"
|
||||
cov_report_opts: ["-64bit",
|
||||
"-licqueue",
|
||||
"-exec {dv_root}/tools/xcelium/cov_report.tcl",
|
||||
"{xcelium_cov_refine_files}"]
|
||||
"-load {cov_merge_db_dir}",
|
||||
" {eval_cmd} echo {xcelium_cov_excl_script} | sed -E 's/(\\S+)/-init \\1/g' ",
|
||||
" {eval_cmd} echo {xcelium_cov_refine_files} | sed -E 's/(\\S+)/-load_refinement \\1/g' ",
|
||||
"-exec {dv_root}/tools/xcelium/cov_report.tcl"]
|
||||
cov_report_txt: "{cov_report_dir}/cov_report.txt"
|
||||
cov_report_page: "index.html"
|
||||
|
||||
|
@ -112,11 +119,10 @@
|
|||
// GUI for visual analysis.
|
||||
cov_analyze_dir: "{scratch_path}/cov_analyze"
|
||||
cov_analyze_cmd: "{job_prefix} imc"
|
||||
cov_analyze_opts: ["-gui",
|
||||
"-64bit",
|
||||
cov_analyze_opts: ["-64bit",
|
||||
"-licqueue",
|
||||
"-load {cov_merge_db_dir}",
|
||||
"-init {xcelium_common_excl_file}",
|
||||
" {eval_cmd} echo {xcelium_cov_excl_script} | sed -E 's/(\\S+)/-init \\1/g' ",
|
||||
" {eval_cmd} echo {xcelium_cov_refine_files} | sed -E 's/(\\S+)/-load_refinement \\1/g' "]
|
||||
|
||||
cov_unr_dir: "{scratch_path}/cov_unr"
|
||||
|
@ -171,7 +177,10 @@
|
|||
// Limit the scope of coverage collection to the DUT.
|
||||
"-covdut {dut}",
|
||||
// Set the coverage configuration file
|
||||
"-covfile {xcelium_cov_cfg_file}"]
|
||||
"-covfile {xcelium_cov_cfg_file}",
|
||||
// Don't warn about the switches we set that will be default in future releases.
|
||||
"-nowarn COVDEF",
|
||||
]
|
||||
run_opts: [// Put the coverage model (*.ucm) and the database (*.ucd) together.
|
||||
"-covmodeldir {cov_db_test_dir}",
|
||||
// Coverage database output location.
|
||||
|
|
16
vendor/lowrisc_ip/dv/tools/vcs/common_cov_excl.cfg
vendored
Normal file
16
vendor/lowrisc_ip/dv/tools/vcs/common_cov_excl.cfg
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// [UNSUPPORTED] Based on our Comportable IP spec, these TL pins are reserved / unused and hence,
|
||||
// tied off.
|
||||
-node tb.dut *tl_i.a_user.rsvd
|
||||
-node tb.dut *tl_i.a_param
|
||||
// [UNR] design ties these outputs to zeros.
|
||||
-node tb.dut *tl_o.d_param
|
||||
-node tb.dut *tl_o.d_opcode[1]
|
||||
-node tb.dut *tl_o.d_opcode[2]
|
||||
-node tb.dut *tl_o.d_sink
|
||||
|
||||
// [LOW_RISK] Verified in prim_alert_receiver TB."
|
||||
-node tb.dut *alert_rx_*.ping_*
|
|
@ -1,16 +0,0 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Exclude below TL toggle coverage as these pins won't be changed in the comportable IPs.
|
||||
|
||||
// Exclude alert_sender as it is fully verified in FPV. Note that user might also need to exclude
|
||||
// prim_diff_decode module, but it is not listed here because modules other than prim_alert_sender
|
||||
// might instantiate this prim_diff_decode as well.
|
||||
|
||||
INSTANCE: tb.dut
|
||||
Toggle tl_o.d_opcode [1] "logic tl_o.d_opcode[2:0]"
|
||||
Toggle tl_o.d_opcode [2] "logic tl_o.d_opcode[2:0]"
|
||||
Toggle tl_o.d_param "logic tl_o.d_param[2:0]"
|
||||
Toggle tl_o.d_sink "logic tl_o.d_sink[0:0]"
|
||||
Toggle tl_i.a_param "logic tl_i.a_param[2:0]"
|
20
vendor/lowrisc_ip/dv/tools/vcs/cover.cfg
vendored
20
vendor/lowrisc_ip/dv/tools/vcs/cover.cfg
vendored
|
@ -8,7 +8,11 @@
|
|||
+tree tb.dut
|
||||
-module pins_if // DV construct.
|
||||
-module clk_rst_if // DV construct.
|
||||
-moduletree prim_alert_sender // prim_alert_sender is verified in FPV.
|
||||
// Prim_alert/esc pairs are verified in FPV and DV testbenches.
|
||||
-moduletree prim_alert_sender
|
||||
-moduletree prim_alert_receiver
|
||||
-moduletree prim_esc_sender
|
||||
-moduletree prim_esc_receiver
|
||||
-moduletree prim_prince // prim_prince is verified in a separate DV environment.
|
||||
-moduletree prim_lfsr // prim_lfsr is verified in FPV.
|
||||
|
||||
|
@ -16,6 +20,20 @@ begin tgl
|
|||
-tree tb
|
||||
+tree tb.dut 1
|
||||
+module prim_alert_sender
|
||||
+module prim_alert_receiver
|
||||
+module prim_esc_sender
|
||||
+module prim_esc_receiver
|
||||
+module prim_prince
|
||||
+module prim_lfsr
|
||||
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.
|
||||
// TODO: check these assertions in top-level or FPV.
|
||||
-assert PrimLcSyncCheckTransients_A
|
||||
-assert PrimLcSyncCheckTransients0_A
|
||||
-assert PrimLcSyncCheckTransients1_A
|
||||
end
|
||||
|
|
|
@ -8,7 +8,10 @@
|
|||
+moduletree *_reg_top
|
||||
+node tb.dut tl_*
|
||||
|
||||
// Remove everything else from toggle coverage.
|
||||
// Remove everything else from toggle coverage except:
|
||||
// - `prim_alert_sender`: the `alert_test` task under `cip_base_vseq` drives `alert_test_i` and
|
||||
// verifies `alert_rx/tx` handshake in each IP.
|
||||
begin tgl
|
||||
-tree tb
|
||||
+module prim_alert_sender
|
||||
end
|
||||
|
|
3
vendor/lowrisc_ip/dv/tools/vcs/unr.cfg
vendored
3
vendor/lowrisc_ip/dv/tools/vcs/unr.cfg
vendored
|
@ -13,9 +13,6 @@
|
|||
# Black box some of the modules
|
||||
# -blackBoxes -type design *
|
||||
|
||||
# Include common el file, so that it doesn't generate reviewed common exclusions
|
||||
-covEL $dv_root/tools/vcs/common_cov_excl.el
|
||||
|
||||
# Name of the generated exclusion file
|
||||
-save_exclusion $SCRATCH_PATH/cov_unr/unr_exclude.el
|
||||
|
||||
|
|
57
vendor/lowrisc_ip/dv/tools/xcelium/common.ccf
vendored
Normal file
57
vendor/lowrisc_ip/dv/tools/xcelium/common.ccf
vendored
Normal file
|
@ -0,0 +1,57 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Common coverage commands that apply to all DUTs.
|
||||
//
|
||||
// This coverge config file is provided by Xcelium and is located at:
|
||||
// ${XCELIUM_HOME}/tools/icc/include/all_coverage.ccf
|
||||
// Xcelium recommends including it, since it bundles together the common set of commands that enable
|
||||
// coverage collection on various design elements, that are otherwise turned off by default. We
|
||||
// maintain it locally with minor amends.
|
||||
|
||||
// Enables expression coverage of various Verilog operators.
|
||||
set_expr_coverable_operators -all -event_or
|
||||
|
||||
// Enables expression coverage of operators in various conditions and assignments.
|
||||
set_expr_coverable_statements -all
|
||||
|
||||
// Enables scoring of Verilog modules compiled with -v/-y or -libcell option but continues to
|
||||
// disable the scoring of Verilog modules defined with the 'celldefine compiler directive.
|
||||
set_libcell_scoring
|
||||
|
||||
// Enables scoring of block and expression coverage for functions and tasks defined directly inside
|
||||
// SystemVerilog packages.
|
||||
set_subprogram_scoring -svpackage
|
||||
|
||||
// Enables scoring of SystemVerilog continuous assignments, which is by disabled by default.
|
||||
set_assign_scoring
|
||||
|
||||
// Scores branches together with block coverage.
|
||||
set_branch_scoring
|
||||
|
||||
// Scores statements within a block.
|
||||
set_statement_scoring
|
||||
|
||||
// Enables expression coverage for expression containing structs (packed and unpacked).
|
||||
set_expr_scoring -struct
|
||||
|
||||
// Enables Toggle scoring and reporting of SystemVerilog enumerations and multidimensional static
|
||||
// arrays , vectors, packed union, modport and generate blocks.
|
||||
set_toggle_scoring -sv_enum enable_mda -sv_struct_with_enum -sv_modport -sv_mda 16 -sv_mda_of_struct -sv_generate -sv_packed_union
|
||||
|
||||
// Enables scoring of reset states and transitions for identified FSMs.
|
||||
set_fsm_reset_scoring
|
||||
|
||||
// Enables scoring of immediate assertions inside a class in a package and assertions inside AMS
|
||||
// modules.
|
||||
select_functional -ams_control -imm_asrt_class_package
|
||||
|
||||
// Improve the scoping and naming of covergroup instances.
|
||||
set_covergroup -new_instance_reporting
|
||||
|
||||
// Enable toggle coverage only on ports.
|
||||
set_toggle_portsonly
|
||||
|
||||
// Enable scoring of FSM arcs (state transitions).
|
||||
set_fsm_arc_scoring
|
9
vendor/lowrisc_ip/dv/tools/xcelium/common_cov_excl.tcl
vendored
Normal file
9
vendor/lowrisc_ip/dv/tools/xcelium/common_cov_excl.tcl
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
# Copyright lowRISC contributors.
|
||||
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
exclude -inst $::env(DUT_TOP) -toggle '*tl_i.a_user.rsvd' -comment "\[UNSUPPORTED\] Based on our Comportability Spec. Exercising this will result in assertion errors thrown."
|
||||
exclude -inst $::env(DUT_TOP) -toggle '*tl_i.a_param' -comment "\[UNSUPPORTED\] Based on our Comportability Spec. Exercising this will result in assertion errors thrown."
|
||||
exclude -inst $::env(DUT_TOP) -toggle '*tl_o.d_param' -comment "\[UNR\] Follows tl_i.a_param which is unsupported."
|
||||
exclude -inst $::env(DUT_TOP) -toggle '*tl_o.d_sink' -comment "\[UNR\] Based on our Comportability Spec."
|
||||
exclude -inst $::env(DUT_TOP) -toggle '*alert_rx_*.ping_*' -comment "\[LOW_RISK\] Verified in prim_alert_receiver TB."
|
|
@ -8,14 +8,14 @@
|
|||
# using the env var 'cov_db_dirs' (which is a space separated list of directories).
|
||||
# Append each of these directories with /* wildcard at the end to allow the tool to
|
||||
# find all available test databases.
|
||||
set cov_db_dirs_env [string trim $::env(cov_db_dirs) " \""]
|
||||
set cov_db_dirs_env [string trim $::env(cov_db_dirs) " \"'"]
|
||||
foreach i $cov_db_dirs_env { append cov_db_dirs "[string trim $i]/* "; }
|
||||
puts "Input coverage directories:\n$cov_db_dirs"
|
||||
|
||||
# Set the output directory for the merged database using the env var 'cov_merge_db_dir'.
|
||||
# The supplied env var may have quotes or spaces that needs to be trimmed.
|
||||
puts "Output directory for merged coverage:"
|
||||
set cov_merge_db_dir [string trim $::env(cov_merge_db_dir) " \""]
|
||||
set cov_merge_db_dir [string trim $::env(cov_merge_db_dir) " \"'"]
|
||||
|
||||
# Run the merge command.
|
||||
merge $cov_db_dirs -out $cov_merge_db_dir -overwrite
|
||||
|
|
|
@ -3,22 +3,18 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# Generate reports for the merged coverage in HTML and text format.
|
||||
|
||||
# Set the input merged coverage database directory using the env var 'cov_merge_db_dir'.
|
||||
# The supplied env var may have quotes or spaces that needs to be trimmed.
|
||||
set cov_merge_db_dir [string trim $::env(cov_merge_db_dir) " \""]
|
||||
#
|
||||
# This file is passed to IMC using the -exec switch. Ensure that the merged coverage database, the
|
||||
# exclusion script and the coverage refinement files are passed to the IMC invocation using the
|
||||
# -load, -init and -load_refinement switches respectively (whichever ones are applicable).
|
||||
|
||||
# Set the output directory for the reports database using the env var 'cov_report_dir'.
|
||||
# The supplied env var may have quotes or spaces that needs to be trimmed.
|
||||
set cov_report_dir [string trim $::env(cov_report_dir) " \""]
|
||||
set cov_report_dir [string trim $::env(cov_report_dir) " \"'"]
|
||||
|
||||
# Set the DUT name.
|
||||
set dut [string trim $::env(DUT_TOP)]
|
||||
set dut_uc [string toupper $dut]
|
||||
set dut_instance [string trim $::env(dut_instance)]
|
||||
|
||||
# Load the merged coverage database.
|
||||
load -run $cov_merge_db_dir
|
||||
|
||||
# Generate the text report (summary is sufficient).
|
||||
report -summary \
|
||||
|
@ -35,7 +31,6 @@ report -summary \
|
|||
-type \
|
||||
-all \
|
||||
-metrics covergroup \
|
||||
-kind abstract \
|
||||
-source off \
|
||||
-out $cov_report_dir/cov_report_cg.txt
|
||||
|
||||
|
|
26
vendor/lowrisc_ip/dv/tools/xcelium/cover.ccf
vendored
Normal file
26
vendor/lowrisc_ip/dv/tools/xcelium/cover.ccf
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Include our common coverage CCF.
|
||||
include_ccf ${dv_root}/tools/xcelium/common.ccf
|
||||
|
||||
// Black-box pre-verified IPs from coverage collection.
|
||||
deselect_coverage -betfs -module pins_if
|
||||
deselect_coverage -betfs -module clk_rst_if
|
||||
deselect_coverage -betfs -module prim_alert_sender...
|
||||
deselect_coverage -betfs -module prim_alert_receiver...
|
||||
deselect_coverage -betfs -module prim_esc_sender...
|
||||
deselect_coverage -betfs -module prim_esc_receiver...
|
||||
deselect_coverage -betfs -module prim_prince...
|
||||
deselect_coverage -betfs -module prim_lfsr...
|
||||
|
||||
// Only collect toggle coverage on the DUT and the black-boxed IP (above) ports.
|
||||
deselect_coverage -toggle -module ${DUT_TOP}...
|
||||
select_coverage -toggle -module ${DUT_TOP}
|
||||
select_coverage -toggle -module prim_alert_sender
|
||||
select_coverage -toggle -module prim_alert_receiver
|
||||
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
|
21
vendor/lowrisc_ip/dv/tools/xcelium/cover_reg_top.ccf
vendored
Normal file
21
vendor/lowrisc_ip/dv/tools/xcelium/cover_reg_top.ccf
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Include our common coverage CCF.
|
||||
include_ccf ${dv_root}/tools/xcelium/common.ccf
|
||||
|
||||
// Only collect code coverage on the *_reg_top instance.
|
||||
deselect_coverage -betfs -module ${DUT_TOP}...
|
||||
select_coverage -befs -module *_reg_top...
|
||||
|
||||
// Include toggle coverage on `prim_alert_sender` because the `alert_test` task under
|
||||
// `cip_base_vseq` drives `alert_test_i` and verifies `alert_rx/tx` handshake in each IP.
|
||||
select_coverage -toggle -module prim_alert_sender
|
||||
|
||||
// TODO: The intent below is to only enable coverage on the DUT's TL interfaces (tests using this
|
||||
// ccf file are meant to fully exercise the TL interfaces, but they do not verify the rest of the
|
||||
// functionality of the block). We enable coverage on all DUT ports but exclude ports that do not
|
||||
// contain tl_i or tl_o in the port name using a separate excludefile that supports regexes.
|
||||
select_coverage -toggle -module ${DUT_TOP}
|
||||
set_toggle_excludefile ${dv_root}/tools/xcelium/cover_reg_top_toggle_excl
|
7
vendor/lowrisc_ip/dv/tools/xcelium/cover_reg_top_toggle_excl
vendored
Normal file
7
vendor/lowrisc_ip/dv/tools/xcelium/cover_reg_top_toggle_excl
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Exclude all but the TL ports of the DUT.
|
||||
// TODO: This does not work.
|
||||
-ere module ^((?!tl_i$|tl_o$).)*$
|
11
vendor/lowrisc_ip/dv/tools/xcelium/exclude.tcl
vendored
11
vendor/lowrisc_ip/dv/tools/xcelium/exclude.tcl
vendored
|
@ -1,11 +0,0 @@
|
|||
# Copyright lowRISC contributors.
|
||||
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
exclude -inst $::env(DUT_TOP) -toggle 'tl_i.a_user.parity'
|
||||
exclude -inst $::env(DUT_TOP) -toggle 'tl_i.a_user.parity_en'
|
||||
exclude -inst $::env(DUT_TOP) -toggle 'tl_i.a_param'
|
||||
exclude -inst $::env(DUT_TOP) -toggle 'tl_o.d_param'
|
||||
exclude -inst $::env(DUT_TOP) -toggle 'tl_o.d_sink'
|
||||
exclude -inst $::env(DUT_TOP) -toggle 'tl_o.d_user'
|
||||
exclude -inst $::env(DUT_TOP) -toggle 'tl_i.a_user.rsvd1'
|
18
vendor/lowrisc_ip/dv/tools/xcelium/xcelium.ccf
vendored
18
vendor/lowrisc_ip/dv/tools/xcelium/xcelium.ccf
vendored
|
@ -1,18 +0,0 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// only collect toggle coverage on dut
|
||||
deselect_coverage -toggle -instance tb.dut.*...
|
||||
|
||||
// only collect toggle coverage on ports
|
||||
set_toggle_portsonly
|
||||
|
||||
// enable toggle scoring of structs and multidim arrays + MDA structs
|
||||
set_toggle_scoring -sv_mda -sv_mda_of_struct
|
||||
|
||||
// filter glitches
|
||||
set_toggle_strobe 0ps
|
||||
|
||||
// Filter unreachable/statically constant blocks
|
||||
set_com -log
|
|
@ -146,7 +146,7 @@ static std::vector<uint8_t> FlattenElfFile(const std::string &filepath) {
|
|||
continue;
|
||||
}
|
||||
|
||||
if (phdr.p_memsz == 0) {
|
||||
if (phdr.p_filesz == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -154,11 +154,11 @@ static std::vector<uint8_t> FlattenElfFile(const std::string &filepath) {
|
|||
low = phdr.p_paddr;
|
||||
}
|
||||
|
||||
Elf32_Addr seg_top = phdr.p_paddr + (phdr.p_memsz - 1);
|
||||
Elf32_Addr seg_top = phdr.p_paddr + (phdr.p_filesz - 1);
|
||||
if (seg_top < phdr.p_paddr) {
|
||||
std::ostringstream oss;
|
||||
oss << "phdr for segment " << i << " has start 0x" << std::hex
|
||||
<< phdr.p_paddr << " and size 0x" << phdr.p_memsz
|
||||
<< phdr.p_paddr << " and size 0x" << phdr.p_filesz
|
||||
<< ", which overflows the address space.";
|
||||
throw ElfError(filepath, oss.str());
|
||||
}
|
||||
|
@ -201,15 +201,12 @@ static std::vector<uint8_t> FlattenElfFile(const std::string &filepath) {
|
|||
throw ElfError(filepath, oss.str());
|
||||
}
|
||||
|
||||
uint32_t off = phdr.p_paddr - low;
|
||||
uint32_t dst_len = phdr.p_memsz;
|
||||
uint32_t src_len = std::min(phdr.p_filesz, dst_len);
|
||||
|
||||
if (!dst_len)
|
||||
if (phdr.p_filesz == 0)
|
||||
continue;
|
||||
|
||||
std::vector<uint8_t> seg(dst_len, 0);
|
||||
memcpy(&seg[0], file_data + phdr.p_offset, src_len);
|
||||
uint32_t off = phdr.p_paddr - low;
|
||||
std::vector<uint8_t> seg(phdr.p_filesz, 0);
|
||||
memcpy(&seg[0], file_data + phdr.p_offset, phdr.p_filesz);
|
||||
ret.AddSegment(off, std::move(seg));
|
||||
}
|
||||
|
||||
|
@ -473,11 +470,11 @@ void DpiMemUtil::StageElf(bool verbose, const std::string &path) {
|
|||
if (phdr.p_type != PT_LOAD)
|
||||
continue;
|
||||
|
||||
if (phdr.p_memsz == 0)
|
||||
if (phdr.p_filesz == 0)
|
||||
continue;
|
||||
|
||||
size_t mem_area_idx =
|
||||
GetRegionForSegment(path, i, phdr.p_paddr, phdr.p_memsz);
|
||||
GetRegionForSegment(path, i, phdr.p_paddr, phdr.p_filesz);
|
||||
|
||||
const MemArea &mem_area = *mem_areas_[mem_area_idx];
|
||||
uint32_t mem_area_base = base_addrs_[mem_area_idx];
|
||||
|
@ -518,8 +515,8 @@ void DpiMemUtil::StageElf(bool verbose, const std::string &path) {
|
|||
StagedMem &staged_mem = staging_area_[name];
|
||||
|
||||
const char *seg_data = file_data + phdr.p_offset;
|
||||
std::vector<uint8_t> vec(phdr.p_memsz, 0);
|
||||
memcpy(&vec[0], seg_data, std::min(phdr.p_filesz, phdr.p_memsz));
|
||||
std::vector<uint8_t> vec(phdr.p_filesz, 0);
|
||||
memcpy(&vec[0], seg_data, phdr.p_filesz);
|
||||
|
||||
staged_mem.AddSegment(local_base, std::move(vec));
|
||||
}
|
||||
|
|
|
@ -12,7 +12,11 @@
|
|||
// This is the maximum width of a memory that's supported by the code in
|
||||
// prim_util_memload.svh
|
||||
#define SV_MEM_WIDTH_BITS 312
|
||||
#define SV_MEM_WIDTH_BYTES ((SV_MEM_WIDTH_BITS + 7) / 8)
|
||||
|
||||
// This is the number of bytes to reserve for buffers used to pass data between
|
||||
// C++ and SystemVerilog using prim_util_memload.svh. Since this goes over DPI
|
||||
// using the svBitVecVal type, we have to round up to the next 32-bit word.
|
||||
#define SV_MEM_WIDTH_BYTES (4 * ((SV_MEM_WIDTH_BITS + 31) / 32))
|
||||
|
||||
/**
|
||||
* A "memory area", representing a memory in the simulated design.
|
||||
|
|
158
vendor/lowrisc_ip/ip/prim/data/prim_mubi_pkg.sv.tpl
vendored
Normal file
158
vendor/lowrisc_ip/ip/prim/data/prim_mubi_pkg.sv.tpl
vendored
Normal file
|
@ -0,0 +1,158 @@
|
|||
// 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
|
125
vendor/lowrisc_ip/ip/prim/doc/prim_ram_1p_scr.md
vendored
Normal file
125
vendor/lowrisc_ip/ip/prim/doc/prim_ram_1p_scr.md
vendored
Normal file
|
@ -0,0 +1,125 @@
|
|||
---
|
||||
title: "Primitive Component: SRAM Scrambler"
|
||||
---
|
||||
|
||||
# Overview
|
||||
|
||||
The scrambling primitive `prim_ram_1p_scr` employs a reduced-round (5 instead of 11) PRINCE block cipher in CTR mode to scramble the data.
|
||||
The PRINCE lightweight block cipher has been selected due to its low latency and low area characteristics, see also [prim_prince]({{< relref "hw/ip/prim/doc/prim_prince" >}}) for more information on PRINCE.
|
||||
The number of rounds is reduced to 5 in order to ease timing pressure and ensure single cycle operation (the number of rounds can always be increased if it turns out that there is enough timing slack).
|
||||
|
||||
In [CTR mode](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Counter_(CTR)), the block cipher is used to encrypt a 64bit IV with the scrambling key in order to create a 64bit keystream block that is bitwise XOR'ed with the data in order to transform plaintext into ciphertext and vice versa.
|
||||
The IV is assembled by concatenating a nonce with the word address.
|
||||
|
||||
If the word width of the scrambled memory is smaller than 64bit, the keystream block is truncated to fit the data width.
|
||||
If the word width is wider than 64bit, the scrambling primitive by default instantiates multiple PRINCE primitives in order to create a unique keystream for the full datawidth.
|
||||
For area constrained settings, the parameter `ReplicateKeyStream` in `prim_ram_1p_scr` can be set to 1 in order to replicate the keystream block generated by one single primitive instead of using multiple parallel PRINCE instances (but it should be understood that this lowers the level of security).
|
||||
|
||||
Since plain CTR mode does not diffuse the data bits due to the bitwise XOR, the scheme is augmented by passing each individual word through a two-layer substitution-permutation (S&P) network implemented with the `prim_subst_perm` primitive (the diffusion chunk width can be parameterized via the `DiffWidth` parameter).
|
||||
The S&P network employed is similar to the one employed in PRESENT and will be explained in more detail [further below]({{< relref "#custom-substitution-permutation-network" >}}).
|
||||
Note that if individual bytes need to be writable without having to perform a read-modify-write operation, the diffusion chunk width should be set to 8.
|
||||
|
||||
Another CTR mode augmentation that is aimed at breaking the linear address space is SRAM address scrambling.
|
||||
The same two-layer S&P network that is used for byte diffusion is leveraged to non-linearly remap the SRAM address as shown in the block diagram above.
|
||||
As opposed to the byte diffusion S&P networks, this particular address scrambling network additionally XOR's in a nonce that has the same width as the address.
|
||||
|
||||
## Parameters
|
||||
|
||||
The following table lists the instantiation parameters of the `prim_ram_1p_scr` primitive.
|
||||
These are not exposed in the `sram_ctrl` IP, but have to be set directly when instantiating `prim_ram_1p_scr` in the top.
|
||||
|
||||
Parameter | Default (Max) | Top Earlgrey | Description
|
||||
----------------------------|-----------------------|--------------|---------------
|
||||
`Depth` | 512 | multiple | SRAM depth, needs to be a power of 2 if `NumAddrScrRounds` > 0.
|
||||
`Width` | 32 | 32 | Effective SRAM width without redundancy.
|
||||
`DataBitsPerMask` | 8 | 8 | Number of data bits per write mask.
|
||||
`EnableParity` | 1 | 1 | This parameter enables byte parity.
|
||||
`CfgWidth` | 8 | 8 | Width of SRAM attributes field.
|
||||
`NumPrinceRoundsHalf` | 2 (5) | 2 | Number of PRINCE half-rounds.
|
||||
`NumDiffRounds` | 2 | 2 | Number of additional diffusion rounds, set to 0 to disable.
|
||||
`DiffWidth` | 8 | 8 | Width of additional diffusion rounds, set to 8 for intra-byte diffusion.
|
||||
`NumAddrScrRounds` | 2 | 2 | Number of address scrambling rounds, set to 0 to disable.
|
||||
`ReplicateKeyStream` | 0 (1) | 0 | If set to 1, the same 64bit key stream is replicated if the data port is wider than 64bit. Otherwise, multiple PRINCE primitives are employed to generate a unique keystream for the full data width.
|
||||
|
||||
## Signal Interfaces
|
||||
|
||||
Signal | Direction | Type | Description
|
||||
---------------------------|------------------|------------------------------------|---------------
|
||||
`key_valid_i` | `input` | `logic` | Indicates whether the key and nonce are considered valid. New memory requests are blocked if this is set to 0.
|
||||
`key_i` | `input` | `logic [127:0]` | Scrambling key.
|
||||
`nonce_i` | `input` | `logic [NonceWidth-1:0]` | Scrambling nonce.
|
||||
`req_i` | `input` | `logic` | Memory request indication signal (from TL-UL SRAM adapter).
|
||||
`gnt_o` | `output` | `logic` | Grant signal for memory request (to TL-UL SRAM adapter)
|
||||
`write_i` | `input` | `logic` | Indicates that this is a write operation (from TL-UL SRAM adapter).
|
||||
`addr_i` | `input` | `logic [AddrWidth-1:0]` | Address for memory op (from TL-UL SRAM adapter).
|
||||
`wdata_i` | `input` | `logic [Width-1:0]` | Write data (from TL-UL SRAM adapter).
|
||||
`wmask_i` | `input` | `logic [Width-1:0]` | Write mask (from TL-UL SRAM adapter).
|
||||
`intg_error_i` | `input` | `logic` | Indicates whether the incoming transaction has an integrity error
|
||||
`rdata_o` | `output` | `logic [Width-1:0]` | Read data output (to TL-UL SRAM adapter).
|
||||
`rvalid_o` | `output` | `logic` | Read data valid indication (to TL-UL SRAM adapter).
|
||||
`rerror_o` | `output` | `logic [1:0]` | Error indication (to TL-UL SRAM adapter). Bit 0 indicates a correctable and bit 1 an uncorrectable error. Note that at this time, only uncorrectable errors are reported, since the scrambling device only supports byte parity.
|
||||
`raddr_o` | `output` | `logic [31:0]` | Address of the faulty read operation.
|
||||
`cfg_i` | `input` | `logic [CfgWidth-1:0]` | Attributes for physical memory macro.
|
||||
|
||||
## Custom Substitution Permutation Network
|
||||
|
||||
In addition to the PRINCE primitive, `prim_ram_1p_scr` employs a custom S&P network for byte diffusion and address scrambling.
|
||||
The structure of that S&P network is similar to the one used in PRESENT, but it uses a modified permutation function that makes it possible to parameterize the network to arbitrary data widths as shown in the pseudo code below.
|
||||
|
||||
```c++
|
||||
|
||||
NUM_ROUNDS = 2;
|
||||
DATA_WIDTH = 8; // bitwidth of the data
|
||||
|
||||
// Apply PRESENT Sbox4 on all nibbles, leave uppermost bits unchanged
|
||||
// if the width is not divisible by 4.
|
||||
state_t sbox4_layer(state) {
|
||||
for (int i = 0; i < DATA_WIDTH/4; i ++) {
|
||||
nibble_t nibble = get_nibble(state, i);
|
||||
nibble = present_sbox4(nibble)
|
||||
set_nibble(state, i, nibble);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
// Reverses the bit order.
|
||||
state_t flip_vector(state) {
|
||||
state_t state_flipped;
|
||||
for (int i = 0; i < DATA_WIDTH; i ++) {
|
||||
state_flipped[i] = state[width-1-i];
|
||||
}
|
||||
return state_flipped;
|
||||
}
|
||||
|
||||
// Gather all even bits and put them into the lower half.
|
||||
// Gather all odd bits and put them into the upper half.
|
||||
state_t perm_layer(state) {
|
||||
// Initialize with input state.
|
||||
// If the number of bits is odd, the uppermost bit
|
||||
// will stay in position, as intended.
|
||||
state_t state_perm = state;
|
||||
for (int i = 0; i < DATA_WIDTH/2; i++) {
|
||||
state_perm[i] = state[i * 2];
|
||||
state_perm[i + DATA_WIDTH/2] = state[i * 2 + 1];
|
||||
}
|
||||
return state_perm;
|
||||
}
|
||||
|
||||
state_t prim_subst_perm(data_i, key_i) {
|
||||
|
||||
state_t state = data_i;
|
||||
for (int i = 0; i < NUM_ROUNDS; i++) {
|
||||
state ^= key_i;
|
||||
state = sbox4_layer(state);
|
||||
// The vector flip and permutation operations have the
|
||||
// combined effect that all bits will be passed through an
|
||||
// Sbox4 eventually, even if the number of bits in data_i
|
||||
// is not aligned with 4.
|
||||
state = flip_vector(state);
|
||||
state = perm_layer(state);
|
||||
}
|
||||
|
||||
return state ^ key_i;
|
||||
}
|
||||
|
||||
```
|
10
vendor/lowrisc_ip/ip/prim/dv/prim_alert/data/prim_alert_cover.cfg
vendored
Normal file
10
vendor/lowrisc_ip/ip/prim/dv/prim_alert/data/prim_alert_cover.cfg
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
+module prim_alert_sender
|
||||
+module prim_alert_receiver
|
||||
begin tgl(portsonly)
|
||||
+module prim_alert_sender
|
||||
+module prim_alert_receiver
|
||||
end
|
76
vendor/lowrisc_ip/ip/prim/dv/prim_alert/data/prim_alert_testplan.hjson
vendored
Normal file
76
vendor/lowrisc_ip/ip/prim/dv/prim_alert/data/prim_alert_testplan.hjson
vendored
Normal file
|
@ -0,0 +1,76 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
{
|
||||
name: "prim_alert"
|
||||
testpoints: [
|
||||
{
|
||||
name: prim_alert_request_test
|
||||
desc: '''Verify alert request from prim_alert_sender.
|
||||
|
||||
- Send an alert request by driving `alert_req` pin to 1.
|
||||
- Verify that `alert_ack` signal is set and the alert handshake completes.
|
||||
- If the alert is fatal, verify if the alert continuous fires until a reset is
|
||||
issued.
|
||||
'''
|
||||
milestone: V1
|
||||
tests: ["prim_async_alert",
|
||||
"prim_async_fatal_alert",
|
||||
"prim_sync_alert",
|
||||
"prim_sync_fatal_alert"]
|
||||
}
|
||||
|
||||
{
|
||||
name: prim_alert_test
|
||||
desc: '''Verify alert test request from prim_alert_sender.
|
||||
|
||||
- Send an alert test request by driving `alert_test` pin to 1.
|
||||
- Verify that alert handshake completes and `alert_ack` signal stays low.
|
||||
'''
|
||||
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.
|
||||
|
||||
- Send a ping request by driving `ping_req` pin to 1.
|
||||
- Verify that `ping_ok` signal is set and ping handshake completes.
|
||||
Because ping reqeust is level trigger, in order to cover toggle coverage for
|
||||
`alert_tx.ping_p/n` the above sequence will run twice.
|
||||
'''
|
||||
milestone: V1
|
||||
tests: ["prim_async_alert",
|
||||
"prim_async_fatal_alert",
|
||||
"prim_sync_alert",
|
||||
"prim_sync_fatal_alert"]
|
||||
}
|
||||
|
||||
{
|
||||
name: prim_alert_integrity_errors_test
|
||||
desc: '''Verify the integrity errors from the prim_alert_sender and prim_alert_receiver pair.
|
||||
|
||||
1). `Ack_p/n` integrity error:
|
||||
- Send an alert reqeust by driving `alert_req` pin to 1.
|
||||
- Force `ack_p` signal to stay low to trigger an integrity error.
|
||||
- Verify that prim_alert_receiver can identify the integrity error by setting
|
||||
`integ_fail_o` output to 1.
|
||||
2). `Ping_p/n` integrity error:
|
||||
- Send a ping request by driving `ping_req` to 1.
|
||||
- Force `ping_n` signal to 1 to trigger an integrity error.
|
||||
- Verify that prim_alert_receiver can identify the integrity error by setting
|
||||
`integ_fail_o` output to 1.
|
||||
'''
|
||||
milestone: V1
|
||||
tests: ["prim_async_alert",
|
||||
"prim_async_fatal_alert",
|
||||
"prim_sync_alert",
|
||||
"prim_sync_fatal_alert"]
|
||||
}
|
||||
|
||||
]
|
||||
}
|
32
vendor/lowrisc_ip/ip/prim/dv/prim_alert/prim_alert_sim.core
vendored
Normal file
32
vendor/lowrisc_ip/ip/prim/dv/prim_alert/prim_alert_sim.core
vendored
Normal file
|
@ -0,0 +1,32 @@
|
|||
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:prim_alert_sim:0.1"
|
||||
description: "ALERT DV sim target"
|
||||
filesets:
|
||||
files_rtl:
|
||||
depend:
|
||||
- lowrisc:prim:alert
|
||||
file_type: systemVerilogSource
|
||||
|
||||
files_dv:
|
||||
depend:
|
||||
- lowrisc:dv:dv_utils
|
||||
- lowrisc:dv:dv_test_status
|
||||
- lowrisc:dv:common_ifs
|
||||
files:
|
||||
- tb/prim_alert_tb.sv
|
||||
file_type: systemVerilogSource
|
||||
|
||||
targets:
|
||||
sim: &sim_target
|
||||
toplevel: prim_alert_tb
|
||||
filesets:
|
||||
- files_rtl
|
||||
- files_dv
|
||||
default_tool: vcs
|
||||
|
||||
lint:
|
||||
<<: *sim_target
|
||||
|
75
vendor/lowrisc_ip/ip/prim/dv/prim_alert/prim_alert_sim_cfg.hjson
vendored
Normal file
75
vendor/lowrisc_ip/ip/prim/dv/prim_alert/prim_alert_sim_cfg.hjson
vendored
Normal file
|
@ -0,0 +1,75 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
{
|
||||
// Name of the sim cfg - typically same as the name of the DUT.
|
||||
name: prim_alert
|
||||
|
||||
// Top level dut name (sv module).
|
||||
dut: prim_alert
|
||||
|
||||
// Top level testbench name (sv module).
|
||||
tb: prim_alert_tb
|
||||
|
||||
// Simulator used to sign off this block
|
||||
tool: vcs
|
||||
|
||||
// Fusesoc core file used for building the file list.
|
||||
fusesoc_core: lowrisc:dv:prim_alert_sim:0.1
|
||||
|
||||
// Testplan hjson file.
|
||||
testplan: "{proj_root}/hw/ip/prim/dv/prim_alert/data/prim_alert_testplan.hjson"
|
||||
|
||||
// Import additional common sim cfg files.
|
||||
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
|
||||
|
||||
build_modes: [
|
||||
{
|
||||
name: sync_alert
|
||||
build_opts: ["+define+IS_SYNC"]
|
||||
}
|
||||
{
|
||||
name: fatal_alert
|
||||
build_opts: ["+define+IS_FATAL"]
|
||||
}
|
||||
{
|
||||
name: sync_fatal_alert
|
||||
build_opts: ["+define+IS_FATAL", "+define+IS_SYNC"]
|
||||
}
|
||||
]
|
||||
|
||||
// List of test specifications.
|
||||
tests: [
|
||||
{
|
||||
name: prim_async_alert
|
||||
}
|
||||
{
|
||||
name: prim_async_fatal_alert
|
||||
build_mode: fatal_alert
|
||||
}
|
||||
{
|
||||
name: prim_sync_alert
|
||||
build_mode: sync_alert
|
||||
}
|
||||
{
|
||||
name: prim_sync_fatal_alert
|
||||
build_mode: sync_fatal_alert
|
||||
}
|
||||
]
|
||||
// List of regressions.
|
||||
regressions: [
|
||||
{
|
||||
name: smoke
|
||||
tests: ["prim_async_alert"]
|
||||
}
|
||||
]
|
||||
overrides: [
|
||||
{
|
||||
name: vcs_cov_cfg_file
|
||||
value: "-cm_hier {proj_root}/hw/ip/prim/dv/prim_alert/data/prim_alert_cover.cfg"
|
||||
}
|
||||
]
|
||||
}
|
320
vendor/lowrisc_ip/ip/prim/dv/prim_alert/tb/prim_alert_tb.sv
vendored
Normal file
320
vendor/lowrisc_ip/ip/prim/dv/prim_alert/tb/prim_alert_tb.sv
vendored
Normal file
|
@ -0,0 +1,320 @@
|
|||
// 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_alert_sender and prim_alert_receiver pair.
|
||||
//
|
||||
// This direct test has five test sequences:
|
||||
// 1). Alert request sequence.
|
||||
// 2). Alert test sequence.
|
||||
// 3). Ping request sequence.
|
||||
// 4). `Ack_p/n` integrity check sequence.
|
||||
// 5). `Ping_p/n` integrity check sequence.
|
||||
//
|
||||
// This direct sequence did not drive `ack_p/n` to trigger integrity error because this sequence is
|
||||
// covered in alert_handler IP level test.
|
||||
|
||||
module prim_alert_tb;
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// config
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
// this can be overriden on the command line
|
||||
`ifdef IS_SYNC
|
||||
localparam bit IsAsync = 0;
|
||||
`else
|
||||
localparam bit IsAsync = 1;
|
||||
`endif
|
||||
`ifdef IS_FATAL
|
||||
localparam bit IsFatal = 1;
|
||||
`else
|
||||
localparam bit IsFatal = 0;
|
||||
`endif
|
||||
|
||||
localparam time ClkPeriod = 10000;
|
||||
localparam int WaitCycle = IsAsync ? 3 : 1;
|
||||
|
||||
// Minimal cycles to wait between each sequence.
|
||||
// The main concern here is the minimal wait cycles between each handshake.
|
||||
localparam int MinHandshakeWait = 2 + WaitCycle;
|
||||
|
||||
typedef enum bit [3:0]{
|
||||
AlertSet,
|
||||
AlertAckSet,
|
||||
AlertReset,
|
||||
AlertAckReset
|
||||
} alert_handshake_e;
|
||||
|
||||
typedef enum bit[1:0] {
|
||||
PingPair,
|
||||
AlertPair,
|
||||
AckPair
|
||||
} alert_signal_pair_e;
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// Clock and Reset
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
wire clk, rst_n;
|
||||
|
||||
clk_rst_if main_clk (
|
||||
.clk,
|
||||
.rst_n
|
||||
);
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// DUTs
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
logic alert_test, alert_req, alert_ack, alert_state;
|
||||
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_alert_sender #(
|
||||
.AsyncOn(IsAsync),
|
||||
.IsFatal(IsFatal)
|
||||
) i_alert_sender (
|
||||
.clk_i(clk),
|
||||
.rst_ni(rst_n),
|
||||
.alert_test_i(alert_test),
|
||||
.alert_req_i(alert_req),
|
||||
.alert_ack_o(alert_ack),
|
||||
.alert_state_o(alert_state),
|
||||
.alert_rx_i(alert_rx),
|
||||
.alert_tx_o(alert_tx)
|
||||
);
|
||||
|
||||
prim_alert_receiver #(
|
||||
.AsyncOn(IsAsync)
|
||||
) i_alert_receiver (
|
||||
.clk_i(clk),
|
||||
.rst_ni(rst_n),
|
||||
// TODO: randomly trigger this
|
||||
.init_trig_i(lc_ctrl_pkg::Off),
|
||||
.ping_req_i(ping_req),
|
||||
.ping_ok_o(ping_ok),
|
||||
.integ_fail_o(integ_fail),
|
||||
.alert_o(alert_o),
|
||||
.alert_rx_o(alert_rx),
|
||||
.alert_tx_i(alert_tx)
|
||||
);
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// Helper Functions/Tasks and Variables
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
logic error = 0;
|
||||
|
||||
// `Alert`, `Ack`, and `Ping` are all differential signal pairs with postfix `_p` and `_n`.
|
||||
function automatic void check_diff_pair(bit exp_p, alert_signal_pair_e signal_pair);
|
||||
bit exp_n = ~exp_p;
|
||||
bit act_p, act_n;
|
||||
string err_msg;
|
||||
|
||||
case (signal_pair)
|
||||
PingPair: begin
|
||||
act_p = alert_rx.ping_p;
|
||||
act_n = alert_rx.ping_n;
|
||||
err_msg = "alert_rx.ping mismatch";
|
||||
end
|
||||
AlertPair: begin
|
||||
act_p = alert_tx.alert_p;
|
||||
act_n = alert_tx.alert_n;
|
||||
err_msg = "alert_tx.alert mismatch";
|
||||
end
|
||||
AckPair: begin
|
||||
act_p = alert_rx.ack_p;
|
||||
act_n = alert_rx.ack_n;
|
||||
err_msg = "alert_rx.ack mismatch";
|
||||
end
|
||||
default: begin
|
||||
$error($sformatf("Invalid signal_pair value %0d", signal_pair));
|
||||
error = 1;
|
||||
end
|
||||
endcase
|
||||
|
||||
if (exp_p != act_p) begin
|
||||
error = 1;
|
||||
$error($sformatf("%0s: exp_p=%0d act_p=%0d", err_msg, exp_p, act_p));
|
||||
end
|
||||
if (exp_n != act_n) begin
|
||||
error = 1;
|
||||
$error($sformatf("%0s: exp_n=%0d act_n=%0d", err_msg, exp_n, act_n));
|
||||
end
|
||||
endfunction
|
||||
|
||||
// Check `alert`, `ack`, and `ping` differential pairs with given alert_handshake stage and
|
||||
// expected ping value.
|
||||
function automatic void check_alert_rxtx(alert_handshake_e alert_handshake, bit exp_ping);
|
||||
case (alert_handshake)
|
||||
AlertSet: begin
|
||||
check_diff_pair(1, AlertPair);
|
||||
check_diff_pair(0, AckPair);
|
||||
end
|
||||
AlertAckSet: begin
|
||||
check_diff_pair(1, AlertPair);
|
||||
check_diff_pair(1, AckPair);
|
||||
end
|
||||
AlertReset: begin
|
||||
check_diff_pair(0, AlertPair);
|
||||
check_diff_pair(1, AckPair);
|
||||
end
|
||||
AlertAckReset: begin
|
||||
check_diff_pair(0, AlertPair);
|
||||
check_diff_pair(0, AckPair);
|
||||
end
|
||||
default: begin
|
||||
$error($sformatf("Invalid alert_handshake value %0d", alert_handshake));
|
||||
error = 1;
|
||||
end
|
||||
endcase
|
||||
check_diff_pair(exp_ping, PingPair);
|
||||
endfunction
|
||||
|
||||
// Verify the alert handshake protocol with the following pattern:
|
||||
// 1). alert_p = 1, alert_n = 0;
|
||||
// 2). ack_p = 1, ack_n = 0;
|
||||
// 3). ack_p = 0, ack_n = 1;
|
||||
// 4). alert_p = 0, alert_n = 1;
|
||||
// There is a fixed cycles of delay between each sequence depending on if the alert is sync or
|
||||
// async mode.
|
||||
task automatic check_alert_handshake(bit exp_ping_value);
|
||||
check_alert_rxtx(AlertSet, exp_ping_value);
|
||||
main_clk.wait_clks(WaitCycle);
|
||||
check_alert_rxtx(AlertAckSet, exp_ping_value);
|
||||
main_clk.wait_clks(WaitCycle);
|
||||
check_alert_rxtx(AlertReset, exp_ping_value);
|
||||
main_clk.wait_clks(WaitCycle);
|
||||
check_alert_rxtx(AlertAckReset, exp_ping_value);
|
||||
endtask
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// Stimuli Application / Response Checking
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
initial begin: p_stimuli
|
||||
alert_test = 0;
|
||||
alert_req = 0;
|
||||
ping_req = 0;
|
||||
main_clk.set_period_ps(ClkPeriod);
|
||||
main_clk.set_active();
|
||||
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);
|
||||
|
||||
// Sequence 1). Alert request sequence.
|
||||
main_clk.wait_clks($urandom_range(0, 10));
|
||||
alert_req = 1;
|
||||
fork
|
||||
begin
|
||||
main_clk.wait_clks(1);
|
||||
check_alert_handshake(.exp_ping_value(0));
|
||||
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();
|
||||
end
|
||||
$display("Alert request sequence finished!");
|
||||
|
||||
// Sequence 2). Alert test sequence.
|
||||
main_clk.wait_clks($urandom_range(MinHandshakeWait, 10));
|
||||
alert_test = 1;
|
||||
fork : isolation_fork
|
||||
begin: isolation_fork
|
||||
fork
|
||||
begin
|
||||
main_clk.wait_clks(1);
|
||||
alert_test = 0;
|
||||
check_alert_handshake(.exp_ping_value(0));
|
||||
// wait random clocks to ensure alert_ack is not set after alert handshake finishes.
|
||||
main_clk.wait_clks($urandom_range(10, 20));
|
||||
end
|
||||
forever begin
|
||||
main_clk.wait_clks(1);
|
||||
if (alert_ack == 1) begin
|
||||
$error("Alert ack should not set high during alert_test sequence!");
|
||||
error = 1;
|
||||
end
|
||||
end
|
||||
join_any
|
||||
disable fork;
|
||||
end
|
||||
join
|
||||
$display("Alert test sequence finished!");
|
||||
|
||||
// Sequence 3) Ping request sequence.
|
||||
// Loop the ping request twice to cover the alert_rx.ping_p/n toggle coverage.
|
||||
for (int i = 0; i < 2; i++) begin
|
||||
// Ping is level triggered, so the two exp_ping value should be 1 and 0.
|
||||
automatic bit exp_ping = (i == 0);
|
||||
main_clk.wait_clks($urandom_range(MinHandshakeWait, 10));
|
||||
ping_req = 1;
|
||||
fork
|
||||
begin
|
||||
main_clk.wait_clks(1);
|
||||
check_diff_pair(exp_ping, PingPair);
|
||||
main_clk.wait_clks(WaitCycle);
|
||||
check_alert_handshake(.exp_ping_value(exp_ping));
|
||||
end
|
||||
begin
|
||||
wait (ping_ok == 1);
|
||||
ping_req = 0;
|
||||
end
|
||||
join
|
||||
$display($sformatf("Ping request sequence[%0d] finished!", i));
|
||||
end
|
||||
|
||||
// Sequence 4) `Ack_p/n` integrity check sequence.
|
||||
// Note that alert_tx signal interigy errors are verified in alert_handler testbench.
|
||||
main_clk.wait_clks($urandom_range(MinHandshakeWait, 10));
|
||||
alert_req = 1;
|
||||
|
||||
$assertoff(0, prim_alert_tb.i_alert_receiver.AckDiffOk_A);
|
||||
force i_alert_receiver.alert_rx_o.ack_p = 0;
|
||||
wait (integ_fail == 1);
|
||||
alert_req = 0;
|
||||
release i_alert_receiver.alert_rx_o.ack_p;
|
||||
|
||||
// Wait until async or sync signal propogate from alert to ack.
|
||||
main_clk.wait_clks(WaitCycle);
|
||||
$asserton(0, prim_alert_tb.i_alert_receiver.AckDiffOk_A);
|
||||
$display("Ack signal integrity error sequence finished!");
|
||||
|
||||
// Sequence 5) `Ping_p/n` integrity check sequence.
|
||||
// Disable the assertion at least two clock cycles before sending the ping request, because the
|
||||
// `PingDiffOk_A` assertion has ##2 delay.
|
||||
$assertoff(2, prim_alert_tb.i_alert_receiver.PingDiffOk_A);
|
||||
main_clk.wait_clks($urandom_range(MinHandshakeWait, 10));
|
||||
ping_req = 1;
|
||||
|
||||
force i_alert_receiver.alert_rx_o.ping_n = 1;
|
||||
wait (integ_fail == 1);
|
||||
ping_req = 0;
|
||||
release i_alert_receiver.alert_rx_o.ping_p;
|
||||
|
||||
// Ping is the first signal of the handshake, so we can directly turn on the assertion once the
|
||||
// forced ping signal is released.
|
||||
$asserton(0, prim_alert_tb.i_alert_receiver.PingDiffOk_A);
|
||||
$display("Ping signal integrity error sequence finished!");
|
||||
|
||||
dv_test_status_pkg::dv_test_status(.passed(!error));
|
||||
$finish();
|
||||
end
|
||||
endmodule
|
10
vendor/lowrisc_ip/ip/prim/dv/prim_esc/data/prim_esc_cover.cfg
vendored
Normal file
10
vendor/lowrisc_ip/ip/prim/dv/prim_esc/data/prim_esc_cover.cfg
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
+module prim_esc_sender
|
||||
+module prim_esc_receiver
|
||||
begin tgl(portsonly)
|
||||
+module prim_esc_sender
|
||||
+module prim_esc_receiver
|
||||
end
|
91
vendor/lowrisc_ip/ip/prim/dv/prim_esc/data/prim_esc_testplan.hjson
vendored
Normal file
91
vendor/lowrisc_ip/ip/prim/dv/prim_esc/data/prim_esc_testplan.hjson
vendored
Normal file
|
@ -0,0 +1,91 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
{
|
||||
name: "prim_esc"
|
||||
testpoints: [
|
||||
{
|
||||
name: prim_esc_request_test
|
||||
desc: '''Verify escalation request from prim_esc_sender.
|
||||
|
||||
- Send an escalation request by driving `esc_req` pin to 1.
|
||||
- Wait random length of cycles and verify `esc_en` output is set and `integ_fail`
|
||||
output remains 0.
|
||||
'''
|
||||
milestone: V1
|
||||
tests: ["prim_esc_test"]
|
||||
}
|
||||
|
||||
{
|
||||
name: prim_ping_req_interrupted_by_esc_req_test
|
||||
desc: '''Verify prim_esc will process the esc_req when ping handshake is in progress.
|
||||
|
||||
- Send a ping request by driving `ping_req` pin to 1.
|
||||
- Randomly wait a few cycles before the ping handshake is completed.
|
||||
- Send an escalation request by driving `esc_req` pin to 1.
|
||||
- Wait for `ping_ok` to set and `esc_req_out` to set.
|
||||
- Check the sequence completes without any signal integrity error.
|
||||
'''
|
||||
milestone: V1
|
||||
tests: ["prim_esc_test"]
|
||||
}
|
||||
|
||||
{
|
||||
name: prim_esc_tx_integrity_errors_test
|
||||
desc: '''Verify `esc_tx` signal integrity error.
|
||||
|
||||
- Send an escalation request by driving `esc_req` pin to 1.
|
||||
- Force `esc_n` signal to stay high to trigger an integrity error.
|
||||
- Verify that prim_esc_sender identifies the error by setting `integ_fail` signal.
|
||||
- Release the `esc_n` signal.
|
||||
- Send a ping request and repeat the above sequence and checkings.
|
||||
'''
|
||||
milestone: V1
|
||||
tests: ["prim_esc_test"]
|
||||
}
|
||||
|
||||
{
|
||||
name: prim_esc_reverse_ping_timeout_test
|
||||
desc: '''Verify prim_esc_receiver detects ping timeout.
|
||||
|
||||
- Send a ping request by driving `ping_req` pin to 1.
|
||||
- Wait for ping handshake to finish and `ping_ok` signal is set.
|
||||
- Verify that `esc_en` output remains 0 and `integ_fail` output remains 0.
|
||||
- Drive `ping_req` signal back to 0 and wait until ping counter timeout.
|
||||
- Verify that `prim_esc_receiver` detects the ping timeout by setting `esc_en` output
|
||||
to 1.
|
||||
- Reset the DUT to clear `esc_en` output.
|
||||
'''
|
||||
milestone: V1
|
||||
tests: ["prim_esc_test"]
|
||||
}
|
||||
|
||||
{
|
||||
name: prim_esc_receiver_counter_fail_test
|
||||
desc: '''Verify prim_esc_receiver detects counter mismatch.
|
||||
|
||||
- Send a ping request by driving `ping_req` pin to 1.
|
||||
- Wait until `ping_ok` output sets to 1, which means the two counters start.
|
||||
- Force one of the two identical counters to 0.
|
||||
- Verify that prim_esc_receiver detects the counter mismatch and set `esc_en` signal to
|
||||
1.
|
||||
'''
|
||||
milestone: V1
|
||||
tests: ["prim_esc_test"]
|
||||
}
|
||||
|
||||
{
|
||||
name: prim_esc_handshake_with_rand_reset_test
|
||||
desc: '''Verify alert request from prim_alert_sender.
|
||||
|
||||
- Send a ping request by driving `ping_req` pin to 1.
|
||||
- Randomly issue reset during the escalation handshake.
|
||||
- Verify that after reset, the prim_esc_sender and prim_esc_receiver pair functions
|
||||
correctly by issuing the tests above.
|
||||
'''
|
||||
milestone: V1
|
||||
tests: ["prim_esc_test"]
|
||||
}
|
||||
|
||||
]
|
||||
}
|
31
vendor/lowrisc_ip/ip/prim/dv/prim_esc/prim_esc_sim.core
vendored
Normal file
31
vendor/lowrisc_ip/ip/prim/dv/prim_esc/prim_esc_sim.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:prim_esc_sim:0.1"
|
||||
description: "ESCALATOR DV sim target"
|
||||
filesets:
|
||||
files_rtl:
|
||||
depend:
|
||||
- lowrisc:prim:esc
|
||||
file_type: systemVerilogSource
|
||||
|
||||
files_dv:
|
||||
depend:
|
||||
- lowrisc:dv:dv_utils
|
||||
- lowrisc:dv:dv_test_status
|
||||
- lowrisc:dv:common_ifs
|
||||
files:
|
||||
- tb/prim_esc_tb.sv
|
||||
file_type: systemVerilogSource
|
||||
|
||||
targets:
|
||||
sim: &sim_target
|
||||
toplevel: prim_esc_tb
|
||||
filesets:
|
||||
- files_rtl
|
||||
- files_dv
|
||||
default_tool: vcs
|
||||
|
||||
lint:
|
||||
<<: *sim_target
|
51
vendor/lowrisc_ip/ip/prim/dv/prim_esc/prim_esc_sim_cfg.hjson
vendored
Normal file
51
vendor/lowrisc_ip/ip/prim/dv/prim_esc/prim_esc_sim_cfg.hjson
vendored
Normal file
|
@ -0,0 +1,51 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
{
|
||||
// Name of the sim cfg - typically same as the name of the DUT.
|
||||
name: prim_esc
|
||||
|
||||
// Top level dut name (sv module).
|
||||
dut: prim_esc
|
||||
|
||||
// Top level testbench name (sv module).
|
||||
tb: prim_esc_tb
|
||||
|
||||
// Simulator used to sign off this block
|
||||
tool: vcs
|
||||
|
||||
// Fusesoc core file used for building the file list.
|
||||
fusesoc_core: lowrisc:dv:prim_esc_sim:0.1
|
||||
|
||||
// Testplan hjson file.
|
||||
testplan: "{proj_root}/hw/ip/prim/dv/prim_esc/data/prim_esc_testplan.hjson"
|
||||
|
||||
// Import additional common sim cfg files.
|
||||
import_cfgs: ["{proj_root}/hw/dv/tools/dvsim/common_sim_cfg.hjson"]
|
||||
|
||||
// Default iterations for all tests - each test entry can override this.
|
||||
reseed: 20
|
||||
|
||||
// List of test specifications.
|
||||
tests: [
|
||||
{
|
||||
name: prim_esc_test
|
||||
run_opts: ["+test_timeout_ns=1_000"]
|
||||
}
|
||||
]
|
||||
|
||||
// List of regressions.
|
||||
regressions: [
|
||||
{
|
||||
name: smoke
|
||||
tests: ["prim_esc_test"]
|
||||
}
|
||||
]
|
||||
|
||||
overrides: [
|
||||
{
|
||||
name: vcs_cov_cfg_file
|
||||
value: "-cm_hier {proj_root}/hw/ip/prim/dv/prim_esc/data/prim_esc_cover.cfg"
|
||||
}
|
||||
]
|
||||
}
|
197
vendor/lowrisc_ip/ip/prim/dv/prim_esc/tb/prim_esc_tb.sv
vendored
Normal file
197
vendor/lowrisc_ip/ip/prim/dv/prim_esc/tb/prim_esc_tb.sv
vendored
Normal file
|
@ -0,0 +1,197 @@
|
|||
// 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_esc_sender and prim_esc_receiver_pair.
|
||||
//
|
||||
// This test has five sequnces:
|
||||
// 1). Random reset during escalation handshake sequence.
|
||||
// 2). Escalation request sequence.
|
||||
// 3). Ping request interrupted by escalation request sequence.
|
||||
// 4). `Esc_tx` integrity error sequence.
|
||||
// 5). Escalation reverse ping timeout sequence.
|
||||
// 6). Escalation receiver counter fail sequence.
|
||||
|
||||
module prim_esc_tb;
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// config
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
localparam time ClkPeriod = 10000;
|
||||
localparam int PING_CNT_DW = 1;
|
||||
localparam int TIMEOUT_CYCLES = 1 << (PING_CNT_DW + 6);
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// Clock and Reset
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
wire clk, rst_n;
|
||||
|
||||
clk_rst_if main_clk (
|
||||
.clk,
|
||||
.rst_n
|
||||
);
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// DUTs
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
logic ping_req, ping_ok, integ_fail, esc_req, esc_req_out;
|
||||
prim_esc_pkg::esc_tx_t esc_tx;
|
||||
prim_esc_pkg::esc_rx_t esc_rx;
|
||||
|
||||
prim_esc_sender i_esc_sender (
|
||||
.clk_i(clk),
|
||||
.rst_ni(rst_n),
|
||||
.ping_req_i(ping_req),
|
||||
.ping_ok_o(ping_ok),
|
||||
.integ_fail_o(integ_fail),
|
||||
.esc_req_i(esc_req),
|
||||
.esc_rx_i(esc_rx),
|
||||
.esc_tx_o(esc_tx)
|
||||
);
|
||||
|
||||
prim_esc_receiver #(
|
||||
.N_ESC_SEV(4),
|
||||
// Set to 1 to avoid long wait period to check ping request reverse timeout.
|
||||
.PING_CNT_DW(PING_CNT_DW)
|
||||
) i_esc_receiver (
|
||||
.clk_i(clk),
|
||||
.rst_ni(rst_n),
|
||||
.esc_req_o(esc_req_out),
|
||||
.esc_rx_o(esc_rx),
|
||||
.esc_tx_i(esc_tx)
|
||||
);
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// Helper Functions/Tasks and Variables
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
logic error = 0;
|
||||
|
||||
function automatic void test_error(string msg);
|
||||
$error($sformatf("%time: %0s", $realtime, msg));
|
||||
error = 1;
|
||||
endfunction
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// Stimuli Application / Response Checking
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
initial begin: p_stimuli
|
||||
ping_req = 0;
|
||||
esc_req = 0;
|
||||
main_clk.set_period_ps(ClkPeriod);
|
||||
main_clk.set_active();
|
||||
main_clk.apply_reset();
|
||||
|
||||
// Sequence 1. Random reset during escalation handshake sequence.
|
||||
ping_req = 1;
|
||||
// Issue async reset between first and fifth clock cycle to reach FSM coverages.
|
||||
#(($urandom_range(1, ClkPeriod) + $urandom_range(1, 5) * ClkPeriod) * 1ps);
|
||||
main_clk.apply_reset();
|
||||
ping_req = 0;
|
||||
|
||||
$display("Random reset during escalation handshake sequence finished!");
|
||||
|
||||
// Sequence 2. Escalation request sequence.
|
||||
esc_req = 1;
|
||||
// Drive random length of esc_req and check `esc_req_out` and `integ_fail` outputs.
|
||||
main_clk.wait_clks($urandom_range(1, 20));
|
||||
if (integ_fail) test_error("Esc_req unexpected signal integrity error!");
|
||||
if (!esc_req_out) test_error("Esc_req did not set esc_req!");
|
||||
esc_req = 0;
|
||||
|
||||
$display("Escalation request sequence finished!");
|
||||
|
||||
// Sequence 3. Ping request interrupted by escalation request.
|
||||
main_clk.wait_clks($urandom_range(1, 20));
|
||||
ping_req = 1;
|
||||
// Wait a max of 5 clock cycle to ensure esc_req is send during ping handshake.
|
||||
main_clk.wait_clks($urandom_range(0, 5));
|
||||
esc_req = 1;
|
||||
wait (ping_ok);
|
||||
wait (esc_req_out);
|
||||
main_clk.wait_clks($urandom_range(1, 20));
|
||||
esc_req = 0;
|
||||
ping_req = 0;
|
||||
if (integ_fail) test_error("Expect no errors when esc_req interrupts ping_req");
|
||||
|
||||
$display("Ping request interrupted by escalation request sequence finished!");
|
||||
|
||||
// Sequence 4.1 `Esc_tx` integrity error sequence during escalation request.
|
||||
main_clk.wait_clks($urandom_range(1, 20));
|
||||
esc_req = 1;
|
||||
// Randomly wait a few clock cycles then inject integrity error.
|
||||
main_clk.wait_clks($urandom_range(0, 5));
|
||||
// Force esc_tx signal to create a integrity fail error case.
|
||||
force esc_tx.esc_n = 1;
|
||||
wait (integ_fail);
|
||||
release esc_tx.esc_n;
|
||||
// Wait #1ps to avoid a race condition on clock edge.
|
||||
#1ps;
|
||||
if (!esc_req_out) test_error("Signal integrity error should set esc_req!");
|
||||
esc_req = 0;
|
||||
|
||||
$display("Escalation esc_p/n integrity sequence during escalation request finished!");
|
||||
|
||||
// Sequence 4.1 `Esc_tx` integrity error sequence during ping request.
|
||||
main_clk.wait_clks($urandom_range(1, 20));
|
||||
ping_req = 1;
|
||||
// Force esc_tx signal to create a integrity fail error case.
|
||||
force esc_tx.esc_n = 1;
|
||||
wait (integ_fail);
|
||||
release esc_tx.esc_n;
|
||||
// Wait #1ps to avoid a race condition on clock edge.
|
||||
#1ps;
|
||||
if (!esc_req_out) test_error("Signal integrity error should set esc_req!");
|
||||
if (ping_ok) test_error("Ping error!");
|
||||
ping_req = 0;
|
||||
|
||||
$display("Escalation esc_p/n integrity sequence during ping request finished!");
|
||||
|
||||
// Sequence 5. Escalation reverse ping timeout sequence.
|
||||
// Wait at least two clock cycles for the previous sequence to finish its escalation request.
|
||||
main_clk.wait_clks($urandom_range(2, 20));
|
||||
ping_req = 1;
|
||||
fork
|
||||
begin
|
||||
// After one ping_req, esc_receiver will start a counter to expect next ping_req. If the
|
||||
// counter reaches its max value but no ping_req has been received, design will set
|
||||
// `esc_req_out` signal.
|
||||
main_clk.wait_clks(TIMEOUT_CYCLES + 1);
|
||||
if (!esc_req_out) test_error("Design failed to detect ping request timeout!");
|
||||
end
|
||||
begin
|
||||
// Wait for a ping handshake to complete.
|
||||
wait (ping_ok);
|
||||
main_clk.wait_clks(2);
|
||||
ping_req = 0;
|
||||
if (integ_fail) test_error("Ping_req unexpected signal integrity error!");
|
||||
if (esc_req_out) test_error("Ping request should not set esc_req_out!");
|
||||
end
|
||||
join
|
||||
main_clk.apply_reset();
|
||||
|
||||
$display("Escalation ping request timeout sequence finished!");
|
||||
|
||||
// Sequence 6. Escalation receiver counter fail sequence.
|
||||
ping_req = 1;
|
||||
// Wait until ping request is acknowledged and counter starts to increment.
|
||||
wait (ping_ok);
|
||||
main_clk.wait_clks(2);
|
||||
ping_req = 0;
|
||||
// If cnt_q[0] and cnt_q[1]'s value do not match, deisgn will set `esc_req_out` signal.
|
||||
force prim_esc_tb.i_esc_receiver.cnt_q[1] = 0;
|
||||
wait (esc_req_out);
|
||||
if (integ_fail) test_error("Escalation receiver counter unexpected signal integrity error!");
|
||||
release prim_esc_tb.i_esc_receiver.cnt_q[1];
|
||||
|
||||
$display("Escalation couter error sequence finished!");
|
||||
|
||||
dv_test_status_pkg::dv_test_status(.passed(!error));
|
||||
$finish();
|
||||
end
|
||||
|
||||
endmodule
|
|
@ -78,12 +78,10 @@ static uint64_t prince_k0_to_k0_prime(const uint64_t k0) {
|
|||
}
|
||||
|
||||
static uint64_t prince_round_constant(const unsigned int round) {
|
||||
uint64_t rc[] = {UINT64_C(0x0000000000000000), UINT64_C(0x13198a2e03707344),
|
||||
UINT64_C(0xa4093822299f31d0), UINT64_C(0x082efa98ec4e6c89),
|
||||
UINT64_C(0x452821e638d01377), UINT64_C(0xbe5466cf34e90c6c),
|
||||
UINT64_C(0x7ef84f78fd955cb1), UINT64_C(0x85840851f1ac43aa),
|
||||
UINT64_C(0xc882d32f25323c54), UINT64_C(0x64a51195e0e3610d),
|
||||
UINT64_C(0xd3b5a399ca0c2399), UINT64_C(0xc0ac29b7c97c50dd)};
|
||||
uint64_t rc[] = {0x0000000000000000, 0x13198a2e03707344, 0xa4093822299f31d0,
|
||||
0x082efa98ec4e6c89, 0x452821e638d01377, 0xbe5466cf34e90c6c,
|
||||
0x7ef84f78fd955cb1, 0x85840851f1ac43aa, 0xc882d32f25323c54,
|
||||
0x64a51195e0e3610d, 0xd3b5a399ca0c2399, 0xc0ac29b7c97c50dd};
|
||||
return rc[round];
|
||||
}
|
||||
|
||||
|
@ -149,7 +147,7 @@ static uint64_t gf2_mat_mult16_1(const uint64_t in, const uint64_t mat[16]) {
|
|||
/**
|
||||
* Build Prince's 16 bit matrices M0 and M1.
|
||||
*/
|
||||
static void prince_m16_matrices(uint64_t m16[2][16]) {
|
||||
static inline void prince_m16_matrices(uint64_t m16[2][16]) {
|
||||
// 4 bits matrices m0 to m3 are stored in array m4
|
||||
const uint64_t m4[4][4] = {// m0
|
||||
{0x0, 0x2, 0x4, 0x8},
|
||||
|
@ -198,7 +196,7 @@ static uint64_t prince_m_prime_layer(const uint64_t m_prime_in) {
|
|||
* The shift row and inverse shift row of the Prince cipher.
|
||||
*/
|
||||
static uint64_t prince_shift_rows(const uint64_t in, int inverse) {
|
||||
const uint64_t row_mask = UINT64_C(0xF000F000F000F000);
|
||||
const uint64_t row_mask = 0xF000F000F000F000;
|
||||
uint64_t shift_rows_out = 0;
|
||||
for (unsigned int i = 0; i < 4; i++) {
|
||||
const uint64_t row = in & (row_mask >> (4 * i));
|
||||
|
@ -278,7 +276,7 @@ static uint64_t prince_core(const uint64_t core_input, const uint64_t k0_new,
|
|||
uint64_t prince_enc_dec_uint64(const uint64_t input, const uint64_t enc_k0,
|
||||
const uint64_t enc_k1, int decrypt,
|
||||
int num_half_rounds, int old_key_schedule) {
|
||||
const uint64_t prince_alpha = UINT64_C(0xc0ac29b7c97c50dd);
|
||||
const uint64_t prince_alpha = 0xc0ac29b7c97c50dd;
|
||||
const uint64_t k1 = enc_k1 ^ (decrypt ? prince_alpha : 0);
|
||||
const uint64_t k0_new =
|
||||
(old_key_schedule) ? k1 : enc_k0 ^ (decrypt ? prince_alpha : 0);
|
||||
|
@ -320,9 +318,10 @@ static void prince_enc_dec(const uint8_t in_bytes[8],
|
|||
* key_bytes 0 to 7 must contain K0.
|
||||
* key_bytes 8 to 15 must contain K1.
|
||||
*/
|
||||
static void prince_encrypt(const uint8_t in_bytes[8],
|
||||
const uint8_t key_bytes[16], uint8_t out_bytes[8],
|
||||
int num_half_rounds, int old_key_schedule) {
|
||||
static inline void prince_encrypt(const uint8_t in_bytes[8],
|
||||
const uint8_t key_bytes[16],
|
||||
uint8_t out_bytes[8], int num_half_rounds,
|
||||
int old_key_schedule) {
|
||||
prince_enc_dec(in_bytes, key_bytes, out_bytes, 0, num_half_rounds,
|
||||
old_key_schedule);
|
||||
}
|
||||
|
@ -333,9 +332,10 @@ static void prince_encrypt(const uint8_t in_bytes[8],
|
|||
* key_bytes 0 to 7 must contain K0.
|
||||
* key_bytes 8 to 15 must contain K1.
|
||||
*/
|
||||
static void prince_decrypt(const uint8_t in_bytes[8],
|
||||
const uint8_t key_bytes[16], uint8_t out_bytes[8],
|
||||
int num_half_rounds, int old_key_schedule) {
|
||||
static inline void prince_decrypt(const uint8_t in_bytes[8],
|
||||
const uint8_t key_bytes[16],
|
||||
uint8_t out_bytes[8], int num_half_rounds,
|
||||
int old_key_schedule) {
|
||||
prince_enc_dec(in_bytes, key_bytes, out_bytes, 1, num_half_rounds,
|
||||
old_key_schedule);
|
||||
uint64_t m16[2][16];
|
||||
|
|
|
@ -124,7 +124,7 @@ module prim_prince_tb;
|
|||
// Drive input into encryption instances.
|
||||
key_in = key;
|
||||
dec_in = 0;
|
||||
valid_in = 1;
|
||||
valid_in = 0;
|
||||
for (int unsigned i = 0; i < 2; i++) begin
|
||||
for (int unsigned j = 0; j < 2; j++) begin
|
||||
for (int unsigned k = 0; k < NumRoundsHalf; k++) begin
|
||||
|
@ -132,10 +132,14 @@ module prim_prince_tb;
|
|||
end
|
||||
end
|
||||
end
|
||||
// wait some time before signaling that the inputs are valid
|
||||
clk_if.wait_clks($urandom_range(0, 10));
|
||||
valid_in = 1;
|
||||
// Wait for the DUTs to finish calculations.
|
||||
clk_if.wait_clks(2);
|
||||
wait(&valid_out == 1);
|
||||
valid_in = 0;
|
||||
clk_if.wait_clks(1);
|
||||
// query DPI model for expected encrypted output.
|
||||
for (int i = 0; i < 2; i++) begin
|
||||
for (int j = 0; j < 2; j++) begin
|
||||
|
@ -162,7 +166,7 @@ module prim_prince_tb;
|
|||
// Drive input into decryption instances.
|
||||
key_in = key;
|
||||
dec_in = 1;
|
||||
valid_in = 1;
|
||||
valid_in = 0;
|
||||
for (int unsigned i = 0; i < 2; i++) begin
|
||||
for (int unsigned j = 0; j < 2; j++) begin
|
||||
for (int unsigned k = 0; k < NumRoundsHalf; k++) begin
|
||||
|
@ -170,6 +174,9 @@ module prim_prince_tb;
|
|||
end
|
||||
end
|
||||
end
|
||||
// wait some time before signaling that the inputs are valid
|
||||
clk_if.wait_clks($urandom_range(0, 10));
|
||||
valid_in = 1;
|
||||
// Wait for the DUTs to finish calculations.
|
||||
clk_if.wait_clks(2);
|
||||
wait(&valid_out == 1);
|
||||
|
@ -243,11 +250,16 @@ module prim_prince_tb;
|
|||
bit [KeyWidth/2-1:0] k0, k1;
|
||||
bit [DataWidth-1:0] plaintext;
|
||||
|
||||
$timeformat(-12, 0, " ps", 12);
|
||||
clk_if.set_period_ps(ClkPeriod);
|
||||
clk_if.set_active();
|
||||
// Toggle reset twice at start of the test to hit a small toggle coverage point:
|
||||
// - rst_ni: 1 -> 0
|
||||
// No additional functional impact
|
||||
clk_if.apply_reset();
|
||||
$timeformat(-12, 0, " ps", 12);
|
||||
clk_if.wait_clks(10);
|
||||
clk_if.wait_clks(5);
|
||||
clk_if.apply_reset();
|
||||
clk_if.wait_clks(5);
|
||||
|
||||
/////////////////////////////
|
||||
// Test the 5 golden vectors.
|
||||
|
|
|
@ -19,7 +19,7 @@ targets:
|
|||
default: &default_target
|
||||
# note, this setting is just used
|
||||
# to generate a file list for jg
|
||||
formal: icarus
|
||||
default_tool: icarus
|
||||
filesets:
|
||||
- files_formal
|
||||
toplevel:
|
||||
|
|
27
vendor/lowrisc_ip/ip/prim/fpv/prim_fifo_async_sram_adapter_fpv.core
vendored
Normal file
27
vendor/lowrisc_ip/ip/prim/fpv/prim_fifo_async_sram_adapter_fpv.core
vendored
Normal file
|
@ -0,0 +1,27 @@
|
|||
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_fifo_async_sram_adapter_fpv:0.1"
|
||||
description: "prim_fifo_async_sram_adapter FPV target"
|
||||
filesets:
|
||||
files_formal:
|
||||
depend:
|
||||
- lowrisc:prim:all
|
||||
- lowrisc:prim:ram_2p_async_adv
|
||||
files:
|
||||
- tb/prim_fifo_async_sram_adapter_fpv.sv
|
||||
file_type: systemVerilogSource
|
||||
|
||||
targets:
|
||||
default: &default_target
|
||||
default_tool: icarus
|
||||
filesets:
|
||||
- files_formal
|
||||
toplevel: prim_fifo_async_sram_adapter_fpv
|
||||
|
||||
formal:
|
||||
<<: *default_target
|
||||
|
||||
lint:
|
||||
<<: *default_target
|
|
@ -10,7 +10,6 @@ filesets:
|
|||
depend:
|
||||
- lowrisc:prim:all
|
||||
files:
|
||||
- ../rtl/prim_packer.sv
|
||||
- tb/prim_packer_fpv.sv
|
||||
file_type: systemVerilogSource
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ module prim_alert_rxtx_async_bind_fpv;
|
|||
.alert_err_ni,
|
||||
.alert_skew_i,
|
||||
.alert_test_i,
|
||||
.init_trig_i,
|
||||
.alert_req_i,
|
||||
.alert_ack_o,
|
||||
.alert_state_o,
|
||||
|
|
|
@ -19,6 +19,7 @@ module prim_alert_rxtx_async_fatal_bind_fpv;
|
|||
.alert_err_ni,
|
||||
.alert_skew_i,
|
||||
.alert_test_i,
|
||||
.init_trig_i,
|
||||
.alert_req_i,
|
||||
.alert_ack_o,
|
||||
.alert_state_o,
|
||||
|
|
|
@ -23,6 +23,7 @@ module prim_alert_rxtx_async_fatal_fpv
|
|||
// 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,
|
||||
|
@ -72,8 +73,8 @@ module prim_alert_rxtx_async_fatal_fpv
|
|||
.AsyncOn ( AsyncOn ),
|
||||
.IsFatal ( IsFatal )
|
||||
) i_prim_alert_sender (
|
||||
.clk_i ,
|
||||
.rst_ni ,
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.alert_test_i,
|
||||
.alert_req_i,
|
||||
.alert_ack_o,
|
||||
|
@ -85,12 +86,13 @@ module prim_alert_rxtx_async_fatal_fpv
|
|||
prim_alert_receiver #(
|
||||
.AsyncOn ( AsyncOn )
|
||||
) i_prim_alert_receiver (
|
||||
.clk_i ,
|
||||
.rst_ni ,
|
||||
.ping_req_i ,
|
||||
.ping_ok_o ,
|
||||
.integ_fail_o ,
|
||||
.alert_o ,
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.init_trig_i,
|
||||
.ping_req_i,
|
||||
.ping_ok_o,
|
||||
.integ_fail_o,
|
||||
.alert_o,
|
||||
.alert_rx_o ( alert_rx_out ),
|
||||
.alert_tx_i ( alert_tx_in )
|
||||
);
|
||||
|
|
|
@ -23,6 +23,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 ping_req_i,
|
||||
output logic alert_ack_o,
|
||||
output logic alert_state_o,
|
||||
|
@ -33,6 +34,7 @@ module prim_alert_rxtx_async_fpv
|
|||
|
||||
// asynchronous case
|
||||
localparam bit AsyncOn = 1'b1;
|
||||
localparam bit IsFatal = 1'b0;
|
||||
|
||||
logic ping_pd;
|
||||
logic ping_nd;
|
||||
|
@ -68,10 +70,11 @@ module prim_alert_rxtx_async_fpv
|
|||
assign alert_tx_in.alert_n = alert_nq[alert_skew_i[1]] ^ alert_err_ni;
|
||||
|
||||
prim_alert_sender #(
|
||||
.AsyncOn ( AsyncOn )
|
||||
.AsyncOn ( AsyncOn ),
|
||||
.IsFatal ( IsFatal )
|
||||
) i_prim_alert_sender (
|
||||
.clk_i ,
|
||||
.rst_ni ,
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.alert_test_i,
|
||||
.alert_req_i,
|
||||
.alert_ack_o,
|
||||
|
@ -83,16 +86,18 @@ module prim_alert_rxtx_async_fpv
|
|||
prim_alert_receiver #(
|
||||
.AsyncOn ( AsyncOn )
|
||||
) i_prim_alert_receiver (
|
||||
.clk_i ,
|
||||
.rst_ni ,
|
||||
.ping_req_i ,
|
||||
.ping_ok_o ,
|
||||
.integ_fail_o ,
|
||||
.alert_o ,
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.init_trig_i,
|
||||
.ping_req_i,
|
||||
.ping_ok_o,
|
||||
.integ_fail_o,
|
||||
.alert_o,
|
||||
.alert_rx_o ( alert_rx_out ),
|
||||
.alert_tx_i ( alert_tx_in )
|
||||
);
|
||||
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin : p_skew_delay
|
||||
if (!rst_ni) begin
|
||||
ping_pq <= '0;
|
||||
|
|
|
@ -19,6 +19,7 @@ module prim_alert_rxtx_bind_fpv;
|
|||
.alert_req_i,
|
||||
.alert_ack_o,
|
||||
.alert_state_o,
|
||||
.init_trig_i,
|
||||
.ping_req_i,
|
||||
.ping_ok_o,
|
||||
.integ_fail_o,
|
||||
|
|
|
@ -20,6 +20,7 @@ module prim_alert_rxtx_fatal_bind_fpv;
|
|||
.alert_req_i,
|
||||
.alert_ack_o,
|
||||
.alert_state_o,
|
||||
.init_trig_i,
|
||||
.ping_req_i,
|
||||
.ping_ok_o,
|
||||
.integ_fail_o,
|
||||
|
|
|
@ -20,6 +20,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 ping_req_i,
|
||||
output logic alert_ack_o,
|
||||
output logic alert_state_o,
|
||||
|
@ -47,8 +48,8 @@ module prim_alert_rxtx_fatal_fpv
|
|||
.AsyncOn ( AsyncOn ),
|
||||
.IsFatal ( IsFatal )
|
||||
) i_prim_alert_sender (
|
||||
.clk_i ,
|
||||
.rst_ni ,
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.alert_test_i,
|
||||
.alert_req_i,
|
||||
.alert_ack_o,
|
||||
|
@ -60,12 +61,13 @@ module prim_alert_rxtx_fatal_fpv
|
|||
prim_alert_receiver #(
|
||||
.AsyncOn ( AsyncOn )
|
||||
) i_prim_alert_receiver (
|
||||
.clk_i ,
|
||||
.rst_ni ,
|
||||
.ping_req_i ,
|
||||
.ping_ok_o ,
|
||||
.integ_fail_o ,
|
||||
.alert_o ,
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.init_trig_i,
|
||||
.ping_req_i,
|
||||
.ping_ok_o,
|
||||
.integ_fail_o,
|
||||
.alert_o,
|
||||
.alert_rx_o ( alert_rx_out ),
|
||||
.alert_tx_i ( alert_tx_in )
|
||||
);
|
||||
|
|
|
@ -20,6 +20,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 ping_req_i,
|
||||
output logic alert_ack_o,
|
||||
output logic alert_state_o,
|
||||
|
@ -30,6 +31,7 @@ module prim_alert_rxtx_fpv
|
|||
|
||||
// synchronous case
|
||||
localparam bit AsyncOn = 1'b0;
|
||||
localparam bit IsFatal = 1'b0;
|
||||
|
||||
alert_rx_t alert_rx_out, alert_rx_in;
|
||||
alert_tx_t alert_tx_out, alert_tx_in;
|
||||
|
@ -43,10 +45,11 @@ module prim_alert_rxtx_fpv
|
|||
assign alert_tx_in.alert_n = alert_tx_out.alert_n ^ alert_err_ni;
|
||||
|
||||
prim_alert_sender #(
|
||||
.AsyncOn ( AsyncOn )
|
||||
.AsyncOn ( AsyncOn ),
|
||||
.IsFatal ( IsFatal )
|
||||
) i_prim_alert_sender (
|
||||
.clk_i ,
|
||||
.rst_ni ,
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.alert_test_i,
|
||||
.alert_req_i,
|
||||
.alert_ack_o,
|
||||
|
@ -58,12 +61,13 @@ module prim_alert_rxtx_fpv
|
|||
prim_alert_receiver #(
|
||||
.AsyncOn ( AsyncOn )
|
||||
) i_prim_alert_receiver (
|
||||
.clk_i ,
|
||||
.rst_ni ,
|
||||
.ping_req_i ,
|
||||
.ping_ok_o ,
|
||||
.integ_fail_o ,
|
||||
.alert_o ,
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.init_trig_i,
|
||||
.ping_req_i,
|
||||
.ping_ok_o,
|
||||
.integ_fail_o,
|
||||
.alert_o,
|
||||
.alert_rx_o ( alert_rx_out ),
|
||||
.alert_tx_i ( alert_tx_in )
|
||||
);
|
||||
|
|
|
@ -17,7 +17,7 @@ module prim_esc_rxtx_bind_fpv;
|
|||
.ping_req_i ,
|
||||
.ping_ok_o ,
|
||||
.integ_fail_o,
|
||||
.esc_en_o
|
||||
.esc_req_o
|
||||
);
|
||||
|
||||
endmodule : prim_esc_rxtx_bind_fpv
|
||||
|
|
|
@ -20,7 +20,7 @@ module prim_esc_rxtx_fpv
|
|||
input ping_req_i,
|
||||
output logic ping_ok_o,
|
||||
output logic integ_fail_o,
|
||||
output logic esc_en_o
|
||||
output logic esc_req_o
|
||||
);
|
||||
|
||||
esc_rx_t esc_rx_in, esc_rx_out;
|
||||
|
@ -49,7 +49,7 @@ module prim_esc_rxtx_fpv
|
|||
) u_prim_esc_receiver (
|
||||
.clk_i ,
|
||||
.rst_ni ,
|
||||
.esc_en_o ,
|
||||
.esc_req_o ,
|
||||
.esc_rx_o ( esc_rx_out ),
|
||||
.esc_tx_i ( esc_tx_in )
|
||||
);
|
||||
|
|
204
vendor/lowrisc_ip/ip/prim/fpv/tb/prim_fifo_async_sram_adapter_fpv.sv
vendored
Normal file
204
vendor/lowrisc_ip/ip/prim/fpv/tb/prim_fifo_async_sram_adapter_fpv.sv
vendored
Normal file
|
@ -0,0 +1,204 @@
|
|||
// 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_fifo_sram_async
|
||||
|
||||
module prim_fifo_async_sram_adapter_fpv #(
|
||||
parameter int unsigned Width = 32,
|
||||
parameter int unsigned Depth = 16,
|
||||
|
||||
parameter int unsigned FpgaSram = 0 // Use FF based
|
||||
) (
|
||||
input clk_wr_i,
|
||||
input clk_rd_i,
|
||||
|
||||
input rst_ni,
|
||||
|
||||
input wvalid_i,
|
||||
output logic wready_o,
|
||||
input [Width-1:0] wdata_i,
|
||||
|
||||
output logic rvalid_o,
|
||||
input rready_i,
|
||||
output logic [Width-1:0] rdata_o
|
||||
);
|
||||
|
||||
localparam int unsigned SramAw = 7;
|
||||
localparam int unsigned SramDw = 32;
|
||||
localparam logic [SramAw-1:0] SramBaseAddr = 'h 30;
|
||||
|
||||
logic w_sram_req;
|
||||
logic w_sram_gnt;
|
||||
logic w_sram_write;
|
||||
logic [SramAw-1:0] w_sram_addr;
|
||||
logic [SramDw-1:0] w_sram_wdata;
|
||||
logic [SramDw-1:0] w_sram_wmask;
|
||||
logic w_sram_rvalid; // not used
|
||||
logic [SramDw-1:0] w_sram_rdata; // not used
|
||||
logic [1:0] w_sram_rerror; // not used
|
||||
|
||||
logic r_sram_req;
|
||||
logic r_sram_gnt;
|
||||
logic r_sram_write;
|
||||
logic [SramAw-1:0] r_sram_addr;
|
||||
logic [SramDw-1:0] r_sram_wdata; // not used
|
||||
logic [SramDw-1:0] r_sram_wmask; // not used
|
||||
logic r_sram_rvalid;
|
||||
logic [SramDw-1:0] r_sram_rdata;
|
||||
logic [1:0] r_sram_rerror;
|
||||
|
||||
prim_fifo_async_sram_adapter #(
|
||||
.Width (Width),
|
||||
.Depth (Depth),
|
||||
|
||||
.SramAw (SramAw), // TODO: random with constraint
|
||||
.SramDw (SramDw), // TODO: random with constraint
|
||||
|
||||
.SramBaseAddr(SramBaseAddr) // TODO: random?
|
||||
) dut (
|
||||
.clk_wr_i,
|
||||
.rst_wr_ni (rst_ni),
|
||||
.clk_rd_i,
|
||||
.rst_rd_ni (rst_ni),
|
||||
|
||||
.wvalid_i,
|
||||
.wready_o,
|
||||
.wdata_i,
|
||||
|
||||
.wdepth_o (),
|
||||
|
||||
.rvalid_o,
|
||||
.rready_i,
|
||||
.rdata_o,
|
||||
|
||||
.rdepth_o (),
|
||||
|
||||
// Sram Interface
|
||||
.w_sram_req_o (w_sram_req ),
|
||||
.w_sram_gnt_i (w_sram_gnt ),
|
||||
.w_sram_write_o (w_sram_write ),
|
||||
.w_sram_addr_o (w_sram_addr ),
|
||||
.w_sram_wdata_o (w_sram_wdata ),
|
||||
.w_sram_wmask_o (w_sram_wmask ),
|
||||
.w_sram_rvalid_i(w_sram_rvalid), // not used
|
||||
.w_sram_rdata_i (w_sram_rdata ), // not used
|
||||
.w_sram_rerror_i(w_sram_rerror), // not used
|
||||
|
||||
// Read SRAM port
|
||||
.r_sram_req_o (r_sram_req ),
|
||||
.r_sram_gnt_i (r_sram_gnt ),
|
||||
.r_sram_write_o (r_sram_write ),
|
||||
.r_sram_addr_o (r_sram_addr ),
|
||||
.r_sram_wdata_o (r_sram_wdata ), // not used
|
||||
.r_sram_wmask_o (r_sram_wmask ), // not used
|
||||
.r_sram_rvalid_i(r_sram_rvalid),
|
||||
.r_sram_rdata_i (r_sram_rdata ),
|
||||
.r_sram_rerror_i(r_sram_rerror),
|
||||
|
||||
.r_full_o(),
|
||||
|
||||
.r_notempty_o(),
|
||||
|
||||
.w_full_o()
|
||||
);
|
||||
|
||||
if (FpgaSram == 1) begin : g_sram_fpga
|
||||
// FPV looks like does not like the style of ram_2p.
|
||||
prim_ram_2p #(
|
||||
.Depth (2**SramAw),
|
||||
.Width (SramDw),
|
||||
.DataBitsPerMask (1)
|
||||
) u_sram (
|
||||
.clk_a_i (clk_wr_i),
|
||||
.clk_b_i (clk_rd_i),
|
||||
|
||||
.a_req_i (w_sram_req ),
|
||||
.a_write_i (w_sram_write ),
|
||||
.a_addr_i (w_sram_addr ),
|
||||
.a_wdata_i (w_sram_wdata ),
|
||||
.a_wmask_i (w_sram_wmask ),
|
||||
.a_rdata_o (w_sram_rdata ),
|
||||
|
||||
.b_req_i (r_sram_req ),
|
||||
.b_write_i (r_sram_write ),
|
||||
.b_addr_i (r_sram_addr ),
|
||||
.b_wdata_i (r_sram_wdata ),
|
||||
.b_wmask_i (r_sram_wmask ),
|
||||
.b_rdata_o (r_sram_rdata ),
|
||||
|
||||
.cfg_i ('0)
|
||||
);
|
||||
end else begin : g_sram_ff
|
||||
logic [SramDw-1:0] mem [2**SramAw];
|
||||
|
||||
always_ff @(posedge clk_wr_i) begin
|
||||
if (w_sram_req && w_sram_write) begin
|
||||
for (int unsigned i = 0; i < SramDw ; i++) begin
|
||||
if (w_sram_wmask[i]) mem[w_sram_addr][i] <= w_sram_wdata[i];
|
||||
end // for
|
||||
end // if
|
||||
end
|
||||
|
||||
always_ff @(posedge clk_rd_i) begin
|
||||
if (r_sram_req && !r_sram_write) begin
|
||||
r_sram_rdata <= mem[r_sram_addr];
|
||||
end
|
||||
end
|
||||
end // !FpgaSram
|
||||
|
||||
assign w_sram_gnt = w_sram_req;
|
||||
|
||||
always_ff @(posedge clk_wr_i) begin
|
||||
w_sram_rvalid <= w_sram_req && !w_sram_write;
|
||||
end
|
||||
|
||||
assign w_sram_rerror = '0;
|
||||
|
||||
assign r_sram_gnt = r_sram_req;
|
||||
|
||||
always_ff @(posedge clk_rd_i) begin
|
||||
r_sram_rvalid <= r_sram_req && !r_sram_write;
|
||||
end
|
||||
|
||||
assign r_sram_rerror = '0;
|
||||
|
||||
`ASSUME_FPV(WdataBins_M,
|
||||
wvalid_i |-> wdata_i inside {
|
||||
32'h DEAD_BEEF, 32'h5A5A_A5A5, 32'h 1234_5678
|
||||
},
|
||||
clk_wr_i, !rst_ni)
|
||||
|
||||
`ifdef FPV_ON
|
||||
logic [Width-1:0] storage [Depth];
|
||||
logic [Width-1:0] rdata;
|
||||
logic [$clog2(Depth)-1:0] wptr, rptr;
|
||||
logic wack, rack;
|
||||
|
||||
assign wack = wvalid_i && wready_o;
|
||||
assign rack = rvalid_o && rready_i;
|
||||
|
||||
always_ff @(posedge clk_wr_i or negedge rst_ni) begin
|
||||
if (!rst_ni) wptr <= '0;
|
||||
else if (wack) wptr <= wptr+1;
|
||||
end
|
||||
always_ff @(posedge clk_rd_i or negedge rst_ni) begin
|
||||
if (!rst_ni) rptr <= '0;
|
||||
else if (rack) rptr <= rptr+1;
|
||||
end
|
||||
|
||||
always_ff @(posedge clk_wr_i or negedge rst_ni) begin
|
||||
if (!rst_ni) storage <= '{default:'0};
|
||||
else if (wack) begin
|
||||
storage[wptr] <= wdata_i;
|
||||
end
|
||||
end
|
||||
|
||||
assign rdata = storage[rptr];
|
||||
|
||||
`ASSERT(DataIntegrityCheck_A,
|
||||
rack |-> rdata_o == rdata,
|
||||
clk_rd_i, !rst_ni)
|
||||
`endif // FPV_ON
|
||||
|
||||
endmodule : prim_fifo_async_sram_adapter_fpv
|
|
@ -20,8 +20,8 @@ module prim_lfsr_fpv #(
|
|||
localparam int unsigned GalMaxGtFibMax = GalXorMaxLfsrDw > FibXnorMaxLfsrDw,
|
||||
localparam int unsigned MaxLfsrDw = GalXorMaxLfsrDw * GalMaxGtFibMax +
|
||||
FibXnorMaxLfsrDw * (1 - GalMaxGtFibMax),
|
||||
localparam int unsigned NumDuts = FibXnorMaxLfsrDw - FibXnorMinLfsrDw + 1 +
|
||||
GalXorMaxLfsrDw - GalXorMinLfsrDw + 1
|
||||
localparam int unsigned NumDuts = 2*(FibXnorMaxLfsrDw - FibXnorMinLfsrDw + 1) +
|
||||
2*(GalXorMaxLfsrDw - GalXorMinLfsrDw + 1)
|
||||
) (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
|
@ -33,7 +33,7 @@ module prim_lfsr_fpv #(
|
|||
);
|
||||
|
||||
for (genvar k = GalXorMinLfsrDw; k <= GalXorMaxLfsrDw; k++) begin : gen_gal_xor_duts
|
||||
localparam int unsigned idx = k - GalXorMinLfsrDw;
|
||||
localparam int unsigned Idx = k - GalXorMinLfsrDw;
|
||||
prim_lfsr #(.LfsrType("GAL_XOR"),
|
||||
.LfsrDw ( k ),
|
||||
.EntropyDw ( EntropyDw ),
|
||||
|
@ -41,19 +41,43 @@ module prim_lfsr_fpv #(
|
|||
.DefaultSeed ( 1 ),
|
||||
// disabled for large LFSRs since this becomes prohibitive in runtime
|
||||
.MaxLenSVA ( k <= MaxLenSVAThresh )
|
||||
) i_prim_lfsr (
|
||||
) u_prim_lfsr (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.seed_en_i ( load_ext_en_i[idx] ),
|
||||
.seed_i ( k'(seed_ext_i[idx]) ),
|
||||
.lfsr_en_i ( lfsr_en_i[idx] ),
|
||||
.entropy_i ( entropy_i[idx] ),
|
||||
.state_o ( state_o[idx] )
|
||||
.seed_en_i ( load_ext_en_i[Idx] ),
|
||||
.seed_i ( k'(seed_ext_i[Idx]) ),
|
||||
.lfsr_en_i ( lfsr_en_i[Idx] ),
|
||||
.entropy_i ( entropy_i[Idx] ),
|
||||
.state_o ( state_o[Idx] )
|
||||
);
|
||||
end
|
||||
|
||||
// same as above but with non-linear output enabled.
|
||||
// only power-of-two widths are allowed.
|
||||
for (genvar k = 16; k <= GalXorMaxLfsrDw; k = k*2)
|
||||
begin : gen_gal_xor_duts_nonlinear
|
||||
localparam int unsigned Idx = k - GalXorMinLfsrDw;
|
||||
prim_lfsr #(.LfsrType("GAL_XOR"),
|
||||
.LfsrDw ( k ),
|
||||
.EntropyDw ( EntropyDw ),
|
||||
.StateOutDw ( StateOutDw ),
|
||||
.DefaultSeed ( 1 ),
|
||||
// disabled for large LFSRs since this becomes prohibitive in runtime
|
||||
.MaxLenSVA ( k <= MaxLenSVAThresh ),
|
||||
.NonLinearOut (1)
|
||||
) u_prim_lfsr (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.seed_en_i ( load_ext_en_i[Idx] ),
|
||||
.seed_i ( k'(seed_ext_i[Idx]) ),
|
||||
.lfsr_en_i ( lfsr_en_i[Idx] ),
|
||||
.entropy_i ( entropy_i[Idx] ),
|
||||
.state_o ( state_o[Idx] )
|
||||
);
|
||||
end
|
||||
|
||||
for (genvar k = FibXnorMinLfsrDw; k <= FibXnorMaxLfsrDw; k++) begin : gen_fib_xnor_duts
|
||||
localparam int unsigned idx = k - FibXnorMinLfsrDw + GalXorMaxLfsrDw - GalXorMinLfsrDw + 1;
|
||||
localparam int unsigned Idx = k - FibXnorMinLfsrDw + GalXorMaxLfsrDw - GalXorMinLfsrDw + 1;
|
||||
prim_lfsr #(.LfsrType("FIB_XNOR"),
|
||||
.LfsrDw ( k ),
|
||||
.EntropyDw ( EntropyDw ),
|
||||
|
@ -61,14 +85,38 @@ module prim_lfsr_fpv #(
|
|||
.DefaultSeed ( 1 ),
|
||||
// disabled for large LFSRs since this becomes prohibitive in runtime
|
||||
.MaxLenSVA ( k <= MaxLenSVAThresh )
|
||||
) i_prim_lfsr (
|
||||
) u_prim_lfsr (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.seed_en_i ( load_ext_en_i[idx] ),
|
||||
.seed_i ( k'(seed_ext_i[idx]) ),
|
||||
.lfsr_en_i ( lfsr_en_i[idx] ),
|
||||
.entropy_i ( entropy_i[idx] ),
|
||||
.state_o ( state_o[idx] )
|
||||
.seed_en_i ( load_ext_en_i[Idx] ),
|
||||
.seed_i ( k'(seed_ext_i[Idx]) ),
|
||||
.lfsr_en_i ( lfsr_en_i[Idx] ),
|
||||
.entropy_i ( entropy_i[Idx] ),
|
||||
.state_o ( state_o[Idx] )
|
||||
);
|
||||
end
|
||||
|
||||
// same as above but with non-linear output enabled.
|
||||
// only power-of-two widths are allowed.
|
||||
for (genvar k = 16; k <= FibXnorMaxLfsrDw; k = k*2)
|
||||
begin : gen_fib_xnor_duts_nonlinear
|
||||
localparam int unsigned Idx = k - FibXnorMinLfsrDw + GalXorMaxLfsrDw - GalXorMinLfsrDw + 1;
|
||||
prim_lfsr #(.LfsrType("FIB_XNOR"),
|
||||
.LfsrDw ( k ),
|
||||
.EntropyDw ( EntropyDw ),
|
||||
.StateOutDw ( StateOutDw ),
|
||||
.DefaultSeed ( 1 ),
|
||||
// disabled for large LFSRs since this becomes prohibitive in runtime
|
||||
.MaxLenSVA ( k <= MaxLenSVAThresh ),
|
||||
.NonLinearOut (1)
|
||||
) u_prim_lfsr (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.seed_en_i ( load_ext_en_i[Idx] ),
|
||||
.seed_i ( k'(seed_ext_i[Idx]) ),
|
||||
.lfsr_en_i ( lfsr_en_i[Idx] ),
|
||||
.entropy_i ( entropy_i[Idx] ),
|
||||
.state_o ( state_o[Idx] )
|
||||
);
|
||||
end
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ module prim_alert_rxtx_assert_fpv (
|
|||
input alert_req_i,
|
||||
input alert_ack_o,
|
||||
input alert_state_o,
|
||||
input lc_ctrl_pkg::lc_tx_t init_trig_i,
|
||||
input ping_req_i,
|
||||
input ping_ok_o,
|
||||
input integ_fail_o,
|
||||
|
@ -33,6 +34,12 @@ module prim_alert_rxtx_assert_fpv (
|
|||
ack_err_pi | ack_err_ni |
|
||||
alert_err_pi | alert_err_ni;
|
||||
|
||||
logic init_pending;
|
||||
assign init_pending = init_trig_i == lc_ctrl_pkg::On ||
|
||||
prim_alert_rxtx_fpv.i_prim_alert_receiver.state_q inside {
|
||||
prim_alert_rxtx_fpv.i_prim_alert_receiver.InitReq,
|
||||
prim_alert_rxtx_fpv.i_prim_alert_receiver.InitAckWait};
|
||||
|
||||
// note: we can only detect sigint errors where one wire is flipped.
|
||||
`ASSUME_FPV(PingErrorsAreOH_M, $onehot0({ping_err_pi, ping_err_ni}), clk_i, !rst_ni)
|
||||
`ASSUME_FPV(AckErrorsAreOH_M, $onehot0({ack_err_pi, ack_err_ni}), clk_i, !rst_ni)
|
||||
|
@ -55,64 +62,81 @@ module prim_alert_rxtx_assert_fpv (
|
|||
endsequence
|
||||
|
||||
// note: injected errors may lockup the FSMs, and hence the full HS can
|
||||
// only take place if both FSMs are in a sane state
|
||||
// only take place if both FSMs are in a good state
|
||||
`ASSERT(PingHs_A, ##1 $changed(prim_alert_rxtx_fpv.alert_rx_out.ping_p) &&
|
||||
(prim_alert_rxtx_fpv.i_prim_alert_sender.state_q ==
|
||||
prim_alert_rxtx_fpv.i_prim_alert_sender.Idle) &&
|
||||
(prim_alert_rxtx_fpv.i_prim_alert_receiver.state_q ==
|
||||
prim_alert_rxtx_fpv.i_prim_alert_receiver.Idle) |=> FullHandshake_S,
|
||||
clk_i, !rst_ni || error_present)
|
||||
clk_i, !rst_ni || error_present || init_trig_i == lc_ctrl_pkg::On)
|
||||
`ASSERT(AlertHs_A, alert_req_i &&
|
||||
(prim_alert_rxtx_fpv.i_prim_alert_sender.state_q ==
|
||||
prim_alert_rxtx_fpv.i_prim_alert_sender.Idle) &&
|
||||
(prim_alert_rxtx_fpv.i_prim_alert_receiver.state_q ==
|
||||
prim_alert_rxtx_fpv.i_prim_alert_receiver.Idle) |=>
|
||||
FullHandshake_S |-> alert_ack_o, clk_i, !rst_ni || error_present)
|
||||
FullHandshake_S |-> alert_ack_o,
|
||||
clk_i, !rst_ni || error_present || init_trig_i == lc_ctrl_pkg::On)
|
||||
`ASSERT(AlertTestHs_A, alert_test_i &&
|
||||
(prim_alert_rxtx_fpv.i_prim_alert_sender.state_q ==
|
||||
prim_alert_rxtx_fpv.i_prim_alert_sender.Idle) &&
|
||||
(prim_alert_rxtx_fpv.i_prim_alert_receiver.state_q ==
|
||||
prim_alert_rxtx_fpv.i_prim_alert_receiver.Idle) |=>
|
||||
FullHandshake_S, clk_i, !rst_ni || error_present)
|
||||
FullHandshake_S,
|
||||
clk_i, !rst_ni || error_present || init_trig_i == lc_ctrl_pkg::On)
|
||||
// Make sure we eventually get an ACK
|
||||
`ASSERT(AlertReqAck_A, alert_req_i &&
|
||||
(prim_alert_rxtx_fpv.i_prim_alert_sender.state_q ==
|
||||
prim_alert_rxtx_fpv.i_prim_alert_sender.Idle) &&
|
||||
(prim_alert_rxtx_fpv.i_prim_alert_receiver.state_q ==
|
||||
prim_alert_rxtx_fpv.i_prim_alert_receiver.Idle) |-> strong(##[1:$] alert_ack_o),
|
||||
clk_i, !rst_ni || error_present)
|
||||
clk_i, !rst_ni || error_present || init_trig_i == lc_ctrl_pkg::On)
|
||||
|
||||
// transmission of pings
|
||||
// note: the complete transmission of pings only happen when no ping handshake is in progress
|
||||
`ASSERT(AlertPingOk_A, !(prim_alert_rxtx_fpv.i_prim_alert_sender.state_q inside {
|
||||
prim_alert_rxtx_fpv.i_prim_alert_sender.PingHsPhase1,
|
||||
prim_alert_rxtx_fpv.i_prim_alert_sender.PingHsPhase2}) && $rose(ping_req_i) |->
|
||||
##[1:9] ping_ok_o, clk_i, !rst_ni || error_present)
|
||||
##[1:9] ping_ok_o,
|
||||
clk_i, !rst_ni || error_present || init_pending)
|
||||
`ASSERT(AlertPingIgnored_A, (prim_alert_rxtx_fpv.i_prim_alert_sender.state_q inside {
|
||||
prim_alert_rxtx_fpv.i_prim_alert_sender.PingHsPhase1,
|
||||
prim_alert_rxtx_fpv.i_prim_alert_sender.PingHsPhase2}) && $rose(ping_req_i) |->
|
||||
ping_ok_o == 0 throughout ping_req_i [->1], clk_i, !rst_ni || error_present)
|
||||
ping_ok_o == 0 throughout ping_req_i [->1],
|
||||
clk_i, !rst_ni || error_present || init_trig_i == lc_ctrl_pkg::On)
|
||||
// transmission of alerts in case of no collision with ping enable
|
||||
`ASSERT(AlertCheck0_A, !ping_req_i [*3] ##0 ($rose(alert_req_i) || $rose(alert_test_i)) &&
|
||||
(prim_alert_rxtx_fpv.i_prim_alert_sender.state_q ==
|
||||
prim_alert_rxtx_fpv.i_prim_alert_sender.Idle) |=>
|
||||
alert_o, clk_i, !rst_ni || error_present || ping_req_i)
|
||||
alert_o,
|
||||
clk_i, !rst_ni || error_present || ping_req_i || init_pending)
|
||||
// transmission of alerts in the general case which can include continous ping collisions
|
||||
`ASSERT(AlertCheck1_A, alert_req_i || alert_test_i |=>
|
||||
strong(##[1:$] ((prim_alert_rxtx_fpv.i_prim_alert_sender.state_q ==
|
||||
prim_alert_rxtx_fpv.i_prim_alert_sender.Idle) && !ping_req_i) ##1 alert_o),
|
||||
clk_i, !rst_ni || error_present || prim_alert_rxtx_fpv.i_prim_alert_sender.alert_clr)
|
||||
clk_i,
|
||||
!rst_ni || error_present || prim_alert_rxtx_fpv.i_prim_alert_sender.alert_clr ||
|
||||
init_trig_i == lc_ctrl_pkg::On)
|
||||
|
||||
// basic liveness of FSMs in case no errors are present
|
||||
`ASSERT(FsmLivenessSender_A,
|
||||
(prim_alert_rxtx_fpv.i_prim_alert_sender.state_q !=
|
||||
prim_alert_rxtx_fpv.i_prim_alert_sender.Idle) |->
|
||||
strong(##[1:$] (prim_alert_rxtx_fpv.i_prim_alert_sender.state_q ==
|
||||
prim_alert_rxtx_fpv.i_prim_alert_sender.Idle)), clk_i, !rst_ni || error_present)
|
||||
prim_alert_rxtx_fpv.i_prim_alert_sender.Idle)),
|
||||
clk_i, !rst_ni || error_present || init_trig_i == lc_ctrl_pkg::On)
|
||||
`ASSERT(FsmLivenessReceiver_A,
|
||||
(prim_alert_rxtx_fpv.i_prim_alert_receiver.state_q !=
|
||||
prim_alert_rxtx_fpv.i_prim_alert_receiver.Idle) |->
|
||||
strong(##[1:$] (prim_alert_rxtx_fpv.i_prim_alert_receiver.state_q ==
|
||||
prim_alert_rxtx_fpv.i_prim_alert_receiver.Idle)),clk_i, !rst_ni || error_present)
|
||||
prim_alert_rxtx_fpv.i_prim_alert_receiver.Idle)),
|
||||
clk_i, !rst_ni || error_present || init_trig_i == lc_ctrl_pkg::On)
|
||||
|
||||
// check that the in-band reset moves sender FSM into Idle state.
|
||||
`ASSERT(InBandInitFromReceiverToSender_A,
|
||||
init_trig_i == lc_ctrl_pkg::On
|
||||
|->
|
||||
##[1:20] (prim_alert_rxtx_fpv.i_prim_alert_sender.state_q ==
|
||||
prim_alert_rxtx_fpv.i_prim_alert_sender.Idle),
|
||||
clk_i, !rst_ni || error_present)
|
||||
|
||||
endmodule : prim_alert_rxtx_assert_fpv
|
||||
|
|
|
@ -22,6 +22,7 @@ module prim_alert_rxtx_async_assert_fpv (
|
|||
input [1:0] alert_skew_i,
|
||||
// normal I/Os
|
||||
input alert_test_i,
|
||||
input lc_ctrl_pkg::lc_tx_t init_trig_i,
|
||||
input alert_req_i,
|
||||
input alert_ack_o,
|
||||
input alert_state_o,
|
||||
|
@ -36,6 +37,12 @@ module prim_alert_rxtx_async_assert_fpv (
|
|||
ack_err_pi | ack_err_ni |
|
||||
alert_err_pi | alert_err_ni;
|
||||
|
||||
logic init_pending;
|
||||
assign init_pending = init_trig_i == lc_ctrl_pkg::On ||
|
||||
prim_alert_rxtx_async_fpv.i_prim_alert_receiver.state_q inside {
|
||||
prim_alert_rxtx_async_fpv.i_prim_alert_receiver.InitReq,
|
||||
prim_alert_rxtx_async_fpv.i_prim_alert_receiver.InitAckWait};
|
||||
|
||||
// used to check that an error has never occured so far
|
||||
// this is used to check the handshake below. the handshake can lock up
|
||||
// the protocol FSMs causing the handshake to never complete.
|
||||
|
@ -59,10 +66,9 @@ module prim_alert_rxtx_async_assert_fpv (
|
|||
|
||||
// ping will stay high until ping ok received, then it must be deasserted
|
||||
// TODO: this excludes the case where no ping ok will be returned due to an error
|
||||
`ASSUME_FPV(PingDeassert_M, ping_req_i && ping_ok_o |=> !ping_req_i, clk_i, !rst_ni)
|
||||
`ASSUME_FPV(PingDeassert_M, ping_req_i && ping_ok_o |=> !ping_req_i)
|
||||
`ASSUME_FPV(PingEn_M, $rose(ping_req_i) |-> ping_req_i throughout
|
||||
(ping_ok_o || error_present)[->1] ##1 $fell(ping_req_i),
|
||||
clk_i, !rst_ni)
|
||||
(ping_ok_o || error_present)[->1] ##1 $fell(ping_req_i))
|
||||
|
||||
// Note: the sequence lengths of the handshake and the following properties needs to
|
||||
// be parameterized accordingly if different clock ratios are to be used here.
|
||||
|
@ -78,32 +84,32 @@ module prim_alert_rxtx_async_assert_fpv (
|
|||
endsequence
|
||||
|
||||
// note: injected errors may lockup the FSMs, and hence the full HS can
|
||||
// only take place if both FSMs are in a sane state
|
||||
// only take place if both FSMs are in a good state
|
||||
`ASSERT(PingHs_A, ##1 $changed(prim_alert_rxtx_async_fpv.ping_pd) &&
|
||||
(prim_alert_rxtx_async_fpv.i_prim_alert_sender.state_q ==
|
||||
prim_alert_rxtx_async_fpv.i_prim_alert_sender.Idle) &&
|
||||
(prim_alert_rxtx_async_fpv.i_prim_alert_receiver.state_q ==
|
||||
prim_alert_rxtx_async_fpv.i_prim_alert_receiver.Idle) |-> ##[0:5] FullHandshake_S,
|
||||
clk_i, !rst_ni || error_setreg_q)
|
||||
clk_i, !rst_ni || error_setreg_q || init_pending)
|
||||
`ASSERT(AlertHs_A, alert_req_i &&
|
||||
(prim_alert_rxtx_async_fpv.i_prim_alert_sender.state_q ==
|
||||
prim_alert_rxtx_async_fpv.i_prim_alert_sender.Idle) &&
|
||||
(prim_alert_rxtx_async_fpv.i_prim_alert_receiver.state_q ==
|
||||
prim_alert_rxtx_async_fpv.i_prim_alert_receiver.Idle) |-> ##[0:5] FullHandshake_S,
|
||||
clk_i, !rst_ni || error_setreg_q)
|
||||
clk_i, !rst_ni || error_setreg_q || init_pending)
|
||||
`ASSERT(AlertTestHs_A, alert_test_i &&
|
||||
(prim_alert_rxtx_async_fpv.i_prim_alert_sender.state_q ==
|
||||
prim_alert_rxtx_async_fpv.i_prim_alert_sender.Idle) &&
|
||||
(prim_alert_rxtx_async_fpv.i_prim_alert_receiver.state_q ==
|
||||
prim_alert_rxtx_async_fpv.i_prim_alert_receiver.Idle) |-> ##[0:5] FullHandshake_S,
|
||||
clk_i, !rst_ni || error_setreg_q)
|
||||
clk_i, !rst_ni || error_setreg_q || init_pending)
|
||||
// Make sure we eventually get an ACK
|
||||
`ASSERT(AlertReqAck_A, alert_req_i &&
|
||||
(prim_alert_rxtx_async_fpv.i_prim_alert_sender.state_q ==
|
||||
prim_alert_rxtx_async_fpv.i_prim_alert_sender.Idle) &&
|
||||
(prim_alert_rxtx_async_fpv.i_prim_alert_receiver.state_q ==
|
||||
prim_alert_rxtx_async_fpv.i_prim_alert_receiver.Idle) |-> strong(##[1:$] alert_ack_o),
|
||||
clk_i, !rst_ni || error_setreg_q)
|
||||
clk_i, !rst_ni || error_setreg_q || init_pending)
|
||||
|
||||
// transmission of pings
|
||||
// this bound is relatively large as in the worst case, we need to resolve
|
||||
|
@ -112,34 +118,47 @@ module prim_alert_rxtx_async_assert_fpv (
|
|||
`ASSERT(AlertPingOk_A, !(prim_alert_rxtx_async_fpv.i_prim_alert_sender.state_q inside {
|
||||
prim_alert_rxtx_async_fpv.i_prim_alert_sender.PingHsPhase1,
|
||||
prim_alert_rxtx_async_fpv.i_prim_alert_sender.PingHsPhase2}) && $rose(ping_req_i) |->
|
||||
##[1:23] ping_ok_o, clk_i, !rst_ni || error_setreg_q)
|
||||
##[1:23] ping_ok_o,
|
||||
clk_i, !rst_ni || error_setreg_q || init_pending)
|
||||
`ASSERT(AlertPingIgnored_A, (prim_alert_rxtx_async_fpv.i_prim_alert_sender.state_q inside {
|
||||
prim_alert_rxtx_async_fpv.i_prim_alert_sender.PingHsPhase1,
|
||||
prim_alert_rxtx_async_fpv.i_prim_alert_sender.PingHsPhase2}) && $rose(ping_req_i) |->
|
||||
ping_ok_o == 0 throughout ping_req_i[->1], clk_i, !rst_ni || error_setreg_q)
|
||||
ping_ok_o == 0 throughout ping_req_i[->1],
|
||||
clk_i, !rst_ni || error_setreg_q)
|
||||
// transmission of first alert assertion (no ping collision)
|
||||
`ASSERT(AlertCheck0_A, !ping_req_i [*10] ##1 ($rose(alert_req_i) || $rose(alert_test_i)) &&
|
||||
(prim_alert_rxtx_async_fpv.i_prim_alert_sender.state_q ==
|
||||
prim_alert_rxtx_async_fpv.i_prim_alert_sender.Idle) |->
|
||||
##[3:5] alert_o, clk_i, !rst_ni || ping_req_i || error_setreg_q)
|
||||
##[3:5] alert_o,
|
||||
clk_i, !rst_ni || ping_req_i || error_setreg_q || init_pending)
|
||||
// eventual transmission of alerts in the general case which can include continous ping
|
||||
// collisions
|
||||
`ASSERT(AlertCheck1_A, alert_req_i || alert_test_i |->
|
||||
strong(##[1:$] (prim_alert_rxtx_async_fpv.i_prim_alert_sender.state_q ==
|
||||
prim_alert_rxtx_async_fpv.i_prim_alert_sender.Idle && !ping_req_i) ##[3:5] alert_o),
|
||||
clk_i, !rst_ni || error_setreg_q ||
|
||||
prim_alert_rxtx_async_fpv.i_prim_alert_sender.alert_clr)
|
||||
prim_alert_rxtx_async_fpv.i_prim_alert_sender.alert_clr || init_pending)
|
||||
|
||||
// basic liveness of FSMs in case no errors are present
|
||||
`ASSERT(FsmLivenessSender_A, !error_present [*2] ##1 !error_present &&
|
||||
(prim_alert_rxtx_async_fpv.i_prim_alert_sender.state_q !=
|
||||
prim_alert_rxtx_async_fpv.i_prim_alert_sender.Idle) |->
|
||||
strong(##[1:$] (prim_alert_rxtx_async_fpv.i_prim_alert_sender.state_q ==
|
||||
prim_alert_rxtx_async_fpv.i_prim_alert_sender.Idle)), clk_i, !rst_ni || error_present)
|
||||
prim_alert_rxtx_async_fpv.i_prim_alert_sender.Idle)),
|
||||
clk_i, !rst_ni || error_present || init_pending)
|
||||
`ASSERT(FsmLivenessReceiver_A, !error_present [*2] ##1 !error_present &&
|
||||
(prim_alert_rxtx_async_fpv.i_prim_alert_receiver.state_q !=
|
||||
prim_alert_rxtx_async_fpv.i_prim_alert_receiver.Idle) |->
|
||||
strong(##[1:$] (prim_alert_rxtx_async_fpv.i_prim_alert_receiver.state_q ==
|
||||
prim_alert_rxtx_async_fpv.i_prim_alert_receiver.Idle)),clk_i, !rst_ni || error_present)
|
||||
prim_alert_rxtx_async_fpv.i_prim_alert_receiver.Idle)),
|
||||
clk_i, !rst_ni || error_present || init_pending)
|
||||
|
||||
// check that the in-band reset moves sender FSM into Idle state.
|
||||
`ASSERT(InBandInitFromReceiverToSender_A,
|
||||
init_trig_i == lc_ctrl_pkg::On
|
||||
|->
|
||||
##[1:30] (prim_alert_rxtx_async_fpv.i_prim_alert_sender.state_q ==
|
||||
prim_alert_rxtx_async_fpv.i_prim_alert_sender.Idle),
|
||||
clk_i, !rst_ni || error_present)
|
||||
|
||||
endmodule : prim_alert_rxtx_async_assert_fpv
|
||||
|
|
|
@ -20,7 +20,7 @@ module prim_esc_rxtx_assert_fpv (
|
|||
input ping_req_i,
|
||||
input ping_ok_o,
|
||||
input integ_fail_o,
|
||||
input esc_en_o
|
||||
input esc_req_o
|
||||
);
|
||||
|
||||
logic error_present;
|
||||
|
@ -103,7 +103,7 @@ module prim_esc_rxtx_assert_fpv (
|
|||
`ASSERT(EscCheck_A,
|
||||
##1 esc_req_i
|
||||
|->
|
||||
##[0:1] esc_en_o,
|
||||
##[0:1] esc_req_o,
|
||||
clk_i,
|
||||
!rst_ni ||
|
||||
error_present)
|
||||
|
@ -143,10 +143,10 @@ module prim_esc_rxtx_assert_fpv (
|
|||
`ASSERT(AutoEscalation0_A,
|
||||
ping_req_i &&
|
||||
ping_ok_o &&
|
||||
!esc_en_o ##1
|
||||
!esc_req_o ##1
|
||||
!ping_req_i [*0 : 2**prim_esc_rxtx_fpv.u_prim_esc_receiver.TimeoutCntDw - 4]
|
||||
|->
|
||||
!esc_en_o,
|
||||
!esc_req_o,
|
||||
clk_i,
|
||||
!rst_ni ||
|
||||
error_d ||
|
||||
|
@ -157,10 +157,10 @@ module prim_esc_rxtx_assert_fpv (
|
|||
`ASSERT(AutoEscalation1_A,
|
||||
ping_req_i &&
|
||||
ping_ok_o &&
|
||||
!esc_en_o ##1
|
||||
!esc_req_o ##1
|
||||
!ping_req_i [* 2**prim_esc_rxtx_fpv.u_prim_esc_receiver.TimeoutCntDw - 3 : $]
|
||||
|->
|
||||
esc_en_o,
|
||||
esc_req_o,
|
||||
clk_i,
|
||||
!rst_ni ||
|
||||
error_d ||
|
||||
|
|
|
@ -73,7 +73,7 @@ module prim_fifo_sync_assert_fpv #(
|
|||
|
||||
if (Pass) begin : gen_pass
|
||||
assign ref_rdata = (ref_depth == 0) ? wdata_i : fifo;
|
||||
end else begin : no_pass
|
||||
end else begin : gen_no_pass
|
||||
assign ref_rdata = fifo;
|
||||
end
|
||||
|
||||
|
@ -119,7 +119,7 @@ module prim_fifo_sync_assert_fpv #(
|
|||
|
||||
if (Pass) begin : gen_pass
|
||||
assign ref_rdata = (ref_depth == 0) ? wdata_i : fifo[rptr];
|
||||
end else begin : no_pass
|
||||
end else begin : gen_no_pass
|
||||
assign ref_rdata = fifo[rptr];
|
||||
end
|
||||
|
||||
|
@ -150,7 +150,8 @@ module prim_fifo_sync_assert_fpv #(
|
|||
// this is unreachable in depth 1 no-pass through mode
|
||||
if (Depth == 1 && Pass) begin : gen_d1_passthru
|
||||
// check simultaneous write and read
|
||||
`ASSERT(WriteAndRead_A, wready_o && wvalid_i && rvalid_o && rready_i |=> depth_o == $past(depth_o),
|
||||
`ASSERT(WriteAndRead_A,
|
||||
wready_o && wvalid_i && rvalid_o && rready_i |=> depth_o == $past(depth_o),
|
||||
clk_i, !rst_ni || clr_i)
|
||||
end
|
||||
|
||||
|
|
12
vendor/lowrisc_ip/ip/prim/lint/prim.waiver
vendored
12
vendor/lowrisc_ip/ip/prim/lint/prim.waiver
vendored
|
@ -4,14 +4,6 @@
|
|||
#
|
||||
# waiver file for prim
|
||||
|
||||
# prim_assert
|
||||
waive -rules {UNDEF_MACRO_REF} -location {prim_assert.sv} -regexp {Macro definition for 'ASSERT_RPT' includes expansion of undefined macro '__(FILE|LINE)__'} \
|
||||
-comment "This is an UVM specific macro inside our assertion shortcuts"
|
||||
# unfortunately most tools do not support line wrapping within the declaration of macro functions, hence we have to waive
|
||||
# line length violations.
|
||||
waive -rules {LINE_LENGTH} -location {prim_assert.sv} -msg {Line length of} \
|
||||
-comment "Some macros cannot be line-wrapped, as some tools do not support that."
|
||||
|
||||
# prim_packer
|
||||
waive -rules INTEGER -location {prim_packer.sv} -msg {'i' of type int used as a non-constant value} \
|
||||
-comment "This assigns int i (signed) to a multibit logic variable (unsigned), which is fine"
|
||||
|
@ -28,3 +20,7 @@ waive -rules {HIER_BRANCH_NOT_READ} -location {tlul_fifo_sync.sv} -regexp {Conne
|
|||
#
|
||||
#waive -rules NOT_READ -location {prim_ram_*_wrapper*} -regexp {(a|b)_rdata_(q|d)\[38} \
|
||||
# -comment "Syndrome is not going out to the interface"
|
||||
|
||||
# prim_sram_arbiter
|
||||
waive -rules CONST_OUTPUT -location {prim_sram_arbiter.sv} -regexp {rsp_error.* is driven by constant} \
|
||||
-comment "SRAM protection is not yet implemented"
|
||||
|
|
|
@ -9,8 +9,5 @@ waive -rules PARTIAL_CONST_ASSIGN -location {prim_arbiter_*.sv} -regexp {'mask.0
|
|||
waive -rules CONST_FF -location {prim_arbiter_*.sv} -regexp {Flip-flop 'mask.0.' is driven by constant} \
|
||||
-comment "makes the code more readable"
|
||||
|
||||
waive -rules CONST_OUTPUT -location {prim_sram_arbiter.sv} -regexp {rsp_error.* is driven by constant} \
|
||||
-comment "SRAM protection is not yet implemented"
|
||||
|
||||
waive -rules {HIER_BRANCH_NOT_READ INPUT_NOT_READ} -location {prim_arbiter_fixed.sv} -regexp {.*'(clk_i|rst_ni)' is not read from in module 'prim_arbiter_fixed'.*} \
|
||||
-comment "clk_ and rst_ni are only used for assertions in this module."
|
||||
|
|
5
vendor/lowrisc_ip/ip/prim/lint/prim_assert.vlt
vendored
Normal file
5
vendor/lowrisc_ip/ip/prim/lint/prim_assert.vlt
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
`verilator_config
|
12
vendor/lowrisc_ip/ip/prim/lint/prim_assert.waiver
vendored
Normal file
12
vendor/lowrisc_ip/ip/prim/lint/prim_assert.waiver
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
# Copyright lowRISC contributors.
|
||||
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# waiver file for prim_assert
|
||||
|
||||
waive -rules {UNDEF_MACRO_REF} -location {prim_assert.sv} -regexp {Macro definition for 'ASSERT_RPT' includes expansion of undefined macro '__(FILE|LINE)__'} \
|
||||
-comment "This is an UVM specific macro inside our assertion shortcuts"
|
||||
# unfortunately most tools do not support line wrapping within the declaration of macro functions, hence we have to waive
|
||||
# line length violations.
|
||||
waive -rules {LINE_LENGTH} -location {prim_assert.sv} -msg {Line length of} \
|
||||
-comment "Some macros cannot be line-wrapped, as some tools do not support that."
|
|
@ -24,3 +24,8 @@ waive -rules VAR_INDEX_RANGE -location {prim_fifo_*sync.sv} -regexp {maximu
|
|||
|
||||
waive -rules EXPLICIT_BITLEN -location {prim_fifo_*sync.sv} -regexp {Bit length not specified for constant '1'} \
|
||||
-comment "index is protected by control logic"
|
||||
|
||||
## prim_fifo_async_sram_adapter
|
||||
waive -rules ARITH_CONTEXT -location {prim_fifo_async_sram_adapter.sv} \
|
||||
-regexp {(r|w)_wptr_v.*_rptr_v} \
|
||||
-comment "The pointer value width is determined. Remove the casting for readability"
|
||||
|
|
8
vendor/lowrisc_ip/ip/prim/lint/prim_xor2.waiver
vendored
Normal file
8
vendor/lowrisc_ip/ip/prim/lint/prim_xor2.waiver
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
# Copyright lowRISC contributors.
|
||||
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# waiver file for prim_xor2
|
||||
|
||||
waive -rules {STAR_PORT_CONN_USE} -location {prim_xor2.sv} -regexp {.*wild card port connection encountered on instance.*} \
|
||||
-comment "Generated prims may have wildcard connections."
|
1
vendor/lowrisc_ip/ip/prim/prim_alert.core
vendored
1
vendor/lowrisc_ip/ip/prim/prim_alert.core
vendored
|
@ -12,6 +12,7 @@ filesets:
|
|||
- lowrisc:prim:diff_decode
|
||||
- lowrisc:prim:buf
|
||||
- lowrisc:prim:flop
|
||||
- lowrisc:ip:lc_ctrl_pkg
|
||||
files:
|
||||
- rtl/prim_alert_pkg.sv
|
||||
- rtl/prim_alert_receiver.sv
|
||||
|
|
24
vendor/lowrisc_ip/ip/prim/prim_assert.core
vendored
24
vendor/lowrisc_ip/ip/prim/prim_assert.core
vendored
|
@ -14,7 +14,31 @@ filesets:
|
|||
- rtl/prim_assert_standard_macros.svh : {is_include_file : true}
|
||||
file_type: systemVerilogSource
|
||||
|
||||
files_verilator_waiver:
|
||||
depend:
|
||||
# common waivers
|
||||
- lowrisc:lint:common
|
||||
files:
|
||||
- lint/prim_assert.vlt
|
||||
file_type: vlt
|
||||
|
||||
files_ascentlint_waiver:
|
||||
depend:
|
||||
# common waivers
|
||||
- lowrisc:lint:common
|
||||
files:
|
||||
- lint/prim_assert.waiver
|
||||
file_type: waiver
|
||||
|
||||
files_veriblelint_waiver:
|
||||
depend:
|
||||
# common waivers
|
||||
- lowrisc:lint:common
|
||||
|
||||
targets:
|
||||
default:
|
||||
filesets:
|
||||
- tool_verilator ? (files_verilator_waiver)
|
||||
- tool_ascentlint ? (files_ascentlint_waiver)
|
||||
- tool_veriblelint ? (files_veriblelint_waiver)
|
||||
- files_rtl
|
||||
|
|
21
vendor/lowrisc_ip/ip/prim/prim_clock_meas.core
vendored
Normal file
21
vendor/lowrisc_ip/ip/prim/prim_clock_meas.core
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
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:prim:measure"
|
||||
description: "Clock measurement"
|
||||
filesets:
|
||||
files_rtl:
|
||||
depend:
|
||||
- lowrisc:prim:all
|
||||
- lowrisc:prim:flop_2sync
|
||||
- lowrisc:prim:assert
|
||||
files:
|
||||
- rtl/prim_clock_meas.sv
|
||||
file_type: systemVerilogSource
|
||||
|
||||
targets:
|
||||
default:
|
||||
filesets:
|
||||
- files_rtl
|
38
vendor/lowrisc_ip/ip/prim/prim_count.core
vendored
Normal file
38
vendor/lowrisc_ip/ip/prim/prim_count.core
vendored
Normal file
|
@ -0,0 +1,38 @@
|
|||
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:prim:count"
|
||||
description: ""
|
||||
filesets:
|
||||
files_rtl:
|
||||
depend:
|
||||
- lowrisc:prim:assert
|
||||
- lowrisc:prim:count_pkg:0.1
|
||||
files:
|
||||
- rtl/prim_count.sv
|
||||
file_type: systemVerilogSource
|
||||
|
||||
files_verilator_waiver:
|
||||
depend:
|
||||
# common waivers
|
||||
- lowrisc:lint:common
|
||||
|
||||
files_ascentlint_waiver:
|
||||
depend:
|
||||
# common waivers
|
||||
- lowrisc:lint:common
|
||||
|
||||
files_veriblelint_waiver:
|
||||
depend:
|
||||
# common waivers
|
||||
- lowrisc:lint:common
|
||||
|
||||
targets:
|
||||
default:
|
||||
filesets:
|
||||
- tool_verilator ? (files_verilator_waiver)
|
||||
- tool_ascentlint ? (files_ascentlint_waiver)
|
||||
- tool_veriblelint ? (files_veriblelint_waiver)
|
||||
- files_rtl
|
37
vendor/lowrisc_ip/ip/prim/prim_count_pkg.core
vendored
Normal file
37
vendor/lowrisc_ip/ip/prim/prim_count_pkg.core
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
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:prim:count_pkg:0.1"
|
||||
description: "Hardened counter package"
|
||||
filesets:
|
||||
files_rtl:
|
||||
files:
|
||||
- rtl/prim_count_pkg.sv
|
||||
file_type: systemVerilogSource
|
||||
|
||||
files_verilator_waiver:
|
||||
depend:
|
||||
# common waivers
|
||||
- lowrisc:lint:common
|
||||
|
||||
files_ascentlint_waiver:
|
||||
depend:
|
||||
# common waivers
|
||||
- lowrisc:lint:common
|
||||
files:
|
||||
file_type: waiver
|
||||
|
||||
files_veriblelint_waiver:
|
||||
depend:
|
||||
# common waivers
|
||||
- lowrisc:lint:common
|
||||
|
||||
targets:
|
||||
default:
|
||||
filesets:
|
||||
- tool_verilator ? (files_verilator_waiver)
|
||||
- tool_ascentlint ? (files_ascentlint_waiver)
|
||||
- tool_veriblelint ? (files_veriblelint_waiver)
|
||||
- files_rtl
|
|
@ -9,6 +9,7 @@ filesets:
|
|||
files_rtl:
|
||||
depend:
|
||||
- lowrisc:prim:assert
|
||||
- lowrisc:prim:flop_2sync
|
||||
files:
|
||||
- rtl/prim_diff_decode.sv
|
||||
file_type: systemVerilogSource
|
||||
|
|
44
vendor/lowrisc_ip/ip/prim/prim_edge_detector.core
vendored
Normal file
44
vendor/lowrisc_ip/ip/prim/prim_edge_detector.core
vendored
Normal file
|
@ -0,0 +1,44 @@
|
|||
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:prim:edge_detector:0.1"
|
||||
description: "Positive/ Negative Edge detector"
|
||||
filesets:
|
||||
files_rtl:
|
||||
depend:
|
||||
- lowrisc:prim:assert
|
||||
- lowrisc:prim:flop_2sync
|
||||
files:
|
||||
- rtl/prim_edge_detector.sv
|
||||
file_type: systemVerilogSource
|
||||
|
||||
files_verilator_waiver:
|
||||
depend:
|
||||
# common waivers
|
||||
- lowrisc:lint:common
|
||||
files:
|
||||
- lint/prim.vlt
|
||||
file_type: vlt
|
||||
|
||||
files_ascentlint_waiver:
|
||||
depend:
|
||||
# common waivers
|
||||
- lowrisc:lint:common
|
||||
files:
|
||||
- lint/prim.waiver
|
||||
file_type: waiver
|
||||
|
||||
files_veriblelint_waiver:
|
||||
depend:
|
||||
# common waivers
|
||||
- lowrisc:lint:common
|
||||
|
||||
targets:
|
||||
default:
|
||||
filesets:
|
||||
- tool_verilator ? (files_verilator_waiver)
|
||||
- tool_ascentlint ? (files_ascentlint_waiver)
|
||||
- tool_veriblelint ? (files_veriblelint_waiver)
|
||||
- files_rtl
|
1
vendor/lowrisc_ip/ip/prim/prim_fifo.core
vendored
1
vendor/lowrisc_ip/ip/prim/prim_fifo.core
vendored
|
@ -12,6 +12,7 @@ filesets:
|
|||
- lowrisc:prim:util
|
||||
- lowrisc:prim:flop_2sync
|
||||
files:
|
||||
- rtl/prim_fifo_async_sram_adapter.sv
|
||||
- rtl/prim_fifo_async.sv
|
||||
- rtl/prim_fifo_sync.sv
|
||||
file_type: systemVerilogSource
|
||||
|
|
53
vendor/lowrisc_ip/ip/prim/prim_lc_combine.core
vendored
Normal file
53
vendor/lowrisc_ip/ip/prim/prim_lc_combine.core
vendored
Normal file
|
@ -0,0 +1,53 @@
|
|||
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:prim:lc_combine:0.1"
|
||||
description: "Logic combination of life cycle control signals."
|
||||
filesets:
|
||||
files_rtl:
|
||||
depend:
|
||||
- lowrisc:ip:lc_ctrl_pkg
|
||||
files:
|
||||
- rtl/prim_lc_combine.sv
|
||||
file_type: systemVerilogSource
|
||||
|
||||
files_verilator_waiver:
|
||||
depend:
|
||||
# common waivers
|
||||
- lowrisc:lint:common
|
||||
files:
|
||||
file_type: vlt
|
||||
|
||||
files_ascentlint_waiver:
|
||||
depend:
|
||||
# common waivers
|
||||
- lowrisc:lint:common
|
||||
files:
|
||||
# - lint/prim_lc_combine.waiver
|
||||
file_type: waiver
|
||||
|
||||
files_veriblelint_waiver:
|
||||
depend:
|
||||
# common waivers
|
||||
- lowrisc:lint:common
|
||||
|
||||
targets:
|
||||
default: &default_target
|
||||
filesets:
|
||||
- tool_verilator ? (files_verilator_waiver)
|
||||
- tool_ascentlint ? (files_ascentlint_waiver)
|
||||
- tool_veriblelint ? (files_veriblelint_waiver)
|
||||
- files_rtl
|
||||
|
||||
lint:
|
||||
<<: *default_target
|
||||
default_tool: verilator
|
||||
parameters:
|
||||
- SYNTHESIS=true
|
||||
tools:
|
||||
verilator:
|
||||
mode: lint-only
|
||||
verilator_options:
|
||||
- "-Wall"
|
1
vendor/lowrisc_ip/ip/prim/prim_lfsr.core
vendored
1
vendor/lowrisc_ip/ip/prim/prim_lfsr.core
vendored
|
@ -9,6 +9,7 @@ filesets:
|
|||
files_rtl:
|
||||
depend:
|
||||
- lowrisc:prim:assert
|
||||
- lowrisc:prim:cipher_pkg
|
||||
files:
|
||||
- rtl/prim_lfsr.sv
|
||||
file_type: systemVerilogSource
|
||||
|
|
17
vendor/lowrisc_ip/ip/prim/prim_mubi.core
vendored
Normal file
17
vendor/lowrisc_ip/ip/prim/prim_mubi.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:prim:mubi:0.1"
|
||||
description: "Multibit types and functions"
|
||||
filesets:
|
||||
files_rtl:
|
||||
files:
|
||||
- rtl/prim_mubi_pkg.sv
|
||||
file_type: systemVerilogSource
|
||||
|
||||
targets:
|
||||
default:
|
||||
filesets:
|
||||
- files_rtl
|
5
vendor/lowrisc_ip/ip/prim/prim_subreg.core
vendored
5
vendor/lowrisc_ip/ip/prim/prim_subreg.core
vendored
|
@ -8,9 +8,14 @@ description: "Register slices"
|
|||
filesets:
|
||||
files_rtl:
|
||||
files:
|
||||
- rtl/prim_subreg_pkg.sv
|
||||
- rtl/prim_subreg_arb.sv
|
||||
- rtl/prim_subreg_cdc.sv
|
||||
- rtl/prim_reg_cdc.sv
|
||||
- rtl/prim_subreg.sv
|
||||
- rtl/prim_subreg_async.sv
|
||||
- rtl/prim_subreg_ext.sv
|
||||
- rtl/prim_subreg_ext_async.sv
|
||||
- rtl/prim_subreg_shadow.sv
|
||||
file_type: systemVerilogSource
|
||||
|
||||
|
|
2
vendor/lowrisc_ip/ip/prim/prim_xor2.core
vendored
2
vendor/lowrisc_ip/ip/prim/prim_xor2.core
vendored
|
@ -22,6 +22,8 @@ filesets:
|
|||
depend:
|
||||
# common waivers
|
||||
- lowrisc:lint:common
|
||||
files:
|
||||
- lint/prim_xor2.waiver
|
||||
file_type: waiver
|
||||
|
||||
files_veriblelint_waiver:
|
||||
|
|
173
vendor/lowrisc_ip/ip/prim/rtl/prim_alert_receiver.sv
vendored
173
vendor/lowrisc_ip/ip/prim/rtl/prim_alert_receiver.sv
vendored
|
@ -37,6 +37,9 @@ module prim_alert_receiver
|
|||
) (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
// if set to lc_ctrl_pkg::On, this triggers the in-band alert channel
|
||||
// reset, which resets both the sender and receiver FSMs into IDLE.
|
||||
input lc_ctrl_pkg::lc_tx_t init_trig_i,
|
||||
// this triggers a ping test. keep asserted
|
||||
// until ping_ok_o is asserted.
|
||||
input ping_req_i,
|
||||
|
@ -85,22 +88,25 @@ module prim_alert_receiver
|
|||
/////////////////////////////////////////////////////
|
||||
// main protocol FSM that drives the diff outputs //
|
||||
/////////////////////////////////////////////////////
|
||||
typedef enum logic [1:0] {Idle, HsAckWait, Pause0, Pause1} state_e;
|
||||
typedef enum logic [2:0] {Idle, HsAckWait, Pause0, Pause1, InitReq, InitAckWait} state_e;
|
||||
state_e state_d, state_q;
|
||||
logic ping_rise;
|
||||
logic ping_tog_pd, ping_tog_pq, ping_tog_dn, ping_tog_nq;
|
||||
logic ack_pd, ack_pq, ack_dn, ack_nq;
|
||||
logic ping_req_d, ping_req_q;
|
||||
logic ping_pending_d, ping_pending_q;
|
||||
logic send_init;
|
||||
|
||||
// signal ping request upon positive transition on ping_req_i
|
||||
// signalling is performed by a level change event on the diff output
|
||||
assign ping_req_d = ping_req_i;
|
||||
assign ping_rise = ping_req_i && !ping_req_q;
|
||||
assign ping_tog_pd = (ping_rise) ? ~ping_tog_pq : ping_tog_pq;
|
||||
assign ping_tog_pd = (send_init) ? 1'b0 :
|
||||
(ping_rise) ? ~ping_tog_pq : ping_tog_pq;
|
||||
|
||||
assign ack_dn = ~ack_pd;
|
||||
assign ping_tog_dn = ~ping_tog_pd;
|
||||
// in-band reset is performed by sending out an integrity error on purpose.
|
||||
assign ack_dn = (send_init) ? ack_pd : ~ack_pd;
|
||||
assign ping_tog_dn = (send_init) ? ping_tog_pd : ~ping_tog_pd;
|
||||
|
||||
// This prevents further tool optimizations of the differential signal.
|
||||
prim_generic_flop #(
|
||||
|
@ -152,6 +158,7 @@ module prim_alert_receiver
|
|||
ping_ok_o = 1'b0;
|
||||
integ_fail_o = 1'b0;
|
||||
alert_o = 1'b0;
|
||||
send_init = 1'b0;
|
||||
|
||||
unique case (state_q)
|
||||
Idle: begin
|
||||
|
@ -178,22 +185,62 @@ module prim_alert_receiver
|
|||
// pause cycles between back-to-back handshakes
|
||||
Pause0: state_d = Pause1;
|
||||
Pause1: state_d = Idle;
|
||||
default : ; // full case
|
||||
// this state is only reached if an in-band reset is
|
||||
// requested via the low-power logic.
|
||||
InitReq: begin
|
||||
// we deliberately place a sigint error on the ack and ping lines in this case.
|
||||
send_init = 1'b1;
|
||||
// As long as init req is asserted, we remain in this state and acknowledge all incoming
|
||||
// ping requests. As soon as the init request is dropped however, ping requests are not
|
||||
// acked anymore such that the ping mechanism can also flag alert channels that got stuck
|
||||
// in the initialization sequence.
|
||||
if (init_trig_i == lc_ctrl_pkg::On) begin
|
||||
ping_ok_o = ping_pending_q;
|
||||
// the sender will respond to the sigint error above with a sigint error on the alert lines.
|
||||
// hence we treat the alert_sigint like an acknowledgement in this case.
|
||||
end else if (alert_sigint) begin
|
||||
state_d = InitAckWait;
|
||||
end
|
||||
end
|
||||
// We get here if the sender has responded with alert_sigint, and init_trig_i==lc_ctrl_pkg::On
|
||||
// has been deasserted. At this point, we need to wait for the alert_sigint to drop again
|
||||
// before resuming normal operation.
|
||||
InitAckWait: begin
|
||||
if (!alert_sigint) begin
|
||||
state_d = Pause0;
|
||||
end
|
||||
end
|
||||
default: state_d = Idle;
|
||||
endcase
|
||||
|
||||
// override in case of sigint
|
||||
if (alert_sigint) begin
|
||||
state_d = Idle;
|
||||
ack_pd = 1'b0;
|
||||
ping_ok_o = 1'b0;
|
||||
integ_fail_o = 1'b1;
|
||||
alert_o = 1'b0;
|
||||
// once the initialization sequence has been triggered,
|
||||
// overrides are not allowed anymore until the initialization has been completed.
|
||||
if (!(state_q inside {InitReq, InitAckWait})) begin
|
||||
// in this case, abort and jump into the initialization sequence
|
||||
if (init_trig_i == lc_ctrl_pkg::On) begin
|
||||
state_d = InitReq;
|
||||
ack_pd = 1'b0;
|
||||
ping_ok_o = 1'b0;
|
||||
integ_fail_o = 1'b0;
|
||||
alert_o = 1'b0;
|
||||
send_init = 1'b1;
|
||||
// if we're not busy with an init request, we clamp down all outputs
|
||||
// and indicate an integrity failure.
|
||||
end else if (alert_sigint) begin
|
||||
state_d = Idle;
|
||||
ack_pd = 1'b0;
|
||||
ping_ok_o = 1'b0;
|
||||
integ_fail_o = 1'b1;
|
||||
alert_o = 1'b0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin : p_reg
|
||||
if (!rst_ni) begin
|
||||
state_q <= Idle;
|
||||
// Reset into the init request so that an alert handler reset implicitly
|
||||
// triggers an in-band reset of all alert channels.
|
||||
state_q <= InitReq;
|
||||
ping_req_q <= 1'b0;
|
||||
ping_pending_q <= 1'b0;
|
||||
end else begin
|
||||
|
@ -214,11 +261,13 @@ module prim_alert_receiver
|
|||
`ASSERT_KNOWN(AlertKnownO_A, alert_o)
|
||||
`ASSERT_KNOWN(PingPKnownO_A, alert_rx_o)
|
||||
|
||||
// check encoding of outgoing diffpairs
|
||||
`ASSERT(PingDiffOk_A, alert_rx_o.ping_p ^ alert_rx_o.ping_n)
|
||||
`ASSERT(AckDiffOk_A, alert_rx_o.ack_p ^ alert_rx_o.ack_n)
|
||||
// check encoding of outgoing diffpairs. note that during init, the outgoing diffpairs are
|
||||
// supposed to be incorrectly encoded on purpose.
|
||||
// shift sequence two cycles to the right to avoid reset effects.
|
||||
`ASSERT(PingDiffOk_A, ##2 $past(send_init) ^ alert_rx_o.ping_p ^ alert_rx_o.ping_n)
|
||||
`ASSERT(AckDiffOk_A, ##2 $past(send_init) ^ alert_rx_o.ack_p ^ alert_rx_o.ack_n)
|
||||
// ping request at input -> need to see encoded ping request
|
||||
`ASSERT(PingRequest0_A, ##1 $rose(ping_req_i) |=> $changed(alert_rx_o.ping_p))
|
||||
`ASSERT(PingRequest0_A, ##1 $rose(ping_req_i) && !send_init |=> $changed(alert_rx_o.ping_p))
|
||||
// ping response implies it has been requested
|
||||
`ASSERT(PingResponse0_A, ping_ok_o |-> ping_pending_q)
|
||||
// correctly latch ping request
|
||||
|
@ -226,25 +275,91 @@ module prim_alert_receiver
|
|||
|
||||
if (AsyncOn) begin : gen_async_assert
|
||||
// signal integrity check propagation
|
||||
`ASSERT(SigInt_A, alert_tx_i.alert_p == alert_tx_i.alert_n [*2] |->
|
||||
##2 integ_fail_o)
|
||||
`ASSERT(SigInt_A,
|
||||
alert_tx_i.alert_p == alert_tx_i.alert_n [*2] ##2
|
||||
!(state_q inside {InitReq, InitAckWait}) &&
|
||||
init_trig_i != lc_ctrl_pkg::On
|
||||
|->
|
||||
integ_fail_o)
|
||||
// TODO: need to add skewed cases as well, the assertions below assume no skew at the moment
|
||||
// ping response
|
||||
`ASSERT(PingResponse1_A, ##1 $rose(alert_tx_i.alert_p) &&
|
||||
(alert_tx_i.alert_p ^ alert_tx_i.alert_n) ##2 state_q == Idle && ping_pending_q |->
|
||||
ping_ok_o, clk_i, !rst_ni || integ_fail_o)
|
||||
`ASSERT(PingResponse1_A,
|
||||
##1 $rose(alert_tx_i.alert_p) &&
|
||||
(alert_tx_i.alert_p ^ alert_tx_i.alert_n) ##2
|
||||
state_q == Idle && ping_pending_q
|
||||
|->
|
||||
ping_ok_o,
|
||||
clk_i, !rst_ni || integ_fail_o || init_trig_i == lc_ctrl_pkg::On)
|
||||
// alert
|
||||
`ASSERT(Alert_A, ##1 $rose(alert_tx_i.alert_p) && (alert_tx_i.alert_p ^ alert_tx_i.alert_n) ##2
|
||||
state_q == Idle && !ping_pending_q |-> alert_o, clk_i, !rst_ni || integ_fail_o)
|
||||
`ASSERT(Alert_A,
|
||||
##1 $rose(alert_tx_i.alert_p) &&
|
||||
(alert_tx_i.alert_p ^ alert_tx_i.alert_n) ##2
|
||||
state_q == Idle &&
|
||||
!ping_pending_q
|
||||
|->
|
||||
alert_o,
|
||||
clk_i, !rst_ni || integ_fail_o || init_trig_i == lc_ctrl_pkg::On)
|
||||
end else begin : gen_sync_assert
|
||||
// signal integrity check propagation
|
||||
`ASSERT(SigInt_A, alert_tx_i.alert_p == alert_tx_i.alert_n |-> integ_fail_o)
|
||||
`ASSERT(SigInt_A,
|
||||
alert_tx_i.alert_p == alert_tx_i.alert_n &&
|
||||
!(state_q inside {InitReq, InitAckWait}) &&
|
||||
init_trig_i != lc_ctrl_pkg::On
|
||||
|->
|
||||
integ_fail_o)
|
||||
// ping response
|
||||
`ASSERT(PingResponse1_A, ##1 $rose(alert_tx_i.alert_p) && state_q == Idle && ping_pending_q |->
|
||||
ping_ok_o, clk_i, !rst_ni || integ_fail_o)
|
||||
`ASSERT(PingResponse1_A,
|
||||
##1 $rose(alert_tx_i.alert_p) &&
|
||||
state_q == Idle &&
|
||||
ping_pending_q
|
||||
|->
|
||||
ping_ok_o,
|
||||
clk_i, !rst_ni || integ_fail_o || init_trig_i == lc_ctrl_pkg::On)
|
||||
// alert
|
||||
`ASSERT(Alert_A, ##1 $rose(alert_tx_i.alert_p) && state_q == Idle && !ping_pending_q |->
|
||||
alert_o, clk_i, !rst_ni || integ_fail_o)
|
||||
`ASSERT(Alert_A,
|
||||
##1 $rose(alert_tx_i.alert_p) &&
|
||||
state_q == Idle &&
|
||||
!ping_pending_q
|
||||
|->
|
||||
alert_o,
|
||||
clk_i, !rst_ni || integ_fail_o || init_trig_i == lc_ctrl_pkg::On)
|
||||
end
|
||||
|
||||
// check in-band init request is always accepted
|
||||
`ASSERT(InBandInitRequest_A,
|
||||
init_trig_i == lc_ctrl_pkg::On &&
|
||||
state_q != InitAckWait
|
||||
|=>
|
||||
state_q == InitReq)
|
||||
// check in-band init sequence moves FSM into IDLE state
|
||||
`ASSERT(InBandInitSequence_A,
|
||||
(state_q == InitReq &&
|
||||
init_trig_i == lc_ctrl_pkg::On [*1:$]) ##1
|
||||
(alert_sigint &&
|
||||
init_trig_i != lc_ctrl_pkg::On) [*1:$] ##1
|
||||
(!alert_sigint &&
|
||||
init_trig_i != lc_ctrl_pkg::On) [*3]
|
||||
|=>
|
||||
state_q == Idle)
|
||||
// check there are no spurious alerts during init
|
||||
`ASSERT(NoSpuriousAlertsDuringInit_A,
|
||||
init_trig_i == lc_ctrl_pkg::On ||
|
||||
(state_q inside {InitReq, InitAckWait})
|
||||
|->
|
||||
!alert_o)
|
||||
// check that there are no spurious ping OKs
|
||||
`ASSERT(NoSpuriousPingOksDuringInit_A,
|
||||
(init_trig_i == lc_ctrl_pkg::On ||
|
||||
(state_q inside {InitReq, InitAckWait})) &&
|
||||
!ping_pending_q
|
||||
|->
|
||||
!ping_ok_o)
|
||||
// check ping request is bypassed when in init state
|
||||
`ASSERT(PingOkBypassDuringInit_A,
|
||||
$rose(ping_req_i) ##1
|
||||
state_q == InitReq &&
|
||||
init_trig_i == lc_ctrl_pkg::On
|
||||
|->
|
||||
ping_ok_o)
|
||||
|
||||
endmodule : prim_alert_receiver
|
||||
|
|
|
@ -131,7 +131,6 @@ module prim_alert_sender
|
|||
AlertHsPhase2,
|
||||
PingHsPhase1,
|
||||
PingHsPhase2,
|
||||
SigInt,
|
||||
Pause0,
|
||||
Pause1
|
||||
} state_e;
|
||||
|
@ -234,34 +233,22 @@ module prim_alert_sender
|
|||
Pause0: begin
|
||||
state_d = Pause1;
|
||||
end
|
||||
|
||||
// clear and ack alert request if it was set
|
||||
Pause1: begin
|
||||
state_d = Idle;
|
||||
end
|
||||
|
||||
// we have a signal integrity issue at one of
|
||||
// the incoming diff pairs. this condition is
|
||||
// signalled by setting the output diffpair
|
||||
// to the same value and continuously toggling
|
||||
// them.
|
||||
SigInt: begin
|
||||
state_d = Idle;
|
||||
if (sigint_detected) begin
|
||||
state_d = SigInt;
|
||||
alert_pd = ~alert_pq;
|
||||
alert_nd = ~alert_pq;
|
||||
end
|
||||
end
|
||||
// catch parasitic states
|
||||
default : state_d = Idle;
|
||||
endcase
|
||||
// bail out if a signal integrity issue has been detected
|
||||
if (sigint_detected && (state_q != SigInt)) begin
|
||||
state_d = SigInt;
|
||||
|
||||
// we have a signal integrity issue at one of the incoming diff pairs. this condition is
|
||||
// signalled by setting the output diffpair to zero. If the sigint has disappeared, we clear
|
||||
// the ping request state of this sender and go back to idle.
|
||||
if (sigint_detected) begin
|
||||
state_d = Idle;
|
||||
alert_pd = 1'b0;
|
||||
alert_nd = 1'b0;
|
||||
ping_clr = 1'b0;
|
||||
ping_clr = 1'b1;
|
||||
alert_clr = 1'b0;
|
||||
end
|
||||
end
|
||||
|
@ -296,15 +283,28 @@ module prim_alert_sender
|
|||
// assertions //
|
||||
////////////////
|
||||
|
||||
// however, since we use sequence constructs below, we need to wrap the entire block again.
|
||||
// typically, the ASSERT macros already contain this INC_ASSERT macro.
|
||||
`ifdef INC_ASSERT
|
||||
// check whether all outputs have a good known state after reset
|
||||
`ASSERT_KNOWN(AlertPKnownO_A, alert_tx_o)
|
||||
|
||||
if (AsyncOn) begin : gen_async_assert
|
||||
sequence PingSigInt_S;
|
||||
alert_rx_i.ping_p == alert_rx_i.ping_n [*2];
|
||||
endsequence
|
||||
sequence AckSigInt_S;
|
||||
alert_rx_i.ping_p == alert_rx_i.ping_n [*2];
|
||||
endsequence
|
||||
// check propagation of sigint issues to output within three cycles
|
||||
`ASSERT(SigIntPing_A, alert_rx_i.ping_p == alert_rx_i.ping_n [*2] |->
|
||||
// shift sequence to the right to avoid reset effects.
|
||||
`ASSERT(SigIntPing_A, ##1 PingSigInt_S |->
|
||||
##3 alert_tx_o.alert_p == alert_tx_o.alert_n)
|
||||
`ASSERT(SigIntAck_A, alert_rx_i.ack_p == alert_rx_i.ack_n [*2] |->
|
||||
`ASSERT(SigIntAck_A, ##1 AckSigInt_S |->
|
||||
##3 alert_tx_o.alert_p == alert_tx_o.alert_n)
|
||||
// Test in-band FSM reset request (via signal integrity error)
|
||||
`ASSERT(InBandInitFsm_A, PingSigInt_S or AckSigInt_S |-> ##3 state_q == Idle)
|
||||
`ASSERT(InBandInitPing_A, PingSigInt_S or AckSigInt_S |-> ##3 !ping_set_q)
|
||||
// output must be driven diff unless sigint issue detected
|
||||
`ASSERT(DiffEncoding_A, (alert_rx_i.ack_p ^ alert_rx_i.ack_n) &&
|
||||
(alert_rx_i.ping_p ^ alert_rx_i.ping_n) |->
|
||||
|
@ -318,11 +318,20 @@ module prim_alert_sender
|
|||
(alert_rx_i.ping_p ^ alert_rx_i.ping_n) ##2 state_q == Idle |=>
|
||||
$rose(alert_tx_o.alert_p), clk_i, !rst_ni || (alert_tx_o.alert_p == alert_tx_o.alert_n))
|
||||
end else begin : gen_sync_assert
|
||||
sequence PingSigInt_S;
|
||||
alert_rx_i.ping_p == alert_rx_i.ping_n;
|
||||
endsequence
|
||||
sequence AckSigInt_S;
|
||||
alert_rx_i.ping_p == alert_rx_i.ping_n;
|
||||
endsequence
|
||||
// check propagation of sigint issues to output within one cycle
|
||||
`ASSERT(SigIntPing_A, alert_rx_i.ping_p == alert_rx_i.ping_n |=>
|
||||
`ASSERT(SigIntPing_A, PingSigInt_S |=>
|
||||
alert_tx_o.alert_p == alert_tx_o.alert_n)
|
||||
`ASSERT(SigIntAck_A, alert_rx_i.ack_p == alert_rx_i.ack_n |=>
|
||||
`ASSERT(SigIntAck_A, AckSigInt_S |=>
|
||||
alert_tx_o.alert_p == alert_tx_o.alert_n)
|
||||
// Test in-band FSM reset request (via signal integrity error)
|
||||
`ASSERT(InBandInitFsm_A, PingSigInt_S or AckSigInt_S |=> state_q == Idle)
|
||||
`ASSERT(InBandInitPing_A, PingSigInt_S or AckSigInt_S |=> !ping_set_q)
|
||||
// output must be driven diff unless sigint issue detected
|
||||
`ASSERT(DiffEncoding_A, (alert_rx_i.ack_p ^ alert_rx_i.ack_n) &&
|
||||
(alert_rx_i.ping_p ^ alert_rx_i.ping_n) |=> alert_tx_o.alert_p ^ alert_tx_o.alert_n)
|
||||
|
@ -355,5 +364,6 @@ module prim_alert_sender
|
|||
// if alert_test_i is true, handshakes should be continuously repeated
|
||||
`ASSERT(AlertTestHs_A, alert_test_i && state_q == Idle |=> $rose(alert_tx_o.alert_p),
|
||||
clk_i, !rst_ni || (alert_tx_o.alert_p == alert_tx_o.alert_n))
|
||||
`endif
|
||||
|
||||
endmodule : prim_alert_sender
|
||||
|
|
137
vendor/lowrisc_ip/ip/prim/rtl/prim_clock_meas.sv
vendored
Normal file
137
vendor/lowrisc_ip/ip/prim/rtl/prim_clock_meas.sv
vendored
Normal file
|
@ -0,0 +1,137 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
// prim_clk_meas is a generic module that measures two clocks against each other.
|
||||
// One clock is the reference, and another is the input.
|
||||
// If the input clocks becomes too fast or too slow, an error condition is created.
|
||||
|
||||
// The default parameters assume the reference clock is significantly slower than
|
||||
// the input clock
|
||||
|
||||
|
||||
`include "prim_assert.sv"
|
||||
|
||||
module prim_clock_meas #(
|
||||
// Maximum value of input clock counts over measurement period
|
||||
parameter int Cnt = 16,
|
||||
// Maximum value of reference clock counts over measurement period
|
||||
parameter int RefCnt = 1,
|
||||
localparam int CntWidth = prim_util_pkg::vbits(Cnt),
|
||||
localparam int RefCntWidth = prim_util_pkg::vbits(RefCnt)
|
||||
) (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
input clk_ref_i,
|
||||
input rst_ref_ni,
|
||||
input en_i,
|
||||
input [CntWidth-1:0] max_cnt,
|
||||
input [CntWidth-1:0] min_cnt,
|
||||
// the output valid and fast/slow indications are all on the
|
||||
// input clock domain
|
||||
output logic valid_o,
|
||||
output logic fast_o,
|
||||
output logic slow_o
|
||||
);
|
||||
|
||||
//////////////////////////
|
||||
// Reference clock logic
|
||||
//////////////////////////
|
||||
|
||||
logic ref_en;
|
||||
prim_flop_2sync #(
|
||||
.Width(1)
|
||||
) u_ref_meas_en_sync (
|
||||
.d_i(en_i),
|
||||
.clk_i(clk_ref_i),
|
||||
.rst_ni(rst_ref_ni),
|
||||
.q_o(ref_en)
|
||||
);
|
||||
|
||||
logic ref_valid;
|
||||
logic [RefCntWidth-1:0] ref_cnt;
|
||||
always_ff @(posedge clk_ref_i or negedge rst_ref_ni) begin
|
||||
if (!rst_ref_ni) begin
|
||||
ref_cnt <= '0;
|
||||
ref_valid <= '0;
|
||||
end else if (!ref_en && |ref_cnt) begin
|
||||
ref_cnt <= '0;
|
||||
ref_valid <= '0;
|
||||
end else if (ref_en && (ref_cnt == RefCnt - 1)) begin
|
||||
// restart count and measure
|
||||
ref_cnt <= '0;
|
||||
ref_valid <= 1'b1;
|
||||
end else if (ref_en) begin
|
||||
ref_cnt <= ref_cnt + 1'b1;
|
||||
ref_valid <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
//////////////////////////
|
||||
// Input Clock Logic
|
||||
//////////////////////////
|
||||
|
||||
|
||||
logic valid;
|
||||
|
||||
// The valid pulse causes the count to reset and start counting again
|
||||
// for each reference cycle.
|
||||
// The count obtained during the the last refernece cycle is then used
|
||||
// to measure how fast/slow the input clock is.
|
||||
prim_pulse_sync u_sync_ref (
|
||||
.clk_src_i(clk_ref_i),
|
||||
.rst_src_ni(rst_ref_ni),
|
||||
.src_pulse_i(ref_valid),
|
||||
.clk_dst_i(clk_i),
|
||||
.rst_dst_ni(rst_ni),
|
||||
.dst_pulse_o(valid)
|
||||
);
|
||||
|
||||
logic cnt_en;
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if (!rst_ni) begin
|
||||
cnt_en <= '0;
|
||||
end else if (!en_i) begin
|
||||
cnt_en <= '0;
|
||||
end else if (en_i && valid) begin
|
||||
cnt_en <= 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
logic cnt_ovfl;
|
||||
logic [CntWidth-1:0] cnt;
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if (!rst_ni) begin
|
||||
cnt <= '0;
|
||||
cnt_ovfl <= '0;
|
||||
end else if (!cnt_en && |cnt) begin
|
||||
cnt <= '0;
|
||||
cnt_ovfl <= '0;
|
||||
end else if (valid_o) begin
|
||||
cnt <= '0;
|
||||
cnt_ovfl <= '0;
|
||||
end else if (cnt_en && cnt_ovfl) begin
|
||||
cnt <= '{default: '1};
|
||||
end else if (cnt_en) begin
|
||||
{cnt_ovfl, cnt} <= cnt + 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
assign valid_o = en_i & valid & |cnt;
|
||||
assign fast_o = valid_o & ((cnt > max_cnt) | cnt_ovfl);
|
||||
assign slow_o = valid_o & (cnt < min_cnt);
|
||||
|
||||
//////////////////////////
|
||||
// Assertions
|
||||
//////////////////////////
|
||||
|
||||
`ASSERT_INIT(RefCntVal_A, RefCnt >= 1)
|
||||
|
||||
// if we've reached the max count, enable must be 0 next.
|
||||
// Otherwise the width of the counter is too small to accommodate the usecase
|
||||
`ASSERT(MaxWidth_A, (cnt == Cnt-1) |=> !cnt_en )
|
||||
|
||||
|
||||
|
||||
|
||||
endmodule // prim_clk_meas
|
152
vendor/lowrisc_ip/ip/prim/rtl/prim_count.sv
vendored
Normal file
152
vendor/lowrisc_ip/ip/prim/rtl/prim_count.sv
vendored
Normal file
|
@ -0,0 +1,152 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
// Primitive hardened counter module
|
||||
//
|
||||
// This module implements two styles of hardened counting
|
||||
// 1. Duplicate count
|
||||
// There are two copies of the relevant counter and they are constantly compared.
|
||||
// 2. Cross count
|
||||
// There is an up count and a down count, and the combined value must always
|
||||
// combine to the same value
|
||||
//
|
||||
// This counter supports a generic clr / set / en interface.
|
||||
// When clr_i is set, the counter clears to 0
|
||||
// When set_i is set, the down count (if enabled) will set to the max value
|
||||
// When neither of the above is set, increment the up count(s) or decrement the down count.
|
||||
//
|
||||
// Note there are many other flavor of functions that can be added, but this primitive
|
||||
// module initially favors the usage inside keymgr and flash_ctrl.
|
||||
//
|
||||
// The usage of set_cnt_i is as follows:
|
||||
// When doing CrossCnt, set_cnt_i sets the maximum value as well as the starting value of down_cnt.
|
||||
// When doing DupCnt, set_cnt_i sets the starting value of up_cnt. Note during DupCnt, the maximum
|
||||
// value is just the max possible value given the counter width.
|
||||
|
||||
module prim_count 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, // increment/decrement step when enabled
|
||||
output logic [Width-1:0] cnt_o,
|
||||
output logic err_o
|
||||
);
|
||||
|
||||
// if output selects downcount, it MUST be the cross count style
|
||||
`ASSERT_INIT(CntStyleMatch_A, OutSelDnCnt ? CntStyle == CrossCnt : 1'b1)
|
||||
|
||||
localparam int CntCopies = (CntStyle == DupCnt) ? 2 : 1;
|
||||
|
||||
cmp_valid_e cmp_valid;
|
||||
logic [CntCopies-1:0][Width-1:0] up_cnt_d, up_cnt_d_buf;
|
||||
logic [CntCopies-1:0][Width-1:0] up_cnt_q;
|
||||
logic [Width-1:0] max_val;
|
||||
logic err;
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if (!rst_ni) begin
|
||||
max_val <= '{default: '1};
|
||||
end else if (set_i && (CntStyle == CrossCnt)) begin
|
||||
max_val <= set_cnt_i;
|
||||
end
|
||||
end
|
||||
|
||||
for (genvar i = 0; i < CntCopies; i++) begin : gen_cnts
|
||||
// up-count
|
||||
assign up_cnt_d[i] = (clr_i) ? '0 :
|
||||
(set_i & CntStyle == DupCnt) ? set_cnt_i :
|
||||
(en_i & up_cnt_q[i] < max_val) ? up_cnt_q[i] + step_i :
|
||||
up_cnt_q[i];
|
||||
|
||||
prim_buf #(
|
||||
.Width(Width)
|
||||
) u_buf (
|
||||
.in_i(up_cnt_d[i]),
|
||||
.out_o(up_cnt_d_buf[i])
|
||||
);
|
||||
|
||||
prim_flop #(
|
||||
.Width(Width),
|
||||
.ResetValue('0)
|
||||
) u_cnt_flop (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.d_i(up_cnt_d_buf[i]),
|
||||
.q_o(up_cnt_q[i])
|
||||
);
|
||||
end
|
||||
|
||||
if (CntStyle == CrossCnt) begin : gen_cross_cnt_hardening
|
||||
logic [Width-1:0] down_cnt;
|
||||
logic [Width-1:0] sum;
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if (!rst_ni) begin
|
||||
cmp_valid <= CmpInvalid;
|
||||
end else if (clr_i) begin
|
||||
cmp_valid <= CmpInvalid;
|
||||
end else if ((cmp_valid == CmpInvalid) && set_i) begin
|
||||
cmp_valid <= CmpValid;
|
||||
end
|
||||
end
|
||||
|
||||
// down-count
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if (!rst_ni) begin
|
||||
down_cnt <= '0;
|
||||
end else if (clr_i) begin
|
||||
down_cnt <= '0;
|
||||
end else if (set_i) begin
|
||||
down_cnt <= set_cnt_i;
|
||||
end else if (en_i && down_cnt > '0) begin
|
||||
down_cnt <= down_cnt - step_i;
|
||||
end
|
||||
end
|
||||
|
||||
logic msb;
|
||||
assign {msb, sum} = down_cnt + up_cnt_q[0];
|
||||
assign cnt_o = OutSelDnCnt ? down_cnt : up_cnt_q[0];
|
||||
assign err = max_val != sum | msb;
|
||||
|
||||
`ASSERT(CrossCntErrForward_A,
|
||||
(cmp_valid == CmpValid) && ((down_cnt + up_cnt_q[0]) != {1'b0, max_val}) |-> err_o)
|
||||
`ASSERT(CrossCntErrBackward_A, err_o |->
|
||||
(cmp_valid == CmpValid) && ((down_cnt + up_cnt_q[0]) != {1'b0, max_val}))
|
||||
|
||||
end else if (CntStyle == DupCnt) begin : gen_dup_cnt_hardening
|
||||
// duplicate count compare is always valid
|
||||
assign cmp_valid = CmpValid;
|
||||
assign cnt_o = up_cnt_q[0];
|
||||
assign err = (up_cnt_q[0] != up_cnt_q[1]);
|
||||
|
||||
`ASSERT(DupCntErrForward_A, up_cnt_q[0] != up_cnt_q[1] |-> err_o)
|
||||
`ASSERT(DupCntErrBackward_A, err_o |-> up_cnt_q[0] != up_cnt_q[1])
|
||||
end
|
||||
|
||||
// if the compare flag is not a valid enum, treat it like an error.
|
||||
assign err_o = (cmp_valid == CmpValid) ? err :
|
||||
(cmp_valid == CmpInvalid) ? '0 : 1'b1;
|
||||
|
||||
// Clear and set should not be seen at the same time
|
||||
`ASSERT(SimulClrSet_A, clr_i || set_i |-> clr_i != set_i)
|
||||
|
||||
// Max value must be an integer multiple of the step size during cross count
|
||||
`ASSERT(DownCntStepInt_A, (CntStyle == CrossCnt) & (cmp_valid == CmpValid)
|
||||
|-> max_val % step_i == 0)
|
||||
|
||||
// If using DupCnt, the count can never overflow
|
||||
logic [Width:0] unused_cnt;
|
||||
assign unused_cnt = up_cnt_q[0] + step_i;
|
||||
logic unused_incr_cnt;
|
||||
assign unused_incr_cnt = (CntStyle == DupCnt) & (cmp_valid == CmpValid) & !clr_i & !set_i;
|
||||
`ASSERT(UpCntOverFlow_A, unused_incr_cnt |-> ~unused_cnt[Width])
|
||||
|
||||
endmodule // keymgr_cnt
|
22
vendor/lowrisc_ip/ip/prim/rtl/prim_count_pkg.sv
vendored
Normal file
22
vendor/lowrisc_ip/ip/prim/rtl/prim_count_pkg.sv
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
// Package for primitive hardened counter module
|
||||
//
|
||||
|
||||
package prim_count_pkg;
|
||||
|
||||
// Enumeration for hardened count style
|
||||
typedef enum logic {
|
||||
CrossCnt, // up count and down count
|
||||
DupCnt // duplicate counters
|
||||
} prim_count_style_e;
|
||||
|
||||
// Enumeration for differential valid
|
||||
typedef enum logic [1:0] {
|
||||
CmpInvalid = 2'b01,
|
||||
CmpValid = 2'b10
|
||||
} cmp_valid_e;
|
||||
|
||||
endpackage //
|
|
@ -218,33 +218,56 @@ module prim_diff_decode #(
|
|||
`ASSERT(SigintFallCheck_A, sigint_o |-> !fall_o)
|
||||
|
||||
if (AsyncOn) begin : gen_async_assert
|
||||
`ifdef INC_ASSERT
|
||||
// assertions for asynchronous case
|
||||
// correctly detect sigint issue (only one transition cycle of permissible due to skew)
|
||||
`ASSERT(SigintCheck0_A, diff_pi == diff_ni [*2] |-> ##[1:2] sigint_o)
|
||||
// the synchronizer adds 2 cycles of latency
|
||||
`ASSERT(SigintCheck1_A, ##1 (diff_pi ^ diff_ni) && $stable(diff_pi) && $stable(diff_ni) ##1
|
||||
$rose(diff_pi) && $stable(diff_ni) ##1 $stable(diff_pi) && $fell(diff_ni) |->
|
||||
##2 rise_o)
|
||||
`ASSERT(SigintCheck2_A, ##1 (diff_pi ^ diff_ni) && $stable(diff_pi) && $stable(diff_ni) ##1
|
||||
$fell(diff_pi) && $stable(diff_ni) ##1 $stable(diff_pi) && $rose(diff_ni) |->
|
||||
##2 fall_o)
|
||||
`ASSERT(SigintCheck3_A, ##1 (diff_pi ^ diff_ni) && $stable(diff_pi) && $stable(diff_ni) ##1
|
||||
$rose(diff_ni) && $stable(diff_pi) ##1 $stable(diff_ni) && $fell(diff_pi) |->
|
||||
##2 fall_o)
|
||||
`ASSERT(SigintCheck4_A, ##1 (diff_pi ^ diff_ni) && $stable(diff_pi) && $stable(diff_ni) ##1
|
||||
$fell(diff_ni) && $stable(diff_pi) ##1 $stable(diff_ni) && $rose(diff_pi) |->
|
||||
##2 rise_o)
|
||||
// correctly detect edges
|
||||
`ASSERT(RiseCheck_A, ##1 $rose(diff_pi) && (diff_pi ^ diff_ni) |->
|
||||
##[2:3] rise_o, clk_i, !rst_ni || sigint_o)
|
||||
`ASSERT(FallCheck_A, ##1 $fell(diff_pi) && (diff_pi ^ diff_ni) |->
|
||||
##[2:3] fall_o, clk_i, !rst_ni || sigint_o)
|
||||
`ASSERT(EventCheck_A, ##1 $changed(diff_pi) && (diff_pi ^ diff_ni) |->
|
||||
##[2:3] event_o, clk_i, !rst_ni || sigint_o)
|
||||
// correctly detect level
|
||||
`ASSERT(LevelCheck0_A, !sigint_o && (diff_pi ^ diff_ni) [*3] |=> $past(diff_pi, 2) == level_o,
|
||||
clk_i, !rst_ni || sigint_o)
|
||||
// in this case we need to sample the input signals onto the local clock to avoid race
|
||||
// conditions between the RTL and assertion sampling in simulation.
|
||||
logic hlp_diff_pq, hlp_diff_nq;
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin : p_edge_reg
|
||||
if (!rst_ni) begin
|
||||
hlp_diff_pq <= 1'b0;
|
||||
hlp_diff_nq <= 1'b1;
|
||||
end else begin
|
||||
hlp_diff_pq <= diff_pi;
|
||||
hlp_diff_nq <= diff_ni;
|
||||
end
|
||||
end
|
||||
|
||||
// correctly detect sigint issue (only one transition cycle of permissible due to skew)
|
||||
`ASSERT(SigintCheck0_A, hlp_diff_pq == hlp_diff_nq [*2] |-> ##[0:1] sigint_o)
|
||||
// the synchronizer adds 2 cycles of latency with respect to input signals.
|
||||
`ASSERT(SigintCheck1_A,
|
||||
##1 (hlp_diff_pq ^ hlp_diff_nq) && $stable(hlp_diff_pq) && $stable(hlp_diff_nq) ##1
|
||||
$rose(hlp_diff_pq) && $stable(hlp_diff_nq) ##1 $stable(hlp_diff_pq) && $fell(hlp_diff_nq)
|
||||
|->
|
||||
##1 rise_o)
|
||||
`ASSERT(SigintCheck2_A,
|
||||
##1 (hlp_diff_pq ^ hlp_diff_nq) && $stable(hlp_diff_pq) && $stable(hlp_diff_nq) ##1
|
||||
$fell(hlp_diff_pq) && $stable(hlp_diff_nq) ##1 $stable(hlp_diff_pq) && $rose(hlp_diff_nq)
|
||||
|->
|
||||
##1 fall_o)
|
||||
`ASSERT(SigintCheck3_A,
|
||||
##1 (hlp_diff_pq ^ hlp_diff_nq) && $stable(hlp_diff_pq) && $stable(hlp_diff_nq) ##1
|
||||
$rose(hlp_diff_nq) && $stable(hlp_diff_pq) ##1 $stable(hlp_diff_nq) && $fell(hlp_diff_pq)
|
||||
|->
|
||||
##1 fall_o)
|
||||
`ASSERT(SigintCheck4_A,
|
||||
##1 (hlp_diff_pq ^ hlp_diff_nq) && $stable(hlp_diff_pq) && $stable(hlp_diff_nq) ##1
|
||||
$fell(hlp_diff_nq) && $stable(hlp_diff_pq) ##1 $stable(hlp_diff_nq) && $rose(hlp_diff_pq)
|
||||
|->
|
||||
##1 rise_o)
|
||||
// correctly detect edges
|
||||
`ASSERT(RiseCheck_A, ##1 $rose(hlp_diff_pq) && (hlp_diff_pq ^ hlp_diff_nq) |->
|
||||
##[1:2] rise_o, clk_i, !rst_ni || sigint_o)
|
||||
`ASSERT(FallCheck_A, ##1 $fell(hlp_diff_pq) && (hlp_diff_pq ^ hlp_diff_nq) |->
|
||||
##[1:2] fall_o, clk_i, !rst_ni || sigint_o)
|
||||
`ASSERT(EventCheck_A, ##1 $changed(hlp_diff_pq) && (hlp_diff_pq ^ hlp_diff_nq) |->
|
||||
##[1:2] event_o, clk_i, !rst_ni || sigint_o)
|
||||
// correctly detect level
|
||||
`ASSERT(LevelCheck0_A, !sigint_o && (hlp_diff_pq ^ hlp_diff_nq) [*3] |=>
|
||||
$past(hlp_diff_pq, 1) == level_o,
|
||||
clk_i, !rst_ni || sigint_o)
|
||||
`endif
|
||||
end else begin : gen_sync_assert
|
||||
// assertions for synchronous case
|
||||
// correctly detect sigint issue
|
||||
|
|
55
vendor/lowrisc_ip/ip/prim/rtl/prim_edge_detector.sv
vendored
Normal file
55
vendor/lowrisc_ip/ip/prim/rtl/prim_edge_detector.sv
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
// Edge Detector
|
||||
|
||||
module prim_edge_detector #(
|
||||
parameter int unsigned Width = 1,
|
||||
|
||||
parameter logic [Width-1:0] ResetValue = '0,
|
||||
|
||||
// EnSync
|
||||
//
|
||||
// Enable Synchronizer to the input signal.
|
||||
// It is assumed that the input signal is glitch free (registered input).
|
||||
parameter bit EnSync = 1'b 1
|
||||
) (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
|
||||
input [Width-1:0] d_i,
|
||||
output logic [Width-1:0] q_sync_o,
|
||||
|
||||
output logic [Width-1:0] q_posedge_pulse_o,
|
||||
output logic [Width-1:0] q_negedge_pulse_o
|
||||
);
|
||||
|
||||
logic [Width-1:0] q_sync_d, q_sync_q;
|
||||
|
||||
if (EnSync) begin : g_sync
|
||||
prim_flop_2sync #(
|
||||
.Width (Width),
|
||||
.ResetValue (ResetValue)
|
||||
) u_sync (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.d_i,
|
||||
.q_o (q_sync_d)
|
||||
);
|
||||
end : g_sync
|
||||
else begin : g_nosync
|
||||
assign q_sync_d = d_i;
|
||||
end : g_nosync
|
||||
|
||||
assign q_sync_o = q_sync_d;
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if (!rst_ni) q_sync_q <= ResetValue;
|
||||
else q_sync_q <= q_sync_d;
|
||||
end
|
||||
|
||||
assign q_posedge_pulse_o = q_sync_d & ~q_sync_q;
|
||||
assign q_negedge_pulse_o = ~q_sync_d & q_sync_q;
|
||||
|
||||
endmodule : prim_edge_detector
|
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