diff --git a/vendor/lowrisc_ip.lock.hjson b/vendor/lowrisc_ip.lock.hjson
index 5666f668..600db907 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: d78da129c7f2b115ccabd1c3af199e0e5812f365
+ rev: c91b50f357a76dae2ada104e397f6a91f72a33da
}
}
diff --git a/vendor/lowrisc_ip.vendor.hjson b/vendor/lowrisc_ip.vendor.hjson
index 3e3710da..803140f6 100644
--- a/vendor/lowrisc_ip.vendor.hjson
+++ b/vendor/lowrisc_ip.vendor.hjson
@@ -11,19 +11,20 @@
}
mapping: [
- {from: "hw/dv/sv/common_ifs", to: "common_ifs"},
- {from: "hw/dv/sv/csr_utils", to: "csr_utils"},
- {from: "hw/dv/sv/dv_lib", to: "dv_lib"},
- {from: "hw/dv/sv/dv_utils", to: "dv_utils"},
- {from: "hw/dv/verilator", to: "dv_verilator"},
+ {from: "hw/dv/sv/common_ifs", to: "common_ifs"},
+ {from: "hw/dv/sv/csr_utils", to: "csr_utils"},
+ {from: "hw/dv/sv/dv_lib", to: "dv_lib"},
+ {from: "hw/dv/sv/dv_utils", to: "dv_utils"},
+ {from: "hw/dv/sv/dv_base_reg", to: "dv_base_reg"},
+ {from: "hw/dv/verilator", to: "dv_verilator"},
- {from: "hw/ip/prim", to: "prim"},
- {from: "hw/ip/prim_generic", to: "prim_generic"},
- {from: "hw/ip/prim_xilinx", to: "prim_xilinx"},
+ {from: "hw/ip/prim", to: "prim"},
+ {from: "hw/ip/prim_generic", to: "prim_generic"},
+ {from: "hw/ip/prim_xilinx", to: "prim_xilinx"},
- {from: "hw/lint", to: "lint"},
+ {from: "hw/lint", to: "lint"},
- {from: "util/dvsim", to: "dvsim"},
- {from: "util/uvmdvgen", to: "uvmdvgen"},
+ {from: "util/dvsim", to: "dvsim"},
+ {from: "util/uvmdvgen", to: "uvmdvgen"},
]
}
diff --git a/vendor/lowrisc_ip/common_ifs/clk_rst_if.sv b/vendor/lowrisc_ip/common_ifs/clk_rst_if.sv
index 31382ecc..394e34f7 100644
--- a/vendor/lowrisc_ip/common_ifs/clk_rst_if.sv
+++ b/vendor/lowrisc_ip/common_ifs/clk_rst_if.sv
@@ -42,6 +42,7 @@ interface clk_rst_if #(
int clk_hi_ps; // half period hi in ps
int clk_lo_ps; // half period lo in ps
int jitter_chance_pc = 0; // jitter chance in percentage on clock edge - disabled by default
+ bit sole_clock = 1'b0; // if true, this is the only clock in the system
// use IfName as a part of msgs to indicate which clk_rst_vif instance
string msg_id = {"clk_rst_if::", IfName};
@@ -129,6 +130,13 @@ interface clk_rst_if #(
jitter_chance_pc = jitter_chance;
endfunction
+ // Set whether this is the only clock in the system. If true, various bits of timing randomisation
+ // are disabled. If there's no other clock to (de)synchronise with, this should not weaken the
+ // test at all.
+ function automatic void set_sole_clock(bit is_sole = 1'b1);
+ sole_clock = is_sole;
+ endfunction
+
// start / ungate the clk
task automatic start_clk(bit wait_for_posedge = 1'b0);
clk_gate = 1'b0;
@@ -207,10 +215,27 @@ interface clk_rst_if #(
// clk gen
initial begin
- // start driving clk only after the first por reset assertion
- wait_for_reset(.wait_posedge(1'b0));
- #1ps o_clk = 1'b0;
- #($urandom_range(0, 10) * 1ps);
+ // start driving clk only after the first por reset assertion. The fork/join means that we'll
+ // wait a whole number of clock periods, which means it's possible for the clock to synchronise
+ // with the "expected" timestamps.
+ bit done = 1'b0;
+ fork
+ begin
+ wait_for_reset(.wait_posedge(1'b0));
+
+ // Wait a short time after reset before starting to drive the clock.
+ #1ps;
+ o_clk = 1'b0;
+
+ done = 1'b1;
+ end
+ while (!done) #(clk_period_ps * 1ps);
+ join
+
+ // If there might be multiple clocks in the system, wait another (randomised) short time to
+ // desynchronise.
+ if (!sole_clock) #($urandom_range(0, clk_period_ps) * 1ps);
+
forever begin
if (recompute) begin
clk_hi_ps = clk_period_ps * duty_cycle / 100;
diff --git a/vendor/lowrisc_ip/csr_utils/csr_utils.core b/vendor/lowrisc_ip/csr_utils/csr_utils.core
index adec6549..0b2cbf41 100644
--- a/vendor/lowrisc_ip/csr_utils/csr_utils.core
+++ b/vendor/lowrisc_ip/csr_utils/csr_utils.core
@@ -9,9 +9,9 @@ filesets:
files_dv:
depend:
- lowrisc:dv:dv_utils
+ - lowrisc:dv:dv_base_reg
files:
- csr_utils_pkg.sv
- - csr_excl_item.sv: {is_include_file: true}
- csr_seq_lib.sv: {is_include_file: true}
file_type: systemVerilogSource
diff --git a/vendor/lowrisc_ip/csr_utils/csr_utils_pkg.sv b/vendor/lowrisc_ip/csr_utils/csr_utils_pkg.sv
index dcbcf571..bb0252ff 100644
--- a/vendor/lowrisc_ip/csr_utils/csr_utils_pkg.sv
+++ b/vendor/lowrisc_ip/csr_utils/csr_utils_pkg.sv
@@ -6,6 +6,7 @@ package csr_utils_pkg;
// dep packages
import uvm_pkg::*;
import dv_utils_pkg::*;
+ import dv_base_reg_pkg::*;
// macro includes
`include "uvm_macros.svh"
@@ -20,9 +21,6 @@ package csr_utils_pkg;
bit under_reset = 0;
int max_outstanding_accesses = 100;
- // global paramters for number of csr tests (including memory test)
- parameter uint NUM_CSR_TESTS = 4;
-
// csr field struct - hold field specific params
typedef struct {
uvm_reg csr;
@@ -31,29 +29,6 @@ package csr_utils_pkg;
uint shift;
} csr_field_s;
- // csr test types
- typedef enum bit [NUM_CSR_TESTS-1:0] {
- CsrInvalidTest = 4'h0,
- // elementary test types
- CsrHwResetTest = 4'h1,
- CsrRwTest = 4'h2,
- CsrBitBashTest = 4'h4,
- CsrAliasingTest = 4'h8,
- // combinational test types (combinations of the above), used for exclusion tagging
- CsrNonInitTests = 4'he, // all but HwReset test
- CsrAllTests = 4'hf // all tests
- } csr_test_type_e;
-
- // csr exclusion indications
- typedef enum bit [2:0] {
- CsrNoExcl = 3'b000, // no exclusions
- CsrExclInitCheck = 3'b001, // exclude csr from init val check
- CsrExclWriteCheck = 3'b010, // exclude csr from write-read check
- CsrExclCheck = 3'b011, // exclude csr from init or write-read check
- CsrExclWrite = 3'b100, // exclude csr from write
- CsrExclAll = 3'b111 // exclude csr from init or write or write-read check
- } csr_excl_type_e;
-
function automatic void increment_outstanding_access();
outstanding_accesses++;
endfunction
@@ -252,10 +227,14 @@ package csr_utils_pkg;
input uvm_check_e check = UVM_CHECK,
input uvm_path_e path = UVM_DEFAULT_PATH,
input bit blocking = default_csr_blocking,
+ input bit backdoor = 0,
input uint timeout_ns = default_timeout_ns,
input bit predict = 0,
input uvm_reg_map map = null);
- if (blocking) begin
+ if (backdoor) begin
+ csr_poke(csr, value, check);
+ if (predict) void'(csr.predict(.value(value), .kind(UVM_PREDICT_DIRECT)));
+ end else if (blocking) begin
csr_wr_sub(csr, value, check, path, timeout_ns, map);
if (predict) void'(csr.predict(.value(value), .kind(UVM_PREDICT_WRITE)));
end else begin
@@ -304,14 +283,30 @@ package csr_utils_pkg;
join
endtask
+ // backdoor write csr
+ task automatic csr_poke(input uvm_reg csr,
+ input uvm_reg_data_t value,
+ input uvm_check_e check = UVM_CHECK);
+ uvm_status_e status;
+ string msg_id = {csr_utils_pkg::msg_id, "::csr_poke"};
+
+ csr.poke(.status(status), .value(value));
+ if (check == UVM_CHECK) begin
+ `DV_CHECK_EQ(status, UVM_IS_OK, "", error, msg_id)
+ end
+ endtask
+
task automatic csr_rd(input uvm_object ptr, // accept reg or field
output uvm_reg_data_t value,
input uvm_check_e check = UVM_CHECK,
input uvm_path_e path = UVM_DEFAULT_PATH,
input bit blocking = default_csr_blocking,
+ input bit backdoor = 0,
input uint timeout_ns = default_timeout_ns,
input uvm_reg_map map = null);
- if (blocking) begin
+ if (backdoor) begin
+ csr_peek(ptr, value, check);
+ end else if (blocking) begin
csr_rd_sub(ptr, value, check, path, timeout_ns, map);
end else begin
fork
@@ -362,10 +357,41 @@ package csr_utils_pkg;
join
endtask
+ // backdoor read csr
+ // uvm_reg::peek() returns a 2-state value, directly get data from hdl path
+ task automatic csr_peek(input uvm_object ptr,
+ output uvm_reg_data_t value,
+ input uvm_check_e check = UVM_CHECK);
+ string msg_id = {csr_utils_pkg::msg_id, "::csr_peek"};
+ csr_field_s csr_or_fld = decode_csr_or_field(ptr);
+ uvm_reg csr = csr_or_fld.csr;
+
+ if (csr.has_hdl_path()) begin
+ uvm_hdl_path_concat paths[$];
+
+ csr.get_full_hdl_path(paths);
+ foreach (paths[0].slices[i]) begin
+ uvm_reg_data_t field_val;
+ if (uvm_hdl_read(paths[0].slices[i].path, field_val)) begin
+ if (check == UVM_CHECK) `DV_CHECK_EQ($isunknown(value), 0, "", error, msg_id)
+ value |= field_val << paths[0].slices[i].offset;
+ end else begin
+ `uvm_fatal(msg_id, $sformatf("uvm_hdl_read failed for %0s", csr.get_full_name()))
+ end
+ end
+ end else begin
+ `uvm_fatal(msg_id, $sformatf("No backdoor defined for %0s", csr.get_full_name()))
+ end
+
+ // if it's field, only return field value
+ if (csr_or_fld.field != null) value = get_field_val(csr_or_fld.field, value);
+ endtask
+
task automatic csr_rd_check(input uvm_object ptr,
input uvm_check_e check = UVM_CHECK,
input uvm_path_e path = UVM_DEFAULT_PATH,
input bit blocking = default_csr_blocking,
+ input bit backdoor = 0,
input uint timeout_ns = default_timeout_ns,
input bit compare = 1'b1,
input bit compare_vs_ral = 1'b0,
@@ -383,10 +409,9 @@ package csr_utils_pkg;
uvm_reg_data_t exp;
string msg_id = {csr_utils_pkg::msg_id, "::csr_rd_check"};
- increment_outstanding_access();
csr_or_fld = decode_csr_or_field(ptr);
- csr_rd(.ptr(ptr), .value(obs), .check(check), .path(path),
+ csr_rd(.ptr(ptr), .value(obs), .check(check), .path(path), .backdoor(backdoor),
.blocking(1), .timeout_ns(timeout_ns), .map(map));
// get mirrored value after read to make sure the read reg access is updated
@@ -401,7 +426,6 @@ package csr_utils_pkg;
`DV_CHECK_EQ(obs, exp, {"Regname: ", ptr.get_full_name(), " ", err_msg},
error, msg_id)
end
- decrement_outstanding_access();
end
join_none
if (blocking) wait fork;
@@ -429,6 +453,7 @@ package csr_utils_pkg;
input uint spinwait_delay_ns = 0,
input uint timeout_ns = default_spinwait_timeout_ns,
input compare_op_e compare_op = CompareOpEq,
+ input bit backdoor = 0,
input uvm_verbosity verbosity = UVM_HIGH);
fork
begin : isolation_fork
@@ -437,11 +462,12 @@ package csr_utils_pkg;
string msg_id = {csr_utils_pkg::msg_id, "::csr_spinwait"};
csr_or_fld = decode_csr_or_field(ptr);
+ if (backdoor && spinwait_delay_ns == 0) spinwait_delay_ns = 1;
fork
while (!under_reset) begin
if (spinwait_delay_ns) #(spinwait_delay_ns * 1ns);
csr_rd(.ptr(ptr), .value(read_data), .check(check), .path(path),
- .blocking(1), .map(map));
+ .blocking(1), .map(map), .backdoor(backdoor));
`uvm_info(msg_id, $sformatf("ptr %0s == 0x%0h",
ptr.get_full_name(), read_data), verbosity)
case (compare_op)
@@ -566,8 +592,6 @@ package csr_utils_pkg;
join
endtask : mem_wr_sub
- `include "csr_excl_item.sv"
-
// Fields could be excluded from writes & reads - This function zeros out the excluded fields
function automatic uvm_reg_data_t get_mask_excl_fields(uvm_reg csr,
csr_excl_type_e csr_excl_type,
diff --git a/vendor/lowrisc_ip/csr_utils/csr_excl_item.sv b/vendor/lowrisc_ip/dv_base_reg/csr_excl_item.sv
similarity index 100%
rename from vendor/lowrisc_ip/csr_utils/csr_excl_item.sv
rename to vendor/lowrisc_ip/dv_base_reg/csr_excl_item.sv
diff --git a/vendor/lowrisc_ip/dv_lib/dv_base_mem.sv b/vendor/lowrisc_ip/dv_base_reg/dv_base_mem.sv
similarity index 100%
rename from vendor/lowrisc_ip/dv_lib/dv_base_mem.sv
rename to vendor/lowrisc_ip/dv_base_reg/dv_base_mem.sv
diff --git a/vendor/lowrisc_ip/dv_base_reg/dv_base_reg.core b/vendor/lowrisc_ip/dv_base_reg/dv_base_reg.core
new file mode 100644
index 00000000..ff746ae5
--- /dev/null
+++ b/vendor/lowrisc_ip/dv_base_reg/dv_base_reg.core
@@ -0,0 +1,25 @@
+CAPI=2:
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+name: "lowrisc:dv:dv_base_reg"
+description: "DV base reg/mem library"
+
+filesets:
+ files_dv:
+ depend:
+ - lowrisc:dv:dv_utils
+ files:
+ - dv_base_reg_pkg.sv
+ - csr_excl_item.sv: {is_include_file: true}
+ - dv_base_reg_field.sv: {is_include_file: true}
+ - dv_base_reg.sv: {is_include_file: true}
+ - dv_base_mem.sv: {is_include_file: true}
+ - dv_base_reg_block.sv: {is_include_file: true}
+ - dv_base_reg_map.sv: {is_include_file: true}
+ file_type: systemVerilogSource
+
+targets:
+ default:
+ filesets:
+ - files_dv
diff --git a/vendor/lowrisc_ip/dv_lib/dv_base_reg.sv b/vendor/lowrisc_ip/dv_base_reg/dv_base_reg.sv
similarity index 90%
rename from vendor/lowrisc_ip/dv_lib/dv_base_reg.sv
rename to vendor/lowrisc_ip/dv_base_reg/dv_base_reg.sv
index 39139403..3ad45eeb 100644
--- a/vendor/lowrisc_ip/dv_lib/dv_base_reg.sv
+++ b/vendor/lowrisc_ip/dv_base_reg/dv_base_reg.sv
@@ -4,6 +4,11 @@
//
// base register class which will be used to generate the reg
class dv_base_reg extends uvm_reg;
+ // external reg doesn't have storage in reg module, which may connect to some combinational logic
+ // hence, backdoor write isn't available
+ local bit is_ext_reg;
+
+ local dv_base_reg locked_regs[$];
function new(string name = "",
int unsigned n_bits,
@@ -11,9 +16,6 @@ class dv_base_reg extends uvm_reg;
super.new(name, n_bits, has_coverage);
endfunction : new
-
- local dv_base_reg locked_regs[$];
-
function void get_dv_base_reg_fields(ref dv_base_reg_field dv_fields[$]);
uvm_reg_field ral_fields[$];
get_fields(ral_fields);
@@ -80,4 +82,12 @@ class dv_base_reg extends uvm_reg;
end
endtask
+ virtual function void set_is_ext_reg(bit is_ext);
+ is_ext_reg = is_ext;
+ endfunction
+
+ virtual function bit get_is_ext_reg();
+ return is_ext_reg;
+ endfunction
+
endclass
diff --git a/vendor/lowrisc_ip/dv_lib/dv_base_reg_block.sv b/vendor/lowrisc_ip/dv_base_reg/dv_base_reg_block.sv
similarity index 96%
rename from vendor/lowrisc_ip/dv_lib/dv_base_reg_block.sv
rename to vendor/lowrisc_ip/dv_base_reg/dv_base_reg_block.sv
index 5f72678d..c0bbcc62 100644
--- a/vendor/lowrisc_ip/dv_lib/dv_base_reg_block.sv
+++ b/vendor/lowrisc_ip/dv_base_reg/dv_base_reg_block.sv
@@ -14,7 +14,7 @@ class dv_base_reg_block extends uvm_reg_block;
// provide build function to supply base addr
virtual function void build(uvm_reg_addr_t base_addr,
- csr_utils_pkg::csr_excl_item csr_excl = null);
+ csr_excl_item csr_excl = null);
`uvm_fatal(`gfn, "this method is not supposed to be called directly!")
endfunction
diff --git a/vendor/lowrisc_ip/dv_lib/dv_base_reg_field.sv b/vendor/lowrisc_ip/dv_base_reg/dv_base_reg_field.sv
similarity index 80%
rename from vendor/lowrisc_ip/dv_lib/dv_base_reg_field.sv
rename to vendor/lowrisc_ip/dv_base_reg/dv_base_reg_field.sv
index 021d1edf..6bcb400f 100644
--- a/vendor/lowrisc_ip/dv_lib/dv_base_reg_field.sv
+++ b/vendor/lowrisc_ip/dv_base_reg/dv_base_reg_field.sv
@@ -11,11 +11,15 @@ class dv_base_reg_field extends uvm_reg_field;
// when use UVM_PREDICT_WRITE and the CSR access is WO, this function will return the default
// val of the register, rather than the written value
+ // TODO, need to handle predict value when backdoor write happens WO reg
+ // 1. for read, design ties the read data to default value
+ // 2. when backdoor write updates internal reg, backdoor read can get the written value, but
+ // frontdoor read always returns the default value.
virtual function uvm_reg_data_t XpredictX(uvm_reg_data_t cur_val,
uvm_reg_data_t wr_val,
uvm_reg_map map);
- if (get_access(map) == "WO") return cur_val;
+ if (get_access(map) == "WO") return get_reset();
else return super.XpredictX(cur_val, wr_val, map);
endfunction
diff --git a/vendor/lowrisc_ip/dv_lib/dv_base_reg_map.sv b/vendor/lowrisc_ip/dv_base_reg/dv_base_reg_map.sv
similarity index 100%
rename from vendor/lowrisc_ip/dv_lib/dv_base_reg_map.sv
rename to vendor/lowrisc_ip/dv_base_reg/dv_base_reg_map.sv
diff --git a/vendor/lowrisc_ip/dv_base_reg/dv_base_reg_pkg.sv b/vendor/lowrisc_ip/dv_base_reg/dv_base_reg_pkg.sv
new file mode 100644
index 00000000..a5018ce3
--- /dev/null
+++ b/vendor/lowrisc_ip/dv_base_reg/dv_base_reg_pkg.sv
@@ -0,0 +1,49 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+package dv_base_reg_pkg;
+ // dep packages
+ import uvm_pkg::*;
+ import dv_utils_pkg::*;
+
+ // macro includes
+ `include "uvm_macros.svh"
+ `include "dv_macros.svh"
+
+ // global paramters for number of csr tests (including memory test)
+ parameter uint NUM_CSR_TESTS = 4;
+
+ // csr exclusion indications
+ typedef enum bit [2:0] {
+ CsrNoExcl = 3'b000, // no exclusions
+ CsrExclInitCheck = 3'b001, // exclude csr from init val check
+ CsrExclWriteCheck = 3'b010, // exclude csr from write-read check
+ CsrExclCheck = 3'b011, // exclude csr from init or write-read check
+ CsrExclWrite = 3'b100, // exclude csr from write
+ CsrExclAll = 3'b111 // exclude csr from init or write or write-read check
+ } csr_excl_type_e;
+
+ // csr test types
+ typedef enum bit [NUM_CSR_TESTS-1:0] {
+ CsrInvalidTest = 4'h0,
+ // elementary test types
+ CsrHwResetTest = 4'h1,
+ CsrRwTest = 4'h2,
+ CsrBitBashTest = 4'h4,
+ CsrAliasingTest = 4'h8,
+ // combinational test types (combinations of the above), used for exclusion tagging
+ CsrNonInitTests = 4'he, // all but HwReset test
+ CsrAllTests = 4'hf // all tests
+ } csr_test_type_e;
+
+ // package sources
+ // base ral
+ `include "csr_excl_item.sv"
+ `include "dv_base_reg_field.sv"
+ `include "dv_base_reg.sv"
+ `include "dv_base_mem.sv"
+ `include "dv_base_reg_block.sv"
+ `include "dv_base_reg_map.sv"
+
+endpackage
diff --git a/vendor/lowrisc_ip/dv_lib/dv_base_env_cfg.sv b/vendor/lowrisc_ip/dv_lib/dv_base_env_cfg.sv
index 1360ff64..0512e1e8 100644
--- a/vendor/lowrisc_ip/dv_lib/dv_base_env_cfg.sv
+++ b/vendor/lowrisc_ip/dv_lib/dv_base_env_cfg.sv
@@ -15,6 +15,7 @@ class dv_base_env_cfg #(type RAL_T = dv_base_reg_block) extends uvm_object;
// reg model & q of valid csr addresses
RAL_T ral;
+ dv_base_reg_block ral_models[$];
bit [TL_AW-1:0] csr_addrs[$];
addr_range_t mem_ranges[$];
@@ -64,6 +65,7 @@ class dv_base_env_cfg #(type RAL_T = dv_base_reg_block) extends uvm_object;
ral = RAL_T::type_id::create("ral");
ral.build(this.csr_base_addr, null);
apply_ral_fixes();
+ ral_models.push_back(ral);
end
endfunction
diff --git a/vendor/lowrisc_ip/dv_lib/dv_base_vseq.sv b/vendor/lowrisc_ip/dv_lib/dv_base_vseq.sv
index 6b0e8c5b..7cade3bf 100644
--- a/vendor/lowrisc_ip/dv_lib/dv_base_vseq.sv
+++ b/vendor/lowrisc_ip/dv_lib/dv_base_vseq.sv
@@ -71,7 +71,9 @@ class dv_base_vseq #(type RAL_T = dv_base_reg_block,
cfg.clk_rst_vif.apply_reset();
csr_utils_pkg::reset_deasserted();
end
- if (cfg.has_ral) ral.reset(kind);
+ if (cfg.has_ral) begin
+ foreach (cfg.ral_models[i]) cfg.ral_models[i].reset(kind);
+ end
endtask
virtual task wait_for_reset(string reset_kind = "HARD",
@@ -167,7 +169,7 @@ class dv_base_vseq #(type RAL_T = dv_base_reg_block,
// run write-only sequence to randomize the csr values
m_csr_write_seq = csr_write_seq::type_id::create("m_csr_write_seq");
- m_csr_write_seq.models.push_back(ral);
+ m_csr_write_seq.models = cfg.ral_models;
m_csr_write_seq.set_csr_excl_item(csr_excl);
m_csr_write_seq.external_checker = cfg.en_scb;
if (!enable_asserts_in_hw_reset_rand_wr) $assertoff;
@@ -184,7 +186,7 @@ class dv_base_vseq #(type RAL_T = dv_base_reg_block,
// create base csr seq and pass our ral
m_csr_seq = csr_base_seq::type_id::create("m_csr_seq");
m_csr_seq.num_test_csrs = num_test_csrs;
- m_csr_seq.models.push_back(ral);
+ m_csr_seq.models = cfg.ral_models;
m_csr_seq.set_csr_excl_item(csr_excl);
m_csr_seq.external_checker = cfg.en_scb;
m_csr_seq.start(null);
diff --git a/vendor/lowrisc_ip/dv_lib/dv_lib.core b/vendor/lowrisc_ip/dv_lib/dv_lib.core
index 73c7fe16..2d18f535 100644
--- a/vendor/lowrisc_ip/dv_lib/dv_lib.core
+++ b/vendor/lowrisc_ip/dv_lib/dv_lib.core
@@ -10,15 +10,10 @@ filesets:
depend:
- lowrisc:dv:dv_utils
- lowrisc:dv:csr_utils
+ - lowrisc:dv:dv_base_reg
files:
- dv_lib_pkg.sv
- - dv_base_reg_field.sv: {is_include_file: true}
- - dv_base_reg.sv: {is_include_file: true}
- - dv_base_mem.sv: {is_include_file: true}
- - dv_base_reg_block.sv: {is_include_file: true}
- - dv_base_reg_map.sv: {is_include_file: true}
-
- dv_base_agent_cfg.sv: {is_include_file: true}
- dv_base_agent_cov.sv: {is_include_file: true}
- dv_base_monitor.sv: {is_include_file: true}
diff --git a/vendor/lowrisc_ip/dv_lib/dv_lib_pkg.sv b/vendor/lowrisc_ip/dv_lib/dv_lib_pkg.sv
index 0036c4ec..034b4995 100644
--- a/vendor/lowrisc_ip/dv_lib/dv_lib_pkg.sv
+++ b/vendor/lowrisc_ip/dv_lib/dv_lib_pkg.sv
@@ -8,6 +8,7 @@ package dv_lib_pkg;
import top_pkg::*;
import dv_utils_pkg::*;
import csr_utils_pkg::*;
+ import dv_base_reg_pkg::*;
// macro includes
`include "uvm_macros.svh"
@@ -17,13 +18,6 @@ package dv_lib_pkg;
string msg_id = "dv_lib_pkg";
// package sources
- // base ral
- `include "dv_base_reg_field.sv"
- `include "dv_base_reg.sv"
- `include "dv_base_mem.sv"
- `include "dv_base_reg_block.sv"
- `include "dv_base_reg_map.sv"
-
// base agent
`include "dv_base_agent_cfg.sv"
`include "dv_base_agent_cov.sv"
diff --git a/vendor/lowrisc_ip/dvsim/Deploy.py b/vendor/lowrisc_ip/dvsim/Deploy.py
index 7f958f41..b0dde6ac 100644
--- a/vendor/lowrisc_ip/dvsim/Deploy.py
+++ b/vendor/lowrisc_ip/dvsim/Deploy.py
@@ -257,8 +257,9 @@ class Deploy():
def set_status(self):
self.status = 'P'
if self.dry_run is False:
+ seen_fail_pattern = False
for fail_pattern in self.fail_patterns:
- # Return error messege with the following 4 lines.
+ # Return error message with the following 4 lines.
grep_cmd = "grep -m 1 -A 4 -E \'" + fail_pattern + "\' " + self.log
(status, rslt) = subprocess.getstatusoutput(grep_cmd)
if rslt:
@@ -266,12 +267,13 @@ class Deploy():
self.fail_msg += msg
log.log(VERBOSE, msg)
self.status = 'F'
+ seen_fail_pattern = True
break
# If fail patterns were not encountered, but the job returned with non-zero exit code
# for whatever reason, then show the last 10 lines of the log as the failure message,
# which might help with the debug.
- if self.process.returncode != 0 and not self.fail_msg:
+ if self.process.returncode != 0 and not seen_fail_pattern:
msg = "Last 10 lines of the log:
\n"
self.fail_msg += msg
log.log(VERBOSE, msg)
diff --git a/vendor/lowrisc_ip/dvsim/SimCfg.py b/vendor/lowrisc_ip/dvsim/SimCfg.py
index 3f8a6f09..e6a23618 100644
--- a/vendor/lowrisc_ip/dvsim/SimCfg.py
+++ b/vendor/lowrisc_ip/dvsim/SimCfg.py
@@ -90,8 +90,7 @@ class SimCfg(FlowCfg):
self.tool = args.tool
self.build_opts = []
self.build_opts.extend(args.build_opts)
- self.en_build_modes = []
- self.en_build_modes.extend(args.build_modes)
+ self.en_build_modes = args.build_modes.copy()
self.run_opts = []
self.run_opts.extend(args.run_opts)
self.en_run_modes = []
@@ -223,7 +222,7 @@ class SimCfg(FlowCfg):
# Use the default build mode for tests that do not specify it
if not hasattr(self, "build_mode"):
- setattr(self, "build_mode", "default")
+ self.build_mode = 'default'
self._process_exports()
@@ -257,16 +256,12 @@ class SimCfg(FlowCfg):
def _create_objects(self):
# Create build and run modes objects
- build_modes = Modes.create_modes(BuildModes,
- getattr(self, "build_modes"))
- setattr(self, "build_modes", build_modes)
-
- run_modes = Modes.create_modes(RunModes, getattr(self, "run_modes"))
- setattr(self, "run_modes", run_modes)
+ self.build_modes = Modes.create_modes(BuildModes, self.build_modes)
+ self.run_modes = Modes.create_modes(RunModes, self.run_modes)
# Walk through build modes enabled on the CLI and append the opts
for en_build_mode in self.en_build_modes:
- build_mode_obj = Modes.find_mode(en_build_mode, build_modes)
+ build_mode_obj = Modes.find_mode(en_build_mode, self.build_modes)
if build_mode_obj is not None:
self.build_opts.extend(build_mode_obj.build_opts)
self.run_opts.extend(build_mode_obj.run_opts)
@@ -278,7 +273,7 @@ class SimCfg(FlowCfg):
# Walk through run modes enabled on the CLI and append the opts
for en_run_mode in self.en_run_modes:
- run_mode_obj = Modes.find_mode(en_run_mode, run_modes)
+ run_mode_obj = Modes.find_mode(en_run_mode, self.run_modes)
if run_mode_obj is not None:
self.run_opts.extend(run_mode_obj.run_opts)
else:
@@ -288,8 +283,7 @@ class SimCfg(FlowCfg):
sys.exit(1)
# Create tests from given list of items
- tests = Tests.create_tests(getattr(self, "tests"), self)
- setattr(self, "tests", tests)
+ self.tests = Tests.create_tests(self.tests, self)
# Regressions
# Parse testplan if provided.
@@ -299,9 +293,8 @@ class SimCfg(FlowCfg):
self.regressions.extend(self.testplan.get_milestone_regressions())
# Create regressions
- regressions = Regressions.create_regressions(
- getattr(self, "regressions"), self, tests)
- setattr(self, "regressions", regressions)
+ self.regressions = Regressions.create_regressions(self.regressions,
+ self, self.tests)
def _print_list(self):
for list_item in self.list_items:
@@ -417,6 +410,43 @@ class SimCfg(FlowCfg):
create_link_dirs_cmd)
sys.exit(1)
+ def _expand_run_list(self, build_map):
+ '''Generate a list of tests to be run
+
+ For each test in tests, we add it test.reseed times. The ordering is
+ interleaved so that we run through all of the tests as soon as
+ possible. If there are multiple tests and they have different reseed
+ values, they are "fully interleaved" at the start (so if there are
+ tests A, B with reseed values of 5 and 2, respectively, then the list
+ will be ABABAAA).
+
+ build_map is a dictionary from build name to a CompileSim object. Each
+ test is added to the CompileSim item that it depends on (signifying
+ that the test should be built once the build on which it depends is
+ done).
+
+ cfg is a SimCfg object, passed to the RunTest constructor.
+
+ '''
+ tagged = []
+ for test in self.run_list:
+ for idx in range(test.reseed):
+ tagged.append((idx,
+ test,
+ RunTest(idx, test, self)))
+
+ # Stably sort the tagged list by the 1st coordinate
+ tagged.sort(key=lambda x: x[0])
+
+ # Now iterate over it again, adding tests to build_map (in the
+ # interleaved order) and collecting up the RunTest objects.
+ runs = []
+ for _, test, run in tagged:
+ build_map[test.build_mode].sub.append(run)
+ runs.append(run)
+
+ return runs
+
def _create_deploy_objects(self):
'''Create deploy objects from the build and run lists.
'''
@@ -431,18 +461,12 @@ class SimCfg(FlowCfg):
builds.append(item)
build_map[build] = item
- runs = []
- for test in self.run_list:
- for num in range(test.reseed):
- item = RunTest(num, test, self)
- if self.build_only is False:
- build_map[test.build_mode].sub.append(item)
- runs.append(item)
-
self.builds = builds
- self.runs = runs
+ self.runs = ([]
+ if self.build_only
+ else self._expand_run_list(build_map))
if self.run_only is True:
- self.deploy = runs
+ self.deploy = self.runs
else:
self.deploy = builds
@@ -555,8 +579,7 @@ class SimCfg(FlowCfg):
# Add path to testplan.
if hasattr(self, "testplan_doc_path"):
- testplan = "https://" + self.doc_server + '/' + getattr(
- self, "testplan_doc_path")
+ testplan = "https://" + self.doc_server + '/' + self.testplan_doc_path
else:
testplan = "https://" + self.doc_server + '/' + self.rel_path
testplan = testplan.replace("/dv", "/doc/dv_plan/#testplan")
@@ -583,8 +606,7 @@ class SimCfg(FlowCfg):
# Link the dashboard page using "cov_report_page" value.
if hasattr(self, "cov_report_page"):
results_str += "\n### [Coverage Dashboard]"
- results_str += "({})\n\n".format(
- getattr(self, "cov_report_page"))
+ results_str += "({})\n\n".format(self.cov_report_page)
results_str += self.cov_report_deploy.cov_results
self.results_summary[
"Coverage"] = self.cov_report_deploy.cov_total
diff --git a/vendor/lowrisc_ip/dvsim/dvsim.py b/vendor/lowrisc_ip/dvsim/dvsim.py
index 1d601eab..5e1cb5ec 100755
--- a/vendor/lowrisc_ip/dvsim/dvsim.py
+++ b/vendor/lowrisc_ip/dvsim/dvsim.py
@@ -2,14 +2,21 @@
# Copyright lowRISC contributors.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
-"""
-dvsim is a command line tool to deploy regressions for design verification. It uses hjson as the
-format for specifying what to build and run. It is an end-to-end regression manager that can deploy
-multiple builds (where some tests might need different set of compile time options requiring a
-uniquely build sim executable) in parallel followed by tests in parallel using the load balancer
-of your choice. dvsim is built to be tool-agnostic so that you can easily switch between tools
-available at your disposal. dvsim uses fusesoc as the starting step to resolve all inter-package
-dependencies and provide us with a filelist that will be consumed by the sim tool.
+"""dvsim is a command line tool to deploy ASIC tool flows such as regressions
+for design verification (DV), formal property verification (FPV), linting and
+synthesis.
+
+It uses hjson as the format for specifying what to build and run. It is an
+end-to-end regression manager that can deploy multiple builds (where some tests
+might need different set of compile time options requiring a uniquely build sim
+executable) in parallel followed by tests in parallel using the load balancer
+of your choice.
+
+dvsim is built to be tool-agnostic so that you can easily switch between the
+tools at your disposal. dvsim uses fusesoc as the starting step to resolve all
+inter-package dependencies and provide us with a filelist that will be consumed
+by the sim tool.
+
"""
import argparse
@@ -18,6 +25,7 @@ import logging as log
import os
import subprocess
import sys
+import textwrap
from signal import SIGINT, signal
import Deploy
@@ -72,6 +80,39 @@ def resolve_scratch_root(arg_scratch_root):
return (arg_scratch_root)
+def read_max_parallel(arg):
+ '''Take value for --max-parallel as an integer'''
+ try:
+ int_val = int(arg)
+ if int_val <= 0:
+ raise ValueError('bad value')
+ return int_val
+
+ except ValueError:
+ raise argparse.ArgumentTypeError('Bad argument for --max-parallel '
+ '({!r}): must be a positive integer.'
+ .format(arg))
+
+
+def resolve_max_parallel(arg):
+ '''Pick a value of max_parallel, defaulting to 16 or $DVSIM_MAX_PARALLEL'''
+ if arg is not None:
+ assert arg > 0
+ return arg
+
+ from_env = os.environ.get('DVSIM_MAX_PARALLEL')
+ if from_env is not None:
+ try:
+ return read_max_parallel(from_env)
+ except argparse.ArgumentTypeError:
+ log.warning('DVSIM_MAX_PARALLEL environment variable has value '
+ '{!r}, which is not a positive integer. Using default '
+ 'value (16).'
+ .format(from_env))
+
+ return 16
+
+
def resolve_branch(branch):
'''Choose a branch name for output files
@@ -138,301 +179,304 @@ def sigint_handler(signal_received, frame):
exit(1)
-def main():
+def wrapped_docstring():
+ '''Return a text-wrapped version of the module docstring'''
+ paras = []
+ para = []
+ for line in __doc__.strip().split('\n'):
+ line = line.strip()
+ if not line:
+ if para:
+ paras.append('\n'.join(para))
+ para = []
+ else:
+ para.append(line)
+ if para:
+ paras.append('\n'.join(para))
+
+ return '\n\n'.join(textwrap.fill(p) for p in paras)
+
+
+def parse_args():
parser = argparse.ArgumentParser(
- description=__doc__,
+ description=wrapped_docstring(),
formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument("cfg",
metavar="",
help="""Configuration hjson file.""")
- parser.add_argument("-i",
- "--items",
- nargs="*",
- default=["sanity"],
- metavar="regr1, regr2, regr3|test1, test2, test3, ...",
- help="""Indicate which regressions or tests to run.""")
-
- parser.add_argument(
- "-l",
- "--list",
- nargs="*",
- choices=_LIST_CATEGORIES,
- metavar="build_modes|run_modes|tests|regressions",
- help=
- """List the available build_modes / run_modes / tests / regressions for use."""
- )
-
- parser.add_argument("-t",
- "--tool",
- metavar="vcs|xcelium|ascentlint|veriblelint|dc|...",
- help="Override the tool that is set in hjson file")
-
- parser.add_argument(
- "--select-cfgs",
- nargs="*",
- metavar="cfg1, cfg2, cfg3, ...",
- help="""Specifies which cfg(s) of the master cfg shall be processed.
- If this switch is not specified, dvsim will process all cfgs specified in
- the master cfg list.""")
-
- parser.add_argument(
- "-sr",
- "--scratch-root",
- metavar="path",
- help="""root scratch directory path where all build / run drectories go;
- by default, the tool will create the {scratch_path} = {scratch_root}/{dut}
- directory if it doesn't already exist; under {scratch_path}, there will be
- {compile_set} set of directories where all the build outputs go and
- {test_name} set of directories where the test outputs go"""
- )
-
- parser.add_argument("-pr",
- "--proj-root",
- metavar="path",
- help="""Specify the root directory of the project.
- If this option is not passed, the tool will assume that this is
- a local GitHub repository and will attempt to automatically find
- the root directory.""")
-
- parser.add_argument(
- "-br",
- "--branch",
- metavar="",
- help=
- """This variable is used to construct the scratch path directory name. If not
- specified, it defaults to the GitHub branch name. The idea is to uniquefy the
- scratch paths between different branches.""")
-
- parser.add_argument(
- "-bo",
- "--build-opts",
- nargs="+",
- default=[],
- metavar="",
- help="""Pass additional build options over the command line;
- note that if there are multiple compile sets identified to be built,
- these options will be passed on to all of them""")
-
- parser.add_argument(
- "-bm",
- "--build-modes",
- nargs="+",
- default=[],
- metavar="",
- help="""Set build modes on the command line for all tests run as a part
- of the regression.""")
-
- parser.add_argument(
- "-ro",
- "--run-opts",
- nargs="+",
- default=[],
- metavar="",
- help="""Pass additional run time options over the command line;
- these options will be passed on to all tests scheduled to be run"""
- )
-
- parser.add_argument(
- "-rm",
- "--run-modes",
- nargs="+",
- default=[],
- metavar="",
- help="""Set run modes on the command line for all tests run as a part
- of the regression.""")
-
- parser.add_argument(
- "-bu",
- "--build-unique",
- action='store_true',
- help=
- """By default, under the {scratch} directory, there is a {compile_set}
- directory created where the build output goes; this can be
- uniquified by appending the current timestamp. This is suitable
- for the case when a test / regression already running and you want
- to run something else from a different terminal without affecting
- the previous one""")
-
- parser.add_argument(
- "--build-only",
- action='store_true',
- help="Only build the simulation executables for the givem items.")
-
- parser.add_argument(
- "--run-only",
- action='store_true',
- help="Assume sim exec is available and proceed to run step")
-
- parser.add_argument(
- "-s",
- "--seeds",
- nargs="+",
- default=[],
- metavar="seed0 seed1 ...",
- help=
- """Run tests with a specific seeds. Note that these specific seeds are applied to
- items being run in the order they are passed.""")
-
- parser.add_argument(
- "--fixed-seed",
- type=int,
- help=
- """Run all items with a fixed seed value. This option enforces --reseed 1."""
- )
-
- parser.add_argument(
- "-r",
- "--reseed",
- type=int,
- metavar="N",
- help="""Repeat tests with N iterations with different seeds""")
-
- parser.add_argument("-rx",
- "--reseed-multiplier",
- type=int,
- default=1,
- metavar="N",
- help="""Multiplier for existing reseed values.""")
-
- parser.add_argument("-w",
- "--waves",
- action='store_true',
- help="Enable dumping of waves")
-
- parser.add_argument("-d",
- "--dump",
- choices=["fsdb", "shm", "vpd"],
- help=("Format to dump waves for simulation. If Verdi "
- "is installed (detected by searching PATH) this "
- "defaults to fsdb. Otherwise, defaults to shm "
- "for Xcelium or vpd for VCS."))
-
- parser.add_argument("-mw",
- "--max-waves",
- type=int,
- default=5,
- metavar="N",
- help="""Enable dumping of waves for at most N tests;
- this includes tests scheduled for run AND automatic rerun"""
- )
-
- parser.add_argument("-c",
- "--cov",
- action='store_true',
- help="turn on coverage collection")
-
- parser.add_argument(
- "--cov-merge-previous",
- action='store_true',
- help="""Applicable when --cov switch is enabled. If a previous cov
- database directory exists, this switch will cause it to be merged with
- the current cov database.""")
-
- parser.add_argument(
- "--cov-analyze",
- action='store_true',
- help="Analyze the coverage from the last regression result.")
-
- parser.add_argument("-p",
- "--profile",
- nargs='?',
- const='time',
- choices=["time", "mem"],
- help="Turn on simulation profiling")
-
- parser.add_argument("--xprop-off",
- action='store_true',
- help="Turn off Xpropagation")
-
- parser.add_argument("--job-prefix",
- default="",
- metavar="job-prefix",
- help="Job prefix before deploying the tool commands.")
-
- parser.add_argument("--purge",
- action='store_true',
- help="Clean the scratch directory before running.")
-
- parser.add_argument(
- "-mo",
- "--max-odirs",
- type=int,
- default=5,
- metavar="N",
- help="""When tests are run, the older runs are backed up. This switch
- limits the number of backup directories being maintained.""")
-
- parser.add_argument(
- "--no-rerun",
- action='store_true',
- help=
- """By default, failing tests will be automatically be rerun with waves;
- this option will prevent the rerun from being triggered""")
-
- parser.add_argument("-v",
- "--verbosity",
- default="l",
- choices=["n", "l", "m", "h", "d"],
- help="""Set verbosity to none/low/medium/high/debug;
- This will override any setting added to any of the hjson files
- used for config""")
-
- parser.add_argument(
- "--verbose",
- nargs="?",
- choices=['default', 'debug'],
- default=None,
- const="default",
- metavar="debug",
- help="""Print verbose dvsim tool messages. If 'debug' is passed, then the
- volume of messages is ven higher.""")
-
parser.add_argument("--version",
action='store_true',
help="Print version and exit")
- parser.add_argument(
- "-n",
- "--dry-run",
- action='store_true',
- help=
- "Print dvsim tool messages only, without actually running any command")
+ parser.add_argument("--tool", "-t",
+ default="",
+ help=("Explicitly set the tool to use. This is "
+ "optional for running simulations (where it can "
+ "be set in an .hjson file), but is required for "
+ "other flows. Possible tools include: vcs, "
+ "xcelium, ascentlint, verible, dc."))
- parser.add_argument(
- "--map-full-testplan",
- action='store_true',
- help="Force complete testplan annotated results to be shown at the end."
- )
+ parser.add_argument("--list", "-l",
+ nargs="*",
+ metavar='CAT',
+ choices=_LIST_CATEGORIES,
+ help=('Parse the the given .hjson config file, list '
+ 'the things that can be run, then exit. The '
+ 'list can be filtered with a space-separated '
+ 'of categories from: {}.'
+ .format(', '.join(_LIST_CATEGORIES))))
- parser.add_argument(
- "--publish",
- action='store_true',
- help="Publish results to the reports.opentitan.org web server.")
+ whatg = parser.add_argument_group('Choosing what to run')
- parser.add_argument(
- "-pi",
- "--print-interval",
- type=int,
- default=10,
- metavar="N",
- help="""Interval in seconds. Print status every N seconds.""")
+ whatg.add_argument("-i",
+ "--items",
+ nargs="*",
+ default=["sanity"],
+ help=('Specify the regressions or tests to run. '
+ 'Defaults to "sanity", but can be a '
+ 'space separated list of test or regression '
+ 'names.'))
- parser.add_argument(
- "-mp",
- "--max-parallel",
- type=int,
- default=16,
- metavar="N",
- help="""Run only upto a fixed number of builds/tests at a time.""")
+ whatg.add_argument("--select-cfgs",
+ nargs="*",
+ metavar="CFG",
+ help=('The .hjson file is a master config. Only run '
+ 'the given configs from it. If this argument is '
+ 'not used, dvsim will process all configs listed '
+ 'in a master config.'))
- parser.add_argument(
- "--local",
- action='store_true',
- help=
- """Deploy builds and runs on the local workstation instead of the compute farm.
- Support for this has not been added yet.""")
+ disg = parser.add_argument_group('Dispatch options')
+
+ disg.add_argument("--job-prefix",
+ default="",
+ metavar="PFX",
+ help=('Prepend this string when running each tool '
+ 'command.'))
+
+ disg.add_argument("--max-parallel", "-mp",
+ type=read_max_parallel,
+ metavar="N",
+ help=('Run only up to N builds/tests at a time. '
+ 'Default value 16, unless the DVSIM_MAX_PARALLEL '
+ 'environment variable is set, in which case that '
+ 'is used.'))
+
+ pathg = parser.add_argument_group('File management')
+
+ pathg.add_argument("--scratch-root", "-sr",
+ metavar="PATH",
+ help=('Destination for build / run directories. If not '
+ 'specified, uses the path in the SCRATCH_ROOT '
+ 'environment variable, if set, or ./scratch '
+ 'otherwise.'))
+
+ pathg.add_argument("--proj-root", "-pr",
+ metavar="PATH",
+ help=('The root directory of the project. If not '
+ 'specified, dvsim will search for a git '
+ 'repository containing the current directory.'))
+
+ pathg.add_argument("--branch", "-br",
+ metavar='B',
+ help=('By default, dvsim creates files below '
+ '{scratch-root}/{dut}.{flow}.{tool}/{branch}. '
+ 'If --branch is not specified, dvsim assumes the '
+ 'current directory is a git repository and uses '
+ 'the name of the current branch.'))
+
+ pathg.add_argument("--max-odirs", "-mo",
+ type=int,
+ default=5,
+ metavar="N",
+ help=('When tests are run, older runs are backed '
+ 'up. Discard all but the N most recent (defaults '
+ 'to 5).'))
+
+ pathg.add_argument("--purge",
+ action='store_true',
+ help="Clean the scratch directory before running.")
+
+ buildg = parser.add_argument_group('Options for building')
+
+ buildg.add_argument("--build-only",
+ action='store_true',
+ help=('Stop after building executables for the given '
+ 'items.'))
+
+ buildg.add_argument("--build-unique", "-bu",
+ action='store_true',
+ help=('Append a timestamp to the directory in which '
+ 'files are built. This is suitable for the case '
+ 'when another test is already running and you '
+ 'want to run something else from a different '
+ 'terminal without affecting it.'))
+
+ buildg.add_argument("--build-opts", "-bo",
+ nargs="+",
+ default=[],
+ metavar="OPT",
+ help=('Additional options passed on the command line '
+ 'each time a build tool is run.'))
+
+ buildg.add_argument("--build-modes", "-bm",
+ nargs="+",
+ default=[],
+ metavar="MODE",
+ help=('The options for each build_mode in this list '
+ 'are applied to all build and run targets.'))
+
+ rung = parser.add_argument_group('Options for running')
+
+ rung.add_argument("--run-only",
+ action='store_true',
+ help=('Skip the build step (assume that simulation '
+ 'executables have already been built).'))
+
+ rung.add_argument("--run-opts", "-ro",
+ nargs="+",
+ default=[],
+ metavar="OPT",
+ help=('Additional options passed on the command line '
+ 'each time a test is run.'))
+
+ rung.add_argument("--run-modes", "-rm",
+ nargs="+",
+ default=[],
+ metavar="MODE",
+ help=('The options for each run_mode in this list are '
+ 'applied to each simulation run.'))
+
+ rung.add_argument("--profile", "-p",
+ choices=['time', 'mem'],
+ metavar="P",
+ help=('Turn on simulation profiling (where P is time '
+ 'or mem).'))
+
+ rung.add_argument("--xprop-off",
+ action='store_true',
+ help="Turn off X-propagation in simulation.")
+
+ rung.add_argument("--no-rerun",
+ action='store_true',
+ help=("Disable the default behaviour, where failing "
+ "tests are automatically rerun with waves "
+ "enabled."))
+
+ rung.add_argument("--verbosity", "-v",
+ default="l",
+ choices=['n', 'l', 'm', 'h', 'd'],
+ metavar='V',
+ help=('Set UVM verbosity to none (n), low (l; the '
+ 'default), medium (m), high (h) or debug (d). '
+ 'This overrides any setting in the config files.'))
+
+ seedg = parser.add_argument_group('Test seeds')
+
+ seedg.add_argument("--seeds", "-s",
+ nargs="+",
+ default=[],
+ metavar="S",
+ help=('A list of seeds for tests. Note that these '
+ 'specific seeds are applied to items being run '
+ 'in the order they are passed.'))
+
+ seedg.add_argument("--fixed-seed",
+ type=int,
+ metavar='S',
+ help=('Run all items with the seed S. This implies '
+ '--reseed 1.'))
+
+ seedg.add_argument("--reseed", "-r",
+ type=int,
+ metavar="N",
+ help=('Override any reseed value in the test '
+ 'configuration and run each test N times, with '
+ 'a new seed each time.'))
+
+ seedg.add_argument("--reseed-multiplier", "-rx",
+ type=int,
+ default=1,
+ metavar="N",
+ help=('Scale each reseed value in the test '
+ 'configuration by N. This allows e.g. running '
+ 'the tests 10 times as much as normal while '
+ 'maintaining the ratio of numbers of runs '
+ 'between different tests.'))
+
+ waveg = parser.add_argument_group('Dumping waves')
+
+ waveg.add_argument("--waves", "-w",
+ action='store_true',
+ help="Enable dumping of waves")
+
+ waveg.add_argument("-d",
+ "--dump",
+ choices=["fsdb", "shm", "vpd"],
+ help=("Format to dump waves for simulation. The default "
+ "format depends on the tool. With VCS, this "
+ "defaults to fsdb if Verdi is installed, else "
+ "vpd. With Xcelium, defaults to shm."))
+
+ waveg.add_argument("--max-waves", "-mw",
+ type=int,
+ default=5,
+ metavar="N",
+ help=('Only dump waves for the first N tests run. This '
+ 'includes both tests scheduled for run and those '
+ 'that are automatically rerun.'))
+
+ covg = parser.add_argument_group('Generating simulation coverage')
+
+ covg.add_argument("--cov", "-c",
+ action='store_true',
+ help="Enable collection of coverage data.")
+
+ covg.add_argument("--cov-merge-previous",
+ action='store_true',
+ help=('Only applicable with --cov. Merge any previous '
+ 'coverage database directory with the new '
+ 'coverage database.'))
+
+ covg.add_argument("--cov-analyze",
+ action='store_true',
+ help=('Rather than building or running any tests, '
+ 'analyze the coverage from the last run.'))
+
+ pubg = parser.add_argument_group('Generating and publishing results')
+
+ pubg.add_argument("--map-full-testplan",
+ action='store_true',
+ help=("Show complete testplan annotated results "
+ "at the end."))
+
+ pubg.add_argument("--publish",
+ action='store_true',
+ help="Publish results to reports.opentitan.org.")
+
+ dvg = parser.add_argument_group('Controlling DVSim itself')
+
+ dvg.add_argument("--print-interval", "-pi",
+ type=int,
+ default=10,
+ metavar="N",
+ help="Print status every N seconds.")
+
+ dvg.add_argument("--verbose",
+ nargs="?",
+ choices=['default', 'debug'],
+ default=None,
+ const="default",
+ metavar="D",
+ help=('With no argument, print verbose dvsim tool '
+ 'messages. With --verbose=debug, the volume of '
+ 'messages is even higher.'))
+
+ dvg.add_argument("--dry-run", "-n",
+ action='store_true',
+ help=("Print dvsim tool messages but don't actually "
+ "run any command"))
args = parser.parse_args()
@@ -447,6 +491,17 @@ def main():
if args.list == []:
args.list = _LIST_CATEGORIES
+ # Get max_parallel from environment if it wasn't specified on the command
+ # line.
+ args.max_parallel = resolve_max_parallel(args.max_parallel)
+ assert args.max_parallel > 0
+
+ return args
+
+
+def main():
+ args = parse_args()
+
# Add log level 'VERBOSE' between INFO and DEBUG
log.addLevelName(utils.VERBOSE, 'VERBOSE')
diff --git a/vendor/lowrisc_ip/prim/prim.core b/vendor/lowrisc_ip/prim/prim.core
index 166b4cd5..9ab4f550 100644
--- a/vendor/lowrisc_ip/prim/prim.core
+++ b/vendor/lowrisc_ip/prim/prim.core
@@ -9,8 +9,6 @@ description: "Primitives"
filesets:
files_rtl:
depend:
- - lowrisc:prim:ram_2p # for prim_ram_2p_adv
- - lowrisc:prim:secded # for prim_ram_2p_adv
- lowrisc:prim:assert
- lowrisc:prim:diff_decode # for prim_alert_sender/receiver
- lowrisc:prim:pad_wrapper
@@ -45,8 +43,6 @@ filesets:
- rtl/prim_subreg.sv
- rtl/prim_subreg_ext.sv
- rtl/prim_intr_hw.sv
- - rtl/prim_ram_2p_adv.sv
- - rtl/prim_ram_2p_async_adv.sv
file_type: systemVerilogSource
files_verilator_waiver:
diff --git a/vendor/lowrisc_ip/prim/prim_flash.core b/vendor/lowrisc_ip/prim/prim_flash.core
index 9d7b41ea..c7d1aa3a 100644
--- a/vendor/lowrisc_ip/prim/prim_flash.core
+++ b/vendor/lowrisc_ip/prim/prim_flash.core
@@ -10,6 +10,9 @@ filesets:
depend:
- lowrisc:prim:prim_pkg
- lowrisc:prim:primgen
+ # TODO olofk/fusesoc#404: The below dependency is already added to prim_generic_flash.core.
+ # However, the generator for the prim:ram1p does not kick in, causing compile errors.
+ - lowrisc:prim:ram_1p
generate:
impl:
diff --git a/vendor/lowrisc_ip/prim/prim_ram_1p_adv.core b/vendor/lowrisc_ip/prim/prim_ram_1p_adv.core
index fe655a87..5c3b4199 100644
--- a/vendor/lowrisc_ip/prim/prim_ram_1p_adv.core
+++ b/vendor/lowrisc_ip/prim/prim_ram_1p_adv.core
@@ -8,6 +8,9 @@ description: "Single-port RAM primitive with advanced features"
filesets:
files_rtl:
depend:
+ - lowrisc:prim:assert
+ - lowrisc:prim:util
+ - lowrisc:prim:secded
- lowrisc:prim:ram_1p
files:
- rtl/prim_ram_1p_adv.sv
diff --git a/vendor/lowrisc_ip/prim/prim_ram_2p_adv.core b/vendor/lowrisc_ip/prim/prim_ram_2p_adv.core
new file mode 100644
index 00000000..3ff2dcd8
--- /dev/null
+++ b/vendor/lowrisc_ip/prim/prim_ram_2p_adv.core
@@ -0,0 +1,19 @@
+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:ram_2p_adv:0.1"
+description: "Dual-port RAM primitive with advanced features"
+filesets:
+ files_rtl:
+ depend:
+ - lowrisc:prim:ram_2p_async_adv
+ files:
+ - rtl/prim_ram_2p_adv.sv
+ file_type: systemVerilogSource
+
+targets:
+ default:
+ filesets:
+ - files_rtl
diff --git a/vendor/lowrisc_ip/prim/prim_ram_2p_async_adv.core b/vendor/lowrisc_ip/prim/prim_ram_2p_async_adv.core
new file mode 100644
index 00000000..e5eda9d0
--- /dev/null
+++ b/vendor/lowrisc_ip/prim/prim_ram_2p_async_adv.core
@@ -0,0 +1,22 @@
+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:ram_2p_async_adv:0.1"
+description: "Asynchronous dual-port RAM primitive with advanced features"
+filesets:
+ files_rtl:
+ depend:
+ - lowrisc:prim:assert
+ - lowrisc:prim:util
+ - lowrisc:prim:secded
+ - lowrisc:prim:ram_2p
+ files:
+ - rtl/prim_ram_2p_async_adv.sv
+ file_type: systemVerilogSource
+
+targets:
+ default:
+ filesets:
+ - files_rtl
diff --git a/vendor/lowrisc_ip/prim/prim_rom_adv.core b/vendor/lowrisc_ip/prim/prim_rom_adv.core
new file mode 100644
index 00000000..249d6dd0
--- /dev/null
+++ b/vendor/lowrisc_ip/prim/prim_rom_adv.core
@@ -0,0 +1,20 @@
+CAPI=2:
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+name: "lowrisc:prim:rom_adv:0.1"
+description: "ROM primitive with advanced features"
+filesets:
+ files_rtl:
+ depend:
+ - lowrisc:prim:assert
+ - lowrisc:prim:rom
+ files:
+ - rtl/prim_rom_adv.sv
+ file_type: systemVerilogSource
+
+targets:
+ default:
+ filesets:
+ - files_rtl
diff --git a/vendor/lowrisc_ip/prim/prim_util.core b/vendor/lowrisc_ip/prim/prim_util.core
new file mode 100644
index 00000000..c46765ba
--- /dev/null
+++ b/vendor/lowrisc_ip/prim/prim_util.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:util:0.1"
+description: "Utilities"
+filesets:
+ files_rtl:
+ files:
+ - rtl/prim_util.svh : {is_include_file : true}
+ file_type: systemVerilogSource
+
+targets:
+ default:
+ filesets:
+ - files_rtl
diff --git a/vendor/lowrisc_ip/prim/rtl/prim_fifo_sync.sv b/vendor/lowrisc_ip/prim/rtl/prim_fifo_sync.sv
index e2199db6..455e63cb 100644
--- a/vendor/lowrisc_ip/prim/rtl/prim_fifo_sync.sv
+++ b/vendor/lowrisc_ip/prim/rtl/prim_fifo_sync.sv
@@ -10,6 +10,7 @@ module prim_fifo_sync #(
parameter int unsigned Width = 16,
parameter bit Pass = 1'b1, // if == 1 allow requests to pass through empty FIFO
parameter int unsigned Depth = 4,
+ parameter bit OutputZeroIfEmpty = 1'b1, // if == 1 always output 0 when FIFO is empty
// derived parameter
localparam int unsigned DepthWNorm = $clog2(Depth+1),
localparam int unsigned DepthW = (DepthWNorm == 0) ? 1 : DepthWNorm
@@ -131,14 +132,21 @@ module prim_fifo_sync #(
end
end
+ logic [Width-1:0] rdata_int;
if (Pass == 1'b1) begin : gen_pass
- assign rdata = (fifo_empty && wvalid) ? wdata : storage_rdata;
+ assign rdata_int = (fifo_empty && wvalid) ? wdata : storage_rdata;
assign empty = fifo_empty & ~wvalid;
end else begin : gen_nopass
- assign rdata = storage_rdata;
+ assign rdata_int = storage_rdata;
assign empty = fifo_empty;
end
+ if (OutputZeroIfEmpty == 1'b1) begin : gen_output_zero
+ assign rdata = empty ? 'b0 : rdata_int;
+ end else begin : gen_no_output_zero
+ assign rdata = rdata_int;
+ end
+
`ASSERT(depthShallNotExceedParamDepth, !empty |-> depth <= DepthW'(Depth))
end // block: gen_normal_fifo
diff --git a/vendor/lowrisc_ip/prim/rtl/prim_lfsr.sv b/vendor/lowrisc_ip/prim/rtl/prim_lfsr.sv
index 68481bc5..cf356422 100644
--- a/vendor/lowrisc_ip/prim/rtl/prim_lfsr.sv
+++ b/vendor/lowrisc_ip/prim/rtl/prim_lfsr.sv
@@ -476,12 +476,12 @@ module prim_lfsr #(
perturbed_q <= perturbed_d;
end
end
-`endif
`ASSERT(MaximalLengthCheck0_A, cnt_q == 0 |-> lfsr_q == DefaultSeed,
clk_i, !rst_ni || perturbed_q)
`ASSERT(MaximalLengthCheck1_A, cnt_q != 0 |-> lfsr_q != DefaultSeed,
clk_i, !rst_ni || perturbed_q)
+`endif
end
endmodule
diff --git a/vendor/lowrisc_ip/prim/rtl/prim_ram_1p_adv.sv b/vendor/lowrisc_ip/prim/rtl/prim_ram_1p_adv.sv
index 6d546782..4452a181 100644
--- a/vendor/lowrisc_ip/prim/rtl/prim_ram_1p_adv.sv
+++ b/vendor/lowrisc_ip/prim/rtl/prim_ram_1p_adv.sv
@@ -3,63 +3,215 @@
// SPDX-License-Identifier: Apache-2.0
//
// Single-Port SRAM Wrapper
+//
+// Supported configurations:
+// - ECC for 32b wide memories with no write mask
+// (Width == 32 && DataBitsPerMask == 32).
+// - Byte parity if Width is a multiple of 8 bit and write masks have Byte
+// granularity (DataBitsPerMask == 8).
+//
+// Note that the write mask needs to be per Byte if parity is enabled. If ECC is enabled, the write
+// mask cannot be used and has to be tied to {Width{1'b1}}.
`include "prim_assert.sv"
+`include "prim_util.svh"
module prim_ram_1p_adv #(
- // Parameters passed on the the SRAM primitive.
- parameter int Width = 32, // bit
- parameter int Depth = 128,
- parameter int DataBitsPerMask = 1, // Number of data bits per bit of write mask
- parameter MemInitFile = "", // VMEM file to initialize the memory with
+ parameter int Depth = 512,
+ parameter int Width = 32,
+ parameter int DataBitsPerMask = 1, // Number of data bits per bit of write mask
+ parameter int CfgW = 8, // WTC, RTC, etc
+ parameter MemInitFile = "", // VMEM file to initialize the memory with
- parameter int CfgW = 8, // WTC, RTC, etc
+ // Configurations
+ parameter bit EnableECC = 0, // Enables per-word ECC
+ parameter bit EnableParity = 0, // Enables per-Byte Parity
+ parameter bit EnableInputPipeline = 0, // Adds an input register (read latency +1)
+ parameter bit EnableOutputPipeline = 0, // Adds an output register (read latency +1)
- localparam int Aw = $clog2(Depth)
+ localparam int Aw = vbits(Depth)
) (
- input clk_i,
- input rst_ni,
+ input clk_i,
+ input rst_ni,
- input req_i,
- input write_i,
- input [Aw-1:0] addr_i,
- input [Width-1:0] wdata_i,
- input [Width-1:0] wmask_i,
- output logic [Width-1:0] rdata_o,
- output logic rvalid_o, // read response (rdata_o) is valid
- output logic [1:0] rerror_o, // Bit1: Uncorrectable, Bit0: Correctable
+ input req_i,
+ input write_i,
+ input [Aw-1:0] addr_i,
+ input [Width-1:0] wdata_i,
+ input [Width-1:0] wmask_i,
+ output logic [Width-1:0] rdata_o,
+ output logic rvalid_o, // read response (rdata_o) is valid
+ output logic [1:0] rerror_o, // Bit1: Uncorrectable, Bit0: Correctable
- input [CfgW-1:0] cfg_i
+ // config
+ input [CfgW-1:0] cfg_i
);
- // We will eventually use cfg_i for RTC/WTC or other memory parameters.
- logic [CfgW-1:0] unused_cfg;
- assign unused_cfg = cfg_i;
+ `ASSERT_INIT(CannotHaveEccAndParity_A, !(EnableParity && EnableECC))
+
+ // While we require DataBitsPerMask to be per Byte (8) at the interface in case Byte parity is
+ // enabled, we need to switch this to a per-bit mask locally such that we can individually enable
+ // the parity bits to be written alongside the data.
+ localparam int LocalDataBitsPerMask = (EnableParity) ? 1 : DataBitsPerMask;
+
+ // Calculate ECC width
+ localparam int ParWidth = (EnableParity) ? Width/8 :
+ (!EnableECC) ? 0 :
+ (Width <= 4) ? 4 :
+ (Width <= 11) ? 5 :
+ (Width <= 26) ? 6 :
+ (Width <= 57) ? 7 :
+ (Width <= 120) ? 8 : 8 ;
+ localparam int TotalWidth = Width + ParWidth;
+
+ ////////////////////////////
+ // RAM Primitive Instance //
+ ////////////////////////////
+
+ logic req_q, req_d ;
+ logic write_q, write_d ;
+ logic [Aw-1:0] addr_q, addr_d ;
+ logic [TotalWidth-1:0] wdata_q, wdata_d ;
+ logic [TotalWidth-1:0] wmask_q, wmask_d ;
+ logic rvalid_q, rvalid_d, rvalid_sram ;
+ logic [Width-1:0] rdata_q, rdata_d ;
+ logic [TotalWidth-1:0] rdata_sram ;
+ logic [1:0] rerror_q, rerror_d ;
prim_ram_1p #(
- .Width (Width),
+ .MemInitFile (MemInitFile),
+
+ .Width (TotalWidth),
.Depth (Depth),
- .DataBitsPerMask (DataBitsPerMask),
- .MemInitFile (MemInitFile)
+ .DataBitsPerMask (LocalDataBitsPerMask)
) u_mem (
.clk_i,
- .req_i,
- .write_i,
- .addr_i,
- .wdata_i,
- .wmask_i,
- .rdata_o
+ .req_i (req_q),
+ .write_i (write_q),
+ .addr_i (addr_q),
+ .wdata_i (wdata_q),
+ .wmask_i (wmask_q),
+ .rdata_o (rdata_sram)
);
- always_ff @(posedge clk_i, negedge rst_ni) begin
+ always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
- rvalid_o <= '0;
+ rvalid_sram <= 1'b0;
end else begin
- rvalid_o <= req_i & ~write_i;
+ rvalid_sram <= req_q & ~write_q;
end
end
- assign rerror_o = 2'b0;
+ assign req_d = req_i;
+ assign write_d = write_i;
+ assign addr_d = addr_i;
+ assign rvalid_o = rvalid_q;
+ assign rdata_o = rdata_q;
+ assign rerror_o = rerror_q;
-endmodule
+ /////////////////////////////
+ // ECC / Parity Generation //
+ /////////////////////////////
+
+ if (EnableParity == 0 && EnableECC) begin : gen_secded
+
+ // check supported widths
+ `ASSERT_INIT(SecDecWidth_A, Width inside {32})
+
+ // the wmask is constantly set to 1 in this case
+ `ASSERT(OnlyWordWritePossibleWithEccPortA_A, req_i |->
+ wmask_i == {TotalWidth{1'b1}})
+
+ assign wmask_d = {TotalWidth{1'b1}};
+
+ if (Width == 32) begin : gen_secded_39_32
+ prim_secded_39_32_enc u_enc (.in(wdata_i), .out(wdata_d));
+ prim_secded_39_32_dec u_dec (
+ .in (rdata_sram),
+ .d_o (rdata_d[0+:Width]),
+ .syndrome_o ( ),
+ .err_o (rerror_d)
+ );
+ end
+ end else if (EnableParity) begin : gen_byte_parity
+
+ `ASSERT_INIT(WidthNeedsToBeByteAligned_A, Width % 8 == 0)
+ `ASSERT_INIT(ParityNeedsByteWriteMask_A, DataBitsPerMask == 8)
+
+ always_comb begin : p_parity
+ rerror_d = '0;
+ wmask_d[0+:Width] = wmask_i;
+ wdata_d[0+:Width] = wdata_i;
+
+ for (int i = 0; i < Width/8; i ++) begin
+ // parity generation (odd parity)
+ wdata_d[Width + i] = ~(^wdata_i[i*8 +: 8]);
+ wmask_d[Width + i] = &wmask_i[i*8 +: 8];
+ // parity decoding (errors are always uncorrectable)
+ rerror_d[1] |= ~(^{rdata_sram[i*8 +: 8], rdata_sram[Width + i]});
+ end
+ // tie to zero if the read data is not valid
+ rerror_d &= {2{rvalid_sram}};
+ end
+
+ assign rdata_d = rdata_sram[0+:Width];
+ end else begin : gen_nosecded_noparity
+ assign wmask_d = wmask_i;
+ assign wdata_d = wdata_i;
+
+ assign rdata_d = rdata_sram[0+:Width];
+ assign rerror_d = '0;
+ end
+
+ assign rvalid_d = rvalid_sram;
+
+ /////////////////////////////////////
+ // Input/Output Pipeline Registers //
+ /////////////////////////////////////
+
+ if (EnableInputPipeline) begin : gen_regslice_input
+ // Put the register slices between ECC encoding to SRAM port
+ always_ff @(posedge clk_i or negedge rst_ni) begin
+ if (!rst_ni) begin
+ req_q <= '0;
+ write_q <= '0;
+ addr_q <= '0;
+ wdata_q <= '0;
+ wmask_q <= '0;
+ end else begin
+ req_q <= req_d;
+ write_q <= write_d;
+ addr_q <= addr_d;
+ wdata_q <= wdata_d;
+ wmask_q <= wmask_d;
+ end
+ end
+ end else begin : gen_dirconnect_input
+ assign req_q = req_d;
+ assign write_q = write_d;
+ assign addr_q = addr_d;
+ assign wdata_q = wdata_d;
+ assign wmask_q = wmask_d;
+ end
+
+ if (EnableOutputPipeline) begin : gen_regslice_output
+ // Put the register slices between ECC decoding to output
+ always_ff @(posedge clk_i or negedge rst_ni) begin
+ if (!rst_ni) begin
+ rvalid_q <= '0;
+ rdata_q <= '0;
+ rerror_q <= '0;
+ end else begin
+ rvalid_q <= rvalid_d;
+ rdata_q <= rdata_d;
+ rerror_q <= rerror_d;
+ end
+ end
+ end else begin : gen_dirconnect_output
+ assign rvalid_q = rvalid_d;
+ assign rdata_q = rdata_d;
+ assign rerror_q = rerror_d;
+ end
+
+endmodule : prim_ram_1p_adv
diff --git a/vendor/lowrisc_ip/prim/rtl/prim_ram_2p_adv.sv b/vendor/lowrisc_ip/prim/rtl/prim_ram_2p_adv.sv
index 4fc1b729..2d9e5a80 100644
--- a/vendor/lowrisc_ip/prim/rtl/prim_ram_2p_adv.sv
+++ b/vendor/lowrisc_ip/prim/rtl/prim_ram_2p_adv.sv
@@ -2,271 +2,91 @@
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
-// Dual-port SRAM Wrapper
-// This module to connect SRAM interface to actual SRAM interface
-// At this time, it doesn't utilize ECC or any pipeline.
-// This module stays to include any additional calculation logic later on.
-// Instantiating SRAM is up to the top design to remove process dependency.
-
-// Parameter
-// EnableECC:
-// EnableParity:
-// EnableInputPipeline:
-// EnableOutputPipeline:
+// Dual-Port SRAM Wrapper
+//
+// Supported configurations:
+// - ECC for 32b wide memories with no write mask
+// (Width == 32 && DataBitsPerMask == 32).
+// - Byte parity if Width is a multiple of 8 bit and write masks have Byte
+// granularity (DataBitsPerMask == 8).
+//
+// Note that the write mask needs to be per Byte if parity is enabled. If ECC is enabled, the write
+// mask cannot be used and has to be tied to {Width{1'b1}}.
`include "prim_assert.sv"
+`include "prim_util.svh"
module prim_ram_2p_adv #(
parameter int Depth = 512,
parameter int Width = 32,
- parameter int CfgW = 8, // WTC, RTC, etc
+ parameter int DataBitsPerMask = 1, // Number of data bits per bit of write mask
+ parameter int CfgW = 8, // WTC, RTC, etc
parameter MemInitFile = "", // VMEM file to initialize the memory with
// Configurations
- parameter bit EnableECC = 0,
- parameter bit EnableParity = 0,
- parameter bit EnableInputPipeline = 0,
- parameter bit EnableOutputPipeline = 0,
+ parameter bit EnableECC = 0, // Enables per-word ECC
+ parameter bit EnableParity = 0, // Enables per-Byte Parity
+ parameter bit EnableInputPipeline = 0, // Adds an input register (read latency +1)
+ parameter bit EnableOutputPipeline = 0, // Adds an output register (read latency +1)
- parameter MemT = "REGISTER", // can be "REGISTER" or "SRAM"
-
- localparam int Aw = $clog2(Depth)
+ localparam int Aw = vbits(Depth)
) (
- input clk_i,
- input rst_ni,
+ input clk_i,
+ input rst_ni,
- input a_req_i,
- input a_write_i,
- input [Aw-1:0] a_addr_i,
- input [Width-1:0] a_wdata_i,
- output logic [Width-1:0] a_rdata_o,
- output logic a_rvalid_o, // read response (a_rdata_o) is valid
- output logic [1:0] a_rerror_o, // Bit1: Uncorrectable, Bit0: Correctable
+ input a_req_i,
+ input a_write_i,
+ input [Aw-1:0] a_addr_i,
+ input [Width-1:0] a_wdata_i,
+ input [Width-1:0] a_wmask_i, // cannot be used with ECC, tie to 1 in that case
+ output logic [Width-1:0] a_rdata_o,
+ output logic a_rvalid_o, // read response (a_rdata_o) is valid
+ output logic [1:0] a_rerror_o, // Bit1: Uncorrectable, Bit0: Correctable
- input b_req_i,
- input b_write_i,
- input [Aw-1:0] b_addr_i,
- input [Width-1:0] b_wdata_i,
- output logic [Width-1:0] b_rdata_o,
- output logic b_rvalid_o, // read response (b_rdata_o) is valid
- output logic [1:0] b_rerror_o, // Bit1: Uncorrectable, Bit0: Correctable
+ input b_req_i,
+ input b_write_i,
+ input [Aw-1:0] b_addr_i,
+ input [Width-1:0] b_wdata_i,
+ input [Width-1:0] b_wmask_i, // cannot be used with ECC, tie to 1 in that case
+ output logic [Width-1:0] b_rdata_o,
+ output logic b_rvalid_o, // read response (b_rdata_o) is valid
+ output logic [1:0] b_rerror_o, // Bit1: Uncorrectable, Bit0: Correctable
- input [CfgW-1:0] cfg_i
+ input [CfgW-1:0] cfg_i
);
- // Calculate ECC width
- localparam int ParWidth = (EnableParity) ? 1 :
- (!EnableECC) ? 0 :
- (Width <= 4) ? 4 :
- (Width <= 11) ? 5 :
- (Width <= 26) ? 6 :
- (Width <= 57) ? 7 :
- (Width <= 120) ? 8 : 8 ;
- localparam int TotalWidth = Width + ParWidth;
+ prim_ram_2p_async_adv #(
+ .Depth (Depth),
+ .Width (Width),
+ .DataBitsPerMask (DataBitsPerMask),
+ .CfgW (CfgW),
+ .MemInitFile (MemInitFile),
+ .EnableECC (EnableECC),
+ .EnableParity (EnableParity),
+ .EnableInputPipeline (EnableInputPipeline),
+ .EnableOutputPipeline(EnableOutputPipeline)
+ ) i_prim_ram_2p_async_adv (
+ .clk_a_i(clk_i),
+ .rst_a_ni(rst_ni),
+ .clk_b_i(clk_i),
+ .rst_b_ni(rst_ni),
+ .a_req_i,
+ .a_write_i,
+ .a_addr_i,
+ .a_wdata_i,
+ .a_wmask_i,
+ .a_rdata_o,
+ .a_rvalid_o,
+ .a_rerror_o,
+ .b_req_i,
+ .b_write_i,
+ .b_addr_i,
+ .b_wdata_i,
+ .b_wmask_i,
+ .b_rdata_o,
+ .b_rvalid_o,
+ .b_rerror_o,
+ .cfg_i
+ );
- // We will eventually use cfg_i for RTC/WTC or other memory parameters.
- logic [CfgW-1:0] unused_cfg;
- assign unused_cfg = cfg_i;
-
- logic a_req_q, a_req_d ;
- logic a_write_q, a_write_d ;
- logic [Aw-1:0] a_addr_q, a_addr_d ;
- logic [TotalWidth-1:0] a_wdata_q, a_wdata_d ;
- logic a_rvalid_q, a_rvalid_d, a_rvalid_sram ;
- logic [Width-1:0] a_rdata_q, a_rdata_d ;
- logic [TotalWidth-1:0] a_rdata_sram ;
- logic [1:0] a_rerror_q, a_rerror_d ;
-
- logic b_req_q, b_req_d ;
- logic b_write_q, b_write_d ;
- logic [Aw-1:0] b_addr_q, b_addr_d ;
- logic [TotalWidth-1:0] b_wdata_q, b_wdata_d ;
- logic b_rvalid_q, b_rvalid_d, b_rvalid_sram ;
- logic [Width-1:0] b_rdata_q, b_rdata_d ;
- logic [TotalWidth-1:0] b_rdata_sram ;
- logic [1:0] b_rerror_q, b_rerror_d ;
-
- if (MemT == "REGISTER") begin : gen_regmem
- prim_ram_2p #(
- // force register implementation for all targets
- .Impl (prim_pkg::ImplGeneric),
-
- .Width (TotalWidth),
- .Depth (Depth),
- .DataBitsPerMask (TotalWidth),
- .MemInitFile (MemInitFile)
- ) u_mem (
- .clk_a_i (clk_i),
- .clk_b_i (clk_i),
-
- .a_req_i (a_req_q),
- .a_write_i (a_write_q),
- .a_addr_i (a_addr_q),
- .a_wdata_i (a_wdata_q),
- .a_wmask_i ({TotalWidth{1'b1}}),
- .a_rdata_o (a_rdata_sram),
-
- .b_req_i (b_req_q),
- .b_write_i (b_write_q),
- .b_addr_i (b_addr_q),
- .b_wdata_i (b_wdata_q),
- .b_wmask_i ({TotalWidth{1'b1}}),
- .b_rdata_o (b_rdata_sram)
- );
- // end else if (TotalWidth == aa && Depth == yy) begin
- end else if (MemT == "SRAM") begin : gen_srammem
- prim_ram_2p #(
- .Width (TotalWidth),
- .Depth (Depth),
- .DataBitsPerMask (TotalWidth),
- .MemInitFile (MemInitFile)
- ) u_mem (
- .clk_a_i (clk_i),
- .clk_b_i (clk_i),
-
- .a_req_i (a_req_q),
- .a_write_i (a_write_q),
- .a_addr_i (a_addr_q),
- .a_wdata_i (a_wdata_q),
- .a_wmask_i ({TotalWidth{1'b1}}),
- .a_rdata_o (a_rdata_sram),
-
- .b_req_i (b_req_q),
- .b_write_i (b_write_q),
- .b_addr_i (b_addr_q),
- .b_wdata_i (b_wdata_q),
- .b_wmask_i ({TotalWidth{1'b1}}),
- .b_rdata_o (b_rdata_sram)
- );
- end
-
- always_ff @(posedge clk_i, negedge rst_ni) begin
- if (!rst_ni) begin
- a_rvalid_sram <= '0;
- b_rvalid_sram <= '0;
- end else begin
- a_rvalid_sram <= a_req_q & ~a_write_q;
- b_rvalid_sram <= b_req_q & ~b_write_q;
- end
- end
-
- assign a_req_d = a_req_i;
- assign a_write_d = a_write_i;
- assign a_addr_d = a_addr_i;
- assign a_rvalid_o = a_rvalid_q;
- assign a_rdata_o = a_rdata_q;
- assign a_rerror_o = a_rerror_q;
-
- assign b_req_d = b_req_i;
- assign b_write_d = b_write_i;
- assign b_addr_d = b_addr_i;
- assign b_rvalid_o = b_rvalid_q;
- assign b_rdata_o = b_rdata_q;
- assign b_rerror_o = b_rerror_q;
-
- // TODO: Parity Logic
- `ASSERT_INIT(ParityNotYetSupported_A, EnableParity == 0)
-
- if (EnableParity == 0 && EnableECC) begin : gen_secded
-
- // check supported widths
- `ASSERT_INIT(SecDecWidth_A, Width inside {32})
-
- if (Width == 32) begin : gen_secded_39_32
- prim_secded_39_32_enc u_enc_a (.in(a_wdata_i), .out(a_wdata_d));
- prim_secded_39_32_dec u_dec_a (
- .in (a_rdata_sram),
- .d_o (a_rdata_d),
- .syndrome_o (),
- .err_o (a_rerror_d)
- );
- prim_secded_39_32_enc u_enc_b (.in(b_wdata_i), .out(b_wdata_d));
- prim_secded_39_32_dec u_dec_b (
- .in (b_rdata_sram),
- .d_o (b_rdata_d),
- .syndrome_o (),
- .err_o (b_rerror_d)
- );
- assign a_rvalid_d = a_rvalid_sram;
- assign b_rvalid_d = b_rvalid_sram;
- end
- end else begin : gen_nosecded
- assign a_wdata_d[0+:Width] = a_wdata_i;
- assign b_wdata_d[0+:Width] = b_wdata_i;
- assign a_rdata_d = a_rdata_sram;
- assign b_rdata_d = b_rdata_sram;
- assign a_rvalid_d = a_rvalid_sram;
- assign b_rvalid_d = b_rvalid_sram;
- assign a_rerror_d = 2'b00;
- assign b_rerror_d = 2'b00;
- end
-
- if (EnableInputPipeline) begin : gen_regslice_input
- // Put the register slices between ECC encoding to SRAM port
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- a_req_q <= '0;
- a_write_q <= '0;
- a_addr_q <= '0;
- a_wdata_q <= '0;
-
- b_req_q <= '0;
- b_write_q <= '0;
- b_addr_q <= '0;
- b_wdata_q <= '0;
- end else begin
- a_req_q <= a_req_d;
- a_write_q <= a_write_d;
- a_addr_q <= a_addr_d;
- a_wdata_q <= a_wdata_d;
-
- b_req_q <= b_req_d;
- b_write_q <= b_write_d;
- b_addr_q <= b_addr_d;
- b_wdata_q <= b_wdata_d;
- end
- end
- end else begin : gen_dirconnect_input
- assign a_req_q = a_req_d;
- assign a_write_q = a_write_d;
- assign a_addr_q = a_addr_d;
- assign a_wdata_q = a_wdata_d;
-
- assign b_req_q = b_req_d;
- assign b_write_q = b_write_d;
- assign b_addr_q = b_addr_d;
- assign b_wdata_q = b_wdata_d;
- end
-
- if (EnableOutputPipeline) begin : gen_regslice_output
- // Put the register slices between ECC decoding to output
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- a_rvalid_q <= '0;
- a_rdata_q <= '0;
- a_rerror_q <= '0;
-
- b_rvalid_q <= '0;
- b_rdata_q <= '0;
- b_rerror_q <= '0;
- end else begin
- a_rvalid_q <= a_rvalid_d;
- a_rdata_q <= a_rdata_d ;
- a_rerror_q <= a_rerror_d;
-
- b_rvalid_q <= b_rvalid_d;
- b_rdata_q <= b_rdata_d ;
- b_rerror_q <= b_rerror_d;
- end
- end
- end else begin : gen_dirconnect_output
- assign a_rvalid_q = a_rvalid_d;
- assign a_rdata_q = a_rdata_d;
- assign a_rerror_q = a_rerror_d;
-
- assign b_rvalid_q = b_rvalid_d;
- assign b_rdata_q = b_rdata_d;
- assign b_rerror_q = b_rerror_d;
- end
-
-endmodule
+endmodule : prim_ram_2p_adv
diff --git a/vendor/lowrisc_ip/prim/rtl/prim_ram_2p_async_adv.sv b/vendor/lowrisc_ip/prim/rtl/prim_ram_2p_async_adv.sv
index a1c8474b..ab0cd08d 100644
--- a/vendor/lowrisc_ip/prim/rtl/prim_ram_2p_async_adv.sv
+++ b/vendor/lowrisc_ip/prim/rtl/prim_ram_2p_async_adv.sv
@@ -2,63 +2,71 @@
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
-// Dual-port SRAM Wrapper
-// This module to connect SRAM interface to actual SRAM interface
-// At this time, it doesn't utilize ECC or any pipeline.
-// This module stays to include any additional calculation logic later on.
-// Instantiating SRAM is up to the top design to remove process dependency.
-
-// Parameter
-// EnableECC:
-// EnableParity:
-// EnableInputPipeline:
-// EnableOutputPipeline:
+// Asynchronous Dual-Port SRAM Wrapper
+//
+// Supported configurations:
+// - ECC for 32b wide memories with no write mask
+// (Width == 32 && DataBitsPerMask == 32).
+// - Byte parity if Width is a multiple of 8 bit and write masks have Byte
+// granularity (DataBitsPerMask == 8).
+//
+// Note that the write mask needs to be per Byte if parity is enabled. If ECC is enabled, the write
+// mask cannot be used and has to be tied to {Width{1'b1}}.
`include "prim_assert.sv"
+`include "prim_util.svh"
module prim_ram_2p_async_adv #(
- parameter int Depth = 512,
- parameter int Width = 32,
- parameter int CfgW = 8, // WTC, RTC, etc
+ parameter int Depth = 512,
+ parameter int Width = 32,
+ parameter int DataBitsPerMask = 1, // Number of data bits per bit of write mask
+ parameter int CfgW = 8, // WTC, RTC, etc
+ parameter MemInitFile = "", // VMEM file to initialize the memory with
// Configurations
- parameter bit EnableECC = 0,
- parameter bit EnableParity = 0,
- parameter bit EnableInputPipeline = 0,
- parameter bit EnableOutputPipeline = 0,
+ parameter bit EnableECC = 0, // Enables per-word ECC
+ parameter bit EnableParity = 0, // Enables per-Byte Parity
+ parameter bit EnableInputPipeline = 0, // Adds an input register (read latency +1)
+ parameter bit EnableOutputPipeline = 0, // Adds an output register (read latency +1)
- parameter MemT = "REGISTER", // can be "REGISTER" or "SRAM"
-
- // Do not touch
- parameter int SramAw = $clog2(Depth)
+ localparam int Aw = vbits(Depth)
) (
input clk_a_i,
input clk_b_i,
input rst_a_ni,
input rst_b_ni,
- input a_req_i,
- input a_write_i,
- input [SramAw-1:0] a_addr_i,
- input [Width-1:0] a_wdata_i,
- output logic a_rvalid_o,
- output logic [Width-1:0] a_rdata_o,
- output logic [1:0] a_rerror_o,
+ input a_req_i,
+ input a_write_i,
+ input [Aw-1:0] a_addr_i,
+ input [Width-1:0] a_wdata_i,
+ input [Width-1:0] a_wmask_i, // cannot be used with ECC, tie to 1 in that case
+ output logic [Width-1:0] a_rdata_o,
+ output logic a_rvalid_o, // read response (a_rdata_o) is valid
+ output logic [1:0] a_rerror_o, // Bit1: Uncorrectable, Bit0: Correctable
- input b_req_i,
- input b_write_i,
- input [SramAw-1:0] b_addr_i,
- input [Width-1:0] b_wdata_i,
- output logic b_rvalid_o,
- output logic [Width-1:0] b_rdata_o,
- output logic [1:0] b_rerror_o, // Bit1: Uncorrectable, Bit0: Correctable
+ input b_req_i,
+ input b_write_i,
+ input [Aw-1:0] b_addr_i,
+ input [Width-1:0] b_wdata_i,
+ input [Width-1:0] b_wmask_i, // cannot be used with ECC, tie to 1 in that case
+ output logic [Width-1:0] b_rdata_o,
+ output logic b_rvalid_o, // read response (b_rdata_o) is valid
+ output logic [1:0] b_rerror_o, // Bit1: Uncorrectable, Bit0: Correctable
// config
input [CfgW-1:0] cfg_i
);
+ `ASSERT_INIT(CannotHaveEccAndParity_A, !(EnableParity && EnableECC))
+
+ // While we require DataBitsPerMask to be per Byte (8) at the interface in case Byte parity is
+ // enabled, we need to switch this to a per-bit mask locally such that we can individually enable
+ // the parity bits to be written alongside the data.
+ localparam int LocalDataBitsPerMask = (EnableParity) ? 1 : DataBitsPerMask;
+
// Calculate ECC width
- localparam int ParWidth = (EnableParity) ? 1 :
+ localparam int ParWidth = (EnableParity) ? Width/8 :
(!EnableECC) ? 0 :
(Width <= 4) ? 4 :
(Width <= 11) ? 5 :
@@ -67,75 +75,54 @@ module prim_ram_2p_async_adv #(
(Width <= 120) ? 8 : 8 ;
localparam int TotalWidth = Width + ParWidth;
- logic a_req_q, a_req_d ;
- logic a_write_q, a_write_d ;
- logic [SramAw-1:0] a_addr_q, a_addr_d ;
- logic [TotalWidth-1:0] a_wdata_q, a_wdata_d ;
- logic a_rvalid_q, a_rvalid_d, a_rvalid_sram ;
- logic [TotalWidth-1:0] a_rdata_d, a_rdata_sram ;
- logic [Width-1:0] a_rdata_q ;
- logic [1:0] a_rerror_q, a_rerror_d ;
+ ////////////////////////////
+ // RAM Primitive Instance //
+ ////////////////////////////
- logic b_req_q, b_req_d ;
- logic b_write_q, b_write_d ;
- logic [SramAw-1:0] b_addr_q, b_addr_d ;
- logic [TotalWidth-1:0] b_wdata_q, b_wdata_d ;
- logic b_rvalid_q, b_rvalid_d, b_rvalid_sram ;
- logic [TotalWidth-1:0] b_rdata_d, b_rdata_sram ;
- logic [Width-1:0] b_rdata_q ;
- logic [1:0] b_rerror_q, b_rerror_d ;
+ logic a_req_q, a_req_d ;
+ logic a_write_q, a_write_d ;
+ logic [Aw-1:0] a_addr_q, a_addr_d ;
+ logic [TotalWidth-1:0] a_wdata_q, a_wdata_d ;
+ logic [TotalWidth-1:0] a_wmask_q, a_wmask_d ;
+ logic a_rvalid_q, a_rvalid_d, a_rvalid_sram ;
+ logic [Width-1:0] a_rdata_q, a_rdata_d ;
+ logic [TotalWidth-1:0] a_rdata_sram ;
+ logic [1:0] a_rerror_q, a_rerror_d ;
- if (MemT == "REGISTER") begin : gen_regmem
- prim_ram_2p #(
- // force register implementation for all targets
- .Impl (prim_pkg::ImplGeneric),
+ logic b_req_q, b_req_d ;
+ logic b_write_q, b_write_d ;
+ logic [Aw-1:0] b_addr_q, b_addr_d ;
+ logic [TotalWidth-1:0] b_wdata_q, b_wdata_d ;
+ logic [TotalWidth-1:0] b_wmask_q, b_wmask_d ;
+ logic b_rvalid_q, b_rvalid_d, b_rvalid_sram ;
+ logic [Width-1:0] b_rdata_q, b_rdata_d ;
+ logic [TotalWidth-1:0] b_rdata_sram ;
+ logic [1:0] b_rerror_q, b_rerror_d ;
- .Width (TotalWidth),
- .Depth (Depth),
- .DataBitsPerMask (TotalWidth)
- ) u_mem (
- .clk_a_i (clk_a_i),
- .clk_b_i (clk_b_i),
+ prim_ram_2p #(
+ .MemInitFile (MemInitFile),
- .a_req_i (a_req_q),
- .a_write_i (a_write_q),
- .a_addr_i (a_addr_q),
- .a_wdata_i (a_wdata_q),
- .a_wmask_i ({TotalWidth{1'b1}}),
- .a_rdata_o (a_rdata_sram),
+ .Width (TotalWidth),
+ .Depth (Depth),
+ .DataBitsPerMask (LocalDataBitsPerMask)
+ ) u_mem (
+ .clk_a_i (clk_a_i),
+ .clk_b_i (clk_b_i),
- .b_req_i (b_req_q),
- .b_write_i (b_write_q),
- .b_addr_i (b_addr_q),
- .b_wdata_i (b_wdata_q),
- .b_wmask_i ({TotalWidth{1'b1}}),
- .b_rdata_o (b_rdata_sram)
- );
- // end else if (TotalWidth == aa && Depth == yy) begin
- end else if (MemT == "SRAM") begin : gen_srammem
- prim_ram_2p #(
- .Width (TotalWidth),
- .Depth (Depth),
- .DataBitsPerMask (TotalWidth)
- ) u_mem (
- .clk_a_i (clk_a_i),
- .clk_b_i (clk_b_i),
+ .a_req_i (a_req_q),
+ .a_write_i (a_write_q),
+ .a_addr_i (a_addr_q),
+ .a_wdata_i (a_wdata_q),
+ .a_wmask_i (a_wmask_q),
+ .a_rdata_o (a_rdata_sram),
- .a_req_i (a_req_q),
- .a_write_i (a_write_q),
- .a_addr_i (a_addr_q),
- .a_wdata_i (a_wdata_q),
- .a_wmask_i ({TotalWidth{1'b1}}),
- .a_rdata_o (a_rdata_sram),
-
- .b_req_i (b_req_q),
- .b_write_i (b_write_q),
- .b_addr_i (b_addr_q),
- .b_wdata_i (b_wdata_q),
- .b_wmask_i ({TotalWidth{1'b1}}),
- .b_rdata_o (b_rdata_sram)
- );
- end
+ .b_req_i (b_req_q),
+ .b_write_i (b_write_q),
+ .b_addr_i (b_addr_q),
+ .b_wdata_i (b_wdata_q),
+ .b_wmask_i (b_wmask_q),
+ .b_rdata_o (b_rdata_sram)
+ );
always_ff @(posedge clk_a_i or negedge rst_a_ni) begin
if (!rst_a_ni) begin
@@ -166,43 +153,88 @@ module prim_ram_2p_async_adv #(
assign b_rdata_o = b_rdata_q;
assign b_rerror_o = b_rerror_q;
- // TODO: Parity Logic
- `ASSERT_INIT(ParityNotYetSupported_A, EnableParity == 0)
+ /////////////////////////////
+ // ECC / Parity Generation //
+ /////////////////////////////
if (EnableParity == 0 && EnableECC) begin : gen_secded
// check supported widths
`ASSERT_INIT(SecDecWidth_A, Width inside {32})
+ // the wmask is constantly set to 1 in this case
+ `ASSERT(OnlyWordWritePossibleWithEccPortA_A, a_req_i |->
+ a_wmask_i == {TotalWidth{1'b1}}, clk_a_i, rst_a_ni)
+ `ASSERT(OnlyWordWritePossibleWithEccPortB_A, b_req_i |->
+ b_wmask_i == {TotalWidth{1'b1}}, clk_b_i, rst_b_ni)
+
+ assign a_wmask_d = {TotalWidth{1'b1}};
+ assign b_wmask_d = {TotalWidth{1'b1}};
+
if (Width == 32) begin : gen_secded_39_32
prim_secded_39_32_enc u_enc_a (.in(a_wdata_i), .out(a_wdata_d));
prim_secded_39_32_dec u_dec_a (
.in (a_rdata_sram),
.d_o (a_rdata_d[0+:Width]),
- .syndrome_o (a_rdata_d[Width+:ParWidth]),
+ .syndrome_o ( ),
.err_o (a_rerror_d)
);
prim_secded_39_32_enc u_enc_b (.in(b_wdata_i), .out(b_wdata_d));
prim_secded_39_32_dec u_dec_b (
.in (b_rdata_sram),
.d_o (b_rdata_d[0+:Width]),
- .syndrome_o (b_rdata_d[Width+:ParWidth]),
+ .syndrome_o ( ),
.err_o (b_rerror_d)
);
- assign a_rvalid_d = a_rvalid_sram;
- assign b_rvalid_d = b_rvalid_sram;
end
- end else begin : gen_nosecded
- assign a_wdata_d[0+:Width] = a_wdata_i;
- assign b_wdata_d[0+:Width] = b_wdata_i;
- assign a_rdata_d[0+:Width] = a_rdata_sram;
- assign b_rdata_d[0+:Width] = b_rdata_sram;
- assign a_rvalid_d = a_rvalid_sram;
- assign b_rvalid_d = b_rvalid_sram;
- assign a_rerror_d = 2'b00;
- assign b_rerror_d = 2'b00;
+ end else if (EnableParity) begin : gen_byte_parity
+
+ `ASSERT_INIT(ParityNeedsByteWriteMask_A, DataBitsPerMask == 8)
+ `ASSERT_INIT(WidthNeedsToBeByteAligned_A, Width % 8 == 0)
+
+ always_comb begin : p_parity
+ a_rerror_d = '0;
+ b_rerror_d = '0;
+ a_wmask_d[0+:Width] = a_wmask_i;
+ b_wmask_d[0+:Width] = b_wmask_i;
+ a_wdata_d[0+:Width] = a_wdata_i;
+ b_wdata_d[0+:Width] = b_wdata_i;
+
+ for (int i = 0; i < Width/8; i ++) begin
+ // parity generation (odd parity)
+ a_wdata_d[Width + i] = ~(^a_wdata_i[i*8 +: 8]);
+ b_wdata_d[Width + i] = ~(^b_wdata_i[i*8 +: 8]);
+ a_wmask_d[Width + i] = &a_wmask_i[i*8 +: 8];
+ b_wmask_d[Width + i] = &b_wmask_i[i*8 +: 8];
+ // parity decoding (errors are always uncorrectable)
+ a_rerror_d[1] |= ~(^{a_rdata_sram[i*8 +: 8], a_rdata_sram[Width + i]});
+ b_rerror_d[1] |= ~(^{b_rdata_sram[i*8 +: 8], b_rdata_sram[Width + i]});
+ end
+ // tie to zero if the read data is not valid
+ a_rerror_d &= {2{a_rvalid_sram}};
+ b_rerror_d &= {2{b_rvalid_sram}};
+ end
+
+ assign a_rdata_d = a_rdata_sram[0+:Width];
+ assign b_rdata_d = b_rdata_sram[0+:Width];
+ end else begin : gen_nosecded_noparity
+ assign a_wmask_d = a_wmask_i;
+ assign b_wmask_d = b_wmask_i;
+ assign a_wdata_d = a_wdata_i;
+ assign b_wdata_d = b_wdata_i;
+ assign a_rdata_d = a_rdata_sram[0+:Width];
+ assign b_rdata_d = b_rdata_sram[0+:Width];
+ assign a_rerror_d = '0;
+ assign b_rerror_d = '0;
end
+ assign a_rvalid_d = a_rvalid_sram;
+ assign b_rvalid_d = b_rvalid_sram;
+
+ /////////////////////////////////////
+ // Input/Output Pipeline Registers //
+ /////////////////////////////////////
+
if (EnableInputPipeline) begin : gen_regslice_input
// Put the register slices between ECC encoding to SRAM port
always_ff @(posedge clk_a_i or negedge rst_a_ni) begin
@@ -211,11 +243,13 @@ module prim_ram_2p_async_adv #(
a_write_q <= '0;
a_addr_q <= '0;
a_wdata_q <= '0;
+ a_wmask_q <= '0;
end else begin
a_req_q <= a_req_d;
a_write_q <= a_write_d;
a_addr_q <= a_addr_d;
a_wdata_q <= a_wdata_d;
+ a_wmask_q <= a_wmask_d;
end
end
always_ff @(posedge clk_b_i or negedge rst_b_ni) begin
@@ -224,11 +258,13 @@ module prim_ram_2p_async_adv #(
b_write_q <= '0;
b_addr_q <= '0;
b_wdata_q <= '0;
+ b_wmask_q <= '0;
end else begin
b_req_q <= b_req_d;
b_write_q <= b_write_d;
b_addr_q <= b_addr_d;
b_wdata_q <= b_wdata_d;
+ b_wmask_q <= b_wmask_d;
end
end
end else begin : gen_dirconnect_input
@@ -236,11 +272,13 @@ module prim_ram_2p_async_adv #(
assign a_write_q = a_write_d;
assign a_addr_q = a_addr_d;
assign a_wdata_q = a_wdata_d;
+ assign a_wmask_q = a_wmask_d;
assign b_req_q = b_req_d;
assign b_write_q = b_write_d;
assign b_addr_q = b_addr_d;
assign b_wdata_q = b_wdata_d;
+ assign b_wmask_q = b_wmask_d;
end
if (EnableOutputPipeline) begin : gen_regslice_output
@@ -252,7 +290,7 @@ module prim_ram_2p_async_adv #(
a_rerror_q <= '0;
end else begin
a_rvalid_q <= a_rvalid_d;
- a_rdata_q <= a_rdata_d[0+:Width] ;
+ a_rdata_q <= a_rdata_d;
a_rerror_q <= a_rerror_d;
end
end
@@ -263,18 +301,18 @@ module prim_ram_2p_async_adv #(
b_rerror_q <= '0;
end else begin
b_rvalid_q <= b_rvalid_d;
- b_rdata_q <= b_rdata_d[0+:Width] ;
+ b_rdata_q <= b_rdata_d;
b_rerror_q <= b_rerror_d;
end
end
end else begin : gen_dirconnect_output
assign a_rvalid_q = a_rvalid_d;
- assign a_rdata_q = a_rdata_d[0+:Width];
+ assign a_rdata_q = a_rdata_d;
assign a_rerror_q = a_rerror_d;
assign b_rvalid_q = b_rvalid_d;
- assign b_rdata_q = b_rdata_d[0+:Width];
+ assign b_rdata_q = b_rdata_d;
assign b_rerror_q = b_rerror_d;
end
-endmodule
+endmodule : prim_ram_2p_async_adv
diff --git a/vendor/lowrisc_ip/prim/rtl/prim_rom_adv.sv b/vendor/lowrisc_ip/prim/rtl/prim_rom_adv.sv
new file mode 100644
index 00000000..b0c26ce1
--- /dev/null
+++ b/vendor/lowrisc_ip/prim/rtl/prim_rom_adv.sv
@@ -0,0 +1,58 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// ROM wrapper with rvalid register
+
+`include "prim_assert.sv"
+
+module prim_rom_adv #(
+ // Parameters passed on the the ROM primitive.
+ parameter int Width = 32,
+ parameter int Depth = 2048, // 8kB default
+ parameter MemInitFile = "", // VMEM file to initialize the memory with
+
+ parameter int CfgW = 8, // WTC, RTC, etc
+
+ localparam int Aw = $clog2(Depth)
+) (
+ input logic clk_i,
+ input logic rst_ni,
+ input logic req_i,
+ input logic [Aw-1:0] addr_i,
+ output logic rvalid_o,
+ output logic [Width-1:0] rdata_o,
+
+ input [CfgW-1:0] cfg_i
+);
+
+ // We will eventually use cfg_i for RTC/WTC or other memory parameters.
+ logic [CfgW-1:0] unused_cfg;
+ assign unused_cfg = cfg_i;
+
+ prim_rom #(
+ .Width(Width),
+ .Depth(Depth),
+ .MemInitFile(MemInitFile)
+ ) u_prim_rom (
+ .clk_i,
+ .req_i,
+ .addr_i,
+ .rdata_o
+ );
+
+ always_ff @(posedge clk_i or negedge rst_ni) begin
+ if (!rst_ni) begin
+ rvalid_o <= 1'b0;
+ end else begin
+ rvalid_o <= req_i;
+ end
+ end
+
+ ////////////////
+ // ASSERTIONS //
+ ////////////////
+
+ // Control Signals should never be X
+ `ASSERT(noXOnCsI, !$isunknown(req_i), clk_i, '0)
+endmodule : prim_rom_adv
diff --git a/vendor/lowrisc_ip/prim/rtl/prim_util.svh b/vendor/lowrisc_ip/prim/rtl/prim_util.svh
new file mode 100644
index 00000000..4543a377
--- /dev/null
+++ b/vendor/lowrisc_ip/prim/rtl/prim_util.svh
@@ -0,0 +1,47 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// Utility macros
+
+`ifndef PRIM_UTIL_SVH
+`define PRIM_UTIL_SVH
+
+/**
+ * Math function: Number of bits needed to address |value| items.
+ *
+ * 0 for value == 0
+ * vbits = 1 for value == 1
+ * ceil(log2(value)) for value > 1
+ *
+ *
+ * The primary use case for this function is the definition of registers/arrays
+ * which are wide enough to contain |value| items.
+ *
+ * This function identical to $clog2() for all input values except the value 1;
+ * it could be considered an "enhanced" $clog2() function.
+ *
+ *
+ * Example 1:
+ * parameter Items = 1;
+ * localparam ItemsWidth = vbits(Items); // 1
+ * logic [ItemsWidth-1:0] item_register; // items_register is now [0:0]
+ *
+ * Example 2:
+ * parameter Items = 64;
+ * localparam ItemsWidth = vbits(Items); // 6
+ * logic [ItemsWidth-1:0] item_register; // items_register is now [5:0]
+ *
+ * Note: If you want to store the number "value" inside a register, you need
+ * a register with size vbits(value + 1), since you also need to store
+ * the number 0.
+ *
+ * Example 3:
+ * logic [vbits(64)-1:0] store_64_logic_values; // width is [5:0]
+ * logic [vbits(64 + 1)-1:0] store_number_64; // width is [6:0]
+ */
+function automatic integer vbits(integer value);
+ return (value == 1) ? 1 : $clog2(value);
+endfunction
+
+`endif // PRIM_UTIL_SVH
diff --git a/vendor/lowrisc_ip/prim_generic/rtl/prim_generic_flash.sv b/vendor/lowrisc_ip/prim_generic/rtl/prim_generic_flash.sv
index 6a0655e0..682729c4 100644
--- a/vendor/lowrisc_ip/prim_generic/rtl/prim_generic_flash.sv
+++ b/vendor/lowrisc_ip/prim_generic/rtl/prim_generic_flash.sv
@@ -282,6 +282,4 @@ module prim_generic_flash #(
.rdata_o (rd_data_o)
);
-
-
endmodule // prim_generic_flash
diff --git a/vendor/lowrisc_ip/prim_generic/rtl/prim_generic_rom.sv b/vendor/lowrisc_ip/prim_generic/rtl/prim_generic_rom.sv
index 9bfe88b5..47cb80f8 100644
--- a/vendor/lowrisc_ip/prim_generic/rtl/prim_generic_rom.sv
+++ b/vendor/lowrisc_ip/prim_generic/rtl/prim_generic_rom.sv
@@ -11,27 +11,17 @@ module prim_generic_rom #(
localparam int Aw = $clog2(Depth)
) (
- input clk_i,
- input rst_ni,
- input [Aw-1:0] addr_i,
- input cs_i,
- output logic [Width-1:0] dout_o,
- output logic dvalid_o
+ input logic clk_i,
+ input logic req_i,
+ input logic [Aw-1:0] addr_i,
+ output logic [Width-1:0] rdata_o
);
logic [Width-1:0] mem [Depth];
always_ff @(posedge clk_i) begin
- if (cs_i) begin
- dout_o <= mem[addr_i];
- end
- end
-
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- dvalid_o <= 1'b0;
- end else begin
- dvalid_o <= cs_i;
+ if (req_i) begin
+ rdata_o <= mem[addr_i];
end
end
@@ -42,5 +32,5 @@ module prim_generic_rom #(
////////////////
// Control Signals should never be X
- `ASSERT(noXOnCsI, !$isunknown(cs_i), clk_i, '0)
+ `ASSERT(noXOnCsI, !$isunknown(req_i), clk_i, '0)
endmodule