mirror of
https://github.com/openhwgroup/cve2.git
synced 2025-04-22 21:17:59 -04:00
Update lowrisc_ip to lowRISC/opentitan@c91b50f3
This is manually squashed with a change to import dv_base_reg too, a new module that was created by Weicai's "csr backdoor support" patch. It's needed because it is a dependency of dv_lib. Update code from upstream repository https://github.com/lowRISC/opentitan to revision c91b50f357a76dae2ada104e397f6a91f72a33da * [prim_ram*_adv] Update core files and add prim_util dependency (Michael Schaffner) * [prim_ram*_adv] Implement Byte parity in prim_ram*_adv (Michael Schaffner) * [dvsim] Run tests in "interleaved" order (Rupert Swarbrick) * [dvsim] Remove unnecessary getattr/setattr calls from SimCfg.py (Rupert Swarbrick) * [dv] Add support for multiple ral models (Srikrishna Iyer) * [rtl] Fix prim flash dependency (Srikrishna Iyer) * [prim_fifo_sync] Make FIFO output zero when empty (Noah Moroze) * [dv] csr backdoor support (Weicai Yang) * [prim] Add a "clog2 width" function (Philipp Wagner) * [dvsim] Allow max-parallel to be set in the environment (Rupert Swarbrick) * [dvsim] Fix --reseed argument (Rupert Swarbrick) * [prim_ram/rom*_adv] Break out into individual core files (Michael Schaffner) * [prim_rom] Align port naming with prim_ram* (Michael Schaffner) * [dv] Allow a test to have "simple" timestamps (Rupert Swarbrick) * [dvsim] Improve --help message (Rupert Swarbrick) * [dvsim] Remove unused --local argument (Rupert Swarbrick) * [dvsim] Small tidy-ups to mode selection in SimCfg.py (Rupert Swarbrick) * [fpv] formal compile fix required by VC Formal (Cindy Chen) * [dvsim] Fix error detection logic in Deploy.py (Rupert Swarbrick) Signed-off-by: Rupert Swarbrick <rswarbrick@lowrisc.org>
This commit is contained in:
parent
d79eb58ae5
commit
8c11bd780c
36 changed files with 1224 additions and 823 deletions
2
vendor/lowrisc_ip.lock.hjson
vendored
2
vendor/lowrisc_ip.lock.hjson
vendored
|
@ -9,6 +9,6 @@
|
|||
upstream:
|
||||
{
|
||||
url: https://github.com/lowRISC/opentitan
|
||||
rev: d78da129c7f2b115ccabd1c3af199e0e5812f365
|
||||
rev: c91b50f357a76dae2ada104e397f6a91f72a33da
|
||||
}
|
||||
}
|
||||
|
|
23
vendor/lowrisc_ip.vendor.hjson
vendored
23
vendor/lowrisc_ip.vendor.hjson
vendored
|
@ -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"},
|
||||
]
|
||||
}
|
||||
|
|
33
vendor/lowrisc_ip/common_ifs/clk_rst_if.sv
vendored
33
vendor/lowrisc_ip/common_ifs/clk_rst_if.sv
vendored
|
@ -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;
|
||||
|
|
2
vendor/lowrisc_ip/csr_utils/csr_utils.core
vendored
2
vendor/lowrisc_ip/csr_utils/csr_utils.core
vendored
|
@ -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
|
||||
|
||||
|
|
92
vendor/lowrisc_ip/csr_utils/csr_utils_pkg.sv
vendored
92
vendor/lowrisc_ip/csr_utils/csr_utils_pkg.sv
vendored
|
@ -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,
|
||||
|
|
25
vendor/lowrisc_ip/dv_base_reg/dv_base_reg.core
vendored
Normal file
25
vendor/lowrisc_ip/dv_base_reg/dv_base_reg.core
vendored
Normal file
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
49
vendor/lowrisc_ip/dv_base_reg/dv_base_reg_pkg.sv
vendored
Normal file
49
vendor/lowrisc_ip/dv_base_reg/dv_base_reg_pkg.sv
vendored
Normal file
|
@ -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
|
2
vendor/lowrisc_ip/dv_lib/dv_base_env_cfg.sv
vendored
2
vendor/lowrisc_ip/dv_lib/dv_base_env_cfg.sv
vendored
|
@ -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
|
||||
|
||||
|
|
8
vendor/lowrisc_ip/dv_lib/dv_base_vseq.sv
vendored
8
vendor/lowrisc_ip/dv_lib/dv_base_vseq.sv
vendored
|
@ -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);
|
||||
|
|
7
vendor/lowrisc_ip/dv_lib/dv_lib.core
vendored
7
vendor/lowrisc_ip/dv_lib/dv_lib.core
vendored
|
@ -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}
|
||||
|
|
8
vendor/lowrisc_ip/dv_lib/dv_lib_pkg.sv
vendored
8
vendor/lowrisc_ip/dv_lib/dv_lib_pkg.sv
vendored
|
@ -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"
|
||||
|
|
6
vendor/lowrisc_ip/dvsim/Deploy.py
vendored
6
vendor/lowrisc_ip/dvsim/Deploy.py
vendored
|
@ -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:<br>\n"
|
||||
self.fail_msg += msg
|
||||
log.log(VERBOSE, msg)
|
||||
|
|
82
vendor/lowrisc_ip/dvsim/SimCfg.py
vendored
82
vendor/lowrisc_ip/dvsim/SimCfg.py
vendored
|
@ -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
|
||||
|
|
629
vendor/lowrisc_ip/dvsim/dvsim.py
vendored
629
vendor/lowrisc_ip/dvsim/dvsim.py
vendored
|
@ -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="<cfg-hjson-file>",
|
||||
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="<branch-name>",
|
||||
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')
|
||||
|
||||
|
|
4
vendor/lowrisc_ip/prim/prim.core
vendored
4
vendor/lowrisc_ip/prim/prim.core
vendored
|
@ -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:
|
||||
|
|
3
vendor/lowrisc_ip/prim/prim_flash.core
vendored
3
vendor/lowrisc_ip/prim/prim_flash.core
vendored
|
@ -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:
|
||||
|
|
3
vendor/lowrisc_ip/prim/prim_ram_1p_adv.core
vendored
3
vendor/lowrisc_ip/prim/prim_ram_1p_adv.core
vendored
|
@ -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
|
||||
|
|
19
vendor/lowrisc_ip/prim/prim_ram_2p_adv.core
vendored
Normal file
19
vendor/lowrisc_ip/prim/prim_ram_2p_adv.core
vendored
Normal file
|
@ -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
|
22
vendor/lowrisc_ip/prim/prim_ram_2p_async_adv.core
vendored
Normal file
22
vendor/lowrisc_ip/prim/prim_ram_2p_async_adv.core
vendored
Normal file
|
@ -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
|
20
vendor/lowrisc_ip/prim/prim_rom_adv.core
vendored
Normal file
20
vendor/lowrisc_ip/prim/prim_rom_adv.core
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
CAPI=2:
|
||||
# Copyright lowRISC contributors.
|
||||
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
name: "lowrisc: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
|
17
vendor/lowrisc_ip/prim/prim_util.core
vendored
Normal file
17
vendor/lowrisc_ip/prim/prim_util.core
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
CAPI=2:
|
||||
# Copyright lowRISC contributors.
|
||||
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
name: "lowrisc:prim:util:0.1"
|
||||
description: "Utilities"
|
||||
filesets:
|
||||
files_rtl:
|
||||
files:
|
||||
- rtl/prim_util.svh : {is_include_file : true}
|
||||
file_type: systemVerilogSource
|
||||
|
||||
targets:
|
||||
default:
|
||||
filesets:
|
||||
- files_rtl
|
12
vendor/lowrisc_ip/prim/rtl/prim_fifo_sync.sv
vendored
12
vendor/lowrisc_ip/prim/rtl/prim_fifo_sync.sv
vendored
|
@ -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
|
||||
|
||||
|
|
2
vendor/lowrisc_ip/prim/rtl/prim_lfsr.sv
vendored
2
vendor/lowrisc_ip/prim/rtl/prim_lfsr.sv
vendored
|
@ -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
|
||||
|
|
222
vendor/lowrisc_ip/prim/rtl/prim_ram_1p_adv.sv
vendored
222
vendor/lowrisc_ip/prim/rtl/prim_ram_1p_adv.sv
vendored
|
@ -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
|
||||
|
|
322
vendor/lowrisc_ip/prim/rtl/prim_ram_2p_adv.sv
vendored
322
vendor/lowrisc_ip/prim/rtl/prim_ram_2p_adv.sv
vendored
|
@ -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
|
||||
|
|
278
vendor/lowrisc_ip/prim/rtl/prim_ram_2p_async_adv.sv
vendored
278
vendor/lowrisc_ip/prim/rtl/prim_ram_2p_async_adv.sv
vendored
|
@ -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
|
||||
|
|
58
vendor/lowrisc_ip/prim/rtl/prim_rom_adv.sv
vendored
Normal file
58
vendor/lowrisc_ip/prim/rtl/prim_rom_adv.sv
vendored
Normal file
|
@ -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
|
47
vendor/lowrisc_ip/prim/rtl/prim_util.svh
vendored
Normal file
47
vendor/lowrisc_ip/prim/rtl/prim_util.svh
vendored
Normal file
|
@ -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
|
|
@ -282,6 +282,4 @@ module prim_generic_flash #(
|
|||
.rdata_o (rd_data_o)
|
||||
);
|
||||
|
||||
|
||||
|
||||
endmodule // prim_generic_flash
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue