mirror of
https://github.com/openhwgroup/cve2.git
synced 2025-04-22 13:07:46 -04:00
Update lowrisc_ip to lowRISC/opentitan@da3ac7c4e
Update code from upstream repository https://github.com/lowRISC/opentitan to revision da3ac7c4eb23a92194874ad2daf2e5f9e3330572 * [memutil] Allow use without scrambled memories (Philipp Wagner) * [prim_prince] Fix comment (Philipp Wagner) * [memutil] Fix width mismatch (Philipp Wagner) * [prim] Allow disabling SVAs ensuring REQ is held until ACK at run time (Pirmin Vogel) * [prim] Fix typo that caused fifo_async to get stuck (Timothy Chen) * [prim] Add a missing ROM_CFG_DEFAULT to prim_rom_pkg.sv (Rupert Swarbrick) * [dvsim] Do not assume the build failed if "ERROR" is printed (Philipp Wagner) * [prim_subreg_shadow] Invert meaning of SWACCESS in shadow/stage regs (Michael Schaffner) * [prim_arb_tree/rv_plic_target] Remove TODOs due to a Vivado tool bug (Michael Schaffner) * [primgen] Remove unused import (Philipp Wagner) * [primgen] Add shebang (Philipp Wagner) * [primgen] Make primgen "portable" again (Philipp Wagner) * [dv] Small optimization in memutil (Philipp Wagner) * [tools/ascent] updated ascent to use the --job-prefix option (Rasmus Madsen) * [otp_ctrl] Remove invalid command error (Michael Schaffner) * [tlul] Add some missing dependencies (Michael Schaffner) * [otbn/otp_ctrl] Replicate dmem scrambling keystream (Michael Schaffner) * [adc_ctrl] Various preparation steps for d2 (Timothy Chen) * [tools/dvsim] Fix some VCS flags (Guillermo Maturana) * Revert "[prim] Do remove prim_esc.core from the dependencies" (Rupert Swarbrick) * [prim] Remove dependency of prim:esc on a hardware block (Rupert Swarbrick) * [lint] prim_ram_1p_scr verilator lint fixes (Greg Chadwick) * [dv] Add scrambled_ecc32_mem_area for memutils (Greg Chadwick) * [dv] Add C++ memory scrambling model (Greg Chadwick) * [tools/dsim] Fix non-LRM compliant code (Guillermo Maturana) * [prim] Do remove prim_esc.core from the dependencies (Michael Schaffner) * [dv/dv_utils] Improvement on `max` function (Cindy Chen) * [alert_handler] Implement reverse ping feature (Michael Schaffner) * [prim_esc] Split the prims into their own core file (Michael Schaffner) * [dvsim] Fix GUI mode and launcher creation fixes (Srikrishna Iyer) * [dv/common] Stress_all_with_rand_reset apply reset concurrently (Cindy Chen) * [dv/all] update scoreboard `csr_addrs` accesses (Udi Jonnalagadda) * [dv/csr_utils] update unmapped_addr calculation (Udi Jonnalagadda) * [dv] Update intg alert names (Weicai Yang) * [dv, flash_ctrl] Fix the intr test (Srikrishna Iyer) * [prim_fifo_async] Fix a width calculation issue in case of Depth = 1 (Michael Schaffner) * [dv] Update VCS opt for uvm_hdl_* (Weicai Yang) * [dv, util] Make poll_for_stop() opt-in (Srikrishna Iyer) * [dvsim] Separate publish report option [PART1] (Cindy Chen) * [dv/kmac/sram] reduce iterations of smoke test (Udi Jonnalagadda) * [dv/stress_all_with_reset] Revert back IPs that uses apply_reset (Cindy Chen) * [dv/edn_reset] Fix apply_reset to concurrently deassert resets (Cindy Chen) * [dv] Update VCS cov merge opts (Srikrishna Iyer) * [dv] Add TL integrity error test for CSR (Weicai Yang) * [dv, chip] Remove USB clk driver (Srikrishna Iyer) * [script/dvsim] Update output folder (Cindy Chen) * [dv/edn_reset] Update IPs that overrides apply_reset task (Cindy Chen) * [dv/edn_reset] Fix stress_all_with_rand_reset error (Cindy Chen) * [dv/dv_base_scoreboard] remove duplicated code (Cindy Chen) * [otbn,dv] Teach otbn_memutil to track expected end address (Rupert Swarbrick) * [dv, dv_utils_pkg] Fix common int typedefs (Srikrishna Iyer) * [prim_lfsr] Fix spyglass lint warnings (Michael Schaffner) * [prim_clock_gating] Target 7series Xilinx devices (Philipp Wagner) * [dv/edn_rst] Add coverage to collect edn reset and dut reset (Cindy Chen) * [otp_ctrl/lc_ctrl] Add LC TAP register to control OTP test mechanisms (Michael Schaffner) * [prim_alert*/prim_esc*] Rework placement of size_only bufs/flops (Michael Schaffner) * [dv] fix a typo in tl_device_access_types_testplan (Weicai Yang) * [prim_otp] Rework generic model to match new error behavior (Michael Schaffner) * [dv/tlul_common_test] Add a testplan for TLUL integrity check (Cindy Chen) * [dvsim] Allow recursive testplan import (Srikrishna Iyer) * [primgen] Use verible-verilog-syntax for parsing (Mariusz Glebocki) * [prim] Break always_comb block to avoid apparent loop (Rupert Swarbrick) * [dvsim] Fix testplan bugs (Srikrishna Iyer) * [fpv] update secded_gen (Cindy Chen) * [dv/template] small fixes on index.md format (Cindy Chen) * [prim_otp] Add a waiver for power signal unused in generic prim (Michael Schaffner) * [simutil_verilator] Improve timeout handling (Rupert Swarbrick) * [testplans] Rename entries with testpoints (Srikrishna Iyer) * [dvsim/testplan] Fix the rendered testplan (Srikrishna Iyer) * [dv/cov] exclude prim_lfsr and prim_prince (Udi Jonnalagadda) Signed-off-by: Philipp Wagner <phw@lowrisc.org>
This commit is contained in:
parent
270cd91b38
commit
d003d479ff
122 changed files with 3416 additions and 663 deletions
2
vendor/lowrisc_ip.lock.hjson
vendored
2
vendor/lowrisc_ip.lock.hjson
vendored
|
@ -9,6 +9,6 @@
|
|||
upstream:
|
||||
{
|
||||
url: https://github.com/lowRISC/opentitan
|
||||
rev: 7117c349d5465b5152d3bb774079013924a3e9ba
|
||||
rev: da3ac7c4eb23a92194874ad2daf2e5f9e3330572
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,28 +60,6 @@ package csr_utils_pkg;
|
|||
under_reset = 0;
|
||||
endfunction
|
||||
|
||||
// Get all valid csr addrs - useful to check if incoming addr falls in the csr range.
|
||||
function automatic void get_csr_addrs(input uvm_reg_block ral, ref uvm_reg_addr_t csr_addrs[$]);
|
||||
uvm_reg csrs[$];
|
||||
ral.get_registers(csrs);
|
||||
foreach (csrs[i]) begin
|
||||
csr_addrs.push_back(csrs[i].get_address());
|
||||
end
|
||||
endfunction
|
||||
|
||||
// Get all valid mem addr ranges - useful to check if incoming addr falls in the mem range.
|
||||
function automatic void get_mem_addr_ranges(uvm_reg_block ral, ref addr_range_t mem_ranges[$]);
|
||||
uvm_mem mems[$];
|
||||
ral.get_memories(mems);
|
||||
foreach (mems[i]) begin
|
||||
addr_range_t mem_range;
|
||||
mem_range.start_addr = mems[i].get_address();
|
||||
mem_range.end_addr = mem_range.start_addr +
|
||||
mems[i].get_size() * mems[i].get_n_bytes() - 1;
|
||||
mem_ranges.push_back(mem_range);
|
||||
end
|
||||
endfunction
|
||||
|
||||
// get mem object from address
|
||||
function automatic uvm_mem get_mem_by_addr(uvm_reg_block ral, uvm_reg_addr_t addr);
|
||||
uvm_mem mem;
|
||||
|
|
|
@ -16,6 +16,15 @@ class dv_base_reg_block extends uvm_reg_block;
|
|||
// This is set by compute_addr_mask(), which must run after locking the model.
|
||||
protected uvm_reg_addr_t addr_mask[uvm_reg_map];
|
||||
|
||||
uvm_reg_addr_t csr_addrs[$];
|
||||
|
||||
addr_range_t mem_ranges[$];
|
||||
|
||||
addr_range_t mapped_addr_ranges[$];
|
||||
|
||||
bit has_unmapped_addrs;
|
||||
addr_range_t unmapped_addr_ranges[$];
|
||||
|
||||
function new (string name = "", int has_coverage = UVM_NO_COVERAGE);
|
||||
super.new(name, has_coverage);
|
||||
endfunction
|
||||
|
@ -94,6 +103,98 @@ class dv_base_reg_block extends uvm_reg_block;
|
|||
`DV_CHECK_FATAL(addr_mask[map])
|
||||
endfunction
|
||||
|
||||
// Internal function, used to get a list of all valid CSR addresses.
|
||||
protected function void compute_csr_addrs();
|
||||
uvm_reg csrs[$];
|
||||
get_registers(csrs);
|
||||
foreach (csrs[i]) begin
|
||||
csr_addrs.push_back(csrs[i].get_address());
|
||||
end
|
||||
endfunction
|
||||
|
||||
// Internal function, used to get a list of all valid memory ranges
|
||||
protected function void compute_mem_addr_ranges();
|
||||
uvm_mem mems[$];
|
||||
get_memories(mems);
|
||||
foreach (mems[i]) begin
|
||||
addr_range_t mem_range;
|
||||
mem_range.start_addr = mems[i].get_address();
|
||||
mem_range.end_addr = mem_range.start_addr +
|
||||
mems[i].get_size() * mems[i].get_n_bytes() - 1;
|
||||
mem_ranges.push_back(mem_range);
|
||||
end
|
||||
endfunction
|
||||
|
||||
// Used to get a list of all valid address ranges covered by this reg block
|
||||
function void compute_mapped_addr_ranges();
|
||||
uvm_reg csrs[$];
|
||||
get_registers(csrs);
|
||||
|
||||
// Compute all CSR addresses and mem ranges known to this reg block
|
||||
compute_csr_addrs();
|
||||
compute_mem_addr_ranges();
|
||||
|
||||
// Convert each CSR into an address range
|
||||
foreach (csrs[i]) begin
|
||||
addr_range_t csr_addr_range;
|
||||
csr_addr_range.start_addr = csrs[i].get_address();
|
||||
csr_addr_range.end_addr = csr_addr_range.start_addr + csrs[i].get_n_bytes() - 1;
|
||||
mapped_addr_ranges.push_back(csr_addr_range);
|
||||
end
|
||||
|
||||
mapped_addr_ranges = {mapped_addr_ranges, mem_ranges};
|
||||
|
||||
// Sort the mapped address ranges in ascending order based on the start_addr of each range
|
||||
mapped_addr_ranges.sort(m) with (m.start_addr);
|
||||
|
||||
endfunction
|
||||
|
||||
// Used to get a list of all invalid address ranges in this reg block
|
||||
function void compute_unmapped_addr_ranges();
|
||||
addr_range_t range;
|
||||
|
||||
// convert the address mask into a relative address,
|
||||
// this is the highest addressable location in the register block
|
||||
uvm_reg_addr_t highest_addr = default_map.get_base_addr() + get_addr_mask();
|
||||
|
||||
// unmapped address ranges consist of:
|
||||
// - the address space between all mapped address ranges (if exists)
|
||||
// - space between csr_base_addr and the first mapped address range (if exists)
|
||||
// - space between the last mapped address and the highest address mapped by the address mask
|
||||
if (mapped_addr_ranges.size() == 0) begin
|
||||
range.start_addr = default_map.get_base_addr();
|
||||
range.end_addr = highest_addr;
|
||||
unmapped_addr_ranges.push_back(range);
|
||||
end else begin
|
||||
// 0 -> start_addr-1
|
||||
if (mapped_addr_ranges[0].start_addr - default_map.get_base_addr() > 0) begin
|
||||
range.start_addr = default_map.get_base_addr();
|
||||
range.end_addr = mapped_addr_ranges[0].start_addr - 1;
|
||||
unmapped_addr_ranges.push_back(range);
|
||||
end
|
||||
|
||||
// all address ranges in the "middle" - only applies if
|
||||
// there are more than 1 mapped address ranges
|
||||
if (mapped_addr_ranges.size() > 1) begin
|
||||
for (int i = 0; i < mapped_addr_ranges.size() - 1; i++) begin
|
||||
range.start_addr = mapped_addr_ranges[i].end_addr + 1;
|
||||
range.end_addr = mapped_addr_ranges[i+1].start_addr - 1;
|
||||
if (range.start_addr < range.end_addr) begin
|
||||
unmapped_addr_ranges.push_back(range);
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// end_addr+1 -> highest_addr
|
||||
if (mapped_addr_ranges[$].end_addr < highest_addr) begin
|
||||
range.start_addr = mapped_addr_ranges[$].end_addr + 1;
|
||||
range.end_addr = highest_addr;
|
||||
unmapped_addr_ranges.push_back(range);
|
||||
end
|
||||
end
|
||||
has_unmapped_addrs = (unmapped_addr_ranges.size() > 0);
|
||||
endfunction
|
||||
|
||||
// Return the offset of the highest byte contained in either a register or a memory
|
||||
function uvm_reg_addr_t get_max_offset(uvm_reg_map map = null);
|
||||
uvm_reg_addr_t max_offset;
|
||||
|
@ -143,6 +244,7 @@ class dv_base_reg_block extends uvm_reg_block;
|
|||
if (map == null) map = get_default_map();
|
||||
mask = get_addr_mask(map);
|
||||
|
||||
|
||||
// If base_addr is '1, randomly pick an aligned base address
|
||||
if (base_addr == '1) begin
|
||||
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(base_addr, (base_addr & mask) == '0;)
|
||||
|
|
|
@ -17,7 +17,7 @@ class dv_base_env_cfg #(type RAL_T = dv_base_reg_block) extends uvm_object;
|
|||
// useful to keep the runtime down especially in time-sensitive runs such as CI, which is meant
|
||||
// to check the code health and not find design bugs. It is set via plusarg and retrieved in
|
||||
// `dv_base_test`.
|
||||
bit smoke_test = 0;
|
||||
bit smoke_test = 0;
|
||||
|
||||
// bit to configure all uvcs with zero delays to create high bw test
|
||||
rand bit zero_delays;
|
||||
|
@ -38,9 +38,6 @@ class dv_base_env_cfg #(type RAL_T = dv_base_reg_block) extends uvm_object;
|
|||
// super.initialize(csr_base_addr);
|
||||
string ral_model_names[$] = {RAL_T::type_name};
|
||||
|
||||
bit [bus_params_pkg::BUS_AW-1:0] csr_addrs[string][$];
|
||||
addr_range_t mem_ranges[string][$];
|
||||
|
||||
// clk_rst_if & freq
|
||||
// clk_rst_vif and clk_freq_mhz are used for default clk/rst. If more than one RAL, the other
|
||||
// clk_rst_vif and clk_freq_mhz can be found from the associative arrays
|
||||
|
@ -50,10 +47,10 @@ class dv_base_env_cfg #(type RAL_T = dv_base_reg_block) extends uvm_object;
|
|||
rand clk_freq_mhz_e clk_freqs_mhz[string];
|
||||
|
||||
`uvm_object_param_utils_begin(dv_base_env_cfg #(RAL_T))
|
||||
`uvm_field_int (is_active, UVM_DEFAULT)
|
||||
`uvm_field_int (en_scb, UVM_DEFAULT)
|
||||
`uvm_field_int (en_cov, UVM_DEFAULT)
|
||||
`uvm_field_int (zero_delays, UVM_DEFAULT)
|
||||
`uvm_field_int (is_active, UVM_DEFAULT)
|
||||
`uvm_field_int (en_scb, UVM_DEFAULT)
|
||||
`uvm_field_int (en_cov, UVM_DEFAULT)
|
||||
`uvm_field_int (zero_delays, UVM_DEFAULT)
|
||||
`uvm_object_utils_end
|
||||
|
||||
`uvm_object_new
|
||||
|
@ -98,6 +95,7 @@ class dv_base_env_cfg #(type RAL_T = dv_base_reg_block) extends uvm_object;
|
|||
endfunction
|
||||
|
||||
virtual function void create_ral_models(bit [bus_params_pkg::BUS_AW-1:0] csr_base_addr = '1);
|
||||
|
||||
foreach (ral_model_names[i]) begin
|
||||
string ral_name = ral_model_names[i];
|
||||
uvm_reg_addr_t base_addr;
|
||||
|
@ -123,8 +121,16 @@ class dv_base_env_cfg #(type RAL_T = dv_base_reg_block) extends uvm_object;
|
|||
reg_blk.set_base_addr(base_addr);
|
||||
|
||||
// Get list of valid csr addresses (useful in seq to randomize addr as well as in scb checks)
|
||||
get_csr_addrs(reg_blk, csr_addrs[ral_name]);
|
||||
get_mem_addr_ranges(reg_blk, mem_ranges[ral_name]);
|
||||
reg_blk.compute_mapped_addr_ranges();
|
||||
reg_blk.compute_unmapped_addr_ranges();
|
||||
`uvm_info(msg_id,
|
||||
$sformatf("RAL[%0s] mapped addresses: %0p",
|
||||
ral_name, reg_blk.mapped_addr_ranges),
|
||||
UVM_HIGH)
|
||||
`uvm_info(msg_id,
|
||||
$sformatf("RAL[%0s] unmapped addresses: %0p",
|
||||
ral_name, reg_blk.unmapped_addr_ranges),
|
||||
UVM_HIGH)
|
||||
ral_models[ral_name] = reg_blk;
|
||||
end
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ class dv_base_scoreboard #(type RAL_T = dv_base_reg_block,
|
|||
super.run_phase(phase);
|
||||
fork
|
||||
monitor_reset();
|
||||
sample_resets();
|
||||
join_none
|
||||
endtask
|
||||
|
||||
|
@ -33,12 +34,10 @@ class dv_base_scoreboard #(type RAL_T = dv_base_reg_block,
|
|||
if (!cfg.clk_rst_vif.rst_n) begin
|
||||
`uvm_info(`gfn, "reset occurred", UVM_HIGH)
|
||||
cfg.reset_asserted();
|
||||
csr_utils_pkg::reset_asserted();
|
||||
@(posedge cfg.clk_rst_vif.rst_n);
|
||||
reset();
|
||||
cfg.reset_deasserted();
|
||||
csr_utils_pkg::clear_outstanding_access();
|
||||
csr_utils_pkg::reset_deasserted();
|
||||
`uvm_info(`gfn, "out of reset", UVM_HIGH)
|
||||
end
|
||||
else begin
|
||||
|
@ -48,6 +47,10 @@ class dv_base_scoreboard #(type RAL_T = dv_base_reg_block,
|
|||
end
|
||||
endtask
|
||||
|
||||
virtual task sample_resets();
|
||||
// Do nothing, actual coverage collection is under extended classes.
|
||||
endtask
|
||||
|
||||
virtual function void reset(string kind = "HARD");
|
||||
// reset the ral model
|
||||
foreach (cfg.ral_models[i]) cfg.ral_models[i].reset(kind);
|
||||
|
|
|
@ -14,7 +14,7 @@ class dv_base_test #(type CFG_T = dv_base_env_cfg,
|
|||
uint max_quit_count = 1;
|
||||
uint64 test_timeout_ns = 200_000_000; // 200ms
|
||||
uint drain_time_ns = 2_000; // 2us
|
||||
bit poll_for_stop = 1'b1;
|
||||
bit poll_for_stop = 1'b0;
|
||||
uint poll_for_stop_interval_ns = 1000;
|
||||
|
||||
`uvm_component_new
|
||||
|
|
47
vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_vseq.sv
vendored
47
vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_vseq.sv
vendored
|
@ -86,7 +86,7 @@ class dv_base_vseq #(type RAL_T = dv_base_reg_block,
|
|||
|
||||
virtual task apply_reset(string kind = "HARD");
|
||||
if (kind == "HARD") begin
|
||||
if (cfg.clk_rst_vifs.size > 0) begin
|
||||
if (cfg.clk_rst_vifs.size() > 0) begin
|
||||
fork
|
||||
begin : isolation_fork
|
||||
foreach (cfg.clk_rst_vifs[i]) begin
|
||||
|
@ -104,6 +104,39 @@ class dv_base_vseq #(type RAL_T = dv_base_reg_block,
|
|||
end // if (kind == "HARD")
|
||||
endtask
|
||||
|
||||
// Apply all resets in the DUT concurrently to generate a random in-test reset scenario.
|
||||
//
|
||||
// - Assert resets concurrently to make sure all resets are issued.
|
||||
// - Deassert resets concurrently is a specific requirement of the `stress_all_with_rand_reset`
|
||||
// sequence, which will randomly issue resets and terminate the parallel sequence once all DUT
|
||||
// resets are deasserted. If DUT resets are deasserted at different time, the parallel sequence
|
||||
// might send a transaction request to driver between different resets are deasserting. Then when
|
||||
// `stress_all_with_rand_reset` sequence tries to terminate the parallel sequence, an UVM_ERROR
|
||||
// will be thrown by the sequencer saying `task responsible for requesting a wait_for_grant has
|
||||
// been killed`.
|
||||
// In order to ensure all resets at least being asserted for one clock cycle, this task takes an
|
||||
// optional input `reset_duration_ps` if the DUT has additional resets. The task uses this input
|
||||
// to compute the minimal time required to keep all resets asserted.
|
||||
virtual task apply_resets_concurrently(int reset_duration_ps = 0);
|
||||
|
||||
// Has one or more RAL models in DUT.
|
||||
if (cfg.clk_rst_vifs.size() > 0) begin
|
||||
foreach (cfg.clk_rst_vifs[i]) begin
|
||||
cfg.clk_rst_vifs[i].drive_rst_pin(0);
|
||||
reset_duration_ps = max2(reset_duration_ps, cfg.clk_rst_vifs[i].clk_period_ps);
|
||||
end
|
||||
#(reset_duration_ps * $urandom_range(2, 10) * 1ps);
|
||||
foreach (cfg.clk_rst_vifs[i]) cfg.clk_rst_vifs[i].drive_rst_pin(1);
|
||||
|
||||
// No RAL model and only has default clk_rst_vif.
|
||||
end else begin
|
||||
cfg.clk_rst_vif.drive_rst_pin(0);
|
||||
reset_duration_ps = max2(reset_duration_ps, cfg.clk_rst_vif.clk_period_ps);
|
||||
#(reset_duration_ps * $urandom_range(2, 10) * 1ps);
|
||||
cfg.clk_rst_vif.drive_rst_pin(1);
|
||||
end
|
||||
endtask
|
||||
|
||||
virtual task wait_for_reset(string reset_kind = "HARD",
|
||||
bit wait_for_assert = 1,
|
||||
bit wait_for_deassert = 1);
|
||||
|
@ -179,7 +212,11 @@ class dv_base_vseq #(type RAL_T = dv_base_reg_block,
|
|||
|
||||
// run write-only sequence to randomize the csr values
|
||||
m_csr_write_seq = csr_write_seq::type_id::create("m_csr_write_seq");
|
||||
m_csr_write_seq.models = cfg.ral_models;
|
||||
// We have to assign this array in a loop because the element types aren't equivalent, so
|
||||
// the array types aren't assignment compatible.
|
||||
foreach (cfg.ral_models[i]) begin
|
||||
m_csr_write_seq.models[i] = cfg.ral_models[i];
|
||||
end
|
||||
m_csr_write_seq.external_checker = cfg.en_scb;
|
||||
m_csr_write_seq.en_rand_backdoor_write = 1'b1;
|
||||
m_csr_write_seq.start(null);
|
||||
|
@ -196,7 +233,11 @@ class dv_base_vseq #(type RAL_T = dv_base_reg_block,
|
|||
|
||||
// create base csr seq and pass our ral
|
||||
m_csr_seq = csr_base_seq::type_id::create("m_csr_seq");
|
||||
m_csr_seq.models = cfg.ral_models;
|
||||
// We have to assign this array in a loop because the element types aren't equivalent, so
|
||||
// the array types aren't assignment compatible.
|
||||
foreach (cfg.ral_models[i]) begin
|
||||
m_csr_seq.models[i] = cfg.ral_models[i];
|
||||
end
|
||||
m_csr_seq.external_checker = cfg.en_scb;
|
||||
m_csr_seq.num_test_csrs = num_test_csrs;
|
||||
m_csr_seq.start(null);
|
||||
|
|
26
vendor/lowrisc_ip/dv/sv/dv_utils/dv_utils_pkg.sv
vendored
26
vendor/lowrisc_ip/dv/sv/dv_utils/dv_utils_pkg.sv
vendored
|
@ -14,8 +14,11 @@ package dv_utils_pkg;
|
|||
`endif
|
||||
|
||||
// common parameters used across all benches
|
||||
parameter int NUM_MAX_INTERRUPTS = 32;
|
||||
parameter int NUM_MAX_ALERTS = 32;
|
||||
parameter int NUM_MAX_INTERRUPTS = 32;
|
||||
typedef logic [NUM_MAX_INTERRUPTS-1:0] interrupt_t;
|
||||
|
||||
parameter int NUM_MAX_ALERTS = 32;
|
||||
typedef logic [NUM_MAX_ALERTS-1:0] alert_t;
|
||||
|
||||
// types & variables
|
||||
typedef bit [31:0] uint;
|
||||
|
@ -24,6 +27,13 @@ package dv_utils_pkg;
|
|||
typedef bit [31:0] uint32;
|
||||
typedef bit [63:0] uint64;
|
||||
|
||||
// TODO: The above typedefs violate the name rule, which is fixed below. Cleanup the codebase to
|
||||
// use the typedefs below and remove the ones above.
|
||||
typedef bit [7:0] uint8_t;
|
||||
typedef bit [15:0] uint16_t;
|
||||
typedef bit [31:0] uint32_t;
|
||||
typedef bit [63:0] uint64_t;
|
||||
|
||||
// typedef parameterized pins_if for ease of implementation for interrupts and alerts
|
||||
typedef virtual pins_if #(NUM_MAX_INTERRUPTS) intr_vif;
|
||||
typedef virtual pins_if #(1) devmode_vif;
|
||||
|
@ -87,6 +97,16 @@ package dv_utils_pkg;
|
|||
return (a > b) ? a : b;
|
||||
endfunction
|
||||
|
||||
// return the biggest value within the given queue of integers.
|
||||
function automatic int max(const ref int int_q[$]);
|
||||
`DV_CHECK_GT_FATAL(int_q.size(), 0, "max function cannot accept an empty queue of integers!",
|
||||
msg_id)
|
||||
// Assign the first value from the queue in case of negative integers.
|
||||
max = int_q[0];
|
||||
foreach (int_q[i]) max = max2(max, int_q[i]);
|
||||
return max;
|
||||
endfunction
|
||||
|
||||
// get absolute value of the input. Usage: absolute(val) or absolute(a - b)
|
||||
function automatic uint absolute(int val);
|
||||
return val >= 0 ? val : -val;
|
||||
|
@ -182,7 +202,7 @@ package dv_utils_pkg;
|
|||
|
||||
// Periodically check for the existence of a magic file (dv.stop). Exit if it exists. This
|
||||
// provides a mechanism to gracefully kill a simulation without direct access to the process.
|
||||
task automatic poll_for_stop(uint interval_ns = 1000, string filename = "dv.stop");
|
||||
task automatic poll_for_stop(uint interval_ns = 10_000, string filename = "dv.stop");
|
||||
fork
|
||||
while (1) begin
|
||||
#(interval_ns * 1ns);
|
||||
|
|
|
@ -21,7 +21,9 @@
|
|||
|
||||
// pass and fail patterns
|
||||
build_pass_patterns: []
|
||||
build_fail_patterns: ["^ERROR:.*$"] // fusesoc build error
|
||||
// TODO: Add back FuseSoC fail pattern after
|
||||
// https://github.com/lowRISC/opentitan/issues/7348 is resolved.
|
||||
build_fail_patterns: []
|
||||
run_pass_patterns: ["^TEST PASSED (UVM_)?CHECKS$"]
|
||||
run_fail_patterns: ["^UVM_ERROR\\s[^:].*$",
|
||||
"^UVM_FATAL\\s[^:].*$",
|
||||
|
|
|
@ -12,21 +12,22 @@
|
|||
{
|
||||
name: tl_d_illegal_access
|
||||
desc: '''Drive unsupported requests via TL interface and verify correctness of response
|
||||
/ behavior. Below error cases are tested
|
||||
/ behavior. Below error cases are tested bases on the
|
||||
[TLUL spec]({{< relref "hw/ip/tlul/doc/_index.md#explicit-error-cases" >}})
|
||||
- TL-UL protocol error cases
|
||||
- Unsupported opcode. e.g a_opcode isn't Get, PutPartialData or PutFullData
|
||||
- Mask isn't all active if opcode = PutFullData
|
||||
- Mask isn't in enabled lanes, e.g. a_address = 0x00, a_size = 0, a_mask = 'b0010
|
||||
- Mask doesn't align with address, e.g. a_address = 0x01, a_mask = 'b0001
|
||||
- Address and size aren't aligned, e.g. a_address = 0x01, a_size != 0
|
||||
- Size is over 2.
|
||||
- invalid opcode
|
||||
- some mask bits not set when opcode is `PutFullData`
|
||||
- mask does not match the transfer size, e.g. `a_address = 0x00`, `a_size = 0`,
|
||||
`a_mask = 'b0010`
|
||||
- mask and address misaligned, e.g. `a_address = 0x01`, `a_mask = 'b0001`
|
||||
- address and size aren't aligned, e.g. `a_address = 0x01`, `a_size != 0`
|
||||
- size is greater than 2
|
||||
- OpenTitan defined error cases
|
||||
- Access unmapped address, return d_error = 1 when devmode_i == 1
|
||||
- Write CSR with unaligned address, e.g. a_address[1:0] != 0
|
||||
- Write CSR less than its width, e.g. when CSR is 2 bytes wide, only write 1 byte
|
||||
- Write a memory without enabling all lanes (a_mask = '1) if memory doesn't support
|
||||
byte enabled write
|
||||
- Read a WO (write-only) memory'''
|
||||
- access unmapped address, expect `d_error = 1` when `devmode_i == 1`
|
||||
- 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'''
|
||||
milestone: V2
|
||||
tests: ["{name}_tl_errors"]
|
||||
}
|
||||
|
@ -43,15 +44,24 @@
|
|||
}
|
||||
{
|
||||
name: tl_d_partial_access
|
||||
desc: '''Access CSR with one or more bytes of data
|
||||
For read, expect to return all word value of the CSR
|
||||
For write, enabling bytes should cover all CSR valid fields'''
|
||||
desc: '''Access CSR with one or more bytes of data.
|
||||
For read, expect to return all word value of the CSR.
|
||||
For write, enabling bytes should cover all CSR valid fields.'''
|
||||
milestone: V2
|
||||
tests: ["{name}_csr_hw_reset",
|
||||
"{name}_csr_rw",
|
||||
"{name}_csr_aliasing",
|
||||
"{name}_same_csr_outstanding"]
|
||||
}
|
||||
{
|
||||
name: tl_intg_err
|
||||
desc: ''' Verify that the data integrity check violation generates an alert.
|
||||
|
||||
Randomly inject errors on the control, data, or the ECC bits during CSR accesses.
|
||||
Verify that triggers the correct fatal alert.'''
|
||||
milestone: V3
|
||||
tests: ["{name}_tl_intg_err"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
|
|
@ -16,5 +16,14 @@
|
|||
run_opts: ["+run_tl_errors"]
|
||||
reseed: 20
|
||||
}
|
||||
{
|
||||
name: "{name}_tl_intg_err"
|
||||
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
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
55
vendor/lowrisc_ip/dv/tools/dvsim/vcs.hjson
vendored
55
vendor/lowrisc_ip/dv/tools/dvsim/vcs.hjson
vendored
|
@ -48,7 +48,10 @@
|
|||
// - Read capability on registers, variables, and nets
|
||||
// - Write (deposit) capability on registers and variables
|
||||
// - Force capability on registers, variables, and nets
|
||||
// TODO Trim this flag since +f hurts performance.
|
||||
"-debug_access+f",
|
||||
// This option is needed for uvm_hdl_*, when it accesses the array under `celldefine
|
||||
"-debug_region=cell+lib",
|
||||
// Use this to conditionally compile for VCS (example: LRM interpretations differ
|
||||
// across tools).
|
||||
"+define+VCS",
|
||||
|
@ -125,31 +128,47 @@
|
|||
cov_merge_dir: "{scratch_path}/cov_merge"
|
||||
cov_merge_db_dir: "{cov_merge_dir}/merged.vdb"
|
||||
cov_merge_cmd: "{job_prefix} urg"
|
||||
cov_merge_opts: ["-full64",
|
||||
"+urg+lic+wait",
|
||||
"-nocheck",
|
||||
cov_merge_opts: ["-lca",
|
||||
"-full64",
|
||||
// No need of generating report when merging coverage.
|
||||
"-noreport",
|
||||
"-flex_merge drop",
|
||||
"-group merge_across_scopes",
|
||||
// Merge results from tests in parallel.
|
||||
"-parallel",
|
||||
"-parallel_split 20",
|
||||
"-parallel_temproot {cov_merge_dir}",
|
||||
"+urg+lic+wait",
|
||||
// Merge same assert instances found in different VDBs.
|
||||
"-merge_across_libs",
|
||||
// This enables grading on the merged vdb.
|
||||
"-show tests",
|
||||
// Enable union mode of flexible merging for covergroups.
|
||||
"-flex_merge union",
|
||||
// Use cov_db_dirs var for dir args; append -dir in front of each
|
||||
"{eval_cmd} echo {cov_db_dirs} | sed -E 's/(\\S+)/-dir \\1/g'",
|
||||
"-dbname {cov_merge_db_dir}"]
|
||||
|
||||
// Generate coverage reports in text as well as html.
|
||||
cov_report_dir: "{scratch_path}/cov_report"
|
||||
cov_report_cmd: "{job_prefix} urg"
|
||||
cov_report_opts: ["-full64",
|
||||
"+urg+lic+wait",
|
||||
"-dir {cov_merge_db_dir}",
|
||||
"-group instcov_for_score",
|
||||
"-line nocasedef",
|
||||
"-format both",
|
||||
"-elfile {vcs_cov_excl_files}",
|
||||
"-report {cov_report_dir}"]
|
||||
cov_report_txt: "{cov_report_dir}/dashboard.txt"
|
||||
cov_report_page: "dashboard.html"
|
||||
cov_report_dir: "{scratch_path}/cov_report"
|
||||
cov_report_cmd: "{job_prefix} urg"
|
||||
cov_report_opts: ["-lca",
|
||||
"-full64",
|
||||
"+urg+lic+wait",
|
||||
// Lists all the tests that covered a given object.
|
||||
"-show tests",
|
||||
// Enable test grading.
|
||||
"-grade index",
|
||||
// Use simple ratio of total covered bins over total bins across cps & crs,
|
||||
"-group ratio",
|
||||
// Compute overall coverage for per-instance covergroups individually rather
|
||||
// than cumulatively.
|
||||
"-group instcov_for_score",
|
||||
"-dir {cov_merge_db_dir}",
|
||||
"-line nocasedef",
|
||||
"-format both",
|
||||
"-elfile {vcs_cov_excl_files}",
|
||||
"-report {cov_report_dir}"]
|
||||
cov_report_txt: "{cov_report_dir}/dashboard.txt"
|
||||
cov_report_page: "dashboard.html"
|
||||
|
||||
// UNR related.
|
||||
// All code coverage, assert isn't supported
|
||||
|
@ -227,7 +246,7 @@
|
|||
{
|
||||
name: vcs_waves
|
||||
is_sim_mode: 1
|
||||
build_opts: ["-debug_access+all"]
|
||||
build_opts: ["-debug_access"]
|
||||
}
|
||||
{
|
||||
name: vcs_cov
|
||||
|
|
4
vendor/lowrisc_ip/dv/tools/vcs/cover.cfg
vendored
4
vendor/lowrisc_ip/dv/tools/vcs/cover.cfg
vendored
|
@ -9,9 +9,13 @@
|
|||
-module pins_if // DV construct.
|
||||
-module clk_rst_if // DV construct.
|
||||
-moduletree prim_alert_sender // prim_alert_sender is verified in FPV.
|
||||
-moduletree prim_prince // prim_prince is verified in a separate DV environment.
|
||||
-moduletree prim_lfsr // prim_lfsr is verified in FPV.
|
||||
|
||||
begin tgl
|
||||
-tree tb
|
||||
+tree tb.dut 1
|
||||
+module prim_alert_sender
|
||||
+module prim_prince
|
||||
+module prim_lfsr
|
||||
end
|
||||
|
|
|
@ -431,7 +431,7 @@ void DpiMemUtil::LoadElfToMemories(bool verbose, const std::string &filepath) {
|
|||
|
||||
const MemArea &mem_area = *mem_areas_[mem_area_it->second];
|
||||
|
||||
for (const auto seg_pr : staged_mem.GetSegs()) {
|
||||
for (const auto &seg_pr : staged_mem.GetSegs()) {
|
||||
const AddrRange<uint32_t> &seg_rng = seg_pr.first;
|
||||
const std::vector<uint8_t> &seg_data = seg_pr.second;
|
||||
|
||||
|
@ -458,6 +458,9 @@ void DpiMemUtil::StageElf(bool verbose, const std::string &path) {
|
|||
|
||||
ElfFile elf(path);
|
||||
|
||||
// Allow subclasses to get at the loaded ELF data if they need it
|
||||
OnElfLoaded(elf.ptr_);
|
||||
|
||||
size_t file_size;
|
||||
const char *file_data = elf_rawfile(elf.ptr_, &file_size);
|
||||
assert(file_data);
|
||||
|
|
13
vendor/lowrisc_ip/dv/verilator/cpp/dpi_memutil.h
vendored
13
vendor/lowrisc_ip/dv/verilator/cpp/dpi_memutil.h
vendored
|
@ -13,6 +13,9 @@
|
|||
#include "mem_area.h"
|
||||
#include "ranged_map.h"
|
||||
|
||||
// Forward declaration for the Elf type from libelf.
|
||||
struct Elf;
|
||||
|
||||
enum MemImageType {
|
||||
kMemImageUnknown = 0,
|
||||
kMemImageElf,
|
||||
|
@ -59,6 +62,8 @@ class StagedMem {
|
|||
*/
|
||||
class DpiMemUtil {
|
||||
public:
|
||||
virtual ~DpiMemUtil() {}
|
||||
|
||||
/**
|
||||
* Register a memory as instantiated by generic ram
|
||||
*
|
||||
|
@ -128,6 +133,14 @@ class DpiMemUtil {
|
|||
*/
|
||||
const StagedMem &GetMemoryData(const std::string &mem_name) const;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* A hook for subclasses to do extra computations with loaded ELF data. This
|
||||
* runs as part of StageElf: after loading the ELF file, but before reading
|
||||
* in the segments.
|
||||
*/
|
||||
virtual void OnElfLoaded(Elf *elf_file) {}
|
||||
|
||||
private:
|
||||
// Memory area registry. The maps give indices pointing into the vectors
|
||||
// (which all have the same number of elements). Note that mem_areas_ does
|
||||
|
|
|
@ -31,7 +31,7 @@ void Ecc32MemArea::LoadVmem(const std::string &path) const {
|
|||
|
||||
void Ecc32MemArea::WriteBuffer(uint8_t buf[SV_MEM_WIDTH_BYTES],
|
||||
const std::vector<uint8_t> &data,
|
||||
size_t start_idx) const {
|
||||
size_t start_idx, uint32_t dst_word) const {
|
||||
int log_width_32 = width_byte_ / 4;
|
||||
int phy_width_bits = 39 * log_width_32;
|
||||
int phy_width_bytes = (phy_width_bits + 7) / 8;
|
||||
|
@ -116,7 +116,8 @@ void Ecc32MemArea::WriteBuffer(uint8_t buf[SV_MEM_WIDTH_BYTES],
|
|||
}
|
||||
|
||||
void Ecc32MemArea::ReadBuffer(std::vector<uint8_t> &data,
|
||||
const uint8_t buf[SV_MEM_WIDTH_BYTES]) const {
|
||||
const uint8_t buf[SV_MEM_WIDTH_BYTES],
|
||||
uint32_t src_word) const {
|
||||
for (int i = 0; i < width_byte_; ++i) {
|
||||
int in_word = i / 4;
|
||||
|
||||
|
|
|
@ -24,13 +24,14 @@ class Ecc32MemArea : public MemArea {
|
|||
|
||||
void LoadVmem(const std::string &path) const override;
|
||||
|
||||
private:
|
||||
protected:
|
||||
void WriteBuffer(uint8_t buf[SV_MEM_WIDTH_BYTES],
|
||||
const std::vector<uint8_t> &data,
|
||||
size_t start_idx) const override;
|
||||
const std::vector<uint8_t> &data, size_t start_idx,
|
||||
uint32_t dst_word) const override;
|
||||
|
||||
void ReadBuffer(std::vector<uint8_t> &data,
|
||||
const uint8_t buf[SV_MEM_WIDTH_BYTES]) const override;
|
||||
const uint8_t buf[SV_MEM_WIDTH_BYTES],
|
||||
uint32_t src_word) const override;
|
||||
};
|
||||
|
||||
#endif // OPENTITAN_HW_DV_VERILATOR_CPP_ECC32_MEM_AREA_H_
|
||||
|
|
49
vendor/lowrisc_ip/dv/verilator/cpp/mem_area.cc
vendored
49
vendor/lowrisc_ip/dv/verilator/cpp/mem_area.cc
vendored
|
@ -27,10 +27,6 @@ MemArea::MemArea(const std::string &scope, uint32_t num_words,
|
|||
|
||||
void MemArea::Write(uint32_t word_offset,
|
||||
const std::vector<uint8_t> &data) const {
|
||||
// If this fails to set scope, it will throw an error which should
|
||||
// be caught at this function's callsite.
|
||||
SVScoped scoped(scope_);
|
||||
|
||||
// This "mini buffer" is used to transfer each write to SystemVerilog.
|
||||
// `simutil_set_mem` takes a fixed SV_MEM_WIDTH_BITS-bit vector but it will
|
||||
// only use the bits required for the RAM width. As an example, for a 32-bit
|
||||
|
@ -47,8 +43,17 @@ void MemArea::Write(uint32_t word_offset,
|
|||
|
||||
for (uint32_t i = 0; i < data_words; ++i) {
|
||||
uint32_t dst_word = word_offset + i;
|
||||
WriteBuffer(minibuf, data, i * width_byte_);
|
||||
if (!simutil_set_mem(dst_word, (svBitVecVal *)minibuf)) {
|
||||
uint32_t phys_addr = ToPhysAddr(dst_word);
|
||||
|
||||
WriteBuffer(minibuf, data, i * width_byte_, dst_word);
|
||||
|
||||
// Both ToPhysAddr and WriteBuffer might set the scope with `SVScoped` so
|
||||
// only construct `SVScoped` once they've both been called so they don't
|
||||
// interact causing incorrect relative path behaviour. If this fails to set
|
||||
// scope, it will throw an error which should be caught at this function's
|
||||
// callsite.
|
||||
SVScoped scoped(scope_);
|
||||
if (!simutil_set_mem(phys_addr, (svBitVecVal *)minibuf)) {
|
||||
std::ostringstream oss;
|
||||
oss << "Could not set memory at byte offset 0x" << std::hex
|
||||
<< dst_word * width_byte_ << ".";
|
||||
|
@ -64,8 +69,6 @@ std::vector<uint8_t> MemArea::Read(uint32_t word_offset,
|
|||
uint32_t num_bytes = width_byte_ * num_words;
|
||||
assert(num_words <= num_bytes);
|
||||
|
||||
SVScoped scoped(scope_);
|
||||
|
||||
// See Write for an explanation for this buffer.
|
||||
uint8_t minibuf[SV_MEM_WIDTH_BYTES];
|
||||
memset(minibuf, 0, sizeof minibuf);
|
||||
|
@ -76,13 +79,24 @@ std::vector<uint8_t> MemArea::Read(uint32_t word_offset,
|
|||
|
||||
for (uint32_t i = 0; i < num_words; ++i) {
|
||||
uint32_t src_word = word_offset + i;
|
||||
if (!simutil_get_mem(src_word, (svBitVecVal *)minibuf)) {
|
||||
std::ostringstream oss;
|
||||
oss << "Could not read memory at byte offset 0x" << std::hex
|
||||
<< src_word * width_byte_ << ".";
|
||||
throw std::runtime_error(oss.str());
|
||||
uint32_t phys_addr = ToPhysAddr(src_word);
|
||||
|
||||
{
|
||||
// Both ToPhysAddr and ReadBuffer might set the scope with `SVScoped`.
|
||||
// Keep the `SVScoped` here confined to an inner scope so they don't
|
||||
// interact causing incorrect relative path behaviour. If this fails to
|
||||
// set scope, it will throw an error which should be caught at this
|
||||
// function's callsite.
|
||||
SVScoped scoped(scope_);
|
||||
if (!simutil_get_mem(phys_addr, (svBitVecVal *)minibuf)) {
|
||||
std::ostringstream oss;
|
||||
oss << "Could not read memory at byte offset 0x" << std::hex
|
||||
<< src_word * width_byte_ << ".";
|
||||
throw std::runtime_error(oss.str());
|
||||
}
|
||||
}
|
||||
ReadBuffer(ret, minibuf);
|
||||
|
||||
ReadBuffer(ret, minibuf, src_word);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -95,8 +109,8 @@ void MemArea::LoadVmem(const std::string &path) const {
|
|||
}
|
||||
|
||||
void MemArea::WriteBuffer(uint8_t buf[SV_MEM_WIDTH_BYTES],
|
||||
const std::vector<uint8_t> &data,
|
||||
size_t start_idx) const {
|
||||
const std::vector<uint8_t> &data, size_t start_idx,
|
||||
uint32_t dst_word) const {
|
||||
size_t words_left = data.size() - start_idx;
|
||||
size_t to_copy = std::min(words_left, (size_t)width_byte_);
|
||||
if (to_copy < width_byte_) {
|
||||
|
@ -106,7 +120,8 @@ void MemArea::WriteBuffer(uint8_t buf[SV_MEM_WIDTH_BYTES],
|
|||
}
|
||||
|
||||
void MemArea::ReadBuffer(std::vector<uint8_t> &data,
|
||||
const uint8_t buf[SV_MEM_WIDTH_BYTES]) const {
|
||||
const uint8_t buf[SV_MEM_WIDTH_BYTES],
|
||||
uint32_t src_word) const {
|
||||
// Append the first width_byte_ bytes of buf to data.
|
||||
std::copy_n(reinterpret_cast<const char *>(buf), width_byte_,
|
||||
std::back_inserter(data));
|
||||
|
|
26
vendor/lowrisc_ip/dv/verilator/cpp/mem_area.h
vendored
26
vendor/lowrisc_ip/dv/verilator/cpp/mem_area.h
vendored
|
@ -92,10 +92,11 @@ class MemArea {
|
|||
* @param buf Destination buffer
|
||||
* @param data A large buffer that contains the data to be written
|
||||
* @param start_idx An offset into \p data for the start of the memory word
|
||||
* @param dst_word Logical address of the location being written
|
||||
*/
|
||||
virtual void WriteBuffer(uint8_t buf[SV_MEM_WIDTH_BYTES],
|
||||
const std::vector<uint8_t> &data,
|
||||
size_t start_idx) const;
|
||||
const std::vector<uint8_t> &data, size_t start_idx,
|
||||
uint32_t dst_word) const;
|
||||
|
||||
/** Extract the logical memory contents corresponding to the physical
|
||||
* memory contents in \p buf and append them to \p data.
|
||||
|
@ -104,13 +105,26 @@ class MemArea {
|
|||
* across. Other implementations might undo scrambling, remove ECC bits or
|
||||
* similar.
|
||||
*
|
||||
* @param data The target, onto which the extracted memory contents should be
|
||||
* appended.
|
||||
* @param data The target, onto which the extracted memory contents should
|
||||
* be appended.
|
||||
*
|
||||
* @param buf Source buffer (physical memory bits)
|
||||
* @param buf Source buffer (physical memory bits)
|
||||
* @param src_word Logical address of the location being read
|
||||
*/
|
||||
virtual void ReadBuffer(std::vector<uint8_t> &data,
|
||||
const uint8_t buf[SV_MEM_WIDTH_BYTES]) const;
|
||||
const uint8_t buf[SV_MEM_WIDTH_BYTES],
|
||||
uint32_t src_word) const;
|
||||
|
||||
/** Convert a logical address to physical address
|
||||
*
|
||||
* Some memories may have a mapping between the address supplied on the
|
||||
* request and the physical address used to access the memory array (for
|
||||
* example scrambled memories). By default logical and physical address are
|
||||
* the same.
|
||||
*/
|
||||
virtual uint32_t ToPhysAddr(uint32_t logical_addr) const {
|
||||
return logical_addr;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // OPENTITAN_HW_DV_VERILATOR_CPP_MEM_AREA_H_
|
||||
|
|
191
vendor/lowrisc_ip/dv/verilator/cpp/scrambled_ecc32_mem_area.cc
vendored
Normal file
191
vendor/lowrisc_ip/dv/verilator/cpp/scrambled_ecc32_mem_area.cc
vendored
Normal file
|
@ -0,0 +1,191 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#include "scrambled_ecc32_mem_area.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#include "scramble_model.h"
|
||||
#include "sv_scoped.h"
|
||||
|
||||
// This is the maximum width of a nonce that's supported by the code in
|
||||
// prim_util_get_scramble_key_nonce.svh
|
||||
static const uint32_t kScrMaxNonceWidth = 320;
|
||||
static const uint32_t kScrMaxNonceWidthByte = (kScrMaxNonceWidth + 7) / 8;
|
||||
|
||||
// Functions to convert from integer address to/from a little-endian vector of
|
||||
// bytes, addr_width is given in bits
|
||||
static std::vector<uint8_t> AddrIntToBytes(uint32_t addr, uint32_t addr_width) {
|
||||
uint32_t addr_width_bytes = (addr_width + 7) / 8;
|
||||
std::vector<uint8_t> addr_bytes(addr_width_bytes);
|
||||
|
||||
for (int i = 0; i < addr_width_bytes; ++i) {
|
||||
addr_bytes[i] = addr & 0xff;
|
||||
addr >>= 8;
|
||||
}
|
||||
|
||||
return addr_bytes;
|
||||
}
|
||||
|
||||
static uint32_t AddrBytesToInt(const std::vector<uint8_t> &addr) {
|
||||
assert(addr.size() <= 4);
|
||||
|
||||
uint32_t addr_out = 0;
|
||||
int cur_shift = 0;
|
||||
|
||||
for (int i = 0; i < addr.size(); ++i) {
|
||||
addr_out |= (addr[i] << cur_shift);
|
||||
cur_shift += 8;
|
||||
}
|
||||
|
||||
return addr_out;
|
||||
}
|
||||
|
||||
// Converts svBitVecVal (bit[m:n] SV type) into a byte vector
|
||||
static std::vector<uint8_t> ByteVecFromSV(svBitVecVal sv_val[],
|
||||
uint32_t bytes) {
|
||||
int shift = 0;
|
||||
std::vector<uint8_t> vec(bytes);
|
||||
for (int i = 0; i < bytes; ++i) {
|
||||
vec[i] = (sv_val[i / 4] >> shift) & 0xff;
|
||||
|
||||
shift += 8;
|
||||
if (shift == 32) {
|
||||
shift = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
// Analogous to the vbits SystemVerilog function from prim_util_pkg.sv. It
|
||||
// calculates the number of bits needed to address size items.
|
||||
static uint32_t vbits(uint32_t size) {
|
||||
assert(size > 0);
|
||||
|
||||
if (size == 1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
size -= 1;
|
||||
uint32_t width = 0;
|
||||
while (size) {
|
||||
width++;
|
||||
size /= 2;
|
||||
}
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
int simutil_get_scramble_key(svBitVecVal *key);
|
||||
int simutil_get_scramble_nonce(svBitVecVal *nonce);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> ScrambledEcc32MemArea::GetScrambleKey() const {
|
||||
SVScoped scoped(scr_scope_);
|
||||
svBitVecVal key_minibuf[((kPrinceWidthByte * 2) + 3) / 4];
|
||||
|
||||
if (!simutil_get_scramble_key(key_minibuf)) {
|
||||
std::ostringstream oss;
|
||||
oss << "Could not read key at scope " << scr_scope_;
|
||||
throw std::runtime_error(oss.str());
|
||||
}
|
||||
|
||||
return ByteVecFromSV(key_minibuf, kPrinceWidthByte * 2);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> ScrambledEcc32MemArea::GetScrambleNonce() const {
|
||||
assert(GetNonceWidthByte() <= kScrMaxNonceWidthByte);
|
||||
|
||||
SVScoped scoped(scr_scope_);
|
||||
svBitVecVal nonce_minibuf[(kScrMaxNonceWidthByte + 3) / 4];
|
||||
|
||||
if (!simutil_get_scramble_nonce((svBitVecVal *)nonce_minibuf)) {
|
||||
std::ostringstream oss;
|
||||
oss << "Could not read nonce at scope " << scr_scope_;
|
||||
throw std::runtime_error(oss.str());
|
||||
}
|
||||
|
||||
return ByteVecFromSV(nonce_minibuf, GetNonceWidthByte());
|
||||
}
|
||||
|
||||
ScrambledEcc32MemArea::ScrambledEcc32MemArea(const std::string &scope,
|
||||
uint32_t size, uint32_t width_32,
|
||||
bool repeat_keystream)
|
||||
: Ecc32MemArea(
|
||||
SVScoped::join_sv_scopes(
|
||||
scope, "u_prim_ram_1p_adv.u_mem.gen_generic.u_impl_generic"),
|
||||
size, width_32),
|
||||
scr_scope_(scope) {
|
||||
addr_width_ = vbits(size);
|
||||
repeat_keystream_ = repeat_keystream;
|
||||
}
|
||||
|
||||
uint32_t ScrambledEcc32MemArea::GetPhysWidth() const {
|
||||
return (GetWidthByte() / 4) * 39;
|
||||
}
|
||||
|
||||
uint32_t ScrambledEcc32MemArea::GetPhysWidthByte() const {
|
||||
return (GetPhysWidth() + 7) / 8;
|
||||
}
|
||||
|
||||
uint32_t ScrambledEcc32MemArea::GetPrinceReplications() const {
|
||||
if (repeat_keystream_) {
|
||||
return 1;
|
||||
} else {
|
||||
return (GetPhysWidthByte() + 7) / 8;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t ScrambledEcc32MemArea::GetNonceWidth() const {
|
||||
return GetPrinceReplications() * 64;
|
||||
}
|
||||
|
||||
uint32_t ScrambledEcc32MemArea::GetNonceWidthByte() const {
|
||||
return GetPrinceReplications() * 8;
|
||||
}
|
||||
|
||||
void ScrambledEcc32MemArea::WriteBuffer(uint8_t buf[SV_MEM_WIDTH_BYTES],
|
||||
const std::vector<uint8_t> &data,
|
||||
size_t start_idx,
|
||||
uint32_t dst_word) const {
|
||||
// Compute integrity
|
||||
Ecc32MemArea::WriteBuffer(buf, data, start_idx, dst_word);
|
||||
|
||||
std::vector<uint8_t> scramble_buf =
|
||||
std::vector<uint8_t>(buf, buf + GetPhysWidthByte());
|
||||
|
||||
// Scramble data with integrity
|
||||
scramble_buf = scramble_encrypt_data(
|
||||
scramble_buf, GetPhysWidth(), 39, AddrIntToBytes(dst_word, addr_width_),
|
||||
addr_width_, GetScrambleNonce(), GetScrambleKey(), repeat_keystream_);
|
||||
|
||||
// Copy scrambled data to write buffer
|
||||
std::copy(scramble_buf.begin(), scramble_buf.end(), &buf[0]);
|
||||
}
|
||||
|
||||
void ScrambledEcc32MemArea::ReadBuffer(std::vector<uint8_t> &data,
|
||||
const uint8_t buf[SV_MEM_WIDTH_BYTES],
|
||||
uint32_t src_word) const {
|
||||
// Unscramble data from read buffer
|
||||
std::vector<uint8_t> scrambled_data =
|
||||
std::vector<uint8_t>(buf, buf + GetPhysWidthByte());
|
||||
std::vector<uint8_t> unscrambled_data = scramble_decrypt_data(
|
||||
scrambled_data, GetPhysWidth(), 39, AddrIntToBytes(src_word, addr_width_),
|
||||
addr_width_, GetScrambleNonce(), GetScrambleKey(), repeat_keystream_);
|
||||
|
||||
// Strip integrity to give final result
|
||||
Ecc32MemArea::ReadBuffer(data, &unscrambled_data[0], src_word);
|
||||
}
|
||||
|
||||
uint32_t ScrambledEcc32MemArea::ToPhysAddr(uint32_t logical_addr) const {
|
||||
// Scramble logical address to get physical address
|
||||
return AddrBytesToInt(scramble_addr(AddrIntToBytes(logical_addr, addr_width_),
|
||||
addr_width_, GetScrambleNonce(),
|
||||
GetNonceWidth()));
|
||||
}
|
60
vendor/lowrisc_ip/dv/verilator/cpp/scrambled_ecc32_mem_area.h
vendored
Normal file
60
vendor/lowrisc_ip/dv/verilator/cpp/scrambled_ecc32_mem_area.h
vendored
Normal file
|
@ -0,0 +1,60 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#ifndef OPENTITAN_HW_DV_VERILATOR_CPP_SCRAMBLED_ECC32_MEM_AREA_H_
|
||||
#define OPENTITAN_HW_DV_VERILATOR_CPP_SCRAMBLED_ECC32_MEM_AREA_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "ecc32_mem_area.h"
|
||||
|
||||
/**
|
||||
* A memory that implements scrambling over a 32-bit ECC integrity protection
|
||||
* scheme storing 39 = 32 + 7 bits of physical data for each 32 bits of logical
|
||||
* data.
|
||||
*/
|
||||
class ScrambledEcc32MemArea : public Ecc32MemArea {
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* Create an ScrambledEcc32MemArea that will connect to a SystemVerilog memory
|
||||
* at scope. It is size words long. Each memory word is 4 * width_32 bytes
|
||||
* wide in the address space and 39 * width_32 bits wide in the physical
|
||||
* memory.
|
||||
*
|
||||
* If the keystream of one single PRINCE instance should be repeated,
|
||||
* set "repeat_keystream" to true. If this is set to false, multiple
|
||||
* PRINCE instances are employed to produce the keystream.
|
||||
*
|
||||
*/
|
||||
ScrambledEcc32MemArea(const std::string &scope, uint32_t size,
|
||||
uint32_t width_32, bool repeat_keystream = true);
|
||||
|
||||
private:
|
||||
void WriteBuffer(uint8_t buf[SV_MEM_WIDTH_BYTES],
|
||||
const std::vector<uint8_t> &data, size_t start_idx,
|
||||
uint32_t dst_word) const override;
|
||||
|
||||
void ReadBuffer(std::vector<uint8_t> &data,
|
||||
const uint8_t buf[SV_MEM_WIDTH_BYTES],
|
||||
uint32_t src_word) const override;
|
||||
|
||||
uint32_t ToPhysAddr(uint32_t logical_addr) const override;
|
||||
|
||||
uint32_t GetPhysWidth() const;
|
||||
uint32_t GetPhysWidthByte() const;
|
||||
uint32_t GetPrinceReplications() const;
|
||||
uint32_t GetNonceWidth() const;
|
||||
uint32_t GetNonceWidthByte() const;
|
||||
|
||||
std::vector<uint8_t> GetScrambleKey() const;
|
||||
std::vector<uint8_t> GetScrambleNonce() const;
|
||||
|
||||
std::string scr_scope_;
|
||||
uint32_t addr_width_;
|
||||
bool repeat_keystream_;
|
||||
};
|
||||
|
||||
#endif // OPENTITAN_HW_DV_VERILATOR_CPP_SCRAMBLED_ECC32_MEM_AREA_H_
|
|
@ -93,3 +93,12 @@ SVScoped::Error::Error(const std::string &scope_name)
|
|||
oss << "No such SystemVerilog scope: `" << scope_name << "'.";
|
||||
msg_ = oss.str();
|
||||
}
|
||||
|
||||
std::string SVScoped::join_sv_scopes(const std::string &a,
|
||||
const std::string &b) {
|
||||
assert(a.size() && b.size());
|
||||
// If a = ".." and b = "foo.bar", we want "..foo.bar". Otherwise, a
|
||||
// = "..foo" and b = "bar.baz", so we want "..foo.bar.baz"
|
||||
// (inserting a "." between the two)
|
||||
return (a.back() == '.') ? a + b : a + "." + b;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#ifndef OPENTITAN_HW_DV_VERILATOR_CPP_SV_SCOPED_H_
|
||||
#define OPENTITAN_HW_DV_VERILATOR_CPP_SV_SCOPED_H_
|
||||
|
||||
#include <cassert>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <svdpi.h>
|
||||
|
@ -44,6 +45,9 @@ class SVScoped {
|
|||
std::string msg_;
|
||||
};
|
||||
|
||||
// helper function to join two, possibly relative, scopes correctly.
|
||||
static std::string join_sv_scopes(const std::string &a, const std::string &b);
|
||||
|
||||
private:
|
||||
svScope prev_scope_;
|
||||
};
|
||||
|
|
21
vendor/lowrisc_ip/dv/verilator/memutil_dpi_scrambled.core
vendored
Normal file
21
vendor/lowrisc_ip/dv/verilator/memutil_dpi_scrambled.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:dv_verilator:memutil_dpi_scrambled"
|
||||
description: "DPI memory utilities for scrambled memories"
|
||||
filesets:
|
||||
files_cpp:
|
||||
depend:
|
||||
- lowrisc:dv_verilator:memutil_dpi
|
||||
- lowrisc:dv:scramble_model
|
||||
files:
|
||||
- cpp/scrambled_ecc32_mem_area.cc
|
||||
- cpp/scrambled_ecc32_mem_area.h: { is_include_file: true }
|
||||
file_type: cppSource
|
||||
|
||||
targets:
|
||||
default:
|
||||
filesets:
|
||||
- files_cpp
|
44
vendor/lowrisc_ip/dv/verilator/memutil_dpi_scrambled_opts.hjson
vendored
Normal file
44
vendor/lowrisc_ip/dv/verilator/memutil_dpi_scrambled_opts.hjson
vendored
Normal file
|
@ -0,0 +1,44 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
{
|
||||
// Additional build-time options needed to compile C++ sources in
|
||||
// simulators such as VCS and Xcelium for anything that uses
|
||||
// memutil_dpi_scrambled.
|
||||
memutil_dpi_core: "lowrisc:dv_verilator:memutil_dpi:0"
|
||||
memutil_dpi_src_dir: "{eval_cmd} echo \"{memutil_dpi_core}\" | tr ':' '_'"
|
||||
|
||||
memutil_dpi_scrambled_core: "lowrisc:dv_verilator:memutil_dpi_scrambled:0"
|
||||
memutil_dpi_scrambled_src_dir: "{eval_cmd} echo \"{memutil_dpi_scrambled_core}\" | tr ':' '_'"
|
||||
|
||||
secded_enc_core: "lowrisc:dv:secded_enc:0"
|
||||
secded_enc_src_dir: "{eval_cmd} echo \"{secded_enc_core}\" | tr ':' '_'"
|
||||
|
||||
scramble_model_core: "lowrisc:dv:scramble_model:0"
|
||||
scramble_model_dir: "{eval_cmd} echo \"{scramble_model_core}\" | tr ':' '_'"
|
||||
|
||||
prince_ref_core: "lowrisc:dv:crypto_prince_ref:0.1"
|
||||
prince_ref_src_dir: "{eval_cmd} echo \"{prince_ref_core}\" | tr ':' '_'"
|
||||
|
||||
|
||||
build_modes: [
|
||||
{
|
||||
name: vcs_memutil_dpi_scrambled_build_opts
|
||||
build_opts: ["-CFLAGS -I{build_dir}/src/{memutil_dpi_src_dir}/cpp",
|
||||
"-CFLAGS -I{build_dir}/src/{memutil_dpi_scrambled_src_dir}/cpp",
|
||||
"-CFLAGS -I{build_dir}/src/{secded_enc_src_dir}",
|
||||
"-CFLAGS -I{build_dir}/src/{scramble_model_dir}",
|
||||
"-CFLAGS -I{build_dir}/src/{prince_ref_src_dir}",
|
||||
"-lelf"]
|
||||
}
|
||||
|
||||
{
|
||||
name: xcelium_memutil_dpi_scrambled_build_opts
|
||||
build_opts: ["-I{build_dir}/src/{memutil_dpi_src_dir}/cpp",
|
||||
"-I{build_dir}/src/{memutil_dpi_scrambled_src_dir}/cpp",
|
||||
"-I{build_dir}/src/{prince_ref_src_dir}",
|
||||
"-I{build_dir}/src/{scramble_model_dir}",
|
||||
"-lelf"]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -60,6 +60,52 @@ std::pair<int, bool> VerilatorSimCtrl::Exec(int argc, char **argv) {
|
|||
return std::make_pair(retcode, true);
|
||||
}
|
||||
|
||||
static bool read_ul_arg(unsigned long *arg_val, const char *arg_name,
|
||||
const char *arg_text) {
|
||||
assert(arg_val && arg_name && arg_text);
|
||||
|
||||
bool bad_fmt = false;
|
||||
bool out_of_range = false;
|
||||
|
||||
// We have a stricter input format that strtoul: no leading space and no
|
||||
// leading plus or minus signs (strtoul has magic behaviour if the input
|
||||
// starts with a minus sign, but we don't want that). We're using auto base
|
||||
// detection, but a valid number will always start with 0-9 (since hex
|
||||
// constants start with "0x")
|
||||
if (!(('0' <= arg_text[0]) && (arg_text[0] <= '9'))) {
|
||||
bad_fmt = true;
|
||||
} else {
|
||||
char *txt_end;
|
||||
*arg_val = strtoul(arg_text, &txt_end, 0);
|
||||
|
||||
// If txt_end doesn't point at a \0 then we didn't read the entire
|
||||
// argument.
|
||||
if (*txt_end) {
|
||||
bad_fmt = true;
|
||||
} else {
|
||||
// If the value was too big to fit in an unsigned long, strtoul sets
|
||||
// errno to ERANGE.
|
||||
if (errno != 0) {
|
||||
assert(errno == ERANGE);
|
||||
out_of_range = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bad_fmt) {
|
||||
std::cerr << "ERROR: Bad format for " << arg_name << " argument: `"
|
||||
<< arg_text << "' is not an unsigned integer.\n";
|
||||
return false;
|
||||
}
|
||||
if (out_of_range) {
|
||||
std::cerr << "ERROR: Bad format for " << arg_name << " argument: `"
|
||||
<< arg_text << "' is too big.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VerilatorSimCtrl::ParseCommandArgs(int argc, char **argv, bool &exit_app) {
|
||||
const struct option long_options[] = {
|
||||
{"term-after-cycles", required_argument, nullptr, 'c'},
|
||||
|
@ -89,7 +135,10 @@ bool VerilatorSimCtrl::ParseCommandArgs(int argc, char **argv, bool &exit_app) {
|
|||
TraceOn();
|
||||
break;
|
||||
case 'c':
|
||||
term_after_cycles_ = atoi(optarg);
|
||||
if (!read_ul_arg(&term_after_cycles_, "term-after-cycles", optarg)) {
|
||||
exit_app = true;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case 'h':
|
||||
PrintHelp();
|
||||
|
@ -159,6 +208,10 @@ void VerilatorSimCtrl::SetResetDuration(unsigned int cycles) {
|
|||
reset_duration_cycles_ = cycles;
|
||||
}
|
||||
|
||||
void VerilatorSimCtrl::SetTimeout(unsigned int cycles) {
|
||||
term_after_cycles_ = cycles;
|
||||
}
|
||||
|
||||
void VerilatorSimCtrl::RequestStop(bool simulation_success) {
|
||||
request_stop_ = true;
|
||||
simulation_success_ &= simulation_success;
|
||||
|
@ -217,7 +270,7 @@ void VerilatorSimCtrl::PrintHelp() const {
|
|||
" Write a trace file from the start\n\n";
|
||||
}
|
||||
std::cout << "-c|--term-after-cycles=N\n"
|
||||
" Terminate simulation after N cycles\n\n"
|
||||
" Terminate simulation after N cycles. 0 means no timeout.\n\n"
|
||||
"-h|--help\n"
|
||||
" Show help\n\n"
|
||||
"All arguments are passed to the design and can be used "
|
||||
|
|
|
@ -97,6 +97,15 @@ class VerilatorSimCtrl {
|
|||
*/
|
||||
void SetResetDuration(unsigned int cycles);
|
||||
|
||||
/**
|
||||
* Set a timeout in clock cycles.
|
||||
*
|
||||
* This can be overridden by the user (in either direction) with the
|
||||
* --term-after-cycles command-line argument. Setting to zero means
|
||||
* no timeout, which is the default behaviour.
|
||||
*/
|
||||
void SetTimeout(unsigned int cycles);
|
||||
|
||||
/**
|
||||
* Request the simulation to stop
|
||||
*/
|
||||
|
@ -129,7 +138,7 @@ class VerilatorSimCtrl {
|
|||
std::chrono::steady_clock::time_point time_begin_;
|
||||
std::chrono::steady_clock::time_point time_end_;
|
||||
VerilatedTracer tracer_;
|
||||
int term_after_cycles_;
|
||||
unsigned long term_after_cycles_;
|
||||
std::vector<SimCtrlExtension *> extension_array_;
|
||||
|
||||
/**
|
||||
|
|
|
@ -3,11 +3,12 @@ CAPI=2:
|
|||
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
name: "lowrisc:dv:crypto_dpi_prince:0.1"
|
||||
description: "PRINCE block cipher reference C implementation from Sebastien Riou"
|
||||
description: "PRINCE block cipher reference C implementation DPI interface"
|
||||
filesets:
|
||||
files_dv:
|
||||
depend:
|
||||
- lowrisc:dv:crypto_prince_ref
|
||||
files:
|
||||
- prince_ref.h: {file_type: cSource, is_include_file: true}
|
||||
- crypto_dpi_prince.c: {file_type: cSource}
|
||||
- crypto_dpi_prince_pkg.sv: {file_type: systemVerilogSource}
|
||||
|
||||
|
|
22
vendor/lowrisc_ip/ip/prim/dv/prim_prince/crypto_dpi_prince/crypto_dpi_prince_sim_opts.hjson
vendored
Normal file
22
vendor/lowrisc_ip/ip/prim/dv/prim_prince/crypto_dpi_prince/crypto_dpi_prince_sim_opts.hjson
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
|
||||
{
|
||||
// Additional build-time options needed to compile C++ sources in
|
||||
// simulators such as VCS and Xcelium for anything that uses
|
||||
// crypto_prince_ref.
|
||||
crypto_prince_ref_core: "lowrisc:dv:crypto_prince_ref:0.1"
|
||||
crypto_prince_ref_src_dir: "{eval_cmd} echo \"{crypto_prince_ref_core}\" | tr ':' '_'"
|
||||
|
||||
build_modes: [
|
||||
{
|
||||
name: vcs_crypto_dpi_prince_build_opts
|
||||
build_opts: ["-CFLAGS -I{build_dir}/src/{crypto_prince_ref_src_dir}"]
|
||||
}
|
||||
|
||||
{
|
||||
name: xcelium_crypto_dpi_prince_build_opts
|
||||
build_opts: ["-I{build_dir}/src/{crypto_prince_ref_src_dir}"]
|
||||
}
|
||||
]
|
||||
}
|
15
vendor/lowrisc_ip/ip/prim/dv/prim_prince/crypto_dpi_prince/crypto_prince_ref.core
vendored
Normal file
15
vendor/lowrisc_ip/ip/prim/dv/prim_prince/crypto_dpi_prince/crypto_prince_ref.core
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
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:crypto_prince_ref:0.1"
|
||||
description: "PRINCE block cipher reference C implementation from Sebastien Riou"
|
||||
filesets:
|
||||
files_dv:
|
||||
files:
|
||||
- prince_ref.h: {file_type: cSource, is_include_file: true}
|
||||
|
||||
targets:
|
||||
default:
|
||||
filesets:
|
||||
- files_dv
|
|
@ -18,7 +18,11 @@
|
|||
fusesoc_core: lowrisc:dv:prim_prince_sim:0.1
|
||||
|
||||
// Import additional common sim cfg files.
|
||||
import_cfgs: ["{proj_root}/hw/dv/tools/dvsim/common_sim_cfg.hjson"]
|
||||
import_cfgs: ["{proj_root}/hw/dv/tools/dvsim/common_sim_cfg.hjson",
|
||||
// Config files to get the correct flags for crypto_dpi_prince
|
||||
"{proj_root}/hw/ip/prim/dv/prim_prince/crypto_dpi_prince/crypto_dpi_prince_sim_opts.hjson"]
|
||||
|
||||
en_build_modes: ["{tool}_crypto_dpi_prince_build_opts"]
|
||||
|
||||
// Default iterations for all tests - each test entry can override this.
|
||||
reseed: 50
|
||||
|
|
362
vendor/lowrisc_ip/ip/prim/dv/prim_ram_scr/cpp/scramble_model.cc
vendored
Normal file
362
vendor/lowrisc_ip/ip/prim/dv/prim_ram_scr/cpp/scramble_model.cc
vendored
Normal file
|
@ -0,0 +1,362 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#include "scramble_model.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
|
||||
#include "prince_ref.h"
|
||||
|
||||
uint8_t PRESENT_SBOX4[] = {0xc, 0x5, 0x6, 0xb, 0x9, 0x0, 0xa, 0xd,
|
||||
0x3, 0xe, 0xf, 0x8, 0x4, 0x7, 0x1, 0x2};
|
||||
|
||||
uint8_t PRESENT_SBOX4_INV[] = {0x5, 0xe, 0xf, 0x8, 0xc, 0x1, 0x2, 0xd,
|
||||
0xb, 0x4, 0x6, 0x3, 0x0, 0x7, 0x9, 0xa};
|
||||
|
||||
static const uint32_t kNumAddrSubstPermRounds = 2;
|
||||
static const uint32_t kNumDataSubstPermRounds = 2;
|
||||
static const uint32_t kNumPrinceHalfRounds = 2;
|
||||
|
||||
static std::vector<uint8_t> byte_reverse_vector(
|
||||
const std::vector<uint8_t> &vec_in) {
|
||||
std::vector<uint8_t> vec_out(vec_in.size());
|
||||
|
||||
std::reverse_copy(std::begin(vec_in), std::end(vec_in), std::begin(vec_out));
|
||||
|
||||
return vec_out;
|
||||
}
|
||||
|
||||
static uint8_t read_vector_bit(const std::vector<uint8_t> &vec,
|
||||
uint32_t bit_pos) {
|
||||
assert(bit_pos / 8 < vec.size());
|
||||
|
||||
return (vec[bit_pos / 8] >> (bit_pos % 8)) & 1;
|
||||
}
|
||||
|
||||
static void or_vector_bit(std::vector<uint8_t> &vec, uint32_t bit_pos,
|
||||
uint8_t bit) {
|
||||
assert(bit_pos / 8 < vec.size());
|
||||
|
||||
vec[bit_pos / 8] |= bit << (bit_pos % 8);
|
||||
}
|
||||
|
||||
static std::vector<uint8_t> xor_vectors(const std::vector<uint8_t> &vec_a,
|
||||
const std::vector<uint8_t> &vec_b) {
|
||||
assert(vec_a.size() == vec_b.size());
|
||||
|
||||
std::vector<uint8_t> vec_out(vec_a.size());
|
||||
|
||||
std::transform(vec_a.begin(), vec_a.end(), vec_b.begin(), vec_out.begin(),
|
||||
std::bit_xor<uint8_t>{});
|
||||
|
||||
return vec_out;
|
||||
}
|
||||
|
||||
// Run each 4-bit chunk of bytes from `in` through the SBOX. Where `bit_width`
|
||||
// isn't a multiple of 4 the remaining bits are just copied straight through.
|
||||
// `invert` choose whether to use the inverted SBOX or not.
|
||||
static std::vector<uint8_t> scramble_sbox_layer(const std::vector<uint8_t> &in,
|
||||
uint32_t bit_width,
|
||||
uint8_t sbox[16]) {
|
||||
assert(in.size() == ((bit_width + 7) / 8));
|
||||
std::vector<uint8_t> out(in.size(), 0);
|
||||
|
||||
// Iterate through each 4 bit chunk of the data and apply the appropriate SBOX
|
||||
for (int i = 0; i < bit_width / 4; ++i) {
|
||||
uint8_t sbox_in, sbox_out;
|
||||
|
||||
sbox_in = in[i / 2];
|
||||
|
||||
int shift = (i % 2) ? 4 : 0;
|
||||
sbox_in = (sbox_in >> shift) & 0xf;
|
||||
|
||||
sbox_out = sbox[sbox_in];
|
||||
|
||||
out[i / 2] |= sbox_out << shift;
|
||||
}
|
||||
|
||||
// Where bit_width is not a multiple of 4 copy over the remaining bits
|
||||
if (bit_width % 4) {
|
||||
int shift = ((bit_width % 8) >= 4) ? 4 : 0;
|
||||
uint8_t nibble = (in[bit_width / 8] >> shift) & 0xf;
|
||||
out[bit_width / 8] |= nibble << shift;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
// Reverse bits from incoming byte vector
|
||||
static std::vector<uint8_t> scramble_flip_layer(const std::vector<uint8_t> &in,
|
||||
uint32_t bit_width) {
|
||||
assert(in.size() == ((bit_width + 7) / 8));
|
||||
std::vector<uint8_t> out(in.size(), 0);
|
||||
|
||||
for (int i = 0; i < bit_width; ++i) {
|
||||
or_vector_bit(out, bit_width - i - 1, read_vector_bit(in, i));
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
// Apply butterfly to incoming byte vector. Even bits are placed in the lower
|
||||
// half of the output, odd bits are placed in the upper half of the output.
|
||||
static std::vector<uint8_t> scramble_perm_layer(const std::vector<uint8_t> &in,
|
||||
uint32_t bit_width,
|
||||
bool invert) {
|
||||
assert(in.size() == ((bit_width + 7) / 8));
|
||||
std::vector<uint8_t> out(in.size(), 0);
|
||||
|
||||
for (int i = 0; i < bit_width / 2; ++i) {
|
||||
if (invert) {
|
||||
or_vector_bit(out, i * 2, read_vector_bit(in, i));
|
||||
or_vector_bit(out, i * 2 + 1, read_vector_bit(in, i + (bit_width / 2)));
|
||||
} else {
|
||||
or_vector_bit(out, i, read_vector_bit(in, i * 2));
|
||||
or_vector_bit(out, i + (bit_width / 2), read_vector_bit(in, i * 2 + 1));
|
||||
}
|
||||
}
|
||||
|
||||
if (bit_width % 2) {
|
||||
// Where bit_width isn't even, the final bit is copied across to the same
|
||||
// position
|
||||
or_vector_bit(out, bit_width - 1, read_vector_bit(in, bit_width - 1));
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
// Apply a full set of subsitution/permutation rounds for encrypt to the
|
||||
// incoming byte vector
|
||||
static std::vector<uint8_t> scramble_subst_perm_enc(
|
||||
const std::vector<uint8_t> &in, const std::vector<uint8_t> &key,
|
||||
uint32_t bit_width, uint32_t num_rounds) {
|
||||
assert(in.size() == ((bit_width + 7) / 8));
|
||||
assert(key.size() == ((bit_width + 7) / 8));
|
||||
|
||||
std::vector<uint8_t> state(in);
|
||||
|
||||
for (int i = 0; i < num_rounds; ++i) {
|
||||
state = xor_vectors(state, key);
|
||||
|
||||
state = scramble_sbox_layer(state, bit_width, PRESENT_SBOX4);
|
||||
state = scramble_flip_layer(state, bit_width);
|
||||
state = scramble_perm_layer(state, bit_width, false);
|
||||
}
|
||||
|
||||
state = xor_vectors(state, key);
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
// Apply a full set of substitution/permutation rounds for decrypt to the
|
||||
// incoming byte vector
|
||||
static std::vector<uint8_t> scramble_subst_perm_dec(
|
||||
const std::vector<uint8_t> &in, const std::vector<uint8_t> &key,
|
||||
uint32_t bit_width, uint32_t num_rounds) {
|
||||
assert(in.size() == ((bit_width + 7) / 8));
|
||||
assert(key.size() == ((bit_width + 7) / 8));
|
||||
|
||||
std::vector<uint8_t> state(in);
|
||||
|
||||
for (int i = 0; i < num_rounds; ++i) {
|
||||
state = xor_vectors(state, key);
|
||||
|
||||
state = scramble_perm_layer(state, bit_width, true);
|
||||
state = scramble_flip_layer(state, bit_width);
|
||||
state = scramble_sbox_layer(state, bit_width, PRESENT_SBOX4_INV);
|
||||
}
|
||||
|
||||
state = xor_vectors(state, key);
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
// Generate a keystream for XORing with data using PRINCE.
|
||||
// If repeat_keystream is set to true, the output from one PRINCE instance is
|
||||
// repeated when the keystream is greater than a single PRINCE width (64bit).
|
||||
// Otherwise, multiple PRINCEs are instantiated to form the keystream.
|
||||
static std::vector<uint8_t> scramble_gen_keystream(
|
||||
const std::vector<uint8_t> &addr, uint32_t addr_width,
|
||||
const std::vector<uint8_t> &nonce, const std::vector<uint8_t> &key,
|
||||
uint32_t keystream_width, uint32_t num_half_rounds, bool repeat_keystream) {
|
||||
assert(key.size() == (kPrinceWidthByte * 2));
|
||||
|
||||
// Determine how many PRINCE replications are required
|
||||
uint32_t num_princes, num_repetitions;
|
||||
if (repeat_keystream) {
|
||||
num_princes = 1;
|
||||
num_repetitions = (keystream_width + kPrinceWidth - 1) / kPrinceWidth;
|
||||
} else {
|
||||
num_princes = (keystream_width + kPrinceWidth - 1) / kPrinceWidth;
|
||||
num_repetitions = 1;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> keystream;
|
||||
|
||||
for (int i = 0; i < num_princes; ++i) {
|
||||
// Initial vector is data for PRINCE to encrypt. Formed from nonce and data
|
||||
// address
|
||||
std::vector<uint8_t> iv(8, 0);
|
||||
|
||||
for (int j = 0; j < kPrinceWidth; ++j) {
|
||||
if (j < addr_width) {
|
||||
// Bottom addr_width bits of IV are address
|
||||
or_vector_bit(iv, j, read_vector_bit(addr, j));
|
||||
} else {
|
||||
// Other bits are taken from nonce. Each PRINCE instantiation will use
|
||||
// different nonce bits.
|
||||
int nonce_bit = (j - addr_width) + i * (kPrinceWidth - addr_width);
|
||||
or_vector_bit(iv, j, read_vector_bit(nonce, nonce_bit));
|
||||
}
|
||||
}
|
||||
|
||||
// PRINCE C reference model works on big-endian byte order
|
||||
iv = byte_reverse_vector(iv);
|
||||
auto key_be = byte_reverse_vector(key);
|
||||
|
||||
// Apply PRINCE to IV to produce keystream
|
||||
std::vector<uint8_t> keystream_block(kPrinceWidthByte);
|
||||
prince_enc_dec(&iv[0], &key_be[0], &keystream_block[0], 0, num_half_rounds,
|
||||
0);
|
||||
|
||||
// Flip keystream into little endian order and add to keystream vector
|
||||
keystream_block = byte_reverse_vector(keystream_block);
|
||||
// Repeat the output of a single PRINCE instance if needed
|
||||
for (int k = 0; k < num_repetitions; ++k) {
|
||||
keystream.insert(keystream.end(), keystream_block.begin(),
|
||||
keystream_block.end());
|
||||
}
|
||||
}
|
||||
|
||||
// Total keystream bits generated are some multiple of kPrinceWidth. This can
|
||||
// result in unused keystream bits. Remove the unused bytes from the keystream
|
||||
// vector and zero out top unused bits in the final byte if required.
|
||||
uint32_t keystream_bytes = (keystream_width + 7) / 8;
|
||||
uint32_t keystream_bytes_to_erase = keystream.size() - keystream_bytes;
|
||||
if (keystream_bytes_to_erase) {
|
||||
keystream.erase(keystream.end() - keystream_bytes_to_erase,
|
||||
keystream.end());
|
||||
}
|
||||
|
||||
if (keystream_width % 8) {
|
||||
keystream[keystream.size() - 1] &= (1 << (keystream_width % 8)) - 1;
|
||||
}
|
||||
|
||||
return keystream;
|
||||
}
|
||||
|
||||
// Split incoming data into subst_perm_width chunks and individually apply the
|
||||
// substitution/permutation layer to each
|
||||
static std::vector<uint8_t> scramble_subst_perm_full_width(
|
||||
const std::vector<uint8_t> &in, uint32_t bit_width,
|
||||
uint32_t subst_perm_width, bool enc) {
|
||||
assert(in.size() == ((bit_width + 7) / 8));
|
||||
|
||||
// Determine how many bytes each subst_perm_width chunk is and how many
|
||||
// chunks are needed to cover the full bit_width.
|
||||
uint32_t subst_perm_bytes = (subst_perm_width + 7) / 8;
|
||||
uint32_t subst_perm_blocks =
|
||||
(bit_width + subst_perm_width - 1) / subst_perm_width;
|
||||
|
||||
std::vector<uint8_t> out(in.size(), 0);
|
||||
std::vector<uint8_t> zero_key(subst_perm_bytes, 0);
|
||||
|
||||
auto sp_scrambler = enc ? scramble_subst_perm_enc : scramble_subst_perm_dec;
|
||||
|
||||
for (int i = 0; i < subst_perm_blocks; ++i) {
|
||||
// Where bit_width does not evenly divide into subst_perm_width the
|
||||
// final block is smaller.
|
||||
uint32_t bits_so_far = subst_perm_width * i;
|
||||
uint32_t block_width = std::min(subst_perm_width, bit_width - bits_so_far);
|
||||
|
||||
std::vector<uint8_t> subst_perm_data(subst_perm_bytes, 0);
|
||||
|
||||
// Extract bits from in for this chunk
|
||||
for (int j = 0; j < block_width; ++j) {
|
||||
or_vector_bit(subst_perm_data, j,
|
||||
read_vector_bit(in, j + i * subst_perm_width));
|
||||
}
|
||||
|
||||
// Apply the substitution/permutation layer to the chunk
|
||||
auto subst_perm_out = sp_scrambler(subst_perm_data, zero_key, block_width,
|
||||
kNumDataSubstPermRounds);
|
||||
|
||||
// Write the result to the `out` vector
|
||||
for (int j = 0; j < block_width; ++j) {
|
||||
or_vector_bit(out, j + i * subst_perm_width,
|
||||
read_vector_bit(subst_perm_out, j));
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> scramble_addr(const std::vector<uint8_t> &addr_in,
|
||||
uint32_t addr_width,
|
||||
const std::vector<uint8_t> &nonce,
|
||||
uint32_t nonce_width) {
|
||||
assert(addr_in.size() == ((addr_width + 7) / 8));
|
||||
|
||||
std::vector<uint8_t> addr_enc_nonce(addr_in.size(), 0);
|
||||
|
||||
// Address is scrambled by using substitution/permutation layer with the nonce
|
||||
// used as a key.
|
||||
// Extract relevant nonce bits for key
|
||||
for (int i = 0; i < addr_width; ++i) {
|
||||
or_vector_bit(addr_enc_nonce, i,
|
||||
read_vector_bit(nonce, nonce_width - addr_width + i));
|
||||
}
|
||||
|
||||
// Apply substitution/permutation layer
|
||||
return scramble_subst_perm_enc(addr_in, addr_enc_nonce, addr_width,
|
||||
kNumAddrSubstPermRounds);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> scramble_encrypt_data(
|
||||
const std::vector<uint8_t> &data_in, uint32_t data_width,
|
||||
uint32_t subst_perm_width, const std::vector<uint8_t> &addr,
|
||||
uint32_t addr_width, const std::vector<uint8_t> &nonce,
|
||||
const std::vector<uint8_t> &key, bool repeat_keystream) {
|
||||
assert(data_in.size() == ((data_width + 7) / 8));
|
||||
assert(addr.size() == ((addr_width + 7) / 8));
|
||||
|
||||
// Data is encrypted by XORing with keystream then applying
|
||||
// substitution/permutation layer
|
||||
|
||||
auto keystream =
|
||||
scramble_gen_keystream(addr, addr_width, nonce, key, data_width,
|
||||
kNumPrinceHalfRounds, repeat_keystream);
|
||||
|
||||
auto data_enc = xor_vectors(data_in, keystream);
|
||||
|
||||
return scramble_subst_perm_full_width(data_enc, data_width, subst_perm_width,
|
||||
true);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> scramble_decrypt_data(
|
||||
const std::vector<uint8_t> &data_in, uint32_t data_width,
|
||||
uint32_t subst_perm_width, const std::vector<uint8_t> &addr,
|
||||
uint32_t addr_width, const std::vector<uint8_t> &nonce,
|
||||
const std::vector<uint8_t> &key, bool repeat_keystream) {
|
||||
assert(data_in.size() == ((data_width + 7) / 8));
|
||||
assert(addr.size() == ((addr_width + 7) / 8));
|
||||
|
||||
// Data is decrypted by reversing substitution/permutation layer then XORing
|
||||
// with keystream
|
||||
auto data_sp_out = scramble_subst_perm_full_width(data_in, data_width,
|
||||
subst_perm_width, false);
|
||||
|
||||
auto keystream =
|
||||
scramble_gen_keystream(addr, addr_width, nonce, key, data_width,
|
||||
kNumPrinceHalfRounds, repeat_keystream);
|
||||
|
||||
auto data_dec = xor_vectors(data_sp_out, keystream);
|
||||
|
||||
return data_dec;
|
||||
}
|
20
vendor/lowrisc_ip/ip/prim/dv/prim_ram_scr/cpp/scramble_model.core
vendored
Normal file
20
vendor/lowrisc_ip/ip/prim/dv/prim_ram_scr/cpp/scramble_model.core
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
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:scramble_model"
|
||||
description: "Memory scrambling C++ model"
|
||||
filesets:
|
||||
files_cpp:
|
||||
depend:
|
||||
- lowrisc:dv:crypto_prince_ref
|
||||
files:
|
||||
- scramble_model.cc
|
||||
- scramble_model.h: { is_include_file: true }
|
||||
file_type: cppSource
|
||||
|
||||
targets:
|
||||
default:
|
||||
filesets:
|
||||
- files_cpp
|
71
vendor/lowrisc_ip/ip/prim/dv/prim_ram_scr/cpp/scramble_model.h
vendored
Normal file
71
vendor/lowrisc_ip/ip/prim/dv/prim_ram_scr/cpp/scramble_model.h
vendored
Normal file
|
@ -0,0 +1,71 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#ifndef OPENTITAN_HW_IP_PRIM_DV_PRIM_RAM_SCR_CPP_SCRAMBLE_MODEL_H_
|
||||
#define OPENTITAN_HW_IP_PRIM_DV_PRIM_RAM_SCR_CPP_SCRAMBLE_MODEL_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
|
||||
const uint32_t kPrinceWidth = 64;
|
||||
const uint32_t kPrinceWidthByte = kPrinceWidth / 8;
|
||||
|
||||
// C++ model of memory scrambling. All byte vectors are in little endian byte
|
||||
// order (least significant byte at index 0).
|
||||
|
||||
/** Scramble an address to give the physical address used to access the
|
||||
* scrambled memory. Return vector of scrambled address bytes
|
||||
*
|
||||
* @param addr_in Byte vector of address
|
||||
* @param addr_width Width of the address in bits
|
||||
* @param nonce Byte vector of scrambling nonce
|
||||
* @param nonce_width Width of scramble nonce in bits
|
||||
* @return Byte vector with scrambled address
|
||||
*/
|
||||
std::vector<uint8_t> scramble_addr(const std::vector<uint8_t> &addr_in,
|
||||
uint32_t addr_width,
|
||||
const std::vector<uint8_t> &nonce,
|
||||
uint32_t nonce_width);
|
||||
|
||||
/** Decrypt scrambled data
|
||||
* @param data_in Byte vector of data to decrypt
|
||||
* @param data_width Width of data in bits
|
||||
* @param subst_perm_width Width over which the substitution/permutation network
|
||||
* is applied (DiffWidth parameter on prim_ram_1p_scr)
|
||||
* @param addr Byte vector of data address
|
||||
* @param addr_width Width of the address in bits
|
||||
* @param nonce Byte vector of scrambling nonce
|
||||
* @param key Byte vector of scrambling key
|
||||
* @param repeat_keystream Repeat the keystream of one single PRINCE instance if
|
||||
* set to true. Otherwise multiple PRINCE instances are
|
||||
* used.
|
||||
* @return Byte vector with decrypted data
|
||||
*/
|
||||
std::vector<uint8_t> scramble_decrypt_data(
|
||||
const std::vector<uint8_t> &data_in, uint32_t data_width,
|
||||
uint32_t subst_perm_width, const std::vector<uint8_t> &addr,
|
||||
uint32_t addr_width, const std::vector<uint8_t> &nonce,
|
||||
const std::vector<uint8_t> &key, bool repeat_keystream);
|
||||
|
||||
/** Encrypt scrambled data
|
||||
* @param data_in Byte vector of data to encrypt
|
||||
* @param data_width Width of data in bits
|
||||
* @param subst_perm_width Width over which the substitution/permutation network
|
||||
* is applied (DiffWidth parameter on prim_ram_1p_scr)
|
||||
* @param addr Byte vector of data address
|
||||
* @param addr_width Width of the address in bits
|
||||
* @param nonce Byte vector of scrambling nonce
|
||||
* @param key Byte vector of scrambling key
|
||||
* @param repeat_keystream Repeat the keystream of one single PRINCE instance if
|
||||
* set to true. Otherwise multiple PRINCE instances are
|
||||
* used.
|
||||
* @return Byte vector with encrypted data
|
||||
*/
|
||||
std::vector<uint8_t> scramble_encrypt_data(
|
||||
const std::vector<uint8_t> &data_in, uint32_t data_width,
|
||||
uint32_t subst_perm_width, const std::vector<uint8_t> &addr,
|
||||
uint32_t addr_width, const std::vector<uint8_t> &nonce,
|
||||
const std::vector<uint8_t> &key, bool repeat_keystream);
|
||||
|
||||
#endif // OPENTITAN_HW_IP_PRIM_DV_PRIM_RAM_SCR_CPP_SCRAMBLE_MODEL_H_
|
|
@ -8,6 +8,7 @@ filesets:
|
|||
files_formal:
|
||||
depend:
|
||||
- lowrisc:prim:all
|
||||
- lowrisc:prim:alert
|
||||
files:
|
||||
- vip/prim_alert_rxtx_async_assert_fpv.sv
|
||||
- tb/prim_alert_rxtx_async_fatal_fpv.sv
|
||||
|
|
|
@ -8,6 +8,7 @@ filesets:
|
|||
files_formal:
|
||||
depend:
|
||||
- lowrisc:prim:all
|
||||
- lowrisc:prim:alert
|
||||
files:
|
||||
- vip/prim_alert_rxtx_async_assert_fpv.sv
|
||||
- tb/prim_alert_rxtx_async_fpv.sv
|
||||
|
|
|
@ -8,6 +8,7 @@ filesets:
|
|||
files_formal:
|
||||
depend:
|
||||
- lowrisc:prim:all
|
||||
- lowrisc:prim:alert
|
||||
files:
|
||||
- vip/prim_alert_rxtx_assert_fpv.sv
|
||||
- tb/prim_alert_rxtx_fatal_fpv.sv
|
||||
|
|
|
@ -8,6 +8,7 @@ filesets:
|
|||
files_formal:
|
||||
depend:
|
||||
- lowrisc:prim:all
|
||||
- lowrisc:prim:alert
|
||||
files:
|
||||
- vip/prim_alert_rxtx_assert_fpv.sv
|
||||
- tb/prim_alert_rxtx_fpv.sv
|
||||
|
|
|
@ -8,6 +8,7 @@ filesets:
|
|||
files_formal:
|
||||
depend:
|
||||
- lowrisc:prim:all
|
||||
- lowrisc:prim:esc
|
||||
files:
|
||||
- vip/prim_esc_rxtx_assert_fpv.sv
|
||||
- tb/prim_esc_rxtx_bind_fpv.sv
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
module prim_alert_rxtx_async_fatal_fpv
|
||||
import prim_alert_pkg::*;
|
||||
import prim_esc_pkg::*;
|
||||
(
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
module prim_alert_rxtx_async_fpv
|
||||
import prim_alert_pkg::*;
|
||||
import prim_esc_pkg::*;
|
||||
(
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
module prim_alert_rxtx_fatal_fpv
|
||||
import prim_alert_pkg::*;
|
||||
import prim_esc_pkg::*;
|
||||
(
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
module prim_alert_rxtx_fpv
|
||||
import prim_alert_pkg::*;
|
||||
import prim_esc_pkg::*;
|
||||
(
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
|
|
|
@ -9,12 +9,13 @@ module prim_arbiter_ppc_fpv #(
|
|||
parameter int unsigned N = 8,
|
||||
parameter int unsigned DW = 32,
|
||||
parameter bit EnDataPort = 1,
|
||||
parameter bit EnReqStabA = 1,
|
||||
localparam int IdxW = $clog2(N)
|
||||
) (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
|
||||
input req_chk_i,
|
||||
|
||||
input [ N-1:0] req_i,
|
||||
input [DW-1:0] data_i [N],
|
||||
output logic [ N-1:0] gnt_o,
|
||||
|
@ -29,11 +30,11 @@ module prim_arbiter_ppc_fpv #(
|
|||
prim_arbiter_ppc #(
|
||||
.N(N),
|
||||
.DW(DW),
|
||||
.EnDataPort(EnDataPort),
|
||||
.EnReqStabA(EnReqStabA)
|
||||
.EnDataPort(EnDataPort)
|
||||
) i_prim_arbiter_ppc (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.req_chk_i,
|
||||
.req_i,
|
||||
.data_i,
|
||||
.gnt_o,
|
||||
|
|
|
@ -9,12 +9,13 @@ module prim_arbiter_tree_fpv #(
|
|||
parameter int N = 8,
|
||||
parameter int DW = 32,
|
||||
parameter bit EnDataPort = 1,
|
||||
parameter bit EnReqStabA = 1,
|
||||
localparam int IdxW = $clog2(N)
|
||||
) (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
|
||||
input req_chk_i,
|
||||
|
||||
input [ N-1:0] req_i,
|
||||
input [DW-1:0] data_i [N],
|
||||
output logic [ N-1:0] gnt_o,
|
||||
|
@ -29,11 +30,11 @@ module prim_arbiter_tree_fpv #(
|
|||
prim_arbiter_tree #(
|
||||
.N(N),
|
||||
.DW(DW),
|
||||
.EnDataPort(EnDataPort),
|
||||
.EnReqStabA(EnReqStabA)
|
||||
.EnDataPort(EnDataPort)
|
||||
) i_prim_arbiter_tree (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.req_chk_i,
|
||||
.req_i,
|
||||
.data_i,
|
||||
.gnt_o,
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
// a formal tool.
|
||||
|
||||
module prim_esc_rxtx_fpv
|
||||
import prim_alert_pkg::*;
|
||||
import prim_esc_pkg::*;
|
||||
(
|
||||
input clk_i,
|
||||
|
@ -32,7 +31,7 @@ module prim_esc_rxtx_fpv
|
|||
assign esc_tx_in.esc_p = esc_tx_out.esc_p ^ esc_err_pi;
|
||||
assign esc_tx_in.esc_n = esc_tx_out.esc_n ^ esc_err_ni;
|
||||
|
||||
prim_esc_sender i_prim_esc_sender (
|
||||
prim_esc_sender u_prim_esc_sender (
|
||||
.clk_i ,
|
||||
.rst_ni ,
|
||||
.ping_req_i ,
|
||||
|
@ -43,7 +42,11 @@ module prim_esc_rxtx_fpv
|
|||
.esc_tx_o ( esc_tx_out )
|
||||
);
|
||||
|
||||
prim_esc_receiver i_prim_esc_receiver (
|
||||
prim_esc_receiver #(
|
||||
// This reduces the state space for this counter
|
||||
// from 2**24 to 2**6 to speed up convergence.
|
||||
.TimeoutCntDw(6)
|
||||
) u_prim_esc_receiver (
|
||||
.clk_i ,
|
||||
.rst_ni ,
|
||||
.esc_en_o ,
|
||||
|
|
|
@ -10,8 +10,8 @@ module prim_secded_22_16_bind_fpv;
|
|||
prim_secded_22_16_assert_fpv prim_secded_22_16_assert_fpv (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.in,
|
||||
.d_o,
|
||||
.data_i,
|
||||
.data_o,
|
||||
.syndrome_o,
|
||||
.err_o,
|
||||
.error_inject_i
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
module prim_secded_22_16_fpv (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
input [15:0] in,
|
||||
output logic [15:0] d_o,
|
||||
input [15:0] data_i,
|
||||
output logic [15:0] data_o,
|
||||
output logic [5:0] syndrome_o,
|
||||
output logic [1:0] err_o,
|
||||
input [21:0] error_inject_i
|
||||
|
@ -17,13 +17,13 @@ module prim_secded_22_16_fpv (
|
|||
logic [21:0] data_enc;
|
||||
|
||||
prim_secded_22_16_enc prim_secded_22_16_enc (
|
||||
.in,
|
||||
.out(data_enc)
|
||||
.data_i,
|
||||
.data_o(data_enc)
|
||||
);
|
||||
|
||||
prim_secded_22_16_dec prim_secded_22_16_dec (
|
||||
.in(data_enc ^ error_inject_i),
|
||||
.d_o,
|
||||
.data_i(data_enc ^ error_inject_i),
|
||||
.data_o,
|
||||
.syndrome_o,
|
||||
.err_o
|
||||
);
|
||||
|
|
|
@ -10,8 +10,8 @@ module prim_secded_28_22_bind_fpv;
|
|||
prim_secded_28_22_assert_fpv prim_secded_28_22_assert_fpv (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.in,
|
||||
.d_o,
|
||||
.data_i,
|
||||
.data_o,
|
||||
.syndrome_o,
|
||||
.err_o,
|
||||
.error_inject_i
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
module prim_secded_28_22_fpv (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
input [21:0] in,
|
||||
output logic [21:0] d_o,
|
||||
input [21:0] data_i,
|
||||
output logic [21:0] data_o,
|
||||
output logic [5:0] syndrome_o,
|
||||
output logic [1:0] err_o,
|
||||
input [27:0] error_inject_i
|
||||
|
@ -17,13 +17,13 @@ module prim_secded_28_22_fpv (
|
|||
logic [27:0] data_enc;
|
||||
|
||||
prim_secded_28_22_enc prim_secded_28_22_enc (
|
||||
.in,
|
||||
.out(data_enc)
|
||||
.data_i,
|
||||
.data_o(data_enc)
|
||||
);
|
||||
|
||||
prim_secded_28_22_dec prim_secded_28_22_dec (
|
||||
.in(data_enc ^ error_inject_i),
|
||||
.d_o,
|
||||
.data_i(data_enc ^ error_inject_i),
|
||||
.data_o,
|
||||
.syndrome_o,
|
||||
.err_o
|
||||
);
|
||||
|
|
|
@ -10,8 +10,8 @@ module prim_secded_39_32_bind_fpv;
|
|||
prim_secded_39_32_assert_fpv prim_secded_39_32_assert_fpv (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.in,
|
||||
.d_o,
|
||||
.data_i,
|
||||
.data_o,
|
||||
.syndrome_o,
|
||||
.err_o,
|
||||
.error_inject_i
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
module prim_secded_39_32_fpv (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
input [31:0] in,
|
||||
output logic [31:0] d_o,
|
||||
input [31:0] data_i,
|
||||
output logic [31:0] data_o,
|
||||
output logic [6:0] syndrome_o,
|
||||
output logic [1:0] err_o,
|
||||
input [38:0] error_inject_i
|
||||
|
@ -17,13 +17,13 @@ module prim_secded_39_32_fpv (
|
|||
logic [38:0] data_enc;
|
||||
|
||||
prim_secded_39_32_enc prim_secded_39_32_enc (
|
||||
.in,
|
||||
.out(data_enc)
|
||||
.data_i,
|
||||
.data_o(data_enc)
|
||||
);
|
||||
|
||||
prim_secded_39_32_dec prim_secded_39_32_dec (
|
||||
.in(data_enc ^ error_inject_i),
|
||||
.d_o,
|
||||
.data_i(data_enc ^ error_inject_i),
|
||||
.data_o,
|
||||
.syndrome_o,
|
||||
.err_o
|
||||
);
|
||||
|
|
|
@ -10,8 +10,8 @@ module prim_secded_64_57_bind_fpv;
|
|||
prim_secded_64_57_assert_fpv prim_secded_64_57_assert_fpv (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.in,
|
||||
.d_o,
|
||||
.data_i,
|
||||
.data_o,
|
||||
.syndrome_o,
|
||||
.err_o,
|
||||
.error_inject_i
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
module prim_secded_64_57_fpv (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
input [56:0] in,
|
||||
output logic [56:0] d_o,
|
||||
input [56:0] data_i,
|
||||
output logic [56:0] data_o,
|
||||
output logic [6:0] syndrome_o,
|
||||
output logic [1:0] err_o,
|
||||
input [63:0] error_inject_i
|
||||
|
@ -17,13 +17,13 @@ module prim_secded_64_57_fpv (
|
|||
logic [63:0] data_enc;
|
||||
|
||||
prim_secded_64_57_enc prim_secded_64_57_enc (
|
||||
.in,
|
||||
.out(data_enc)
|
||||
.data_i,
|
||||
.data_o(data_enc)
|
||||
);
|
||||
|
||||
prim_secded_64_57_dec prim_secded_64_57_dec (
|
||||
.in(data_enc ^ error_inject_i),
|
||||
.d_o,
|
||||
.data_i(data_enc ^ error_inject_i),
|
||||
.data_o,
|
||||
.syndrome_o,
|
||||
.err_o
|
||||
);
|
||||
|
|
|
@ -10,8 +10,8 @@ module prim_secded_72_64_bind_fpv;
|
|||
prim_secded_72_64_assert_fpv prim_secded_72_64_assert_fpv (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.in,
|
||||
.d_o,
|
||||
.data_i,
|
||||
.data_o,
|
||||
.syndrome_o,
|
||||
.err_o,
|
||||
.error_inject_i
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
module prim_secded_72_64_fpv (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
input [63:0] in,
|
||||
output logic [63:0] d_o,
|
||||
input [63:0] data_i,
|
||||
output logic [63:0] data_o,
|
||||
output logic [7:0] syndrome_o,
|
||||
output logic [1:0] err_o,
|
||||
input [71:0] error_inject_i
|
||||
|
@ -17,13 +17,13 @@ module prim_secded_72_64_fpv (
|
|||
logic [71:0] data_enc;
|
||||
|
||||
prim_secded_72_64_enc prim_secded_72_64_enc (
|
||||
.in,
|
||||
.out(data_enc)
|
||||
.data_i,
|
||||
.data_o(data_enc)
|
||||
);
|
||||
|
||||
prim_secded_72_64_dec prim_secded_72_64_dec (
|
||||
.in(data_enc ^ error_inject_i),
|
||||
.d_o,
|
||||
.data_i(data_enc ^ error_inject_i),
|
||||
.data_o,
|
||||
.syndrome_o,
|
||||
.err_o
|
||||
);
|
||||
|
|
|
@ -10,8 +10,8 @@ module prim_secded_hamming_22_16_bind_fpv;
|
|||
prim_secded_hamming_22_16_assert_fpv prim_secded_hamming_22_16_assert_fpv (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.in,
|
||||
.d_o,
|
||||
.data_i,
|
||||
.data_o,
|
||||
.syndrome_o,
|
||||
.err_o,
|
||||
.error_inject_i
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
module prim_secded_hamming_22_16_fpv (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
input [15:0] in,
|
||||
output logic [15:0] d_o,
|
||||
input [15:0] data_i,
|
||||
output logic [15:0] data_o,
|
||||
output logic [5:0] syndrome_o,
|
||||
output logic [1:0] err_o,
|
||||
input [21:0] error_inject_i
|
||||
|
@ -17,13 +17,13 @@ module prim_secded_hamming_22_16_fpv (
|
|||
logic [21:0] data_enc;
|
||||
|
||||
prim_secded_hamming_22_16_enc prim_secded_hamming_22_16_enc (
|
||||
.in,
|
||||
.out(data_enc)
|
||||
.data_i,
|
||||
.data_o(data_enc)
|
||||
);
|
||||
|
||||
prim_secded_hamming_22_16_dec prim_secded_hamming_22_16_dec (
|
||||
.in(data_enc ^ error_inject_i),
|
||||
.d_o,
|
||||
.data_i(data_enc ^ error_inject_i),
|
||||
.data_o,
|
||||
.syndrome_o,
|
||||
.err_o
|
||||
);
|
||||
|
|
|
@ -10,8 +10,8 @@ module prim_secded_hamming_39_32_bind_fpv;
|
|||
prim_secded_hamming_39_32_assert_fpv prim_secded_hamming_39_32_assert_fpv (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.in,
|
||||
.d_o,
|
||||
.data_i,
|
||||
.data_o,
|
||||
.syndrome_o,
|
||||
.err_o,
|
||||
.error_inject_i
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
module prim_secded_hamming_39_32_fpv (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
input [31:0] in,
|
||||
output logic [31:0] d_o,
|
||||
input [31:0] data_i,
|
||||
output logic [31:0] data_o,
|
||||
output logic [6:0] syndrome_o,
|
||||
output logic [1:0] err_o,
|
||||
input [38:0] error_inject_i
|
||||
|
@ -17,13 +17,13 @@ module prim_secded_hamming_39_32_fpv (
|
|||
logic [38:0] data_enc;
|
||||
|
||||
prim_secded_hamming_39_32_enc prim_secded_hamming_39_32_enc (
|
||||
.in,
|
||||
.out(data_enc)
|
||||
.data_i,
|
||||
.data_o(data_enc)
|
||||
);
|
||||
|
||||
prim_secded_hamming_39_32_dec prim_secded_hamming_39_32_dec (
|
||||
.in(data_enc ^ error_inject_i),
|
||||
.d_o,
|
||||
.data_i(data_enc ^ error_inject_i),
|
||||
.data_o,
|
||||
.syndrome_o,
|
||||
.err_o
|
||||
);
|
||||
|
|
|
@ -10,8 +10,8 @@ module prim_secded_hamming_72_64_bind_fpv;
|
|||
prim_secded_hamming_72_64_assert_fpv prim_secded_hamming_72_64_assert_fpv (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.in,
|
||||
.d_o,
|
||||
.data_i,
|
||||
.data_o,
|
||||
.syndrome_o,
|
||||
.err_o,
|
||||
.error_inject_i
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
module prim_secded_hamming_72_64_fpv (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
input [63:0] in,
|
||||
output logic [63:0] d_o,
|
||||
input [63:0] data_i,
|
||||
output logic [63:0] data_o,
|
||||
output logic [7:0] syndrome_o,
|
||||
output logic [1:0] err_o,
|
||||
input [71:0] error_inject_i
|
||||
|
@ -17,13 +17,13 @@ module prim_secded_hamming_72_64_fpv (
|
|||
logic [71:0] data_enc;
|
||||
|
||||
prim_secded_hamming_72_64_enc prim_secded_hamming_72_64_enc (
|
||||
.in,
|
||||
.out(data_enc)
|
||||
.data_i,
|
||||
.data_o(data_enc)
|
||||
);
|
||||
|
||||
prim_secded_hamming_72_64_dec prim_secded_hamming_72_64_dec (
|
||||
.in(data_enc ^ error_inject_i),
|
||||
.d_o,
|
||||
.data_i(data_enc ^ error_inject_i),
|
||||
.data_o,
|
||||
.syndrome_o,
|
||||
.err_o
|
||||
);
|
||||
|
|
|
@ -24,47 +24,147 @@ module prim_esc_rxtx_assert_fpv (
|
|||
);
|
||||
|
||||
logic error_present;
|
||||
assign error_present = resp_err_pi | resp_err_ni |
|
||||
esc_err_pi | esc_err_ni;
|
||||
assign error_present = resp_err_pi ||
|
||||
resp_err_ni ||
|
||||
esc_err_pi ||
|
||||
esc_err_ni;
|
||||
|
||||
// tracks whether any error has been injected so far
|
||||
logic error_d, error_q;
|
||||
assign error_d = error_q || error_present;
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin : p_error_reg
|
||||
if (!rst_ni) begin
|
||||
error_q <= 1'b0;
|
||||
end else begin
|
||||
error_q <= error_d;
|
||||
end
|
||||
end
|
||||
|
||||
// tracks whether escalation has been triggered so far
|
||||
logic esc_d, esc_q;
|
||||
assign esc_d = esc_q || esc_req_i;
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin : p_esc_reg
|
||||
if (!rst_ni) begin
|
||||
esc_q <= 1'b0;
|
||||
end else begin
|
||||
esc_q <= esc_d;
|
||||
end
|
||||
end
|
||||
|
||||
// ping will stay high until ping ok received, then it must be deasserted
|
||||
// TODO: this escludes 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(PingEnStaysAsserted0_M, ping_req_i |=>
|
||||
(ping_req_i && !ping_ok_o) or (ping_req_i && ping_ok_o ##1 $fell(ping_req_i)),
|
||||
clk_i, !rst_ni || error_present)
|
||||
`ASSUME_FPV(PingReqDeassert_M,
|
||||
ping_req_i &&
|
||||
ping_ok_o
|
||||
|=>
|
||||
!ping_req_i)
|
||||
`ASSUME_FPV(PingReqStaysAsserted0_M,
|
||||
ping_req_i &&
|
||||
!ping_ok_o
|
||||
|=>
|
||||
ping_req_i)
|
||||
// this timing is guaranteed by the lfsr ping timer.
|
||||
`ASSUME_FPV(PingReqStaysLowFor3Cycles_M,
|
||||
$fell(ping_req_i)
|
||||
|->
|
||||
!ping_req_i [*3])
|
||||
|
||||
// assume that the ping enable and escalation enable signals will eventually be deasserted (and
|
||||
// esc will stay low for more than 2 cycles)
|
||||
`ASSUME_FPV(FiniteEsc_M, esc_req_i |-> strong(##[1:$] !esc_req_i [*2]))
|
||||
`ASSUME_FPV(FinitePing_M, ping_req_i |-> strong(##[1:$] !ping_req_i))
|
||||
|
||||
// ping response mus occur within 4 cycles (given that no
|
||||
// error occured within the previous cycles)
|
||||
`ASSERT(PingRespCheck_A, !error_present [*4] ##1 $rose(ping_req_i) |->
|
||||
##[0:4] ping_ok_o, clk_i, !rst_ni || error_present)
|
||||
// assume that escalation enable signal will eventually be deasserted
|
||||
// for more than 3 cycles (this assumption is needed such that the FSM liveness
|
||||
// assertion below can be proven).
|
||||
`ASSUME_FPV(FiniteEsc_M,
|
||||
esc_req_i
|
||||
|->
|
||||
strong(##[1:$] !esc_req_i [*3]))
|
||||
|
||||
// be more specific (i.e. use throughout)
|
||||
`ASSERT(EscRespCheck_A, ##1 esc_req_i |-> ##[0:1] prim_esc_rxtx_fpv.esc_rx_out.resp_p ##1
|
||||
!prim_esc_rxtx_fpv.esc_rx_out.resp_p, clk_i, !rst_ni || error_present)
|
||||
// check that ping response time is bounded if no error has occurred so far, and
|
||||
// no escalation is being requested.
|
||||
`ASSERT(PingRespCheck_A,
|
||||
$rose(ping_req_i) &&
|
||||
!esc_req_i
|
||||
|->
|
||||
##[0:4] ping_ok_o,
|
||||
clk_i,
|
||||
!rst_ni ||
|
||||
error_d ||
|
||||
esc_req_i)
|
||||
|
||||
// check escalation response toggles.
|
||||
`ASSERT(EscRespCheck_A,
|
||||
##1 esc_req_i
|
||||
|->
|
||||
##[0:1] prim_esc_rxtx_fpv.esc_rx_out.resp_p
|
||||
##1 !prim_esc_rxtx_fpv.esc_rx_out.resp_p,
|
||||
clk_i,
|
||||
!rst_ni ||
|
||||
error_present)
|
||||
|
||||
// check correct transmission of escalation within 0-1 cycles
|
||||
`ASSERT(EscCheck_A, ##1 esc_req_i |-> ##[0:1] esc_en_o, clk_i, !rst_ni || error_present)
|
||||
`ASSERT(EscCheck_A,
|
||||
##1 esc_req_i
|
||||
|->
|
||||
##[0:1] esc_en_o,
|
||||
clk_i,
|
||||
!rst_ni ||
|
||||
error_present)
|
||||
|
||||
// check that a single error on the diffpairs is detected
|
||||
`ASSERT(SingleSigIntDetected0_A, {esc_err_pi, esc_err_ni} == '0 ##1
|
||||
$onehot({resp_err_pi, resp_err_ni}) |-> integ_fail_o)
|
||||
`ASSERT(SingleSigIntDetected1_A, $onehot({esc_err_pi, esc_err_ni}) ##1
|
||||
{resp_err_pi, resp_err_ni} == '0 |-> integ_fail_o)
|
||||
`ASSERT(SingleSigIntDetected0_A,
|
||||
{esc_err_pi, esc_err_ni} == '0 ##1
|
||||
$onehot({resp_err_pi, resp_err_ni})
|
||||
|->
|
||||
integ_fail_o)
|
||||
`ASSERT(SingleSigIntDetected1_A,
|
||||
$onehot({esc_err_pi, esc_err_ni}) ##1
|
||||
{resp_err_pi, resp_err_ni} == '0
|
||||
|->
|
||||
integ_fail_o)
|
||||
|
||||
// basic liveness of sender FSM
|
||||
`ASSERT(FsmLivenessSender_A,
|
||||
(prim_esc_rxtx_fpv.u_prim_esc_sender.state_q !=
|
||||
prim_esc_rxtx_fpv.u_prim_esc_sender.Idle)
|
||||
|->
|
||||
strong(##[1:$] (prim_esc_rxtx_fpv.u_prim_esc_sender.state_q
|
||||
== prim_esc_rxtx_fpv.u_prim_esc_sender.Idle)))
|
||||
// basic liveness of sender FSM (can only be guaranteed if no error is present)
|
||||
`ASSERT(FsmLivenessReceiver_A,
|
||||
(prim_esc_rxtx_fpv.u_prim_esc_receiver.state_q !=
|
||||
prim_esc_rxtx_fpv.u_prim_esc_receiver.Idle)
|
||||
|->
|
||||
strong(##[1:$] (prim_esc_rxtx_fpv.u_prim_esc_receiver.state_q
|
||||
== prim_esc_rxtx_fpv.u_prim_esc_receiver.Idle)),
|
||||
clk_i,
|
||||
rst_ni ||
|
||||
error_present)
|
||||
|
||||
// check that auto escalation timeout does not trigger prematurely.
|
||||
// this requires that no errors have been present so far.
|
||||
`ASSERT(AutoEscalation0_A,
|
||||
ping_req_i &&
|
||||
ping_ok_o &&
|
||||
!esc_en_o ##1
|
||||
!ping_req_i [*0 : 2**prim_esc_rxtx_fpv.u_prim_esc_receiver.TimeoutCntDw - 4]
|
||||
|->
|
||||
!esc_en_o,
|
||||
clk_i,
|
||||
!rst_ni ||
|
||||
error_d ||
|
||||
esc_d)
|
||||
|
||||
// check that auto escalation timeout kicks in if pings are absent for too long.
|
||||
// this requires that no errors have been present so far.
|
||||
`ASSERT(AutoEscalation1_A,
|
||||
ping_req_i &&
|
||||
ping_ok_o &&
|
||||
!esc_en_o ##1
|
||||
!ping_req_i [* 2**prim_esc_rxtx_fpv.u_prim_esc_receiver.TimeoutCntDw - 3 : $]
|
||||
|->
|
||||
esc_en_o,
|
||||
clk_i,
|
||||
!rst_ni ||
|
||||
error_d ||
|
||||
esc_d)
|
||||
|
||||
// basic liveness of FSMs in case no errors are present
|
||||
`ASSERT(FsmLivenessSender_A, (prim_esc_rxtx_fpv.i_prim_esc_sender.state_q !=
|
||||
prim_esc_rxtx_fpv.i_prim_esc_sender.Idle) |->
|
||||
strong(##[1:$] (prim_esc_rxtx_fpv.i_prim_esc_sender.state_q
|
||||
== prim_esc_rxtx_fpv.i_prim_esc_sender.Idle)), clk_i, !rst_ni || error_present)
|
||||
`ASSERT(FsmLivenessReceiver_A, (prim_esc_rxtx_fpv.i_prim_esc_receiver.state_q !=
|
||||
prim_esc_rxtx_fpv.i_prim_esc_receiver.Idle) |->
|
||||
strong(##[1:$] (prim_esc_rxtx_fpv.i_prim_esc_receiver.state_q
|
||||
== prim_esc_rxtx_fpv.i_prim_esc_receiver.Idle)), clk_i, !rst_ni || error_present)
|
||||
|
||||
endmodule : prim_esc_rxtx_assert_fpv
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
module prim_secded_22_16_assert_fpv (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
input [15:0] in,
|
||||
input [15:0] d_o,
|
||||
input [15:0] data_i,
|
||||
input [15:0] data_o,
|
||||
input [5:0] syndrome_o,
|
||||
input [1:0] err_o,
|
||||
input [21:0] error_inject_i
|
||||
|
@ -17,7 +17,7 @@ module prim_secded_22_16_assert_fpv (
|
|||
// Inject a maximum of two errors simultaneously.
|
||||
`ASSUME_FPV(MaxTwoErrors_M, $countones(error_inject_i) <= 2)
|
||||
// This bounds the input data state space to make sure the solver converges.
|
||||
`ASSUME_FPV(DataLimit_M, $onehot0(in) || $onehot0(~in))
|
||||
`ASSUME_FPV(DataLimit_M, $onehot0(data_i) || $onehot0(~data_i))
|
||||
// Single bit error detection
|
||||
`ASSERT(SingleErrorDetect_A, $countones(error_inject_i) == 1 |-> err_o[0])
|
||||
`ASSERT(SingleErrorDetectReverse_A, err_o[0] |-> $countones(error_inject_i) == 1)
|
||||
|
@ -25,7 +25,7 @@ module prim_secded_22_16_assert_fpv (
|
|||
`ASSERT(DoubleErrorDetect_A, $countones(error_inject_i) == 2 |-> err_o[1])
|
||||
`ASSERT(DoubleErrorDetectReverse_A, err_o[1] |-> $countones(error_inject_i) == 2)
|
||||
// Single bit error correction (implicitly tests the syndrome output)
|
||||
`ASSERT(SingleErrorCorrect_A, $countones(error_inject_i) < 2 |-> in == d_o)
|
||||
`ASSERT(SingleErrorCorrect_A, $countones(error_inject_i) < 2 |-> data_i == data_o)
|
||||
// Basic syndrome check
|
||||
`ASSERT(SyndromeCheck_A, |syndrome_o |-> $countones(error_inject_i) > 0)
|
||||
`ASSERT(SyndromeCheckReverse_A, $countones(error_inject_i) > 0 |-> |syndrome_o)
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
module prim_secded_28_22_assert_fpv (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
input [21:0] in,
|
||||
input [21:0] d_o,
|
||||
input [21:0] data_i,
|
||||
input [21:0] data_o,
|
||||
input [5:0] syndrome_o,
|
||||
input [1:0] err_o,
|
||||
input [27:0] error_inject_i
|
||||
|
@ -17,7 +17,7 @@ module prim_secded_28_22_assert_fpv (
|
|||
// Inject a maximum of two errors simultaneously.
|
||||
`ASSUME_FPV(MaxTwoErrors_M, $countones(error_inject_i) <= 2)
|
||||
// This bounds the input data state space to make sure the solver converges.
|
||||
`ASSUME_FPV(DataLimit_M, $onehot0(in) || $onehot0(~in))
|
||||
`ASSUME_FPV(DataLimit_M, $onehot0(data_i) || $onehot0(~data_i))
|
||||
// Single bit error detection
|
||||
`ASSERT(SingleErrorDetect_A, $countones(error_inject_i) == 1 |-> err_o[0])
|
||||
`ASSERT(SingleErrorDetectReverse_A, err_o[0] |-> $countones(error_inject_i) == 1)
|
||||
|
@ -25,7 +25,7 @@ module prim_secded_28_22_assert_fpv (
|
|||
`ASSERT(DoubleErrorDetect_A, $countones(error_inject_i) == 2 |-> err_o[1])
|
||||
`ASSERT(DoubleErrorDetectReverse_A, err_o[1] |-> $countones(error_inject_i) == 2)
|
||||
// Single bit error correction (implicitly tests the syndrome output)
|
||||
`ASSERT(SingleErrorCorrect_A, $countones(error_inject_i) < 2 |-> in == d_o)
|
||||
`ASSERT(SingleErrorCorrect_A, $countones(error_inject_i) < 2 |-> data_i == data_o)
|
||||
// Basic syndrome check
|
||||
`ASSERT(SyndromeCheck_A, |syndrome_o |-> $countones(error_inject_i) > 0)
|
||||
`ASSERT(SyndromeCheckReverse_A, $countones(error_inject_i) > 0 |-> |syndrome_o)
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
module prim_secded_39_32_assert_fpv (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
input [31:0] in,
|
||||
input [31:0] d_o,
|
||||
input [31:0] data_i,
|
||||
input [31:0] data_o,
|
||||
input [6:0] syndrome_o,
|
||||
input [1:0] err_o,
|
||||
input [38:0] error_inject_i
|
||||
|
@ -17,7 +17,7 @@ module prim_secded_39_32_assert_fpv (
|
|||
// Inject a maximum of two errors simultaneously.
|
||||
`ASSUME_FPV(MaxTwoErrors_M, $countones(error_inject_i) <= 2)
|
||||
// This bounds the input data state space to make sure the solver converges.
|
||||
`ASSUME_FPV(DataLimit_M, $onehot0(in) || $onehot0(~in))
|
||||
`ASSUME_FPV(DataLimit_M, $onehot0(data_i) || $onehot0(~data_i))
|
||||
// Single bit error detection
|
||||
`ASSERT(SingleErrorDetect_A, $countones(error_inject_i) == 1 |-> err_o[0])
|
||||
`ASSERT(SingleErrorDetectReverse_A, err_o[0] |-> $countones(error_inject_i) == 1)
|
||||
|
@ -25,7 +25,7 @@ module prim_secded_39_32_assert_fpv (
|
|||
`ASSERT(DoubleErrorDetect_A, $countones(error_inject_i) == 2 |-> err_o[1])
|
||||
`ASSERT(DoubleErrorDetectReverse_A, err_o[1] |-> $countones(error_inject_i) == 2)
|
||||
// Single bit error correction (implicitly tests the syndrome output)
|
||||
`ASSERT(SingleErrorCorrect_A, $countones(error_inject_i) < 2 |-> in == d_o)
|
||||
`ASSERT(SingleErrorCorrect_A, $countones(error_inject_i) < 2 |-> data_i == data_o)
|
||||
// Basic syndrome check
|
||||
`ASSERT(SyndromeCheck_A, |syndrome_o |-> $countones(error_inject_i) > 0)
|
||||
`ASSERT(SyndromeCheckReverse_A, $countones(error_inject_i) > 0 |-> |syndrome_o)
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
module prim_secded_64_57_assert_fpv (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
input [56:0] in,
|
||||
input [56:0] d_o,
|
||||
input [56:0] data_i,
|
||||
input [56:0] data_o,
|
||||
input [6:0] syndrome_o,
|
||||
input [1:0] err_o,
|
||||
input [63:0] error_inject_i
|
||||
|
@ -17,7 +17,7 @@ module prim_secded_64_57_assert_fpv (
|
|||
// Inject a maximum of two errors simultaneously.
|
||||
`ASSUME_FPV(MaxTwoErrors_M, $countones(error_inject_i) <= 2)
|
||||
// This bounds the input data state space to make sure the solver converges.
|
||||
`ASSUME_FPV(DataLimit_M, $onehot0(in) || $onehot0(~in))
|
||||
`ASSUME_FPV(DataLimit_M, $onehot0(data_i) || $onehot0(~data_i))
|
||||
// Single bit error detection
|
||||
`ASSERT(SingleErrorDetect_A, $countones(error_inject_i) == 1 |-> err_o[0])
|
||||
`ASSERT(SingleErrorDetectReverse_A, err_o[0] |-> $countones(error_inject_i) == 1)
|
||||
|
@ -25,7 +25,7 @@ module prim_secded_64_57_assert_fpv (
|
|||
`ASSERT(DoubleErrorDetect_A, $countones(error_inject_i) == 2 |-> err_o[1])
|
||||
`ASSERT(DoubleErrorDetectReverse_A, err_o[1] |-> $countones(error_inject_i) == 2)
|
||||
// Single bit error correction (implicitly tests the syndrome output)
|
||||
`ASSERT(SingleErrorCorrect_A, $countones(error_inject_i) < 2 |-> in == d_o)
|
||||
`ASSERT(SingleErrorCorrect_A, $countones(error_inject_i) < 2 |-> data_i == data_o)
|
||||
// Basic syndrome check
|
||||
`ASSERT(SyndromeCheck_A, |syndrome_o |-> $countones(error_inject_i) > 0)
|
||||
`ASSERT(SyndromeCheckReverse_A, $countones(error_inject_i) > 0 |-> |syndrome_o)
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
module prim_secded_72_64_assert_fpv (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
input [63:0] in,
|
||||
input [63:0] d_o,
|
||||
input [63:0] data_i,
|
||||
input [63:0] data_o,
|
||||
input [7:0] syndrome_o,
|
||||
input [1:0] err_o,
|
||||
input [71:0] error_inject_i
|
||||
|
@ -17,7 +17,7 @@ module prim_secded_72_64_assert_fpv (
|
|||
// Inject a maximum of two errors simultaneously.
|
||||
`ASSUME_FPV(MaxTwoErrors_M, $countones(error_inject_i) <= 2)
|
||||
// This bounds the input data state space to make sure the solver converges.
|
||||
`ASSUME_FPV(DataLimit_M, $onehot0(in) || $onehot0(~in))
|
||||
`ASSUME_FPV(DataLimit_M, $onehot0(data_i) || $onehot0(~data_i))
|
||||
// Single bit error detection
|
||||
`ASSERT(SingleErrorDetect_A, $countones(error_inject_i) == 1 |-> err_o[0])
|
||||
`ASSERT(SingleErrorDetectReverse_A, err_o[0] |-> $countones(error_inject_i) == 1)
|
||||
|
@ -25,7 +25,7 @@ module prim_secded_72_64_assert_fpv (
|
|||
`ASSERT(DoubleErrorDetect_A, $countones(error_inject_i) == 2 |-> err_o[1])
|
||||
`ASSERT(DoubleErrorDetectReverse_A, err_o[1] |-> $countones(error_inject_i) == 2)
|
||||
// Single bit error correction (implicitly tests the syndrome output)
|
||||
`ASSERT(SingleErrorCorrect_A, $countones(error_inject_i) < 2 |-> in == d_o)
|
||||
`ASSERT(SingleErrorCorrect_A, $countones(error_inject_i) < 2 |-> data_i == data_o)
|
||||
// Basic syndrome check
|
||||
`ASSERT(SyndromeCheck_A, |syndrome_o |-> $countones(error_inject_i) > 0)
|
||||
`ASSERT(SyndromeCheckReverse_A, $countones(error_inject_i) > 0 |-> |syndrome_o)
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
module prim_secded_hamming_22_16_assert_fpv (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
input [15:0] in,
|
||||
input [15:0] d_o,
|
||||
input [15:0] data_i,
|
||||
input [15:0] data_o,
|
||||
input [5:0] syndrome_o,
|
||||
input [1:0] err_o,
|
||||
input [21:0] error_inject_i
|
||||
|
@ -17,7 +17,7 @@ module prim_secded_hamming_22_16_assert_fpv (
|
|||
// Inject a maximum of two errors simultaneously.
|
||||
`ASSUME_FPV(MaxTwoErrors_M, $countones(error_inject_i) <= 2)
|
||||
// This bounds the input data state space to make sure the solver converges.
|
||||
`ASSUME_FPV(DataLimit_M, $onehot0(in) || $onehot0(~in))
|
||||
`ASSUME_FPV(DataLimit_M, $onehot0(data_i) || $onehot0(~data_i))
|
||||
// Single bit error detection
|
||||
`ASSERT(SingleErrorDetect_A, $countones(error_inject_i) == 1 |-> err_o[0])
|
||||
`ASSERT(SingleErrorDetectReverse_A, err_o[0] |-> $countones(error_inject_i) == 1)
|
||||
|
@ -25,7 +25,7 @@ module prim_secded_hamming_22_16_assert_fpv (
|
|||
`ASSERT(DoubleErrorDetect_A, $countones(error_inject_i) == 2 |-> err_o[1])
|
||||
`ASSERT(DoubleErrorDetectReverse_A, err_o[1] |-> $countones(error_inject_i) == 2)
|
||||
// Single bit error correction (implicitly tests the syndrome output)
|
||||
`ASSERT(SingleErrorCorrect_A, $countones(error_inject_i) < 2 |-> in == d_o)
|
||||
`ASSERT(SingleErrorCorrect_A, $countones(error_inject_i) < 2 |-> data_i == data_o)
|
||||
// Basic syndrome check
|
||||
`ASSERT(SyndromeCheck_A, |syndrome_o |-> $countones(error_inject_i) > 0)
|
||||
`ASSERT(SyndromeCheckReverse_A, $countones(error_inject_i) > 0 |-> |syndrome_o)
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
module prim_secded_hamming_39_32_assert_fpv (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
input [31:0] in,
|
||||
input [31:0] d_o,
|
||||
input [31:0] data_i,
|
||||
input [31:0] data_o,
|
||||
input [6:0] syndrome_o,
|
||||
input [1:0] err_o,
|
||||
input [38:0] error_inject_i
|
||||
|
@ -17,7 +17,7 @@ module prim_secded_hamming_39_32_assert_fpv (
|
|||
// Inject a maximum of two errors simultaneously.
|
||||
`ASSUME_FPV(MaxTwoErrors_M, $countones(error_inject_i) <= 2)
|
||||
// This bounds the input data state space to make sure the solver converges.
|
||||
`ASSUME_FPV(DataLimit_M, $onehot0(in) || $onehot0(~in))
|
||||
`ASSUME_FPV(DataLimit_M, $onehot0(data_i) || $onehot0(~data_i))
|
||||
// Single bit error detection
|
||||
`ASSERT(SingleErrorDetect_A, $countones(error_inject_i) == 1 |-> err_o[0])
|
||||
`ASSERT(SingleErrorDetectReverse_A, err_o[0] |-> $countones(error_inject_i) == 1)
|
||||
|
@ -25,7 +25,7 @@ module prim_secded_hamming_39_32_assert_fpv (
|
|||
`ASSERT(DoubleErrorDetect_A, $countones(error_inject_i) == 2 |-> err_o[1])
|
||||
`ASSERT(DoubleErrorDetectReverse_A, err_o[1] |-> $countones(error_inject_i) == 2)
|
||||
// Single bit error correction (implicitly tests the syndrome output)
|
||||
`ASSERT(SingleErrorCorrect_A, $countones(error_inject_i) < 2 |-> in == d_o)
|
||||
`ASSERT(SingleErrorCorrect_A, $countones(error_inject_i) < 2 |-> data_i == data_o)
|
||||
// Basic syndrome check
|
||||
`ASSERT(SyndromeCheck_A, |syndrome_o |-> $countones(error_inject_i) > 0)
|
||||
`ASSERT(SyndromeCheckReverse_A, $countones(error_inject_i) > 0 |-> |syndrome_o)
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
module prim_secded_hamming_72_64_assert_fpv (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
input [63:0] in,
|
||||
input [63:0] d_o,
|
||||
input [63:0] data_i,
|
||||
input [63:0] data_o,
|
||||
input [7:0] syndrome_o,
|
||||
input [1:0] err_o,
|
||||
input [71:0] error_inject_i
|
||||
|
@ -17,7 +17,7 @@ module prim_secded_hamming_72_64_assert_fpv (
|
|||
// Inject a maximum of two errors simultaneously.
|
||||
`ASSUME_FPV(MaxTwoErrors_M, $countones(error_inject_i) <= 2)
|
||||
// This bounds the input data state space to make sure the solver converges.
|
||||
`ASSUME_FPV(DataLimit_M, $onehot0(in) || $onehot0(~in))
|
||||
`ASSUME_FPV(DataLimit_M, $onehot0(data_i) || $onehot0(~data_i))
|
||||
// Single bit error detection
|
||||
`ASSERT(SingleErrorDetect_A, $countones(error_inject_i) == 1 |-> err_o[0])
|
||||
`ASSERT(SingleErrorDetectReverse_A, err_o[0] |-> $countones(error_inject_i) == 1)
|
||||
|
@ -25,7 +25,7 @@ module prim_secded_hamming_72_64_assert_fpv (
|
|||
`ASSERT(DoubleErrorDetect_A, $countones(error_inject_i) == 2 |-> err_o[1])
|
||||
`ASSERT(DoubleErrorDetectReverse_A, err_o[1] |-> $countones(error_inject_i) == 2)
|
||||
// Single bit error correction (implicitly tests the syndrome output)
|
||||
`ASSERT(SingleErrorCorrect_A, $countones(error_inject_i) < 2 |-> in == d_o)
|
||||
`ASSERT(SingleErrorCorrect_A, $countones(error_inject_i) < 2 |-> data_i == data_o)
|
||||
// Basic syndrome check
|
||||
`ASSERT(SyndromeCheck_A, |syndrome_o |-> $countones(error_inject_i) > 0)
|
||||
`ASSERT(SyndromeCheckReverse_A, $countones(error_inject_i) > 0 |-> |syndrome_o)
|
||||
|
|
9
vendor/lowrisc_ip/ip/prim/lint/prim_ram_1p_scr.vlt
vendored
Normal file
9
vendor/lowrisc_ip/ip/prim/lint/prim_ram_1p_scr.vlt
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
|
||||
|
||||
`verilator_config
|
||||
|
||||
// prim_ram_1p_scr
|
||||
// waive warnings on comparing 'addr_cnt_q' with 32 bit parameters
|
||||
lint_off -rule WIDTH -file "*/rtl/prim_ram_1p_scr.sv" -match "Operator * expects 32 bits on the LHS, but LHS's VARREF 'addr_cnt_q' generates * bits."
|
|
@ -69,6 +69,8 @@ module prim_sync_reqack_tb #(
|
|||
.clk_dst_i (clk_dst),
|
||||
.rst_dst_ni (rst_slow_n),
|
||||
|
||||
.req_chk_i (1'b1),
|
||||
|
||||
.src_req_i (src_req),
|
||||
.src_ack_o (src_ack),
|
||||
.dst_req_o (dst_req),
|
||||
|
|
4
vendor/lowrisc_ip/ip/prim/prim.core
vendored
4
vendor/lowrisc_ip/ip/prim/prim.core
vendored
|
@ -22,14 +22,12 @@ filesets:
|
|||
- lowrisc:prim:arbiter
|
||||
- lowrisc:prim:fifo
|
||||
- lowrisc:prim:alert
|
||||
- lowrisc:prim:esc
|
||||
- lowrisc:prim:subreg
|
||||
- lowrisc:prim:cipher
|
||||
- lowrisc:prim:xor2
|
||||
files:
|
||||
- rtl/prim_clock_gating_sync.sv
|
||||
- rtl/prim_esc_pkg.sv
|
||||
- rtl/prim_esc_receiver.sv
|
||||
- rtl/prim_esc_sender.sv
|
||||
- rtl/prim_sram_arbiter.sv
|
||||
- rtl/prim_slicer.sv
|
||||
- rtl/prim_sync_reqack.sv
|
||||
|
|
1
vendor/lowrisc_ip/ip/prim/prim_alert.core
vendored
1
vendor/lowrisc_ip/ip/prim/prim_alert.core
vendored
|
@ -11,6 +11,7 @@ filesets:
|
|||
- lowrisc:prim:assert
|
||||
- lowrisc:prim:diff_decode
|
||||
- lowrisc:prim:buf
|
||||
- lowrisc:prim:flop
|
||||
files:
|
||||
- rtl/prim_alert_pkg.sv
|
||||
- rtl/prim_alert_receiver.sv
|
||||
|
|
42
vendor/lowrisc_ip/ip/prim/prim_esc.core
vendored
Normal file
42
vendor/lowrisc_ip/ip/prim/prim_esc.core
vendored
Normal file
|
@ -0,0 +1,42 @@
|
|||
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:esc"
|
||||
description: "Escalation send and receive"
|
||||
filesets:
|
||||
files_rtl:
|
||||
depend:
|
||||
- lowrisc:prim:assert
|
||||
- lowrisc:prim:diff_decode
|
||||
- lowrisc:prim:buf
|
||||
- lowrisc:prim:flop
|
||||
files:
|
||||
- rtl/prim_esc_pkg.sv
|
||||
- rtl/prim_esc_receiver.sv
|
||||
- rtl/prim_esc_sender.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
|
1
vendor/lowrisc_ip/ip/prim/prim_fifo.core
vendored
1
vendor/lowrisc_ip/ip/prim/prim_fifo.core
vendored
|
@ -9,6 +9,7 @@ filesets:
|
|||
files_rtl:
|
||||
depend:
|
||||
- lowrisc:prim:assert
|
||||
- lowrisc:prim:util
|
||||
- lowrisc:prim:flop_2sync
|
||||
files:
|
||||
- rtl/prim_fifo_async.sv
|
||||
|
|
11
vendor/lowrisc_ip/ip/prim/prim_ram_1p_scr.core
vendored
11
vendor/lowrisc_ip/ip/prim/prim_ram_1p_scr.core
vendored
|
@ -13,11 +13,22 @@ filesets:
|
|||
- lowrisc:prim:ram_1p_adv
|
||||
- lowrisc:prim:lfsr
|
||||
- lowrisc:prim:all
|
||||
- lowrisc:prim:util_get_scramble_params
|
||||
- lowrisc:dv_verilator:memutil_dpi_scrambled
|
||||
files:
|
||||
- rtl/prim_ram_1p_scr.sv
|
||||
file_type: systemVerilogSource
|
||||
|
||||
files_verilator_waiver:
|
||||
depend:
|
||||
# common waivers
|
||||
- lowrisc:lint:common
|
||||
files:
|
||||
- lint/prim_ram_1p_scr.vlt
|
||||
file_type: vlt
|
||||
|
||||
targets:
|
||||
default:
|
||||
filesets:
|
||||
- tool_verilator ? (files_verilator_waiver)
|
||||
- files_rtl
|
||||
|
|
17
vendor/lowrisc_ip/ip/prim/prim_util_get_scramble_params.core
vendored
Normal file
17
vendor/lowrisc_ip/ip/prim/prim_util_get_scramble_params.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:util_get_scramble_params"
|
||||
description: "DPI functions to snoop scramble key and nonce for simulation"
|
||||
filesets:
|
||||
files_rtl:
|
||||
files:
|
||||
- rtl/prim_util_get_scramble_params.svh: {is_include_file: true}
|
||||
file_type: systemVerilogSource
|
||||
|
||||
targets:
|
||||
default:
|
||||
filesets:
|
||||
- files_rtl
|
|
@ -56,15 +56,25 @@ module prim_alert_receiver
|
|||
/////////////////////////////////
|
||||
// decode differential signals //
|
||||
/////////////////////////////////
|
||||
logic alert_level, alert_sigint;
|
||||
logic alert_level, alert_sigint, alert_p, alert_n;
|
||||
|
||||
// This prevents further tool optimizations of the differential signal.
|
||||
prim_buf #(
|
||||
.Width(2)
|
||||
) u_prim_buf (
|
||||
.in_i({alert_tx_i.alert_n,
|
||||
alert_tx_i.alert_p}),
|
||||
.out_o({alert_n,
|
||||
alert_p})
|
||||
);
|
||||
|
||||
prim_diff_decode #(
|
||||
.AsyncOn(AsyncOn)
|
||||
) i_decode_alert (
|
||||
) u_decode_alert (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.diff_pi ( alert_tx_i.alert_p ),
|
||||
.diff_ni ( alert_tx_i.alert_n ),
|
||||
.diff_pi ( alert_p ),
|
||||
.diff_ni ( alert_n ),
|
||||
.level_o ( alert_level ),
|
||||
.rise_o ( ),
|
||||
.fall_o ( ),
|
||||
|
@ -78,33 +88,43 @@ module prim_alert_receiver
|
|||
typedef enum logic [1:0] {Idle, HsAckWait, Pause0, Pause1} state_e;
|
||||
state_e state_d, state_q;
|
||||
logic ping_rise;
|
||||
logic ping_tog, ping_tog_dp, ping_tog_qp, ping_tog_dn, ping_tog_qn;
|
||||
logic ack, ack_dp, ack_qp, ack_dn, ack_qn;
|
||||
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;
|
||||
|
||||
// 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 = (ping_rise) ? ~ping_tog_qp : ping_tog_qp;
|
||||
assign ping_rise = ping_req_i && !ping_req_q;
|
||||
assign ping_tog_pd = (ping_rise) ? ~ping_tog_pq : ping_tog_pq;
|
||||
|
||||
assign ack_dn = ~ack_pd;
|
||||
assign ping_tog_dn = ~ping_tog_pd;
|
||||
|
||||
// This prevents further tool optimizations of the differential signal.
|
||||
prim_buf u_prim_buf_ack_p (
|
||||
.in_i(ack),
|
||||
.out_o(ack_dp)
|
||||
prim_generic_flop #(
|
||||
.Width (2),
|
||||
.ResetValue(2'b10)
|
||||
) u_prim_generic_flop_ack (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.d_i({ack_dn,
|
||||
ack_pd}),
|
||||
.q_o({ack_nq,
|
||||
ack_pq})
|
||||
);
|
||||
prim_buf u_prim_buf_ack_n (
|
||||
.in_i(~ack),
|
||||
.out_o(ack_dn)
|
||||
);
|
||||
prim_buf u_prim_buf_ping_p (
|
||||
.in_i(ping_tog),
|
||||
.out_o(ping_tog_dp)
|
||||
);
|
||||
prim_buf u_prim_buf_ping_n (
|
||||
.in_i(~ping_tog),
|
||||
.out_o(ping_tog_dn)
|
||||
|
||||
prim_generic_flop #(
|
||||
.Width (2),
|
||||
.ResetValue(2'b10)
|
||||
) u_prim_generic_flop_ping (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.d_i({ping_tog_dn,
|
||||
ping_tog_pd}),
|
||||
.q_o({ping_tog_nq,
|
||||
ping_tog_pq})
|
||||
);
|
||||
|
||||
// the ping pending signal is used to in the FSM to distinguish whether the
|
||||
|
@ -115,11 +135,11 @@ module prim_alert_receiver
|
|||
assign ping_pending_d = ping_rise | ((~ping_ok_o) & ping_req_i & ping_pending_q);
|
||||
|
||||
// diff pair outputs
|
||||
assign alert_rx_o.ack_p = ack_qp;
|
||||
assign alert_rx_o.ack_n = ack_qn;
|
||||
assign alert_rx_o.ack_p = ack_pq;
|
||||
assign alert_rx_o.ack_n = ack_nq;
|
||||
|
||||
assign alert_rx_o.ping_p = ping_tog_qp;
|
||||
assign alert_rx_o.ping_n = ping_tog_qn;
|
||||
assign alert_rx_o.ping_p = ping_tog_pq;
|
||||
assign alert_rx_o.ping_n = ping_tog_nq;
|
||||
|
||||
// this FSM receives the four phase handshakes from the alert receiver
|
||||
// note that the latency of the alert_p/n input diff pair is at least one
|
||||
|
@ -128,7 +148,7 @@ module prim_alert_receiver
|
|||
always_comb begin : p_fsm
|
||||
// default
|
||||
state_d = state_q;
|
||||
ack = 1'b0;
|
||||
ack_pd = 1'b0;
|
||||
ping_ok_o = 1'b0;
|
||||
integ_fail_o = 1'b0;
|
||||
alert_o = 1'b0;
|
||||
|
@ -138,7 +158,7 @@ module prim_alert_receiver
|
|||
// wait for handshake to be initiated
|
||||
if (alert_level) begin
|
||||
state_d = HsAckWait;
|
||||
ack = 1'b1;
|
||||
ack_pd = 1'b1;
|
||||
// signal either an alert or ping received on the output
|
||||
if (ping_pending_q) begin
|
||||
ping_ok_o = 1'b1;
|
||||
|
@ -152,7 +172,7 @@ module prim_alert_receiver
|
|||
if (!alert_level) begin
|
||||
state_d = Pause0;
|
||||
end else begin
|
||||
ack = 1'b1;
|
||||
ack_pd = 1'b1;
|
||||
end
|
||||
end
|
||||
// pause cycles between back-to-back handshakes
|
||||
|
@ -164,7 +184,7 @@ module prim_alert_receiver
|
|||
// override in case of sigint
|
||||
if (alert_sigint) begin
|
||||
state_d = Idle;
|
||||
ack = 1'b0;
|
||||
ack_pd = 1'b0;
|
||||
ping_ok_o = 1'b0;
|
||||
integ_fail_o = 1'b1;
|
||||
alert_o = 1'b0;
|
||||
|
@ -174,18 +194,10 @@ module prim_alert_receiver
|
|||
always_ff @(posedge clk_i or negedge rst_ni) begin : p_reg
|
||||
if (!rst_ni) begin
|
||||
state_q <= Idle;
|
||||
ack_qp <= 1'b0;
|
||||
ack_qn <= 1'b1;
|
||||
ping_tog_qp <= 1'b0;
|
||||
ping_tog_qn <= 1'b1;
|
||||
ping_req_q <= 1'b0;
|
||||
ping_pending_q <= 1'b0;
|
||||
end else begin
|
||||
state_q <= state_d;
|
||||
ack_qp <= ack_dp;
|
||||
ack_qn <= ack_dn;
|
||||
ping_tog_qp <= ping_tog_dp;
|
||||
ping_tog_qn <= ping_tog_dn;
|
||||
ping_req_q <= ping_req_d;
|
||||
ping_pending_q <= ping_pending_d;
|
||||
end
|
||||
|
|
109
vendor/lowrisc_ip/ip/prim/rtl/prim_alert_sender.sv
vendored
109
vendor/lowrisc_ip/ip/prim/rtl/prim_alert_sender.sv
vendored
|
@ -69,36 +69,56 @@ module prim_alert_sender
|
|||
/////////////////////////////////
|
||||
// decode differential signals //
|
||||
/////////////////////////////////
|
||||
logic ping_sigint, ping_event;
|
||||
logic ping_sigint, ping_event, ping_n, ping_p;
|
||||
|
||||
prim_diff_decode #(
|
||||
.AsyncOn(AsyncOn)
|
||||
) i_decode_ping (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.diff_pi ( alert_rx_i.ping_p ),
|
||||
.diff_ni ( alert_rx_i.ping_n ),
|
||||
.level_o ( ),
|
||||
.rise_o ( ),
|
||||
.fall_o ( ),
|
||||
.event_o ( ping_event ),
|
||||
.sigint_o ( ping_sigint )
|
||||
// This prevents further tool optimizations of the differential signal.
|
||||
prim_buf #(
|
||||
.Width(2)
|
||||
) u_prim_buf_ping (
|
||||
.in_i({alert_rx_i.ping_n,
|
||||
alert_rx_i.ping_p}),
|
||||
.out_o({ping_n,
|
||||
ping_p})
|
||||
);
|
||||
|
||||
logic ack_sigint, ack_level;
|
||||
prim_diff_decode #(
|
||||
.AsyncOn(AsyncOn)
|
||||
) u_decode_ping (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.diff_pi ( ping_p ),
|
||||
.diff_ni ( ping_n ),
|
||||
.level_o ( ),
|
||||
.rise_o ( ),
|
||||
.fall_o ( ),
|
||||
.event_o ( ping_event ),
|
||||
.sigint_o ( ping_sigint )
|
||||
);
|
||||
|
||||
logic ack_sigint, ack_level, ack_n, ack_p;
|
||||
|
||||
// This prevents further tool optimizations of the differential signal.
|
||||
prim_buf #(
|
||||
.Width(2)
|
||||
) u_prim_buf_ack (
|
||||
.in_i({alert_rx_i.ack_n,
|
||||
alert_rx_i.ack_p}),
|
||||
.out_o({ack_n,
|
||||
ack_p})
|
||||
);
|
||||
|
||||
prim_diff_decode #(
|
||||
.AsyncOn(AsyncOn)
|
||||
) i_decode_ack (
|
||||
) u_decode_ack (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.diff_pi ( alert_rx_i.ack_p ),
|
||||
.diff_ni ( alert_rx_i.ack_n ),
|
||||
.level_o ( ack_level ),
|
||||
.rise_o ( ),
|
||||
.fall_o ( ),
|
||||
.event_o ( ),
|
||||
.sigint_o ( ack_sigint )
|
||||
.diff_pi ( ack_p ),
|
||||
.diff_ni ( ack_n ),
|
||||
.level_o ( ack_level ),
|
||||
.rise_o ( ),
|
||||
.fall_o ( ),
|
||||
.event_o ( ),
|
||||
.sigint_o ( ack_sigint )
|
||||
);
|
||||
|
||||
|
||||
|
@ -116,7 +136,7 @@ module prim_alert_sender
|
|||
Pause1
|
||||
} state_e;
|
||||
state_e state_d, state_q;
|
||||
logic alert_p, alert_n, alert_pq, alert_nq, alert_pd, alert_nd;
|
||||
logic alert_pq, alert_nq, alert_pd, alert_nd;
|
||||
logic sigint_detected;
|
||||
|
||||
assign sigint_detected = ack_sigint | ping_sigint;
|
||||
|
@ -164,8 +184,8 @@ module prim_alert_sender
|
|||
always_comb begin : p_fsm
|
||||
// default
|
||||
state_d = state_q;
|
||||
alert_p = 1'b0;
|
||||
alert_n = 1'b1;
|
||||
alert_pd = 1'b0;
|
||||
alert_nd = 1'b1;
|
||||
ping_clr = 1'b0;
|
||||
alert_clr = 1'b0;
|
||||
|
||||
|
@ -174,8 +194,8 @@ module prim_alert_sender
|
|||
// alert always takes precedence
|
||||
if (alert_trigger || ping_trigger) begin
|
||||
state_d = (alert_trigger) ? AlertHsPhase1 : PingHsPhase1;
|
||||
alert_p = 1'b1;
|
||||
alert_n = 1'b0;
|
||||
alert_pd = 1'b1;
|
||||
alert_nd = 1'b0;
|
||||
end
|
||||
end
|
||||
// waiting for ack from receiver
|
||||
|
@ -183,8 +203,8 @@ module prim_alert_sender
|
|||
if (ack_level) begin
|
||||
state_d = AlertHsPhase2;
|
||||
end else begin
|
||||
alert_p = 1'b1;
|
||||
alert_n = 1'b0;
|
||||
alert_pd = 1'b1;
|
||||
alert_nd = 1'b0;
|
||||
end
|
||||
end
|
||||
// wait for deassertion of ack
|
||||
|
@ -199,8 +219,8 @@ module prim_alert_sender
|
|||
if (ack_level) begin
|
||||
state_d = PingHsPhase2;
|
||||
end else begin
|
||||
alert_p = 1'b1;
|
||||
alert_n = 1'b0;
|
||||
alert_pd = 1'b1;
|
||||
alert_nd = 1'b0;
|
||||
end
|
||||
end
|
||||
// wait for deassertion of ack
|
||||
|
@ -229,8 +249,8 @@ module prim_alert_sender
|
|||
state_d = Idle;
|
||||
if (sigint_detected) begin
|
||||
state_d = SigInt;
|
||||
alert_p = ~alert_pq;
|
||||
alert_n = ~alert_pq;
|
||||
alert_pd = ~alert_pq;
|
||||
alert_nd = ~alert_pq;
|
||||
end
|
||||
end
|
||||
// catch parasitic states
|
||||
|
@ -239,35 +259,32 @@ module prim_alert_sender
|
|||
// bail out if a signal integrity issue has been detected
|
||||
if (sigint_detected && (state_q != SigInt)) begin
|
||||
state_d = SigInt;
|
||||
alert_p = 1'b0;
|
||||
alert_n = 1'b0;
|
||||
alert_pd = 1'b0;
|
||||
alert_nd = 1'b0;
|
||||
ping_clr = 1'b0;
|
||||
alert_clr = 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
// This prevents further tool optimizations of the differential signal.
|
||||
prim_buf u_prim_buf_p (
|
||||
.in_i(alert_p),
|
||||
.out_o(alert_pd)
|
||||
);
|
||||
prim_buf u_prim_buf_n (
|
||||
.in_i(alert_n),
|
||||
.out_o(alert_nd)
|
||||
prim_generic_flop #(
|
||||
.Width (2),
|
||||
.ResetValue(2'b10)
|
||||
) u_prim_generic_flop (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.d_i({alert_nd, alert_pd}),
|
||||
.q_o({alert_nq, alert_pq})
|
||||
);
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin : p_reg
|
||||
if (!rst_ni) begin
|
||||
state_q <= Idle;
|
||||
alert_pq <= 1'b0;
|
||||
alert_nq <= 1'b1;
|
||||
alert_set_q <= 1'b0;
|
||||
alert_test_set_q <= 1'b0;
|
||||
ping_set_q <= 1'b0;
|
||||
end else begin
|
||||
state_q <= state_d;
|
||||
alert_pq <= alert_pd;
|
||||
alert_nq <= alert_nd;
|
||||
alert_set_q <= alert_set_d;
|
||||
alert_test_set_q <= alert_test_set_d;
|
||||
ping_set_q <= ping_set_d;
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
// N: Number of request ports
|
||||
// DW: Data width
|
||||
// DataPort: Set to 1 to enable the data port. Otherwise that port will be ignored.
|
||||
// EnReqStabA: Checks whether requests remain asserted until granted
|
||||
//
|
||||
// This is the original implementation of the arbiter which relies on parallel prefix computing
|
||||
// optimization to optimize the request / arbiter tree. Not all synthesis tools may support this.
|
||||
|
@ -18,8 +17,8 @@
|
|||
// this behavior.
|
||||
//
|
||||
// Also, this module contains a request stability assertion that checks that requests stay asserted
|
||||
// until they have been served. This assertion can be optionally disabled by setting EnReqStabA to
|
||||
// zero. This is a non-functional parameter and does not affect the designs behavior.
|
||||
// until they have been served. This assertion can be gated by driving the req_chk_i low. This is
|
||||
// a non-functional input and does not affect the designs behavior.
|
||||
//
|
||||
// See also: prim_arbiter_tree
|
||||
|
||||
|
@ -33,15 +32,14 @@ module prim_arbiter_ppc #(
|
|||
// EnDataPort: {0, 1}, if 0, input data will be ignored
|
||||
parameter bit EnDataPort = 1,
|
||||
|
||||
// Non-functional parameter to switch on the request stability assertion
|
||||
parameter bit EnReqStabA = 1,
|
||||
|
||||
// Derived parameters
|
||||
localparam int IdxW = $clog2(N)
|
||||
) (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
|
||||
input req_chk_i, // Used for gating assertions. Drive to 1 during normal
|
||||
// operation.
|
||||
input [ N-1:0] req_i,
|
||||
input [DW-1:0] data_i [N],
|
||||
output logic [ N-1:0] gnt_o,
|
||||
|
@ -52,6 +50,10 @@ module prim_arbiter_ppc #(
|
|||
input ready_i
|
||||
);
|
||||
|
||||
// req_chk_i is used for gating assertions only.
|
||||
logic unused_req_chk;
|
||||
assign unused_req_chk = req_chk_i;
|
||||
|
||||
`ASSERT_INIT(CheckNGreaterZero_A, N > 0)
|
||||
|
||||
// this case is basically just a bypass
|
||||
|
@ -165,13 +167,12 @@ if (EnDataPort) begin: gen_data_port_assertion
|
|||
`ASSERT(DataFlow_A, ready_i && valid_o |-> data_o == data_i[idx_o])
|
||||
end
|
||||
|
||||
if (EnReqStabA) begin : gen_lock_assertion
|
||||
// requests must stay asserted until they have been granted
|
||||
`ASSUME(ReqStaysHighUntilGranted0_M, (|req_i) && !ready_i |=>
|
||||
(req_i & $past(req_i)) == $past(req_i))
|
||||
`ASSUME(ReqStaysHighUntilGranted0_M, |req_i && !ready_i |=>
|
||||
(req_i & $past(req_i)) == $past(req_i), clk_i, !rst_ni || !req_chk_i)
|
||||
// check that the arbitration decision is held if the sink is not ready
|
||||
`ASSERT(LockArbDecision_A, |req_i && !ready_i |=> idx_o == $past(idx_o))
|
||||
end
|
||||
`ASSERT(LockArbDecision_A, |req_i && !ready_i |=> idx_o == $past(idx_o),
|
||||
clk_i, !rst_ni || !req_chk_i)
|
||||
|
||||
// FPV-only assertions with symbolic variables
|
||||
`ifdef FPV_ON
|
||||
|
@ -216,11 +217,9 @@ end
|
|||
end
|
||||
end
|
||||
|
||||
if (EnReqStabA) begin : gen_lock_assertion_fpv
|
||||
// requests must stay asserted until they have been granted
|
||||
`ASSUME(ReqStaysHighUntilGranted1_M, req_i[k] & !gnt_o[k] |=>
|
||||
req_i[k], clk_i, !rst_ni)
|
||||
end
|
||||
// requests must stay asserted until they have been granted
|
||||
`ASSUME(ReqStaysHighUntilGranted1_M, req_i[k] && !gnt_o[k] |=>
|
||||
req_i[k], clk_i, !rst_ni || !req_chk_i)
|
||||
`endif
|
||||
|
||||
endmodule : prim_arbiter_ppc
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
// N: Number of request ports
|
||||
// DW: Data width
|
||||
// DataPort: Set to 1 to enable the data port. Otherwise that port will be ignored.
|
||||
// EnReqStabA: Checks whether requests remain asserted until granted
|
||||
//
|
||||
// This is a tree implementation of a round robin arbiter. It has the same behavior as the PPC
|
||||
// implementation in prim_arbiter_ppc, and also uses a prefix summing approach to determine the next
|
||||
|
@ -25,8 +24,8 @@
|
|||
// this behavior.
|
||||
//
|
||||
// Also, this module contains a request stability assertion that checks that requests stay asserted
|
||||
// until they have been served. This assertion can be optionally disabled by setting EnReqStabA to
|
||||
// zero. This is a non-functional parameter and does not affect the designs behavior.
|
||||
// until they have been served. This assertion can be gated by driving the req_chk_i low. This is
|
||||
// a non-functional input and does not affect the designs behavior.
|
||||
//
|
||||
// See also: prim_arbiter_ppc
|
||||
|
||||
|
@ -40,15 +39,14 @@ module prim_arbiter_tree #(
|
|||
// EnDataPort: {0, 1}, if 0, input data will be ignored
|
||||
parameter bit EnDataPort = 1,
|
||||
|
||||
// Non-functional parameter to switch on the request stability assertion
|
||||
parameter bit EnReqStabA = 1,
|
||||
|
||||
// Derived parameters
|
||||
localparam int IdxW = $clog2(N)
|
||||
) (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
|
||||
input req_chk_i, // Used for gating assertions. Drive to 1 during normal
|
||||
// operation.
|
||||
input [ N-1:0] req_i,
|
||||
input [DW-1:0] data_i [N],
|
||||
output logic [ N-1:0] gnt_o,
|
||||
|
@ -59,6 +57,10 @@ module prim_arbiter_tree #(
|
|||
input ready_i
|
||||
);
|
||||
|
||||
// req_chk_i is used for gating assertions only.
|
||||
logic unused_req_chk;
|
||||
assign unused_req_chk = req_chk_i;
|
||||
|
||||
`ASSERT_INIT(CheckNGreaterZero_A, N > 0)
|
||||
|
||||
// this case is basically just a bypass
|
||||
|
@ -140,25 +142,26 @@ module prim_arbiter_tree #(
|
|||
end else begin : gen_nodes
|
||||
// local helper variable
|
||||
logic sel;
|
||||
always_comb begin : p_node
|
||||
// forward path (requests and data)
|
||||
// each node looks at its two children, and selects the one with higher priority
|
||||
sel = ~req_tree[C0] | ~prio_tree[C0] & prio_tree[C1];
|
||||
// propagate requests
|
||||
req_tree[Pa] = req_tree[C0] | req_tree[C1];
|
||||
prio_tree[Pa] = prio_tree[C1] | prio_tree[C0];
|
||||
// data and index muxes
|
||||
idx_tree[Pa] = (sel) ? idx_tree[C1] : idx_tree[C0];
|
||||
data_tree[Pa] = (sel) ? data_tree[C1] : data_tree[C0];
|
||||
|
||||
// backward path (grants and prefix sum)
|
||||
// this propagates the selction index back and computes a hot one mask
|
||||
sel_tree[C0] = sel_tree[Pa] & ~sel;
|
||||
sel_tree[C1] = sel_tree[Pa] & sel;
|
||||
// this performs a prefix sum for masking the input requests in the next cycle
|
||||
mask_tree[C0] = mask_tree[Pa];
|
||||
mask_tree[C1] = mask_tree[Pa] | sel_tree[C0];
|
||||
end
|
||||
// forward path (requests and data)
|
||||
// each node looks at its two children, and selects the one with higher priority
|
||||
assign sel = ~req_tree[C0] | ~prio_tree[C0] & prio_tree[C1];
|
||||
// propagate requests
|
||||
assign req_tree[Pa] = req_tree[C0] | req_tree[C1];
|
||||
assign prio_tree[Pa] = prio_tree[C1] | prio_tree[C0];
|
||||
// data and index muxes
|
||||
// Note: these ternaries have triggered a synthesis bug in Vivado versions older
|
||||
// than 2020.2. If the problem resurfaces again, have a look at issue #1408.
|
||||
assign idx_tree[Pa] = (sel) ? idx_tree[C1] : idx_tree[C0];
|
||||
assign data_tree[Pa] = (sel) ? data_tree[C1] : data_tree[C0];
|
||||
|
||||
// backward path (grants and prefix sum)
|
||||
// this propagates the selction index back and computes a hot one mask
|
||||
assign sel_tree[C0] = sel_tree[Pa] & ~sel;
|
||||
assign sel_tree[C1] = sel_tree[Pa] & sel;
|
||||
// this performs a prefix sum for masking the input requests in the next cycle
|
||||
assign mask_tree[C0] = mask_tree[Pa];
|
||||
assign mask_tree[C1] = mask_tree[Pa] | sel_tree[C0];
|
||||
end
|
||||
end : gen_level
|
||||
end : gen_tree
|
||||
|
@ -230,13 +233,12 @@ if (EnDataPort) begin: gen_data_port_assertion
|
|||
`ASSERT(DataFlow_A, ready_i && valid_o |-> data_o == data_i[idx_o])
|
||||
end
|
||||
|
||||
if (EnReqStabA) begin : gen_lock_assertion
|
||||
// requests must stay asserted until they have been granted
|
||||
`ASSUME(ReqStaysHighUntilGranted0_M, (|req_i) && !ready_i |=>
|
||||
(req_i & $past(req_i)) == $past(req_i))
|
||||
`ASSUME(ReqStaysHighUntilGranted0_M, |req_i && !ready_i |=>
|
||||
(req_i & $past(req_i)) == $past(req_i), clk_i, !rst_ni || !req_chk_i)
|
||||
// check that the arbitration decision is held if the sink is not ready
|
||||
`ASSERT(LockArbDecision_A, |req_i && !ready_i |=> idx_o == $past(idx_o))
|
||||
end
|
||||
`ASSERT(LockArbDecision_A, |req_i && !ready_i |=> idx_o == $past(idx_o),
|
||||
clk_i, !rst_ni || !req_chk_i)
|
||||
|
||||
// FPV-only assertions with symbolic variables
|
||||
`ifdef FPV_ON
|
||||
|
@ -281,11 +283,9 @@ end
|
|||
end
|
||||
end
|
||||
|
||||
if (EnReqStabA) begin : gen_lock_assertion_fpv
|
||||
// requests must stay asserted until they have been granted
|
||||
`ASSUME(ReqStaysHighUntilGranted1_M, req_i[k] & !gnt_o[k] |=>
|
||||
req_i[k], clk_i, !rst_ni)
|
||||
end
|
||||
// requests must stay asserted until they have been granted
|
||||
`ASSUME(ReqStaysHighUntilGranted1_M, req_i[k] && !gnt_o[k] |=>
|
||||
req_i[k], clk_i, !rst_ni || !req_chk_i)
|
||||
`endif
|
||||
|
||||
endmodule : prim_arbiter_tree
|
||||
|
|
12
vendor/lowrisc_ip/ip/prim/rtl/prim_edn_req.sv
vendored
12
vendor/lowrisc_ip/ip/prim/rtl/prim_edn_req.sv
vendored
|
@ -16,15 +16,13 @@
|
|||
module prim_edn_req
|
||||
import prim_alert_pkg::*;
|
||||
#(
|
||||
parameter int OutWidth = 32,
|
||||
|
||||
// Non-functional parameter to switch on the request stability assertion.
|
||||
// Used in submodule `prim_sync_reqack`.
|
||||
parameter bit EnReqStabA = 1
|
||||
parameter int OutWidth = 32
|
||||
) (
|
||||
// Design side
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
input req_chk_i, // Used for gating assertions. Drive to 1 during normal
|
||||
// operation.
|
||||
input req_i,
|
||||
output logic ack_o,
|
||||
output logic [OutWidth-1:0] data_o,
|
||||
|
@ -46,13 +44,13 @@ module prim_edn_req
|
|||
prim_sync_reqack_data #(
|
||||
.Width(SyncWidth),
|
||||
.DataSrc2Dst(1'b0),
|
||||
.DataReg(1'b0),
|
||||
.EnReqStabA(EnReqStabA)
|
||||
.DataReg(1'b0)
|
||||
) u_prim_sync_reqack_data (
|
||||
.clk_src_i ( clk_i ),
|
||||
.rst_src_ni ( rst_ni ),
|
||||
.clk_dst_i ( clk_edn_i ),
|
||||
.rst_dst_ni ( rst_edn_ni ),
|
||||
.req_chk_i ( req_chk_i ),
|
||||
.src_req_i ( word_req ),
|
||||
.src_ack_o ( word_ack ),
|
||||
.dst_req_o ( edn_o.edn_req ),
|
||||
|
|
141
vendor/lowrisc_ip/ip/prim/rtl/prim_esc_receiver.sv
vendored
141
vendor/lowrisc_ip/ip/prim/rtl/prim_esc_receiver.sv
vendored
|
@ -20,7 +20,32 @@
|
|||
|
||||
module prim_esc_receiver
|
||||
import prim_esc_pkg::*;
|
||||
(
|
||||
#(
|
||||
// The number of escalation severities. Should be set to the Alert Handler's N_ESC_SEV when this
|
||||
// primitive is instantiated.
|
||||
parameter int N_ESC_SEV = 4,
|
||||
|
||||
// The width of the Alert Handler's ping counter. Should be set to the Alert Handler's PING_CNT_DW
|
||||
// when this primitive is instantiated.
|
||||
parameter int PING_CNT_DW = 16,
|
||||
|
||||
// This counter monitors incoming ping requests and auto-escalates if the alert handler
|
||||
// ceases to send them regularly. The maximum number of cycles between subsequent ping requests
|
||||
// is N_ESC_SEV x (2 x 2 x 2**PING_CNT_DW), see also implementation of the ping timer
|
||||
// (alert_handler_ping_timer.sv). The timeout counter below uses a timeout that is 4x larger than
|
||||
// that in order to incorporate some margin.
|
||||
//
|
||||
// Do NOT modify this counter value, when instantiating it in the design. It is only exposed to
|
||||
// reduce the state space in the FPV testbench.
|
||||
localparam int MarginFactor = 4,
|
||||
localparam int NumWaitCounts = 2,
|
||||
localparam int NumTimeoutCounts = 2,
|
||||
parameter int TimeoutCntDw = $clog2(MarginFactor) +
|
||||
$clog2(N_ESC_SEV) +
|
||||
$clog2(NumWaitCounts) +
|
||||
$clog2(NumTimeoutCounts) +
|
||||
PING_CNT_DW
|
||||
) (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
// escalation enable
|
||||
|
@ -35,15 +60,25 @@ module prim_esc_receiver
|
|||
// decode differential signals //
|
||||
/////////////////////////////////
|
||||
|
||||
logic esc_level, sigint_detected;
|
||||
logic esc_level, esc_p, esc_n, sigint_detected;
|
||||
|
||||
// This prevents further tool optimizations of the differential signal.
|
||||
prim_buf #(
|
||||
.Width(2)
|
||||
) u_prim_buf_esc (
|
||||
.in_i({esc_tx_i.esc_n,
|
||||
esc_tx_i.esc_p}),
|
||||
.out_o({esc_n,
|
||||
esc_p})
|
||||
);
|
||||
|
||||
prim_diff_decode #(
|
||||
.AsyncOn(1'b0)
|
||||
) i_decode_esc (
|
||||
) u_decode_esc (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.diff_pi ( esc_tx_i.esc_p ),
|
||||
.diff_ni ( esc_tx_i.esc_n ),
|
||||
.diff_pi ( esc_p ),
|
||||
.diff_ni ( esc_n ),
|
||||
.level_o ( esc_level ),
|
||||
.rise_o ( ),
|
||||
.fall_o ( ),
|
||||
|
@ -51,23 +86,59 @@ module prim_esc_receiver
|
|||
.sigint_o ( sigint_detected )
|
||||
);
|
||||
|
||||
////////////////////////////////////////////
|
||||
// Ping Monitor Counter / Auto Escalation //
|
||||
////////////////////////////////////////////
|
||||
|
||||
logic ping_en, esc_en;
|
||||
logic [1:0][TimeoutCntDw-1:0] cnt_q;
|
||||
|
||||
for (genvar k = 0; k < 2; k++) begin : gen_timeout_cnt
|
||||
|
||||
logic [TimeoutCntDw-1:0] cnt_d;
|
||||
|
||||
// The timeout counter is kicked off when the first ping occurs, and subsequent pings reset
|
||||
// the counter to 1. The counter keeps on counting when it is nonzero, and saturates when it
|
||||
// has reached its maximum (this state is terminal).
|
||||
assign cnt_d = (ping_en && !(&cnt_q[k])) ? TimeoutCntDw'(1) :
|
||||
((cnt_q[k] > '0) && !(&cnt_q[k])) ? cnt_q[k] + 1'b1 :
|
||||
cnt_q[k];
|
||||
prim_flop #(
|
||||
.Width(TimeoutCntDw)
|
||||
) u_prim_flop (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.d_i(cnt_d),
|
||||
.q_o(cnt_q[k])
|
||||
);
|
||||
end
|
||||
|
||||
// Escalation is asserted if
|
||||
// - requested via the escalation sender/receiver path,
|
||||
// - the ping monitor timeout is reached,
|
||||
// - the two ping monitor counters are in an inconsistent state.
|
||||
assign esc_en_o = esc_en ||
|
||||
(&cnt_q[0]) ||
|
||||
(cnt_q[0] != cnt_q[1]);
|
||||
|
||||
/////////////////
|
||||
// RX/TX Logic //
|
||||
/////////////////
|
||||
|
||||
typedef enum logic [2:0] {Idle, Check, PingResp, EscResp, SigInt} state_e;
|
||||
state_e state_d, state_q;
|
||||
logic resp_p, resp_pd, resp_pq;
|
||||
logic resp_n, resp_nd, resp_nq;
|
||||
logic resp_pd, resp_pq;
|
||||
logic resp_nd, resp_nq;
|
||||
|
||||
// This prevents further tool optimizations of the differential signal.
|
||||
prim_buf u_prim_buf_p (
|
||||
.in_i(resp_p),
|
||||
.out_o(resp_pd)
|
||||
);
|
||||
prim_buf u_prim_buf_n (
|
||||
.in_i(resp_n),
|
||||
.out_o(resp_nd)
|
||||
prim_generic_flop #(
|
||||
.Width(2),
|
||||
.ResetValue(2'b10)
|
||||
) u_prim_generic_flop (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.d_i({resp_nd, resp_pd}),
|
||||
.q_o({resp_nq, resp_pq})
|
||||
);
|
||||
|
||||
assign esc_rx_o.resp_p = resp_pq;
|
||||
|
@ -76,17 +147,18 @@ module prim_esc_receiver
|
|||
always_comb begin : p_fsm
|
||||
// default
|
||||
state_d = state_q;
|
||||
resp_p = 1'b0;
|
||||
resp_n = 1'b1;
|
||||
esc_en_o = 1'b0;
|
||||
resp_pd = 1'b0;
|
||||
resp_nd = 1'b1;
|
||||
esc_en = 1'b0;
|
||||
ping_en = 1'b0;
|
||||
|
||||
unique case (state_q)
|
||||
// wait for the esc_p/n diff pair
|
||||
Idle: begin
|
||||
if (esc_level) begin
|
||||
state_d = Check;
|
||||
resp_p = 1'b1;
|
||||
resp_n = 1'b0;
|
||||
resp_pd = 1'b1;
|
||||
resp_nd = 1'b0;
|
||||
end
|
||||
end
|
||||
// we decide here whether this is only a ping request or
|
||||
|
@ -95,18 +167,19 @@ module prim_esc_receiver
|
|||
state_d = PingResp;
|
||||
if (esc_level) begin
|
||||
state_d = EscResp;
|
||||
esc_en_o = 1'b1;
|
||||
esc_en = 1'b1;
|
||||
end
|
||||
end
|
||||
// finish ping response. in case esc_level is again asserted,
|
||||
// we got an escalation signal (pings cannot occur back to back)
|
||||
PingResp: begin
|
||||
state_d = Idle;
|
||||
resp_p = 1'b1;
|
||||
resp_n = 1'b0;
|
||||
resp_pd = 1'b1;
|
||||
resp_nd = 1'b0;
|
||||
ping_en = 1'b1;
|
||||
if (esc_level) begin
|
||||
state_d = EscResp;
|
||||
esc_en_o = 1'b1;
|
||||
esc_en = 1'b1;
|
||||
end
|
||||
end
|
||||
// we have got an escalation enable pulse,
|
||||
|
@ -115,9 +188,9 @@ module prim_esc_receiver
|
|||
state_d = Idle;
|
||||
if (esc_level) begin
|
||||
state_d = EscResp;
|
||||
resp_p = ~resp_pq;
|
||||
resp_n = resp_pq;
|
||||
esc_en_o = 1'b1;
|
||||
resp_pd = ~resp_pq;
|
||||
resp_nd = resp_pq;
|
||||
esc_en = 1'b1;
|
||||
end
|
||||
end
|
||||
// we have a signal integrity issue at one of
|
||||
|
@ -129,8 +202,8 @@ module prim_esc_receiver
|
|||
state_d = Idle;
|
||||
if (sigint_detected) begin
|
||||
state_d = SigInt;
|
||||
resp_p = ~resp_pq;
|
||||
resp_n = ~resp_pq;
|
||||
resp_pd = ~resp_pq;
|
||||
resp_nd = ~resp_pq;
|
||||
end
|
||||
end
|
||||
default : state_d = Idle;
|
||||
|
@ -139,8 +212,8 @@ module prim_esc_receiver
|
|||
// bail out if a signal integrity issue has been detected
|
||||
if (sigint_detected && (state_q != SigInt)) begin
|
||||
state_d = SigInt;
|
||||
resp_p = 1'b0;
|
||||
resp_n = 1'b0;
|
||||
resp_pd = 1'b0;
|
||||
resp_nd = 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -152,12 +225,8 @@ module prim_esc_receiver
|
|||
always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs
|
||||
if (!rst_ni) begin
|
||||
state_q <= Idle;
|
||||
resp_pq <= 1'b0;
|
||||
resp_nq <= 1'b1;
|
||||
end else begin
|
||||
state_q <= state_d;
|
||||
resp_pq <= resp_pd;
|
||||
resp_nq <= resp_nd;
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -186,5 +255,9 @@ module prim_esc_receiver
|
|||
// detect escalation pulse
|
||||
`ASSERT(EscEnCheck_A, esc_tx_i.esc_p && (esc_tx_i.esc_p ^ esc_tx_i.esc_n) && state_q != SigInt
|
||||
|=> esc_tx_i.esc_p && (esc_tx_i.esc_p ^ esc_tx_i.esc_n) |-> esc_en_o)
|
||||
// make sure the counter does not wrap around
|
||||
`ASSERT(EscCntWrap_A, &cnt_q[0] |=> cnt_q[0] != 0)
|
||||
// if the counter expires, escalation should be asserted
|
||||
`ASSERT(EscCntEsc_A, &cnt_q[0] |-> esc_en_o)
|
||||
|
||||
endmodule : prim_esc_receiver
|
||||
|
|
32
vendor/lowrisc_ip/ip/prim/rtl/prim_esc_sender.sv
vendored
32
vendor/lowrisc_ip/ip/prim/rtl/prim_esc_sender.sv
vendored
|
@ -43,15 +43,25 @@ module prim_esc_sender
|
|||
// decode differential signals //
|
||||
/////////////////////////////////
|
||||
|
||||
logic resp, sigint_detected;
|
||||
logic resp, resp_n, resp_p, sigint_detected;
|
||||
|
||||
// This prevents further tool optimizations of the differential signal.
|
||||
prim_buf #(
|
||||
.Width(2)
|
||||
) u_prim_buf_resp (
|
||||
.in_i({esc_rx_i.resp_n,
|
||||
esc_rx_i.resp_p}),
|
||||
.out_o({resp_n,
|
||||
resp_p})
|
||||
);
|
||||
|
||||
prim_diff_decode #(
|
||||
.AsyncOn(1'b0)
|
||||
) i_decode_resp (
|
||||
) u_decode_resp (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.diff_pi ( esc_rx_i.resp_p ),
|
||||
.diff_ni ( esc_rx_i.resp_n ),
|
||||
.diff_pi ( resp_p ),
|
||||
.diff_ni ( resp_n ),
|
||||
.level_o ( resp ),
|
||||
.rise_o ( ),
|
||||
.fall_o ( ),
|
||||
|
@ -75,13 +85,13 @@ module prim_esc_sender
|
|||
assign esc_p = esc_req_i | esc_req_q | (ping_req_d & ~ping_req_q);
|
||||
|
||||
// This prevents further tool optimizations of the differential signal.
|
||||
prim_buf u_prim_buf_p (
|
||||
.in_i(esc_p),
|
||||
.out_o(esc_tx_o.esc_p)
|
||||
);
|
||||
prim_buf u_prim_buf_n (
|
||||
.in_i(~esc_p),
|
||||
.out_o(esc_tx_o.esc_n)
|
||||
prim_buf #(
|
||||
.Width(2)
|
||||
) u_prim_buf_esc (
|
||||
.in_i({~esc_p,
|
||||
esc_p}),
|
||||
.out_o({esc_tx_o.esc_n,
|
||||
esc_tx_o.esc_p})
|
||||
);
|
||||
|
||||
//////////////
|
||||
|
|
46
vendor/lowrisc_ip/ip/prim/rtl/prim_fifo_async.sv
vendored
46
vendor/lowrisc_ip/ip/prim/rtl/prim_fifo_async.sv
vendored
|
@ -52,7 +52,7 @@ module prim_fifo_async #(
|
|||
assign fifo_incr_wptr = wvalid_i & wready_o;
|
||||
|
||||
// decimal version
|
||||
assign fifo_wptr_d = fifo_wptr_q + PTR_WIDTH'(1);
|
||||
assign fifo_wptr_d = fifo_wptr_q + PTR_WIDTH'(1'b1);
|
||||
|
||||
always_ff @(posedge clk_wr_i or negedge rst_wr_ni) begin
|
||||
if (!rst_wr_ni) begin
|
||||
|
@ -85,7 +85,7 @@ module prim_fifo_async #(
|
|||
assign fifo_incr_rptr = rvalid_o & rready_i;
|
||||
|
||||
// decimal version
|
||||
assign fifo_rptr_d = fifo_rptr_q + PTR_WIDTH'(1);
|
||||
assign fifo_rptr_d = fifo_rptr_q + PTR_WIDTH'(1'b1);
|
||||
|
||||
always_ff @(posedge clk_rd_i or negedge rst_rd_ni) begin
|
||||
if (!rst_rd_ni) begin
|
||||
|
@ -124,8 +124,10 @@ module prim_fifo_async #(
|
|||
// Empty / Full //
|
||||
//////////////////
|
||||
|
||||
assign full_wclk = (fifo_wptr_q == (fifo_rptr_sync_q ^ {1'b1,{(PTR_WIDTH-1){1'b0}}}));
|
||||
assign full_rclk = (fifo_wptr_sync_combi == (fifo_rptr_q ^ {1'b1,{(PTR_WIDTH-1){1'b0}}}));
|
||||
logic [PTR_WIDTH-1:0] xor_mask;
|
||||
assign xor_mask = PTR_WIDTH'(1'b1) << (PTR_WIDTH-1);
|
||||
assign full_wclk = (fifo_wptr_q == (fifo_rptr_sync_q ^ xor_mask));
|
||||
assign full_rclk = (fifo_wptr_sync_combi == (fifo_rptr_q ^ xor_mask));
|
||||
assign empty_rclk = (fifo_wptr_sync_combi == fifo_rptr_q);
|
||||
|
||||
if (Depth > 1) begin : g_depth_calc
|
||||
|
@ -210,32 +212,42 @@ module prim_fifo_async #(
|
|||
|
||||
function automatic [PTR_WIDTH-1:0] dec2gray(input logic [PTR_WIDTH-1:0] decval);
|
||||
logic [PTR_WIDTH-1:0] decval_sub;
|
||||
logic [PTR_WIDTH-2:0] decval_in;
|
||||
logic [PTR_WIDTH-1:0] decval_in;
|
||||
logic unused_decval_msb;
|
||||
|
||||
decval_sub = (PTR_WIDTH)'(Depth) - {1'b0, decval[PTR_WIDTH-2:0]} - 1'b1;
|
||||
|
||||
{unused_decval_msb, decval_in} = decval[PTR_WIDTH-1] ? decval_sub : decval;
|
||||
// Was done in two assigns for low bits and top bit
|
||||
// but that generates a (bogus) verilator warning, so do in one assign
|
||||
dec2gray = {decval[PTR_WIDTH-1],
|
||||
{1'b0,decval_in[PTR_WIDTH-2:1]} ^ decval_in[PTR_WIDTH-2:0]};
|
||||
decval_in = decval[PTR_WIDTH-1] ? decval_sub : decval;
|
||||
|
||||
// We do not care about the MSB, hence we mask it out
|
||||
unused_decval_msb = decval_in[PTR_WIDTH-1];
|
||||
decval_in[PTR_WIDTH-1] = 1'b0;
|
||||
|
||||
// Perform the XOR conversion
|
||||
dec2gray = decval_in;
|
||||
dec2gray ^= (decval_in >> 1);
|
||||
|
||||
// Override the MSB
|
||||
dec2gray[PTR_WIDTH-1] = decval[PTR_WIDTH-1];
|
||||
endfunction
|
||||
|
||||
// Algorithm walks up from 0..N-1 then flips the upper bit and walks down from N-1 to 0.
|
||||
function automatic [PTR_WIDTH-1:0] gray2dec(input logic [PTR_WIDTH-1:0] grayval);
|
||||
logic [PTR_WIDTH-2:0] dec_tmp, dec_tmp_sub;
|
||||
logic [PTR_WIDTH-1:0] dec_tmp, dec_tmp_sub;
|
||||
logic unused_decsub_msb;
|
||||
|
||||
dec_tmp[PTR_WIDTH-2] = grayval[PTR_WIDTH-2];
|
||||
for (int i = PTR_WIDTH-3; i >= 0; i--) begin
|
||||
dec_tmp = '0;
|
||||
for (int i = PTR_WIDTH-2; i >= 0; i--) begin
|
||||
dec_tmp[i] = dec_tmp[i+1] ^ grayval[i];
|
||||
end
|
||||
{unused_decsub_msb, dec_tmp_sub} = (PTR_WIDTH-1)'(Depth) - {1'b0, dec_tmp} - 1'b1;
|
||||
dec_tmp_sub = (PTR_WIDTH)'(Depth) - dec_tmp - 1'b1;
|
||||
if (grayval[PTR_WIDTH-1]) begin
|
||||
gray2dec = {1'b1, dec_tmp_sub};
|
||||
gray2dec = dec_tmp_sub;
|
||||
// Override MSB
|
||||
gray2dec[PTR_WIDTH-1] = 1'b1;
|
||||
unused_decsub_msb = dec_tmp_sub[PTR_WIDTH-1];
|
||||
end else begin
|
||||
gray2dec = {1'b0, dec_tmp};
|
||||
gray2dec = dec_tmp;
|
||||
end
|
||||
endfunction
|
||||
|
||||
|
@ -250,7 +262,7 @@ module prim_fifo_async #(
|
|||
end else if (Depth == 2) begin : g_simple_gray_conversion
|
||||
|
||||
assign fifo_rptr_sync_combi = {fifo_rptr_gray_sync[PTR_WIDTH-1], ^fifo_rptr_gray_sync};
|
||||
assign fifo_wptr_sync_combi = {fifo_wptr_gray_sync[PTR_WIDTH-1], ^fifo_rptr_gray_sync};
|
||||
assign fifo_wptr_sync_combi = {fifo_wptr_gray_sync[PTR_WIDTH-1], ^fifo_wptr_gray_sync};
|
||||
|
||||
assign fifo_rptr_gray_d = {fifo_rptr_d[PTR_WIDTH-1], ^fifo_rptr_d};
|
||||
assign fifo_wptr_gray_d = {fifo_wptr_d[PTR_WIDTH-1], ^fifo_wptr_d};
|
||||
|
|
3
vendor/lowrisc_ip/ip/prim/rtl/prim_lfsr.sv
vendored
3
vendor/lowrisc_ip/ip/prim/rtl/prim_lfsr.sv
vendored
|
@ -354,6 +354,9 @@ module prim_lfsr #(
|
|||
// Unknown //
|
||||
/////////////
|
||||
end else begin : gen_unknown_type
|
||||
assign coeffs = '0;
|
||||
assign next_lfsr_state = '0;
|
||||
assign lockup = 1'b0;
|
||||
`ASSERT_INIT(UnknownLfsrType_A, 0)
|
||||
end
|
||||
|
||||
|
|
|
@ -516,4 +516,6 @@ module prim_ram_1p_scr import prim_ram_1p_pkg::*; #(
|
|||
.cfg_i
|
||||
);
|
||||
|
||||
`include "prim_util_get_scramble_params.svh"
|
||||
|
||||
endmodule : prim_ram_1p_scr
|
||||
|
|
|
@ -10,4 +10,6 @@ package prim_rom_pkg;
|
|||
logic [3:0] cfg;
|
||||
} rom_cfg_t;
|
||||
|
||||
parameter rom_cfg_t ROM_CFG_DEFAULT = '0;
|
||||
|
||||
endpackage // prim_rom_pkg
|
||||
|
|
|
@ -67,13 +67,14 @@ module prim_sram_arbiter #(
|
|||
) u_reqarb (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.req_chk_i ( 1'b1 ),
|
||||
.req_i,
|
||||
.data_i ( req_packed ),
|
||||
.data_i ( req_packed ),
|
||||
.gnt_o,
|
||||
.idx_o ( ),
|
||||
.valid_o ( sram_req_o ),
|
||||
.data_o ( sram_packed ),
|
||||
.ready_i ( 1'b1 )
|
||||
.idx_o ( ),
|
||||
.valid_o ( sram_req_o ),
|
||||
.data_o ( sram_packed ),
|
||||
.ready_i ( 1'b1 )
|
||||
);
|
||||
end else if (ArbiterImpl == "BINTREE") begin : gen_tree_arb
|
||||
prim_arbiter_tree #(
|
||||
|
@ -82,13 +83,14 @@ module prim_sram_arbiter #(
|
|||
) u_reqarb (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.req_chk_i ( 1'b1 ),
|
||||
.req_i,
|
||||
.data_i ( req_packed ),
|
||||
.data_i ( req_packed ),
|
||||
.gnt_o,
|
||||
.idx_o ( ),
|
||||
.valid_o ( sram_req_o ),
|
||||
.data_o ( sram_packed ),
|
||||
.ready_i ( 1'b1 )
|
||||
.idx_o ( ),
|
||||
.valid_o ( sram_req_o ),
|
||||
.data_o ( sram_packed ),
|
||||
.ready_i ( 1'b1 )
|
||||
);
|
||||
end else begin : gen_unknown
|
||||
`ASSERT_INIT(UnknownArbImpl_A, 0)
|
||||
|
|
|
@ -33,6 +33,13 @@ module prim_subreg_shadow #(
|
|||
output logic err_storage
|
||||
);
|
||||
|
||||
// Since the shadow and staging registers work with the 1's complement value,
|
||||
// we need to invert the polarity of the SW access if it is either "W1S" or "W0C".
|
||||
// W1C is forbidden since the W0S complement is not implemented.
|
||||
`ASSERT_INIT(CheckSwAccessIsLegal_A, SWACCESS inside {"RW", "RO", "WO", "W1S", "W0C", "RC"})
|
||||
parameter bit [3*8-1:0] INVERTED_SWACCESS = (SWACCESS == "W1S") ? "W0C" :
|
||||
(SWACCESS == "W0C") ? "W1S" : SWACCESS;
|
||||
|
||||
// Subreg control signals
|
||||
logic phase_clear;
|
||||
logic phase_q;
|
||||
|
@ -86,9 +93,9 @@ module prim_subreg_shadow #(
|
|||
assign staged_we = we & ~phase_q;
|
||||
assign staged_de = de & ~phase_q;
|
||||
prim_subreg #(
|
||||
.DW ( DW ),
|
||||
.SWACCESS ( SWACCESS ),
|
||||
.RESVAL ( ~RESVAL )
|
||||
.DW ( DW ),
|
||||
.SWACCESS ( INVERTED_SWACCESS ),
|
||||
.RESVAL ( ~RESVAL )
|
||||
) staged_reg (
|
||||
.clk_i ( clk_i ),
|
||||
.rst_ni ( rst_ni ),
|
||||
|
@ -109,9 +116,9 @@ module prim_subreg_shadow #(
|
|||
assign shadow_we = we & phase_q & ~err_update;
|
||||
assign shadow_de = de & phase_q & ~err_update;
|
||||
prim_subreg #(
|
||||
.DW ( DW ),
|
||||
.SWACCESS ( SWACCESS ),
|
||||
.RESVAL ( ~RESVAL )
|
||||
.DW ( DW ),
|
||||
.SWACCESS ( INVERTED_SWACCESS ),
|
||||
.RESVAL ( ~RESVAL )
|
||||
) shadow_reg (
|
||||
.clk_i ( clk_i ),
|
||||
.rst_ni ( rst_ni ),
|
||||
|
|
|
@ -23,21 +23,24 @@
|
|||
|
||||
`include "prim_assert.sv"
|
||||
|
||||
module prim_sync_reqack #(
|
||||
// Non-functional parameter to switch on the request stability assertion
|
||||
parameter bit EnReqStabA = 1
|
||||
) (
|
||||
module prim_sync_reqack (
|
||||
input clk_src_i, // REQ side, SRC domain
|
||||
input rst_src_ni, // REQ side, SRC domain
|
||||
input clk_dst_i, // ACK side, DST domain
|
||||
input rst_dst_ni, // ACK side, DST domain
|
||||
|
||||
input logic req_chk_i, // Used for gating assertions. Drive to 1 during normal operation.
|
||||
|
||||
input logic src_req_i, // REQ side, SRC domain
|
||||
output logic src_ack_o, // REQ side, SRC domain
|
||||
output logic dst_req_o, // ACK side, DST domain
|
||||
input logic dst_ack_i // ACK side, DST domain
|
||||
);
|
||||
|
||||
// req_chk_i is used for gating assertions only.
|
||||
logic unused_req_chk;
|
||||
assign unused_req_chk = req_chk_i;
|
||||
|
||||
// Types
|
||||
typedef enum logic {
|
||||
EVEN, ODD
|
||||
|
@ -167,10 +170,9 @@ module prim_sync_reqack #(
|
|||
end
|
||||
end
|
||||
|
||||
if (EnReqStabA) begin : gen_lock_assertion
|
||||
// SRC domain can only de-assert REQ after receiving ACK.
|
||||
`ASSERT(SyncReqAckHoldReq, $fell(src_req_i) |-> $fell(src_ack_o), clk_src_i, !rst_src_ni)
|
||||
end
|
||||
// SRC domain can only de-assert REQ after receiving ACK.
|
||||
`ASSERT(SyncReqAckHoldReq, $fell(src_req_i) |->
|
||||
$fell(src_ack_o), clk_src_i, !rst_src_ni || !req_chk_i)
|
||||
|
||||
// DST domain cannot assert ACK without REQ.
|
||||
`ASSERT(SyncReqAckAckNeedsReq, dst_ack_i |-> dst_req_o, clk_dst_i, !rst_dst_ni)
|
||||
|
|
|
@ -20,15 +20,16 @@ module prim_sync_reqack_data #(
|
|||
parameter int unsigned Width = 1,
|
||||
parameter bit DataSrc2Dst = 1'b1, // Direction of data flow: 1'b1 = SRC to DST,
|
||||
// 1'b0 = DST to SRC
|
||||
parameter bit DataReg = 1'b0, // Enable optional register stage for data,
|
||||
parameter bit DataReg = 1'b0 // Enable optional register stage for data,
|
||||
// only usable with DataSrc2Dst == 1'b0.
|
||||
parameter bit EnReqStabA = 1 // Used in submodule `prim_sync_reqack`.
|
||||
) (
|
||||
input clk_src_i, // REQ side, SRC domain
|
||||
input rst_src_ni, // REQ side, SRC domain
|
||||
input clk_dst_i, // ACK side, DST domain
|
||||
input rst_dst_ni, // ACK side, DST domain
|
||||
|
||||
input logic req_chk_i, // Used for gating assertions. Drive to 1 during normal operation.
|
||||
|
||||
input logic src_req_i, // REQ side, SRC domain
|
||||
output logic src_ack_o, // REQ side, SRC domain
|
||||
output logic dst_req_o, // ACK side, DST domain
|
||||
|
@ -41,14 +42,14 @@ module prim_sync_reqack_data #(
|
|||
////////////////////////////////////
|
||||
// REQ/ACK synchronizer primitive //
|
||||
////////////////////////////////////
|
||||
prim_sync_reqack #(
|
||||
.EnReqStabA(EnReqStabA)
|
||||
) u_prim_sync_reqack (
|
||||
prim_sync_reqack u_prim_sync_reqack (
|
||||
.clk_src_i,
|
||||
.rst_src_ni,
|
||||
.clk_dst_i,
|
||||
.rst_dst_ni,
|
||||
|
||||
.req_chk_i,
|
||||
|
||||
.src_req_i,
|
||||
.src_ack_o,
|
||||
.dst_req_o,
|
||||
|
|
36
vendor/lowrisc_ip/ip/prim/rtl/prim_util_get_scramble_params.svh
vendored
Normal file
36
vendor/lowrisc_ip/ip/prim/rtl/prim_util_get_scramble_params.svh
vendored
Normal file
|
@ -0,0 +1,36 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
`ifndef SYNTHESIS
|
||||
export "DPI-C" function simutil_get_scramble_key;
|
||||
|
||||
function int simutil_get_scramble_key(output bit [127:0] val);
|
||||
if (!key_valid_i) begin
|
||||
return 0;
|
||||
end
|
||||
|
||||
if (DataKeyWidth != 128) begin
|
||||
return 0;
|
||||
end
|
||||
|
||||
val = key_i;
|
||||
return 1;
|
||||
endfunction
|
||||
|
||||
export "DPI-C" function simutil_get_scramble_nonce;
|
||||
|
||||
function int simutil_get_scramble_nonce(output bit [319:0] nonce);
|
||||
if (!key_valid_i) begin
|
||||
return 0;
|
||||
end
|
||||
|
||||
if (NonceWidth > 320) begin
|
||||
return 0;
|
||||
end
|
||||
|
||||
nonce = '0;
|
||||
nonce[NonceWidth-1:0] = nonce_i;
|
||||
return 1;
|
||||
endfunction
|
||||
`endif
|
123
vendor/lowrisc_ip/ip/prim/util/primgen.py
vendored
123
vendor/lowrisc_ip/ip/prim/util/primgen.py
vendored
|
@ -1,15 +1,21 @@
|
|||
#!/usr/bin/env python3
|
||||
# Copyright lowRISC contributors.
|
||||
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
# Make vendored packages available in the search path.
|
||||
sys.path.append('vendor')
|
||||
|
||||
import re
|
||||
import shutil
|
||||
import sys
|
||||
|
||||
import yaml
|
||||
from mako.template import Template
|
||||
|
||||
|
||||
try:
|
||||
from yaml import CSafeLoader as YamlLoader, CSafeDumper as YamlDumper
|
||||
except ImportError:
|
||||
|
@ -84,29 +90,76 @@ def _top_module_file(core_files, module_name):
|
|||
return file
|
||||
|
||||
|
||||
def _parse_module_header(generic_impl_filepath, module_name):
|
||||
""" Parse a SystemVerilog file to extract the 'module' header
|
||||
def _parse_module_header_verible(generic_impl_filepath, module_name):
|
||||
""" Parse a SystemVerilog file to extract the 'module' header using Verible
|
||||
|
||||
Return a dict with the following entries:
|
||||
- module_header: the whole module header (including the 'module' keyword)
|
||||
- package_import_declaration: import declarations
|
||||
- parameter_port_list: parameter/localparam declarations in the header
|
||||
- ports: the list of ports. The portlist can be ANSI or non-ANSI style (with
|
||||
or without signal declarations; see the SV spec for details).
|
||||
Implementation of _parse_module_header() which uses verible-verilog-syntax
|
||||
to do the parsing. This is the primary implementation and is used when
|
||||
supported Verible version is available.
|
||||
|
||||
See _parse_module_header() for API details.
|
||||
"""
|
||||
|
||||
# TODO: Evaluate different Python SV parsers and use one instead of this
|
||||
# beautiful regex. A more complete parser would ignore comments, for
|
||||
# example, or properly handle matching parentheses ... Or write a minimal
|
||||
# parser that can parse the module header.
|
||||
#
|
||||
# Initial evaluations:
|
||||
# - https://github.com/PyHDI/Pyverilog:
|
||||
# requires Icarus and Python 3.6
|
||||
# - https://kevinpt.github.io/hdlparse/:
|
||||
# Didn't do anything in my tests.
|
||||
# - https://github.com/sepandhaghighi/verilogparser:
|
||||
# Doesn't support SystemVerilog
|
||||
from google_verible_verilog_syntax_py.verible_verilog_syntax import VeribleVerilogSyntax, PreOrderTreeIterator
|
||||
|
||||
parser = VeribleVerilogSyntax()
|
||||
|
||||
data = parser.parse_file(generic_impl_filepath, options={"skip_null": True})
|
||||
if data.errors:
|
||||
for err in data.errors:
|
||||
print(f'Verible: {err.phase} error in line {err.line} column {err.column}'
|
||||
+ (': {err.message}' if err.message else '.'))
|
||||
# Intentionally not raising an exception here.
|
||||
# There are chances that Verible recovered from errors.
|
||||
if not data.tree:
|
||||
raise ValueError(f"Unable to parse {generic_impl_filepath!r}.")
|
||||
|
||||
module = data.tree.find({"tag": "kModuleDeclaration"})
|
||||
header = module.find({"tag": "kModuleHeader"})
|
||||
if not header:
|
||||
raise ValueError("Unable to extract module header from %s." %
|
||||
(generic_impl_filepath, ))
|
||||
|
||||
name = header.find({"tag": ["SymbolIdentifier", "EscapedIdentifier"]},
|
||||
iter_=PreOrderTreeIterator)
|
||||
if not name:
|
||||
raise ValueError("Unable to extract module name from %s." %
|
||||
(generic_impl_filepath, ))
|
||||
|
||||
imports = header.find_all({"tag": "kPackageImportDeclaration"})
|
||||
|
||||
parameters_list = header.find({"tag": "kFormalParameterList"})
|
||||
parameters = set()
|
||||
if parameters_list:
|
||||
for parameter in parameters_list.iter_find_all({"tag":
|
||||
"kParamDeclaration"}):
|
||||
if parameter.find({"tag": "parameter"}):
|
||||
parameter_id = parameter.find({"tag": ["SymbolIdentifier",
|
||||
"EscapedIdentifier"]})
|
||||
parameters.add(parameter_id.text)
|
||||
|
||||
ports = header.find({"tag": "kPortDeclarationList"})
|
||||
|
||||
return {
|
||||
'module_header': header.text,
|
||||
'package_import_declaration': '\n'.join([i.text for i in imports]),
|
||||
'parameter_port_list':
|
||||
parameters_list.text if parameters_list else '',
|
||||
'ports': ports.text if ports else '',
|
||||
'parameters': parameters,
|
||||
'parser': 'Verible'
|
||||
}
|
||||
|
||||
|
||||
def _parse_module_header_fallback(generic_impl_filepath, module_name):
|
||||
""" Parse a SystemVerilog file to extract the 'module' header using RegExp
|
||||
|
||||
Legacy implementation of _parse_module_header() using regular expressions.
|
||||
It is not as robust as Verible-backed implementation, but doesn't need
|
||||
Verible to work.
|
||||
|
||||
See _parse_module_header() for API details.
|
||||
"""
|
||||
|
||||
# Grammar fragments from the SV2017 spec:
|
||||
#
|
||||
|
@ -155,7 +208,8 @@ def _parse_module_header(generic_impl_filepath, module_name):
|
|||
'ports':
|
||||
matches.group('ports').strip() or '',
|
||||
'parameters':
|
||||
_parse_parameter_port_list(parameter_port_list)
|
||||
_parse_parameter_port_list(parameter_port_list),
|
||||
'parser': 'Fallback (regex)'
|
||||
}
|
||||
|
||||
|
||||
|
@ -197,6 +251,26 @@ def _parse_parameter_port_list(parameter_port_list):
|
|||
return parameters
|
||||
|
||||
|
||||
def _parse_module_header(generic_impl_filepath, module_name):
|
||||
""" Parse a SystemVerilog file to extract the 'module' header
|
||||
|
||||
Return a dict with the following entries:
|
||||
- module_header: the whole module header (including the 'module' keyword)
|
||||
- package_import_declaration: import declarations
|
||||
- parameter_port_list: parameter/localparam declarations in the header
|
||||
- ports: the list of ports. The portlist can be ANSI or non-ANSI style (with
|
||||
or without signal declarations; see the SV spec for details).
|
||||
- parser: parser used to extract the data.
|
||||
"""
|
||||
|
||||
try:
|
||||
return _parse_module_header_verible(generic_impl_filepath, module_name)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
print(f"Verible parser failed, using regex fallback instead.")
|
||||
return _parse_module_header_fallback(generic_impl_filepath, module_name)
|
||||
|
||||
|
||||
def _check_gapi(gapi):
|
||||
if 'cores' not in gapi:
|
||||
print("Key 'cores' not found in GAPI structure. "
|
||||
|
@ -331,11 +405,12 @@ def _generate_abstract_impl(gapi):
|
|||
module_header_imports=generic_hdr['package_import_declaration'],
|
||||
module_header_params=generic_hdr['parameter_port_list'],
|
||||
module_header_ports=generic_hdr['ports'],
|
||||
num_techlibs= len(techlibs),
|
||||
num_techlibs=len(techlibs),
|
||||
# Creating the code to instantiate the primitives in the Mako templating
|
||||
# language is tricky to do; do it in Python instead.
|
||||
instances=_create_instances(prim_name, techlibs,
|
||||
generic_hdr['parameters']))
|
||||
generic_hdr['parameters']),
|
||||
parser_info=generic_hdr['parser'])
|
||||
abstract_prim_sv_filepath = 'prim_%s.sv' % (prim_name)
|
||||
with open(abstract_prim_sv_filepath, 'w') as f:
|
||||
f.write(abstract_prim_sv)
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// This file is auto-generated.
|
||||
// Used parser: ${parser_info}
|
||||
|
||||
% if num_techlibs > 1:
|
||||
`ifndef PRIM_DEFAULT_IMPL
|
||||
|
|
15
vendor/lowrisc_ip/ip/prim/util/vendor/google_verible_verilog_syntax_py.lock.hjson
vendored
Normal file
15
vendor/lowrisc_ip/ip/prim/util/vendor/google_verible_verilog_syntax_py.lock.hjson
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// This file is generated by the util/vendor script. Please do not modify it
|
||||
// manually.
|
||||
|
||||
{
|
||||
upstream:
|
||||
{
|
||||
url: https://github.com/google/verible.git
|
||||
rev: ed1f3a9577047b801854fb36dd14ebe0aecbdddc
|
||||
only_subdir: verilog/tools/syntax/export_json_examples
|
||||
}
|
||||
}
|
13
vendor/lowrisc_ip/ip/prim/util/vendor/google_verible_verilog_syntax_py.vendor.hjson
vendored
Normal file
13
vendor/lowrisc_ip/ip/prim/util/vendor/google_verible_verilog_syntax_py.vendor.hjson
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
{
|
||||
name: "google_verible_verilog_syntax_py",
|
||||
target_dir: "google_verible_verilog_syntax_py",
|
||||
|
||||
upstream: {
|
||||
url: "https://github.com/google/verible.git",
|
||||
rev: "v0.0-943-ged1f3a9",
|
||||
only_subdir: "verilog/tools/syntax/export_json_examples",
|
||||
},
|
||||
}
|
55
vendor/lowrisc_ip/ip/prim/util/vendor/google_verible_verilog_syntax_py/BUILD
vendored
Normal file
55
vendor/lowrisc_ip/ip/prim/util/vendor/google_verible_verilog_syntax_py/BUILD
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
load("@rules_python//python:defs.bzl", "py_test", "py_library", "py_binary")
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
py_library(
|
||||
name = "verible_verilog_syntax_py",
|
||||
srcs = ["verible_verilog_syntax.py"],
|
||||
srcs_version = "PY3",
|
||||
imports = ["."],
|
||||
data = ["//verilog/tools/syntax:verible-verilog-syntax"],
|
||||
deps = [
|
||||
"@python_anytree//:anytree",
|
||||
"//third_party/py/dataclasses",
|
||||
],
|
||||
)
|
||||
|
||||
py_test(
|
||||
name = "verible_verilog_syntax_py_test",
|
||||
size = "small",
|
||||
srcs = ["verible_verilog_syntax_test.py"],
|
||||
srcs_version = "PY3",
|
||||
python_version = "PY3",
|
||||
main = "verible_verilog_syntax_test.py",
|
||||
deps = [":verible_verilog_syntax_py"],
|
||||
data = ["//verilog/tools/syntax:verible-verilog-syntax"],
|
||||
args = ["$(location //verilog/tools/syntax:verible-verilog-syntax)"],
|
||||
)
|
||||
|
||||
py_binary(
|
||||
name = "print_modules",
|
||||
srcs = ["print_modules.py"],
|
||||
srcs_version = "PY3",
|
||||
python_version = "PY3",
|
||||
main = "print_modules.py",
|
||||
deps = [
|
||||
":verible_verilog_syntax_py",
|
||||
"@python_anytree//:anytree",
|
||||
],
|
||||
data = ["//verilog/tools/syntax:verible-verilog-syntax"],
|
||||
args = ["$(location //verilog/tools/syntax:verible-verilog-syntax)"],
|
||||
)
|
||||
|
||||
py_binary(
|
||||
name = "print_tree",
|
||||
srcs = ["print_tree.py"],
|
||||
srcs_version = "PY3",
|
||||
python_version = "PY3",
|
||||
main = "print_tree.py",
|
||||
deps = [
|
||||
":verible_verilog_syntax_py",
|
||||
"@python_anytree//:anytree",
|
||||
],
|
||||
data = ["//verilog/tools/syntax:verible-verilog-syntax"],
|
||||
args = ["$(location //verilog/tools/syntax:verible-verilog-syntax)"],
|
||||
)
|
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