diff --git a/vendor/lowrisc_ip.lock.hjson b/vendor/lowrisc_ip.lock.hjson index ec89b5b4..a644cca0 100644 --- a/vendor/lowrisc_ip.lock.hjson +++ b/vendor/lowrisc_ip.lock.hjson @@ -9,6 +9,6 @@ upstream: { url: https://github.com/lowRISC/opentitan - rev: d1be61ba88a145e882df4e7c7a47f78bcf2371f8 + rev: affb06d8de0973bfdc271a6aa4b5ed7dc0b575bb } } diff --git a/vendor/lowrisc_ip/dv/sv/common_ifs/clk_rst_if.sv b/vendor/lowrisc_ip/dv/sv/common_ifs/clk_rst_if.sv index 88a942b0..e9ef603b 100644 --- a/vendor/lowrisc_ip/dv/sv/common_ifs/clk_rst_if.sv +++ b/vendor/lowrisc_ip/dv/sv/common_ifs/clk_rst_if.sv @@ -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 diff --git a/vendor/lowrisc_ip/dv/sv/common_ifs/common_ifs.core b/vendor/lowrisc_ip/dv/sv/common_ifs/common_ifs.core index 31ca6932..369a0d3f 100644 --- a/vendor/lowrisc_ip/dv/sv/common_ifs/common_ifs.core +++ b/vendor/lowrisc_ip/dv/sv/common_ifs/common_ifs.core @@ -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 diff --git a/vendor/lowrisc_ip/dv/sv/common_ifs/index.md b/vendor/lowrisc_ip/dv/sv/common_ifs/index.md index 6e2e99a9..fff99514 100644 --- a/vendor/lowrisc_ip/dv/sv/common_ifs/index.md +++ b/vendor/lowrisc_ip/dv/sv/common_ifs/index.md @@ -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 diff --git a/vendor/lowrisc_ip/dv/sv/common_ifs/pins_if.sv b/vendor/lowrisc_ip/dv/sv/common_ifs/pins_if.sv index b387b202..23168809 100644 --- a/vendor/lowrisc_ip/dv/sv/common_ifs/pins_if.sv +++ b/vendor/lowrisc_ip/dv/sv/common_ifs/pins_if.sv @@ -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. diff --git a/vendor/lowrisc_ip/dv/sv/csr_utils/csr_utils_pkg.sv b/vendor/lowrisc_ip/dv/sv/csr_utils/csr_utils_pkg.sv index 1037d98c..8650c2d3 100644 --- a/vendor/lowrisc_ip/dv/sv/csr_utils/csr_utils_pkg.sv +++ b/vendor/lowrisc_ip/dv/sv/csr_utils/csr_utils_pkg.sv @@ -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; diff --git a/vendor/lowrisc_ip/dv/sv/csr_utils/doc/index.md b/vendor/lowrisc_ip/dv/sv/csr_utils/doc/index.md index 948a21d3..17ce59f4 100644 --- a/vendor/lowrisc_ip/dv/sv/csr_utils/doc/index.md +++ b/vendor/lowrisc_ip/dv/sv/csr_utils/doc/index.md @@ -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. diff --git a/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_reg.core b/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_reg.core index 39a147b1..d961118c 100644 --- a/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_reg.core +++ b/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_reg.core @@ -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 diff --git a/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_reg.sv b/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_reg.sv index 24864df2..4ce61fa3 100644 --- a/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_reg.sv +++ b/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_reg.sv @@ -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 diff --git a/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_reg_block.sv b/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_reg_block.sv index 7adc55bc..969ed278 100644 --- a/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_reg_block.sv +++ b/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_reg_block.sv @@ -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 diff --git a/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_reg_field.sv b/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_reg_field.sv index 8b401a6f..ea23467f 100644 --- a/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_reg_field.sv +++ b/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_reg_field.sv @@ -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 diff --git a/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_reg_pkg.sv b/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_reg_pkg.sv index cfe03e39..261cf776 100644 --- a/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_reg_pkg.sv +++ b/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_reg_pkg.sv @@ -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" diff --git a/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_shadowed_field_cov.sv b/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_shadowed_field_cov.sv new file mode 100644 index 00000000..e1dc3c67 --- /dev/null +++ b/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_shadowed_field_cov.sv @@ -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 diff --git a/vendor/lowrisc_ip/dv/sv/dv_utils/dv_macros.svh b/vendor/lowrisc_ip/dv/sv/dv_utils/dv_macros.svh index 6794f0ce..c35dea6a 100644 --- a/vendor/lowrisc_ip/dv/sv/dv_utils/dv_macros.svh +++ b/vendor/lowrisc_ip/dv/sv/dv_utils/dv_macros.svh @@ -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__ +// +// 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 diff --git a/vendor/lowrisc_ip/dv/sv/dv_utils/dv_test_status.core b/vendor/lowrisc_ip/dv/sv/dv_utils/dv_test_status.core index bbec1b05..e11cfd4b 100644 --- a/vendor/lowrisc_ip/dv/sv/dv_utils/dv_test_status.core +++ b/vendor/lowrisc_ip/dv/sv/dv_utils/dv_test_status.core @@ -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 diff --git a/vendor/lowrisc_ip/dv/sv/dv_utils/dv_test_status_pkg.sv b/vendor/lowrisc_ip/dv/sv/dv_utils/dv_test_status_pkg.sv index 3a81ddfc..2b6d979a 100644 --- a/vendor/lowrisc_ip/dv/sv/dv_utils/dv_test_status_pkg.sv +++ b/vendor/lowrisc_ip/dv/sv/dv_utils/dv_test_status_pkg.sv @@ -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(" _____ _ _ _ "); diff --git a/vendor/lowrisc_ip/dv/sv/dv_utils/dv_utils_pkg.sv b/vendor/lowrisc_ip/dv/sv/dv_utils/dv_utils_pkg.sv index 62f3b765..50f84028 100644 --- a/vendor/lowrisc_ip/dv/sv/dv_utils/dv_utils_pkg.sv +++ b/vendor/lowrisc_ip/dv/sv/dv_utils/dv_utils_pkg.sv @@ -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] diff --git a/vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util__otp.sv b/vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util__otp.sv index 9f1aeb64..aeb67ae4 100644 --- a/vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util__otp.sv +++ b/vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util__otp.sv @@ -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 diff --git a/vendor/lowrisc_ip/dv/sv/mem_model/doc/index.md b/vendor/lowrisc_ip/dv/sv/mem_model/doc/index.md index 6851bead..59c1055f 100644 --- a/vendor/lowrisc_ip/dv/sv/mem_model/doc/index.md +++ b/vendor/lowrisc_ip/dv/sv/mem_model/doc/index.md @@ -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. diff --git a/vendor/lowrisc_ip/dv/tools/dvsim/sim.mk b/vendor/lowrisc_ip/dv/tools/dvsim/sim.mk index 25da4901..3d5889f0 100644 --- a/vendor/lowrisc_ip/dv/tools/dvsim/sim.mk +++ b/vendor/lowrisc_ip/dv/tools/dvsim/sim.mk @@ -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 \ diff --git a/vendor/lowrisc_ip/dv/tools/dvsim/testplans/shadow_reg_errors_testplan.hjson b/vendor/lowrisc_ip/dv/tools/dvsim/testplans/shadow_reg_errors_testplan.hjson index 7b7aee9f..6cc64557 100644 --- a/vendor/lowrisc_ip/dv/tools/dvsim/testplans/shadow_reg_errors_testplan.hjson +++ b/vendor/lowrisc_ip/dv/tools/dvsim/testplans/shadow_reg_errors_testplan.hjson @@ -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 + ''' + } + ] } diff --git a/vendor/lowrisc_ip/dv/tools/dvsim/testplans/tl_device_access_types_testplan.hjson b/vendor/lowrisc_ip/dv/tools/dvsim/testplans/tl_device_access_types_testplan.hjson index 37369dca..f3c63d6c 100644 --- a/vendor/lowrisc_ip/dv/tools/dvsim/testplans/tl_device_access_types_testplan.hjson +++ b/vendor/lowrisc_ip/dv/tools/dvsim/testplans/tl_device_access_types_testplan.hjson @@ -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 diff --git a/vendor/lowrisc_ip/dv/tools/dvsim/testplans/tl_device_access_types_wo_intg_testplan.hjson b/vendor/lowrisc_ip/dv/tools/dvsim/testplans/tl_device_access_types_wo_intg_testplan.hjson new file mode 100644 index 00000000..e72060d7 --- /dev/null +++ b/vendor/lowrisc_ip/dv/tools/dvsim/testplans/tl_device_access_types_wo_intg_testplan.hjson @@ -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`. + ''' + } + ] +} diff --git a/vendor/lowrisc_ip/dv/tools/dvsim/xcelium.hjson b/vendor/lowrisc_ip/dv/tools/dvsim/xcelium.hjson index b7492e3b..6891bf92 100644 --- a/vendor/lowrisc_ip/dv/tools/dvsim/xcelium.hjson +++ b/vendor/lowrisc_ip/dv/tools/dvsim/xcelium.hjson @@ -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, diff --git a/vendor/lowrisc_ip/dv/tools/vcs/cover.cfg b/vendor/lowrisc_ip/dv/tools/vcs/cover.cfg index a3386ee7..59aeb2c1 100644 --- a/vendor/lowrisc_ip/dv/tools/vcs/cover.cfg +++ b/vendor/lowrisc_ip/dv/tools/vcs/cover.cfg @@ -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 diff --git a/vendor/lowrisc_ip/dv/tools/vcs/cover_reg_top.cfg b/vendor/lowrisc_ip/dv/tools/vcs/cover_reg_top.cfg index 965cda55..a74b0d88 100644 --- a/vendor/lowrisc_ip/dv/tools/vcs/cover_reg_top.cfg +++ b/vendor/lowrisc_ip/dv/tools/vcs/cover_reg_top.cfg @@ -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: diff --git a/vendor/lowrisc_ip/dv/tools/vcs/unr.cfg b/vendor/lowrisc_ip/dv/tools/vcs/unr.cfg index debceaf5..290f3a45 100644 --- a/vendor/lowrisc_ip/dv/tools/vcs/unr.cfg +++ b/vendor/lowrisc_ip/dv/tools/vcs/unr.cfg @@ -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 diff --git a/vendor/lowrisc_ip/dv/tools/xcelium/cover.ccf b/vendor/lowrisc_ip/dv/tools/xcelium/cover.ccf index 12b92311..9b0cbe7c 100644 --- a/vendor/lowrisc_ip/dv/tools/xcelium/cover.ccf +++ b/vendor/lowrisc_ip/dv/tools/xcelium/cover.ccf @@ -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 diff --git a/vendor/lowrisc_ip/ip/prim/doc/prim_clock_gp_mux2.md b/vendor/lowrisc_ip/ip/prim/doc/prim_clock_gp_mux2.md new file mode 100644 index 00000000..a3e75c89 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/doc/prim_clock_gp_mux2.md @@ -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 >}} diff --git a/vendor/lowrisc_ip/ip/prim/doc/prim_flash.md b/vendor/lowrisc_ip/ip/prim/doc/prim_flash.md index 779397cd..ecf09012 100644 --- a/vendor/lowrisc_ip/ip/prim/doc/prim_flash.md +++ b/vendor/lowrisc_ip/ip/prim/doc/prim_flash.md @@ -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. diff --git a/vendor/lowrisc_ip/ip/prim/doc/prim_keccak.md b/vendor/lowrisc_ip/ip/prim/doc/prim_keccak.md index 8f0f65ac..0a63c71b 100644 --- a/vendor/lowrisc_ip/ip/prim/doc/prim_keccak.md +++ b/vendor/lowrisc_ip/ip/prim/doc/prim_keccak.md @@ -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. - diff --git a/vendor/lowrisc_ip/ip/prim/doc/prim_packer.md b/vendor/lowrisc_ip/ip/prim/doc/prim_packer.md index 99997fd8..c5fdf198 100644 --- a/vendor/lowrisc_ip/ip/prim/doc/prim_packer.md +++ b/vendor/lowrisc_ip/ip/prim/doc/prim_packer.md @@ -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 /----------\ diff --git a/vendor/lowrisc_ip/ip/prim/doc/prim_packer_fifo.md b/vendor/lowrisc_ip/ip/prim/doc/prim_packer_fifo.md index 95e5eaae..f3ad487e 100644 --- a/vendor/lowrisc_ip/ip/prim/doc/prim_packer_fifo.md +++ b/vendor/lowrisc_ip/ip/prim/doc/prim_packer_fifo.md @@ -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. - diff --git a/vendor/lowrisc_ip/ip/prim/doc/prim_xoshiro256pp.md b/vendor/lowrisc_ip/ip/prim/doc/prim_xoshiro256pp.md index 94314a76..8e623033 100644 --- a/vendor/lowrisc_ip/ip/prim/doc/prim_xoshiro256pp.md +++ b/vendor/lowrisc_ip/ip/prim/doc/prim_xoshiro256pp.md @@ -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 >}} diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_lfsr/prim_lfsr_sim_cfg.hjson b/vendor/lowrisc_ip/ip/prim/dv/prim_lfsr/prim_lfsr_sim_cfg.hjson index 75c993df..fb0d69c1 100644 --- a/vendor/lowrisc_ip/ip/prim/dv/prim_lfsr/prim_lfsr_sim_cfg.hjson +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_lfsr/prim_lfsr_sim_cfg.hjson @@ -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 } ] diff --git a/vendor/lowrisc_ip/ip/prim/dv/prim_lfsr/prim_lfsr_tb.sv b/vendor/lowrisc_ip/ip/prim/dv/prim_lfsr/prim_lfsr_tb.sv index 2a6de2ea..056bb9b4 100644 --- a/vendor/lowrisc_ip/ip/prim/dv/prim_lfsr/prim_lfsr_tb.sv +++ b/vendor/lowrisc_ip/ip/prim/dv/prim_lfsr/prim_lfsr_tb.sv @@ -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 diff --git a/vendor/lowrisc_ip/ip/prim/lint/prim_cdc_rand_delay.waiver b/vendor/lowrisc_ip/ip/prim/lint/prim_cdc_rand_delay.waiver index 00a95ef9..db67e540 100644 --- a/vendor/lowrisc_ip/ip/prim/lint/prim_cdc_rand_delay.waiver +++ b/vendor/lowrisc_ip/ip/prim/lint/prim_cdc_rand_delay.waiver @@ -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." diff --git a/vendor/lowrisc_ip/ip/prim/lint/prim_count.waiver b/vendor/lowrisc_ip/ip/prim/lint/prim_count.waiver index e0bb9827..c0b59c97 100644 --- a/vendor/lowrisc_ip/ip/prim/lint/prim_count.waiver +++ b/vendor/lowrisc_ip/ip/prim/lint/prim_count.waiver @@ -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." diff --git a/vendor/lowrisc_ip/ip/prim/lint/prim_flop_2sync.waiver b/vendor/lowrisc_ip/ip/prim/lint/prim_flop_2sync.waiver index cb0ef18a..65c9f8a5 100644 --- a/vendor/lowrisc_ip/ip/prim/lint/prim_flop_2sync.waiver +++ b/vendor/lowrisc_ip/ip/prim/lint/prim_flop_2sync.waiver @@ -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." diff --git a/vendor/lowrisc_ip/ip/prim/lint/prim_rst_sync.waiver b/vendor/lowrisc_ip/ip/prim/lint/prim_rst_sync.waiver new file mode 100644 index 00000000..e05268b2 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/lint/prim_rst_sync.waiver @@ -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 diff --git a/vendor/lowrisc_ip/ip/prim/pre_dv/prim_sync_reqack/README.md b/vendor/lowrisc_ip/ip/prim/pre_dv/prim_sync_reqack/README.md index 77447b4c..cd149efa 100644 --- a/vendor/lowrisc_ip/ip/prim/pre_dv/prim_sync_reqack/README.md +++ b/vendor/lowrisc_ip/ip/prim/pre_dv/prim_sync_reqack/README.md @@ -1,4 +1,4 @@ -REQ/ACK Syncronizer Verilator Testbench +REQ/ACK Synchronizer Verilator Testbench ======================================= This directory contains a basic, scratch Verilator testbench targeting diff --git a/vendor/lowrisc_ip/ip/prim/prim.core b/vendor/lowrisc_ip/ip/prim/prim.core index b1f7b9ba..47389f96 100644 --- a/vendor/lowrisc_ip/ip/prim/prim.core +++ b/vendor/lowrisc_ip/ip/prim/prim.core @@ -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 diff --git a/vendor/lowrisc_ip/ip/prim/prim_macros.core b/vendor/lowrisc_ip/ip/prim/prim_macros.core new file mode 100644 index 00000000..70b9debd --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/prim_macros.core @@ -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 diff --git a/vendor/lowrisc_ip/ip/prim/prim_rst_sync.core b/vendor/lowrisc_ip/ip/prim/prim_rst_sync.core new file mode 100644 index 00000000..7d207004 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/prim_rst_sync.core @@ -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 diff --git a/vendor/lowrisc_ip/ip/prim/prim_util.core b/vendor/lowrisc_ip/ip/prim/prim_util.core index 33a08a35..5f224118 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_util.core +++ b/vendor/lowrisc_ip/ip/prim/prim_util.core @@ -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 diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_alert_sender.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_alert_sender.sv index 009e2999..6476fc26 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_alert_sender.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_alert_sender.sv @@ -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 diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_cdc_rand_delay.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_cdc_rand_delay.sv index 583ae84e..a283afdd 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_cdc_rand_delay.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_cdc_rand_delay.sv @@ -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 diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_clock_meas.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_clock_meas.sv index a784bbb7..e2c2b7f2 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_clock_meas.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_clock_meas.sv @@ -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; diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_count.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_count.sv index 9f32247a..646ad6a4 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_count.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_count.sv @@ -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 diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_diff_decode.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_diff_decode.sv index 1d1b6895..caf32199 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_diff_decode.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_diff_decode.sv @@ -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 diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_double_lfsr.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_double_lfsr.sv index f03cb4e2..8fce7b76 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_double_lfsr.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_double_lfsr.sv @@ -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]; diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_edn_req.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_edn_req.sv index a3cf9880..7fb07da6 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_edn_req.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_edn_req.sv @@ -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 diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_esc_receiver.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_esc_receiver.sv index d8c60199..24aeb4ca 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_esc_receiver.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_esc_receiver.sv @@ -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) diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_fifo_async.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_fifo_async.sv index e2f2d07a..0edebc76 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_fifo_async.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_fifo_async.sv @@ -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 ////////////////////////////////////// diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_flop_2sync.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_flop_2sync.sv index 313634c1..1922b0d0 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_flop_2sync.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_flop_2sync.sv @@ -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), diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_intr_hw.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_intr_hw.sv index be09a7c8..1813194e 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_intr_hw.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_intr_hw.sv @@ -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 diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_lc_sync.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_lc_sync.sv index 633c142a..d1536c6b 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_lc_sync.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_lc_sync.sv @@ -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 diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_lfsr.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_lfsr.sv index e17e1126..1ced7212 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_lfsr.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_lfsr.sv @@ -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 diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_macros.svh b/vendor/lowrisc_ip/ip/prim/rtl/prim_macros.svh new file mode 100644 index 00000000..eed1a7cb --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_macros.svh @@ -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 = 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 +*/ diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi12_sync.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi12_sync.sv index c380142d..956f40c4 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi12_sync.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi12_sync.sv @@ -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 diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi16_sync.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi16_sync.sv index 8ee4b2f2..ab46fbc0 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi16_sync.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi16_sync.sv @@ -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 diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi4_sync.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi4_sync.sv index 8c7d9958..264355c6 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi4_sync.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi4_sync.sv @@ -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 diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi8_sync.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi8_sync.sv index bb543a8d..51b1a32a 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi8_sync.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_mubi8_sync.sv @@ -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 diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_pulse_sync.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_pulse_sync.sv index d6e51a21..86bc60db 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_pulse_sync.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_pulse_sync.sv @@ -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 diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_reg_cdc.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_reg_cdc.sv index 3c4b6482..d94e196b 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_reg_cdc.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_reg_cdc.sv @@ -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 diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_reg_cdc_arb.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_reg_cdc_arb.sv index ced71d81..520559cf 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_reg_cdc_arb.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_reg_cdc_arb.sv @@ -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 diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_rst_sync.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_rst_sync.sv new file mode 100644 index 00000000..b499a1a8 --- /dev/null +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_rst_sync.sv @@ -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 diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_sync_reqack.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_sync_reqack.sv index 202f6650..8f4d9aad 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_sync_reqack.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_sync_reqack.sv @@ -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 diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_sync_reqack_data.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_sync_reqack_data.sv index 840d86d8..6950716d 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_sync_reqack_data.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_sync_reqack_data.sv @@ -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 diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_util_pkg.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_util_pkg.sv index 36960c65..f5e3c92a 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_util_pkg.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_util_pkg.sv @@ -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 diff --git a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_flash.sv b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_flash.sv index b193b31e..e67e25a8 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_flash.sv +++ b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_flash.sv @@ -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; diff --git a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_flash_bank.sv b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_flash_bank.sv index d61a9a6a..b6e0d8b0 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_flash_bank.sv +++ b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_flash_bank.sv @@ -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 diff --git a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_otp.sv b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_otp.sv index 69736253..298a6d38 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_otp.sv +++ b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_otp.sv @@ -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 diff --git a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_pad_wrapper.sv b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_pad_wrapper.sv index 485a4d66..e7da2760 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_pad_wrapper.sv +++ b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_pad_wrapper.sv @@ -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; diff --git a/vendor/lowrisc_ip/lint/doc/index.md b/vendor/lowrisc_ip/lint/doc/index.md index 03f745ad..2c3ae825 100644 --- a/vendor/lowrisc_ip/lint/doc/index.md +++ b/vendor/lowrisc_ip/lint/doc/index.md @@ -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: ``` diff --git a/vendor/lowrisc_ip/util/dvsim/LauncherFactory.py b/vendor/lowrisc_ip/util/dvsim/LauncherFactory.py index 6d60868d..3829187c 100644 --- a/vendor/lowrisc_ip/util/dvsim/LauncherFactory.py +++ b/vendor/lowrisc_ip/util/dvsim/LauncherFactory.py @@ -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: diff --git a/vendor/lowrisc_ip/util/dvsim/SGE.py b/vendor/lowrisc_ip/util/dvsim/SGE.py new file mode 100755 index 00000000..2086b78e --- /dev/null +++ b/vendor/lowrisc_ip/util/dvsim/SGE.py @@ -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 diff --git a/vendor/lowrisc_ip/util/dvsim/Scheduler.py b/vendor/lowrisc_ip/util/dvsim/Scheduler.py index 7dbedb01..5bd4f5fe 100644 --- a/vendor/lowrisc_ip/util/dvsim/Scheduler.py +++ b/vendor/lowrisc_ip/util/dvsim/Scheduler.py @@ -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) diff --git a/vendor/lowrisc_ip/util/dvsim/SgeLauncher.py b/vendor/lowrisc_ip/util/dvsim/SgeLauncher.py new file mode 100755 index 00000000..ad7c50ed --- /dev/null +++ b/vendor/lowrisc_ip/util/dvsim/SgeLauncher.py @@ -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() diff --git a/vendor/lowrisc_ip/util/dvsim/SimCfg.py b/vendor/lowrisc_ip/util/dvsim/SimCfg.py index 71e70475..7fb81104 100644 --- a/vendor/lowrisc_ip/util/dvsim/SimCfg.py +++ b/vendor/lowrisc_ip/util/dvsim/SimCfg.py @@ -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: diff --git a/vendor/lowrisc_ip/util/dvsim/doc/testplanner.md b/vendor/lowrisc_ip/util/dvsim/doc/testplanner.md index 316c2c6d..44bcdbba 100644 --- a/vendor/lowrisc_ip/util/dvsim/doc/testplanner.md +++ b/vendor/lowrisc_ip/util/dvsim/doc/testplanner.md @@ -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. diff --git a/vendor/lowrisc_ip/util/dvsim/dvsim.py b/vendor/lowrisc_ip/util/dvsim/dvsim.py index b720e88b..4a3887f5 100755 --- a/vendor/lowrisc_ip/util/dvsim/dvsim.py +++ b/vendor/lowrisc_ip/util/dvsim/dvsim.py @@ -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) diff --git a/vendor/lowrisc_ip/util/dvsim/qsubopts.py b/vendor/lowrisc_ip/util/dvsim/qsubopts.py new file mode 100755 index 00000000..97d6e9f5 --- /dev/null +++ b/vendor/lowrisc_ip/util/dvsim/qsubopts.py @@ -0,0 +1,1849 @@ +#!/usr/bin/env python +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# -*- coding: utf-8 -*- +# ---------------------------------- +# qsubOptions Class +# ---------------------------------- +"""A helper class designed to handle the managment of options and +positional arguments to qsub and related Grid Engine executables. + +Contains functions to write the requested execution string either +to the command line or to a script file. +""" + +import argparse + + +class qsubOptions(): + "A data type meant to collect qsub options. See man qsub for information" + + def __init__(self, optstring='', prog='qsub'): + # Which SGE command are we going to work with? + self.prog = prog + sge_program_names = [ + 'qsub', 'qrsh', 'qsh', 'qlogin', 'qalter', 'qresub', 'qmake' + ] + assert self.prog in sge_program_names, 'Unsupported SGE command: ' + prog + \ + 'not one of ' + ', '.join(sge_program_names) + + if prog == 'qmake' and '-pe' in optstring: + prog = 'qsub' + else: + prog = 'qrsh' + + # SUPPRESS = If not specified, do not generate variable in namespace + self.parser = argparse.ArgumentParser( + description='Options to pass to qsub', + formatter_class=argparse.RawTextHelpFormatter, + argument_default=argparse.SUPPRESS, + epilog="""The following is scraped from the qsub manpage for GE \ + 6.2u5 dated 2009/12/01 12:24:06""") + + # BEGIN SGE OPTION PARSER + # BUG if help still begins with a line with -option, have cosmetic bug where + # metavar cannot be specified correctly + + yesno = ['y', 'yes', 'n', 'no'] + + if prog in ['qsub', 'qrsh', 'qsh', 'qlogin']: + self.parser.add_argument('-@', + metavar='optionfile', + help="""\ + Forces qsub, qrsh, qsh, or qlogin to use the options contained + in optionfile. The indicated file may contain all + valid options. Comment lines must start with a "#" sign.""") + + if prog in ['qsub', 'qalter']: + self.parser.add_argument('-a', + metavar='date_time', + help="""\ + Available for qsub and qalter only. + + Defines or redefines the time and date at which a job is eligible + for execution. Date_time conforms to [[CC]]YY]MMDDhhmm[.SS], + for the details, please see Date_time in: sge_types(1). + + If this option is used with qsub or if a corresponding value is specified + in qmon then a parameter named a and the value in the format CCYYMMDDhhmm.SS + will be passed to the defined JSV instances (see -jsv option below or + find more information concerning JSV in jsv(1))""") + + if prog in ['qsub', 'qsh', 'qrsh', 'qlogin', 'qalter']: + self.parser.add_argument('-ac', + metavar='variable[=value]', + action='append', + help=""" -ac variable[=value],... + Available for qsub, qsh, qrsh, qlogin and qalter only. + + Adds the given name/value pair(s) to the job's context. Value may be omitted. + Grid Engine appends the given argument to the list of context variables for the job. + Multiple -ac, -dc, and -sc options may be given. The order is important here. + + The outcome of the evaluation of all -ac, -dc, and -sc options or + corresponding values in qmon is passed to defined JSV instances as parameter + with the name ac. (see -jsv option below or find more information concerning + JSV in jsv(1)) QALTER allows changing this option even while the job executes.""" + ) + + if prog in ['qsub', 'qalter', 'qrsh', 'qsh', 'qlogin']: + self.parser.add_argument('-ar', + metavar='ar_id', + help="""\ + Available for qsub, qalter, qrsh, qsh, or qlogin only. + + Assigns the submitted job to be a part of an existing Advance Reservation. + The complete list of existing + Advance Reservations can be obtained using the qrstat(1) command. + + Note that the -ar option adds implicitly the -w e option if not otherwise requested. + + Qalter allows changing this option even while the job executes. + The modified parameter will only be in effect + after a restart or migration of the job however. + + If this option or a corresponding value in qmon is specified + then this value will be passed to defined JSV instances as parameter + with the name ar. (see -jsv option below or find more information + concerning JSV in jsv(1))""") + + if prog in ['qsub', 'qsh', 'qrsh', 'qlogin', 'qalter']: + self.parser.add_argument('-A', + metavar='account_string', + help="""\ + Available for qsub, qsh, qrsh, qlogin and qalter only. + + Identifies the account to which the resource consumption of the + job should be charged. The account_string should + conform to the name definition in M sge_types 1 . + In the absence of this parameter Grid Engine will place the + default account string "ge" in the accounting record of the job. + Qalter allows changing this option even while the job executes. + + If this option or a corresponding value in qmon is specified + then this value will be passed to defined JSV instances as parameter with the name A. + (see -jsv option below or find more information concerning JSV in jsv(1))""" + ) + + self.parser.add_argument('-binding', + nargs='+', + metavar=('binding_instance', + 'binding_strategy'), + help="""\ + -binding [ binding_instance ] binding_strategy + + A job can request a specific processor core binding (processor affinity) + with this parameter. This request is neither a hard nor a soft request, + it is a hint for the execution host to do this if possible. Please note that + the requested binding strategy is not used for resource selection within + Grid Engine. As a result an execution host might be selected where Grid Engine + does not even know the hardware topology and therefore is not able + to apply the requested binding. + + To enforce Grid Engine to select hardware on which the binding can be applied + please use the -l switch in combination with the complex attribute m_topology. + + binding_instance is an optional parameter. + It might either be env, pe or set depending on which instance should + accomplish the job to core binding. If the value for binding_instance + is not specified then set will be used. + + env means that the environment variable SGE_BINDING will be exported + to the job environment of the job. This variable contains the selected + operating system internal processor numbers. They might be more than selected + cores in presence of SMT or CMT because each core could be represented + by multiple processor identifiers. The processor numbers are space separated. + + pe means that the information about the selected cores appears in + the fourth column of the pe_hostfile. Here the logical core and + socket numbers are printed (they start at 0 and have no holes) + in colon separated pairs (i.e. 0,0:1,0 which means core 0 on socket 0 and + core 0 on socket 1). For more information about the $pe_hostfile + check ge_pe(5) + + set (default if nothing else is specified). The binding strategy is applied + by Grid Engine. How this is achieved depends on the underlying hardware + architecture of the execution host where the submitted job will be started. + + On Solaris 10 hosts a processor set will be created where the job can + exclusively run in. Because of operating system limitations at least + one core must remain unbound. This resource could of course used by an unbound job. + + On Linux hosts a processor affinity mask will be set to restrict the job + to run exclusively on the selected cores. + The operating system allows other unbound processes to use these cores. + Please note that on Linux the binding requires a Linux kernel + version of 2.6.16 or greater. It might be even possible to use a kernel with + lower version number but in that case additional kernel patches have to be + applied. The loadcheck tool in the utilbin directory can be used to check + if the hosts capabilities. You can also use the -sep in combination with + -cb of qconf(5) command to identify if Grid Engine is able to recognize the + hardware topology. + + Possible values for binding_strategy are as follows: + + linear:[:,] + striding::[:,] + explicit:[,;...], + + For the binding strategy linear and striding there is an optional + socket and core pair attached. + These denotes the mandatory starting point for the first core to bind on. + + linear means that Grid Engine tries to bind the job on amount successive cores. + If socket and core is omitted then Grid Engine first allocates successive cores + on the first empty socket found. Empty means that there are + no jobs bound to the socket by Grid Engine. If this is not possible or is + not sufficient Grid Engine tries to + find (further) cores on the socket with the most unbound cores and so on. + If the amount of allocated cores is + lower than requested cores, no binding is done for the job. + If socket and core is specified then Grid Engine + tries to find amount of empty cores beginning with this starting point. + If this is not possible then binding is not done. + + striding means that Grid Engine tries to find cores with a certain offset. + It will select amount of empty cores with a offset of n -1 cores in between. + Start point for the search algorithm is socket 0 core 0. As soon as + amount cores are found they will be used to do the job binding. + If there are not enough empty cores or if correct offset cannot be + achieved then there will be no binding done. + + explicit binds the specified sockets and cores that are mentioned + in the provided socket/core list. Each socket/core pair has to + be specified only once.If a socket/core pair is already in use by a different job the + whole binding request will be ignored. + + Qalter allows changing this option even while the job executes. + The modified parameter will only be in effect + after a restart or migration of the job, however. + + If this option or a corresponding value in qmon is specified then these values + will be passe to defined JSV instances as parameters with the names binding_strategy, + binding_type, binding_amount, binding_step, binding_socket, + binding_core, binding_exp_n, binding_exp_socket, binding_exp_core. + + Please note that the length of the socket/core value list of the explicit binding is + reported as binding_exp_n. + will be replaced by the position of the socket/core pair within the explicit + list (0 <= id < binding_exp_n). The first socket/core pair of the explicit + binding will be reported with the parameter names bind- + ing_exp_socket0 and binding_exp_core0. + + Values that do not apply for the specified binding will not be reported to JSV. + E.g. binding_step will only be + reported for the striding binding and all binding_exp_* values will passed to + JSV if explicit binding was speci‐ + fied. (see -jsv option below or find more information concerning + JSV in jsv(1))""") + + if prog in ['qsub', 'qrsh']: + self.parser.add_argument('-b', + choices=yesno, + help="""\ + Available for qsub, qrsh only. Qalter does not allow changing this option. + This option cannot be embedded in the script file itself. + + Gives the user the possibility to indicate explicitly whether command should be + treated as binary or script. If the value of -b is 'y', then command may be a + binary or script. The command might not be accessible from the + submission host. Nothing except the path of the command will be + transferred from the submission host to the + execution host. Path aliasing will be applied to the path of command + before command will be executed. + + If the value of -b is 'n' then command needs to be a script and it will + be handled as script. The script file + has to be accessible by the submission host. + It will be transferred to the execution host. qsub/qrsh will search + directive prefixes within script. + + qsub will implicitly use -b n whereas qrsh will apply the -b y option + if nothing else is specified. + + The value specified with this option or the corresponding value + specified in qmon will only be passed to defined + JSV instances if the value is yes. The name of the parameter will be b. + The value will be y also when then long + form yes was specified during submission. + (see -jsv option below or find more information concerning JSV in + jsv(1)) + + Please note that submission of command as script (-b n) can have a + significant performance impact,especially for short running jobs and big job scripts. + Script submission adds a number of operations to the submission + process: The job script needs to be + - parsed at client side (for special comments) + - transferred from submit client to qmaster + - spooled in qmaster + - transferred to execd at job execution + - spooled in execd + - removed from spooling both in execd and qmaster once the job is done + If job scripts are available on the execution nodes, e.g. via NFS, binary + submission can be the better choice.""") + + if prog in ['qsub', 'qalter']: + self.parser.add_argument('-c', + metavar='occasion_specifier', + help="""\ + Available for qsub and qalter only. + + Defines or redefines whether the job should be checkpointed, and if so, + under what circumstances. The specifica‐ + tion of the checkpointing occasions with this option overwrites the + definitions of the when parameter in the + checkpointing environment (see checkpoint(5)) referenced by the qsub + -ckpt switch. Possible values for occa‐ + sion_specifier are + + n no checkpoint is performed. + s checkpoint when batch server is shut down. + m checkpoint at minimum CPU interval. + x checkpoint when job gets suspended. + checkpoint in the specified time interval. + + The minimum CPU interval is defined in the queue configuration (see + queue_conf(5) for details). has + to be specified in the format hh:mm:ss. + The maximum of and the queue's minimum CPU interval is used + if is specified. This is done to ensure that a machine is not + overloaded by checkpoints being generated too frequently. + + The value specified with this option or the corresponding value specified + in qmon will be passed to defined JSV + instances. The will be available as parameter with the name c_interval. + The character sequence + specified will be available as parameter with the name c_occasion. + Please note that if you change c_occasion via + JSV then the last setting of c_interval will be overwritten and vice versa. + (see -jsv option below or find more + information concerning JSV in jsv(1))""") + + if prog in ['qsub', 'qalter']: + self.parser.add_argument('-ckpt', + metavar='ckpt_name', + help="""\ + Available for qsub and qalter only. + + Selects the checkpointing environment (see checkpoint(5)) to be used + for checkpointing the job. Also declares the job to be a checkpointing job. + + If this option or a corresponding value in qmon is specified then this + value will be passed to defined JSV + instances as parameter with the name ckpt. (see -jsv option below or + find more information concerning JSV in jsv(1))""") + + if prog in ['qsub', 'qsh', 'qrsh', 'qlogin']: + self.parser.add_argument('-clear', + action='store_true', + help="""\ + Available for qsub, qsh, qrsh, and qlogin only. + + Causes all elements of the job to be reset to the initial default + status prior to applying any modifications (if + any) appearing in this specific command.""") + + if prog in ['qsub', 'qsh', 'qrsh', 'qalter']: + self.parser.add_argument('-cwd', + action='store_true', + help="""\ + Available for qsub, qsh, qrsh and qalter only. + + Execute the job from the current working directory. + This switch will activate Grid Engine's path aliasing + facility, if the corresponding configuration files are present (see ge_aliases(5)). + + In the case of qalter, the previous definition of the current working + directory will be overwritten if qalter is + executed from a different directory than the preceding qsub or qalter. + + Qalter allows changing this option even while the job executes. + The modified parameter will only be in effect + after a restart or migration of the job, however. + + If this option or a corresponding value in qmon is specified + then this value will be passed to defined JSV + instances as parameter with the name cwd. The value of this parameter + will be the absolute path to the current + working directory. JSV scripts can remove the path from jobs during the + verification process by setting the + value of this parameter to an empty string. + As a result the job behaves as if -cwd was not specified during job + submission. (see -jsv option below or find more information + concerning JSV in jsv(1))""") + + if prog in ['qsub', 'qrsh']: + self.parser.add_argument('-C', + metavar='prefix_string', + help="""\ + Available for qsub and qrsh with script submission (-b n). + + Prefix_string defines the prefix that declares a directive in the job's command. + The prefix is not a job + attribute, but affects the behavior of qsub and qrsh. + If prefix is a null string, the command will not be + scanned for embedded directives. + The directive prefix consists of two ASCII characters which, + when appearing in the first two bytes of a script + line, indicate that what follows is an Grid Engine command. The default is "#$". + The user should be aware that changing the first delimiting character + can produce unforeseen side effects. If + the script file contains anything other than a "#" character in the first byte + position of the line, the shell + processor for the job will reject the line and may exit the job prematurely. + If the -C option is present in the script file, it is ignored.""" + ) + + if prog in ['qsub', 'qsh', 'qrsh', 'qlogin', 'qalter']: + self.parser.add_argument('-dc', + action='append', + metavar='variable', + help="""\ + -dc variable,... + Available for qsub, qsh, qrsh, qlogin and qalter only. + + Removes the given variable(s) from the job's context. Multiple -ac, -dc, and + -sc options may be given. The order is important. + + Qalter allows changing this option even while the job executes. + + The outcome of the evaluation of all -ac, -dc, and -sc options or corresponding + values in qmon is passed to + defined JSV instances as parameter with the name ac. (see -jsv option below or + find more information concerning + JSV in jsv(1))""") + + if prog in ['qsh', 'qrsh']: + self.parser.add_argument('-display', + metavar='display_specifier', + help="""\ + Available for qsh and qrsh. + + Directs xterm(1) to use display_specifier in order to contact the X server. + The display_specifier has to con‐ + tain the hostname part of the display name (e.g. myhost:1). + Local display names (e.g. :0) cannot be used in + grid environments. Values set with the -display option overwrite settings + from the submission environment and + from -v command line options. + + If this option or a corresponding value in qmon is specified then this + value will be passed to defined JSV + instances as parameter with the name display. This value will also be available + in the job environment which + might optionally be passed to JSV scripts. The variable name will be DISPLAY. + (see -jsv option below or find + more information concerning JSV in jsv(1))""") + + if prog in ['qsub', 'qsh', 'qrsh', 'qlogin', 'qalter']: + self.parser.add_argument('-dl', + metavar='date_time', + help="""\ + Available for qsub, qsh, qrsh, qlogin and qalter only. + + Specifies the deadline initiation time in [[CC]YY]MMDDhhmm[.SS] format (see -a + option above). The deadline ini‐ + tiation time is the time at which a deadline job has to reach top priority to be + able to complete within a given + deadline. Before the deadline initiation time the priority of a deadline job + will be raised steadily until it + reaches the maximum as configured by the Grid Engine administrator. + + This option is applicable only for users allowed to submit deadline jobs. + + If this option or a corresponding value in qmon is specified then this + value will be passed to defined JSV + instances as parameter with the name dl. The format for the date_time value + is CCYYMMDDhhmm.SS (see -jsv option + below or find more information concerning JSV in jsv(1))""") + + if prog in ['qsub', 'qsh', 'qrsh', 'qlogin', 'qalter']: + self.parser.add_argument('-e', + metavar='path', + help="""\ + -e [[hostname]:]path,... + Available for qsub, qsh, qrsh, qlogin and qalter only. + + Defines or redefines the path used for the standard error stream of the job. + For qsh, qrsh and qlogin only the + standard error stream of prolog and epilog is redirected. If the path + constitutes an absolute path name, the + error-path attribute of the job is set to path, including the hostname. + If the path name is relative, Grid + Engine expands path either with the current working directory path + (if the -cwd switch (see above) is also spec‐ + ified) or with the home directory path. If hostname is present, + the standard error stream will be placed in the + corresponding location only if the job runs on the specified host. + If the path contains a ":" without a host‐ + name, a leading ":" has to be specified. + + By default the file name for interactive jobs is /dev/null. + For batch jobs the default file name has the form + job_name.ejob_id and job_name.ejob_id.task_id for array job tasks (see -t option + below). + + If path is a directory, the standard error stream of the job will be put + in this directory under the default + file name. If the pathname contains certain pseudo environment variables, + their value will be expanded at run‐ + time of the job and will be used to constitute the standard error stream path name. + The following pseudo envi‐ + ronment variables are supported currently: + + $HOME home directory on execution machine + $USER user ID of job owner + $JOB_ID current job ID + $JOB_NAME current job name (see -N option) + $HOSTNAME name of the execution host + $TASK_ID array job task index number + + Alternatively to $HOME the tilde sign "~" can be used as common in csh(1) + or ksh(1). Note, that the "~" sign + also works in combination with user names, so that "~" expands to the + home directory of . Using + another user ID than that of the job owner requires corresponding permissions, + of course. + + Qalter allows changing this option even while the job executes. + The modified parameter will only be in effect + after a restart or migration of the job, however. + + If this option or a corresponding value in qmon is specified then this value + will be passed to defined JSV + instances as parameter with the name e. (see -jsv option below or + find more information concerning JSV in + jsv(1))""") + + if prog in ['qsub', 'qsh', 'qrsh', 'qlogin', 'qalter']: + self.parser.add_argument('-hard', + action='store_true', + help="""\ + Available for qsub, qsh, qrsh, qlogin and qalter only. + + Signifies that all -q and -l resource requirements following in the command + line will be hard requirements and + must be satisfied in full before a job can be scheduled. + As Grid Engine scans the command line and script file for Grid Engine options + and parameters it builds a list of + resources required by a job. All such resource requests are considered as + absolutely essential for the job to + commence. If the -soft option (see below) is encountered during the scan then + all following resources are desig‐ + nated as "soft requirements" for execution, or "nice-to-have, but not essential". + If the -hard flag is encoun‐ + tered at a later stage of the scan, all resource requests following it once again + become "essential". The -hard + and -soft options in effect act as "toggles" during the scan. + + If this option or a corresponding value in qmon is specified then the corresponding + -q and -l resource require‐ + ments will be passed to defined JSV instances as parameter with the names + q_hard and l_hard. Find for informa‐ + tion in the sections describing -q and -l. (see -jsv option below or find + more information concerning JSV in + jsv(1))""") + + if prog in ['qsub', 'qrsh', 'qalter', 'qresub']: + # NOTE in SGE this is -h, here I have renamed it to -hold + # TODO check if multiple holds are parsed correctly + self.parser.add_argument('-hold', + choices='usonUOS', + help="""\ + NOTE: Originally defined as -h, but changed to -hold here. + + Available for qsub (only -h), qrsh, qalter and qresub (hold state is + removed when not set explicitly). + + List of holds to place on a job, a task or some tasks of a job. + + `u' denotes a user hold. + `s' denotes a system hold. + `o' denotes a operator hold. + `n' denotes no hold (requires manager privileges). + + As long as any hold other than `n' is assigned to the job the job is + not eligible for execution. Holds can be + released via qalter and qrls(1). In case of qalter this is supported + by the following additional option speci‐ + fiers for the -h switch: + + `U' removes a user hold. + `S' removes a system hold. + `O' removes a operator hold. + + Grid Engine managers can assign and remove all hold types, + Grid Engine operators can assign and remove user and + operator holds, and users can only assign or remove user holds. + + In the case of qsub only user holds can be placed on a job and thus + only the first form of the option with the + -h switch alone is allowed. As opposed to this, qalter requires + the second form described above. + + An alternate means to assign hold is provided by the qhold(1) facility. + + If the job is a array job (see the -t option below), all tasks specified via + -t are affected by the -h operation + simultaneously. + + Qalter allows changing this option even while the job executes. + The modified parameter will only be in effect + after a restart or migration of the job, however. + + If this option is specified with qsub or during the submission + of a job in qmon then the parameter h with the + value u will be passed to the defined JSV instances indicating that + the job will be in user hold after the sub‐ + mission finishes. (see -jsv option below or find more information + concerning JSV in jsv(1))""") + + if prog in ['qsub', 'qrsh', 'qalter']: + self.parser.add_argument('-hold_jid', + nargs='+', + metavar='wc_job_list', + help="""\ + Available for qsub, qrsh, and qalter only. See sge_types(1). + for wc_job_list definition. + + Defines or redefines the job dependency list of the submitted job. + A reference by job name or pattern is only + accepted if the referenced job is owned by the same user as the referring job. + The submitted job is not eligible + for execution unless all jobs referenced in the comma-separated job id and/or + job name list have completed. If + any of the referenced jobs exits with exit code 100, the submitted + job will remain ineligible for execution. + + With the help of job names or regular pattern one can specify a job + dependency on multiple jobs satisfying the + regular pattern or on all jobs with the requested name. + The name dependencies are resolved at submit time and + can only be changed via qalter. New jobs or name changes + of other jobs will not be taken into account. + + Qalter allows changing this option even while the job executes. + The modified parameter will only be in effect + after a restart or migration of the job, however. + + If this option or a corresponding value in qmon is specified + then this value will be passed to defined JSV + instances as parameter with the name hold_jid. + (see -jsv option below or find more information concerning JSV + in jsv(1))""") + + if prog in ['qsub', 'qrsh', 'qalter']: + self.parser.add_argument('-hold_jid_ad', + nargs='+', + metavar='wc_job_list', + help="""\ + Available for qsub, qrsh, and qalter only. See sge_types(1). + for wc_job_list definition. + + Defines or redefines the job array dependency list of + the submitted job. A reference by job name or pattern is + only accepted if the referenced job is owned by the same + user as the referring job. Each sub-task of the submit‐ + ted job is not eligible for execution unless the corresponding + sub-tasks of all jobs referenced in the comma- + separated job id and/or job name list have completed. + If any array task of the referenced jobs exits with exit + code 100, the dependent tasks of the submitted job will remain + ineligible for execution. + + With the help of job names or regular pattern one can specify + a job dependency on multiple jobs satisfying the + regular pattern or on all jobs with the requested name. + The name dependencies are resolved at submit time and + can only be changed via qalter. New jobs or name changes of other + jobs will not be taken into account. + + If either the submitted job or any job in wc_job_list are + not array jobs with the same range of sub-tasks (see + -t option below), the request list will be rejected and the + job create or modify operation will error. + + qalter allows changing this option even while the job executes. + The modified parameter will only be in effect + after a restart or migration of the job, however. + + If this option or a corresponding value in qmon is + specified then this value will be passed to defined JSV + instances as parameter with the name hold_jid_ad. + (see -jsv option below or find more information concerning + JSV in jsv(1))""") + + if prog in ['qsub', 'qalter']: + self.parser.add_argument('-i', + metavar='file', + help="""\ + -i [[hostname]:]file,... + Available for qsub, and qalter only. + + Defines or redefines the file used for the standard input stream of + the job. If the file constitutes an absolute + filename, the input-path attribute of the job is set to path, + including the hostname. If the path name is rela‐ + tive, Grid Engine expands path either with the current working + directory path (if the -cwd switch (see above) is + also specified) or with the home directory path. If hostname is present, + the standard input stream will be + placed in the corresponding location only if the job runs + on the specified host. If the path contains a ":" + without a hostname, a leading ":" has to be specified. + + By default /dev/null is the input stream for the job. + + It is possible to use certain pseudo variables, whose values + will be expanded at runtime of the job and will be + used to express the standard input stream as described in + the -e option for the standard error stream. + + Qalter allows changing this option even while the job executes. + The modified parameter will only be in effect + after a restart or migration of the job, however. + + If this option or a corresponding value in qmon is specified then + this value will be passed to defined JSV + instances as parameter with the name i. + (see -jsv option below or find more information concerning JSV in + jsv(1))""") + + if prog in ['qrsh', 'qmake']: + self.parser.add_argument('-inherit', + action='store_true', + help="""\ + Available only for qrsh and qmake(1). + + qrsh allows the user to start a task in an already scheduled parallel job. + The option -inherit tells qrsh to + read a job id from the environment variable JOB_ID and start the + specified command as a task in this job. Please + note that in this case, the hostname of the host where the command + will be executed must precede the command to + execute; the syntax changes to + + qrsh -inherit [ other options ] hostname command [ command_args ] + + Note also, that in combination with -inherit, most other command line + options will be ignored. Only the options + -verbose, -v and -V will be interpreted. As a replacement to option + -cwd please use -v PWD. + + Usually a task should have the same environment (including the + current working directory) as the corresponding + job, so specifying the option -V should be suitable for most applications. + + Note: If in your system the qmaster tcp port is not configured as a service, + but rather via the environment + variable GE_QMASTER_PORT, make sure that this variable is set in the + environment when calling qrsh or qmake with + the -inherit option. If you call qrsh or qmake with the + -inherit option from within a job script, export + GE_QMASTER_PORT with the option "-v GE_QMASTER_PORT" either as + a command argument or an embedded directive. + + This parameter is not available in the JSV context. + (see -jsv option below or find more information concerning + JSV in jsv(1))""") + + if prog in ['qsub', 'qsh', 'qrsh', 'qlogin', 'qalter']: + self.parser.add_argument('-j', + choices=yesno, + help="""\ + Available for qsub, qsh, qrsh, qlogin and qalter only. + + Specifies whether or not the standard error stream of the job + is merged into the standard output stream. + If both the -j y and the -e options are present, + Grid Engine sets but ignores the error-path attribute. + + Qalter allows changing this option even while the job executes. + The modified parameter will only be in effect + after a restart or migration of the job, however. + + + The value specified with this option or the corresponding + value specified in qmon will only be passed to defined + JSV instances if the value is yes. The name of the parameter will be j. + The value will be y also when then long + form yes was specified during submission. + (see -jsv option below or find more information concerning JSV in + jsv(1))""") + + if prog in ['qsub', 'qsh', 'qrsh', 'qlogin', 'qalter']: + self.parser.add_argument('-js', + nargs='?', + type=int, + metavar='job_share', + help="""\ + Available for qsub, qsh, qrsh, qlogin and qalter only. + + Defines or redefines the job share of the job relative to other jobs. + Job share is an unsigned integer value. + The default job share value for jobs is 0. + + The job share influences the Share Tree Policy and the Functional Policy. + It has no effect on the Urgency and + Override Policies (see share_tree(5), sched_conf(5) and the + Grid Engine Installation and Administration Guide + for further information on the resource management policies supported + by Grid Engine). + + In case of the Share Tree Policy, users can distribute the tickets to + which they are currently entitled among + their jobs using different shares assigned via -js. + If all jobs have the same job share value, the tickets are + distributed evenly. Otherwise, jobs receive tickets relative + to the different job shares. Job shares are treated + like an additional level in the share tree in the latter case. + + In connection with the Functional Policy, the job share can be + used to weight jobs within the functional job + category. Tickets are distributed relative to any uneven + job share distribution treated as a virtual share dis‐ + tribution level underneath the functional job category. + + If both the Share Tree and the Functional Policy are active, + the job shares will have an effect in both poli‐ + cies, and the tickets independently derived in each of them are + added to the total number of tickets for each + job. + + If this option or a corresponding value in qmon is specified + then this value will be passed to defined JSV + instances as parameter with the name js. (see -jsv option below or + find more information concerning JSV in + jsv(1))""") + + if prog in ['qsub', 'qsh', 'qrsh', 'qlogin']: + self.parser.add_argument('-jsv', + metavar='jsv_url', + help="""\ + Available for qsub, qsh, qrsh and qlogin only. + + Defines a client JSV instance which will be executed to + verify the job specification before the job is sent to + qmaster. + + In contrast to other options this switch will not be overwritten + if it is also used in sge_request files. + Instead all specified JSV instances will be executed to verify + the job to be submitted. + + The JSV instance which is directly passed with the commandline + of a client is executed as first to verify the + job specification. After that the JSV instance which might have + been defined in various sge_request files will + be triggered to check the job. Find more details + in man page jsv(1) and sge_request(5). + + The syntax of the jsv_url is specified in sge_types(1).()""") + + if prog in ['qsub', 'qsh', 'qrsh', 'qlogin', 'qalter']: + self.parser.add_argument('-l', + metavar='keywords', + help="""\ + -l resource=value,... + Available for qsub, qsh, qrsh, qlogin and qalter only. + + Launch the job in a Grid Engine queue meeting the given resource + request list. In case of qalter the previous + definition is replaced by the specified one. + + complex(5) describes how a list of available resources and their + associated valid value specifiers can be + obtained. + + There may be multiple -l switches in a single command. + You may request multiple -l options to be soft or hard + both in the same command line. In case of a serial job multiple + -l switches refine the definition for the sought + queue. + + Qalter allows changing the value of this option even while the + job is running, but only if the initial list of + resources does not contain a resource that is marked as consumable. + However the modification will only be effec‐ + tive after a restart or migration of the job. + + If this option or a corresponding value in qmon is specified the + these hard and soft resource requirements will + be passed to defined JSV instances as parameter with the names + l_hard and l_soft. If regular expressions will be + used for resource requests, then these expressions will + be passed as they are. Also shortcut names will not be + expanded. (see -jsv option above or find more information + concerning JSV in jsv(1))""") + + if prog in ['qsub', 'qsh', 'qrsh', 'qlogin', 'qalter']: + # TODO check if multiple arguments are parsed correctly + self.parser.add_argument('-m', + nargs='+', + choices='beasn', + help="""\ + Available for qsub, qsh, qrsh, qlogin and qalter only. + + Defines or redefines under which circumstances mail + is to be sent to the job owner or to the users defined with + the -M option described below. The option arguments + have the following meaning: + + `b' Mail is sent at the beginning of the job. + `e' Mail is sent at the end of the job. + `a' Mail is sent when the job is aborted or + rescheduled. + `s' Mail is sent when the job is suspended. + `n' No mail is sent. + + Currently no mail is sent when a job is suspended. + + Qalter allows changing the b, e, and a option arguments + even while the job executes. The modification of the b + option argument will only be in effect after a restart + or migration of the job, however. + + If this option or a corresponding value in qmon is + specified then this value will be passed to defined JSV + instances as parameter with the name m. (see -jsv option + above or find more information concerning JSV in""") + + if prog in ['qsub', 'qsh', 'qrsh', 'qlogin', 'qalter']: + self.parser.add_argument('-M', + metavar='user[@host]', + help="""\ + -M user[@host],... + Available for qsub, qsh, qrsh, qlogin and qalter only. + + Defines or redefines the list of users to which the server + that executes the job has to send mail, if the server + sends mail about the job. Default is the job owner at the originating host. + + Qalter allows changing this option even while the job executes. + + If this option or a corresponding value in qmon is specified then + this value will be passed to defined JSV + instances as parameter with the name M. (see -jsv option above or + find more information concerning JSV in + jsv(1))""") + + if prog in ['qsub', 'qsh', 'qrsh', 'qlogin', 'qalter']: + self.parser.add_argument('-masterq', + nargs='+', + metavar='wc_queue_list', + help="""\ + Available for qsub, qrsh, qsh, qlogin and qalter. Only meaningful + for parallel jobs, i.e. together with the -pe option. + + Defines or redefines a list of cluster queues, queue domains and + queue instances which may be used to become the + so called master queue of this parallel job. A more detailed + description of wc_queue_list can be found in + sge_types(1). The master queue is defined as the queue where + the parallel job is started. The other queues to + which the parallel job spawns tasks are called slave queues. + A parallel job only has one master queue. + + This parameter has all the properties of a resource request + and will be merged with requirements derived from + the -l option described above. + + Qalter allows changing this option even while the job executes. + The modified parameter will only be in effect + after a restart or migration of the job, however. + + If this option or a corresponding value in qmon is specified + the this hard resource requirement will be passed + to defined JSV instances as parameter with the name masterq. + (see -jsv option above or find more information + concerning JSV in jsv(1))""") + + if prog in ['qsub', 'qrsh', 'qalter']: + self.parser.add_argument('-notify', + action='store_true', + help="""\ + Available for qsub, qrsh (with command) and qalter only. + + This flag, when set causes Grid Engine to send "warning" signals + to a running job prior to sending the signals + themselves. If a SIGSTOP is pending, the job will receive + a SIGUSR1 several seconds before the SIGSTOP. If a + SIGKILL is pending, the job will receive a SIGUSR2 several + seconds before the SIGKILL. This option provides the + running job, before receiving the SIGSTOP or SIGKILL, + a configured time interval to do e.g. cleanup operations. + The amount of time delay is controlled by the notify parameter + in each queue configuration (see queue_conf(5)). + + Note that the Linux operating system "misused" the user + signals SIGUSR1 and SIGUSR2 in some early Posix thread + implementations. You might not want to use the + -notify option if you are running multi-threaded applications in + your jobs under Linux, particularly on 2.0 or earlier kernels. + + Qalter allows changing this option even while the job executes. + + Only if this option is used the parameter named notify with + the value y will be passed to defined JSV instances. + (see -jsv option above or find more information concerning + JSV in jsv(1))""") + + if prog in ['qsub', 'qsh', 'qrsh', 'qlogin']: + self.parser.add_argument('-now', + choices=yesno, + help="""\ + Available for qsub, qsh, qlogin and qrsh. + + -now y tries to start the job immediately or not at all. + The command returns 0 on success, or 1 on failure (also + if the job could not be scheduled immediately). + For array jobs submitted with the -now option, if all tasks + cannot be immediately scheduled, no tasks are scheduled. + -now y is default for qsh, qlogin and qrsh + + With the -now n option, the job will be put into the pending + queue if it cannot be executed immediately. -now n + is default for qsub. + + The value specified with this option or the corresponding + value specified in qmon will only be passed to defined + JSV instances if the value is yes. The name of the + parameter will be now. The value will be y also when then + long form yes was specified during submission. + (see -jsv option above or find more information concerning JSV + in jsv(1))""") + + if prog in ['qsub', 'qsh', 'qrsh', 'qlogin', 'qalter']: + self.parser.add_argument('-N', + metavar='name', + help="""\ + Available for qsub, qsh, qrsh, qlogin and qalter only. + + The name of the job. The name should follow the "name" + definition in sge_types(1). Invalid job names will be + denied at submit time. + + If the -N option is not present, Grid Engine assigns + the name of the job script to the job after any directory + pathname has been removed from the script-name. + If the script is read from standard input, the job name defaults + to STDIN. + + In the case of qsh or qlogin with the -N option is absent, + + the string `INTERACT' is assigned to the job. + + In the case of qrsh if the -N option is absent, the resulting + job name is determined from the qrsh command line + by using the argument string up to the first + occurrence of a semicolon or whitespace and removing the directory + pathname. + + Qalter allows changing this option even while the job executes. + + The value specified with this option or the corresponding value + specified in qmon will be passed to defined JSV + instances as parameter with the name N. (see -jsv + option above or find more information concerning JSV in + jsv(1))""") + + if prog in ['qrsh']: + self.parser.add_argument('-noshell', + action='store_true', + help="""\ + Available only for qrsh with a command line. + + Do not start the command line given to qrsh in a user's login shell, + i.e. execute it without the wrapping + shell. + + This option can be used to speed up execution as some overhead, + like the shell startup and sourcing the shell + resource files, is avoided. + + This option can only be used if no shell-specific command line + parsing is required. If the command line contains + shell syntax like environment variable substitution or (back) quoting, + a shell must be started. In this case, + either do not use the -noshell option or include the shell call in the command line. + + Example: + qrsh echo '$HOSTNAME' + Alternative call with the -noshell option + qrsh -noshell /bin/tcsh -f -c 'echo $HOSTNAME'""") + + if prog in ['qrsh']: + self.parser.add_argument('-nostdin', + action='store_true', + help="""\ + Available only for qrsh. + + Suppress the input stream STDIN - qrsh will pass the option -n + to the rsh(1) command. This is especially useful, + if multiple tasks are executed in parallel using qrsh, e.g. + in a make(1) process - it would be undefined, which + process would get the input.""") + + if prog in ['qsub', 'qsh', 'qrsh', 'qlogin', 'qalter']: + self.parser.add_argument('-o', + metavar='path', + help="""\ + -o [[hostname]:]path,... + Available for qsub, qsh, qrsh, qlogin and qalter only. + + The path used for the standard output stream of the job. + The path is handled as described in the -e option for + the standard error stream. + + By default the file name for standard output has the + form job_name.ojob_id and job_name.ojob_id.task_id for + array job tasks (see -t option below). + + Qalter allows changing this option even while the job executes. + The modified parameter will only be in effect + after a restart or migration of the job, however. + + If this option or a corresponding value in qmon is + specified then this value will be passed to defined JSV + instances as parameter with the name o. (see -jsv option + above or find more information concerning JSV in + jsv(1))""") + + if prog in ['qalter']: + self.parser.add_argument('-ot', + metavar='override_tickets', + help="""\ + Available for qalter only. + + Changes the number of override tickets for the specified job. + Requires manager/operator privileges.""") + + if prog in ['qsub', 'qsh', 'qrsh', 'qlogin', 'qalter']: + self.parser.add_argument('-P', + metavar='project_name', + help="""\ + Available for qsub, qsh, qrsh, qlogin and qalter only. + + Specifies the project to which this job is assigned. + The administrator needs to give permission to individual + users to submit jobs to a specific project. (see -aprj option to qconf(1)). + + If this option or a corresponding value in qmon is specified then + this value will be passed to defined JSV + instances as parameter with the name ot. (see -jsv option + above or find more information concerning JSV in + jsv(1))""") + + if prog in ['qsub', 'qsh', 'qrsh', 'qlogin', 'qalter']: + self.parser.add_argument('-p', + metavar='priority', + help="""\ + Available for qsub, qsh, qrsh, qlogin and qalter only. + + Defines or redefines the priority of the job relative to other jobs. + Priority is an integer in the range -1023 + to 1024. The default priority value for jobs is 0. + + Users may only decrease the priority of their jobs. + Grid Engine managers and administrators may also increase + the priority associated with jobs. If a pending job has higher priority, + it is earlier eligible for being dis‐ + patched by the Grid Engine scheduler. + + If this option or a corresponding value in qmon is specified and + the priority is not 0 then this value will be + passed to defined JSV instances as parameter with the name p. + (see -jsv option above or find more information + concerning JSV in jsv(1))""") + + if prog in ['qsub', 'qsh', 'qrsh', 'qlogin', 'qalter']: + self.parser.add_argument('-slot', + metavar='slot', + help="""\ + Available for qsub, qsh, qrsh, qlogin and qalter only. + + Defines or redefines the priority of the job relative to other jobs. + Priority is an integer in the range -1023 + to 1024. The default priority value for jobs is 0. + + Users may only decrease the priority of their jobs. + Grid Engine managers and administrators may also increase + the priority associated with jobs. If a pending job has higher priority, + it is earlier eligible for being dis‐ + patched by the Grid Engine scheduler. + + If this option or a corresponding value in qmon is specified and + the priority is not 0 then this value will be + passed to defined JSV instances as parameter with the name p. + (see -jsv option above or find more information + concerning JSV in jsv(1))""") + + if prog in ['qsub', 'qsh', 'qrsh', 'qlogin', 'qalter']: + self.parser.add_argument('-pe', + nargs=2, + metavar=('parallel_environment', 'n'), + help="""\ + -pe parallel_environment n[-[m]]|[-]m,... + Available for qsub, qsh, qrsh, qlogin and qalter only. + + Parallel programming environment (PE) to instantiate. + For more detail about PEs, please see the sge_types(1). + + Qalter allows changing this option even while the job executes. + The modified parameter will only be in effect + after a restart or migration of the job, however. + + If this option or a corresponding value in qmon is specified + then the parameters pe_name, pe_min and pe_max will + be passed to configured JSV instances where pe_name will be the + name of the parallel environment and the values + pe_min and pe_max represent the values n and m which have been + provided with the -pe option. A missing specifi‐ + cation of m will be expanded as value 9999999 in JSV scripts + and it represents the value infinity. (see -jsv + option above or find more information concerning JSV in jsv(1))""" + ) + + if prog in ['qrsh', 'qlogin']: + self.parser.add_argument('-pty', + choices=yesno, + help="""\ + Available for qrsh and qlogin only. + + -pty yes enforces the job to be started in a pseudo terminal (pty). + If no pty is available, the job start fails. + -pty no enforces the job to be started without a pty. + By default, qrsh without a command and qlogin start the + job in a pty, qrsh with a command starts the job without a pty. + + This parameter is not available in the JSV context. + (see -jsv option above or find more information concerning + JSV in jsv(1))""") + + if prog in ['qsub', 'qrsh', 'qsh', 'qlogin', 'qalter']: + self.parser.add_argument('-q', + nargs='+', + metavar='wc_queue_list', + help="""\ + Available for qsub, qrsh, qsh, qlogin and qalter. + + Defines or redefines a list of cluster queues, + queue domains or queue instances which may be used to execute + this job. Please find a description of wc_queue_list in sge_types(1). + This parameter has all the properties of + a resource request and will be merged with requirements derived from the + -l option described above. + + Qalter allows changing this option even while the job executes. + The modified parameter will only be in effect + after a restart or migration of the job, however. + + If this option or a corresponding value in qmon is specified + the these hard and soft resource requirements will + be passed to defined JSV instances as parameters with the + names q_hard and q_soft. If regular expressions will + be used for resource requests, then these expressions will + be passed as they are. Also shortcut names will not + be expanded. (see -jsv option above or find more information + concerning JSV in jsv(1))""") + + if prog in ['qsub', 'qrsh', 'qsh', 'qlogin', 'qalter']: + self.parser.add_argument('-R', + choices=yesno, + help="""\ + Available for qsub, qrsh, qsh, qlogin and qalter. + + Indicates whether a reservation for this job should be done. + Reservation is never done for immediate jobs, i.e. + jobs submitted using the -now yes option. Please note that + regardless of the reservation request, job reserva‐ + tion might be disabled using max_reservation in sched_conf(5) + and might be limited only to a certain number of + high priority jobs. + + By default jobs are submitted with the -R n option. + + The value specified with this option or the corresponding value + specified in qmon will only be passed to defined + JSV instances if the value is yes. The name of the parameter will be R. + The value will be y also when then long + form yes was specified during submission. + (see -jsv option above or find more information concerning JSV in + jsv(1))""") + + if prog in ['qsub', 'qalter']: + self.parser.add_argument('-r', + choices=yesno, + help="""\ + Available for qsub and qalter only. + + Identifies the ability of a job to be rerun or not. + If the value of -r is 'yes', the job will be rerun if the + job was aborted without leaving a consistent exit state. + (This is typically the case if the node on which the + job is running crashes). If -r is 'no', + the job will not be rerun under any circumstances. + Interactive jobs submitted with qsh, qrsh or qlogin are not rerunnable. + + Qalter allows changing this option even while the job executes. + + The value specified with this option or the corresponding value specified + in qmon will only be passed to defined + JSV instances if the value is yes. The name of the parameter will be r. + The value will be y also when then long + form yes was specified during submission. (see -jsv option above or + find more information concerning JSV in + jsv(1))""") + + if prog in ['qsub', 'qrsh', 'qsh', 'qlogin', 'qalter']: + self.parser.add_argument('-sc', + action='append', + metavar='variable[=value]', + help="""\ + -sc variable[=value],... + Available for qsub, qsh, qrsh, qlogin and qalter only. + + Sets the given name/value pairs as the job's context. Value may be omitted. + Grid Engine replaces the job's pre‐ + viously defined context with the one given as the argument. + Multiple -ac, -dc, and -sc options may be given. + The order is important. + + Contexts provide a way to dynamically attach and remove meta-information + to and from a job. The context vari‐ + ables are not passed to the job's execution context in its environment. + + Qalter allows changing this option even while the job executes. + + The outcome of the evaluation of all -ac, -dc, and -sc options + or corresponding values in qmon is passed to + defined JSV instances as parameter with the name ac. + (see -jsv option above or find more information concerning + JSV in jsv(1))""") + + if prog in ['qsub']: + self.parser.add_argument('-shell', + choices=yesno, + help="""\ + Available only for qsub. + + -shell n causes qsub to execute the command line directly, + as if by exec(2). No command shell will be executed + for the job. This option only applies when -b y is also used. + Without -b y, -shell n has no effect. + + This option can be used to speed up execution as some overhead, + like the shell startup and sourcing the shell + resource files is avoided. + + This option can only be used if no shell-specific command line parsing + is required. If the command line contains + shell syntax, like environment variable substitution or (back) quoting, + a shell must be started. In this case + either do not use the -shell n option or execute the shell as the + command line and pass the path to the exe‐ + cutable as a parameter. + + If a job executed with the -shell n option fails due to a user error, + such as an invalid path to the executable, + the job will enter the error state. + + -shell y cancels the effect of a previous -shell n. Otherwise, it has no effect. + + See -b and -noshell for more information. + + The value specified with this option or the corresponding value + specified in qmon will only be passed to defined + JSV instances if the value is yes. The name of the parameter + will be shell. The value will be y also when then + long form yes was specified during submission. + (see -jsv option above or find more information concerning JSV + in jsv(1))""") + + if prog in ['qsub', 'qrsh', 'qsh', 'qlogin', 'qalter']: + self.parser.add_argument('-soft', + action='store_true', + help="""\ + Available for qsub, qsh, qrsh, qlogin and qalter only. + + Signifies that all resource requirements following in the command + line will be soft requirements and are to be + filled on an "as available" basis. + As Grid Engine scans the command line and script file for + Grid Engine options and parameters, it builds a list + of resources required by the job. All such resource requests are + considered as absolutely essential for the job + to commence. If the -soft option is encountered during the + scan then all following resources are designated as + "soft requirements" for execution, or "nice-to-have, but not essential". + If the -hard flag (see above) is + encountered at a later stage of the scan, all resource requests following + it once again become "essential". The + -hard and -soft options in effect act as "toggles" during the scan. + + If this option or a corresponding value in qmon is + specified then the corresponding -q and -l resource require‐ + ments will be passed to defined JSV instances as parameter + with the names q_soft and l_soft. Find for informa‐ + tion in the sections describing -q and -l. (see -jsv option + above or find more information concerning JSV in + jsv(1))""") + + if prog in ['qsub']: + self.parser.add_argument('-sync', + choices=yesno, + help="""\ + Available for qsub. + + -sync y causes qsub to wait for the job to complete before exiting. + If the job completes successfully, qsub's + exit code will be that of the completed job. + If the job fails to complete successfully, qsub will print out a + error message indicating why the job failed and will have an exit code of 1. + If qsub is interrupted, e.g. with + CTRL-C, before the job completes, the job will be canceled. + With the -sync n option, qsub will exit with an exit code of 0 as soon as the + job is submitted successfully. + -sync n is default for qsub. + If -sync y is used in conjunction with -now y, qsub will behave + as though only -now y were given until the job + has been successfully scheduled, after which time qsub will behave + as though only -sync y were given. + If -sync y is used in conjunction with -t n[-m[:i]], qsub will + wait for all the job's tasks to complete before + exiting. If all the job's tasks complete successfully, qsub's + exit code will be that of the first completed job + tasks with a non-zero exit code, or 0 if all job tasks exited + with an exit code of 0. If any of the job's tasks + fail to complete successfully, qsub will print out an + error message indicating why the job task(s) failed and + will have an exit code of 1. If qsub is interrupted, + e.g. with CTRL-C, before the job completes, all of the + job's tasks will be canceled. + + Information that this switch was specified during + submission is not available in the JSV context. (see -jsv + option above or find more information concerning JSV in jsv(1))""" + ) + + if prog in ['qsub', 'qsh', 'qalter']: + self.parser.add_argument('-S', + metavar='pathname', + help="""\ + -S [[hostname]:]pathname,... + Available for qsub, qsh and qalter. + + Specifies the interpreting shell for the job. + Only one pathname component without a host specifier is valid and + only one path name for a given host is allowed. + Shell paths with host assignments define the interpreting shell + for the job if the host is the execution host. + The shell path without host specification is used if the execu‐ + tion host matches none of the hosts in the list. + + Furthermore, the pathname can be constructed with pseudo + environment variables as described for the -e option + above. + + In the case of qsh the specified shell path is used to + execute the corresponding command interpreter in the + xterm(1) (via its -e option) started on behalf of the interactive job. + Qalter allows changing this option even + while the job executes. The modified parameter will only be in effect + after a restart or migration of the job, + however. + + If this option or a corresponding value in qmon is + specified then this value will be passed to defined JSV + instances as parameter with the name S. (see -jsv option + above or find more information concerning JSV in + jsv(1))""") + + if True or prog in ['qsub', 'qalter']: + self.parser.add_argument('-t', + metavar='n[-m[:s]]', + help="""\ + Available for qsub and qalter only. + + Submits a so called Array Job, i.e. an array of identical + tasks being differentiated only by an index number and + being treated by Grid Engine almost like a series of jobs. + The option argument to -t specifies the number of + array job tasks and the index number which will be associated with the tasks. + The index numbers will be exported + to the job tasks via the environment variable GE_TASK_ID. + The option arguments n, m and s will be available + through the environment variables GE_TASK_FIRST, + GE_TASK_LAST and GE_TASK_STEPSIZE. + + Following restrictions apply to the values n and m: + + 1 <= n <= MIN(2^31-1, max_aj_tasks) + 1 <= m <= MIN(2^31-1, max_aj_tasks) + n <= m + + max_aj_tasks is defined in the cluster configuration (see sge_conf(5)) + + The task id range specified in the option argument may be a single + number, a simple range of the form n-m or a + range with a step size. Hence, the task id range specified by + 2-10:2 would result in the task id indexes 2, 4, + 6, 8, and 10, for a total of 5 identical tasks, each with + the environment variable GE_TASK_ID containing one of + the 5 index numbers. + + All array job tasks inherit the same resource requests and + attribute definitions as specified in the qsub or + qalter command line, except for the -t option. + The tasks are scheduled independently and, provided enough + resources exist, concurrently, very much like separate jobs. + However, an array job or a sub-array there of can + be accessed as a single unit by commands like qmod(1) or qdel(1). + See the corresponding manual pages for fur‐ + ther detail. + + Array jobs are commonly used to execute the same type of operation + on varying input data sets correlated with + the task index number. The number of tasks in a array job is unlimited. + + STDOUT and STDERR of array job tasks will be written into different + files with the default location + + .['e'|'o']'.' + + In order to change this default, the -e and -o options (see above) + can be used together with the pseudo environ‐ + ment variables $HOME, $USER, $JOB_ID, $JOB_NAME, $HOSTNAME, and $GE_TASK_ID. + + Note, that you can use the output redirection to divert the output + of all tasks into the same file, but the + result of this is undefined. + + If this option or a corresponding value in qmon is specified + then this value will be passed to defined JSV + instances as parameters with the name t_min, t_max and t_step + (see -jsv option above or find more information + concerning JSV in jsv(1))""") + + if prog in ['qsub', 'qalter']: + self.parser.add_argument('-tc', + type=int, + metavar='max_running_tasks', + help="""\ + -allow users to limit concurrent array job task + execution. Parameter max_running_tasks specifies maximum number + of simultaneously running tasks. For example we have + running SGE with 10 free slots. We call qsub -t 1-100 -tc + 2 jobscript. Then only 2 tasks will be scheduled to run even + when 8 slots are free.""") + + if prog in ['qsub']: + self.parser.add_argument('-terse', + action='store_true', + help="""\ + Available for qsub only. + + -terse causes the qsub to display only the job-id of the + job being submitted rather than the regular "Your job + ..." string. In case of an error the error is reported on stderr as usual. + This can be helpful for scripts which need to parse qsub output to get the job-id. + + Information that this switch was specified during submission + is not available in the JSV context. (see -jsv + option above or find more information concerning JSV in jsv(1))""" + ) + + if prog in ['qalter']: + self.parser.add_argument('-u', + metavar='username', + help="""\ + -u username,... + Available for qalter only. Changes are only made + on those jobs which were submitted by users specified in the + list of usernames. For managers it is possible to use + the qalter -u '*' command to modify all jobs of all + users. + + If you use the -u switch it is not permitted to + specify an additional wc_job_range_list.""") + + if prog in ['qsub', 'qrsh', 'qalter']: + self.parser.add_argument('-v', + metavar='variable[=value]', + help="""\ + -v variable[=value],... + Available for qsub, qrsh (with command argument) and qalter. + + Defines or redefines the environment + variables to be exported to the execution context of the job. If the -v + option is present Grid Engine will add the + environment variables defined as arguments to the switch and, option‐ + ally, values of specified variables, to the execution context of the job. + + Qalter allows changing this option even while the job executes. + The modified parameter will only be in effect + after a restart or migration of the job, however. + + All environment variables specified with -v, -V or the + DISPLAY variable provided with -display will be exported + to the defined JSV instances only optionally when this is + requested explicitly during the job submission verifi‐ + cation. (see -jsv option above or find more information concerning JSV in jsv(1))""" + ) + + if prog in ['qrsh', 'qmake']: + self.parser.add_argument('-verbose', + action='store_true', + help="""\ + Available only for qrsh and qmake(1). + + Unlike qsh and qlogin, qrsh does not output any + informational messages while establishing the session, compliant + with the standard rsh(1) and rlogin(1) system calls. + If the option -verbose is set, qrsh behaves like the qsh + and qlogin commands, printing information about the + process of establishing the rsh(1) or rlogin(1) session.""") + + if prog in ['qsub', 'qrsh', 'qsh', 'qlogin', 'qalter']: + self.parser.add_argument('-verify', + action='store_true', + help="""\ + Available for qsub, qsh, qrsh, qlogin and qalter. + + Instead of submitting a job, prints detailed information + about the would-be job as though qstat(1) -j were used, + including the effects of command-line parameters and + the external environment.""") + + if prog in ['qsub', 'qrsh', 'qsh', 'qlogin', 'qalter']: + # TODO parse acceptability of qrsh argument properly + self.parser.add_argument('-V', + action='store_true', + help="""\ + Available for qsub, qsh, qrsh with command and qalter. + + Specifies that all environment variables active within + the qsub utility be exported to the context of the job. + + All environment variables specified with -v, -V or the DISPLAY + variable provided with -display will be exported + to the defined JSV instances only optionally when this is + requested explicitly during the job submission verifi‐ + cation. (see -jsv option above or find more information + concerning JSV in jsv(1))""") + + if prog in ['qsub', 'qrsh', 'qsh', 'qlogin', 'qalter']: + self.parser.add_argument('-w', + choices='ewnpv', + help="""\ + Available for qsub, qsh, qrsh, qlogin and qalter. + + Specifies a validation level applied to the job to be submitted + (qsub, qlogin, and qsh) or the specified queued + job (qalter). The information displayed indicates whether the + job can possibly be scheduled assuming an empty + system with no other jobs. Resource requests exceeding the + configured maximal thresholds or requesting unavail‐ + able resource attributes are possible causes for jobs to fail this validation. + + The specifiers e, w, n and v define the following validation modes: + + `e' error - jobs with invalid requests will be + rejected. + `w' warning - only a warning will be displayed + for invalid requests. + `n' none - switches off validation; the default for + qsub, qalter, qrsh, qsh + and qlogin. + `p' poke - does not submit the job but prints a + validation report based on a cluster as is with + all resource utilizations in place. + `v' verify - does not submit the job but prints a + validation report based on an empty cluster. + + Note, that the necessary checks are performance consuming + and hence the checking is switched off by default. It + should also be noted that load values are not taken + into account with the verification since they are assumed to + be too volatile. To cause -w e verification to be passed + at submission time, it is possible to specify non- + volatile values (non-consumables) or maximum values + (consumables) in complex_values.""") + + if prog in ['qsub', 'qrsh', 'qsh', 'qalter']: + self.parser.add_argument('-wd', + metavar='working_dir', + help="""\ + Available for qsub, qsh, qrsh and qalter only. + + Execute the job from the directory specified in working_dir. + This switch will activate Grid Engine's path + aliasing facility, if the corresponding configuration files are present + (see ge_aliases(5)). + + Qalter allows changing this option even while the job executes. + The modified parameter will only be in effect + after a restart or migration of the job, however. + The parameter value will be available in defined JSV + instances as parameter with the name cwd (see -cwd switch above or + find more information concerning JSV in + jsv(1))""") + + if prog in ['qsub', 'qrsh']: + self.parser.add_argument('command', + help="""\ + Available for qsub and qrsh only. + + The job's scriptfile or binary. If not present or if the operand + is the single-character string '-', qsub reads + the script from standard input. + + The command will be available in defined JSV instances as parameter + with the name CMDNAME (see -jsv option above + or find more information concerning JSV in jsv(1))""") + + if prog in ['qsub', 'qrsh', 'qalter']: + self.parser.add_argument('command_args', + nargs='*', + help="""\ + Available for qsub, qrsh and qalter only. + + Arguments to the job. Not valid if the script is entered from standard input. + + Qalter allows changing this option even while the job executes. + The modified parameter will only be in effect + after a restart or migration of the job, however. + + The number of command arguments is provided to configured + JSV instances as parameter with the name CMDARGS. Also + the argument values can by accessed. Argument names + have the format CMDARG where is a integer + between 0 and CMDARGS - 1. (see -jsv option above or + find more information concerning JSV in jsv(1))""") + + if prog in ['qsh']: + self.parser.add_argument('xterm_args', + nargs='*', + help="""\ + Available for qsh only. + + Arguments to the xterm(1) executable, as defined in the configuration. + For details, refer to ge_conf(5)). + + Information concerning xterm_args will be available in JSV context as + parameters with the name CMDARGS and + CMDARG. Find more information above in section command_args. + (see -jsv option above or find more infor‐ + mation concerning JSV in jsv(1))""") + + # END SGE OPTION PARSER + + # Initialize with defaults + self.parse('-cwd -V -j y -terse -pe lammpi 1 echo') + + def parse(self, inputstring=''): + """Helper method: parses a string""" + return self.parse_args(inputstring.split()) + + def parse_args(self, args=None): + """Helper method: parses a list""" + if args is None: + self.args = self.parser.parse_args() # default is sys.argv[1:] + else: + self.args = self.parser.parse_args(args) + return self.args + + def write_qsub_script(self, filename, echo=False): + """ + Writes the entire command line to a qsub script + + filename: name of file to write + echo : echo contents of script to stdout. Default: False + """ + + buf = ['#!/usr/bin/env qsub', '# Written using SGE module'] + + for option, value in self.args.__dict__.items(): + if value is True: + value = '' + + if option not in ['command', 'command_args', 'xterm_args']: + if isinstance(value, list): + val = ' '.join(value) + else: + val = str(value) + + buf.append(' '.join(['#', '-' + option, val])) + + args = getattr(self.args, 'command_args', []) + args = getattr(self.args, 'xterm_args', args) + + buf.append(' '.join([self.args.command] + args)) + + if echo: + print('\n'.join(buf)) + + f = open(filename, 'w') + f.write('\n'.join(buf)) + f.close() + + def execute(self, mode='local', path=''): + """ + Executes qsub + + known modes: local - run locally + echo - echoes out execution string only + + path: path to qsub/... executable: Default = nothing + """ + + # Form execution string + + import os + program = os.path.join(path, self.prog) + options = [] + + for option, value in self.args.__dict__.items(): + if value is True: + value = '' + + if isinstance(value, list): + val = ' '.join(value) + else: + val = str(value) + + if option not in ['command', 'command_args', 'xterm_args']: + options.append('-' + option + ' ' + val) + + args = getattr(self.args, 'command_args', []) + args = getattr(self.args, 'xterm_args', args) + + exestring = ' '.join([program] + options + [self.args.command] + args) + exestring = exestring.replace('-pe lammpi 1', '') + exestring = exestring.replace('-slot', '-pe make') + exestring = exestring.replace('-ll ', '-l ') + exestring = exestring.replace('-t 0', '') + # exestring = exestring.replace('-j y','') + + if mode == 'echo': + return (exestring) + elif mode == 'local': + import subprocess + p = subprocess.Popen(exestring, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + shell=True) + print(p.stdout.read()) + + +if __name__ == '__main__': + print('Attempting to validate qsub arguments using argparse') + o = qsubOptions() + o.parse_args() + o.args.t = '1-1000' + print('I will now print the script') + o.write_qsub_script('/dev/null', echo=True) + print('*' * 70) + print('I will now print the command line') + o.execute(mode='echo') diff --git a/vendor/lowrisc_ip/util/uvmdvgen/doc/index.md b/vendor/lowrisc_ip/util/uvmdvgen/doc/index.md index fe401495..66751f68 100644 --- a/vendor/lowrisc_ip/util/uvmdvgen/doc/index.md +++ b/vendor/lowrisc_ip/util/uvmdvgen/doc/index.md @@ -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.