mirror of
https://github.com/lowRISC/ibex.git
synced 2025-04-22 21:07:34 -04:00
Update lowrisc_ip to lowRISC/opentitan@affb06d8d
Update code from upstream repository https://github.com/lowRISC/opentitan to revision affb06d8de0973bfdc271a6aa4b5ed7dc0b575bb * [dv] Add `wait_clks_or_rst` to `clk_rst_if` (Andreas Kurth) * [dv/cdc] Use cycle based CDC instrumentation (Guillermo Maturana) * [dv/prim_edn_req] Check data valid (Cindy Chen) * [rtl, chip dv] Coverage exclusions for pinmux / padring (Srikrishna Iyer) * [dv] Enhance probe function macro (Srikrishna Iyer) * [dv] enable loading `opentitan_flash_binary` images in DV (Timothy Trippel) * [prim_diff_decode] Update SVAs to make them compatible with sim CDC (Michael Schaffner) * [prim-lfsr] Fix DefaultSeedLocal compile scope (Srikrishna Iyer) * [dv] Update dv_base_reg_field to handle status interrupts (Weicai Yang) * [dvsim] fix bindgen error in nightlies (Timothy Trippel) * feat(prim): Add Status Interrupt type to `prim_intr_hw` (Eli Kim) * [dv/shadow_reg] Add coverplan for shadow reg (Cindy Chen) * [dv/shadow_reg] Add shadow reg fcov (Cindy Chen) * [dv/chip] Skip creating dv_base_reg coverage (Cindy Chen) * [chip, dv] Remove a testpoint - tl_intg_err (Weicai Yang) * [dv/top] Add option to automatically set rom_exec_en (Timothy Chen) * [dv] Use positive check in DV_CHECK* macros (Srikrishna Iyer) * [top/dv] Add plusargs to clear secret partitions (Michael Schaffner) * [dv/prim] Disable coverage for unused logic (Guillermo Maturana) * [dv] Add a global end-of-test signaling for RTL (Srikrishna Iyer) * [dv] Properly remove coverage on CDC rand delay module (Srikrishna Iyer) * [prim_sync_reqack] Disable reset checks by default, enable inside OTBN (Pirmin Vogel) * [prim_sync_reqack] Modify/extend SVAs with respect to reset (Pirmin Vogel) * [dv/clkmgr] Add exclusions and coverage pragmas (Guillermo Maturana) * [prim] Simplify defensive coding (Timothy Chen) * [prim_mubi] Fix sampling issue in MUBI sync assertions (Michael Schaffner) * [rtl/prim] Fix some prim_esc_receiver SVAs (Guillermo Maturana) * refactor(prim): rst_sync to have scanchain (Eli Kim) * [unr] Use elite license (Cindy Chen) * feat(prim): prim_rst_sync (Eli Kim) * refactor(dvsim): Remove `verdi` checker (Eli Kim) * [mubi/lc] Relax transient SVA checks (Michael Schaffner) * [fpv] fix random seed syntax error (Cindy) * [doc] Fix typos in //hw/lint and //hw/top_earlgrey (Dan McArdle) * [doc] Fix typos in //hw/ip (Dan McArdle) * [doc] Fix trailing whitespace before editing Markdown (Dan McArdle) * [dv/shadow_reg] Update comment (Cindy Chen) * [dv] Add macro `DV_CHECK_Q_EQ` (Weicai Yang) * [fpv/pwrmgr] Add assertions to check escalation (Cindy Chen) * [dv] Fix clk_rst_if limitation (Srikrishna Iyer) * [dv, pins_if] Add disconnect() method (Srikrishna Iyer) * SunGrid launcher support (Sharon Topaz) * [chip dv] Fix errors due to use of invalid HIER macros (Srikrishna Iyer) * [dv, clk_rst_if] Expand instance name in context (Srikrishna Iyer) * [dv] pins_if improvement (Srikrishna Iyer) * [CDC/PRIM] Updated prim_fifo_sync and prim_fifo_async to avoid CDC in rdata (Joshua Park) * Fix various typos in Markdown files (Dan McArdle) * [dvsim] Promote xcelium warning ENUMERR to an error (Michael Schaffner) * [dvsim] Install a SIGTERM handler (Srikrishna Iyer) * [flash_ctrl,dv] Enable random device param for all tests (Jaedon Kim) * [prim] Patch up design to help with coverage (Timothy Chen) * [flash_ctrl] Use comportable channels for alerts emanating from prim_flash (Michael Schaffner) * [doc, prim] doc update for new prim library (Joshua Park) * [otp_ctrl] Use comportable channels for alerts emanating from prim_otp (Michael Schaffner) * [dv] Replace wait_timeout with DV_WAIT_TIMEOUT (Weicai Yang) * [prim_lfsr] Initial block label (Srikrishna Iyer) * [dv/top] Regression triage (Timothy Chen) * [prim_lfsr] Enable randomization of initial seed (Srikrishna Iyer) * [dv] Fix timeout log (Weicai Yang) Signed-off-by: Andreas Kurth <adk@lowrisc.org>
This commit is contained in:
parent
46dad5edc1
commit
e9a866ef55
84 changed files with 3719 additions and 820 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: d1be61ba88a145e882df4e7c7a47f78bcf2371f8
|
||||
rev: affb06d8de0973bfdc271a6aa4b5ed7dc0b575bb
|
||||
}
|
||||
}
|
||||
|
|
22
vendor/lowrisc_ip/dv/sv/common_ifs/clk_rst_if.sv
vendored
22
vendor/lowrisc_ip/dv/sv/common_ifs/clk_rst_if.sv
vendored
|
@ -97,7 +97,7 @@ interface clk_rst_if #(
|
|||
bit sole_clock = 1'b0;
|
||||
|
||||
// use IfName as a part of msgs to indicate which clk_rst_vif instance
|
||||
string msg_id = {"clk_rst_if::", IfName};
|
||||
string msg_id = $sformatf("[%m(clk_rst_if):%s]", IfName);
|
||||
|
||||
clocking cb @(posedge clk);
|
||||
endclocking
|
||||
|
@ -115,6 +115,14 @@ interface clk_rst_if #(
|
|||
repeat (num_clks) @cbn;
|
||||
endtask
|
||||
|
||||
// Wait for 'num_clks' clocks based on the positive clock edge or reset, whichever comes first.
|
||||
task automatic wait_clks_or_rst(int num_clks);
|
||||
fork
|
||||
wait_clks(num_clks);
|
||||
wait_for_reset(.wait_negedge(1'b1), .wait_posedge(1'b0));
|
||||
join_any
|
||||
endtask
|
||||
|
||||
// wait for rst_n to assert and then deassert
|
||||
task automatic wait_for_reset(bit wait_negedge = 1'b1, bit wait_posedge = 1'b1);
|
||||
if (wait_negedge && ($isunknown(rst_n) || rst_n === 1'b1)) @(negedge rst_n);
|
||||
|
@ -149,16 +157,10 @@ interface clk_rst_if #(
|
|||
clk_freq_scale_up = freq_scale_up;
|
||||
endfunction
|
||||
|
||||
// call this function at t=0 (from tb top) to enable clk and rst_n to be driven
|
||||
// Enables the clock and reset to be driven.
|
||||
function automatic void set_active(bit drive_clk_val = 1'b1, bit drive_rst_n_val = 1'b1);
|
||||
time t = $time;
|
||||
if (t == 0) begin
|
||||
drive_clk = drive_clk_val;
|
||||
drive_rst_n = drive_rst_n_val;
|
||||
end
|
||||
else begin
|
||||
`dv_fatal("This function can only be called at t=0", msg_id)
|
||||
end
|
||||
drive_clk = drive_clk_val;
|
||||
drive_rst_n = drive_rst_n_val;
|
||||
endfunction
|
||||
|
||||
// set the clk period in ps
|
||||
|
|
|
@ -8,6 +8,7 @@ description: "Common interfaces used in DV"
|
|||
filesets:
|
||||
files_dv:
|
||||
depend:
|
||||
- lowrisc:prim:assert
|
||||
- lowrisc:dv:pins_if
|
||||
files:
|
||||
- clk_if.sv
|
||||
|
|
2
vendor/lowrisc_ip/dv/sv/common_ifs/index.md
vendored
2
vendor/lowrisc_ip/dv/sv/common_ifs/index.md
vendored
|
@ -22,7 +22,7 @@ unless the `set_active` function is called.
|
|||
|
||||
Just like `clk_if`, this interface has clocking blocks `cb` and `cbn`, together
|
||||
with `wait_clks` and `wait_n_clks` utility tasks. It also has
|
||||
* `wait_for_reset`: wait for a reset signalled on `rst_n`
|
||||
* `wait_for_reset`: wait for a reset signaled on `rst_n`
|
||||
|
||||
To generate a clock signal, call `set_active` at the start of the simulation.
|
||||
This is typically called from an `initial` block in the testbench. To configure
|
||||
|
|
29
vendor/lowrisc_ip/dv/sv/common_ifs/pins_if.sv
vendored
29
vendor/lowrisc_ip/dv/sv/common_ifs/pins_if.sv
vendored
|
@ -8,11 +8,15 @@
|
|||
`ifndef SYNTHESIS
|
||||
|
||||
interface pins_if #(
|
||||
parameter int Width = 1
|
||||
parameter int Width = 1,
|
||||
parameter bit [8*4-1:0] PullStrength = "Pull"
|
||||
) (
|
||||
inout [Width-1:0] pins
|
||||
);
|
||||
|
||||
`include "prim_assert.sv"
|
||||
|
||||
`ASSERT_INIT(PullStrengthParamValid, PullStrength inside {"Weak", "Pull"})
|
||||
|
||||
logic [Width-1:0] pins_o; // value to be driven out
|
||||
bit [Width-1:0] pins_oe = '0; // output enable
|
||||
|
@ -71,6 +75,13 @@ interface pins_if #(
|
|||
return pins;
|
||||
endfunction
|
||||
|
||||
// Fully disconnect this interface, including the pulls.
|
||||
function automatic void disconnect();
|
||||
pins_oe = {Width{1'b0}};
|
||||
pins_pu = {Width{1'b0}};
|
||||
pins_pd = {Width{1'b0}};
|
||||
endfunction
|
||||
|
||||
// make connections
|
||||
for (genvar i = 0; i < Width; i++) begin : gen_each_pin
|
||||
`ifdef VERILATOR
|
||||
|
@ -78,10 +89,18 @@ interface pins_if #(
|
|||
pins_pu[i] ? 1'b1 :
|
||||
pins_pd[i] ? 1'b0 : 1'bz;
|
||||
`else
|
||||
// Drive the pin with pull strength based on whether pullup / pulldown is enabled.
|
||||
assign (pull0, pull1) pins[i] = ~pins_oe[i] ? (pins_pu[i] ? 1'b1 :
|
||||
pins_pd[i] ? 1'b0 : 1'bz) : 1'bz;
|
||||
|
||||
// Drive the pin based on whether pullup / pulldown is enabled.
|
||||
//
|
||||
// If output is not enabled, then the pin is pulled up or down with the `PullStrength` strength
|
||||
// Pullup has priority over pulldown.
|
||||
if (PullStrength == "Pull") begin : gen_pull_strength_pull
|
||||
assign (pull0, pull1) pins[i] = ~pins_oe[i] ? (pins_pu[i] ? 1'b1 :
|
||||
pins_pd[i] ? 1'b0 : 1'bz) : 1'bz;
|
||||
end : gen_pull_strength_pull
|
||||
else if (PullStrength == "Weak") begin : gen_pull_strength_weak
|
||||
assign (weak0, weak1) pins[i] = ~pins_oe[i] ? (pins_pu[i] ? 1'b1 :
|
||||
pins_pd[i] ? 1'b0 : 1'bz) : 1'bz;
|
||||
end : gen_pull_strength_weak
|
||||
|
||||
// If output enable is 1, strong driver assigns pin to 'value to be driven out';
|
||||
// the external strong driver can still affect pin, if exists.
|
||||
|
|
|
@ -206,9 +206,9 @@ package csr_utils_pkg;
|
|||
decrement_outstanding_access();
|
||||
end
|
||||
begin
|
||||
wait_timeout(timeout_ns, msg_id,
|
||||
$sformatf("Timeout waiting to csr_wr %0s (addr=0x%0h)",
|
||||
csr.get_full_name(), csr.get_address()));
|
||||
`DV_WAIT_TIMEOUT(timeout_ns, msg_id,
|
||||
$sformatf("Timeout waiting to csr_wr %0s (addr=0x%0h)",
|
||||
csr.get_full_name(), csr.get_address()))
|
||||
end
|
||||
join_any
|
||||
disable fork;
|
||||
|
@ -354,9 +354,9 @@ package csr_utils_pkg;
|
|||
decrement_outstanding_access();
|
||||
end
|
||||
begin
|
||||
wait_timeout(timeout_ns, msg_id,
|
||||
$sformatf("Timeout waiting to csr_rd %0s (addr=0x%0h)",
|
||||
ptr.get_full_name(), csr_or_fld.csr.get_address()));
|
||||
`DV_WAIT_TIMEOUT(timeout_ns, msg_id,
|
||||
$sformatf("Timeout waiting to csr_rd %0s (addr=0x%0h)",
|
||||
ptr.get_full_name(), csr_or_fld.csr.get_address()))
|
||||
end
|
||||
join_any
|
||||
disable fork;
|
||||
|
@ -539,8 +539,8 @@ package csr_utils_pkg;
|
|||
endcase
|
||||
end
|
||||
begin
|
||||
wait_timeout(timeout_ns, msg_id, $sformatf("timeout %0s (addr=0x%0h) == 0x%0h",
|
||||
ptr.get_full_name(), csr_or_fld.csr.get_address(), exp_data));
|
||||
`DV_WAIT_TIMEOUT(timeout_ns, msg_id, $sformatf("timeout %0s (addr=0x%0h) == 0x%0h",
|
||||
ptr.get_full_name(), csr_or_fld.csr.get_address(), exp_data))
|
||||
end
|
||||
join_any
|
||||
disable fork;
|
||||
|
@ -588,9 +588,9 @@ package csr_utils_pkg;
|
|||
decrement_outstanding_access();
|
||||
end
|
||||
begin : mem_rd_timeout
|
||||
wait_timeout(timeout_ns, msg_id,
|
||||
$sformatf("Timeout waiting to mem_rd %0s (addr=0x%0h)",
|
||||
ptr.get_full_name(), offset));
|
||||
`DV_WAIT_TIMEOUT(timeout_ns, msg_id,
|
||||
$sformatf("Timeout waiting to mem_rd %0s (addr=0x%0h)",
|
||||
ptr.get_full_name(), offset))
|
||||
end
|
||||
join_any
|
||||
disable fork;
|
||||
|
@ -639,9 +639,9 @@ package csr_utils_pkg;
|
|||
decrement_outstanding_access();
|
||||
end
|
||||
begin
|
||||
wait_timeout(timeout_ns, msg_id,
|
||||
$sformatf("Timeout waiting to mem_wr %0s (addr=0x%0h)",
|
||||
ptr.get_full_name(), offset));
|
||||
`DV_WAIT_TIMEOUT(timeout_ns, msg_id,
|
||||
$sformatf("Timeout waiting to mem_wr %0s (addr=0x%0h)",
|
||||
ptr.get_full_name(), offset))
|
||||
end
|
||||
join_any
|
||||
disable fork;
|
||||
|
|
|
@ -156,5 +156,5 @@ Examples of useful functions in this class are:
|
|||
|
||||
### CSR sequence framework
|
||||
The [cip_lib]({{< relref "hw/dv/sv/cip_lib/doc" >}}) includes a virtual sequence named `cip_base_vseq`,
|
||||
that provides a common framework for all testbenchs to run these CSR test sequences and
|
||||
that provides a common framework for all testbenches to run these CSR test sequences and
|
||||
add exclusions.
|
||||
|
|
|
@ -19,6 +19,7 @@ filesets:
|
|||
- dv_base_reg_block.sv: {is_include_file: true}
|
||||
- dv_base_reg_map.sv: {is_include_file: true}
|
||||
- dv_base_lockable_field_cov.sv: {is_include_file: true}
|
||||
- dv_base_shadowed_field_cov.sv: {is_include_file: true}
|
||||
- dv_base_mubi_cov.sv: {is_include_file: true}
|
||||
file_type: systemVerilogSource
|
||||
|
||||
|
|
|
@ -35,6 +35,14 @@ class dv_base_reg extends uvm_reg;
|
|||
atomic_en_shadow_wr = new(1);
|
||||
endfunction : new
|
||||
|
||||
// Create this register and its fields' IP-specific functional coverage.
|
||||
function void create_cov();
|
||||
dv_base_reg_field fields[$];
|
||||
get_dv_base_reg_fields(fields);
|
||||
foreach(fields[i]) fields[i].create_cov();
|
||||
// Create register-specific covergroups here.
|
||||
endfunction
|
||||
|
||||
// this is similar to get_name, but it gets the
|
||||
// simple name of the aliased register instead.
|
||||
function string get_alias_name ();
|
||||
|
@ -235,6 +243,7 @@ class dv_base_reg extends uvm_reg;
|
|||
flds[i].update_shadowed_val(~wr_data);
|
||||
end else begin
|
||||
shadow_update_err = 1;
|
||||
flds[i].sample_shadow_field_cov(.update_err(1));
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -278,7 +287,7 @@ class dv_base_reg extends uvm_reg;
|
|||
return;
|
||||
end else begin
|
||||
`uvm_info(`gfn, $sformatf(
|
||||
"Shadow reg %0s has update error, update rw.value from %0h to %0h",
|
||||
"Update shadow reg %0s rw.value from %0h to %0h",
|
||||
get_name(), rw.value[0], get_committed_val()), UVM_HIGH)
|
||||
rw.value[0] = get_committed_val();
|
||||
end
|
||||
|
|
|
@ -56,6 +56,10 @@ class dv_base_reg_block extends uvm_reg_block;
|
|||
// Custom RAL models may support sub-word CSR writes smaller than CSR width.
|
||||
protected bit supports_sub_word_csr_writes = 1'b0;
|
||||
|
||||
// Enables functional coverage of comportable IP-specific specialized registers, such as regwen
|
||||
// and mubi. This flag can only be disabled before invoking `create_dv_reg_cov`.
|
||||
protected bit en_dv_reg_cov = 1;
|
||||
|
||||
bit has_unmapped_addrs;
|
||||
addr_range_t unmapped_addr_ranges[$];
|
||||
|
||||
|
@ -113,6 +117,20 @@ class dv_base_reg_block extends uvm_reg_block;
|
|||
`uvm_fatal(`gfn, "this method is not supposed to be called directly!")
|
||||
endfunction
|
||||
|
||||
// This function is invoked at the end of `build` method in uvm_reg_base.sv template to create
|
||||
// IP-specific functional coverage for this block and its registers and fields.
|
||||
function void create_cov();
|
||||
dv_base_reg_block blks[$];
|
||||
dv_base_reg regs[$];
|
||||
|
||||
get_dv_base_reg_blocks(blks);
|
||||
foreach (blks[i]) blks[i].create_cov();
|
||||
|
||||
get_dv_base_regs(regs);
|
||||
foreach (regs[i]) regs[i].create_cov();
|
||||
// Create block-specific covergroups here.
|
||||
endfunction
|
||||
|
||||
function void get_dv_base_reg_blocks(ref dv_base_reg_block blks[$]);
|
||||
uvm_reg_block uvm_blks[$];
|
||||
this.get_blocks(uvm_blks);
|
||||
|
@ -405,4 +423,16 @@ class dv_base_reg_block extends uvm_reg_block;
|
|||
return retval;
|
||||
endfunction
|
||||
|
||||
function void set_en_dv_reg_cov(bit val);
|
||||
uvm_reg csrs[$];
|
||||
get_registers(csrs);
|
||||
`DV_CHECK_FATAL(!csrs.size(),
|
||||
"Cannot set en_dv_base_reg_cov when covergroups are built already!")
|
||||
en_dv_reg_cov = val;
|
||||
endfunction
|
||||
|
||||
function bit get_en_dv_reg_cov();
|
||||
return en_dv_reg_cov;
|
||||
endfunction
|
||||
|
||||
endclass
|
||||
|
|
|
@ -17,9 +17,15 @@ class dv_base_reg_field extends uvm_reg_field;
|
|||
// This is used for get_field_by_name
|
||||
string alias_name = "";
|
||||
|
||||
// Default mubi_width = 0 indicates this register field is not a mubi type.
|
||||
protected int mubi_width;
|
||||
|
||||
// variable for mubi coverage, which is only created when this is a mubi reg
|
||||
dv_base_mubi_cov mubi_cov;
|
||||
|
||||
// variable for shadowed coverage, which is only created when this is a shadowed reg
|
||||
local dv_base_shadowed_field_cov shadowed_cov;
|
||||
|
||||
`uvm_object_utils(dv_base_reg_field)
|
||||
`uvm_object_new
|
||||
|
||||
|
@ -83,10 +89,18 @@ class dv_base_reg_field extends uvm_reg_field;
|
|||
uvm_reg_data_t field_val = rw.value[0] & ((1 << get_n_bits())-1);
|
||||
|
||||
// update intr_state mirrored value if this is an intr_test reg
|
||||
if (is_intr_test_fld) begin
|
||||
// if kind is UVM_PREDICT_DIRECT or UVM_PREDICT_READ, super.do_predict can handle
|
||||
if (kind == UVM_PREDICT_WRITE && is_intr_test_fld) begin
|
||||
uvm_reg_field intr_state_fld = get_intr_state_field();
|
||||
bit predict_val;
|
||||
if (intr_state_fld.get_access == "RO") begin // status interrupt
|
||||
predict_val = field_val;
|
||||
end else begin // regular W1C interrupt
|
||||
`DV_CHECK_STREQ(intr_state_fld.get_access, "W1C")
|
||||
predict_val = field_val | `gmv(intr_state_fld);
|
||||
end
|
||||
// use UVM_PREDICT_READ to avoid uvm_warning due to UVM_PREDICT_DIRECT
|
||||
void'(intr_state_fld.predict(field_val | `gmv(intr_state_fld), .kind(UVM_PREDICT_READ)));
|
||||
void'(intr_state_fld.predict(predict_val, .kind(UVM_PREDICT_READ)));
|
||||
end
|
||||
|
||||
super.do_predict(rw, kind, be);
|
||||
|
@ -136,7 +150,6 @@ class dv_base_reg_field extends uvm_reg_field;
|
|||
foreach (flds[i]) begin
|
||||
lockable_flds.push_back(flds[i]);
|
||||
flds[i].regwen_fld = this;
|
||||
flds[i].create_lockable_fld_cov();
|
||||
end
|
||||
endfunction
|
||||
|
||||
|
@ -144,9 +157,20 @@ class dv_base_reg_field extends uvm_reg_field;
|
|||
lockable_field_cov = dv_base_lockable_field_cov::type_id::create(`gfn);
|
||||
endfunction
|
||||
|
||||
function void create_mubi_cov(int mubi_width);
|
||||
function void create_mubi_cov(int width);
|
||||
mubi_cov = dv_base_mubi_cov::type_id::create(`gfn);
|
||||
mubi_cov.create_cov(mubi_width);
|
||||
mubi_cov.create_cov(width);
|
||||
endfunction
|
||||
|
||||
function void create_shadowed_fld_cov();
|
||||
shadowed_cov = dv_base_shadowed_field_cov::type_id::create(`gfn);
|
||||
endfunction
|
||||
|
||||
function void create_cov();
|
||||
string csr_name = this.get_parent().get_name();
|
||||
if (mubi_width > 0) create_mubi_cov(mubi_width);
|
||||
if (regwen_fld != null) create_lockable_fld_cov();
|
||||
if (!uvm_re_match("*_shadowed", csr_name)) create_shadowed_fld_cov();
|
||||
endfunction
|
||||
|
||||
// Returns true if this field can lock the specified register/field, else return false.
|
||||
|
@ -175,6 +199,22 @@ class dv_base_reg_field extends uvm_reg_field;
|
|||
lockable_flds_q = lockable_flds;
|
||||
endfunction
|
||||
|
||||
// Return if the RAL block is locked or not.
|
||||
function bit is_locked();
|
||||
uvm_reg_block blk = this.get_parent().get_parent();
|
||||
return blk.is_locked();
|
||||
endfunction
|
||||
|
||||
// If the register field is a mubi type, set the mubi width before the RAL is locked.
|
||||
function void set_mubi_width(int width);
|
||||
if (is_locked()) `uvm_fatal(`gfn, "Cannot set mubi width when the block is locked")
|
||||
mubi_width = width;
|
||||
endfunction
|
||||
|
||||
function int get_mubi_width();
|
||||
return mubi_width;
|
||||
endfunction
|
||||
|
||||
// shadow register field read will clear its phase tracker
|
||||
virtual task post_read(uvm_reg_item rw);
|
||||
if (rw.status == UVM_IS_OK) begin
|
||||
|
@ -201,9 +241,14 @@ class dv_base_reg_field extends uvm_reg_field;
|
|||
uvm_reg_data_t committed_val_temp = committed_val & mask;
|
||||
`uvm_info(`gfn, $sformatf("shadow_val %0h, commmit_val %0h", shadowed_val_temp,
|
||||
committed_val_temp), UVM_HIGH)
|
||||
sample_shadow_field_cov(.storage_err(1));
|
||||
return shadowed_val_temp != committed_val_temp;
|
||||
endfunction
|
||||
|
||||
function void sample_shadow_field_cov(bit update_err = 0, bit storage_err = 0);
|
||||
if (shadowed_cov != null) shadowed_cov.shadow_field_errs_cg.sample(update_err, storage_err);
|
||||
endfunction
|
||||
|
||||
function void update_staged_val(uvm_reg_data_t val);
|
||||
staged_val = val;
|
||||
endfunction
|
||||
|
|
|
@ -68,9 +68,9 @@ package dv_base_reg_pkg;
|
|||
string msg_id = {dv_base_reg_pkg::msg_id, "::decode_csr_or_field"};
|
||||
|
||||
if ($cast(csr, ptr)) begin
|
||||
// return csr object with null field; set the mask to all 1s and shift to 0
|
||||
// return csr object with null field; set the mask to the width's all 1s and shift to 0
|
||||
result.csr = csr;
|
||||
result.mask = '1;
|
||||
result.mask = (1 << csr.get_n_bits()) - 1;
|
||||
result.shift = 0;
|
||||
end
|
||||
else if ($cast(fld, ptr)) begin
|
||||
|
@ -114,6 +114,7 @@ package dv_base_reg_pkg;
|
|||
|
||||
`include "csr_excl_item.sv"
|
||||
`include "dv_base_lockable_field_cov.sv"
|
||||
`include "dv_base_shadowed_field_cov.sv"
|
||||
`include "dv_base_mubi_cov.sv"
|
||||
`include "dv_base_reg_field.sv"
|
||||
`include "dv_base_reg.sv"
|
||||
|
|
29
vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_shadowed_field_cov.sv
vendored
Normal file
29
vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_shadowed_field_cov.sv
vendored
Normal file
|
@ -0,0 +1,29 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
// coverage object of shadowed errors - update and storage errors.
|
||||
|
||||
class dv_base_shadowed_field_cov extends uvm_object;
|
||||
`uvm_object_utils(dv_base_shadowed_field_cov)
|
||||
|
||||
covergroup shadow_field_errs_cg(string name) with function sample(bit update_err = 0,
|
||||
bit storage_err = 0);
|
||||
option.per_instance = 1;
|
||||
option.name = name;
|
||||
|
||||
cp_update_err: coverpoint update_err {
|
||||
bins update_err = {1};
|
||||
}
|
||||
|
||||
cp_storage_err: coverpoint storage_err {
|
||||
bins storage_err = {1};
|
||||
}
|
||||
endgroup
|
||||
|
||||
// use reg_field name as this name
|
||||
function new(string name = "");
|
||||
shadow_field_errs_cg = new($sformatf("%0s_shadowed_errs_cov", name));
|
||||
endfunction : new
|
||||
|
||||
endclass
|
82
vendor/lowrisc_ip/dv/sv/dv_utils/dv_macros.svh
vendored
82
vendor/lowrisc_ip/dv/sv/dv_utils/dv_macros.svh
vendored
|
@ -85,7 +85,7 @@
|
|||
`ifndef DV_CHECK
|
||||
`define DV_CHECK(T_, MSG_="", SEV_=error, ID_=`gfn) \
|
||||
begin \
|
||||
if (!(T_)) begin \
|
||||
if (T_) ; else begin \
|
||||
`dv_``SEV_($sformatf("Check failed (%s) %s ", `"T_`", MSG_), ID_) \
|
||||
end \
|
||||
end
|
||||
|
@ -94,7 +94,7 @@
|
|||
`ifndef DV_CHECK_EQ
|
||||
`define DV_CHECK_EQ(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \
|
||||
begin \
|
||||
if (!((ACT_) == (EXP_))) begin \
|
||||
if ((ACT_) == (EXP_)) ; else begin \
|
||||
`dv_``SEV_($sformatf("Check failed %s == %s (%0d [0x%0h] vs %0d [0x%0h]) %s", \
|
||||
`"ACT_`", `"EXP_`", ACT_, ACT_, EXP_, EXP_, MSG_), ID_) \
|
||||
end \
|
||||
|
@ -104,7 +104,7 @@
|
|||
`ifndef DV_CHECK_NE
|
||||
`define DV_CHECK_NE(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \
|
||||
begin \
|
||||
if (!((ACT_) != (EXP_))) begin \
|
||||
if ((ACT_) != (EXP_)) ; else begin \
|
||||
`dv_``SEV_($sformatf("Check failed %s != %s (%0d [0x%0h] vs %0d [0x%0h]) %s", \
|
||||
`"ACT_`", `"EXP_`", ACT_, ACT_, EXP_, EXP_, MSG_), ID_) \
|
||||
end \
|
||||
|
@ -114,7 +114,7 @@
|
|||
`ifndef DV_CHECK_CASE_EQ
|
||||
`define DV_CHECK_CASE_EQ(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \
|
||||
begin \
|
||||
if (!((ACT_) === (EXP_))) begin \
|
||||
if ((ACT_) === (EXP_)) ; else begin \
|
||||
`dv_``SEV_($sformatf("Check failed %s === %s (0x%0h [%0b] vs 0x%0h [%0b]) %s", \
|
||||
`"ACT_`", `"EXP_`", ACT_, ACT_, EXP_, EXP_, MSG_), ID_) \
|
||||
end \
|
||||
|
@ -124,7 +124,7 @@
|
|||
`ifndef DV_CHECK_CASE_NE
|
||||
`define DV_CHECK_CASE_NE(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \
|
||||
begin \
|
||||
if (!((ACT_) !== (EXP_))) begin \
|
||||
if ((ACT_) !== (EXP_)) ; else begin \
|
||||
`dv_``SEV_($sformatf("Check failed %s !== %s (%0d [0x%0h] vs %0d [0x%0h]) %s", \
|
||||
`"ACT_`", `"EXP_`", ACT_, ACT_, EXP_, EXP_, MSG_), ID_) \
|
||||
end \
|
||||
|
@ -134,7 +134,7 @@
|
|||
`ifndef DV_CHECK_LT
|
||||
`define DV_CHECK_LT(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \
|
||||
begin \
|
||||
if (!((ACT_) < (EXP_))) begin \
|
||||
if ((ACT_) < (EXP_)) ; else begin \
|
||||
`dv_``SEV_($sformatf("Check failed %s < %s (%0d [0x%0h] vs %0d [0x%0h]) %s", \
|
||||
`"ACT_`", `"EXP_`", ACT_, ACT_, EXP_, EXP_, MSG_), ID_) \
|
||||
end \
|
||||
|
@ -144,7 +144,7 @@
|
|||
`ifndef DV_CHECK_GT
|
||||
`define DV_CHECK_GT(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \
|
||||
begin \
|
||||
if (!((ACT_) > (EXP_))) begin \
|
||||
if ((ACT_) > (EXP_)) ; else begin \
|
||||
`dv_``SEV_($sformatf("Check failed %s > %s (%0d [0x%0h] vs %0d [0x%0h]) %s", \
|
||||
`"ACT_`", `"EXP_`", ACT_, ACT_, EXP_, EXP_, MSG_), ID_) \
|
||||
end \
|
||||
|
@ -154,7 +154,7 @@
|
|||
`ifndef DV_CHECK_LE
|
||||
`define DV_CHECK_LE(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \
|
||||
begin \
|
||||
if (!((ACT_) <= (EXP_))) begin \
|
||||
if ((ACT_) <= (EXP_)) ; else begin \
|
||||
`dv_``SEV_($sformatf("Check failed %s <= %s (%0d [0x%0h] vs %0d [0x%0h]) %s", \
|
||||
`"ACT_`", `"EXP_`", ACT_, ACT_, EXP_, EXP_, MSG_), ID_) \
|
||||
end \
|
||||
|
@ -164,7 +164,7 @@
|
|||
`ifndef DV_CHECK_GE
|
||||
`define DV_CHECK_GE(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \
|
||||
begin \
|
||||
if (!((ACT_) >= (EXP_))) begin \
|
||||
if ((ACT_) >= (EXP_)) ; else begin \
|
||||
`dv_``SEV_($sformatf("Check failed %s >= %s (%0d [0x%0h] vs %0d [0x%0h]) %s", \
|
||||
`"ACT_`", `"EXP_`", ACT_, ACT_, EXP_, EXP_, MSG_), ID_) \
|
||||
end \
|
||||
|
@ -173,15 +173,29 @@
|
|||
|
||||
`ifndef DV_CHECK_STREQ
|
||||
`define DV_CHECK_STREQ(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \
|
||||
if (!((ACT_) == (EXP_))) begin \
|
||||
`dv_``SEV_($sformatf("Check failed \"%s\" == \"%s\" %s", ACT_, EXP_, MSG_), ID_) \
|
||||
begin \
|
||||
if ((ACT_) == (EXP_)) ; else begin \
|
||||
`dv_``SEV_($sformatf("Check failed \"%s\" == \"%s\" %s", ACT_, EXP_, MSG_), ID_) \
|
||||
end \
|
||||
end
|
||||
`endif
|
||||
|
||||
`ifndef DV_CHECK_STRNE
|
||||
`define DV_CHECK_STRNE(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \
|
||||
if (!((ACT_) != (EXP_))) begin \
|
||||
`dv_``SEV_($sformatf("Check failed \"%s\" != \"%s\" %s", ACT_, EXP_, MSG_), ID_) \
|
||||
begin \
|
||||
if ((ACT_) != (EXP_)) ; else begin \
|
||||
`dv_``SEV_($sformatf("Check failed \"%s\" != \"%s\" %s", ACT_, EXP_, MSG_), ID_) \
|
||||
end \
|
||||
end
|
||||
`endif
|
||||
|
||||
`ifndef DV_CHECK_Q_EQ
|
||||
`define DV_CHECK_Q_EQ(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \
|
||||
begin \
|
||||
`DV_CHECK_EQ(ACT_.size(), EXP_.size(), MSG_, SEV_, ID_) \
|
||||
foreach (ACT_[i]) begin \
|
||||
`DV_CHECK_EQ(ACT_[i], EXP_[i], $sformatf("for i = %0d %s", i, MSG_), SEV_, ID_) \
|
||||
end \
|
||||
end
|
||||
`endif
|
||||
|
||||
|
@ -374,10 +388,20 @@
|
|||
end
|
||||
`endif
|
||||
|
||||
// macro that waits for a given delay and then reports an error
|
||||
`ifndef DV_WAIT_TIMEOUT
|
||||
`define DV_WAIT_TIMEOUT(TIMEOUT_NS_, ID_ = `gfn, ERROR_MSG_ = "timeout occurred!", REPORT_FATAL_ = 1) \
|
||||
begin \
|
||||
#(TIMEOUT_NS_ * 1ns); \
|
||||
if (REPORT_FATAL_) `dv_fatal(ERROR_MSG_, ID_) \
|
||||
else `dv_error(ERROR_MSG_, ID_) \
|
||||
end
|
||||
`endif
|
||||
|
||||
// wait a task or statement with timer watchdog
|
||||
`ifndef DV_SPINWAIT
|
||||
`define DV_SPINWAIT(WAIT_, MSG_ = "timeout occurred!", TIMEOUT_NS_ = default_spinwait_timeout_ns, ID_ =`gfn) \
|
||||
`DV_SPINWAIT_EXIT(WAIT_, wait_timeout(TIMEOUT_NS_, ID_, MSG_);, "", ID_)
|
||||
`DV_SPINWAIT_EXIT(WAIT_, `DV_WAIT_TIMEOUT(TIMEOUT_NS_, ID_, MSG_);, "", ID_)
|
||||
`endif
|
||||
|
||||
// a shorthand of `DV_SPINWAIT(wait(...))
|
||||
|
@ -555,3 +579,33 @@
|
|||
`ifndef DV_MAX2
|
||||
`define DV_MAX2(a, b) ((a) > (b) ? (a) : (b))
|
||||
`endif
|
||||
|
||||
// Creates a signal probe function to sample / force / release an internal signal.
|
||||
//
|
||||
// If there is a need to sample / force an internal signal, then it must be done in the testbench,
|
||||
// or in an interface bound to the DUT. This macro creates a standardized signal probe function
|
||||
// meant to be invoked an interface. The generated function can then be invoked in test sequences
|
||||
// or other UVM classes. The macro takes 2 arguments - name of the function and the hierarchical
|
||||
// path to the signal. If invoked in an interface which is bound to the DUT, the signal can be a
|
||||
// partial hierarchical path within the DUT. The generated function accepts 2 arguments - the first
|
||||
// indicates the probe action (sample, force or release) of type dv_utils_pkg::signal_probe_e. The
|
||||
// second argument is the value to be forced. If sample action is chosen, then it returns the
|
||||
// sampled value (for other actions as well).
|
||||
//
|
||||
// The suggested naming convention for the function is:
|
||||
// signal_probe_<DUT_or_IP_block_name>_<signal_name>
|
||||
//
|
||||
// This macro must be invoked in an interface or module.
|
||||
`ifndef DV_CREATE_SIGNAL_PROBE_FUNCTION
|
||||
`define DV_CREATE_SIGNAL_PROBE_FUNCTION(FUNC_NAME_, SIGNAL_PATH_, SIGNAL_WIDTH_ = uvm_pkg::UVM_HDL_MAX_WIDTH) \
|
||||
function static logic [SIGNAL_WIDTH_-1:0] FUNC_NAME_(dv_utils_pkg::signal_probe_e kind, \
|
||||
logic [SIGNAL_WIDTH_-1:0] value = '0); \
|
||||
case (kind) \
|
||||
dv_utils_pkg::SignalProbeSample: ; \
|
||||
dv_utils_pkg::SignalProbeForce: force SIGNAL_PATH_ = value; \
|
||||
dv_utils_pkg::SignalProbeRelease: release SIGNAL_PATH_; \
|
||||
default: `uvm_fatal(`"FUNC_NAME_`", $sformatf("Bad value: %0d", kind)) \
|
||||
endcase \
|
||||
return SIGNAL_PATH_; \
|
||||
endfunction
|
||||
`endif
|
||||
|
|
|
@ -7,6 +7,8 @@ description: "DV test status reporting utilities"
|
|||
|
||||
filesets:
|
||||
files_dv:
|
||||
depend:
|
||||
- lowrisc:prim:util
|
||||
files:
|
||||
- dv_test_status_pkg.sv
|
||||
file_type: systemVerilogSource
|
||||
|
|
|
@ -10,6 +10,12 @@ package dv_test_status_pkg;
|
|||
// signature along with a banner. The signature can be used by external scripts to determine if
|
||||
// the test passed or failed.
|
||||
function automatic void dv_test_status(bit passed);
|
||||
`ifdef INC_ASSERT
|
||||
if (prim_util_pkg::end_of_simulation) begin
|
||||
$fatal("prim_util_pkg::end_of_simulation was already signaled!");
|
||||
end
|
||||
prim_util_pkg::end_of_simulation = 1'b1;
|
||||
`endif
|
||||
if (passed) begin
|
||||
$display("\nTEST PASSED CHECKS");
|
||||
$display(" _____ _ _ _ ");
|
||||
|
|
17
vendor/lowrisc_ip/dv/sv/dv_utils/dv_utils_pkg.sv
vendored
17
vendor/lowrisc_ip/dv/sv/dv_utils/dv_utils_pkg.sv
vendored
|
@ -68,6 +68,13 @@ package dv_utils_pkg;
|
|||
BusOpRead = 1'b1
|
||||
} bus_op_e;
|
||||
|
||||
// Enum representing a probe operation on an internal signal.
|
||||
typedef enum {
|
||||
SignalProbeSample, // Sample the signal.
|
||||
SignalProbeForce, // Force the signal with some value.
|
||||
SignalProbeRelease // Release the previous force.
|
||||
} signal_probe_e;
|
||||
|
||||
// Enum representing a type of host requests - read only, write only or random read & write
|
||||
typedef enum int {
|
||||
HostReqNone = 0,
|
||||
|
@ -138,16 +145,6 @@ package dv_utils_pkg;
|
|||
return report_server.get_severity_count(UVM_FATAL) > 0;
|
||||
endfunction
|
||||
|
||||
// task that waits for the specfied timeout
|
||||
task automatic wait_timeout(input uint timeout_ns,
|
||||
input string error_msg_id = msg_id,
|
||||
input string error_msg = "timeout occurred!",
|
||||
input bit report_fatal = 1);
|
||||
#(timeout_ns * 1ns);
|
||||
if (report_fatal) `uvm_fatal(error_msg_id, error_msg)
|
||||
else `uvm_error(error_msg_id, error_msg)
|
||||
endtask : wait_timeout
|
||||
|
||||
// get masked data based on provided byte mask; if csr reg handle is provided (optional) then
|
||||
// masked bytes from csr's mirrored value are returned, else masked bytes are 0's
|
||||
function automatic bit [bus_params_pkg::BUS_DW-1:0]
|
||||
|
|
|
@ -9,7 +9,16 @@ virtual function void otp_write_lc_partition_state(lc_ctrl_state_pkg::lc_state_e
|
|||
for (int i = 0; i < LcStateSize; i += 4) begin
|
||||
write32(i + LcStateOffset, lc_state[i*8+:32]);
|
||||
end
|
||||
endfunction
|
||||
endfunction : otp_write_lc_partition_state
|
||||
|
||||
virtual function lc_ctrl_state_pkg::lc_state_e otp_read_lc_partition_state();
|
||||
lc_ctrl_state_pkg::lc_state_e lc_state;
|
||||
for (int i = 0; i < LcStateSize; i += 4) begin
|
||||
lc_state[i*8 +: 32] = read32(i + LcStateOffset);
|
||||
end
|
||||
|
||||
return lc_state;
|
||||
endfunction : otp_read_lc_partition_state
|
||||
|
||||
virtual function void otp_write_lc_partition_cnt(lc_ctrl_state_pkg::lc_cnt_e lc_cnt);
|
||||
for (int i = 0; i < LcTransitionCntSize; i += 4) begin
|
||||
|
@ -139,3 +148,29 @@ virtual function void otp_write_hw_cfg_partition(
|
|||
|
||||
write64(HwCfgDigestOffset, digest);
|
||||
endfunction
|
||||
|
||||
// Functions that clear the provisioning state of the buffered partitions.
|
||||
// This is useful in tests that make front-door accesses for provisioning purposes.
|
||||
virtual function void otp_clear_secret0_partition();
|
||||
for (int i = 0; i < Secret0Size; i += 4) begin
|
||||
write32(i + Secret0Offset, 32'h0);
|
||||
end
|
||||
endfunction
|
||||
|
||||
virtual function void otp_clear_secret1_partition();
|
||||
for (int i = 0; i < Secret1Size; i += 4) begin
|
||||
write32(i + Secret1Offset, 32'h0);
|
||||
end
|
||||
endfunction
|
||||
|
||||
virtual function void otp_clear_secret2_partition();
|
||||
for (int i = 0; i < Secret2Size; i += 4) begin
|
||||
write32(i + Secret2Offset, 32'h0);
|
||||
end
|
||||
endfunction
|
||||
|
||||
virtual function void otp_clear_hw_cfg_partition();
|
||||
for (int i = 0; i < HwCfgSize; i += 4) begin
|
||||
write32(i + HwCfgOffset, 32'h0);
|
||||
end
|
||||
endfunction
|
||||
|
|
|
@ -4,7 +4,7 @@ title: "Memory Model"
|
|||
|
||||
The memory model UVC models a memory device which any host interface can read
|
||||
from or write to. It is implemented as a `uvm_object`, and instantiates an
|
||||
associative array of bytes `system_memory`. This class is paramterized by both
|
||||
associative array of bytes `system_memory`. This class is parameterized by both
|
||||
the address width and the data width, and creates two `typedefs` to represent
|
||||
both, `mem_addr_t` and `mem_data_t`.
|
||||
The `mem_model` class has four main functions, which are detailed below.
|
||||
|
|
4
vendor/lowrisc_ip/dv/tools/dvsim/sim.mk
vendored
4
vendor/lowrisc_ip/dv/tools/dvsim/sim.mk
vendored
|
@ -95,12 +95,14 @@ ifneq (${sw_images},)
|
|||
bazel_cmd="./bazelisk.sh"; \
|
||||
else \
|
||||
echo "Building \"$${bazel_label}\" on air-gapped machine."; \
|
||||
bazel_opts+=" --define SPECIFY_BINDGEN_LIBSTDCXX=true"; \
|
||||
bazel_opts+=" --distdir=$${BAZEL_DISTDIR} --repository_cache=$${BAZEL_CACHE}"; \
|
||||
bazel_cmd="bazel"; \
|
||||
fi; \
|
||||
echo "Building with command: $${bazel_cmd} build $${bazel_opts} $${bazel_label}"; \
|
||||
$${bazel_cmd} build $${bazel_opts} $${bazel_label}; \
|
||||
for dep in $$($${bazel_cmd} cquery "labels(data, $${bazel_label})" \
|
||||
for dep in $$($${bazel_cmd} cquery \
|
||||
"labels(data, $${bazel_label}) union labels(srcs, $${bazel_label})" \
|
||||
--ui_event_filters=-info \
|
||||
--noshow_progress \
|
||||
--output=starlark); do \
|
||||
|
|
|
@ -83,4 +83,17 @@
|
|||
tests: ["{name}_shadow_reg_errors_with_csr_rw"]
|
||||
}
|
||||
]
|
||||
|
||||
covergroups: [
|
||||
{
|
||||
name: shadow_field_errs_cg
|
||||
desc: '''Cover all shadow register errors for each register field.
|
||||
|
||||
For all register fields within the shadowed register, this coverpoint covers the
|
||||
following errors:
|
||||
- Update error
|
||||
- Storage error
|
||||
'''
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -2,59 +2,8 @@
|
|||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
{
|
||||
import_testplans: ["hw/dv/tools/dvsim/testplans/tl_device_access_types_wo_intg_testplan.hjson"]
|
||||
testpoints: [
|
||||
{
|
||||
name: tl_d_oob_addr_access
|
||||
desc: "Access out of bounds address and verify correctness of response / behavior"
|
||||
stage: V2
|
||||
tests: ["{name}_tl_errors"]
|
||||
}
|
||||
{
|
||||
name: tl_d_illegal_access
|
||||
desc: '''Drive unsupported requests via TL interface and verify correctness of response
|
||||
/ 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
|
||||
- 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, 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
|
||||
- write a RO (read-only) memory
|
||||
- write with `instr_type = True`'''
|
||||
stage: V2
|
||||
tests: ["{name}_tl_errors"]
|
||||
}
|
||||
{
|
||||
name: tl_d_outstanding_access
|
||||
desc: '''Drive back-to-back requests without waiting for response to ensure there is one
|
||||
transaction outstanding within the TL device. Also, verify one outstanding when back-
|
||||
to-back accesses are made to the same address.'''
|
||||
stage: V2
|
||||
tests: ["{name}_csr_hw_reset",
|
||||
"{name}_csr_rw",
|
||||
"{name}_csr_aliasing",
|
||||
"{name}_same_csr_outstanding"]
|
||||
}
|
||||
{
|
||||
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.'''
|
||||
stage: 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.
|
||||
|
@ -68,13 +17,6 @@
|
|||
}
|
||||
]
|
||||
covergroups: [
|
||||
{
|
||||
name: tl_errors_cg
|
||||
desc: '''Cover the following error cases on TL-UL bus:
|
||||
- TL-UL protocol error cases.
|
||||
- OpenTitan defined error cases, refer to testpoint `tl_d_illegal_access`.
|
||||
'''
|
||||
}
|
||||
{
|
||||
name: tl_intg_err_cg
|
||||
desc: '''Cover all kinds of integrity errors (command, data or both) and cover number of
|
||||
|
|
68
vendor/lowrisc_ip/dv/tools/dvsim/testplans/tl_device_access_types_wo_intg_testplan.hjson
vendored
Normal file
68
vendor/lowrisc_ip/dv/tools/dvsim/testplans/tl_device_access_types_wo_intg_testplan.hjson
vendored
Normal file
|
@ -0,0 +1,68 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
{
|
||||
testpoints: [
|
||||
{
|
||||
name: tl_d_oob_addr_access
|
||||
desc: "Access out of bounds address and verify correctness of response / behavior"
|
||||
stage: V2
|
||||
tests: ["{name}_tl_errors"]
|
||||
}
|
||||
{
|
||||
name: tl_d_illegal_access
|
||||
desc: '''Drive unsupported requests via TL interface and verify correctness of response
|
||||
/ 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
|
||||
- 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, 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
|
||||
- write a RO (read-only) memory
|
||||
- write with `instr_type = True`'''
|
||||
stage: V2
|
||||
tests: ["{name}_tl_errors"]
|
||||
}
|
||||
{
|
||||
name: tl_d_outstanding_access
|
||||
desc: '''Drive back-to-back requests without waiting for response to ensure there is one
|
||||
transaction outstanding within the TL device. Also, verify one outstanding when back-
|
||||
to-back accesses are made to the same address.'''
|
||||
stage: V2
|
||||
tests: ["{name}_csr_hw_reset",
|
||||
"{name}_csr_rw",
|
||||
"{name}_csr_aliasing",
|
||||
"{name}_same_csr_outstanding"]
|
||||
}
|
||||
{
|
||||
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.'''
|
||||
stage: V2
|
||||
tests: ["{name}_csr_hw_reset",
|
||||
"{name}_csr_rw",
|
||||
"{name}_csr_aliasing",
|
||||
"{name}_same_csr_outstanding"]
|
||||
}
|
||||
]
|
||||
covergroups: [
|
||||
{
|
||||
name: tl_errors_cg
|
||||
desc: '''Cover the following error cases on TL-UL bus:
|
||||
- TL-UL protocol error cases.
|
||||
- OpenTitan defined error cases, refer to testpoint `tl_d_illegal_access`.
|
||||
'''
|
||||
}
|
||||
]
|
||||
}
|
|
@ -47,6 +47,10 @@
|
|||
"-nowarn SPDUSD",
|
||||
// Needed for including "secded_enc.h".
|
||||
"-I{build_dir}/src/lowrisc_dv_secded_enc_0",
|
||||
// This warning is thrown when a scalar enum variable is assigned to an enum array.
|
||||
// Other tools (e.g., FPV) treat such assignments as an error, hence we bump it to
|
||||
// an error in simulation so that this can be caught early in CI.
|
||||
"-NCError ENUMERR"
|
||||
]
|
||||
|
||||
// We want to allow the possibility of passing no test or no test sequence. Unfortunately,
|
||||
|
|
27
vendor/lowrisc_ip/dv/tools/vcs/cover.cfg
vendored
27
vendor/lowrisc_ip/dv/tools/vcs/cover.cfg
vendored
|
@ -20,7 +20,7 @@
|
|||
// csr_assert_fpv is an auto-generated csr read assertion module. So only assertion coverage is
|
||||
// meaningful to collect.
|
||||
-moduletree *csr_assert_fpv
|
||||
-module prim_cdc_rand_delay // DV CDC module
|
||||
-module prim_cdc_rand_delay // DV construct.
|
||||
|
||||
begin tgl
|
||||
-tree tb
|
||||
|
@ -37,29 +37,4 @@ end
|
|||
|
||||
begin assert
|
||||
+moduletree *csr_assert_fpv
|
||||
-moduletree prim_cdc_rand_delay // TODO: CDC not enabled yet
|
||||
// These three assertions in prim_lc_sync and prim_mubi* check when `lc_ctrl_pkg::lc_tx_t` or
|
||||
// `mubi*_t` input are neither `On` or `Off`, it is interrupted to the correct `On` or `Off`
|
||||
// after one clock cycle. This behavior is implemented outside of IP level design thus these
|
||||
// assertions are not covered in IP level testbenchs.
|
||||
// TODO: check these assertions in top-level or FPV.
|
||||
-assert PrimLcSyncCheckTransients_A
|
||||
-assert PrimLcSyncCheckTransients0_A
|
||||
-assert PrimLcSyncCheckTransients1_A
|
||||
|
||||
-assert PrimMubi4SyncCheckTransients_A
|
||||
-assert PrimMubi4SyncCheckTransients0_A
|
||||
-assert PrimMubi4SyncCheckTransients1_A
|
||||
|
||||
-assert PrimMubi8SyncCheckTransients_A
|
||||
-assert PrimMubi8SyncCheckTransients0_A
|
||||
-assert PrimMubi8SyncCheckTransients1_A
|
||||
|
||||
-assert PrimMubi12SyncCheckTransients_A
|
||||
-assert PrimMubi12SyncCheckTransients0_A
|
||||
-assert PrimMubi12SyncCheckTransients1_A
|
||||
|
||||
-assert PrimMubi16SyncCheckTransients_A
|
||||
-assert PrimMubi16SyncCheckTransients0_A
|
||||
-assert PrimMubi16SyncCheckTransients1_A
|
||||
end
|
||||
|
|
|
@ -7,11 +7,11 @@
|
|||
|
||||
+moduletree *_reg_top
|
||||
+node tb.dut tl_*
|
||||
-module prim_cdc_rand_delay // DV construct.
|
||||
|
||||
begin assert
|
||||
+moduletree *csr_assert_fpv
|
||||
+moduletree tlul_assert
|
||||
-moduletree prim_cdc_rand_delay // TODO: CDC not enabled yet
|
||||
end
|
||||
|
||||
// Remove everything else from toggle coverage except:
|
||||
|
|
4
vendor/lowrisc_ip/dv/tools/vcs/unr.cfg
vendored
4
vendor/lowrisc_ip/dv/tools/vcs/unr.cfg
vendored
|
@ -10,6 +10,10 @@
|
|||
# Provide the reset specification: signal_name, active_value, num clk cycles reset to be active
|
||||
-reset rst_ni 0 20
|
||||
|
||||
# Enables the Elite licensing for UNR
|
||||
# Adding this switch avoids the compile error saying could not find the `VC-static-cov` license
|
||||
-fmlElite
|
||||
|
||||
# Black box common security modules
|
||||
-blackBoxes -type design prim_count+prim_spare_fsm+prim_double_lfsr
|
||||
|
||||
|
|
26
vendor/lowrisc_ip/dv/tools/xcelium/cover.ccf
vendored
26
vendor/lowrisc_ip/dv/tools/xcelium/cover.ccf
vendored
|
@ -24,6 +24,7 @@ deselect_coverage -betfs -module prim_lfsr...
|
|||
|
||||
// Black-box DV CDC module.
|
||||
deselect_coverage -betfs -module prim_cdc_rand_delay
|
||||
|
||||
// csr_assert_fpv is an auto-generated csr read assertion module. So only assertion coverage is
|
||||
// meaningful to collect.
|
||||
deselect_coverage -betf -module *csr_assert_fpv...
|
||||
|
@ -45,28 +46,3 @@ select_coverage -toggle -module prim_esc_receiver
|
|||
select_coverage -toggle -module prim_onehot_check
|
||||
select_coverage -toggle -module prim_prince
|
||||
select_coverage -toggle -module prim_lfsr
|
||||
|
||||
// These three assertions in prim_lc_sync and prim_mubi* check when `lc_ctrl_pkg::lc_tx_t` or
|
||||
// `mubi*_t` input are neither `On` or `Off`, it is interrupted to the correct `On` or `Off`
|
||||
// after one clock cycle. This behavior is implemented outside of IP level design thus these
|
||||
// assertions are not covered in IP level testbenchs.
|
||||
// TODO: check these assertions in top-level or FPV.
|
||||
deselect_coverage -assertion *.PrimLcSyncCheckTransients_A
|
||||
deselect_coverage -assertion *.PrimLcSyncCheckTransients0_A
|
||||
deselect_coverage -assertion *.PrimLcSyncCheckTransients1_A
|
||||
|
||||
deselect_coverage -assertion *.PrimMubi4SyncCheckTransients_A
|
||||
deselect_coverage -assertion *.PrimMubi4SyncCheckTransients0_A
|
||||
deselect_coverage -assertion *.PrimMubi4SyncCheckTransients1_A
|
||||
|
||||
deselect_coverage -assertion PrimMubi8SyncCheckTransients_A
|
||||
deselect_coverage -assertion PrimMubi8SyncCheckTransients0_A
|
||||
deselect_coverage -assertion PrimMubi8SyncCheckTransients1_A
|
||||
|
||||
deselect_coverage -assertion PrimMubi12SyncCheckTransients_A
|
||||
deselect_coverage -assertion PrimMubi12SyncCheckTransients0_A
|
||||
deselect_coverage -assertion PrimMubi12SyncCheckTransients1_A
|
||||
|
||||
deselect_coverage -assertion PrimMubi16SyncCheckTransients_A
|
||||
deselect_coverage -assertion PrimMubi16SyncCheckTransients0_A
|
||||
deselect_coverage -assertion PrimMubi16SyncCheckTransients1_A
|
||||
|
|
28
vendor/lowrisc_ip/ip/prim/doc/prim_clock_gp_mux2.md
vendored
Normal file
28
vendor/lowrisc_ip/ip/prim/doc/prim_clock_gp_mux2.md
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
---
|
||||
title: "Primitive Component: Two input clock Mux with glitch protection"
|
||||
---
|
||||
|
||||
# Overview
|
||||
`prim_clock_gp_mux2` is a two input clock mux that protects a glitch. When a current clock source is switched to the next clock source where two clocks are totally unrelated, a glitch can be generated as follows.
|
||||
|
||||
### Glitch
|
||||
{{< wavejson >}}
|
||||
{signal: [
|
||||
{name: 'clk0_i', wave: 'L.H....L....H....L....H....'},
|
||||
{name: 'clk1_i', wave: 'L.H.L.H.L.H.L.H.L.H.L.H.L.H'},
|
||||
{name: 'sel_i', wave: '0............1.............'},
|
||||
{name: 'clk_o', wave: 'L.H....L....HLH.L.H.L.H.L.H'},
|
||||
]}
|
||||
{{< /wavejson >}}
|
||||
|
||||
This glitch free clock mux can avoid glitch by placing two parallel synchronizers connected to each other. 1st flop and 2nd flop are triggered by positive edge and negative edge respectively to protect metastability on the sel_i signal. The following waveform shows the result.
|
||||
|
||||
### Glitch Free
|
||||
{{< wavejson >}}
|
||||
{signal: [
|
||||
{name: 'clk0_i', wave: 'L.H....L....H....L....H....'},
|
||||
{name: 'clk1_i', wave: 'L.H.L.H.L.H.L.H.L.H.L.H.L.H'},
|
||||
{name: 'sel_i', wave: '0............1.............'},
|
||||
{name: 'clk_o', wave: 'L.H....L....H....LH.L.H.L.H'},
|
||||
]}
|
||||
{{< /wavejson >}}
|
6
vendor/lowrisc_ip/ip/prim/doc/prim_flash.md
vendored
6
vendor/lowrisc_ip/ip/prim/doc/prim_flash.md
vendored
|
@ -69,7 +69,7 @@ part | input | requested transaction partition
|
|||
info_sel | input | if requested transaction is information partition, the type of information partition accessed
|
||||
he | input | high endurance enable for requested address
|
||||
prog_data | input | program data
|
||||
ack | output | transction acknowledge
|
||||
ack | output | transaction acknowledge
|
||||
rd_data | output | transaction read data
|
||||
done | output | transaction done
|
||||
|
||||
|
@ -126,9 +126,9 @@ The following are examples for read, program and erase transactions.
|
|||
]}
|
||||
{{< /wavejson >}}
|
||||
|
||||
## Initlialization
|
||||
## Initialization
|
||||
|
||||
The flash wrapper may undergo technology specific intializations when it is first powered up.
|
||||
The flash wrapper may undergo technology specific initializations when it is first powered up.
|
||||
During this state, it asserts the `init_busy` to inform the outside world that it is not ready for transactions.
|
||||
During this time, if a transaction is issued towards the flash wrapper, the transaction is not acknowledged until the initialization is complete.
|
||||
|
||||
|
|
3
vendor/lowrisc_ip/ip/prim/doc/prim_keccak.md
vendored
3
vendor/lowrisc_ip/ip/prim/doc/prim_keccak.md
vendored
|
@ -35,7 +35,7 @@ Signal | Type | Description
|
|||
-------|---------------|------------------------------
|
||||
rnd_i | input [RndW] | current round number [0..(MaxRound-1)]
|
||||
s_i | input [Width] | state input
|
||||
s_o | output[Width] | permutated state output
|
||||
s_o | output[Width] | permuted state output
|
||||
|
||||
`s_i` and `s_o` are little-endian bitarrays.
|
||||
The [SHA3 spec][fibs-pub-202] shows how to convert the bitstream into the 5x5xW state cube.
|
||||
|
@ -86,4 +86,3 @@ The recommended default value of 24 rounds is used in this design,
|
|||
but an argument (changed with the `-r` flag) is provided for reference.
|
||||
The `keccak_rc.py` script creates 64 bit of constants and the `prim_keccak` module uses only lower bits of the constants if the `Width` is less than 1600.
|
||||
For instance, if `Width` is 800, lower 32bits of the round constant are used.
|
||||
|
||||
|
|
2
vendor/lowrisc_ip/ip/prim/doc/prim_packer.md
vendored
2
vendor/lowrisc_ip/ip/prim/doc/prim_packer.md
vendored
|
@ -33,7 +33,7 @@ flush_i | input | Send out stored data and clear state.
|
|||
flush_done_o | output | Indicates flush operation is completed.
|
||||
err_o | output | When EnProtection is set, the error is reported through this port. This signal is asynchronous to the datapath.
|
||||
|
||||
# Theory of Opeations
|
||||
# Theory of Operations
|
||||
|
||||
```code
|
||||
/----------\
|
||||
|
|
|
@ -38,7 +38,7 @@ rdata_o[OutW]| output | Output data.
|
|||
rready_i | input | Output data is popped from the FIFO.
|
||||
depth_o | output | Indicates the fullness of the FIFO.
|
||||
|
||||
# Theory of Opeations
|
||||
# Theory of Operations
|
||||
|
||||
```code
|
||||
/----------\
|
||||
|
@ -47,8 +47,8 @@ wvalid_i | | rvalid_o
|
|||
wdata_i | Flop | rdata_o
|
||||
=====/====>| FIFO |=======/=======>
|
||||
[InW] | | [OutW]
|
||||
| | depth_o
|
||||
| |--------------->
|
||||
| | depth_o
|
||||
| |--------------->
|
||||
wready_o | | rready_i
|
||||
<----------| |<---------------
|
||||
| |
|
||||
|
@ -62,6 +62,5 @@ rvalid_o and rready_i are coincident), will clear the data and depth values on
|
|||
the next clock cycle. The complimentary flow occurs when the`prim_packer_fifo`
|
||||
module is in unpack mode.
|
||||
|
||||
The internal register size is the greate of `InW` and `OutW` bits.
|
||||
The internal register size is the greater of `InW` and `OutW` bits.
|
||||
Timing diagrams are shown in the header of the `prim_packer_fifo` module.
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ state-update function contains a lockup protection which re-seeds the state with
|
|||
|
||||
When the seed enable signal `seed_en_i` is raised, the internal state of xoshiro256++ is updated
|
||||
with the value provided at the 256b input 'seed_i'.
|
||||
The state is internaly updated in every clock cycle whenever the enable signal `xoshiro_en_i` is raised.
|
||||
The state is internally updated in every clock cycle whenever the enable signal `xoshiro_en_i` is raised.
|
||||
The timing diagram below visualizes this process.
|
||||
|
||||
{{< wavejson >}}
|
||||
|
|
|
@ -41,6 +41,13 @@
|
|||
// main build mode. See commit lowrisc/opentitan#51000a8 for more details.
|
||||
primary_build_mode: prim_lfsr_dw_24
|
||||
|
||||
// Always randomize the initial seed of the LFSR.
|
||||
//
|
||||
// For this block level, the DefaultSeed is ignored and a random value is picked instead. This is
|
||||
// facilitated by the plusarg below. At the chip level, this plusarg is not set, so prim_lfsr
|
||||
// randomly picks between the DefaultSeed value and a random value.
|
||||
run_opts: ["+prim_lfsr_use_default_seed=0"]
|
||||
|
||||
// dw_8 is only used for "smoke" sims, so coverage collection is not needed.
|
||||
prim_lfsr_dw_8_vcs_cov_cfg_file: ""
|
||||
prim_lfsr_dw_24_vcs_cov_cfg_file: "-cm_hier {proj_root}/hw/ip/prim/dv/prim_lfsr/data/prim_lfsr_cover.cfg"
|
||||
|
@ -58,6 +65,7 @@
|
|||
{
|
||||
name: prim_lfsr_test
|
||||
build_mode: prim_lfsr_dw_24
|
||||
run_timeout_mins: 120
|
||||
}
|
||||
]
|
||||
|
||||
|
|
|
@ -7,12 +7,15 @@
|
|||
|
||||
module prim_lfsr_tb;
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// config
|
||||
//////////////////////////////////////////////////////
|
||||
import dv_utils_pkg::*;
|
||||
`include "dv_macros.svh"
|
||||
|
||||
// this can be overriden on the command line
|
||||
// supported types are GAL_XOR, FIB_XNOR
|
||||
//////////////////////////////////////////////////////
|
||||
// Build configurations:
|
||||
// LFSR_TYPE; The type of LFSR used. Choices: "GAL_XOR" or "FIB_XOR"
|
||||
// MIN_LFSR_DW: Minimum LFSR width tested.
|
||||
// MAX_LFSR_DW: Maximum LFSR width tested.
|
||||
//////////////////////////////////////////////////////
|
||||
`ifdef LFSR_TYPE
|
||||
localparam string LfsrType = `LFSR_TYPE;
|
||||
`else
|
||||
|
@ -29,30 +32,17 @@ module prim_lfsr_tb;
|
|||
localparam int unsigned MaxLfsrDw = 32;
|
||||
`endif
|
||||
|
||||
// leave this constant
|
||||
localparam logic SEED = 1'b1;
|
||||
|
||||
localparam time ClkPeriod = 10000;
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// clock
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
wire clk, rst_n;
|
||||
|
||||
clk_rst_if main_clk (
|
||||
.clk,
|
||||
.rst_n
|
||||
);
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// DUTs
|
||||
//////////////////////////////////////////////////////
|
||||
// The default seed of the LFSR.
|
||||
//
|
||||
// This is fixed to 1. It is unused in simulations. The `prim_lfsr` instead, randomizes the
|
||||
// default seed value (DefaultSeedLocal) at runtime. This is enforced with
|
||||
// +prim_lfsr_use_default_seed=0 plusarg.
|
||||
localparam logic SEED = 1'b1;
|
||||
|
||||
// The StatePerm below is only defined for LFSRs up to 256bit wide.
|
||||
`ASSERT_INIT(MaxStateSizeCheck_A, MaxLfsrDw < 256)
|
||||
|
||||
logic [MaxLfsrDw:0] lfsr_en, err;
|
||||
logic [MaxLfsrDw:MinLfsrDw] lfsr_en, err, test_done;
|
||||
logic [MaxLfsrDw:MinLfsrDw][MaxLfsrDw-1:0] state_out;
|
||||
logic [MaxLfsrDw:MinLfsrDw][MaxLfsrDw-1:0] lfsr_periods;
|
||||
|
||||
|
@ -127,7 +117,16 @@ module prim_lfsr_tb;
|
|||
Dw'(32'd003), Dw'(32'd002), Dw'(32'd001), Dw'(32'd000)
|
||||
};
|
||||
|
||||
prim_lfsr #(
|
||||
//////////////////////////////////////////////////////
|
||||
// clock & reset
|
||||
//////////////////////////////////////////////////////
|
||||
wire clk, rst_n;
|
||||
clk_rst_if main_clk(.clk, .rst_n);
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// DUTs
|
||||
//////////////////////////////////////////////////////
|
||||
prim_lfsr #(
|
||||
.LfsrType ( LfsrType ),
|
||||
.LfsrDw ( k ),
|
||||
.EntropyDw ( 1 ),
|
||||
|
@ -156,61 +155,59 @@ module prim_lfsr_tb;
|
|||
|
||||
// calculate period of LFSR:
|
||||
assign lfsr_periods[k] = MaxLfsrDw'({{(k-1){1'b1}}, 1'b0});
|
||||
end
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// stimuli application / response checking
|
||||
//////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////
|
||||
// stimuli application / response checking
|
||||
//////////////////////////////////////////////////////
|
||||
initial begin : p_stimuli
|
||||
bit [MaxLfsrDw-1:0] actual_default_seed;
|
||||
|
||||
initial begin : p_stimuli
|
||||
lfsr_en = '0;
|
||||
err = '0;
|
||||
lfsr_en[k] = 0;
|
||||
err[k] = 0;
|
||||
test_done[k] = 0;
|
||||
|
||||
main_clk.set_period_ps(ClkPeriod);
|
||||
main_clk.set_active();
|
||||
main_clk.apply_reset();
|
||||
main_clk.set_sole_clock(1);
|
||||
main_clk.set_active();
|
||||
main_clk.apply_reset();
|
||||
main_clk.wait_clks($urandom_range(2, 20));
|
||||
|
||||
$display("LFSR maxlen test started for %s (%0d bit to %0d bit).",
|
||||
LfsrType, MinLfsrDw, MaxLfsrDw);
|
||||
// For simulations, we modify prim_lfsr to pick a random default seed for every
|
||||
// invocation, instead of going with the DefaultSeed parameter.
|
||||
actual_default_seed = MaxLfsrDw'(i_prim_lfsr.DefaultSeedLocal);
|
||||
|
||||
main_clk.wait_clks(10);
|
||||
// enable this LFSR
|
||||
lfsr_en[k] = 1;
|
||||
|
||||
// enable all LFSRs
|
||||
lfsr_en = '1;
|
||||
|
||||
$display("Running for 2**%0d-1 cycles...", MaxLfsrDw);
|
||||
for (longint unsigned k = 0; k <= lfsr_periods[MaxLfsrDw]; k++ ) begin
|
||||
|
||||
main_clk.wait_clks(1);
|
||||
|
||||
for (int unsigned j = MinLfsrDw; j <= MaxLfsrDw; j++) begin
|
||||
// check if we reached the initial state again
|
||||
if (state_out[j] == MaxLfsrDw'(SEED) && lfsr_en[j]) begin
|
||||
// $display("cycle: %d -- lfsr: %d -- %x ?= %x, %x",
|
||||
// k, j, state_out[j], SEED, lfsr_en);
|
||||
lfsr_en[j] = 1'b0;
|
||||
// we expect this to occur only after the maximum length period
|
||||
if (lfsr_periods[j] == k) begin
|
||||
$display("Maxlen check for LFSR %0d succeeded!", j);
|
||||
$display("Starting LFSR maxlen test for width %0d: running %0d cycles", k, 2 ** k - 1);
|
||||
for (longint unsigned i = 0; i <= lfsr_periods[MaxLfsrDw] && lfsr_en[k]; i++) begin
|
||||
main_clk.wait_clks(1);
|
||||
// Check if we reached the initial state again.
|
||||
if (state_out[k] == actual_default_seed && lfsr_en[k]) begin
|
||||
lfsr_en[k] = 1'b0;
|
||||
// We expect this to occur only after the maximum length period.
|
||||
if (i == lfsr_periods[k]) begin
|
||||
$display("LFSR maxlen test for width %0d passed!", k);
|
||||
end else begin
|
||||
err[j] = 1'b1;
|
||||
$error("Error LFSR %0d is not maximal length!", j);
|
||||
$display("LFSR maxlen test for width %0d failed at period %0d!", k, i);
|
||||
err[k] = 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
main_clk.wait_clks(10);
|
||||
|
||||
for (int unsigned j = MinLfsrDw; j <= MaxLfsrDw; j++) begin
|
||||
if (lfsr_en[j]) begin
|
||||
$error("Error LFSR %0d never got back to initial state!", j);
|
||||
err[j] = 1'b1;
|
||||
main_clk.wait_clks(10);
|
||||
if (lfsr_en[k]) begin
|
||||
$error("LFSR with width %0d never got back to the initial state!", k);
|
||||
err[k] = 1'b1;
|
||||
end
|
||||
main_clk.stop_clk();
|
||||
test_done[k] = 1;
|
||||
end
|
||||
end
|
||||
|
||||
if (!err) $display("All LFSRs from %0d bit to %0d have maximum length!", MinLfsrDw, MaxLfsrDw);
|
||||
dv_test_status_pkg::dv_test_status(.passed(!err));
|
||||
initial begin
|
||||
$display("Testing LFSR of type %0s for widths {[%0d:%0d]}", LfsrType, MinLfsrDw, MaxLfsrDw);
|
||||
`DV_WAIT(test_done === '1, , 1_000_000_000 /*1ms*/, "prim_lfsr_tb")
|
||||
dv_test_status_pkg::dv_test_status(.passed(err === '0 && test_done === '1));
|
||||
$finish();
|
||||
end
|
||||
|
||||
|
|
|
@ -8,12 +8,10 @@ waive -rules {IFDEF_CODE} -location {prim_cdc_rand_delay.sv} -regexp {.*containe
|
|||
-comment "Ifdefs are required for prim_rand_cdc_delay since it is turned on only for simulation."
|
||||
|
||||
waive -rules {HIER_BRANCH_NOT_READ} -location {prim_cdc_rand_delay.sv} -regexp {.*dst_clk.*} \
|
||||
-comment "Destination clock is only used when attempting to simulate random delays."
|
||||
|
||||
waive -rules {INPUT_NOT_READ} -location {prim_cdc_rand_delay.sv} -regexp {dst_clk|src_clk} \
|
||||
-comment "Source/Destination clock is only used when attempting to simulate random delays."
|
||||
|
||||
waive -rules {PARAM_NOT_USED} -location {prim_cdc_rand_delay.sv} -regexp {UseSourceClock|LatencyPs|JitterPs} \
|
||||
-comment "Randomization parameters are only used when attempting to simulate random delays."
|
||||
-comment "Destination clock is only used when simulating random delays."
|
||||
|
||||
waive -rules {INPUT_NOT_READ} -location {prim_cdc_rand_delay.sv} -regexp {clk_i|rst_ni|prev_data_i} \
|
||||
-comment "Clock, reset, and previous data are only used when simulating random delays."
|
||||
|
||||
waive -rules {PARAM_NOT_USED} -location {prim_cdc_rand_delay.sv} -regexp {Enable} \
|
||||
-comment "Enable parameter is only used when simulating random delays."
|
||||
|
|
|
@ -7,5 +7,5 @@
|
|||
waive -rules {PARAM_NOT_USED} -location {prim_count.sv} -regexp {.*EnableAlertTriggerSVA.*} \
|
||||
-comment "The disable parameter is used only during DV / FPV."
|
||||
|
||||
waive -rules {IFDEF_CODE} -location {prim_count.sv} -msg {Assignment to 'fpv_force' contained within `ifndef 'FPV_ON' block at} \
|
||||
waive -rules {IFDEF_CODE} -location {prim_count.sv} -msg {Assignment to 'fpv_force' contained within `ifndef 'FPV_SEC_CM_ON' block at} \
|
||||
-comment "This ifdef segment is ok, since it is used to provide the tool with a symbolic variable for error injection during FPV."
|
||||
|
|
|
@ -4,3 +4,8 @@
|
|||
#
|
||||
# waiver file for prim_flop_2sync
|
||||
|
||||
waive -rules {IFDEF_CODE} -location {prim_flop_2sync.sv} -regexp {.*contained within \`else block.*} \
|
||||
-comment "Ifdefs are required for prim_flop_2sync since it is turned on only for simulation."
|
||||
|
||||
waive -rules {PARAM_NOT_USED} -location {prim_flop_2sync.sv} -regexp {Parameter 'EnablePrimCdcRand' not used in module.*} \
|
||||
-comment "This parameter is used when cdc instrumentation is enabled."
|
||||
|
|
5
vendor/lowrisc_ip/ip/prim/lint/prim_rst_sync.waiver
vendored
Normal file
5
vendor/lowrisc_ip/ip/prim/lint/prim_rst_sync.waiver
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
# Copyright lowRISC contributors.
|
||||
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# waiver file for prim_rst_sync
|
|
@ -1,4 +1,4 @@
|
|||
REQ/ACK Syncronizer Verilator Testbench
|
||||
REQ/ACK Synchronizer Verilator Testbench
|
||||
=======================================
|
||||
|
||||
This directory contains a basic, scratch Verilator testbench targeting
|
||||
|
|
1
vendor/lowrisc_ip/ip/prim/prim.core
vendored
1
vendor/lowrisc_ip/ip/prim/prim.core
vendored
|
@ -19,6 +19,7 @@ filesets:
|
|||
- lowrisc:prim:flop
|
||||
- lowrisc:prim:flop_en
|
||||
- lowrisc:prim:flop_2sync
|
||||
- lowrisc:prim:rst_sync
|
||||
- lowrisc:prim:arbiter
|
||||
- lowrisc:prim:fifo
|
||||
- lowrisc:prim:alert
|
||||
|
|
17
vendor/lowrisc_ip/ip/prim/prim_macros.core
vendored
Normal file
17
vendor/lowrisc_ip/ip/prim/prim_macros.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:macros:0.1"
|
||||
description: "Common support macros"
|
||||
filesets:
|
||||
files_rtl:
|
||||
files:
|
||||
- rtl/prim_macros.svh : {is_include_file : true}
|
||||
file_type: systemVerilogSource
|
||||
|
||||
targets:
|
||||
default:
|
||||
filesets:
|
||||
- files_rtl
|
47
vendor/lowrisc_ip/ip/prim/prim_rst_sync.core
vendored
Normal file
47
vendor/lowrisc_ip/ip/prim/prim_rst_sync.core
vendored
Normal file
|
@ -0,0 +1,47 @@
|
|||
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:rst_sync"
|
||||
description: "Primitive Reset synchronizer"
|
||||
filesets:
|
||||
files_rtl:
|
||||
depend:
|
||||
- lowrisc:prim:prim_pkg
|
||||
# Needed because the generic prim_flop_2sync has a
|
||||
# dependency on prim:flop.
|
||||
- lowrisc:prim:flop_2sync
|
||||
- lowrisc:prim:mubi
|
||||
- lowrisc:prim:cdc_rand_delay
|
||||
files:
|
||||
- rtl/prim_rst_sync.sv
|
||||
file_type: systemVerilogSource
|
||||
|
||||
files_verilator_waiver:
|
||||
depend:
|
||||
# common waivers
|
||||
- lowrisc:lint:common
|
||||
files:
|
||||
file_type: vlt
|
||||
|
||||
files_ascentlint_waiver:
|
||||
depend:
|
||||
# common waivers
|
||||
- lowrisc:lint:common
|
||||
files:
|
||||
- lint/prim_rst_sync.waiver
|
||||
file_type: waiver
|
||||
|
||||
files_veriblelint_waiver:
|
||||
depend:
|
||||
# common waivers
|
||||
- lowrisc:lint:common
|
||||
|
||||
targets:
|
||||
default:
|
||||
filesets:
|
||||
- tool_verilator ? (files_verilator_waiver)
|
||||
- tool_ascentlint ? (files_ascentlint_waiver)
|
||||
- tool_veriblelint ? (files_veriblelint_waiver)
|
||||
- files_rtl
|
2
vendor/lowrisc_ip/ip/prim/prim_util.core
vendored
2
vendor/lowrisc_ip/ip/prim/prim_util.core
vendored
|
@ -7,6 +7,8 @@ name: "lowrisc:prim:util:0.1"
|
|||
description: "Utilities"
|
||||
filesets:
|
||||
files_rtl:
|
||||
depend:
|
||||
- lowrisc:prim:assert
|
||||
files:
|
||||
- rtl/prim_util_pkg.sv
|
||||
file_type: systemVerilogSource
|
||||
|
|
|
@ -320,7 +320,7 @@ module prim_alert_sender
|
|||
// output must be driven diff unless sigint issue detected
|
||||
`ASSERT(DiffEncoding_A, (alert_rx_i.ack_p ^ alert_rx_i.ack_n) &&
|
||||
(alert_rx_i.ping_p ^ alert_rx_i.ping_n) |->
|
||||
##3 alert_tx_o.alert_p ^ alert_tx_o.alert_n)
|
||||
##[3:4] alert_tx_o.alert_p ^ alert_tx_o.alert_n)
|
||||
|
||||
// handshakes can take indefinite time if blocked due to sigint on outgoing
|
||||
// lines (which is not visible here). thus, we only check whether the
|
||||
|
|
260
vendor/lowrisc_ip/ip/prim/rtl/prim_cdc_rand_delay.sv
vendored
260
vendor/lowrisc_ip/ip/prim/rtl/prim_cdc_rand_delay.sv
vendored
|
@ -6,232 +6,62 @@
|
|||
// and allows DV to model real CDC delays within simulations, especially useful at the chip level
|
||||
// or in IPs that communicate across clock domains.
|
||||
//
|
||||
// If not, delay randomization is enabled - the faster of the two clocks is used to latch src_data,
|
||||
// dst_data is synchronously driven with a random combination of the current src_data and
|
||||
// the delayed version of src_data.
|
||||
// The instrumentation is very simple: when this is enabled the input into the first
|
||||
// synchronizer flop has a mux where the select is randomly set. One of the mux inputs is the input
|
||||
// of this module, and the other is the output of the first flop: selecting the latter models the
|
||||
// effect of the first flop missing the input transition.
|
||||
//
|
||||
// If a source clock isn't used, the input src_data is latched after a parameterizable latency
|
||||
// as `src_data_with_latency`, and an internal version of the output data `src_data_delayed` is set
|
||||
// to this same value after a parameterizable jitter period.
|
||||
//
|
||||
// This is meant to model skew between synchronizer bits and wire delay between the src and dst
|
||||
// flops.
|
||||
//
|
||||
// Four different random delay modes are available:
|
||||
//
|
||||
// - RandDelayDisable: If this delay mode is picked, this module acts as a passthrough.
|
||||
//
|
||||
// - RandDelaySlow: If this delay mode is picked, the output to the dst domain is
|
||||
// continuously driven to `src_data_delayed`.
|
||||
//
|
||||
// - RandDelayOnce: If this delay mode is picked, the mask `out_data_mask` used to combine
|
||||
// `src_data_with_latency` and `src_data_delayed` is randomized once at the
|
||||
// start of the simulation.
|
||||
//
|
||||
// - RandDelayInterval: If this delay mode is picked, the mask `out_data_mask` used to
|
||||
// combine `src_data_with_latency` and `src_data_delayed` is fully
|
||||
// randomized every `prim_cdc_rand_delay_interval` times the src_data
|
||||
// value changes. If the `prim_cdc_rand_delay_interval` is set to 0,
|
||||
// then out_data_mask is randomized on every src_data change.
|
||||
//
|
||||
// DV has control of the weights corresponding to each random delay mode when the delay mode is
|
||||
// randomized, but can also directly override the delay mode as desired.
|
||||
//
|
||||
// DV also has control over whether the source clock is used, the latency, and the jitter values -
|
||||
// these can be modified through the provided setter tasks.
|
||||
// Notice the delay should cause the input to be skipped by at most a single cycle. As a perhaps
|
||||
// unnecessary precaution, the select will only be allowed to be random when the input changes.
|
||||
|
||||
module prim_cdc_rand_delay #(
|
||||
parameter int DataWidth = 1,
|
||||
parameter bit UseSourceClock = 1,
|
||||
parameter int LatencyPs = 1000,
|
||||
parameter int JitterPs = 1000
|
||||
parameter bit Enable = 1
|
||||
) (
|
||||
input logic src_clk,
|
||||
input logic [DataWidth-1:0] src_data,
|
||||
|
||||
input logic dst_clk,
|
||||
output logic [DataWidth-1:0] dst_data
|
||||
input logic clk_i,
|
||||
input logic rst_ni,
|
||||
input logic [DataWidth-1:0] prev_data_i,
|
||||
input logic [DataWidth-1:0] src_data_i,
|
||||
output logic [DataWidth-1:0] dst_data_o
|
||||
);
|
||||
|
||||
`ASSERT_INIT(LegalDataWidth_A, DataWidth > 0)
|
||||
`ASSERT_INIT(LegalLatencyPs_A, LatencyPs >= 0)
|
||||
`ASSERT_INIT(LegalJitterPs_A, JitterPs >= 0)
|
||||
|
||||
`ifdef SIMULATION
|
||||
`ifndef DISABLE_PRIM_CDC_RAND_DELAY
|
||||
if (Enable) begin : gen_enable
|
||||
|
||||
// macro includes
|
||||
`include "uvm_macros.svh"
|
||||
`include "dv_macros.svh"
|
||||
// This controls dst_data_o: any bit with its data_sel set uses prev_data_i, others use
|
||||
// src_data_i.
|
||||
bit [DataWidth-1:0] data_sel;
|
||||
bit cdc_instrumentation_enabled;
|
||||
|
||||
typedef enum bit [1:0] {
|
||||
RandDelayModeDisable,
|
||||
RandDelayModeSlow,
|
||||
RandDelayModeOnce,
|
||||
RandDelayModeInterval
|
||||
} rand_delay_mode_e;
|
||||
function automatic bit [DataWidth-1:0] fast_randomize();
|
||||
bit [DataWidth-1:0] data;
|
||||
if (DataWidth <= 32) begin
|
||||
data = $urandom();
|
||||
end else begin
|
||||
`DV_CHECK_STD_RANDOMIZE_FATAL(data, "Randomization of data failed", $sformatf("%m"))
|
||||
end
|
||||
return data;
|
||||
endfunction
|
||||
|
||||
rand_delay_mode_e prim_cdc_rand_delay_mode;
|
||||
int unsigned prim_cdc_rand_delay_interval = 10;
|
||||
int unsigned prim_cdc_rand_delay_disable_weight = 1;
|
||||
int unsigned prim_cdc_rand_delay_slow_weight = 2;
|
||||
int unsigned prim_cdc_rand_delay_once_weight = 4;
|
||||
int unsigned prim_cdc_rand_delay_interval_weight = 3;
|
||||
bit [3:0] mode; // onehot encoded version of prim_cdc_rand_delay_mode.
|
||||
|
||||
int unsigned prim_cdc_jitter_ps = JitterPs;
|
||||
int unsigned prim_cdc_latency_ps = LatencyPs;
|
||||
|
||||
logic [DataWidth-1:0] out_data_mask;
|
||||
logic [DataWidth-1:0] src_data_with_latency;
|
||||
logic [DataWidth-1:0] src_data_delayed;
|
||||
|
||||
function automatic void set_prim_cdc_rand_delay_mode(int val);
|
||||
prim_cdc_rand_delay_mode = rand_delay_mode_e'(val);
|
||||
update_settings();
|
||||
endfunction
|
||||
|
||||
function automatic void set_prim_cdc_rand_delay_interval(int unsigned val);
|
||||
prim_cdc_rand_delay_interval = val;
|
||||
endfunction
|
||||
|
||||
function automatic void set_prim_cdc_jitter_ps(int val);
|
||||
`ASSERT_I(LegalJitter_A, prim_cdc_jitter_ps >= 0)
|
||||
prim_cdc_jitter_ps = val;
|
||||
endfunction
|
||||
|
||||
function automatic void set_prim_cdc_latency_ps(int val);
|
||||
`ASSERT_I(LegalLatencyPs_A, val >= 0)
|
||||
prim_cdc_latency_ps = val;
|
||||
endfunction
|
||||
|
||||
// Internal method called after prim_cdc_rand_delay_mode is set.
|
||||
function automatic void update_settings();
|
||||
mode = '0;
|
||||
mode[prim_cdc_rand_delay_mode] = 1'b1;
|
||||
if (prim_cdc_rand_delay_mode == RandDelayModeSlow) out_data_mask = '1;
|
||||
if (prim_cdc_rand_delay_mode == RandDelayModeOnce) fast_randomize(out_data_mask);
|
||||
endfunction
|
||||
|
||||
// A slightly more performant version of std::randomize(), using $urandom.
|
||||
//
|
||||
// Empirically, using std::randomize() has been found to be slower than $urandom, since the latter
|
||||
// operates on a fixed data width of 32-bits. There may be an incredibly large number of instances
|
||||
// of this module in the DUT, causing this preformance hit to be noticeable. This method
|
||||
// randomizes the data piece-wise, 32-bits at a time using $urandom instead.
|
||||
function automatic void fast_randomize(output logic [DataWidth-1:0] data);
|
||||
for (int i = 0; i < DataWidth; i += 32) data = (data << 32) | $urandom();
|
||||
endfunction
|
||||
|
||||
// Retrieves settings via plusargs.
|
||||
//
|
||||
// prefix is a string prefix to retrieve the plusarg.
|
||||
// Returns 1 if prim_cdc_rand_delay_mode was set, else 0.
|
||||
function automatic bit get_plusargs(string prefix = "");
|
||||
string mode = "";
|
||||
int unsigned val;
|
||||
if (prefix != "") prefix = {prefix, "."};
|
||||
void'($value$plusargs({prefix, "prim_cdc_rand_delay_mode=%0s"}, mode));
|
||||
`ASSERT_I(ValidMode_A, mode inside {"", "disable", "slow", "once", "interval"})
|
||||
void'($value$plusargs({prefix, "prim_cdc_rand_delay_interval=%0d"},
|
||||
prim_cdc_rand_delay_interval));
|
||||
void'($value$plusargs({prefix, "prim_cdc_rand_delay_disable_weight=%0d"},
|
||||
prim_cdc_rand_delay_disable_weight));
|
||||
void'($value$plusargs({prefix, "prim_cdc_rand_delay_slow_weight=%0d"},
|
||||
prim_cdc_rand_delay_slow_weight));
|
||||
void'($value$plusargs({prefix, "prim_cdc_rand_delay_once_weight=%0d"},
|
||||
prim_cdc_rand_delay_once_weight));
|
||||
void'($value$plusargs({prefix, "prim_cdc_rand_delay_interval_weight=%0d"},
|
||||
prim_cdc_rand_delay_interval_weight));
|
||||
void'($value$plusargs({prefix, "prim_cdc_jitter_ps=%0d"}, prim_cdc_jitter_ps));
|
||||
void'($value$plusargs({prefix, "prim_cdc_latency_ps=%0d"}, prim_cdc_latency_ps));
|
||||
|
||||
case (mode)
|
||||
"disable": prim_cdc_rand_delay_mode = RandDelayModeDisable;
|
||||
"slow": prim_cdc_rand_delay_mode = RandDelayModeSlow;
|
||||
"once": prim_cdc_rand_delay_mode = RandDelayModeOnce;
|
||||
"interval": prim_cdc_rand_delay_mode = RandDelayModeInterval;
|
||||
default: return 0;
|
||||
endcase
|
||||
return 1;
|
||||
endfunction
|
||||
|
||||
initial begin
|
||||
bit res;
|
||||
|
||||
// Command-line override via plusargs (global, applies to ALL instances).
|
||||
// Example: +prim_cdc_rand_delay_mode=once
|
||||
res = get_plusargs();
|
||||
|
||||
// Command-line override via plusargs (instance-specific).
|
||||
// Example: +tb.dut.u_foo.u_bar.u_flop_2sync.u_prim_cdc_rand_delay.prim_cdc_latency_ps=200
|
||||
res |= get_plusargs($sformatf("%m"));
|
||||
|
||||
if (!res) begin
|
||||
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(prim_cdc_rand_delay_mode,
|
||||
prim_cdc_rand_delay_mode dist {
|
||||
RandDelayModeDisable :/ prim_cdc_rand_delay_disable_weight,
|
||||
RandDelayModeSlow :/ prim_cdc_rand_delay_slow_weight,
|
||||
RandDelayModeOnce :/ prim_cdc_rand_delay_once_weight,
|
||||
RandDelayModeInterval :/ prim_cdc_rand_delay_interval_weight
|
||||
};,
|
||||
, $sformatf("%m"))
|
||||
initial begin
|
||||
void'($value$plusargs("cdc_instrumentation_enabled=%d", cdc_instrumentation_enabled));
|
||||
data_sel = '0;
|
||||
end
|
||||
update_settings();
|
||||
|
||||
// Set data_sel at random combinationally when the input changes.
|
||||
always @(src_data_i) begin
|
||||
data_sel = cdc_instrumentation_enabled ? fast_randomize() : 0;
|
||||
end
|
||||
|
||||
// Clear data_del on any cycle start.
|
||||
always @(posedge clk_i or negedge rst_ni) begin
|
||||
data_sel <= 0;
|
||||
end
|
||||
|
||||
always_comb dst_data_o = (prev_data_i & data_sel) | (src_data_i & ~data_sel);
|
||||
end else begin : gen_no_enable
|
||||
assign dst_data_o = src_data_i;
|
||||
end
|
||||
|
||||
// TODO: Run some performance experiments using this implementation versus an implementation that
|
||||
// primarily uses `forever` blocks rather than RTL constructs. Need to also check if this
|
||||
// alternate implementation is still valid when compiling/simulating the design.
|
||||
if (UseSourceClock) begin : gen_use_source_clock
|
||||
|
||||
// If relying on src_clk, insert a delay on the faster clock.
|
||||
always_ff @(posedge src_clk or posedge dst_clk) begin
|
||||
src_data_delayed <= src_data;
|
||||
end
|
||||
assign src_data_with_latency = src_data;
|
||||
|
||||
end else begin : gen_no_use_source_clock
|
||||
|
||||
// If not relying on src_clk, delay by a fixed number of ps determined by the module parameters.
|
||||
always @(src_data) begin
|
||||
src_data_with_latency <= #(prim_cdc_latency_ps * 1ps) src_data;
|
||||
end
|
||||
always @(src_data_with_latency) begin
|
||||
src_data_delayed <= #(prim_cdc_jitter_ps * 1ps) src_data_with_latency;
|
||||
end
|
||||
|
||||
end : gen_no_use_source_clock
|
||||
|
||||
// Randomize delayed random data selection when input data changes, every
|
||||
// prim_cdc_rand_delay_interval number of changes.
|
||||
int counter = 0;
|
||||
always @(src_data_with_latency) begin
|
||||
if (mode[RandDelayModeInterval]) begin
|
||||
counter <= (counter >= prim_cdc_rand_delay_interval) ? '0 : counter + 1;
|
||||
if (counter == prim_cdc_rand_delay_interval) fast_randomize(out_data_mask);
|
||||
end else begin
|
||||
counter <= 0;
|
||||
end
|
||||
end
|
||||
|
||||
assign dst_data = mode[RandDelayModeDisable] ? src_data :
|
||||
((src_data_delayed & out_data_mask) | (src_data_with_latency & ~out_data_mask));
|
||||
|
||||
`else
|
||||
|
||||
// Direct pass through.
|
||||
assign dst_data = src_data;
|
||||
|
||||
`endif // DISABLE_PRIM_CDC_RAND_DELAY
|
||||
|
||||
`else
|
||||
|
||||
// Direct pass through.
|
||||
assign dst_data = src_data;
|
||||
|
||||
`else // SIMULATION
|
||||
assign dst_data_o = src_data_i;
|
||||
`endif // SIMULATION
|
||||
|
||||
//TODO: coverage
|
||||
|
||||
endmodule
|
||||
|
|
36
vendor/lowrisc_ip/ip/prim/rtl/prim_clock_meas.sv
vendored
36
vendor/lowrisc_ip/ip/prim/rtl/prim_clock_meas.sv
vendored
|
@ -127,7 +127,11 @@ module prim_clock_meas #(
|
|||
end
|
||||
end
|
||||
|
||||
//VCS coverage off
|
||||
// pragma coverage off
|
||||
default:;
|
||||
//VCS coverage on
|
||||
// pragma coverage on
|
||||
|
||||
endcase // unique case (state_q)
|
||||
end
|
||||
|
@ -151,17 +155,25 @@ module prim_clock_meas #(
|
|||
.dst_pulse_o(valid_ref)
|
||||
);
|
||||
|
||||
logic [RefCntWidth-1:0] cnt_ref;
|
||||
assign valid = valid_ref & (int'(cnt_ref) == RefCnt - 1);
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if (!rst_ni) begin
|
||||
cnt_ref <= '0;
|
||||
end else if (!cnt_en && |cnt_ref) begin
|
||||
cnt_ref <= '0;
|
||||
end else if (cnt_en && valid) begin
|
||||
cnt_ref <= '0;
|
||||
end else if (cnt_en && valid_ref) begin
|
||||
cnt_ref <= cnt_ref + 1'b1;
|
||||
|
||||
if (RefCnt == 1) begin : gen_degenerate_case
|
||||
// if reference count is one, cnt_ref is always 0.
|
||||
// So there is no need to maintain a counter, and
|
||||
// valid just becomes valid_ref
|
||||
assign valid = valid_ref;
|
||||
end else begin : gen_normal_case
|
||||
logic [RefCntWidth-1:0] cnt_ref;
|
||||
assign valid = valid_ref & (int'(cnt_ref) == RefCnt - 1);
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if (!rst_ni) begin
|
||||
cnt_ref <= '0;
|
||||
end else if (!cnt_en && |cnt_ref) begin
|
||||
cnt_ref <= '0;
|
||||
end else if (cnt_en && valid) begin
|
||||
cnt_ref <= '0;
|
||||
end else if (cnt_en && valid_ref) begin
|
||||
cnt_ref <= cnt_ref + 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -177,7 +189,7 @@ module prim_clock_meas #(
|
|||
end else if (valid_o) begin
|
||||
cnt <= '0;
|
||||
cnt_ovfl <= '0;
|
||||
end else if (cnt_en && cnt_ovfl) begin
|
||||
end else if (cnt_ovfl) begin
|
||||
cnt <= '{default: '1};
|
||||
end else if (cnt_en) begin
|
||||
{cnt_ovfl, cnt} <= cnt + 1'b1;
|
||||
|
|
2
vendor/lowrisc_ip/ip/prim/rtl/prim_count.sv
vendored
2
vendor/lowrisc_ip/ip/prim/rtl/prim_count.sv
vendored
|
@ -55,7 +55,7 @@ module prim_count #(
|
|||
|
||||
logic [NumCnt-1:0][Width-1:0] cnt_d, cnt_q, fpv_force;
|
||||
|
||||
`ifndef FPV_ON
|
||||
`ifndef FPV_SEC_CM_ON
|
||||
// This becomes a free variable in FPV.
|
||||
assign fpv_force = '0;
|
||||
`endif
|
||||
|
|
|
@ -218,57 +218,52 @@ module prim_diff_decode #(
|
|||
`ASSERT(SigintFallCheck_A, sigint_o |-> !fall_o)
|
||||
|
||||
if (AsyncOn) begin : gen_async_assert
|
||||
`ifdef INC_ASSERT
|
||||
// assertions for asynchronous case
|
||||
// in this case we need to sample the input signals onto the local clock to avoid race
|
||||
// conditions between the RTL and assertion sampling in simulation.
|
||||
logic hlp_diff_pq, hlp_diff_nq;
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin : p_edge_reg
|
||||
if (!rst_ni) begin
|
||||
hlp_diff_pq <= 1'b0;
|
||||
hlp_diff_nq <= 1'b1;
|
||||
end else begin
|
||||
hlp_diff_pq <= diff_pi;
|
||||
hlp_diff_nq <= diff_ni;
|
||||
end
|
||||
end
|
||||
|
||||
`ifdef INC_ASSERT
|
||||
`ifndef FPV_ALERT_NO_SIGINT_ERR
|
||||
// correctly detect sigint issue (only one transition cycle of permissible due to skew)
|
||||
`ASSERT(SigintCheck0_A, hlp_diff_pq == hlp_diff_nq [*2] |-> ##[0:1] sigint_o)
|
||||
`ASSERT(SigintCheck0_A, gen_async.diff_pd == gen_async.diff_nd [*2] |-> sigint_o)
|
||||
// the synchronizer adds 2 cycles of latency with respect to input signals.
|
||||
`ASSERT(SigintCheck1_A,
|
||||
##1 (hlp_diff_pq ^ hlp_diff_nq) && $stable(hlp_diff_pq) && $stable(hlp_diff_nq) ##1
|
||||
$rose(hlp_diff_pq) && $stable(hlp_diff_nq) ##1 $stable(hlp_diff_pq) && $fell(hlp_diff_nq)
|
||||
|->
|
||||
##1 rise_o)
|
||||
##1 (gen_async.diff_pd ^ gen_async.diff_nd) &&
|
||||
$stable(gen_async.diff_pd) && $stable(gen_async.diff_nd) ##1
|
||||
$rose(gen_async.diff_pd) && $stable(gen_async.diff_nd) ##1
|
||||
$stable(gen_async.diff_pd) && $fell(gen_async.diff_nd)
|
||||
|-> rise_o)
|
||||
`ASSERT(SigintCheck2_A,
|
||||
##1 (hlp_diff_pq ^ hlp_diff_nq) && $stable(hlp_diff_pq) && $stable(hlp_diff_nq) ##1
|
||||
$fell(hlp_diff_pq) && $stable(hlp_diff_nq) ##1 $stable(hlp_diff_pq) && $rose(hlp_diff_nq)
|
||||
|->
|
||||
##1 fall_o)
|
||||
##1 (gen_async.diff_pd ^ gen_async.diff_nd) &&
|
||||
$stable(gen_async.diff_pd) && $stable(gen_async.diff_nd) ##1
|
||||
$fell(gen_async.diff_pd) && $stable(gen_async.diff_nd) ##1
|
||||
$stable(gen_async.diff_pd) && $rose(gen_async.diff_nd)
|
||||
|-> fall_o)
|
||||
`ASSERT(SigintCheck3_A,
|
||||
##1 (hlp_diff_pq ^ hlp_diff_nq) && $stable(hlp_diff_pq) && $stable(hlp_diff_nq) ##1
|
||||
$rose(hlp_diff_nq) && $stable(hlp_diff_pq) ##1 $stable(hlp_diff_nq) && $fell(hlp_diff_pq)
|
||||
|->
|
||||
##1 fall_o)
|
||||
##1 (gen_async.diff_pd ^ gen_async.diff_nd) &&
|
||||
$stable(gen_async.diff_pd) && $stable(gen_async.diff_nd) ##1
|
||||
$rose(gen_async.diff_nd) && $stable(gen_async.diff_pd) ##1
|
||||
$stable(gen_async.diff_nd) && $fell(gen_async.diff_pd)
|
||||
|-> fall_o)
|
||||
`ASSERT(SigintCheck4_A,
|
||||
##1 (hlp_diff_pq ^ hlp_diff_nq) && $stable(hlp_diff_pq) && $stable(hlp_diff_nq) ##1
|
||||
$fell(hlp_diff_nq) && $stable(hlp_diff_pq) ##1 $stable(hlp_diff_nq) && $rose(hlp_diff_pq)
|
||||
|->
|
||||
##1 rise_o)
|
||||
##1 (gen_async.diff_pd ^ gen_async.diff_nd) &&
|
||||
$stable(gen_async.diff_pd) && $stable(gen_async.diff_nd) ##1
|
||||
$fell(gen_async.diff_nd) && $stable(gen_async.diff_pd) ##1
|
||||
$stable(gen_async.diff_nd) && $rose(gen_async.diff_pd)
|
||||
|-> rise_o)
|
||||
`endif
|
||||
|
||||
// correctly detect edges
|
||||
`ASSERT(RiseCheck_A, ##1 $rose(hlp_diff_pq) && (hlp_diff_pq ^ hlp_diff_nq) |->
|
||||
##[1:2] rise_o, clk_i, !rst_ni || sigint_o)
|
||||
`ASSERT(FallCheck_A, ##1 $fell(hlp_diff_pq) && (hlp_diff_pq ^ hlp_diff_nq) |->
|
||||
##[1:2] fall_o, clk_i, !rst_ni || sigint_o)
|
||||
`ASSERT(EventCheck_A, ##1 $changed(hlp_diff_pq) && (hlp_diff_pq ^ hlp_diff_nq) |->
|
||||
##[1:2] event_o, clk_i, !rst_ni || sigint_o)
|
||||
`ASSERT(RiseCheck_A,
|
||||
!sigint_o ##1 $rose(gen_async.diff_pd) && (gen_async.diff_pd ^ gen_async.diff_nd) |->
|
||||
##[0:1] rise_o, clk_i, !rst_ni || sigint_o)
|
||||
`ASSERT(FallCheck_A,
|
||||
!sigint_o ##1 $fell(gen_async.diff_pd) && (gen_async.diff_pd ^ gen_async.diff_nd) |->
|
||||
##[0:1] fall_o, clk_i, !rst_ni || sigint_o)
|
||||
`ASSERT(EventCheck_A,
|
||||
!sigint_o ##1 $changed(gen_async.diff_pd) && (gen_async.diff_pd ^ gen_async.diff_nd) |->
|
||||
##[0:1] event_o, clk_i, !rst_ni || sigint_o)
|
||||
// correctly detect level
|
||||
`ASSERT(LevelCheck0_A, !sigint_o && (hlp_diff_pq ^ hlp_diff_nq) [*3] |=>
|
||||
$past(hlp_diff_pq, 1) == level_o,
|
||||
`ASSERT(LevelCheck0_A,
|
||||
!sigint_o && (gen_async.diff_pd ^ gen_async.diff_nd) [*2] |->
|
||||
gen_async.diff_pd == level_o,
|
||||
clk_i, !rst_ni || sigint_o)
|
||||
`endif
|
||||
end else begin : gen_sync_assert
|
||||
|
|
|
@ -84,6 +84,20 @@ module prim_double_lfsr #(
|
|||
);
|
||||
end
|
||||
|
||||
`ifdef SIMULATION
|
||||
`ifndef VERILATOR
|
||||
// Ensure both LFSRs start off with the same default seed. if randomized in simulations.
|
||||
initial begin : p_sync_lfsr_default_seed
|
||||
wait (!$isunknown(gen_double_lfsr[0].u_prim_lfsr.DefaultSeedLocal));
|
||||
wait (!$isunknown(gen_double_lfsr[1].u_prim_lfsr.DefaultSeedLocal));
|
||||
gen_double_lfsr[1].u_prim_lfsr.DefaultSeedLocal =
|
||||
gen_double_lfsr[0].u_prim_lfsr.DefaultSeedLocal;
|
||||
$display("%m: Updated gen_double_lfsr[1].u_prim_lfsr.DefaultSeedLocal = 0x%0h",
|
||||
gen_double_lfsr[1].u_prim_lfsr.DefaultSeedLocal);
|
||||
end
|
||||
`endif
|
||||
`endif
|
||||
|
||||
// Output the state from the first LFSR
|
||||
assign state_o = lfsr_state[0][StateOutDw-1:0];
|
||||
assign err_o = lfsr_state[0] != lfsr_state[1];
|
||||
|
|
21
vendor/lowrisc_ip/ip/prim/rtl/prim_edn_req.sv
vendored
21
vendor/lowrisc_ip/ip/prim/rtl/prim_edn_req.sv
vendored
|
@ -19,6 +19,8 @@ module prim_edn_req
|
|||
parameter int OutWidth = 32,
|
||||
// Repetition check for incoming edn data
|
||||
parameter bit RepCheck = 0,
|
||||
// Disable reset-related assertion checks inside prim_sync_reqack primitives.
|
||||
parameter bit EnRstChks = 0,
|
||||
|
||||
// EDN Request latency checker
|
||||
//
|
||||
|
@ -56,6 +58,7 @@ module prim_edn_req
|
|||
localparam int SyncWidth = $bits({edn_i.edn_fips, edn_i.edn_bus});
|
||||
prim_sync_reqack_data #(
|
||||
.Width(SyncWidth),
|
||||
.EnRstChks(EnRstChks),
|
||||
.DataSrc2Dst(1'b0),
|
||||
.DataReg(1'b0)
|
||||
) u_prim_sync_reqack_data (
|
||||
|
@ -149,6 +152,24 @@ module prim_edn_req
|
|||
// Assertions //
|
||||
////////////////
|
||||
|
||||
// Check EDN data is valid: Not all zeros, all ones, or not the same as previous data.
|
||||
`ifdef INC_ASSERT
|
||||
logic [OutWidth-1:0] data_prev, data_curr;
|
||||
|
||||
always_ff @(posedge ack_o or negedge rst_ni) begin
|
||||
if (!rst_ni) begin
|
||||
data_prev <= '0;
|
||||
data_curr <= '0;
|
||||
end else if (ack_o) begin
|
||||
data_curr <= data_o;
|
||||
data_prev <= data_curr;
|
||||
end
|
||||
end
|
||||
|
||||
`ASSERT(DataOutputValid_A, ack_o |-> (data_o != 0) && (data_o != '1))
|
||||
`ASSERT(DataOutputDiffFromPrev_A, data_prev != 0 |-> data_prev != data_o)
|
||||
`endif
|
||||
|
||||
// EDN Max Latency Checker
|
||||
`ifndef SYNTHESIS
|
||||
if (MaxLatency != 0) begin: g_maxlatency_assertion
|
||||
|
|
|
@ -155,11 +155,11 @@ module prim_esc_receiver
|
|||
|
||||
always_comb begin : p_fsm
|
||||
// default
|
||||
state_d = state_q;
|
||||
resp_pd = 1'b0;
|
||||
resp_nd = 1'b1;
|
||||
esc_req = 1'b0;
|
||||
ping_en = 1'b0;
|
||||
state_d = state_q;
|
||||
resp_pd = 1'b0;
|
||||
resp_nd = 1'b1;
|
||||
esc_req = 1'b0;
|
||||
ping_en = 1'b0;
|
||||
|
||||
unique case (state_q)
|
||||
// wait for the esc_p/n diff pair
|
||||
|
@ -177,8 +177,8 @@ module prim_esc_receiver
|
|||
resp_pd = ~resp_pq;
|
||||
resp_nd = resp_pq;
|
||||
if (esc_level) begin
|
||||
state_d = EscResp;
|
||||
esc_req = 1'b1;
|
||||
state_d = EscResp;
|
||||
esc_req = 1'b1;
|
||||
end
|
||||
end
|
||||
// finish ping response. in case esc_level is again asserted,
|
||||
|
@ -189,8 +189,8 @@ module prim_esc_receiver
|
|||
resp_nd = resp_pq;
|
||||
ping_en = 1'b1;
|
||||
if (esc_level) begin
|
||||
state_d = EscResp;
|
||||
esc_req = 1'b1;
|
||||
state_d = EscResp;
|
||||
esc_req = 1'b1;
|
||||
end
|
||||
end
|
||||
// we have got an escalation enable pulse,
|
||||
|
@ -198,10 +198,10 @@ module prim_esc_receiver
|
|||
EscResp: begin
|
||||
state_d = Idle;
|
||||
if (esc_level) begin
|
||||
state_d = EscResp;
|
||||
resp_pd = ~resp_pq;
|
||||
resp_nd = resp_pq;
|
||||
esc_req = 1'b1;
|
||||
state_d = EscResp;
|
||||
resp_pd = ~resp_pq;
|
||||
resp_nd = resp_pq;
|
||||
esc_req = 1'b1;
|
||||
end
|
||||
end
|
||||
// we have a signal integrity issue at one of
|
||||
|
@ -218,14 +218,14 @@ module prim_esc_receiver
|
|||
resp_nd = ~resp_pq;
|
||||
end
|
||||
end
|
||||
default : state_d = Idle;
|
||||
default: state_d = Idle;
|
||||
endcase
|
||||
|
||||
// bail out if a signal integrity issue has been detected
|
||||
if (sigint_detected && (state_q != SigInt)) begin
|
||||
state_d = SigInt;
|
||||
resp_pd = 1'b0;
|
||||
resp_nd = 1'b0;
|
||||
state_d = SigInt;
|
||||
resp_pd = 1'b0;
|
||||
resp_nd = 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -250,24 +250,23 @@ module prim_esc_receiver
|
|||
`ASSERT_KNOWN(EscEnKnownO_A, esc_req_o)
|
||||
`ASSERT_KNOWN(RespPKnownO_A, esc_rx_o)
|
||||
|
||||
`ASSERT(SigIntCheck0_A, esc_tx_i.esc_p == esc_tx_i.esc_n |=>
|
||||
esc_rx_o.resp_p == esc_rx_o.resp_n)
|
||||
`ASSERT(SigIntCheck0_A, esc_tx_i.esc_p == esc_tx_i.esc_n |=> esc_rx_o.resp_p == esc_rx_o.resp_n)
|
||||
`ASSERT(SigIntCheck1_A, esc_tx_i.esc_p == esc_tx_i.esc_n |=> state_q == SigInt)
|
||||
// auto-escalate in case of signal integrity issue
|
||||
`ASSERT(SigIntCheck2_A, esc_tx_i.esc_p == esc_tx_i.esc_n |=> esc_req_o)
|
||||
// correct diff encoding
|
||||
`ASSERT(DiffEncCheck_A, esc_tx_i.esc_p ^ esc_tx_i.esc_n |=>
|
||||
esc_rx_o.resp_p ^ esc_rx_o.resp_n)
|
||||
`ASSERT(DiffEncCheck_A, esc_tx_i.esc_p ^ esc_tx_i.esc_n |=> esc_rx_o.resp_p ^ esc_rx_o.resp_n)
|
||||
// disable in case of signal integrity issue
|
||||
`ASSERT(PingRespCheck_A, state_q == Idle ##1 $rose(esc_tx_i.esc_p) ##1 $fell(esc_tx_i.esc_p) |->
|
||||
$rose(esc_rx_o.resp_p) ##1 $fell(esc_rx_o.resp_p),
|
||||
clk_i, !rst_ni || (esc_tx_i.esc_p == esc_tx_i.esc_n))
|
||||
// escalation response needs to continuously toggle
|
||||
`ASSERT(EscRespCheck_A, esc_tx_i.esc_p && $past(esc_tx_i.esc_p) &&
|
||||
`ASSERT(EscRespCheck_A, ##1 esc_tx_i.esc_p && $past(esc_tx_i.esc_p) &&
|
||||
(esc_tx_i.esc_p ^ esc_tx_i.esc_n) && $past(esc_tx_i.esc_p ^ esc_tx_i.esc_n)
|
||||
|=> esc_rx_o.resp_p != $past(esc_rx_o.resp_p))
|
||||
// detect escalation pulse
|
||||
`ASSERT(EscEnCheck_A, esc_tx_i.esc_p && (esc_tx_i.esc_p ^ esc_tx_i.esc_n) && state_q != SigInt
|
||||
`ASSERT(EscEnCheck_A,
|
||||
esc_tx_i.esc_p && (esc_tx_i.esc_p ^ esc_tx_i.esc_n) && state_q != SigInt
|
||||
##1 esc_tx_i.esc_p && (esc_tx_i.esc_p ^ esc_tx_i.esc_n) |-> esc_req_o)
|
||||
// make sure the counter does not wrap around
|
||||
`ASSERT(EscCntWrap_A, &timeout_cnt |=> timeout_cnt != 0)
|
||||
|
|
16
vendor/lowrisc_ip/ip/prim/rtl/prim_fifo_async.sv
vendored
16
vendor/lowrisc_ip/ip/prim/rtl/prim_fifo_async.sv
vendored
|
@ -10,6 +10,7 @@ module prim_fifo_async #(
|
|||
parameter int unsigned Width = 16,
|
||||
parameter int unsigned Depth = 4,
|
||||
parameter bit OutputZeroIfEmpty = 1'b0, // if == 1 always output 0 when FIFO is empty
|
||||
parameter bit OutputZeroIfInvalid = 1'b0, // if == 1 always output 0 when rvalid_o is low
|
||||
localparam int unsigned DepthW = $clog2(Depth+1) // derived parameter representing [0..Depth]
|
||||
) (
|
||||
// write port
|
||||
|
@ -197,10 +198,21 @@ module prim_fifo_async #(
|
|||
|
||||
end
|
||||
|
||||
// rdata_o is qualified with rvalid_o to avoid CDC error
|
||||
if (OutputZeroIfEmpty == 1'b1) begin : gen_output_zero
|
||||
assign rdata_o = empty_rclk ? '0 : rdata_int;
|
||||
if (OutputZeroIfInvalid == 1'b1) begin : gen_invalid_zero
|
||||
assign rdata_o = empty_rclk ? '0 : (rvalid_o ? rdata_int : '0);
|
||||
end
|
||||
else begin : gen_invalid_non_zero
|
||||
assign rdata_o = empty_rclk ? '0 : rdata_int;
|
||||
end
|
||||
end else begin : gen_no_output_zero
|
||||
assign rdata_o = rdata_int;
|
||||
if (OutputZeroIfInvalid == 1'b1) begin : gen_invalid_zero
|
||||
assign rdata_o = rvalid_o ? rdata_int : '0;
|
||||
end
|
||||
else begin : gen_invalid_non_zero
|
||||
assign rdata_o = rdata_int;
|
||||
end
|
||||
end
|
||||
|
||||
//////////////////////////////////////
|
||||
|
|
24
vendor/lowrisc_ip/ip/prim/rtl/prim_flop_2sync.sv
vendored
24
vendor/lowrisc_ip/ip/prim/rtl/prim_flop_2sync.sv
vendored
|
@ -9,8 +9,7 @@
|
|||
module prim_flop_2sync #(
|
||||
parameter int Width = 16,
|
||||
parameter logic [Width-1:0] ResetValue = '0,
|
||||
parameter int CdcLatencyPs = 1000,
|
||||
parameter int CdcJitterPs = 1000
|
||||
parameter bit EnablePrimCdcRand = 1
|
||||
) (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
|
@ -19,20 +18,23 @@ module prim_flop_2sync #(
|
|||
);
|
||||
|
||||
logic [Width-1:0] d_o;
|
||||
logic [Width-1:0] intq;
|
||||
|
||||
`ifdef SIMULATION
|
||||
|
||||
prim_cdc_rand_delay #(
|
||||
.DataWidth(Width),
|
||||
.UseSourceClock(0),
|
||||
.LatencyPs(CdcLatencyPs),
|
||||
.JitterPs(CdcJitterPs)
|
||||
.Enable(EnablePrimCdcRand)
|
||||
) u_prim_cdc_rand_delay (
|
||||
.src_clk(),
|
||||
.src_data(d_i),
|
||||
.dst_clk(clk_i),
|
||||
.dst_data(d_o)
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.src_data_i(d_i),
|
||||
.prev_data_i(intq),
|
||||
.dst_data_o(d_o)
|
||||
);
|
||||
|
||||
logic [Width-1:0] intq;
|
||||
`else // !`ifdef SIMULATION
|
||||
always_comb d_o = d_i;
|
||||
`endif // !`ifdef SIMULATION
|
||||
|
||||
prim_flop #(
|
||||
.Width(Width),
|
||||
|
|
57
vendor/lowrisc_ip/ip/prim/rtl/prim_intr_hw.sv
vendored
57
vendor/lowrisc_ip/ip/prim/rtl/prim_intr_hw.sv
vendored
|
@ -9,7 +9,19 @@
|
|||
|
||||
module prim_intr_hw # (
|
||||
parameter int unsigned Width = 1,
|
||||
parameter bit FlopOutput = 1
|
||||
parameter bit FlopOutput = 1,
|
||||
|
||||
// IntrT parameter is to hint the logic for the interrupt type. Module
|
||||
// supports two interrupt types, *Status* and *Event*.
|
||||
//
|
||||
// The differences between those two types are:
|
||||
// - Status is persistent. Until the root cause is alleviated, the interrupt
|
||||
// keeps asserting.
|
||||
// - Event remains high for a relatively short period time without SW
|
||||
// intervention. One distinct example is an error (error could be status
|
||||
// though). If a certain error condition is captured, HW logic may create a
|
||||
// pulse. In this case the interrupt is assumed as an Event interrupt.
|
||||
parameter IntrT = "Event" // Event or Status
|
||||
) (
|
||||
// event
|
||||
input clk_i,
|
||||
|
@ -28,13 +40,39 @@ module prim_intr_hw # (
|
|||
output logic [Width-1:0] intr_o
|
||||
);
|
||||
|
||||
logic [Width-1:0] new_event;
|
||||
assign new_event =
|
||||
(({Width{reg2hw_intr_test_qe_i}} & reg2hw_intr_test_q_i) | event_intr_i);
|
||||
assign hw2reg_intr_state_de_o = |new_event;
|
||||
// for scalar interrupts, this resolves to '1' with new event
|
||||
// for vector interrupts, new events are OR'd in to existing interrupt state
|
||||
assign hw2reg_intr_state_d_o = new_event | reg2hw_intr_state_q_i;
|
||||
logic [Width-1:0] status; // incl. test
|
||||
|
||||
if (IntrT == "Event") begin : g_intr_event
|
||||
logic [Width-1:0] new_event;
|
||||
assign new_event =
|
||||
(({Width{reg2hw_intr_test_qe_i}} & reg2hw_intr_test_q_i) | event_intr_i);
|
||||
assign hw2reg_intr_state_de_o = |new_event;
|
||||
// for scalar interrupts, this resolves to '1' with new event
|
||||
// for vector interrupts, new events are OR'd in to existing interrupt state
|
||||
assign hw2reg_intr_state_d_o = new_event | reg2hw_intr_state_q_i;
|
||||
|
||||
assign status = reg2hw_intr_state_q_i ;
|
||||
end : g_intr_event
|
||||
else if (IntrT == "Status") begin : g_intr_status
|
||||
logic [Width-1:0] test_q; // Storing test. Cleared by SW
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if (!rst_ni) test_q <= '0;
|
||||
else if (reg2hw_intr_test_qe_i) test_q <= reg2hw_intr_test_q_i;
|
||||
end
|
||||
|
||||
// TODO: In Status type, INTR_STATE is better to be external type and RO.
|
||||
assign hw2reg_intr_state_de_o = 1'b 1; // always represent the status
|
||||
assign hw2reg_intr_state_d_o = event_intr_i | test_q;
|
||||
|
||||
assign status = event_intr_i | test_q;
|
||||
|
||||
// To make the timing same to event type, status signal does not use CSR.q,
|
||||
// rather the input of the CSR.
|
||||
logic unused_reg2hw;
|
||||
assign unused_reg2hw = ^reg2hw_intr_state_q_i;
|
||||
end : g_intr_status
|
||||
|
||||
|
||||
if (FlopOutput == 1) begin : gen_flop_intr_output
|
||||
// flop the interrupt output
|
||||
|
@ -42,7 +80,7 @@ module prim_intr_hw # (
|
|||
if (!rst_ni) begin
|
||||
intr_o <= '0;
|
||||
end else begin
|
||||
intr_o <= reg2hw_intr_state_q_i & reg2hw_intr_enable_q_i;
|
||||
intr_o <= status & reg2hw_intr_enable_q_i;
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -54,5 +92,6 @@ module prim_intr_hw # (
|
|||
assign intr_o = reg2hw_intr_state_q_i & reg2hw_intr_enable_q_i;
|
||||
end
|
||||
|
||||
`ASSERT_INIT(IntrTKind_A, IntrT inside {"Event", "Status"})
|
||||
|
||||
endmodule
|
||||
|
|
55
vendor/lowrisc_ip/ip/prim/rtl/prim_lc_sync.sv
vendored
55
vendor/lowrisc_ip/ip/prim/rtl/prim_lc_sync.sv
vendored
|
@ -46,7 +46,35 @@ module prim_lc_sync #(
|
|||
.d_i(lc_en_i),
|
||||
.q_o(lc_en)
|
||||
);
|
||||
|
||||
// Note regarding SVA below:
|
||||
//
|
||||
// 1) Without the sampled rst_ni pre-condition, this may cause false assertion failures right after
|
||||
// a reset release, since the "disable iff" condition with the rst_ni is sampled in the "observed"
|
||||
// SV scheduler region after all assignments have been evaluated (see also LRM section 16.12, page
|
||||
// 423). This is a simulation artifact due to reset synchronization in RTL, which releases rst_ni
|
||||
// on the active clock edge. This causes the assertion to evaluate although the reset was actually
|
||||
// 0 when entering this simulation cycle.
|
||||
//
|
||||
// 2) Similarly to 1) there can be sampling mismatches of the lc_en_i signal since that signal may
|
||||
// originate from a different clock domain. I.e., in cases where the lc_en_i signal changes exactly
|
||||
// at the same time that the clk_i signal rises, the SVA will not pick up that change in that clock
|
||||
// cycle, whereas RTL will because SVAs sample values in the "preponed" region. To that end we make
|
||||
// use of an RTL helper variable to sample the lc_en_i signal, hence ensuring that there are no
|
||||
// sampling mismatches.
|
||||
`ifdef INC_ASSERT
|
||||
lc_ctrl_pkg::lc_tx_t lc_en_in_sva_q;
|
||||
always_ff @(posedge clk_i) begin
|
||||
lc_en_in_sva_q <= lc_en_i;
|
||||
end
|
||||
`ASSERT(OutputDelay_A,
|
||||
rst_ni |-> ##3 lc_en_o == {NumCopies{$past(lc_en_in_sva_q, 2)}} ||
|
||||
($past(lc_en_in_sva_q, 2) != $past(lc_en_in_sva_q, 1)))
|
||||
`endif
|
||||
end else begin : gen_no_flops
|
||||
//VCS coverage off
|
||||
// pragma coverage off
|
||||
|
||||
// This unused companion logic helps remove lint errors
|
||||
// for modules where clock and reset are used for assertions only
|
||||
// or nothing at all.
|
||||
|
@ -59,8 +87,12 @@ module prim_lc_sync #(
|
|||
unused_logic <= lc_en_i;
|
||||
end
|
||||
end
|
||||
//VCS coverage on
|
||||
// pragma coverage on
|
||||
|
||||
assign lc_en = lc_en_i;
|
||||
|
||||
`ASSERT(OutputDelay_A, lc_en_o == {NumCopies{lc_en_i}})
|
||||
end
|
||||
|
||||
for (genvar j = 0; j < NumCopies; j++) begin : gen_buffs
|
||||
|
@ -81,27 +113,4 @@ module prim_lc_sync #(
|
|||
// The outputs should be known at all times.
|
||||
`ASSERT_KNOWN(OutputsKnown_A, lc_en_o)
|
||||
|
||||
// If the multibit signal is in a transient state, we expect it
|
||||
// to be stable again within one clock cycle.
|
||||
// DV will exclude these three assertions by name, thus added a module name prefix to make it
|
||||
// harder to accidentally replicate in other modules.
|
||||
`ASSERT(PrimLcSyncCheckTransients_A,
|
||||
!(lc_en_i inside {lc_ctrl_pkg::On, lc_ctrl_pkg::Off})
|
||||
|=>
|
||||
(lc_en_i inside {lc_ctrl_pkg::On, lc_ctrl_pkg::Off}))
|
||||
|
||||
// If a signal departs from passive state, we expect it to move to the active state
|
||||
// with only one transient cycle in between.
|
||||
`ASSERT(PrimLcSyncCheckTransients0_A,
|
||||
$past(lc_en_i == lc_ctrl_pkg::Off) &&
|
||||
!(lc_en_i inside {lc_ctrl_pkg::On, lc_ctrl_pkg::Off})
|
||||
|=>
|
||||
(lc_en_i == lc_ctrl_pkg::On))
|
||||
|
||||
`ASSERT(PrimLcSyncCheckTransients1_A,
|
||||
$past(lc_en_i == lc_ctrl_pkg::On) &&
|
||||
!(lc_en_i inside {lc_ctrl_pkg::On, lc_ctrl_pkg::Off})
|
||||
|=>
|
||||
(lc_en_i == lc_ctrl_pkg::Off))
|
||||
|
||||
endmodule : prim_lc_sync
|
||||
|
|
46
vendor/lowrisc_ip/ip/prim/rtl/prim_lfsr.sv
vendored
46
vendor/lowrisc_ip/ip/prim/rtl/prim_lfsr.sv
vendored
|
@ -311,6 +311,36 @@ module prim_lfsr #(
|
|||
logic [LfsrDw-1:0] lfsr_d, lfsr_q;
|
||||
logic [LfsrDw-1:0] next_lfsr_state, coeffs;
|
||||
|
||||
// Enable the randomization of DefaultSeed using DefaultSeedLocal in DV simulations.
|
||||
`ifdef SIMULATION
|
||||
`ifdef VERILATOR
|
||||
localparam logic [LfsrDw-1:0] DefaultSeedLocal = DefaultSeed;
|
||||
|
||||
`else
|
||||
logic [LfsrDw-1:0] DefaultSeedLocal;
|
||||
logic prim_lfsr_use_default_seed;
|
||||
|
||||
initial begin : p_randomize_default_seed
|
||||
if (!$value$plusargs("prim_lfsr_use_default_seed=%0d", prim_lfsr_use_default_seed)) begin
|
||||
// 30% of the time, use the DefaultSeed parameter; 70% of the time, randomize it.
|
||||
`ASSERT_I(UseDefaultSeedRandomizeCheck_A, std::randomize(prim_lfsr_use_default_seed) with {
|
||||
prim_lfsr_use_default_seed dist {0:/7, 1:/3};})
|
||||
end
|
||||
if (prim_lfsr_use_default_seed) begin
|
||||
DefaultSeedLocal = DefaultSeed;
|
||||
end else begin
|
||||
// Randomize the DefaultSeedLocal ensuring its not all 0s or all 1s.
|
||||
`ASSERT_I(DefaultSeedLocalRandomizeCheck_A, std::randomize(DefaultSeedLocal) with {
|
||||
!(DefaultSeedLocal inside {'0, '1});})
|
||||
end
|
||||
$display("%m: DefaultSeed = 0x%0h, DefaultSeedLocal = 0x%0h", DefaultSeed, DefaultSeedLocal);
|
||||
end
|
||||
`endif // ifdef VERILATOR
|
||||
|
||||
`else
|
||||
localparam logic [LfsrDw-1:0] DefaultSeedLocal = DefaultSeed;
|
||||
|
||||
`endif // ifdef SIMULATION
|
||||
|
||||
////////////////
|
||||
// Galois XOR //
|
||||
|
@ -334,7 +364,7 @@ module prim_lfsr #(
|
|||
assign lockup = ~(|lfsr_q);
|
||||
|
||||
// check that seed is not all-zero
|
||||
`ASSERT_INIT(DefaultSeedNzCheck_A, |DefaultSeed)
|
||||
`ASSERT_INIT(DefaultSeedNzCheck_A, |DefaultSeedLocal)
|
||||
|
||||
|
||||
////////////////////
|
||||
|
@ -359,7 +389,7 @@ module prim_lfsr #(
|
|||
assign lockup = &lfsr_q;
|
||||
|
||||
// check that seed is not all-ones
|
||||
`ASSERT_INIT(DefaultSeedNzCheck_A, !(&DefaultSeed))
|
||||
`ASSERT_INIT(DefaultSeedNzCheck_A, !(&DefaultSeedLocal))
|
||||
|
||||
|
||||
/////////////
|
||||
|
@ -378,7 +408,7 @@ module prim_lfsr #(
|
|||
//////////////////
|
||||
|
||||
assign lfsr_d = (seed_en_i) ? seed_i :
|
||||
(lfsr_en_i && lockup) ? DefaultSeed :
|
||||
(lfsr_en_i && lockup) ? DefaultSeedLocal :
|
||||
(lfsr_en_i) ? next_lfsr_state :
|
||||
lfsr_q;
|
||||
|
||||
|
@ -520,7 +550,7 @@ module prim_lfsr #(
|
|||
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin : p_reg
|
||||
if (!rst_ni) begin
|
||||
lfsr_q <= DefaultSeed;
|
||||
lfsr_q <= DefaultSeedLocal;
|
||||
end else begin
|
||||
lfsr_q <= lfsr_d;
|
||||
end
|
||||
|
@ -547,7 +577,7 @@ module prim_lfsr #(
|
|||
// Galois XOR
|
||||
if (64'(LfsrType) == 64'("GAL_XOR")) begin
|
||||
if (next_state == 0) begin
|
||||
next_state = DefaultSeed;
|
||||
next_state = DefaultSeedLocal;
|
||||
end else begin
|
||||
state0 = next_state[0];
|
||||
next_state = next_state >> 1;
|
||||
|
@ -557,7 +587,7 @@ module prim_lfsr #(
|
|||
// Fibonacci XNOR
|
||||
end else if (64'(LfsrType) == "FIB_XNOR") begin
|
||||
if (&next_state) begin
|
||||
next_state = DefaultSeed;
|
||||
next_state = DefaultSeedLocal;
|
||||
end else begin
|
||||
state0 = ~(^(next_state & lfsrcoeffs));
|
||||
next_state = next_state << 1;
|
||||
|
@ -659,9 +689,9 @@ module prim_lfsr #(
|
|||
end
|
||||
end
|
||||
|
||||
`ASSERT(MaximalLengthCheck0_A, cnt_q == 0 |-> lfsr_q == DefaultSeed,
|
||||
`ASSERT(MaximalLengthCheck0_A, cnt_q == 0 |-> lfsr_q == DefaultSeedLocal,
|
||||
clk_i, !rst_ni || perturbed_q)
|
||||
`ASSERT(MaximalLengthCheck1_A, cnt_q != 0 |-> lfsr_q != DefaultSeed,
|
||||
`ASSERT(MaximalLengthCheck1_A, cnt_q != 0 |-> lfsr_q != DefaultSeedLocal,
|
||||
clk_i, !rst_ni || perturbed_q)
|
||||
`endif
|
||||
end
|
||||
|
|
31
vendor/lowrisc_ip/ip/prim/rtl/prim_macros.svh
vendored
Normal file
31
vendor/lowrisc_ip/ip/prim/rtl/prim_macros.svh
vendored
Normal file
|
@ -0,0 +1,31 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Some generally useful macros for RTL.
|
||||
|
||||
// Coverage pragmas, used around code for which we want to disable coverage collection.
|
||||
// Don't forget to add a closing ON pragma after the code to be skipped.
|
||||
//
|
||||
// Some notes:
|
||||
// - The first line is for VCS, the second for xcelium. It is okay to issue both regardless of
|
||||
// the tool used.
|
||||
// - For xcelium it is possible to discriminate between metrics to be disabled as follows
|
||||
// //pragma coverage <metric> = on/off
|
||||
// where metric can be block | expr | toggle | fsm.
|
||||
|
||||
// TODO(https://github.com/chipsalliance/verible/issues/1498) Verible seems to get confused
|
||||
// by these macros, so the code will inline these directives until this is fixed.
|
||||
/*
|
||||
`ifndef PRAGMA_COVERAGE_OFF
|
||||
`define PRAGMA_COVERAGE_OFF \
|
||||
/``/VCS coverage off \
|
||||
/``/ pragma coverage off
|
||||
`endif
|
||||
|
||||
`ifndef PRAGMA_COVERAGE_ON
|
||||
`define PRAGMA_COVERAGE_ON \
|
||||
/``/VCS coverage on \
|
||||
/``/ pragma coverage on
|
||||
`endif
|
||||
*/
|
|
@ -101,11 +101,47 @@ module prim_mubi12_sync
|
|||
);
|
||||
end
|
||||
|
||||
// Note regarding SVAs below:
|
||||
//
|
||||
// 1) Without the sampled rst_ni pre-condition, this may cause false assertion failures right after
|
||||
// a reset release, since the "disable iff" condition with the rst_ni is sampled in the "observed"
|
||||
// SV scheduler region after all assignments have been evaluated (see also LRM section 16.12, page
|
||||
// 423). This is a simulation artifact due to reset synchronization in RTL, which releases rst_ni
|
||||
// on the active clock edge. This causes the assertion to evaluate although the reset was actually
|
||||
// 0 when entering this simulation cycle.
|
||||
//
|
||||
// 2) Similarly to 1) there can be sampling mismatches of the lc_en_i signal since that signal may
|
||||
// originate from a different clock domain. I.e., in cases where the lc_en_i signal changes exactly
|
||||
// at the same time that the clk_i signal rises, the SVA will not pick up that change in that clock
|
||||
// cycle, whereas RTL will because SVAs sample values in the "preponed" region. To that end we make
|
||||
// use of an RTL helper variable to sample the lc_en_i signal, hence ensuring that there are no
|
||||
// sampling mismatches.
|
||||
`ifdef INC_ASSERT
|
||||
mubi12_t mubi_in_sva_q;
|
||||
always_ff @(posedge clk_i) begin
|
||||
mubi_in_sva_q <= mubi_i;
|
||||
end
|
||||
`ASSERT(OutputIfUnstable_A, sig_unstable |-> mubi_o == {NumCopies{reset_value}})
|
||||
`ASSERT(OutputDelay_A,
|
||||
rst_ni |-> ##[3:4] sig_unstable || mubi_o == {NumCopies{$past(mubi_in_sva_q, 2)}})
|
||||
`endif
|
||||
end else begin : gen_no_stable_chks
|
||||
assign mubi = mubi_sync;
|
||||
`ifdef INC_ASSERT
|
||||
mubi12_t mubi_in_sva_q;
|
||||
always_ff @(posedge clk_i) begin
|
||||
mubi_in_sva_q <= mubi_i;
|
||||
end
|
||||
`ASSERT(OutputDelay_A,
|
||||
rst_ni |-> ##3 (mubi_o == {NumCopies{$past(mubi_in_sva_q, 2)}} ||
|
||||
$past(mubi_in_sva_q, 2) != $past(mubi_in_sva_q, 1)))
|
||||
`endif
|
||||
end
|
||||
end else begin : gen_no_flops
|
||||
|
||||
//VCS coverage off
|
||||
// pragma coverage off
|
||||
|
||||
// This unused companion logic helps remove lint errors
|
||||
// for modules where clock and reset are used for assertions only
|
||||
// This logic will be removed for synthesis since it is unloaded.
|
||||
|
@ -118,7 +154,12 @@ module prim_mubi12_sync
|
|||
end
|
||||
end
|
||||
|
||||
//VCS coverage on
|
||||
// pragma coverage on
|
||||
|
||||
assign mubi = MuBi12Width'(mubi_i);
|
||||
|
||||
`ASSERT(OutputDelay_A, mubi_o == {NumCopies{mubi_i}})
|
||||
end
|
||||
|
||||
for (genvar j = 0; j < NumCopies; j++) begin : gen_buffs
|
||||
|
@ -139,27 +180,4 @@ module prim_mubi12_sync
|
|||
// The outputs should be known at all times.
|
||||
`ASSERT_KNOWN(OutputsKnown_A, mubi_o)
|
||||
|
||||
// If the multibit signal is in a transient state, we expect it
|
||||
// to be stable again within one clock cycle.
|
||||
// DV will exclude these three assertions by name, thus added a module name prefix to make it
|
||||
// harder to accidentally replicate in other modules.
|
||||
`ASSERT(PrimMubi12SyncCheckTransients_A,
|
||||
!(mubi_i inside {MuBi12True, MuBi12False})
|
||||
|=>
|
||||
(mubi_i inside {MuBi12True, MuBi12False}))
|
||||
|
||||
// If a signal departs from passive state, we expect it to move to the active state
|
||||
// with only one transient cycle in between.
|
||||
`ASSERT(PrimMubi12SyncCheckTransients0_A,
|
||||
$past(mubi_i == MuBi12False) &&
|
||||
!(mubi_i inside {MuBi12True, MuBi12False})
|
||||
|=>
|
||||
(mubi_i == MuBi12True))
|
||||
|
||||
`ASSERT(PrimMubi12SyncCheckTransients1_A,
|
||||
$past(mubi_i == MuBi12True) &&
|
||||
!(mubi_i inside {MuBi12True, MuBi12False})
|
||||
|=>
|
||||
(mubi_i == MuBi12False))
|
||||
|
||||
endmodule : prim_mubi12_sync
|
||||
|
|
|
@ -101,11 +101,47 @@ module prim_mubi16_sync
|
|||
);
|
||||
end
|
||||
|
||||
// Note regarding SVAs below:
|
||||
//
|
||||
// 1) Without the sampled rst_ni pre-condition, this may cause false assertion failures right after
|
||||
// a reset release, since the "disable iff" condition with the rst_ni is sampled in the "observed"
|
||||
// SV scheduler region after all assignments have been evaluated (see also LRM section 16.12, page
|
||||
// 423). This is a simulation artifact due to reset synchronization in RTL, which releases rst_ni
|
||||
// on the active clock edge. This causes the assertion to evaluate although the reset was actually
|
||||
// 0 when entering this simulation cycle.
|
||||
//
|
||||
// 2) Similarly to 1) there can be sampling mismatches of the lc_en_i signal since that signal may
|
||||
// originate from a different clock domain. I.e., in cases where the lc_en_i signal changes exactly
|
||||
// at the same time that the clk_i signal rises, the SVA will not pick up that change in that clock
|
||||
// cycle, whereas RTL will because SVAs sample values in the "preponed" region. To that end we make
|
||||
// use of an RTL helper variable to sample the lc_en_i signal, hence ensuring that there are no
|
||||
// sampling mismatches.
|
||||
`ifdef INC_ASSERT
|
||||
mubi16_t mubi_in_sva_q;
|
||||
always_ff @(posedge clk_i) begin
|
||||
mubi_in_sva_q <= mubi_i;
|
||||
end
|
||||
`ASSERT(OutputIfUnstable_A, sig_unstable |-> mubi_o == {NumCopies{reset_value}})
|
||||
`ASSERT(OutputDelay_A,
|
||||
rst_ni |-> ##[3:4] sig_unstable || mubi_o == {NumCopies{$past(mubi_in_sva_q, 2)}})
|
||||
`endif
|
||||
end else begin : gen_no_stable_chks
|
||||
assign mubi = mubi_sync;
|
||||
`ifdef INC_ASSERT
|
||||
mubi16_t mubi_in_sva_q;
|
||||
always_ff @(posedge clk_i) begin
|
||||
mubi_in_sva_q <= mubi_i;
|
||||
end
|
||||
`ASSERT(OutputDelay_A,
|
||||
rst_ni |-> ##3 (mubi_o == {NumCopies{$past(mubi_in_sva_q, 2)}} ||
|
||||
$past(mubi_in_sva_q, 2) != $past(mubi_in_sva_q, 1)))
|
||||
`endif
|
||||
end
|
||||
end else begin : gen_no_flops
|
||||
|
||||
//VCS coverage off
|
||||
// pragma coverage off
|
||||
|
||||
// This unused companion logic helps remove lint errors
|
||||
// for modules where clock and reset are used for assertions only
|
||||
// This logic will be removed for synthesis since it is unloaded.
|
||||
|
@ -118,7 +154,12 @@ module prim_mubi16_sync
|
|||
end
|
||||
end
|
||||
|
||||
//VCS coverage on
|
||||
// pragma coverage on
|
||||
|
||||
assign mubi = MuBi16Width'(mubi_i);
|
||||
|
||||
`ASSERT(OutputDelay_A, mubi_o == {NumCopies{mubi_i}})
|
||||
end
|
||||
|
||||
for (genvar j = 0; j < NumCopies; j++) begin : gen_buffs
|
||||
|
@ -139,27 +180,4 @@ module prim_mubi16_sync
|
|||
// The outputs should be known at all times.
|
||||
`ASSERT_KNOWN(OutputsKnown_A, mubi_o)
|
||||
|
||||
// If the multibit signal is in a transient state, we expect it
|
||||
// to be stable again within one clock cycle.
|
||||
// DV will exclude these three assertions by name, thus added a module name prefix to make it
|
||||
// harder to accidentally replicate in other modules.
|
||||
`ASSERT(PrimMubi16SyncCheckTransients_A,
|
||||
!(mubi_i inside {MuBi16True, MuBi16False})
|
||||
|=>
|
||||
(mubi_i inside {MuBi16True, MuBi16False}))
|
||||
|
||||
// If a signal departs from passive state, we expect it to move to the active state
|
||||
// with only one transient cycle in between.
|
||||
`ASSERT(PrimMubi16SyncCheckTransients0_A,
|
||||
$past(mubi_i == MuBi16False) &&
|
||||
!(mubi_i inside {MuBi16True, MuBi16False})
|
||||
|=>
|
||||
(mubi_i == MuBi16True))
|
||||
|
||||
`ASSERT(PrimMubi16SyncCheckTransients1_A,
|
||||
$past(mubi_i == MuBi16True) &&
|
||||
!(mubi_i inside {MuBi16True, MuBi16False})
|
||||
|=>
|
||||
(mubi_i == MuBi16False))
|
||||
|
||||
endmodule : prim_mubi16_sync
|
||||
|
|
64
vendor/lowrisc_ip/ip/prim/rtl/prim_mubi4_sync.sv
vendored
64
vendor/lowrisc_ip/ip/prim/rtl/prim_mubi4_sync.sv
vendored
|
@ -101,11 +101,47 @@ module prim_mubi4_sync
|
|||
);
|
||||
end
|
||||
|
||||
// Note regarding SVAs below:
|
||||
//
|
||||
// 1) Without the sampled rst_ni pre-condition, this may cause false assertion failures right after
|
||||
// a reset release, since the "disable iff" condition with the rst_ni is sampled in the "observed"
|
||||
// SV scheduler region after all assignments have been evaluated (see also LRM section 16.12, page
|
||||
// 423). This is a simulation artifact due to reset synchronization in RTL, which releases rst_ni
|
||||
// on the active clock edge. This causes the assertion to evaluate although the reset was actually
|
||||
// 0 when entering this simulation cycle.
|
||||
//
|
||||
// 2) Similarly to 1) there can be sampling mismatches of the lc_en_i signal since that signal may
|
||||
// originate from a different clock domain. I.e., in cases where the lc_en_i signal changes exactly
|
||||
// at the same time that the clk_i signal rises, the SVA will not pick up that change in that clock
|
||||
// cycle, whereas RTL will because SVAs sample values in the "preponed" region. To that end we make
|
||||
// use of an RTL helper variable to sample the lc_en_i signal, hence ensuring that there are no
|
||||
// sampling mismatches.
|
||||
`ifdef INC_ASSERT
|
||||
mubi4_t mubi_in_sva_q;
|
||||
always_ff @(posedge clk_i) begin
|
||||
mubi_in_sva_q <= mubi_i;
|
||||
end
|
||||
`ASSERT(OutputIfUnstable_A, sig_unstable |-> mubi_o == {NumCopies{reset_value}})
|
||||
`ASSERT(OutputDelay_A,
|
||||
rst_ni |-> ##[3:4] sig_unstable || mubi_o == {NumCopies{$past(mubi_in_sva_q, 2)}})
|
||||
`endif
|
||||
end else begin : gen_no_stable_chks
|
||||
assign mubi = mubi_sync;
|
||||
`ifdef INC_ASSERT
|
||||
mubi4_t mubi_in_sva_q;
|
||||
always_ff @(posedge clk_i) begin
|
||||
mubi_in_sva_q <= mubi_i;
|
||||
end
|
||||
`ASSERT(OutputDelay_A,
|
||||
rst_ni |-> ##3 (mubi_o == {NumCopies{$past(mubi_in_sva_q, 2)}} ||
|
||||
$past(mubi_in_sva_q, 2) != $past(mubi_in_sva_q, 1)))
|
||||
`endif
|
||||
end
|
||||
end else begin : gen_no_flops
|
||||
|
||||
//VCS coverage off
|
||||
// pragma coverage off
|
||||
|
||||
// This unused companion logic helps remove lint errors
|
||||
// for modules where clock and reset are used for assertions only
|
||||
// This logic will be removed for synthesis since it is unloaded.
|
||||
|
@ -118,7 +154,12 @@ module prim_mubi4_sync
|
|||
end
|
||||
end
|
||||
|
||||
//VCS coverage on
|
||||
// pragma coverage on
|
||||
|
||||
assign mubi = MuBi4Width'(mubi_i);
|
||||
|
||||
`ASSERT(OutputDelay_A, mubi_o == {NumCopies{mubi_i}})
|
||||
end
|
||||
|
||||
for (genvar j = 0; j < NumCopies; j++) begin : gen_buffs
|
||||
|
@ -139,27 +180,4 @@ module prim_mubi4_sync
|
|||
// The outputs should be known at all times.
|
||||
`ASSERT_KNOWN(OutputsKnown_A, mubi_o)
|
||||
|
||||
// If the multibit signal is in a transient state, we expect it
|
||||
// to be stable again within one clock cycle.
|
||||
// DV will exclude these three assertions by name, thus added a module name prefix to make it
|
||||
// harder to accidentally replicate in other modules.
|
||||
`ASSERT(PrimMubi4SyncCheckTransients_A,
|
||||
!(mubi_i inside {MuBi4True, MuBi4False})
|
||||
|=>
|
||||
(mubi_i inside {MuBi4True, MuBi4False}))
|
||||
|
||||
// If a signal departs from passive state, we expect it to move to the active state
|
||||
// with only one transient cycle in between.
|
||||
`ASSERT(PrimMubi4SyncCheckTransients0_A,
|
||||
$past(mubi_i == MuBi4False) &&
|
||||
!(mubi_i inside {MuBi4True, MuBi4False})
|
||||
|=>
|
||||
(mubi_i == MuBi4True))
|
||||
|
||||
`ASSERT(PrimMubi4SyncCheckTransients1_A,
|
||||
$past(mubi_i == MuBi4True) &&
|
||||
!(mubi_i inside {MuBi4True, MuBi4False})
|
||||
|=>
|
||||
(mubi_i == MuBi4False))
|
||||
|
||||
endmodule : prim_mubi4_sync
|
||||
|
|
64
vendor/lowrisc_ip/ip/prim/rtl/prim_mubi8_sync.sv
vendored
64
vendor/lowrisc_ip/ip/prim/rtl/prim_mubi8_sync.sv
vendored
|
@ -101,11 +101,47 @@ module prim_mubi8_sync
|
|||
);
|
||||
end
|
||||
|
||||
// Note regarding SVAs below:
|
||||
//
|
||||
// 1) Without the sampled rst_ni pre-condition, this may cause false assertion failures right after
|
||||
// a reset release, since the "disable iff" condition with the rst_ni is sampled in the "observed"
|
||||
// SV scheduler region after all assignments have been evaluated (see also LRM section 16.12, page
|
||||
// 423). This is a simulation artifact due to reset synchronization in RTL, which releases rst_ni
|
||||
// on the active clock edge. This causes the assertion to evaluate although the reset was actually
|
||||
// 0 when entering this simulation cycle.
|
||||
//
|
||||
// 2) Similarly to 1) there can be sampling mismatches of the lc_en_i signal since that signal may
|
||||
// originate from a different clock domain. I.e., in cases where the lc_en_i signal changes exactly
|
||||
// at the same time that the clk_i signal rises, the SVA will not pick up that change in that clock
|
||||
// cycle, whereas RTL will because SVAs sample values in the "preponed" region. To that end we make
|
||||
// use of an RTL helper variable to sample the lc_en_i signal, hence ensuring that there are no
|
||||
// sampling mismatches.
|
||||
`ifdef INC_ASSERT
|
||||
mubi8_t mubi_in_sva_q;
|
||||
always_ff @(posedge clk_i) begin
|
||||
mubi_in_sva_q <= mubi_i;
|
||||
end
|
||||
`ASSERT(OutputIfUnstable_A, sig_unstable |-> mubi_o == {NumCopies{reset_value}})
|
||||
`ASSERT(OutputDelay_A,
|
||||
rst_ni |-> ##[3:4] sig_unstable || mubi_o == {NumCopies{$past(mubi_in_sva_q, 2)}})
|
||||
`endif
|
||||
end else begin : gen_no_stable_chks
|
||||
assign mubi = mubi_sync;
|
||||
`ifdef INC_ASSERT
|
||||
mubi8_t mubi_in_sva_q;
|
||||
always_ff @(posedge clk_i) begin
|
||||
mubi_in_sva_q <= mubi_i;
|
||||
end
|
||||
`ASSERT(OutputDelay_A,
|
||||
rst_ni |-> ##3 (mubi_o == {NumCopies{$past(mubi_in_sva_q, 2)}} ||
|
||||
$past(mubi_in_sva_q, 2) != $past(mubi_in_sva_q, 1)))
|
||||
`endif
|
||||
end
|
||||
end else begin : gen_no_flops
|
||||
|
||||
//VCS coverage off
|
||||
// pragma coverage off
|
||||
|
||||
// This unused companion logic helps remove lint errors
|
||||
// for modules where clock and reset are used for assertions only
|
||||
// This logic will be removed for synthesis since it is unloaded.
|
||||
|
@ -118,7 +154,12 @@ module prim_mubi8_sync
|
|||
end
|
||||
end
|
||||
|
||||
//VCS coverage on
|
||||
// pragma coverage on
|
||||
|
||||
assign mubi = MuBi8Width'(mubi_i);
|
||||
|
||||
`ASSERT(OutputDelay_A, mubi_o == {NumCopies{mubi_i}})
|
||||
end
|
||||
|
||||
for (genvar j = 0; j < NumCopies; j++) begin : gen_buffs
|
||||
|
@ -139,27 +180,4 @@ module prim_mubi8_sync
|
|||
// The outputs should be known at all times.
|
||||
`ASSERT_KNOWN(OutputsKnown_A, mubi_o)
|
||||
|
||||
// If the multibit signal is in a transient state, we expect it
|
||||
// to be stable again within one clock cycle.
|
||||
// DV will exclude these three assertions by name, thus added a module name prefix to make it
|
||||
// harder to accidentally replicate in other modules.
|
||||
`ASSERT(PrimMubi8SyncCheckTransients_A,
|
||||
!(mubi_i inside {MuBi8True, MuBi8False})
|
||||
|=>
|
||||
(mubi_i inside {MuBi8True, MuBi8False}))
|
||||
|
||||
// If a signal departs from passive state, we expect it to move to the active state
|
||||
// with only one transient cycle in between.
|
||||
`ASSERT(PrimMubi8SyncCheckTransients0_A,
|
||||
$past(mubi_i == MuBi8False) &&
|
||||
!(mubi_i inside {MuBi8True, MuBi8False})
|
||||
|=>
|
||||
(mubi_i == MuBi8True))
|
||||
|
||||
`ASSERT(PrimMubi8SyncCheckTransients1_A,
|
||||
$past(mubi_i == MuBi8True) &&
|
||||
!(mubi_i inside {MuBi8True, MuBi8False})
|
||||
|=>
|
||||
(mubi_i == MuBi8False))
|
||||
|
||||
endmodule : prim_mubi8_sync
|
||||
|
|
|
@ -36,6 +36,9 @@ module prim_pulse_sync (
|
|||
// source active must come far enough such that the destination domain has time
|
||||
// to create a valid pulse.
|
||||
`ifdef INC_ASSERT
|
||||
//VCS coverage off
|
||||
// pragma coverage off
|
||||
|
||||
logic src_active_flag;
|
||||
|
||||
// source active flag tracks whether there is an ongoing "toggle" event.
|
||||
|
@ -51,6 +54,9 @@ module prim_pulse_sync (
|
|||
end
|
||||
end
|
||||
|
||||
//VCS coverage on
|
||||
// pragma coverage on
|
||||
|
||||
`ASSERT(SrcPulseCheck_M, src_pulse_i |-> !src_active_flag, clk_src_i, !rst_src_ni)
|
||||
`endif
|
||||
|
||||
|
|
|
@ -61,11 +61,16 @@ module prim_reg_cdc #(
|
|||
src_busy_q <= '0;
|
||||
end else if (src_req) begin
|
||||
src_busy_q <= 1'b1;
|
||||
end else if (src_busy_q && src_ack) begin
|
||||
end else if (src_ack) begin
|
||||
src_busy_q <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
// A src_ack should only be sent if there was a src_req.
|
||||
// src_busy_q asserts whenever there is a src_req. By association,
|
||||
// whenever src_ack is seen, then src_busy must be high.
|
||||
`ASSERT(SrcAckBusyChk_A, src_ack |-> src_busy_q, clk_src_i, !rst_src_ni)
|
||||
|
||||
assign src_busy_o = src_busy_q;
|
||||
|
||||
// src_q acts as both the write holding register and the software read back
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
// a delta is observed between the transit register and the current hardware value,
|
||||
// and a new handshake event is generated.
|
||||
//
|
||||
// The thrid scenario can be folded into the second scenario. The only difference
|
||||
// The third scenario can be folded into the second scenario. The only difference
|
||||
// is that of the 4 cases identified, only case 2 can happen since there is never a
|
||||
// software initiated update.
|
||||
|
||||
|
@ -71,7 +71,7 @@ module prim_reg_cdc_arb #(
|
|||
// ds allows us to sample the destination domain register
|
||||
// one cycle earlier instead of waiting for it to be reflected
|
||||
// in the qs.
|
||||
// This is important because a genearl use case is that interrupts
|
||||
// This is important because a general use case is that interrupts
|
||||
// are captured alongside payloads from the destination domain into
|
||||
// the source domain. If we rely on `qs` only, then it is very likely
|
||||
// that the software observed value will be behind the interrupt
|
||||
|
@ -92,6 +92,13 @@ module prim_reg_cdc_arb #(
|
|||
StWait
|
||||
} state_e;
|
||||
|
||||
|
||||
// Only honor the incoming destinate update request if the incoming
|
||||
// value is actually different from what is already completed in the
|
||||
// handshake
|
||||
logic dst_update;
|
||||
assign dst_update = dst_update_i & (dst_qs_o != dst_ds_i);
|
||||
|
||||
if (DstWrReq) begin : gen_wr_req
|
||||
logic dst_lat_q;
|
||||
logic dst_lat_d;
|
||||
|
@ -161,7 +168,7 @@ module prim_reg_cdc_arb #(
|
|||
|
||||
// if a destination update is received when the system is idle and there is no
|
||||
// software side request, hw update must be selected.
|
||||
`ASSERT(DstUpdateReqCheck_A, ##1 dst_update_i & !dst_req & !busy |=> id_q == SelHwReq,
|
||||
`ASSERT(DstUpdateReqCheck_A, ##1 dst_update & !dst_req & !busy |=> id_q == SelHwReq,
|
||||
clk_dst_i, !rst_dst_ni)
|
||||
|
||||
// if hw select was chosen, then it must be the case there was a destination update
|
||||
|
@ -195,7 +202,7 @@ module prim_reg_cdc_arb #(
|
|||
// there's a software issued request for change
|
||||
state_d = StWait;
|
||||
dst_lat_d = 1'b1;
|
||||
end else if (dst_update_i) begin
|
||||
end else if (dst_update) begin
|
||||
state_d = StWait;
|
||||
dst_lat_d = 1'b1;
|
||||
end else if (dst_qs_o != dst_qs_i) begin
|
||||
|
@ -239,23 +246,29 @@ module prim_reg_cdc_arb #(
|
|||
|
||||
// once hardware makes an update request, we must eventually see an update pulse
|
||||
`ASSERT(ReqTimeout_A, $rose(id_q == SelHwReq) |-> s_eventually(src_update_o),
|
||||
clk_src_i, !rst_src_ni)
|
||||
clk_src_i, !rst_src_ni)
|
||||
|
||||
`ifdef INC_ASSERT
|
||||
//VCS coverage off
|
||||
// pragma coverage off
|
||||
|
||||
logic async_flag;
|
||||
always_ff @(posedge clk_dst_i or negedge rst_dst_ni or posedge src_update_o) begin
|
||||
if (!rst_dst_ni) begin
|
||||
async_flag <= '0;
|
||||
end else if (src_update_o) begin
|
||||
async_flag <= '0;
|
||||
end else if (dst_update_i && !dst_req_o && !busy) begin
|
||||
end else if (dst_update && !dst_req_o && !busy) begin
|
||||
async_flag <= 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
// once hardware makes an update request, we must eventually see an update pulse
|
||||
`ASSERT(UpdateTimeout_A, $rose(async_flag) |-> s_eventually(src_update_o),
|
||||
clk_src_i, !rst_src_ni)
|
||||
//VCS coverage on
|
||||
// pragma coverage on
|
||||
|
||||
// once hardware makes an update request, we must eventually see an update pulse
|
||||
`ASSERT(UpdateTimeout_A, $rose(async_flag) |-> s_eventually(src_update_o),
|
||||
clk_src_i, !rst_src_ni)
|
||||
`endif
|
||||
|
||||
end else begin : gen_passthru
|
||||
|
@ -280,7 +293,7 @@ module prim_reg_cdc_arb #(
|
|||
);
|
||||
|
||||
logic unused_sigs;
|
||||
assign unused_sigs = |{dst_ds_i, dst_update_i};
|
||||
assign unused_sigs = |{dst_ds_i, dst_update};
|
||||
end
|
||||
|
||||
|
||||
|
|
65
vendor/lowrisc_ip/ip/prim/rtl/prim_rst_sync.sv
vendored
Normal file
65
vendor/lowrisc_ip/ip/prim/rtl/prim_rst_sync.sv
vendored
Normal file
|
@ -0,0 +1,65 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
// Reset synchronizer
|
||||
/** Conventional 2FF async assert sync de-assert reset synchronizer
|
||||
*
|
||||
*/
|
||||
|
||||
module prim_rst_sync #(
|
||||
// ActiveHigh should be 0 if the input reset is active low reset
|
||||
parameter bit ActiveHigh = 1'b 0,
|
||||
|
||||
// In certain case, Scan may be inserted at the following reset chain.
|
||||
// Set SkipScan to 1'b 1 in that case.
|
||||
parameter bit SkipScan = 1'b 0
|
||||
) (
|
||||
input clk_i,
|
||||
input d_i, // raw reset (not synched to clk_i)
|
||||
output logic q_o, // reset synched to clk_i
|
||||
|
||||
// Scan chain
|
||||
input scan_rst_ni,
|
||||
input prim_mubi_pkg::mubi4_t scanmode_i
|
||||
);
|
||||
|
||||
logic async_rst_n, scan_rst;
|
||||
logic rst_sync;
|
||||
|
||||
// TODO: Check if 2FF set can be used.
|
||||
if (ActiveHigh == 1'b 1) begin : g_rst_inv
|
||||
assign async_rst_n = ~d_i;
|
||||
assign scan_rst = ~scan_rst_ni;
|
||||
end else begin : g_rst_direct
|
||||
assign async_rst_n = d_i;
|
||||
assign scan_rst = scan_rst_ni;
|
||||
end
|
||||
|
||||
prim_flop_2sync #(
|
||||
.Width (1),
|
||||
.ResetValue (ActiveHigh)
|
||||
) u_sync (
|
||||
.clk_i,
|
||||
.rst_ni (async_rst_n),
|
||||
.d_i (!ActiveHigh), // reset release value
|
||||
.q_o (rst_sync )
|
||||
);
|
||||
|
||||
if (SkipScan) begin : g_skip_scan
|
||||
logic unused_scan;
|
||||
assign unused_scan = ^{scan_rst, scanmode_i};
|
||||
|
||||
assign q_o = rst_sync;
|
||||
end else begin : g_scan_mux
|
||||
prim_clock_mux2 #(
|
||||
.NoFpgaBufG(1'b1)
|
||||
) u_scan_mux (
|
||||
.clk0_i(rst_sync ),
|
||||
.clk1_i(scan_rst ),
|
||||
.sel_i (prim_mubi_pkg::mubi4_test_true_strict(scanmode_i)),
|
||||
.clk_o (q_o )
|
||||
);
|
||||
end
|
||||
|
||||
endmodule : prim_rst_sync
|
|
@ -10,6 +10,8 @@
|
|||
// Notes:
|
||||
// - Once asserted, the source (SRC) domain is not allowed to de-assert REQ without ACK.
|
||||
// - The destination (DST) domain is not allowed to send an ACK without a REQ.
|
||||
// - When resetting one domain, also the other domain needs to be reset with both resets being
|
||||
// active at the same time.
|
||||
// - This module works both when syncing from a faster to a slower clock domain and vice versa.
|
||||
// - Internally, this module uses a non-return-to-zero, two-phase handshake protocol. Assuming the
|
||||
// DST domain responds with an ACK immediately, the latency from asserting the REQ in the
|
||||
|
@ -23,7 +25,9 @@
|
|||
|
||||
`include "prim_assert.sv"
|
||||
|
||||
module prim_sync_reqack (
|
||||
module prim_sync_reqack #(
|
||||
parameter bit EnRstChks = 1'b0 // Enable reset-related assertion checks, disabled by default.
|
||||
) (
|
||||
input clk_src_i, // REQ side, SRC domain
|
||||
input rst_src_ni, // REQ side, SRC domain
|
||||
input clk_dst_i, // ACK side, DST domain
|
||||
|
@ -109,7 +113,14 @@ module prim_sync_reqack (
|
|||
end
|
||||
end
|
||||
|
||||
//VCS coverage off
|
||||
// pragma coverage off
|
||||
|
||||
default: ;
|
||||
|
||||
//VCS coverage on
|
||||
// pragma coverage on
|
||||
|
||||
endcase
|
||||
end
|
||||
|
||||
|
@ -146,7 +157,14 @@ module prim_sync_reqack (
|
|||
end
|
||||
end
|
||||
|
||||
//VCS coverage off
|
||||
// pragma coverage off
|
||||
|
||||
default: ;
|
||||
|
||||
//VCS coverage on
|
||||
// pragma coverage on
|
||||
|
||||
endcase
|
||||
end
|
||||
|
||||
|
@ -172,9 +190,20 @@ module prim_sync_reqack (
|
|||
|
||||
// SRC domain can only de-assert REQ after receiving ACK.
|
||||
`ASSERT(SyncReqAckHoldReq, $fell(src_req_i) && req_chk_i |->
|
||||
$fell(src_ack_o), clk_src_i, !rst_src_ni || !req_chk_i)
|
||||
$fell(src_ack_o), clk_src_i, !rst_src_ni || !rst_dst_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)
|
||||
`ASSERT(SyncReqAckAckNeedsReq, dst_ack_i |->
|
||||
dst_req_o, clk_dst_i, !rst_src_ni || !rst_dst_ni)
|
||||
|
||||
if (EnRstChks) begin : gen_assert_en_rst_chks
|
||||
// Always reset both domains. Both resets need to be active at the same time.
|
||||
`ASSERT(SyncReqAckRstSrc, $fell(rst_src_ni) |->
|
||||
(##[0:$] !rst_dst_ni within !rst_src_ni [*1:$]),
|
||||
clk_src_i, 0)
|
||||
`ASSERT(SyncReqAckRstDst, $fell(rst_dst_ni) |->
|
||||
(##[0:$] !rst_src_ni within !rst_dst_ni [*1:$]),
|
||||
clk_dst_i, 0)
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
|
||||
module prim_sync_reqack_data #(
|
||||
parameter int unsigned Width = 1,
|
||||
parameter bit EnRstChks = 1'b0, // Enable reset-related assertion checks, disabled by
|
||||
// default.
|
||||
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,
|
||||
|
@ -42,7 +44,9 @@ module prim_sync_reqack_data #(
|
|||
////////////////////////////////////
|
||||
// REQ/ACK synchronizer primitive //
|
||||
////////////////////////////////////
|
||||
prim_sync_reqack u_prim_sync_reqack (
|
||||
prim_sync_reqack #(
|
||||
.EnRstChks(EnRstChks)
|
||||
) u_prim_sync_reqack (
|
||||
.clk_src_i,
|
||||
.rst_src_ni,
|
||||
.clk_dst_i,
|
||||
|
@ -92,7 +96,7 @@ module prim_sync_reqack_data #(
|
|||
// SRC domain cannot change data while waiting for ACK.
|
||||
`ASSERT(SyncReqAckDataHoldSrc2Dst, !$stable(data_i) |->
|
||||
(!src_req_i || (src_req_i && src_ack_o)),
|
||||
clk_src_i, !rst_src_ni)
|
||||
clk_src_i, !rst_src_ni || !rst_dst_ni)
|
||||
|
||||
// Register stage cannot be used.
|
||||
`ASSERT_INIT(SyncReqAckDataReg, DataSrc2Dst && !DataReg)
|
||||
|
@ -121,10 +125,10 @@ module prim_sync_reqack_data #(
|
|||
// checks that the DST side doesn't do anything that it shouldn't know is safe.
|
||||
`ASSERT(SyncReqAckDataHoldDst2SrcA,
|
||||
src_req_i && src_ack_o |-> $past(data_o, 2) == data_o && $past(data_o) == data_o,
|
||||
clk_src_i, !rst_src_ni)
|
||||
clk_src_i, !rst_src_ni || !rst_dst_ni)
|
||||
`ASSERT(SyncReqAckDataHoldDst2SrcB,
|
||||
$past(src_req_i && src_ack_o) |-> $past(data_o) == data_o,
|
||||
clk_src_i, !rst_src_ni)
|
||||
clk_src_i, !rst_src_ni || !rst_dst_ni)
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
|
@ -86,4 +86,13 @@ package prim_util_pkg;
|
|||
`endif
|
||||
endfunction
|
||||
|
||||
`ifdef INC_ASSERT
|
||||
// Package-scoped variable to detect the end of simulation.
|
||||
//
|
||||
// Used only in DV simulations. The bit will be used by assertions in RTL to perform end-of-test
|
||||
// cleanup. It is set to 1 in `dv_test_status_pkg::dv_test_status()`, which is invoked right
|
||||
// before the simulation is terminated, to signal the status of the test.
|
||||
bit end_of_simulation;
|
||||
`endif
|
||||
|
||||
endpackage
|
||||
|
|
|
@ -34,7 +34,9 @@ module prim_generic_flash #(
|
|||
inout [TestModeWidth-1:0] flash_test_mode_a_io,
|
||||
inout flash_test_voltage_h_io,
|
||||
output logic flash_err_o,
|
||||
output ast_pkg::ast_dif_t fl_alert_src_o,
|
||||
// Alert indication (to be connected to alert sender in the instantiating IP)
|
||||
output logic fatal_alert_o,
|
||||
output logic recov_alert_o,
|
||||
input tlul_pkg::tl_h2d_t tl_i,
|
||||
output tlul_pkg::tl_d2h_t tl_o,
|
||||
// Observability
|
||||
|
@ -114,6 +116,7 @@ module prim_generic_flash #(
|
|||
// TL-UL Test Interface Emulation //
|
||||
////////////////////////////////////
|
||||
|
||||
logic intg_err;
|
||||
flash_ctrl_reg_pkg::flash_ctrl_prim_reg2hw_t reg2hw;
|
||||
flash_ctrl_reg_pkg::flash_ctrl_prim_hw2reg_t hw2reg;
|
||||
flash_ctrl_prim_reg_top u_reg_top (
|
||||
|
@ -123,7 +126,7 @@ module prim_generic_flash #(
|
|||
.tl_o (tl_o),
|
||||
.reg2hw (reg2hw),
|
||||
.hw2reg (hw2reg),
|
||||
.intg_err_o(), // TODO: do we need to wire this up?
|
||||
.intg_err_o(intg_err),
|
||||
.devmode_i (1'b1)
|
||||
);
|
||||
|
||||
|
@ -137,8 +140,8 @@ module prim_generic_flash #(
|
|||
// open source model has no error response at the moment
|
||||
assign flash_err_o = 1'b0;
|
||||
|
||||
// default alert assignments
|
||||
assign fl_alert_src_o = '{p: '0, n: '1};
|
||||
assign fatal_alert_o = intg_err;
|
||||
assign recov_alert_o = 1'b0;
|
||||
|
||||
logic unused_obs;
|
||||
assign unused_obs = |obs_ctrl_i;
|
||||
|
|
|
@ -53,9 +53,19 @@ module prim_generic_flash_bank #(
|
|||
int EraseLatency = 200;
|
||||
|
||||
initial begin
|
||||
bit flash_rand_delay_en;
|
||||
void'($value$plusargs("flash_rand_delay_en=%0b", flash_rand_delay_en));
|
||||
|
||||
if (flash_rand_delay_en) begin
|
||||
ReadLatency = $urandom_range(1, 5);
|
||||
ProgLatency = $urandom_range(25, 50);
|
||||
EraseLatency = $urandom_range(125, 200);
|
||||
end
|
||||
void'($value$plusargs("flash_read_latency=%0d", ReadLatency));
|
||||
void'($value$plusargs("flash_program_latency=%0d", ProgLatency));
|
||||
void'($value$plusargs("flash_erase_latency=%0d", EraseLatency));
|
||||
$display("%m: ReadLatency:%0d ProgLatency:%0d EraseLatency:%0d",
|
||||
ReadLatency, ProgLatency, EraseLatency);
|
||||
end
|
||||
`endif
|
||||
|
||||
|
|
|
@ -46,8 +46,9 @@ module prim_generic_otp
|
|||
input prim_mubi_pkg::mubi4_t scanmode_i, // Scan Mode input
|
||||
input scan_en_i, // Scan Shift
|
||||
input scan_rst_ni, // Scan Reset
|
||||
// Alert indication
|
||||
output ast_pkg::ast_dif_t otp_alert_src_o,
|
||||
// Alert indication (to be connected to alert sender in the instantiating IP)
|
||||
output logic fatal_alert_o,
|
||||
output logic recov_alert_o,
|
||||
// Ready valid handshake for read/write command
|
||||
output logic ready_o,
|
||||
input valid_i,
|
||||
|
@ -85,7 +86,9 @@ module prim_generic_otp
|
|||
logic unused_scan;
|
||||
assign unused_scan = ^{scanmode_i, scan_en_i, scan_rst_ni};
|
||||
|
||||
assign otp_alert_src_o = '{p: '0, n: '1};
|
||||
logic intg_err, fsm_err;
|
||||
assign fatal_alert_o = intg_err || fsm_err;
|
||||
assign recov_alert_o = 1'b0;
|
||||
|
||||
assign test_vect_o = '0;
|
||||
assign test_status_o = '0;
|
||||
|
@ -103,8 +106,8 @@ module prim_generic_otp
|
|||
.tl_o (test_tl_o ),
|
||||
.reg2hw (reg2hw ),
|
||||
.hw2reg (hw2reg ),
|
||||
.intg_err_o(), // TODO: do we need to wire this up?
|
||||
.devmode_i (1'b1)
|
||||
.intg_err_o(intg_err ),
|
||||
.devmode_i (1'b1 )
|
||||
);
|
||||
|
||||
logic unused_reg_sig;
|
||||
|
@ -115,34 +118,40 @@ module prim_generic_otp
|
|||
// Control logic //
|
||||
///////////////////
|
||||
|
||||
// Encoding generated with ./sparse-fsm-encode.py -d 5 -m 8 -n 10
|
||||
// Encoding generated with:
|
||||
// $ ./util/design/sparse-fsm-encode.py -d 5 -m 9 -n 10 \
|
||||
// -s 2599950981 --language=sv
|
||||
//
|
||||
// Hamming distance histogram:
|
||||
//
|
||||
// 0: --
|
||||
// 1: --
|
||||
// 2: --
|
||||
// 3: --
|
||||
// 4: --
|
||||
// 5: |||||||||||||||||||| (53.57%)
|
||||
// 6: ||||||||||||| (35.71%)
|
||||
// 7: | (3.57%)
|
||||
// 8: || (7.14%)
|
||||
// 9: --
|
||||
// 0: --
|
||||
// 1: --
|
||||
// 2: --
|
||||
// 3: --
|
||||
// 4: --
|
||||
// 5: |||||||||||||||||||| (52.78%)
|
||||
// 6: ||||||||||||||| (41.67%)
|
||||
// 7: | (2.78%)
|
||||
// 8: | (2.78%)
|
||||
// 9: --
|
||||
// 10: --
|
||||
//
|
||||
// Minimum Hamming distance: 5
|
||||
// Maximum Hamming distance: 8
|
||||
// Minimum Hamming weight: 3
|
||||
// Maximum Hamming weight: 8
|
||||
//
|
||||
localparam int StateWidth = 10;
|
||||
typedef enum logic [StateWidth-1:0] {
|
||||
ResetSt = 10'b1100000011,
|
||||
InitSt = 10'b1100110100,
|
||||
IdleSt = 10'b1010111010,
|
||||
ReadSt = 10'b0011100000,
|
||||
ReadWaitSt = 10'b1001011111,
|
||||
WriteCheckSt = 10'b0111010101,
|
||||
WriteWaitSt = 10'b0000001100,
|
||||
WriteSt = 10'b0110101111
|
||||
ResetSt = 10'b1100000110,
|
||||
InitSt = 10'b1000110011,
|
||||
IdleSt = 10'b0101110000,
|
||||
ReadSt = 10'b0010011111,
|
||||
ReadWaitSt = 10'b1001001101,
|
||||
WriteCheckSt = 10'b1111101011,
|
||||
WriteWaitSt = 10'b0011000010,
|
||||
WriteSt = 10'b0110100101,
|
||||
ErrorSt = 10'b1110011000
|
||||
} state_e;
|
||||
|
||||
state_e state_d, state_q;
|
||||
|
@ -175,6 +184,7 @@ module prim_generic_otp
|
|||
cnt_clr = 1'b0;
|
||||
cnt_en = 1'b0;
|
||||
read_ecc_on = 1'b1;
|
||||
fsm_err = 1'b0;
|
||||
|
||||
unique case (state_q)
|
||||
// Wait here until we receive an initialization command.
|
||||
|
@ -273,8 +283,13 @@ module prim_generic_otp
|
|||
state_d = IdleSt;
|
||||
end
|
||||
end
|
||||
// If the FSM is glitched into an invalid state.
|
||||
ErrorSt: begin
|
||||
fsm_err = 1'b1;
|
||||
end
|
||||
default: begin
|
||||
state_d = ResetSt;
|
||||
state_d = ErrorSt;
|
||||
fsm_err = 1'b1;
|
||||
end
|
||||
endcase // state_q
|
||||
end
|
||||
|
@ -348,19 +363,7 @@ module prim_generic_otp
|
|||
// Regs //
|
||||
//////////
|
||||
|
||||
// This primitive is used to place a size-only constraint on the
|
||||
// flops in order to prevent FSM state encoding optimizations.
|
||||
logic [StateWidth-1:0] state_raw_q;
|
||||
assign state_q = state_e'(state_raw_q);
|
||||
prim_flop #(
|
||||
.Width(StateWidth),
|
||||
.ResetValue(StateWidth'(ResetSt))
|
||||
) u_state_regs (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.d_i ( state_d ),
|
||||
.q_o ( state_raw_q )
|
||||
);
|
||||
`PRIM_FLOP_SPARSE_FSM(u_state_regs, state_d, state_q, state_e, ResetSt)
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs
|
||||
if (!rst_ni) begin
|
||||
|
|
|
@ -32,6 +32,8 @@ module prim_generic_pad_wrapper
|
|||
// analog pads cannot have a scan role.
|
||||
`ASSERT_INIT(AnalogNoScan_A, PadType != AnalogIn0 || ScanRole == NoScan)
|
||||
|
||||
//VCS coverage off
|
||||
// pragma coverage off
|
||||
// not all signals are used here.
|
||||
logic unused_sigs;
|
||||
assign unused_sigs = ^{attr_i.slew_rate,
|
||||
|
@ -41,13 +43,19 @@ module prim_generic_pad_wrapper
|
|||
attr_i.keep_en,
|
||||
scanmode_i,
|
||||
pok_i};
|
||||
//VCS coverage on
|
||||
// pragma coverage on
|
||||
|
||||
if (PadType == InputStd) begin : gen_input_only
|
||||
//VCS coverage off
|
||||
// pragma coverage off
|
||||
logic unused_in_sigs;
|
||||
assign unused_in_sigs = ^{out_i,
|
||||
oe_i,
|
||||
attr_i.virt_od_en,
|
||||
attr_i.drive_strength};
|
||||
//VCS coverage on
|
||||
// pragma coverage on
|
||||
|
||||
assign in_raw_o = (ie_i) ? inout_io : 1'bz;
|
||||
// input inversion
|
||||
|
@ -84,8 +92,12 @@ module prim_generic_pad_wrapper
|
|||
`endif
|
||||
end else if (PadType == AnalogIn0 || PadType == AnalogIn1) begin : gen_analog
|
||||
|
||||
//VCS coverage off
|
||||
// pragma coverage off
|
||||
logic unused_ana_sigs;
|
||||
assign unused_ana_sigs = ^{attr_i, out_i, oe_i, ie_i};
|
||||
//VCS coverage on
|
||||
// pragma coverage on
|
||||
|
||||
assign inout_io = 1'bz; // explicitly make this tristate to avoid lint errors.
|
||||
assign in_o = inout_io;
|
||||
|
|
2
vendor/lowrisc_ip/lint/doc/index.md
vendored
2
vendor/lowrisc_ip/lint/doc/index.md
vendored
|
@ -16,7 +16,7 @@ The lint flow run scripts and waiver files are available in the GitHub repositor
|
|||
However, the _"lowRISC Lint Rules"_ are available as part of the default policies in AscentLint release 2019.A.p3 or newer (as `LRLR-v1.0.policy`).
|
||||
This enables designers that have access to this tool to run the lint flow provided locally on their premises.
|
||||
|
||||
Our linting flow leverages FuseSoC to resolve dependencies, build file lists and call the linting tools. See [here](https://github.com/olofk/fusesoc) for an introduction to this opensource package manager and [here](https://docs.opentitan.org/doc/ug/install_instructions/) for installation instructions.
|
||||
Our linting flow leverages FuseSoC to resolve dependencies, build file lists and call the linting tools. See [here](https://github.com/olofk/fusesoc) for an introduction to this open source package manager and [here](https://docs.opentitan.org/doc/ug/install_instructions/) for installation instructions.
|
||||
|
||||
In order to run lint on a [comportable IP](https://docs.opentitan.org/doc/rm/comportability_specification/) block, the corresponding FuseSoC core file must have a lint target and include (optional) waiver files as shown in the following example taken from the FuseSoC core of the AES comportable IP:
|
||||
```
|
||||
|
|
|
@ -8,6 +8,7 @@ import os
|
|||
from Launcher import Launcher
|
||||
from LocalLauncher import LocalLauncher
|
||||
from LsfLauncher import LsfLauncher
|
||||
from SgeLauncher import SgeLauncher
|
||||
|
||||
try:
|
||||
from edacloudlauncher.EdaCloudLauncher import EdaCloudLauncher
|
||||
|
@ -41,6 +42,9 @@ def set_launcher_type(is_local=False):
|
|||
elif launcher == "lsf":
|
||||
_LAUNCHER_CLS = LsfLauncher
|
||||
|
||||
elif launcher == "sge":
|
||||
_LAUNCHER_CLS = SgeLauncher
|
||||
|
||||
# These custom launchers are site specific. They may not be committed to
|
||||
# the open source repo.
|
||||
elif launcher == "edacloud" and EDACLOUD_LAUNCHER_EXISTS:
|
||||
|
|
349
vendor/lowrisc_ip/util/dvsim/SGE.py
vendored
Executable file
349
vendor/lowrisc_ip/util/dvsim/SGE.py
vendored
Executable file
|
@ -0,0 +1,349 @@
|
|||
# Copyright lowRISC contributors.
|
||||
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# ----------------------------------
|
||||
# SGE.py
|
||||
# _JobData Class
|
||||
# ----------------------------------
|
||||
import logging
|
||||
import pwd
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import time
|
||||
|
||||
#
|
||||
from qsubopts import qsubOptions
|
||||
sgeJob_t = qsubOptions()
|
||||
|
||||
|
||||
class _JobData:
|
||||
"""
|
||||
Internal helper class to manage job data from qstat
|
||||
"""
|
||||
def __init__(self, qstat_job_line):
|
||||
# The format of the line goes like
|
||||
# job-ID prior name user state submit/start at queue slots ja-task-ID
|
||||
|
||||
tokens = qstat_job_line.split()
|
||||
|
||||
assert len(tokens) >= 8, 'Not a valid qstat line: ' + qstat_job_line
|
||||
# Job line must have at least 8 tokens
|
||||
try:
|
||||
self.id = int(tokens[0])
|
||||
except ValueError:
|
||||
error_msg = "Could not convert data to an integer."
|
||||
raise ValueError(error_msg)
|
||||
self.priority = float(tokens[1])
|
||||
self.name = tokens[2]
|
||||
self.user = tokens[3]
|
||||
self.state = tokens[4]
|
||||
self.time = ' '.join(tokens[5:7])
|
||||
|
||||
if '@' in qstat_job_line:
|
||||
# Has queue assigned, e.g. core2.q@q2.caspian.mit.edu
|
||||
self.queue = tokens[7]
|
||||
self.slots = tokens[8]
|
||||
if len(tokens) == 9:
|
||||
self.ja_task_id = None
|
||||
elif len(tokens) == 10:
|
||||
self.ja_task_id = tokens[-1]
|
||||
else:
|
||||
raise ValueError(f"Could not parse line: {qstat_job_line}")
|
||||
else:
|
||||
# No queue assigned
|
||||
self.slots = tokens[7]
|
||||
if len(tokens) == 8:
|
||||
self.ja_task_id = None
|
||||
elif len(tokens) == 9:
|
||||
self.ja_task_id = tokens[-1]
|
||||
else:
|
||||
raise ValueError(f"Could not parse line: {qstat_job_line}")
|
||||
|
||||
# Convert array indices ja_task_id into python list format
|
||||
ja_task_id = []
|
||||
if self.ja_task_id is not None:
|
||||
for blob in self.ja_task_id.split(','):
|
||||
# Parse data of form '193-349:1' or '1934'
|
||||
x = blob.split(':')
|
||||
if len(x) == 1:
|
||||
ja_task_id += x
|
||||
else:
|
||||
subjobs, step = x
|
||||
begin, end = subjobs.split('-')
|
||||
ja_task_id += range(int(begin), int(end) + 1, int(step))
|
||||
|
||||
self._ja_tasklist = ja_task_id
|
||||
|
||||
def __repr__(self):
|
||||
repr = ['{']
|
||||
for key, value in self.__dict__.items():
|
||||
if key[0] != '_':
|
||||
repr.append(key + '=' + str(value))
|
||||
repr.append('}')
|
||||
return '\n'.join(repr)
|
||||
|
||||
|
||||
class JobList:
|
||||
"""
|
||||
Internal helper class to manage job lists
|
||||
"""
|
||||
|
||||
def __init__(self, qstat_output=None):
|
||||
self._joblist = []
|
||||
for line in qstat_output.split('\n')[2:-1]:
|
||||
self._joblist.append(_JobData(line))
|
||||
|
||||
def __iter__(self):
|
||||
for job in self._joblist:
|
||||
yield job
|
||||
|
||||
def __repr__(self):
|
||||
return '\n'.join([str(job) for job in self._joblist])
|
||||
|
||||
|
||||
class SGE:
|
||||
"""External system call handler for Sun Grid Engine environment."""
|
||||
|
||||
def __init__(self, q=None, path='', ):
|
||||
|
||||
logger = logging.getLogger('SGE.__init__')
|
||||
|
||||
if q is None:
|
||||
# No queue specified. By default, submit to all available queues.
|
||||
self.cmd_qconf = os.path.join(path, 'qconf')
|
||||
|
||||
try:
|
||||
qliststr = _exec(self.cmd_qconf + ' -sql')
|
||||
except IOError:
|
||||
error_msg = 'Error querying queue configuration'
|
||||
logger.error(error_msg)
|
||||
raise IOError(error_msg)
|
||||
|
||||
self.q = qliststr.replace('\n', ',')[:-1]
|
||||
|
||||
logger.info("""Sun Grid Engine handler initialized
|
||||
Queues detected: %s""", self.q)
|
||||
|
||||
else:
|
||||
self.q = q
|
||||
|
||||
self.cmd_qsub = os.path.join(path, 'qsub')
|
||||
self.cmd_qstat = os.path.join(path, 'qstat')
|
||||
|
||||
def wait(self, jobid, interval=10, name=None, pbar=None,
|
||||
pbar_mode=None):
|
||||
"""Waits for job running on SGE Grid Engine environment to finish.
|
||||
|
||||
If you are just waiting for one job, this becomes a dumb substitute for
|
||||
the -sync y option which can be specified to qsub.
|
||||
|
||||
Inputs:
|
||||
|
||||
jobid
|
||||
interval - Polling interval of SGE queue, in seconds. (Default: 10)
|
||||
"""
|
||||
|
||||
logger = logging.getLogger('SGE.wait')
|
||||
|
||||
dowait = True
|
||||
while dowait:
|
||||
p = subprocess.Popen(self.cmd_qstat, shell=True,
|
||||
stdout=subprocess.PIPE)
|
||||
pout, _ = p.communicate()
|
||||
|
||||
if pbar is not None:
|
||||
logger.error('Progress bar handling not implemented')
|
||||
|
||||
dowait = False
|
||||
for line in pout.split('\n'):
|
||||
t = line.split()
|
||||
if len(t) >= 5 and t[0] == str(jobid):
|
||||
# Find a line with useful info
|
||||
if re.search(t[4], 'qwrt'):
|
||||
# Job must be queued, running or being transferred
|
||||
dowait = True
|
||||
break
|
||||
if re.search(t[4], 'acuE'):
|
||||
# Job or host in error state
|
||||
logger.warning('Job %d in error state', str(jobid))
|
||||
|
||||
if dowait:
|
||||
time.sleep(interval)
|
||||
if name is None:
|
||||
logger.info("Time %s: waiting for jobid %s to finish",
|
||||
time.ctime(), str(jobid))
|
||||
else:
|
||||
logger.info("Time %s: waiting for job '%s' (jobid %s) to \
|
||||
finish", time.ctime(), name, str(jobid))
|
||||
|
||||
def submit(self, job, array=False, useenvironment=True, usecwd=True,
|
||||
name=None, stdin=None, stdout=None, stderr=None,
|
||||
joinstdouterr=True, nproc=1, wait=True, lammpi=True):
|
||||
"""
|
||||
Submits a job to SGE
|
||||
Returns jobid as a number
|
||||
"""
|
||||
|
||||
logger = logging.getLogger('SGE.submit')
|
||||
|
||||
logger.info("Submitting job: " + str(job) + " stdout: %s \
|
||||
Stderr: %s", stdout, stderr)
|
||||
|
||||
# Parameters to qsub specified as the header of the job specified on
|
||||
# STDIN
|
||||
lamstring = lammpi and f" -pe lammpi {nproc}" or ""
|
||||
qsuboptslist = ['-cwd -V ', lamstring]
|
||||
|
||||
if name is not None:
|
||||
qsuboptslist.append('-N ' + name)
|
||||
if stdin is not None:
|
||||
qsuboptslist.append('-i ' + stdin)
|
||||
if stdout is not None:
|
||||
qsuboptslist.append('-o ' + stdout)
|
||||
if stderr is not None:
|
||||
qsuboptslist.append('-e ' + stderr)
|
||||
if joinstdouterr:
|
||||
qsuboptslist.append('-j')
|
||||
if wait:
|
||||
qsuboptslist.append('-sync y')
|
||||
if usecwd:
|
||||
qsuboptslist.append('-cwd')
|
||||
if useenvironment:
|
||||
qsuboptslist.append('-V')
|
||||
if array is not False:
|
||||
try:
|
||||
n = int(array[0])
|
||||
except IndexError:
|
||||
n = int(array)
|
||||
raise IndexError("List is empty!")
|
||||
except ValueError:
|
||||
error_msg = "array[0] being an out of bounds access."
|
||||
logger.error(error_msg)
|
||||
raise ValueError(error_msg)
|
||||
try:
|
||||
m = int(array[1])
|
||||
except ValueError:
|
||||
m = None
|
||||
raise ValueError("Could not convert data to an integer.")
|
||||
except IndexError:
|
||||
m = None
|
||||
raise IndexError("array[1] being an out of bounds access.")
|
||||
try:
|
||||
s = int(array[2])
|
||||
except IndexError:
|
||||
s = None
|
||||
raise IndexError("array[2] being an out of bounds access.")
|
||||
except ValueError:
|
||||
s = None
|
||||
raise ValueError("Could not convert data to an integer.")
|
||||
if m == s is None:
|
||||
qsuboptslist.append('-t %d' % n)
|
||||
elif s is None:
|
||||
qsuboptslist.append('-t %d-%d' % (n, m))
|
||||
else:
|
||||
qsuboptslist.append('-t %d-%d:%d' % (n, m, s))
|
||||
|
||||
qsubopts = ' '.join(qsuboptslist)
|
||||
|
||||
pout = _exec(self.cmd_qsub, stdin=qsubopts + '\n' + job,
|
||||
print_command=False)
|
||||
|
||||
try:
|
||||
# Next to last line should be
|
||||
# "Your job 1389 (name) has been submitted"
|
||||
# parse for job id
|
||||
jobid = int(pout.split('\n')[-2].split()[2])
|
||||
return jobid
|
||||
# except (ValueErrorValueError, IndexError, AttributeError) (e):
|
||||
except (ValueError, IndexError, AttributeError):
|
||||
error_msg = """Error submitting SGE job:
|
||||
%s
|
||||
%s
|
||||
|
||||
Output was:
|
||||
%s""" % (qsubopts, job, pout)
|
||||
logger.error(error_msg)
|
||||
raise IOError(error_msg)
|
||||
|
||||
def getuserjobs(self, user=pwd.getpwuid(os.getuid())[0]):
|
||||
"""Returns a list of SGE jobids run by a specific user
|
||||
|
||||
Inputs
|
||||
user - SGE user to poll (Default = '', i.e. current user)
|
||||
qstat - path to qstat binary (Default = 'qstat')
|
||||
"""
|
||||
|
||||
p = subprocess.Popen(self.cmd_qstat + " -u " + user, shell=True,
|
||||
stdout=subprocess.PIPE)
|
||||
qstat_output, _ = p.communicate()
|
||||
joblist = JobList(qstat_output)
|
||||
return [job for job in joblist if job.user == user]
|
||||
|
||||
def run_job(self, command, name='default', logfnm='default.log',
|
||||
wait=True):
|
||||
"""Run job on SGE with piped logging."""
|
||||
jobid = self.submit(command, name=name, stdout=logfnm,
|
||||
stderr=logfnm, wait=wait)
|
||||
return jobid
|
||||
|
||||
def get_queue_instance_status(self):
|
||||
"""
|
||||
Get loads for each queue instance
|
||||
"""
|
||||
output = _exec(' '.join([self.cmd_qstat, '-f']))
|
||||
|
||||
data = []
|
||||
for line in output.split('\n')[1:]:
|
||||
t = line.split()
|
||||
if len(t) != 5:
|
||||
continue
|
||||
|
||||
nodename = t[0].split('@')[1].split('.')[0]
|
||||
maxslots = int(t[2].split('/')[2])
|
||||
load = float(t[3])
|
||||
|
||||
data.append({'name': nodename, 'maxslots': maxslots, 'load': load})
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def _exec(command, print_to_screen=False, logfnm=None, stdin='',
|
||||
print_command=False):
|
||||
"""
|
||||
Runs command line using subprocess, optionally returning stdout
|
||||
"""
|
||||
def _call_cmd(command, stdin=''):
|
||||
p = subprocess.Popen(command, shell=True, stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT)
|
||||
output, _ = p.communicate(stdin)
|
||||
return output
|
||||
|
||||
logger = logging.getLogger('_exec')
|
||||
|
||||
if print_command:
|
||||
logger.info("Executing process: \x1b[1;92m%-50s\x1b[0m Logfile: %s",
|
||||
command, logfnm)
|
||||
|
||||
output = ""
|
||||
if logfnm is not None:
|
||||
try:
|
||||
with open(logfnm, 'a') as f:
|
||||
if print_command:
|
||||
print(f, "Executing process: %s" % command)
|
||||
output = _call_cmd(command, stdin)
|
||||
f.write(output)
|
||||
except IOError:
|
||||
error_msg = 'Error: File: ' + str(logfnm) + ' does not appear to exist.'
|
||||
logger.error(error_msg)
|
||||
raise IOError(error_msg)
|
||||
else:
|
||||
output = _call_cmd(command, stdin)
|
||||
|
||||
logger.info('Output of command is:\n%s', output)
|
||||
|
||||
if print_to_screen:
|
||||
print(output)
|
||||
|
||||
return output
|
24
vendor/lowrisc_ip/util/dvsim/Scheduler.py
vendored
24
vendor/lowrisc_ip/util/dvsim/Scheduler.py
vendored
|
@ -4,7 +4,7 @@
|
|||
|
||||
import logging as log
|
||||
import threading
|
||||
from signal import SIGINT, signal
|
||||
from signal import SIGINT, SIGTERM, signal
|
||||
|
||||
from Launcher import LauncherError
|
||||
from StatusPrinter import get_status_printer
|
||||
|
@ -130,18 +130,24 @@ class Scheduler:
|
|||
stop_now = threading.Event()
|
||||
old_handler = None
|
||||
|
||||
def on_sigint(signal_received, frame):
|
||||
log.info('Received SIGINT. Exiting gracefully. '
|
||||
'Send another to force immediate quit '
|
||||
'(but you may need to manually kill child processes)')
|
||||
def on_signal(signal_received, frame):
|
||||
log.info("Received signal %s. Exiting gracefully.",
|
||||
signal_received)
|
||||
|
||||
# Restore old handler to catch any second signal
|
||||
assert old_handler is not None
|
||||
signal(SIGINT, old_handler)
|
||||
if signal_received == SIGINT:
|
||||
log.info('Send another to force immediate quit (but you may '
|
||||
'need to manually kill child processes)')
|
||||
|
||||
# Restore old handler to catch a second SIGINT
|
||||
assert old_handler is not None
|
||||
signal(signal_received, old_handler)
|
||||
|
||||
stop_now.set()
|
||||
|
||||
old_handler = signal(SIGINT, on_sigint)
|
||||
old_handler = signal(SIGINT, on_signal)
|
||||
|
||||
# Install the SIGTERM handler before scheduling jobs.
|
||||
signal(SIGTERM, on_signal)
|
||||
|
||||
# Enqueue all items of the first target.
|
||||
self._enqueue_successors(None)
|
||||
|
|
182
vendor/lowrisc_ip/util/dvsim/SgeLauncher.py
vendored
Executable file
182
vendor/lowrisc_ip/util/dvsim/SgeLauncher.py
vendored
Executable file
|
@ -0,0 +1,182 @@
|
|||
# Copyright lowRISC contributors.
|
||||
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# ------------------------------------
|
||||
# SgeLauncher Class
|
||||
#
|
||||
# ------------------------------------
|
||||
import os
|
||||
import shlex
|
||||
import subprocess
|
||||
from subprocess import PIPE, Popen
|
||||
|
||||
import SGE
|
||||
from Launcher import ErrorMessage, Launcher, LauncherError
|
||||
|
||||
global job_name
|
||||
|
||||
pid = os.getpid()
|
||||
|
||||
|
||||
class SgeLauncher(Launcher):
|
||||
"""
|
||||
Implementation of Launcher to launch jobs in the user's local workstation.
|
||||
"""
|
||||
|
||||
# Misc common SgeLauncher settings.
|
||||
max_odirs = 5
|
||||
|
||||
def __init__(self, deploy):
|
||||
'''Initialize common class members.'''
|
||||
|
||||
super().__init__(deploy)
|
||||
|
||||
# Popen object when launching the job.
|
||||
self.process = None
|
||||
|
||||
def _do_launch(self):
|
||||
global job_name
|
||||
# Update the shell's env vars with self.exports. Values in exports must
|
||||
# replace the values in the shell's env vars if the keys match.
|
||||
exports = os.environ.copy()
|
||||
if self.deploy.exports:
|
||||
exports.update(self.deploy.exports)
|
||||
|
||||
# Clear the magic MAKEFLAGS variable from exports if necessary. This
|
||||
# variable is used by recursive Make calls to pass variables from one
|
||||
# level to the next. Here, self.cmd is a call to Make but it's
|
||||
# logically a top-level invocation: we don't want to pollute the flow's
|
||||
# Makefile with Make variables from any wrapper that called dvsim.
|
||||
if 'MAKEFLAGS' in exports:
|
||||
del exports['MAKEFLAGS']
|
||||
|
||||
self._dump_env_vars(exports)
|
||||
|
||||
try:
|
||||
f = open(self.deploy.get_log_path(),
|
||||
"w",
|
||||
encoding="UTF-8",
|
||||
errors="surrogateescape")
|
||||
f.write("[Executing]:\n{}\n\n".format(self.deploy.cmd))
|
||||
f.flush()
|
||||
# ---------- prepare SGE job struct -----
|
||||
sgeJob = SGE.qsubOptions()
|
||||
sgeJob.args.N = 'VCS_RUN_' + str(pid) # Name of Grid Engine job
|
||||
if "build.log" in self.deploy.get_log_path():
|
||||
sgeJob.args.N = 'VCS_BUILD_' + str(
|
||||
pid) # Name of Grid Engine job
|
||||
|
||||
job_name = sgeJob.args.N
|
||||
sgeJob.args.t = '0' # Define an array job with 20 subjobs
|
||||
sgeJob.args.slot = '1' # Define num of slot
|
||||
sgeJob.args.sync = 'y' # wait for job to complete before exiting
|
||||
sgeJob.args.q = 'vcs_q' # Define the sge queue name
|
||||
sgeJob.args.p = '0' # Set priority to 0
|
||||
sgeJob.args.ll = 'mf=20G' # memory req,request the given resources
|
||||
# pecifies a range of priorities from -1023 to 1024.
|
||||
# The higher the number, the higher the priority.
|
||||
# The default priority for jobs is zero
|
||||
sgeJob.args.command = '"' + self.deploy.cmd + '"'
|
||||
sgeJob.args.b = 'y' # This is a binary file
|
||||
sgeJob.args.o = self.deploy.get_log_path() + '.sge'
|
||||
cmd = str(sgeJob.execute(mode='echo'))
|
||||
# ---------------
|
||||
self.process = subprocess.Popen(shlex.split(cmd),
|
||||
bufsize=4096,
|
||||
universal_newlines=True,
|
||||
stdout=f,
|
||||
stderr=f,
|
||||
env=exports)
|
||||
f.close()
|
||||
except subprocess.SubprocessError as e:
|
||||
raise LauncherError('IO Error: {}\nSee {}'.format(
|
||||
e, self.deploy.get_log_path()))
|
||||
finally:
|
||||
self._close_process()
|
||||
|
||||
self._link_odir("D")
|
||||
f.close()
|
||||
|
||||
def poll(self):
|
||||
'''Check status of the running process
|
||||
|
||||
This returns 'D', 'P' or 'F'. If 'D', the job is still running. If 'P',
|
||||
the job finished successfully. If 'F', the job finished with an error.
|
||||
|
||||
This function must only be called after running self.dispatch_cmd() and
|
||||
must not be called again once it has returned 'P' or 'F'.
|
||||
'''
|
||||
|
||||
assert self.process is not None
|
||||
if self.process.poll() is None:
|
||||
return 'D'
|
||||
# -------------------------------------
|
||||
# copy SGE jobb results to log file
|
||||
if os.path.exists(self.deploy.get_log_path() + '.sge'):
|
||||
|
||||
file1 = open(self.deploy.get_log_path() + '.sge', 'r')
|
||||
Lines = file1.readlines()
|
||||
file1.close()
|
||||
f = open(self.deploy.get_log_path(),
|
||||
"a",
|
||||
encoding="UTF-8",
|
||||
errors="surrogateescape")
|
||||
for line in Lines:
|
||||
f.write(line)
|
||||
f.flush()
|
||||
os.remove(self.deploy.get_log_path() + '.sge')
|
||||
f.close()
|
||||
# -------------------------------------
|
||||
|
||||
self.exit_code = self.process.returncode
|
||||
status, err_msg = self._check_status()
|
||||
self._post_finish(status, err_msg)
|
||||
return status
|
||||
|
||||
def kill(self):
|
||||
global job_name
|
||||
'''Kill the running process.
|
||||
|
||||
This must be called between dispatching and reaping the process (the
|
||||
same window as poll()).
|
||||
|
||||
'''
|
||||
assert self.process is not None
|
||||
|
||||
# Try to kill the running process. Send SIGTERM first, wait a bit,
|
||||
# and then send SIGKILL if it didn't work.
|
||||
self.process.terminate()
|
||||
try:
|
||||
self.process.wait(timeout=2)
|
||||
except subprocess.TimeoutExpired:
|
||||
self.process.kill()
|
||||
# ----------------------------
|
||||
# qdel -f kill sge job_name
|
||||
cmd = 'qstatus -a | grep ' + job_name
|
||||
with Popen(cmd, stdout=PIPE, stderr=None, shell=True) as process:
|
||||
output = process.communicate()[0].decode("utf-8")
|
||||
output = output.rstrip("\n")
|
||||
if output != '':
|
||||
output_l = output.split()
|
||||
cmd = 'qdel ' + output_l[0]
|
||||
with Popen(cmd, stdout=PIPE, stderr=None,
|
||||
shell=True) as process:
|
||||
output = process.communicate()[0].decode("utf-8")
|
||||
output = output.rstrip("\n")
|
||||
print('Killed job "' + str(output) + '"')
|
||||
# ----------------------------
|
||||
self._post_finish(
|
||||
'K',
|
||||
ErrorMessage(line_number=None, message='Job killed!', context=[]))
|
||||
|
||||
def _post_finish(self, status, err_msg):
|
||||
super()._post_finish(status, err_msg)
|
||||
self._close_process()
|
||||
self.process = None
|
||||
|
||||
def _close_process(self):
|
||||
'''Close the file descriptors associated with the process.'''
|
||||
|
||||
assert self.process
|
||||
if self.process.stdout:
|
||||
self.process.stdout.close()
|
41
vendor/lowrisc_ip/util/dvsim/SimCfg.py
vendored
41
vendor/lowrisc_ip/util/dvsim/SimCfg.py
vendored
|
@ -9,7 +9,6 @@ import collections
|
|||
import fnmatch
|
||||
import logging as log
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
from collections import OrderedDict
|
||||
|
@ -28,26 +27,6 @@ _MAX_UNIQUE_TESTS = 5
|
|||
_MAX_TEST_RESEEDS = 2
|
||||
|
||||
|
||||
def pick_wave_format(fmts):
|
||||
'''Pick a supported wave format from a list.
|
||||
|
||||
fmts is a list of formats that the chosen tool supports. Return the first
|
||||
that we think is possible (e.g. not fsdb if Verdi is not installed).
|
||||
|
||||
'''
|
||||
assert fmts
|
||||
fmt = fmts[0]
|
||||
# TODO: This will not work if the EDA tools are expected to be launched
|
||||
# in a separate sandboxed environment such as Docker / LSF. In such case,
|
||||
# Verdi may be installed in that environment, but it may not be visible in
|
||||
# the current repo environment where dvsim is invoked.
|
||||
if fmt == 'fsdb' and not shutil.which('verdi'):
|
||||
log.log(VERBOSE, "Skipping fsdb since verdi is not found in $PATH")
|
||||
return pick_wave_format(fmts[1:])
|
||||
|
||||
return fmt
|
||||
|
||||
|
||||
class SimCfg(FlowCfg):
|
||||
"""Simulation configuration object
|
||||
|
||||
|
@ -225,27 +204,13 @@ class SimCfg(FlowCfg):
|
|||
since it is used as a substitution variable in the parsed HJson dict.
|
||||
If waves are not enabled, or if this is a primary cfg, then return
|
||||
'none'. 'tool', which must be set at this point, supports a limited
|
||||
list of wave formats (supplied with 'supported_wave_formats' key). If
|
||||
waves is set to 'default', then pick the first item on that list; else
|
||||
pick the desired format.
|
||||
list of wave formats (supplied with 'supported_wave_formats' key).
|
||||
'''
|
||||
if self.waves == 'none' or self.is_primary_cfg:
|
||||
return 'none'
|
||||
|
||||
assert self.tool is not None
|
||||
|
||||
# If the user hasn't specified a wave format (No argument supplied
|
||||
# to --waves), we need to decide on a format for them. The supported
|
||||
# list of wave formats is set in the tool's HJson configuration using
|
||||
# the `supported_wave_formats` key. If that list is not set, we use
|
||||
# 'vpd' by default and hope for the best. It that list if set, then we
|
||||
# pick the first available format for which the waveform viewer exists.
|
||||
if self.waves == 'default':
|
||||
if self.supported_wave_formats:
|
||||
return pick_wave_format(self.supported_wave_formats)
|
||||
else:
|
||||
return 'vpd'
|
||||
|
||||
# If the user has specified their preferred wave format, use it. As
|
||||
# a sanity check, error out if the chosen tool doesn't support the
|
||||
# format, but only if we know about the tool. If not, we'll just assume
|
||||
|
@ -722,8 +687,8 @@ class SimCfg(FlowCfg):
|
|||
# convert name entry to relative link
|
||||
row = cfg.results_summary
|
||||
row["Name"] = cfg._get_results_page_link(
|
||||
self.results_dir,
|
||||
row["Name"])
|
||||
self.results_dir,
|
||||
row["Name"])
|
||||
|
||||
# If header is set, ensure its the same for all cfgs.
|
||||
if header:
|
||||
|
|
|
@ -6,7 +6,7 @@ title: "Testplanner tool"
|
|||
* Expanding the testplan inline within the DV document as a table;
|
||||
* Annotating the simulation results with testplan entries for a document driven DV execution;
|
||||
|
||||
Please see [DV methodology]({{< relref "doc/ug/dv_methodology/index.md#documentation" >}}) for more details on the rationale and motivation for writing and maintaining testplans in a machine-parsable format (`Hjson`).
|
||||
Please see [DV methodology]({{< relref "doc/ug/dv_methodology/index.md#documentation" >}}) for more details on the rationale and motivation for writing and maintaining testplans in a machine-parseable format (`Hjson`).
|
||||
This document will focus on the anatomy of an Hjson testplan, the list of features supported and some of the ways of using the tool.
|
||||
|
||||
## Hjson testplan
|
||||
|
@ -43,7 +43,7 @@ The following attributes are used to define each testpoint, at minimum:
|
|||
* **tests: list of written test(s) for this testpoint**
|
||||
|
||||
The testplan is written in the initial work stage of the verification [life-cycle]({{< relref "doc/project/development_stages#hardware-verification-stages" >}}).
|
||||
Later, when the DV engineer writes the tests, they may not map one-to-one to a testpoint - it may be possible that a written test satisfactorilly addresses multiple testpoints; OR it may also be possible that a testpoint needs to be split into multiple smaller tests.
|
||||
Later, when the DV engineer writes the tests, they may not map one-to-one to a testpoint - it may be possible that a written test satisfactorily addresses multiple testpoints; OR it may also be possible that a testpoint needs to be split into multiple smaller tests.
|
||||
To cater to these needs, we provide the ability to set a list of written tests for each testpoint.
|
||||
It is used to not only indicate the current progress so far into each verification stage, but also map the simulation results to the testpoints to generate the final report table.
|
||||
This list is initially empty - it is gradually updated as tests are written.
|
||||
|
|
12
vendor/lowrisc_ip/util/dvsim/dvsim.py
vendored
12
vendor/lowrisc_ip/util/dvsim/dvsim.py
vendored
|
@ -33,6 +33,7 @@ from pathlib import Path
|
|||
import Launcher
|
||||
import LauncherFactory
|
||||
import LocalLauncher
|
||||
import SgeLauncher
|
||||
from CfgFactory import make_cfg
|
||||
from Deploy import RunTest
|
||||
from Timer import Timer
|
||||
|
@ -542,13 +543,9 @@ def parse_args():
|
|||
waveg.add_argument(
|
||||
"--waves",
|
||||
"-w",
|
||||
nargs="?",
|
||||
choices=["default", "fsdb", "shm", "vpd", "vcd", "evcd", "fst"],
|
||||
const="default",
|
||||
help=("Enable dumping of waves. It takes an optional "
|
||||
"argument to pick the desired wave format. If "
|
||||
"the optional argument is not supplied, it picks "
|
||||
"whatever is the default for the chosen tool. "
|
||||
choices=["fsdb", "shm", "vpd", "vcd", "evcd", "fst"],
|
||||
help=("Enable dumping of waves. It takes an "
|
||||
"argument to pick the desired wave format."
|
||||
"By default, dumping waves is not enabled."))
|
||||
|
||||
waveg.add_argument("--max-waves",
|
||||
|
@ -692,6 +689,7 @@ def main():
|
|||
# Register the common deploy settings.
|
||||
Timer.print_interval = args.print_interval
|
||||
LocalLauncher.LocalLauncher.max_parallel = args.max_parallel
|
||||
SgeLauncher.SgeLauncher.max_parallel = args.max_parallel
|
||||
Launcher.Launcher.max_odirs = args.max_odirs
|
||||
LauncherFactory.set_launcher_type(args.local)
|
||||
|
||||
|
|
1849
vendor/lowrisc_ip/util/dvsim/qsubopts.py
vendored
Executable file
1849
vendor/lowrisc_ip/util/dvsim/qsubopts.py
vendored
Executable file
File diff suppressed because it is too large
Load diff
2
vendor/lowrisc_ip/util/uvmdvgen/doc/index.md
vendored
2
vendor/lowrisc_ip/util/uvmdvgen/doc/index.md
vendored
|
@ -239,7 +239,7 @@ provided by `-hi` and `-ha` respectively. By default, these are set to 'False'
|
|||
* `env/i2c_host_env`
|
||||
|
||||
This is the env class that creates the downstream agents passed via `-ea`
|
||||
switch. It sets their correspodnding cfg objects (which are members of env cfg
|
||||
switch. It sets their corresponding cfg objects (which are members of env cfg
|
||||
object) into the `uvm_config_db`. It also makes the analysis port connections
|
||||
in the `connect_phase` and sets the sequencer handles in the virtual
|
||||
sequencer.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue