Update code from upstream repository
https://github.com/lowRISC/opentitan to revision
067272a253f4eeed4ae58a9171ee266256528117

* [dv/common] initial support for shadow register (Cindy Chen)
* [rtl/prince] Small fixes for PRINCE cipher logic (Udi Jonnalagadda)
* [dv doc] Fix rendered testplan table (Srikrishna Iyer)
* [prim/dv] Enable coverage collection for PRESENT (Udi Jonnalagadda)
* [dvsim/syn] Minor fix in message reporting (Michael Schaffner)
* [prim] Make prim_clock_inverter a tech specific prim (Michael
  Schaffner)
* [vsg] fix _i/_o for several modules (Scott Johnson)
* [doc] Update Licence Headers to fit agreed style (Sam Elliott)
* [vsg] fix _i/_o usage on sram_arbiter (Scott Johnson)
* [vsg] fix _i/_o usage on prim_fifo (Scott Johnson)
* switch to host, primary, or over-arching as appropriate (Scott
  Johnson)
* [dvsim/lint/syn] Properly set the errors_seen value to return
  nonzero status (Michael Schaffner)
* [dvsim] Fix open() call with Pathlib for older Python versions
  (Michael Schaffner)
* [style-lint] Last round of minor fixes to get all targets clean
  (Michael Schaffner)
* [prim] Add shadow register primitive (Pirmin Vogel)
* [flash_ctrl] Cosmetic updates enum literals (Srikrishna Iyer)
* [tool/script] delete clean section in make files (Cindy Chen)
* [dvsim] Add git commit and branch info to reports (Michael
  Schaffner)
* [dvsim/syn/lint] Add options to selectively sanitize reports
  (Michael Schaffner)
* [lint] Update waiver file for prim_generic_pad_wrapper (Michael
  Schaffner)
* [prim_pad_wrapper] Update pad wrapper (Michael Schaffner)
* [alert_handler/rtl] priority between ping_ok and sig_int_err (Cindy
  Chen)
* [prim] Add a few prim cells needed for clock / resets (Timothy Chen)
* [dv] added default timeout message to DV_SPINWAIT (Srikrishna Iyer)
* [dv] Add mechanism to configure vseq via knobs (Srikrishna Iyer)
* Make the wmask assertion in prim_generic_ram_*p only apply to writes
  (Rupert Swarbrick)
* [prim_gate_gen] Recalibrate gate generator for new std cells
  (Michael Schaffner)
* [primgen] Use SafeDumper for YAML (Philipp Wagner)
* [primgen] Fix some flake8-reported style issues (Philipp Wagner)
* [prim] Improve extraction of parameter port list (Philipp Wagner)
* [prim] Remove outdated comment from primgen (Philipp Wagner)
* Added missing include prim_assert.sv (Dawid Zimonczyk)

Signed-off-by: Rupert Swarbrick <rswarbrick@lowrisc.org>
This commit is contained in:
Rupert Swarbrick 2020-07-23 11:18:21 +01:00 committed by Rupert Swarbrick
parent 94d5057168
commit e37c81a1c1
65 changed files with 1497 additions and 659 deletions

View file

@ -9,6 +9,6 @@
upstream:
{
url: https://github.com/lowRISC/opentitan
rev: ebf4663b42a9d81d026db5821b5c8249d54f23a7
rev: 067272a253f4eeed4ae58a9171ee266256528117
}
}

View file

@ -178,12 +178,13 @@ package csr_utils_pkg;
input uvm_path_e path = UVM_DEFAULT_PATH,
input bit blocking = default_csr_blocking,
input uint timeout_ns = default_timeout_ns,
input uvm_reg_map map = null);
input uvm_reg_map map = null,
input bit en_shadow_wr = 1);
if (blocking) begin
csr_update_sub(csr, check, path, timeout_ns, map);
csr_update_sub(csr, check, path, timeout_ns, map, en_shadow_wr);
end else begin
fork
csr_update_sub(csr, check, path, timeout_ns, map);
csr_update_sub(csr, check, path, timeout_ns, map, en_shadow_wr);
join_none
// Add #0 to ensure that this thread starts executing before any subsequent call
#0;
@ -195,7 +196,8 @@ package csr_utils_pkg;
input uvm_check_e check = UVM_CHECK,
input uvm_path_e path = UVM_DEFAULT_PATH,
input uint timeout_ns = default_timeout_ns,
input uvm_reg_map map = null);
input uvm_reg_map map = null,
input bit en_shadow_wr = 1);
fork
begin : isolation_fork
uvm_status_e status;
@ -204,7 +206,9 @@ package csr_utils_pkg;
fork
begin
increment_outstanding_access();
csr_pre_write_sub(csr, en_shadow_wr);
csr.update(.status(status), .path(path), .map(map), .prior(100));
csr_post_write_sub(csr, en_shadow_wr);
if (check == UVM_CHECK) begin
`DV_CHECK_EQ(status, UVM_IS_OK, "", error, msg_id)
end
@ -229,16 +233,17 @@ package csr_utils_pkg;
input bit backdoor = 0,
input uint timeout_ns = default_timeout_ns,
input bit predict = 0,
input uvm_reg_map map = null);
input uvm_reg_map map = null,
input bit en_shadow_wr = 1);
if (backdoor) begin
csr_poke(csr, value, check, predict);
end else if (blocking) begin
csr_wr_sub(csr, value, check, path, timeout_ns, map);
csr_wr_sub(csr, value, check, path, timeout_ns, map, en_shadow_wr);
if (predict) void'(csr.predict(.value(value), .kind(UVM_PREDICT_WRITE)));
end else begin
fork
begin
csr_wr_sub(csr, value, check, path, timeout_ns, map);
csr_wr_sub(csr, value, check, path, timeout_ns, map, en_shadow_wr);
// predict after csr_wr_sub, to ensure predict after enable register overwrite the locked
// registers' access information
if (predict) void'(csr.predict(.value(value), .kind(UVM_PREDICT_WRITE)));
@ -255,7 +260,8 @@ package csr_utils_pkg;
input uvm_check_e check = UVM_CHECK,
input uvm_path_e path = UVM_DEFAULT_PATH,
input uint timeout_ns = default_timeout_ns,
input uvm_reg_map map = null);
input uvm_reg_map map = null,
input bit en_shadow_wr = 1);
fork
begin : isolation_fork
uvm_status_e status;
@ -264,7 +270,9 @@ package csr_utils_pkg;
fork
begin
increment_outstanding_access();
csr_pre_write_sub(csr, en_shadow_wr);
csr.write(.status(status), .value(value), .path(path), .map(map), .prior(100));
csr_post_write_sub(csr, en_shadow_wr);
if (check == UVM_CHECK) begin
`DV_CHECK_EQ(status, UVM_IS_OK, "", error, msg_id)
end
@ -281,6 +289,30 @@ package csr_utils_pkg;
join
endtask
task automatic csr_pre_write_sub(ref uvm_reg csr, bit en_shadow_wr);
dv_base_reg dv_reg;
`downcast(dv_reg, csr, "", fatal, msg_id)
if (dv_reg.get_is_shadowed()) begin
if (en_shadow_wr) increment_outstanding_access();
dv_reg.atomic_en_shadow_wr.get(1);
dv_reg.set_en_shadow_wr(en_shadow_wr);
end
endtask
task automatic csr_post_write_sub(ref uvm_reg csr, bit en_shadow_wr);
dv_base_reg dv_reg;
`downcast(dv_reg, csr, "", fatal, msg_id)
if (dv_reg.get_is_shadowed()) begin
// try setting en_shadow_wr back to default value 1, this function will only work if the
// shadow reg finished both writes
dv_reg.set_en_shadow_wr(1);
dv_reg.atomic_en_shadow_wr.put(1);
if (en_shadow_wr) begin
decrement_outstanding_access();
end
end
endtask
// backdoor write csr
task automatic csr_poke(input uvm_reg csr,
input uvm_reg_data_t value,

View file

@ -8,12 +8,27 @@ class dv_base_reg extends uvm_reg;
// hence, backdoor write isn't available
local bit is_ext_reg;
local dv_base_reg locked_regs[$];
local dv_base_reg locked_regs[$];
local uvm_reg_data_t staged_shadow_val;
local bit is_shadowed;
local bit shadow_wr_staged; // stage the first shadow reg write
local bit shadow_update_err;
local bit en_shadow_wr = 1;
// atomic_shadow_wr: semaphore to guarantee atomicity of the two writes for shadowed registers.
// In case a parallel thread writing a different value to the same reg causing an update_err
semaphore atomic_shadow_wr;
// atomic_en_shadow_wr: semaphore to guarantee setting or resetting en_shadow_wr is unchanged
// through the 1st/2nd (or both) writes
semaphore atomic_en_shadow_wr;
function new(string name = "",
int unsigned n_bits,
int has_coverage);
super.new(name, n_bits, has_coverage);
atomic_en_shadow_wr = new(1);
atomic_shadow_wr = new(1);
endfunction : new
function void get_dv_base_reg_fields(ref dv_base_reg_field dv_fields[$]);
@ -63,12 +78,58 @@ class dv_base_reg extends uvm_reg;
locked_regs_q = locked_regs;
endfunction
// post_write callback to handle reg enables
// is_shadowed bit is only one-time programmable
// once this function is called in RAL auto-generated class, it cannot be changed
function void set_is_shadowed();
is_shadowed = 1;
endfunction
function void set_en_shadow_wr(bit val);
// do not update en_shadow_wr if shadow register write is in process
if ((en_shadow_wr ^ val) && shadow_wr_staged) begin
`uvm_info(`gfn,
$sformatf("unable to %s en_shadow_wr because register already completed first write",
val ? "set" : "clear"), UVM_LOW)
return;
end
en_shadow_wr = val;
endfunction
function bit get_is_shadowed();
return is_shadowed;
endfunction
function bit get_shadow_update_err();
return shadow_update_err;
endfunction
virtual function void clear_shadow_update_err();
shadow_update_err = 0;
endfunction
// post_write callback to handle special regs:
// - shadow register, enable reg won't be updated until the second write has no error
// - enable register, if enable_reg is disabled, change access policy to all the locked_regs
// TODO: create an `enable_field_access_policy` variable and set the template code during
// automation.
virtual task post_write(uvm_reg_item rw);
dv_base_reg_field fields[$];
string field_access;
if (is_shadowed) begin
// first write
if (!shadow_wr_staged) begin
shadow_wr_staged = 1;
staged_shadow_val = rw.value[0];
return;
end begin
// second write
shadow_wr_staged = 0;
if (staged_shadow_val != rw.value[0]) begin
shadow_update_err = 1;
return;
end
end
end
if (is_enable_reg()) begin
get_dv_base_reg_fields(fields);
field_access = fields[0].get_access();
@ -77,7 +138,7 @@ class dv_base_reg extends uvm_reg;
"W1C": if (rw.value[0][0] == 1'b1) set_locked_regs_access("RO");
"W0C": if (rw.value[0][0] == 1'b0) set_locked_regs_access("RO");
"RO": ; // if RO, it's updated by design, need to predict in scb
default:`uvm_fatal(`gtn, $sformatf("enable register invalid access %s", field_access))
default:`uvm_fatal(`gfn, $sformatf("enable register invalid access %s", field_access))
endcase
end
endtask
@ -90,4 +151,49 @@ class dv_base_reg extends uvm_reg;
return is_ext_reg;
endfunction
// if it is a shadowed register, and is enabled to write it twice, this task will write the
// register twice with the same value and address.
virtual task write(output uvm_status_e status,
input uvm_reg_data_t value,
input uvm_path_e path = UVM_DEFAULT_PATH,
input uvm_reg_map map = null,
input uvm_sequence_base parent=null,
input int prior = -1,
input uvm_object extension = null,
input string fname = "",
input int lineno = 0);
if (is_shadowed) atomic_shadow_wr.get(1);
super.write(status, value, path, map, parent, prior, extension, fname, lineno);
if (is_shadowed && en_shadow_wr) begin
super.write(status, value, path, map, parent, prior, extension, fname, lineno);
end
if (is_shadowed) atomic_shadow_wr.put(1);
endtask
// override do_predict function to support shadow_reg:
// skip predict if it is shadow_reg's first write, or second write with an update_err
virtual function void do_predict (uvm_reg_item rw,
uvm_predict_e kind = UVM_PREDICT_DIRECT,
uvm_reg_byte_en_t be = -1);
if (is_shadowed && (shadow_wr_staged || shadow_update_err) && kind != UVM_PREDICT_READ) begin
`uvm_info(`gfn,
$sformatf("skip predict csr %s: due to shadow_reg_first_wr=%0b or update_err=%0b",
get_name(), shadow_wr_staged, shadow_update_err), UVM_HIGH)
return;
end
super.do_predict(rw, kind, be);
endfunction
virtual function void reset(string kind = "HARD");
super.reset(kind);
if (is_shadowed) begin
shadow_update_err = 0;
shadow_wr_staged = 0;
// in case reset is issued during shadowed writes
void'(atomic_shadow_wr.try_get(1));
void'(atomic_en_shadow_wr.try_get(1));
atomic_shadow_wr.put(1);
atomic_en_shadow_wr.put(1);
end
endfunction
endclass

View file

@ -37,11 +37,30 @@ class dv_base_vseq #(type RAL_T = dv_base_reg_block,
`uvm_object_new
task pre_start();
super.pre_start();
virtual function void set_handles();
`DV_CHECK_NE_FATAL(p_sequencer, null, "Did you forget to call `set_sequencer()`?")
cfg = p_sequencer.cfg;
cov = p_sequencer.cov;
ral = cfg.ral;
endfunction
// This function is invoked in pre_randomize(). Override it in the extended classes to configure
// / control the randomization of this sequence.
virtual function void configure_vseq();
endfunction
function void pre_randomize();
// Set the handles in pre_randomize(), so that the knobs in cfg are available during sequence
// randomization. This forces `p_sequencer` handle to be set before the randomization - users
// are required to call `set_sequencer()` right after creating the sequence and before
// randomizing it.
if (cfg == null) set_handles();
configure_vseq();
endfunction
task pre_start();
super.pre_start();
if (cfg == null) set_handles();
if (do_dut_init) dut_init("HARD");
num_trans.rand_mode(0);
endtask

View file

@ -305,7 +305,7 @@
// ...
// end)
`ifndef DV_SPINWAIT
`define DV_SPINWAIT(WAIT_, MSG_ = "", TIMEOUT_NS_ = default_spinwait_timeout_ns, ID_ =`gfn) \
`define DV_SPINWAIT(WAIT_, MSG_ = "timeout occurred!", TIMEOUT_NS_ = default_spinwait_timeout_ns, ID_ =`gfn) \
begin \
fork begin \
fork \

View file

@ -13,7 +13,7 @@ import sys
import hjson
from Deploy import Deploy
from utils import VERBOSE, md_results_to_html, parse_hjson, print_msg_list, subst_wildcards
from utils import VERBOSE, md_results_to_html, parse_hjson, subst_wildcards
# Interface class for extensions.
@ -51,15 +51,15 @@ class FlowCfg():
# are overridden with the override values.
self.overrides = []
# List of cfgs if the parsed cfg is a master cfg list
# List of cfgs if the parsed cfg is a primary cfg list
self.cfgs = []
# Add a notion of "master" cfg - this is indicated using
# Add a notion of "primary" cfg - this is indicated using
# a special key 'use_cfgs' within the hjson cfg.
self.is_master_cfg = False
self.is_primary_cfg = False
# For a master cfg, it is the aggregated list of all deploy objects under self.cfgs.
# For a non-master cfg, it is the list of items slated for dispatch.
# For a primary cfg, it is the aggregated list of all deploy objects under self.cfgs.
# For a non-primary cfg, it is the list of items slated for dispatch.
self.deploy = []
# Timestamp
@ -72,6 +72,7 @@ class FlowCfg():
self.errors_seen = False
self.rel_path = ""
self.results_title = ""
self.revision_string = ""
self.results_server_prefix = ""
self.results_server_url_prefix = ""
self.results_server_cmd = ""
@ -83,14 +84,20 @@ class FlowCfg():
self.results_summary_server_html = ""
self.results_summary_server_page = ""
# Full and summary results in md text.
# Full results in md text
self.results_md = ""
# Selectively sanitized md results to be mailed out or published
self.email_results_md = ""
self.publish_results_md = ""
self.sanitize_email_results = False
self.sanitize_publish_results = False
# Summary results, generated by over-arching cfg
self.email_summary_md = ""
self.results_summary_md = ""
self.email_summary_md = "" # if user wanted to customize email content
def __post_init__(self):
# Run some post init checks
if not self.is_master_cfg:
if not self.is_primary_cfg:
# Check if self.cfgs is a list of exactly 1 item (self)
if not (len(self.cfgs) == 1 and self.cfgs[0].name == self.name):
log.error("Parse error!\n%s", self.cfgs)
@ -122,12 +129,12 @@ class FlowCfg():
'''
hjson_dict = parse_hjson(flow_cfg_file)
# Check if this is the master cfg, if this is the entry point cfg file
# Check if this is the primary cfg, if this is the entry point cfg file
if is_entry_point:
self.is_master_cfg = self.check_if_master_cfg(hjson_dict)
self.is_primary_cfg = self.check_if_primary_cfg(hjson_dict)
# If not a master cfg, then register self with self.cfgs
if self.is_master_cfg is False:
# If not a primary cfg, then register self with self.cfgs
if self.is_primary_cfg is False:
self.cfgs.append(self)
# Resolve the raw hjson dict to build this object
@ -141,8 +148,8 @@ class FlowCfg():
self.rel_path = os.path.dirname(self.flow_cfg_file).replace(
self.proj_root + '/', '')
def check_if_master_cfg(self, hjson_dict):
# This is a master cfg only if it has a single key called "use_cfgs"
def check_if_primary_cfg(self, hjson_dict):
# This is a primary cfg only if it has a single key called "use_cfgs"
# which contains a list of actual flow cfgs.
hjson_cfg_dict_keys = hjson_dict.keys()
return ("use_cfgs" in hjson_cfg_dict_keys and type(hjson_dict["use_cfgs"]) is list)
@ -219,15 +226,15 @@ class FlowCfg():
import_cfgs.extend(hjson_dict[key])
rm_hjson_dict_keys.append(key)
# If this is a master cfg list and the key is 'use_cfgs'
elif self.is_master_cfg and key == "use_cfgs":
# If this is a primary cfg list and the key is 'use_cfgs'
elif self.is_primary_cfg and key == "use_cfgs":
use_cfgs.extend(hjson_dict[key])
# If this is a not master cfg list and the key is 'use_cfgs'
elif not self.is_master_cfg and key == "use_cfgs":
# If this is a not primary cfg list and the key is 'use_cfgs'
elif not self.is_primary_cfg and key == "use_cfgs":
# Throw an error and exit
log.error(
"Key \"use_cfgs\" encountered in a non-master cfg file list \"%s\"",
"Key \"use_cfgs\" encountered in a non-primary cfg file list \"%s\"",
self.flow_cfg_file)
sys.exit(1)
@ -247,8 +254,8 @@ class FlowCfg():
else:
log.error("Cfg file \"%s\" has already been parsed", cfg_file)
# Parse master cfg files
if self.is_master_cfg:
# Parse primary cfg files
if self.is_primary_cfg:
for entry in use_cfgs:
if type(entry) is str:
# Treat this as a file entry
@ -283,10 +290,10 @@ class FlowCfg():
def _conv_inline_cfg_to_hjson(self, idict):
'''Dump a temp hjson file in the scratch space from input dict.
This method is to be called only by a master cfg'''
This method is to be called only by a primary cfg'''
if not self.is_master_cfg:
log.fatal("This method can only be called by a master cfg")
if not self.is_primary_cfg:
log.fatal("This method can only be called by a primary cfg")
sys.exit(1)
name = idict["name"] if "name" in idict.keys() else None
@ -405,7 +412,7 @@ class FlowCfg():
item._print_list()
def prune_selected_cfgs(self):
'''Prune the list of configs for a master config file'''
'''Prune the list of configs for a primary config file'''
# This should run after self.cfgs has been set
assert self.cfgs
@ -414,10 +421,10 @@ class FlowCfg():
if self.select_cfgs is None:
return
# If the user passed --select-cfgs, but this isn't a master config
# If the user passed --select-cfgs, but this isn't a primary config
# file, we should probably complain.
if not self.is_master_cfg:
log.error('The configuration file at {!r} is not a master config, '
if not self.is_primary_cfg:
log.error('The configuration file at {!r} is not a primary config, '
'but --select-cfgs was passed on the command line.'
.format(self.flow_cfg_file))
sys.exit(1)
@ -436,7 +443,7 @@ class FlowCfg():
'''Public facing API for _create_deploy_objects().
'''
self.prune_selected_cfgs()
if self.is_master_cfg:
if self.is_primary_cfg:
self.deploy = []
for item in self.cfgs:
item._create_deploy_objects()
@ -468,7 +475,7 @@ class FlowCfg():
results.append(result)
self.errors_seen |= item.errors_seen
if self.is_master_cfg:
if self.is_primary_cfg:
self.gen_results_summary()
self.gen_email_html_summary()
@ -485,12 +492,12 @@ class FlowCfg():
return "[%s](%s)" % (link_text, results_page_url)
def gen_email_html_summary(self):
if self.is_master_cfg:
if self.is_primary_cfg:
# user can customize email content by using email_summary_md,
# otherwise default to send out results_summary_md
gen_results = self.email_summary_md or self.results_summary_md
else:
gen_results = self.results_md
gen_results = self.email_results_md or self.results_md
results_html = md_results_to_html(self.results_title, self.css_file, gen_results)
results_html_file = self.scratch_root + "/email.html"
f = open(results_html_file, 'w')
@ -613,14 +620,15 @@ class FlowCfg():
rm_cmd = self.results_server_cmd + " -m rm -r " + rm_cmd + "; "
# Append the history to the results.
results_md = self.results_md + history_txt
publish_results_md = self.publish_results_md or self.results_md
publish_results_md = publish_results_md + history_txt
# Publish the results page.
# First, write the results html file temporarily to the scratch area.
results_html_file = self.scratch_path + "/results_" + self.timestamp + ".html"
f = open(results_html_file, 'w')
f.write(
md_results_to_html(self.results_title, self.css_file, results_md))
md_results_to_html(self.results_title, self.css_file, publish_results_md))
f.close()
rm_cmd += "/bin/rm -rf " + results_html_file + "; "
@ -643,7 +651,7 @@ class FlowCfg():
for item in self.cfgs:
item._publish_results()
if self.is_master_cfg:
if self.is_primary_cfg:
self.publish_results_summary()
def publish_results_summary(self):

View file

@ -125,7 +125,10 @@ class FpvCfg(OneShotCfg):
log.info("Create summary of FPV results")
results_str = "## " + self.results_title + " (Summary)\n\n"
results_str += "### " + self.timestamp_long + "\n\n"
results_str += "### " + self.timestamp_long + "\n"
if self.revision_string:
results_str += "### " + self.revision_string + "\n"
results_str += "\n"
colalign = ("center", ) * len(self.summary_header)
table = [self.summary_header]
@ -216,6 +219,8 @@ class FpvCfg(OneShotCfg):
# }
results_str = "## " + self.results_title + "\n\n"
results_str += "### " + self.timestamp_long + "\n"
if self.revision_string:
results_str += "### " + self.revision_string + "\n"
results_str += "### FPV Tool: " + self.tool.upper() + "\n"
results_str += "### LogFile dir: " + self.scratch_path + "/default\n\n"

View file

@ -14,6 +14,7 @@ from tabulate import tabulate
from OneShotCfg import OneShotCfg
from utils import print_msg_list, subst_wildcards
class LintCfg(OneShotCfg):
"""Derivative class for linting purposes.
"""
@ -46,7 +47,11 @@ class LintCfg(OneShotCfg):
log.info("Create summary of lint results")
results_str = "## " + self.results_title + " (Summary)\n\n"
results_str += "### " + self.timestamp_long + "\n\n"
results_str += "### " + self.timestamp_long + "\n"
if self.revision_string:
results_str += "### " + self.revision_string + "\n"
results_str += "\n"
header = [
"Name", "Tool Warnings", "Tool Errors", "Lint Warnings",
@ -102,13 +107,15 @@ class LintCfg(OneShotCfg):
# parsing script that transforms the tool output into the hjson above
# needs to be adapted.
#
# note that if this is a master config, the results will
# note that if this is a primary config, the results will
# be generated using the _gen_results_summary function
# '''
# Generate results table for runs.
results_str = "## " + self.results_title + "\n\n"
results_str += "### " + self.timestamp_long + "\n"
if self.revision_string:
results_str += "### " + self.revision_string + "\n"
results_str += "### Lint Tool: " + self.tool.upper() + "\n\n"
header = [
@ -133,7 +140,7 @@ class LintCfg(OneShotCfg):
log.info("looking for result data file at %s", result_data)
try:
with open(result_data, "r") as results_file:
with result_data.open() as results_file:
self.result = hjson.load(results_file, use_decimal=True)
except IOError as err:
log.warning("%s", err)
@ -177,13 +184,16 @@ class LintCfg(OneShotCfg):
("Lint Warnings", "lint_warnings"),
("Lint Errors", "lint_errors")]
has_msg = False
# Lint fails if any warning or error message has occurred
self.errors_seen = False
for _, key in hdr_key_pairs:
if key in self.result:
has_msg = True
break
if self.result.get(key):
self.errors_seen = True
break
if has_msg:
if self.errors_seen:
fail_msgs += "\n### Errors and Warnings for Build Mode `'" + mode.name + "'`\n"
for hdr, key in hdr_key_pairs:
msgs = self.result.get(key)
@ -192,9 +202,21 @@ class LintCfg(OneShotCfg):
if len(table) > 1:
self.results_md = results_str + tabulate(
table, headers="firstrow", tablefmt="pipe",
colalign=colalign) + "\n" + fail_msgs
colalign=colalign) + "\n"
# the email and published reports will default to self.results_md if they are
# empty. in case they need to be sanitized, override them and do not append
# detailed messages.
if self.sanitize_email_results:
self.email_results_md = self.results_md
if self.sanitize_publish_results:
self.publish_results_md = self.results_md
# locally generated result always contains all details
self.results_md += fail_msgs
else:
self.results_md = results_str + "\nNo results to display.\n"
self.email_results_md = self.results_md
self.publish_results_md = self.results_md
# Write results to the scratch area
self.results_file = self.scratch_path + "/results_" + self.timestamp + ".md"

View file

@ -93,8 +93,8 @@ class OneShotCfg(FlowCfg):
self.__dict__,
ignored_wildcards)
# Stuff below only pertains to individual cfg (not master cfg).
if not self.is_master_cfg:
# Stuff below only pertains to individual cfg (not primary cfg).
if not self.is_primary_cfg:
# Print info
log.info("[scratch_dir]: [%s]: [%s]", self.name, self.scratch_path)
@ -113,7 +113,7 @@ class OneShotCfg(FlowCfg):
self._process_exports()
# Create objects from raw dicts - build_modes, sim_modes, run_modes,
# tests and regressions, only if not a master cfg obj
# tests and regressions, only if not a primary cfg obj
self._create_objects()
# Post init checks

View file

@ -160,7 +160,7 @@ class SimCfg(FlowCfg):
self.cov_report_deploy = None
self.results_summary = OrderedDict()
# If is_master_cfg is set, then each cfg will have its own cov_deploy.
# If is_primary_cfg is set, then each cfg will have its own cov_deploy.
# Maintain an array of those in cov_deploys.
self.cov_deploys = []
@ -190,19 +190,19 @@ class SimCfg(FlowCfg):
self.__dict__ = find_and_substitute_wildcards(self.__dict__,
self.__dict__,
ignored_wildcards,
self.is_master_cfg)
self.is_primary_cfg)
# Set the title for simulation results.
self.results_title = self.name.upper() + " Simulation Results"
# Stuff below only pertains to individual cfg (not master cfg)
# Stuff below only pertains to individual cfg (not primary cfg)
# or individual selected cfgs (if select_cfgs is configured via command line)
# TODO: find a better way to support select_cfgs
if not self.is_master_cfg and (not self.select_cfgs or
self.name in self.select_cfgs):
if not self.is_primary_cfg and (not self.select_cfgs or
self.name in self.select_cfgs):
# If self.tool is None at this point, there was no --tool argument on
# the command line, and there is no default tool set in the config
# file. That's ok if this is a master config (where the
# file. That's ok if this is a primary config (where the
# sub-configurations can choose tools themselves), but not otherwise.
if self.tool is None:
log.error('Config file does not specify a default tool, '
@ -227,7 +227,7 @@ class SimCfg(FlowCfg):
self._process_exports()
# Create objects from raw dicts - build_modes, sim_modes, run_modes,
# tests and regressions, only if not a master cfg obj
# tests and regressions, only if not a primary cfg obj
self._create_objects()
# Post init checks
@ -576,6 +576,8 @@ class SimCfg(FlowCfg):
# Generate results table for runs.
results_str = "## " + self.results_title + "\n"
results_str += "### " + self.timestamp_long + "\n"
if self.revision_string:
results_str += "### " + self.revision_string + "\n"
# Add path to testplan.
if hasattr(self, "testplan_doc_path"):
@ -648,6 +650,8 @@ class SimCfg(FlowCfg):
table.append(row)
self.results_summary_md = "## " + self.results_title + " (Summary)\n"
self.results_summary_md += "### " + self.timestamp_long + "\n"
if self.revision_string:
self.results_summary_md += "### " + self.revision_string + "\n"
self.results_summary_md += tabulate(table,
headers="firstrow",
tablefmt="pipe",

View file

@ -35,7 +35,10 @@ class SynCfg(OneShotCfg):
log.info("Create summary of synthesis results")
results_str = "## " + self.results_title + " (Summary)\n\n"
results_str += "### " + self.timestamp_long + "\n\n"
results_str += "### " + self.timestamp_long + "\n"
if self.revision_string:
results_str += "### " + self.revision_string + "\n"
results_str += "\n"
self.results_summary_md = results_str + "\nNot supported yet.\n"
@ -116,7 +119,7 @@ class SynCfg(OneShotCfg):
# }
# }
#
# note that if this is a master config, the results will
# note that if this is a primary config, the results will
# be generated using the _gen_results_summary function
# '''
@ -142,6 +145,8 @@ class SynCfg(OneShotCfg):
# Generate results table for runs.
results_str = "## " + self.results_title + "\n\n"
results_str += "### " + self.timestamp_long + "\n"
if self.revision_string:
results_str += "### " + self.revision_string + "\n"
results_str += "### Synthesis Tool: " + self.tool.upper() + "\n\n"
# TODO: extend this to support multiple build modes
@ -155,7 +160,7 @@ class SynCfg(OneShotCfg):
log.info("looking for result data file at %s", result_data)
try:
with open(result_data, "r") as results_file:
with result_data.open() as results_file:
self.result = hjson.load(results_file, use_decimal=True)
except IOError as err:
log.warning("%s", err)
@ -354,22 +359,35 @@ class SynCfg(OneShotCfg):
("Compile Warnings", "compile_warnings"),
("Compile Errors", "compile_errors")]
has_msg = False
# Synthesis fails if any warning or error message has occurred
self.errors_seen = False
fail_msgs = ""
for _, key in hdr_key_pairs:
if key in self.result['messages']:
has_msg = True
break
if self.result['messages'].get(key):
self.errors_seen = True
break
if has_msg and not self.args.publish:
results_str += "\n### Errors and Warnings for Build Mode `'" + mode.name + "'`\n"
if self.errors_seen:
fail_msgs += "\n### Errors and Warnings for Build Mode `'" + mode.name + "'`\n"
for hdr, key in hdr_key_pairs:
msgs = self.result['messages'].get(key)
results_str += print_msg_list("#### " + hdr, msgs, self.max_msg_count)
fail_msgs += print_msg_list("#### " + hdr, msgs, self.max_msg_count)
# the email and published reports will default to self.results_md if they are
# empty. in case they need to be sanitized, override them and do not append
# detailed messages.
if self.sanitize_email_results:
self.email_results_md = results_str
if self.sanitize_publish_results:
self.publish_results_md = results_str
# locally generated result always contains all details
self.results_md = results_str + fail_msgs
# TODO: add support for pie / bar charts for area splits and
# QoR history
self.results_md = results_str
# Write results to the scratch area
self.results_file = self.scratch_path + "/results_" + self.timestamp + ".md"
log.info("Detailed results are available at %s", self.results_file)

View file

@ -244,10 +244,10 @@ def parse_args():
whatg.add_argument("--select-cfgs",
nargs="*",
metavar="CFG",
help=('The .hjson file is a master config. Only run '
help=('The .hjson file is a primary config. Only run '
'the given configs from it. If this argument is '
'not used, dvsim will process all configs listed '
'in a master config.'))
'in a primary config.'))
disg = parser.add_argument_group('Dispatch options')

View file

@ -1,7 +1,6 @@
/* Copyright lowRISC contributors.
* Licensed under the Apache License, Version 2.0, see LICENSE for details.
* SPDX-License-Identifier: Apache-2.0
*/
/* Copyright lowRISC contributors. */
/* Licensed under the Apache License, Version 2.0, see LICENSE for details. */
/* SPDX-License-Identifier: Apache-2.0 */
/* CSS for reports.opentitan.org.
* This is referenced by all results published to the reports server for some basic styling.

View file

@ -304,10 +304,14 @@ class Testplan():
if fmt == "html":
desc = mistletoe.markdown(desc)
table.append([entry.milestone, entry.name, desc, tests])
return tabulate(table,
headers="firstrow",
tablefmt=fmt,
colalign=colalign)
result = tabulate(table,
headers="firstrow",
tablefmt=fmt,
colalign=colalign)
result = result.replace("&lt;", "<")
result = result.replace("&gt;", ">")
return result
def results_table(self, regr_results, map_full_testplan=True, fmt="pipe"):
'''Print the mapped regression results into a table in the format

View file

@ -29,10 +29,6 @@ compile_result: post_compile
@echo "[make]: compile_result"
${report_cmd} ${report_opts}
clean:
echo "[make]: clean"
rm -rf ${scratch_root}/${dut}/*
.PHONY: build \
run \
pre_compile \

View file

@ -100,7 +100,7 @@ $ util/dvsim/dvsim.py hw/top_earlgrey/lint/top_earlgrey_lint_cfgs.hjson --tool a
where the `top_earlgrey_lint_cfgs.hjson` file contains all the lint targets to be run in that regression (currently all available comportable IPs and the top-level are run).
The `purge` option ensures that the scratch directory is fully erased before starting the build, and `mp 1` sets the number of parallel workers to one (should be set depending on your licensing situation).
The batch regression is regularly run on the master branch at eight-hour intervals, and the results are published on a public dashboard such that everybody can inspect the current lint status of all IPs on the project website.
The batch regression is regularly run on the `master` branch at eight-hour intervals, and the results are published on a public dashboard such that everybody can inspect the current lint status of all IPs on the project website.
The dashboard can be found by following the appropriate link on the [hardware IP overview page](https://docs.opentitan.org/hw).
# CDC Linting

View file

@ -56,6 +56,9 @@ def get_results(resdir):
# support for JasperGold and "formal" targets
("warnings",
r"^(?!WARNING: Unknown item formal in section Target)WARNING: .*"
# TODO(https://github.com/lowRISC/ibex/issues/1033):
# remove once this has been fixed in Edalize or in the corefile.
r"^(?!WARNING: Unknown item symbiyosis in section Target)WARNING: .*"
),
("warnings", r"^Warning: .* "),
("warnings", r"^W .*"),

View file

@ -0,0 +1,5 @@
+module prim_present
begin tgl(portsonly)
-tree prim_present_tb
+module prim_present
end

View file

@ -1,3 +1,6 @@
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
{
name: "prim_present"
import_testplans: []

View file

@ -18,30 +18,20 @@
fusesoc_core: lowrisc:dv:prim_present_sim:0.1
// Testplan hjson file.
testplan: "{proj_root}/hw/ip/prim/dv/prim_present/prim_present_testplan.hjson"
testplan: "{proj_root}/hw/ip/prim/dv/prim_present/data/prim_present_testplan.hjson"
// Import additional common sim cfg files.
import_cfgs: ["{proj_root}/hw/dv/data/common_sim_cfg.hjson"]
// Add additional tops for simulation.
//sim_tops: ["-top prim_present_bind"]
sim_tops: []
// Default iterations for all tests - each test entry can override this.
reseed: 50
// Add excl files to tool_srcs so that it gets copied over to the scratch area.
//tool_srcs: ["{proj_root}/hw/ip/prim/dv/prim_present/prim_present_cov_excl.el"]
tool_srcs: []
// Refer to the excl file with vcs_cov_excl_files var with the rel path from tool_srcs_dir
// so the VCS can find it.
//vcs_cov_excl_files: ["{tool_srcs_dir}/prim_present_cov_excl.el"]
vcs_cov_excl_files: []
// Default UVM test and seq class name.
uvm_test: ""
uvm_test_seq: ""
overrides: [
{
name: vcs_cov_hier
value: "-cm_hier {proj_root}/hw/ip/prim/dv/prim_present/data/cover.cfg"
}
]
// List of test specifications.
tests: [

View file

@ -23,13 +23,13 @@ module prim_fifo_sync_bind_fpv;
.clk_i,
.rst_ni,
.clr_i,
.wvalid,
.wready,
.wdata,
.rvalid,
.rready,
.rdata,
.depth
.wvalid_i,
.wready_o,
.wdata_i,
.rvalid_o,
.rready_i,
.rdata_o,
.depth_o
);
bind i_nopass7 prim_fifo_sync_assert_fpv #(
@ -41,13 +41,13 @@ module prim_fifo_sync_bind_fpv;
.clk_i,
.rst_ni,
.clr_i,
.wvalid,
.wready,
.wdata,
.rvalid,
.rready,
.rdata,
.depth
.wvalid_i,
.wready_o,
.wdata_i,
.rvalid_o,
.rready_i,
.rdata_o,
.depth_o
);
bind i_nopass8 prim_fifo_sync_assert_fpv #(
@ -59,13 +59,13 @@ module prim_fifo_sync_bind_fpv;
.clk_i,
.rst_ni,
.clr_i,
.wvalid,
.wready,
.wdata,
.rvalid,
.rready,
.rdata,
.depth
.wvalid_i,
.wready_o,
.wdata_i,
.rvalid_o,
.rready_i,
.rdata_o,
.depth_o
);
bind i_nopass15 prim_fifo_sync_assert_fpv #(
@ -77,13 +77,13 @@ module prim_fifo_sync_bind_fpv;
.clk_i,
.rst_ni,
.clr_i,
.wvalid,
.wready,
.wdata,
.rvalid,
.rready,
.rdata,
.depth
.wvalid_i,
.wready_o,
.wdata_i,
.rvalid_o,
.rready_i,
.rdata_o,
.depth_o
);
bind i_nopass16 prim_fifo_sync_assert_fpv #(
@ -95,13 +95,13 @@ module prim_fifo_sync_bind_fpv;
.clk_i,
.rst_ni,
.clr_i,
.wvalid,
.wready,
.wdata,
.rvalid,
.rready,
.rdata,
.depth
.wvalid_i,
.wready_o,
.wdata_i,
.rvalid_o,
.rready_i,
.rdata_o,
.depth_o
);
////////////////
@ -117,13 +117,13 @@ module prim_fifo_sync_bind_fpv;
.clk_i,
.rst_ni,
.clr_i,
.wvalid,
.wready,
.wdata,
.rvalid,
.rready,
.rdata,
.depth
.wvalid_i,
.wready_o,
.wdata_i,
.rvalid_o,
.rready_i,
.rdata_o,
.depth_o
);
bind i_pass1 prim_fifo_sync_assert_fpv #(
@ -135,13 +135,13 @@ module prim_fifo_sync_bind_fpv;
.clk_i,
.rst_ni,
.clr_i,
.wvalid,
.wready,
.wdata,
.rvalid,
.rready,
.rdata,
.depth
.wvalid_i,
.wready_o,
.wdata_i,
.rvalid_o,
.rready_i,
.rdata_o,
.depth_o
);
bind i_pass7 prim_fifo_sync_assert_fpv #(
@ -153,13 +153,13 @@ module prim_fifo_sync_bind_fpv;
.clk_i,
.rst_ni,
.clr_i,
.wvalid,
.wready,
.wdata,
.rvalid,
.rready,
.rdata,
.depth
.wvalid_i,
.wready_o,
.wdata_i,
.rvalid_o,
.rready_i,
.rdata_o,
.depth_o
);
bind i_pass8 prim_fifo_sync_assert_fpv #(
@ -171,13 +171,13 @@ module prim_fifo_sync_bind_fpv;
.clk_i,
.rst_ni,
.clr_i,
.wvalid,
.wready,
.wdata,
.rvalid,
.rready,
.rdata,
.depth
.wvalid_i,
.wready_o,
.wdata_i,
.rvalid_o,
.rready_i,
.rdata_o,
.depth_o
);
bind i_pass15 prim_fifo_sync_assert_fpv #(
@ -189,13 +189,13 @@ module prim_fifo_sync_bind_fpv;
.clk_i,
.rst_ni,
.clr_i,
.wvalid,
.wready,
.wdata,
.rvalid,
.rready,
.rdata,
.depth
.wvalid_i,
.wready_o,
.wdata_i,
.rvalid_o,
.rready_i,
.rdata_o,
.depth_o
);
bind i_pass16 prim_fifo_sync_assert_fpv #(
@ -207,13 +207,13 @@ module prim_fifo_sync_bind_fpv;
.clk_i,
.rst_ni,
.clr_i,
.wvalid,
.wready,
.wdata,
.rvalid,
.rready,
.rdata,
.depth
.wvalid_i,
.wready_o,
.wdata_i,
.rvalid_o,
.rready_i,
.rdata_o,
.depth_o
);
endmodule : prim_fifo_sync_bind_fpv

View file

@ -25,13 +25,13 @@ module prim_fifo_sync_fpv #(
input clk_i,
input rst_ni,
input clr_i,
input wvalid [NumDuts],
output wready [NumDuts],
input [Width-1:0] wdata [NumDuts],
output rvalid [NumDuts],
input rready [NumDuts],
output [Width-1:0] rdata [NumDuts],
output [DepthW-1:0] depth [NumDuts]
input wvalid_i[NumDuts],
output wready_o[NumDuts],
input [Width-1:0] wdata_i [NumDuts],
output rvalid_o[NumDuts],
input rready_i[NumDuts],
output [Width-1:0] rdata_o [NumDuts],
output [DepthW-1:0] depth_o [NumDuts]
);
// need to instantiate by hand since bind statements inside
@ -49,13 +49,13 @@ module prim_fifo_sync_fpv #(
.clk_i,
.rst_ni,
.clr_i,
.wvalid(wvalid[0]),
.wready(wready[0]),
.wdata(wdata[0]),
.rvalid(rvalid[0]),
.rready(rready[0]),
.rdata(rdata[0]),
.depth(depth[0][0])
.wvalid_i(wvalid_i[0]),
.wready_o(wready_o[0]),
.wdata_i(wdata_i[0]),
.rvalid_o(rvalid_o[0]),
.rready_i(rready_i[0]),
.rdata_o(rdata_o[0]),
.depth_o(depth_o[0][0])
);
prim_fifo_sync #(
@ -66,13 +66,13 @@ module prim_fifo_sync_fpv #(
.clk_i,
.rst_ni,
.clr_i,
.wvalid(wvalid[1]),
.wready(wready[1]),
.wdata(wdata[1]),
.rvalid(rvalid[1]),
.rready(rready[1]),
.rdata(rdata[1]),
.depth(depth[1][2:0])
.wvalid_i(wvalid_i[1]),
.wready_o(wready_o[1]),
.wdata_i(wdata_i[1]),
.rvalid_o(rvalid_o[1]),
.rready_i(rready_i[1]),
.rdata_o(rdata_o[1]),
.depth_o(depth_o[1][2:0])
);
prim_fifo_sync #(
@ -83,13 +83,13 @@ module prim_fifo_sync_fpv #(
.clk_i,
.rst_ni,
.clr_i,
.wvalid(wvalid[2]),
.wready(wready[2]),
.wdata(wdata[2]),
.rvalid(rvalid[2]),
.rready(rready[2]),
.rdata(rdata[2]),
.depth(depth[2][3:0])
.wvalid_i(wvalid_i[2]),
.wready_o(wready_o[2]),
.wdata_i(wdata_i[2]),
.rvalid_o(rvalid_o[2]),
.rready_i(rready_i[2]),
.rdata_o(rdata_o[2]),
.depth_o(depth_o[2][3:0])
);
prim_fifo_sync #(
@ -100,13 +100,13 @@ module prim_fifo_sync_fpv #(
.clk_i,
.rst_ni,
.clr_i,
.wvalid(wvalid[3]),
.wready(wready[3]),
.wdata(wdata[3]),
.rvalid(rvalid[3]),
.rready(rready[3]),
.rdata(rdata[3]),
.depth(depth[3][3:0])
.wvalid_i(wvalid_i[3]),
.wready_o(wready_o[3]),
.wdata_i(wdata_i[3]),
.rvalid_o(rvalid_o[3]),
.rready_i(rready_i[3]),
.rdata_o(rdata_o[3]),
.depth_o(depth_o[3][3:0])
);
prim_fifo_sync #(
@ -117,20 +117,20 @@ module prim_fifo_sync_fpv #(
.clk_i,
.rst_ni,
.clr_i,
.wvalid(wvalid[4]),
.wready(wready[4]),
.wdata(wdata[4]),
.rvalid(rvalid[4]),
.rready(rready[4]),
.rdata(rdata[4]),
.depth(depth[4][4:0])
.wvalid_i(wvalid_i[4]),
.wready_o(wready_o[4]),
.wdata_i(wdata_i[4]),
.rvalid_o(rvalid_o[4]),
.rready_i(rready_i[4]),
.rdata_o(rdata_o[4]),
.depth_o(depth_o[4][4:0])
);
////////////////
// pass FIFOs //
////////////////
// depth-zero is per definition a pass-through FIFO
// depth_o-zero is per definition a pass-through FIFO
prim_fifo_sync #(
.Width(Width),
.Pass(1'b1),
@ -139,13 +139,13 @@ module prim_fifo_sync_fpv #(
.clk_i,
.rst_ni,
.clr_i,
.wvalid(wvalid[5]),
.wready(wready[5]),
.wdata(wdata[5]),
.rvalid(rvalid[5]),
.rready(rready[5]),
.rdata(rdata[5]),
.depth(depth[5][0])
.wvalid_i(wvalid_i[5]),
.wready_o(wready_o[5]),
.wdata_i(wdata_i[5]),
.rvalid_o(rvalid_o[5]),
.rready_i(rready_i[5]),
.rdata_o(rdata_o[5]),
.depth_o(depth_o[5][0])
);
prim_fifo_sync #(
@ -156,13 +156,13 @@ module prim_fifo_sync_fpv #(
.clk_i,
.rst_ni,
.clr_i,
.wvalid(wvalid[6]),
.wready(wready[6]),
.wdata(wdata[6]),
.rvalid(rvalid[6]),
.rready(rready[6]),
.rdata(rdata[6]),
.depth(depth[6][0])
.wvalid_i(wvalid_i[6]),
.wready_o(wready_o[6]),
.wdata_i(wdata_i[6]),
.rvalid_o(rvalid_o[6]),
.rready_i(rready_i[6]),
.rdata_o(rdata_o[6]),
.depth_o(depth_o[6][0])
);
prim_fifo_sync #(
@ -173,13 +173,13 @@ module prim_fifo_sync_fpv #(
.clk_i,
.rst_ni,
.clr_i,
.wvalid(wvalid[7]),
.wready(wready[7]),
.wdata(wdata[7]),
.rvalid(rvalid[7]),
.rready(rready[7]),
.rdata(rdata[7]),
.depth(depth[7][2:0])
.wvalid_i(wvalid_i[7]),
.wready_o(wready_o[7]),
.wdata_i(wdata_i[7]),
.rvalid_o(rvalid_o[7]),
.rready_i(rready_i[7]),
.rdata_o(rdata_o[7]),
.depth_o(depth_o[7][2:0])
);
prim_fifo_sync #(
@ -190,13 +190,13 @@ module prim_fifo_sync_fpv #(
.clk_i,
.rst_ni,
.clr_i,
.wvalid(wvalid[8]),
.wready(wready[8]),
.wdata(wdata[8]),
.rvalid(rvalid[8]),
.rready(rready[8]),
.rdata(rdata[8]),
.depth(depth[8][3:0])
.wvalid_i(wvalid_i[8]),
.wready_o(wready_o[8]),
.wdata_i(wdata_i[8]),
.rvalid_o(rvalid_o[8]),
.rready_i(rready_i[8]),
.rdata_o(rdata_o[8]),
.depth_o(depth_o[8][3:0])
);
prim_fifo_sync #(
@ -207,13 +207,13 @@ module prim_fifo_sync_fpv #(
.clk_i,
.rst_ni,
.clr_i,
.wvalid(wvalid[9]),
.wready(wready[9]),
.wdata(wdata[9]),
.rvalid(rvalid[9]),
.rready(rready[9]),
.rdata(rdata[9]),
.depth(depth[9][3:0])
.wvalid_i(wvalid_i[9]),
.wready_o(wready_o[9]),
.wdata_i(wdata_i[9]),
.rvalid_o(rvalid_o[9]),
.rready_i(rready_i[9]),
.rdata_o(rdata_o[9]),
.depth_o(depth_o[9][3:0])
);
prim_fifo_sync #(
@ -224,13 +224,13 @@ module prim_fifo_sync_fpv #(
.clk_i,
.rst_ni,
.clr_i,
.wvalid(wvalid[10]),
.wready(wready[10]),
.wdata(wdata[10]),
.rvalid(rvalid[10]),
.rready(rready[10]),
.rdata(rdata[10]),
.depth(depth[10][4:0])
.wvalid_i(wvalid_i[10]),
.wready_o(wready_o[10]),
.wdata_i(wdata_i[10]),
.rvalid_o(rvalid_o[10]),
.rready_i(rready_i[10]),
.rdata_o(rdata_o[10]),
.depth_o(depth_o[10][4:0])
);
endmodule : prim_fifo_sync_fpv

View file

@ -19,13 +19,13 @@ module prim_fifo_sync_assert_fpv #(
input clk_i,
input rst_ni,
input clr_i,
input wvalid,
input wready,
input [Width-1:0] wdata,
input rvalid,
input rready,
input [Width-1:0] rdata,
input [DepthW-1:0] depth
input wvalid_i,
input wready_o,
input [Width-1:0] wdata_i,
input rvalid_o,
input rready_i,
input [Width-1:0] rdata_o,
input [DepthW-1:0] depth_o
);
/////////////////
@ -34,7 +34,7 @@ module prim_fifo_sync_assert_fpv #(
// no need to consider all possible input words
// 2-3 different values suffice
`ASSUME(WdataValues_M, wdata inside {Width'(1'b0), Width'(1'b1), {Width{1'b1}}}, clk_i, !rst_ni)
`ASSUME(WdataValues_M, wdata_i inside {Width'(1'b0), Width'(1'b1), {Width{1'b1}}}, clk_i, !rst_ni)
////////////////////////////////
// Data and Depth Value Check //
@ -59,12 +59,12 @@ module prim_fifo_sync_assert_fpv #(
if (clr_i) begin
ref_depth <= 0;
end else begin
if (wvalid && wready && rvalid && rready) begin
fifo <= wdata;
end else if (wvalid && wready) begin
fifo <= wdata;
if (wvalid_i && wready_o && rvalid_o && rready_i) begin
fifo <= wdata_i;
end else if (wvalid_i && wready_o) begin
fifo <= wdata_i;
ref_depth <= ref_depth + 1;
end else if (rvalid && rready) begin
end else if (rvalid_o && rready_i) begin
ref_depth <= ref_depth - 1;
end
end
@ -72,7 +72,7 @@ module prim_fifo_sync_assert_fpv #(
end
if (Pass) begin : gen_pass
assign ref_rdata = (ref_depth == 0) ? wdata : fifo;
assign ref_rdata = (ref_depth == 0) ? wdata_i : fifo;
end else begin : no_pass
assign ref_rdata = fifo;
end
@ -101,15 +101,15 @@ module prim_fifo_sync_assert_fpv #(
rptr <= 0;
ref_depth <= 0;
end else begin
if (wvalid && wready && rvalid && rready) begin
fifo[wptr] <= wdata;
if (wvalid_i && wready_o && rvalid_o && rready_i) begin
fifo[wptr] <= wdata_i;
wptr <= modinc(wptr, Depth);
rptr <= modinc(rptr, Depth);
end else if (wvalid && wready) begin
fifo[wptr] <= wdata;
end else if (wvalid_i && wready_o) begin
fifo[wptr] <= wdata_i;
wptr <= modinc(wptr, Depth);
ref_depth <= ref_depth + 1;
end else if (rvalid && rready) begin
end else if (rvalid_o && rready_i) begin
rptr <= modinc(rptr, Depth);
ref_depth <= ref_depth - 1;
end
@ -118,7 +118,7 @@ module prim_fifo_sync_assert_fpv #(
end
if (Pass) begin : gen_pass
assign ref_rdata = (ref_depth == 0) ? wdata : fifo[rptr];
assign ref_rdata = (ref_depth == 0) ? wdata_i : fifo[rptr];
end else begin : no_pass
assign ref_rdata = fifo[rptr];
end
@ -126,9 +126,9 @@ module prim_fifo_sync_assert_fpv #(
end
// check the data
`ASSERT(DataCheck_A, rvalid |-> rdata == ref_rdata)
`ASSERT(DataCheck_A, rvalid_o |-> rdata_o == ref_rdata)
// check the depth
`ASSERT(DepthCheck_A, ref_depth == depth)
`ASSERT(DepthCheck_A, ref_depth == depth_o)
end
@ -137,20 +137,20 @@ module prim_fifo_sync_assert_fpv #(
////////////////////////
// assert depth of FIFO
`ASSERT(Depth_A, depth <= Depth)
`ASSERT(Depth_A, depth_o <= Depth)
// if we clear the FIFO, it must be empty in the next cycle
`ASSERT(CheckClrDepth_A, clr_i |=> depth == 0)
`ASSERT(CheckClrDepth_A, clr_i |=> depth_o == 0)
// check write on full
`ASSERT(WriteFull_A, depth == Depth && wvalid && !rready |=> depth == $past(depth),
`ASSERT(WriteFull_A, depth_o == Depth && wvalid_i && !rready_i |=> depth_o == $past(depth_o),
clk_i, !rst_ni || clr_i)
// read empty
`ASSERT(ReadEmpty_A, depth == 0 && rready && !wvalid |=> depth == 0,
`ASSERT(ReadEmpty_A, depth_o == 0 && rready_i && !wvalid_i |=> depth_o == 0,
clk_i, !rst_ni || clr_i)
// this is unreachable in depth 1 no-pass through mode
if (Depth == 1 && Pass) begin : gen_d1_passthru
// check simultaneous write and read
`ASSERT(WriteAndRead_A, wready && wvalid && rvalid && rready |=> depth == $past(depth),
`ASSERT(WriteAndRead_A, wready_o && wvalid_i && rvalid_o && rready_i |=> depth_o == $past(depth_o),
clk_i, !rst_ni || clr_i)
end
@ -158,35 +158,35 @@ module prim_fifo_sync_assert_fpv #(
// if there is no register, the FIFO is per definition pass-through
`ASSERT_INIT(ZeroDepthNeedsPass_A, Pass == 1)
// depth must remain zero
`ASSERT(DepthAlwaysZero_A, depth == 0)
`ASSERT(DepthAlwaysZero_A, depth_o == 0)
// data is just passed through
`ASSERT(DataPassThru_A, wdata == rdata)
`ASSERT(DataPassThru_A, wdata_i == rdata_o)
// FIFO is ready if downstream logic is ready
`ASSERT(Wready_A, rready == wready)
`ASSERT(Wready_A, rready_i == wready_o)
// valid input is valid output
`ASSERT(Rvalid_A, rvalid == wvalid)
`ASSERT(Rvalid_A, rvalid_o == wvalid_i)
// ensure full coverage
`ASSERT(UnusedClr_A, prim_fifo_sync.gen_passthru_fifo.unused_clr == clr_i)
end else begin : gen_depth_gt0
// check wready
`ASSERT(Wready_A, depth < Depth |-> wready)
`ASSERT(Wready_A, depth_o < Depth |-> wready_o)
// check rvalid
`ASSERT(Rvalid_A, depth > 0 |-> rvalid)
`ASSERT(Rvalid_A, depth_o > 0 |-> rvalid_o)
// check write only
`ASSERT(WriteOnly_A, wvalid && wready && !rready && depth < Depth |=>
depth == $past(depth) + 1, clk_i, !rst_ni || clr_i)
`ASSERT(WriteOnly_A, wvalid_i && wready_o && !rready_i && depth_o < Depth |=>
depth_o == $past(depth_o) + 1, clk_i, !rst_ni || clr_i)
// check read only
`ASSERT(ReadOnly_A, !wvalid && rready && rvalid && depth > 0 |=>
depth == $past(depth) - 1, clk_i, !rst_ni || clr_i)
`ASSERT(ReadOnly_A, !wvalid_i && rready_i && rvalid_o && depth_o > 0 |=>
depth_o == $past(depth_o) - 1, clk_i, !rst_ni || clr_i)
end
if (Pass) begin : gen_pass_fwd
// if we clear the FIFO, it must be empty in the next cycle
// but we may also get a pass through
`ASSERT(CheckClrValid_A, clr_i |=> wvalid == rvalid)
`ASSERT(CheckClrValid_A, clr_i |=> wvalid_i == rvalid_o)
end else begin : gen_nopass_fwd
// if we clear the FIFO, it must be empty in the next cycle
`ASSERT(CheckClrValid_A, clr_i |=> !rvalid)
`ASSERT(CheckClrValid_A, clr_i |=> !rvalid_o)
end
/////////////////////////
@ -195,19 +195,19 @@ module prim_fifo_sync_assert_fpv #(
if (Pass) begin : gen_pass_bkwd
// there is still space in the FIFO or downstream logic is ready
`ASSERT(WreadySpacekBkwd_A, wready |-> depth < Depth || rready)
`ASSERT(WreadySpacekBkwd_A, wready_o |-> depth_o < Depth || rready_i)
// elements ready to be read or upstream data is valid
`ASSERT(RvalidElemskBkwd_A, rvalid |-> depth > 0 || wvalid)
`ASSERT(RvalidElemskBkwd_A, rvalid_o |-> depth_o > 0 || wvalid_i)
end else begin : gen_nopass_bkwd
// there is still space in the FIFO
`ASSERT(WreadySpacekBkwd_A, wready |-> depth < Depth)
`ASSERT(WreadySpacekBkwd_A, wready_o |-> depth_o < Depth)
// elements ready to be read
`ASSERT(RvalidElemskBkwd_A, rvalid |-> depth > 0)
`ASSERT(RvalidElemskBkwd_A, rvalid_o |-> depth_o > 0)
end
// no more space in the FIFO
`ASSERT(WreadyNoSpaceBkwd_A, !wready |-> depth == Depth)
`ASSERT(WreadyNoSpaceBkwd_A, !wready_o |-> depth_o == Depth)
// elements ready to be read
`ASSERT(RvalidNoElemskBkwd_A, !rvalid |-> depth == 0)
`ASSERT(RvalidNoElemskBkwd_A, !rvalid_o |-> depth_o == 0)
endmodule : prim_fifo_sync_assert_fpv

View file

@ -15,8 +15,9 @@ filesets:
- lowrisc:prim:pad_wrapper
- lowrisc:prim:prim_pkg
- lowrisc:prim:clock_mux2
- lowrisc:prim:flop
- lowrisc:prim:flop_2sync
files:
- rtl/prim_clock_inverter.sv
- rtl/prim_clock_gating_sync.sv
- rtl/prim_alert_pkg.sv
- rtl/prim_alert_receiver.sv
@ -29,7 +30,6 @@ filesets:
- rtl/prim_sram_arbiter.sv
- rtl/prim_fifo_async.sv
- rtl/prim_fifo_sync.sv
- rtl/prim_flop_2sync.sv
- rtl/prim_sync_reqack.sv
- rtl/prim_keccak.sv
- rtl/prim_packer.sv
@ -41,8 +41,10 @@ filesets:
- rtl/prim_pulse_sync.sv
- rtl/prim_filter.sv
- rtl/prim_filter_ctr.sv
- rtl/prim_subreg_arb.sv
- rtl/prim_subreg.sv
- rtl/prim_subreg_ext.sv
- rtl/prim_subreg_shadow.sv
- rtl/prim_intr_hw.sv
file_type: systemVerilogSource

View 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:prim:clock_buf"
description: "Generic clock buffer"
filesets:
primgen_dep:
depend:
- lowrisc:prim:prim_pkg
- lowrisc:prim:primgen
generate:
impl:
generator: primgen
parameters:
prim_name: clock_buf
targets:
default:
filesets:
- primgen_dep
generate:
- impl

View 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:prim:clock_inv"
description: "Clock inverter with scanmode bypass mux"
filesets:
primgen_dep:
depend:
- lowrisc:prim:prim_pkg
- lowrisc:prim:primgen
generate:
impl:
generator: primgen
parameters:
prim_name: clock_inv
targets:
default:
filesets:
- primgen_dep
generate:
- impl

25
vendor/lowrisc_ip/prim/prim_flop.core vendored Normal file
View 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:prim:flop"
description: "Generic flop"
filesets:
primgen_dep:
depend:
- lowrisc:prim:prim_pkg
- lowrisc:prim:primgen
generate:
impl:
generator: primgen
parameters:
prim_name: flop
targets:
default:
filesets:
- primgen_dep
generate:
- impl

View 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:prim:flop_2sync"
description: "Primitive synchronizer"
filesets:
primgen_dep:
depend:
- lowrisc:prim:prim_pkg
- lowrisc:prim:primgen
generate:
impl:
generator: primgen
parameters:
prim_name: flop_2sync
targets:
default:
filesets:
- primgen_dep
generate:
- impl

View file

@ -30,15 +30,15 @@ package prim_cipher_pkg;
4'h9, 4'h8, 4'hD, 4'hF,
4'h2, 4'h3, 4'h7, 4'hB};
// nibble permutations
parameter logic [15:0][3:0] PRINCE_SHIFT_ROWS64 = '{4'hB, 4'h6, 4'h1, 4'hC,
parameter logic [15:0][3:0] PRINCE_SHIFT_ROWS64 = '{4'hF, 4'hA, 4'h5, 4'h0,
4'hB, 4'h6, 4'h1, 4'hC,
4'h7, 4'h2, 4'hD, 4'h8,
4'h3, 4'hE, 4'h9, 4'h4,
4'hF, 4'hA, 4'h5, 4'h0};
4'h3, 4'hE, 4'h9, 4'h4};
parameter logic [15:0][3:0] PRINCE_SHIFT_ROWS64_INV = '{4'h3, 4'h6, 4'h9, 4'hC,
4'hF, 4'h2, 4'h5, 4'h8,
parameter logic [15:0][3:0] PRINCE_SHIFT_ROWS64_INV = '{4'hF, 4'h2, 4'h5, 4'h8,
4'hB, 4'hE, 4'h1, 4'h4,
4'h7, 4'hA, 4'hD, 4'h0};
4'h7, 4'hA, 4'hD, 4'h0,
4'h3, 4'h6, 4'h9, 4'hC};
// these are the round constants
parameter logic [11:0][63:0] PRINCE_ROUND_CONST = {64'hC0AC29B7C97C50DD,
@ -58,10 +58,10 @@ package prim_cipher_pkg;
parameter logic [63:0] PRINCE_ALPHA_CONST = 64'hC0AC29B7C97C50DD;
// masking constants for shift rows function below
parameter logic [15:0] PRINCE_SHIFT_ROWS_CONST0 = 16'hEDB7;
parameter logic [15:0] PRINCE_SHIFT_ROWS_CONST1 = 16'h7EDB;
parameter logic [15:0] PRINCE_SHIFT_ROWS_CONST2 = 16'hB7ED;
parameter logic [15:0] PRINCE_SHIFT_ROWS_CONST3 = 16'hDB7E;
parameter logic [15:0] PRINCE_SHIFT_ROWS_CONST0 = 16'h7BDE;
parameter logic [15:0] PRINCE_SHIFT_ROWS_CONST1 = 16'hBDE7;
parameter logic [15:0] PRINCE_SHIFT_ROWS_CONST2 = 16'hDE7B;
parameter logic [15:0] PRINCE_SHIFT_ROWS_CONST3 = 16'hE7BD;
// nibble shifts
function automatic logic [31:0] prince_shiftrows_32bit(logic [31:0] state_in,
@ -94,15 +94,15 @@ package prim_cipher_pkg;
function automatic logic [31:0] prince_mult_prime_32bit(logic [31:0] state_in);
logic [31:0] state_out;
// M0
state_out[0 +: 4] = prince_nibble_red16(state_in[ 0 +: 16] & PRINCE_SHIFT_ROWS_CONST0);
state_out[4 +: 4] = prince_nibble_red16(state_in[ 0 +: 16] & PRINCE_SHIFT_ROWS_CONST1);
state_out[8 +: 4] = prince_nibble_red16(state_in[ 0 +: 16] & PRINCE_SHIFT_ROWS_CONST2);
state_out[12 +: 4] = prince_nibble_red16(state_in[ 0 +: 16] & PRINCE_SHIFT_ROWS_CONST3);
state_out[0 +: 4] = prince_nibble_red16(state_in[ 0 +: 16] & PRINCE_SHIFT_ROWS_CONST3);
state_out[4 +: 4] = prince_nibble_red16(state_in[ 0 +: 16] & PRINCE_SHIFT_ROWS_CONST2);
state_out[8 +: 4] = prince_nibble_red16(state_in[ 0 +: 16] & PRINCE_SHIFT_ROWS_CONST1);
state_out[12 +: 4] = prince_nibble_red16(state_in[ 0 +: 16] & PRINCE_SHIFT_ROWS_CONST0);
// M1
state_out[16 +: 4] = prince_nibble_red16(state_in[16 +: 16] & PRINCE_SHIFT_ROWS_CONST1);
state_out[20 +: 4] = prince_nibble_red16(state_in[16 +: 16] & PRINCE_SHIFT_ROWS_CONST2);
state_out[24 +: 4] = prince_nibble_red16(state_in[16 +: 16] & PRINCE_SHIFT_ROWS_CONST3);
state_out[28 +: 4] = prince_nibble_red16(state_in[16 +: 16] & PRINCE_SHIFT_ROWS_CONST0);
state_out[16 +: 4] = prince_nibble_red16(state_in[16 +: 16] & PRINCE_SHIFT_ROWS_CONST0);
state_out[20 +: 4] = prince_nibble_red16(state_in[16 +: 16] & PRINCE_SHIFT_ROWS_CONST3);
state_out[24 +: 4] = prince_nibble_red16(state_in[16 +: 16] & PRINCE_SHIFT_ROWS_CONST2);
state_out[28 +: 4] = prince_nibble_red16(state_in[16 +: 16] & PRINCE_SHIFT_ROWS_CONST1);
return state_out;
endfunction : prince_mult_prime_32bit
@ -110,25 +110,25 @@ package prim_cipher_pkg;
function automatic logic [63:0] prince_mult_prime_64bit(logic [63:0] state_in);
logic [63:0] state_out;
// M0
state_out[0 +: 4] = prince_nibble_red16(state_in[ 0 +: 16] & PRINCE_SHIFT_ROWS_CONST0);
state_out[4 +: 4] = prince_nibble_red16(state_in[ 0 +: 16] & PRINCE_SHIFT_ROWS_CONST1);
state_out[8 +: 4] = prince_nibble_red16(state_in[ 0 +: 16] & PRINCE_SHIFT_ROWS_CONST2);
state_out[12 +: 4] = prince_nibble_red16(state_in[ 0 +: 16] & PRINCE_SHIFT_ROWS_CONST3);
state_out[0 +: 4] = prince_nibble_red16(state_in[ 0 +: 16] & PRINCE_SHIFT_ROWS_CONST3);
state_out[4 +: 4] = prince_nibble_red16(state_in[ 0 +: 16] & PRINCE_SHIFT_ROWS_CONST2);
state_out[8 +: 4] = prince_nibble_red16(state_in[ 0 +: 16] & PRINCE_SHIFT_ROWS_CONST1);
state_out[12 +: 4] = prince_nibble_red16(state_in[ 0 +: 16] & PRINCE_SHIFT_ROWS_CONST0);
// M1
state_out[16 +: 4] = prince_nibble_red16(state_in[16 +: 16] & PRINCE_SHIFT_ROWS_CONST1);
state_out[20 +: 4] = prince_nibble_red16(state_in[16 +: 16] & PRINCE_SHIFT_ROWS_CONST2);
state_out[24 +: 4] = prince_nibble_red16(state_in[16 +: 16] & PRINCE_SHIFT_ROWS_CONST3);
state_out[28 +: 4] = prince_nibble_red16(state_in[16 +: 16] & PRINCE_SHIFT_ROWS_CONST0);
state_out[16 +: 4] = prince_nibble_red16(state_in[16 +: 16] & PRINCE_SHIFT_ROWS_CONST0);
state_out[20 +: 4] = prince_nibble_red16(state_in[16 +: 16] & PRINCE_SHIFT_ROWS_CONST3);
state_out[24 +: 4] = prince_nibble_red16(state_in[16 +: 16] & PRINCE_SHIFT_ROWS_CONST2);
state_out[28 +: 4] = prince_nibble_red16(state_in[16 +: 16] & PRINCE_SHIFT_ROWS_CONST1);
// M1
state_out[32 +: 4] = prince_nibble_red16(state_in[32 +: 16] & PRINCE_SHIFT_ROWS_CONST1);
state_out[36 +: 4] = prince_nibble_red16(state_in[32 +: 16] & PRINCE_SHIFT_ROWS_CONST2);
state_out[40 +: 4] = prince_nibble_red16(state_in[32 +: 16] & PRINCE_SHIFT_ROWS_CONST3);
state_out[44 +: 4] = prince_nibble_red16(state_in[32 +: 16] & PRINCE_SHIFT_ROWS_CONST0);
state_out[32 +: 4] = prince_nibble_red16(state_in[32 +: 16] & PRINCE_SHIFT_ROWS_CONST0);
state_out[36 +: 4] = prince_nibble_red16(state_in[32 +: 16] & PRINCE_SHIFT_ROWS_CONST3);
state_out[40 +: 4] = prince_nibble_red16(state_in[32 +: 16] & PRINCE_SHIFT_ROWS_CONST2);
state_out[44 +: 4] = prince_nibble_red16(state_in[32 +: 16] & PRINCE_SHIFT_ROWS_CONST1);
// M0
state_out[48 +: 4] = prince_nibble_red16(state_in[48 +: 16] & PRINCE_SHIFT_ROWS_CONST0);
state_out[52 +: 4] = prince_nibble_red16(state_in[48 +: 16] & PRINCE_SHIFT_ROWS_CONST1);
state_out[56 +: 4] = prince_nibble_red16(state_in[48 +: 16] & PRINCE_SHIFT_ROWS_CONST2);
state_out[60 +: 4] = prince_nibble_red16(state_in[48 +: 16] & PRINCE_SHIFT_ROWS_CONST3);
state_out[48 +: 4] = prince_nibble_red16(state_in[48 +: 16] & PRINCE_SHIFT_ROWS_CONST3);
state_out[52 +: 4] = prince_nibble_red16(state_in[48 +: 16] & PRINCE_SHIFT_ROWS_CONST2);
state_out[56 +: 4] = prince_nibble_red16(state_in[48 +: 16] & PRINCE_SHIFT_ROWS_CONST1);
state_out[60 +: 4] = prince_nibble_red16(state_in[48 +: 16] & PRINCE_SHIFT_ROWS_CONST0);
return state_out;
endfunction : prince_mult_prime_64bit

View file

@ -19,8 +19,8 @@ module prim_clock_gating_sync (
) i_sync (
.clk_i,
.rst_ni,
.d(async_en_i),
.q(en_o)
.d_i(async_en_i),
.q_o(en_o)
);
prim_clock_gating i_cg (

View file

@ -57,8 +57,8 @@ module prim_diff_decode #(
) i_sync_p (
.clk_i,
.rst_ni,
.d(diff_pi),
.q(diff_pd)
.d_i(diff_pi),
.q_o(diff_pd)
);
prim_flop_2sync #(
@ -67,8 +67,8 @@ module prim_diff_decode #(
) i_sync_n (
.clk_i,
.rst_ni,
.d(diff_ni),
.q(diff_nd)
.d_i(diff_ni),
.q_o(diff_nd)
);
// detect level transitions

View file

@ -26,8 +26,7 @@ module prim_esc_sender
(
input clk_i,
input rst_ni,
// this triggers a ping test. keep asserted
// until either ping_ok_o or ping_fail_o is asserted.
// this triggers a ping test. keep asserted until ping_ok_o is pulsed high.
input ping_en_i,
output logic ping_ok_o,
// asserted if signal integrity issue detected
@ -174,12 +173,6 @@ module prim_esc_sender
default : state_d = Idle;
endcase
// escalation takes precedence,
// immediately return ok in that case
if ((esc_en_i || esc_en_q || esc_en_q1) && ping_en_i) begin
ping_ok_o = 1'b1;
end
// a sigint error will reset the state machine
// and have it pause for two cycles to let the
// receiver recover
@ -187,6 +180,12 @@ module prim_esc_sender
ping_ok_o = 1'b0;
state_d = Idle;
end
// escalation takes precedence,
// immediately return ok in that case
if ((esc_en_i || esc_en_q || esc_en_q1) && ping_en_i) begin
ping_ok_o = 1'b1;
end
end
///////////////
@ -245,7 +244,7 @@ module prim_esc_sender
// check that escalation signal is at least 2 cycles high
`ASSERT(EscCheck_A, esc_en_i |-> esc_tx_o.esc_p [*2] )
// escalation / ping collision
`ASSERT(EscPingCheck_A, esc_en_i && ping_en_i |-> ping_ok_o, clk_i, !rst_ni || integ_fail_o)
`ASSERT(EscPingCheck_A, esc_en_i && ping_en_i |-> ping_ok_o)
// check that ping request results in only a single cycle pulse
`ASSERT(PingCheck_A, ##1 $rose(ping_en_i) |-> esc_tx_o.esc_p ##1 !esc_tx_o.esc_p , clk_i,
!rst_ni || esc_en_i || integ_fail_o)

View file

@ -14,18 +14,18 @@ module prim_fifo_async #(
// write port
input clk_wr_i,
input rst_wr_ni,
input wvalid,
output wready,
input [Width-1:0] wdata,
output [DepthW-1:0] wdepth,
input wvalid_i,
output wready_o,
input [Width-1:0] wdata_i,
output [DepthW-1:0] wdepth_o,
// read port
input clk_rd_i,
input rst_rd_ni,
output rvalid,
input rready,
output [Width-1:0] rdata,
output [DepthW-1:0] rdepth
output rvalid_o,
input rready_i,
output [Width-1:0] rdata_o,
output [DepthW-1:0] rdepth_o
);
`ASSERT_INIT(paramCheckDepth, Depth >= 3)
@ -42,13 +42,13 @@ module prim_fifo_async #(
logic full_wclk, full_rclk;
assign wready = !full_wclk;
assign rvalid = !empty;
assign wready_o = !full_wclk;
assign rvalid_o = !empty;
// create the write and read pointers
assign fifo_incr_wptr = wvalid & wready;
assign fifo_incr_rptr = rvalid & rready;
assign fifo_incr_wptr = wvalid_i & wready_o;
assign fifo_incr_rptr = rvalid_o & rready_i;
///////////////////
// write pointer //
@ -80,8 +80,8 @@ module prim_fifo_async #(
prim_flop_2sync #(.Width(PTR_WIDTH)) sync_wptr (
.clk_i (clk_rd_i),
.rst_ni (rst_rd_ni),
.d (fifo_wptr_gray),
.q (fifo_wptr_gray_sync));
.d_i (fifo_wptr_gray),
.q_o (fifo_wptr_gray_sync));
assign fifo_wptr_sync_combi = gray2dec(fifo_wptr_gray_sync);
@ -115,8 +115,8 @@ module prim_fifo_async #(
prim_flop_2sync #(.Width(PTR_WIDTH)) sync_rptr (
.clk_i (clk_wr_i),
.rst_ni (rst_wr_ni),
.d (fifo_rptr_gray),
.q (fifo_rptr_gray_sync));
.d_i (fifo_rptr_gray),
.q_o (fifo_rptr_gray_sync));
always_ff @(posedge clk_wr_i or negedge rst_wr_ni)
if (!rst_wr_ni) begin
@ -141,9 +141,9 @@ module prim_fifo_async #(
assign rptr_sync_msb = fifo_rptr_sync[PTR_WIDTH-1];
assign wptr_value = fifo_wptr[0+:PTRV_W];
assign rptr_sync_value = fifo_rptr_sync[0+:PTRV_W];
assign wdepth = (full_wclk) ? DepthW'(Depth) :
(wptr_msb == rptr_sync_msb) ? DepthW'(wptr_value) - DepthW'(rptr_sync_value) :
(DepthW'(Depth) - DepthW'(rptr_sync_value) + DepthW'(wptr_value)) ;
assign wdepth_o = (full_wclk) ? DepthW'(Depth) :
(wptr_msb == rptr_sync_msb) ? DepthW'(wptr_value) - DepthW'(rptr_sync_value) :
(DepthW'(Depth) - DepthW'(rptr_sync_value) + DepthW'(wptr_value)) ;
// Same again in the read clock side
assign empty = (fifo_wptr_sync_combi == fifo_rptr);
@ -155,9 +155,9 @@ module prim_fifo_async #(
assign rptr_msb = fifo_rptr[PTR_WIDTH-1];
assign wptr_sync_value = fifo_wptr_sync_combi[0+:PTRV_W];
assign rptr_value = fifo_rptr[0+:PTRV_W];
assign rdepth = (full_rclk) ? DepthW'(Depth) :
(wptr_sync_msb == rptr_msb) ? DepthW'(wptr_sync_value) - DepthW'(rptr_value) :
(DepthW'(Depth) - DepthW'(rptr_value) + DepthW'(wptr_sync_value)) ;
assign rdepth_o = (full_rclk) ? DepthW'(Depth) :
(wptr_sync_msb == rptr_msb) ? DepthW'(wptr_sync_value) - DepthW'(rptr_value) :
(DepthW'(Depth) - DepthW'(rptr_value) + DepthW'(wptr_sync_value)) ;
/////////////
// storage //
@ -167,10 +167,10 @@ module prim_fifo_async #(
always_ff @(posedge clk_wr_i)
if (fifo_incr_wptr) begin
storage[fifo_wptr[PTR_WIDTH-2:0]] <= wdata;
storage[fifo_wptr[PTR_WIDTH-2:0]] <= wdata_i;
end
assign rdata = storage[fifo_rptr[PTR_WIDTH-2:0]];
assign rdata_o = storage[fifo_rptr[PTR_WIDTH-2:0]];
// gray code conversion functions. algorithm walks up from 0..N-1
// then flips the upper bit and walks down from N-1 to 0.

View file

@ -19,29 +19,29 @@ module prim_fifo_sync #(
// synchronous clear / flush port
input clr_i,
// write port
input wvalid,
output wready,
input [Width-1:0] wdata,
input wvalid_i,
output wready_o,
input [Width-1:0] wdata_i,
// read port
output rvalid,
input rready,
output [Width-1:0] rdata,
output rvalid_o,
input rready_i,
output [Width-1:0] rdata_o,
// occupancy
output [DepthW-1:0] depth
output [DepthW-1:0] depth_o
);
// FIFO is in complete passthrough mode
if (Depth == 0) begin : gen_passthru_fifo
`ASSERT_INIT(paramCheckPass, Pass == 1)
assign depth = 1'b0; //output is meaningless
assign depth_o = 1'b0; //output is meaningless
// devie facing
assign rvalid = wvalid;
assign rdata = wdata;
assign rvalid_o = wvalid_i;
assign rdata_o = wdata_i;
// host facing
assign wready = rready;
assign wready_o = rready_i;
// this avoids lint warnings
logic unused_clr;
@ -67,15 +67,15 @@ module prim_fifo_sync #(
assign rptr_msb = fifo_rptr[PTR_WIDTH-1];
assign wptr_value = fifo_wptr[0+:PTRV_W];
assign rptr_value = fifo_rptr[0+:PTRV_W];
assign depth = (full) ? DepthW'(Depth) :
(wptr_msb == rptr_msb) ? DepthW'(wptr_value) - DepthW'(rptr_value) :
(DepthW'(Depth) - DepthW'(rptr_value) + DepthW'(wptr_value)) ;
assign depth_o = (full) ? DepthW'(Depth) :
(wptr_msb == rptr_msb) ? DepthW'(wptr_value) - DepthW'(rptr_value) :
(DepthW'(Depth) - DepthW'(rptr_value) + DepthW'(wptr_value)) ;
assign fifo_incr_wptr = wvalid & wready;
assign fifo_incr_rptr = rvalid & rready;
assign fifo_incr_wptr = wvalid_i & wready_o;
assign fifo_incr_rptr = rvalid_o & rready_i;
assign wready = ~full;
assign rvalid = ~empty;
assign wready_o = ~full;
assign rvalid_o = ~empty;
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
@ -118,7 +118,7 @@ module prim_fifo_sync #(
always_ff @(posedge clk_i)
if (fifo_incr_wptr) begin
storage[0] <= wdata;
storage[0] <= wdata_i;
end
// fifo with more than one storage element
end else begin : gen_depth_gt1
@ -126,26 +126,26 @@ module prim_fifo_sync #(
always_ff @(posedge clk_i)
if (fifo_incr_wptr) begin
storage[fifo_wptr[PTR_WIDTH-2:0]] <= wdata;
storage[fifo_wptr[PTR_WIDTH-2:0]] <= wdata_i;
end
end
logic [Width-1:0] rdata_int;
if (Pass == 1'b1) begin : gen_pass
assign rdata_int = (fifo_empty && wvalid) ? wdata : storage_rdata;
assign empty = fifo_empty & ~wvalid;
assign rdata_int = (fifo_empty && wvalid_i) ? wdata_i : storage_rdata;
assign empty = fifo_empty & ~wvalid_i;
end else begin : gen_nopass
assign rdata_int = storage_rdata;
assign empty = fifo_empty;
end
if (OutputZeroIfEmpty == 1'b1) begin : gen_output_zero
assign rdata = empty ? 'b0 : rdata_int;
assign rdata_o = empty ? 'b0 : rdata_int;
end else begin : gen_no_output_zero
assign rdata = rdata_int;
assign rdata_o = rdata_int;
end
`ASSERT(depthShallNotExceedParamDepth, !empty |-> depth <= DepthW'(Depth))
`ASSERT(depthShallNotExceedParamDepth, !empty |-> depth_o <= DepthW'(Depth))
end // block: gen_normal_fifo
@ -153,9 +153,9 @@ module prim_fifo_sync #(
// Known Assertions //
//////////////////////
`ASSERT(DataKnown_A, rvalid |-> !$isunknown(rdata))
`ASSERT_KNOWN(DepthKnown_A, depth)
`ASSERT_KNOWN(RvalidKnown_A, rvalid)
`ASSERT_KNOWN(WreadyKnown_A, wready)
`ASSERT(DataKnown_A, rvalid_o |-> !$isunknown(rdata_o))
`ASSERT_KNOWN(DepthKnown_A, depth_o)
`ASSERT_KNOWN(RvalidKnown_A, rvalid_o)
`ASSERT_KNOWN(WreadyKnown_A, wready_o)
endmodule

View file

@ -1,6 +1,6 @@
// Copyright 2018 lowRISC contributors.
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Indentifier: Apache-2.0
// SPDX-License-Identifier: Apache-2.0
//
// Primitive input filter, with enable. Configurable number of cycles.
//

View file

@ -1,6 +1,6 @@
// Copyright 2018 lowRISC contributors.
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Indentifier: Apache-2.0
// SPDX-License-Identifier: Apache-2.0
//
// Primitive counter-based input filter, with enable.
// Configurable number of cycles. Cheaper version of filter for

View file

@ -1,28 +0,0 @@
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// Generic double-synchronizer flop
module prim_flop_2sync #(
parameter int Width = 16,
parameter logic [Width-1:0] ResetValue = '0
) (
input clk_i, // receive clock
input rst_ni,
input [Width-1:0] d,
output logic [Width-1:0] q
);
logic [Width-1:0] intq;
always_ff @(posedge clk_i or negedge rst_ni)
if (!rst_ni) begin
intq <= ResetValue;
q <= ResetValue;
end else begin
intq <= d;
q <= intq;
end
endmodule

View file

@ -2,50 +2,36 @@
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// Simple parameterizable gate generator. Used to fill up the netlist
// with gates that cannot be optimized away.
// Simple parameterizable gate generator. Used to fill up the netlist with gates that cannot be
// optimized away.
//
// The module leverages 4bit SBoxes from the PRINCE cipher, and interleaves
// them with registers, resulting in a split of around 50/50 between logic and
// sequential cells.
// The module leverages 4bit SBoxes from the PRINCE cipher, and interleaves them with registers,
// resulting in a split of around 50/50 between logic and sequential cells.
//
// This generator has been tested with 32bit wide data, and produces
// the following results:
// This generator has been tested with 32bit wide data, and produces the following results:
//
// if valid_i constantly set to 1'b1:
// -------------+-----------+----------
// requested GE | actual GE | GE error
// -------------+-----------+----------
// 500 | 679 | 179
// 1000 | 1018 | 18
// 1500 | 1696 | 196
// 2500 | 2714 | 214
// 5000 | 5210 | 210
// 7500 | 7456 | -44
// 10000 | 10015 | 15
// 15000 | 15191 | 191
// 25000 | 25228 | 228
// 50000 | 50485 | 485
// 500 | 483 | -17
// 1000 | 964 | -36
// 1500 | 1447 | -53
// 2500 | 2892 | 392
// 5000 | 5299 | 299
// 7500 | 8030 | 530
// 10000 | 10393 | 393
// 15000 | 15575 | 575
// 25000 | 26422 | 1422
// 50000 | 52859 | 2859
// 100000 | 105270 | 5270
//
// otherwise, with clock gating enabled:
// -------------+-----------+----------
// requested GE | actual GE | GE error
// -------------+-----------+----------
// 500 | 696 | 196
// 1000 | 1043 | 43
// 1500 | 1737 | 237
// 2500 | 2779 | 279
// 5000 | 5340 | 340
// 7500 | 7634 | 134
// 10000 | 10284 | 284
// 15000 | 15585 | 585
// 25000 | 25855 | 855
// 50000 | 51732 | 1732
// Note that the generator is not very accurate for smaller gate counts due to the generate loop
// granularity. Hence, do not use for fever than 500 GE.
//
// Note that the generator is not very accurate for smaller gate counts due
// to the generate loop granularity. Hence, do not use for fever than 500 GE.
// If valid_i constantly set to 1'b1, the gate generator produces around 2.5% smaller designs for
// the configurations listed in the table above.
`include "prim_assert.sv"
module prim_gate_gen #(
parameter int DataWidth = 32,
parameter int NumGates = 1000
@ -66,7 +52,7 @@ module prim_gate_gen #(
// technology specific tuning, do not modify.
// an inner round is comprised of a 2bit rotation, followed by a 4bit SBox Layer.
localparam int NumInnerRounds = 2;
localparam int GatesPerRound = DataWidth * 10;
localparam int GatesPerRound = DataWidth * 14;
// an outer round consists of NumInnerRounds, followed by a register.
localparam int NumOuterRounds = (NumGates + GatesPerRound / 2) / GatesPerRound;

View file

@ -1,6 +1,6 @@
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Indentifier: Apache-2.0
// SPDX-License-Identifier: Apache-2.0
//
// Primitive interrupt handler. This assumes the existence of three
// controller registers: INTR_ENABLE, INTR_STATE, INTR_TEST.

View file

@ -3,7 +3,7 @@
// SPDX-License-Identifier: Apache-2.0
//
// prim_keccak is single round permutation module
`include "prim_assert.sv"
module prim_keccak #(
parameter int Width = 1600, // b= {25, 50, 100, 200, 400, 800, 1600}

View file

@ -22,7 +22,7 @@
// TODO: this module has not been verified yet, and has only been used in
// synthesis experiments.
`include "prim_assert.sv"
module prim_present #(
parameter int DataWidth = 64, // {32, 64}
parameter int KeyWidth = 128, // {64, 80, 128}

View file

@ -24,7 +24,7 @@
// TODO: this module has not been verified yet, and has only been used in
// synthesis experiments.
`include "prim_assert.sv"
module prim_prince #(
parameter int DataWidth = 64,
parameter int KeyWidth = 128,

View file

@ -39,11 +39,11 @@ module prim_pulse_sync (
prim_flop_2sync #(.Width(1)) prim_flop_2sync (
// source clock domain
.d (src_level),
.d_i (src_level),
// destination clock domain
.clk_i (clk_dst_i),
.rst_ni (rst_dst_ni),
.q (dst_level)
.q_o (dst_level)
);
////////////////////////////////////////

View file

@ -20,24 +20,24 @@ module prim_sram_arbiter #(
input clk_i,
input rst_ni,
input [ N-1:0] req,
input [SramAw-1:0] req_addr [N],
input req_write [N],
input [SramDw-1:0] req_wdata [N],
output logic [ N-1:0] gnt,
input [ N-1:0] req_i,
input [SramAw-1:0] req_addr_i [N],
input req_write_i[N],
input [SramDw-1:0] req_wdata_i[N],
output logic [ N-1:0] gnt_o,
output logic [ N-1:0] rsp_rvalid, // Pulse
output logic [SramDw-1:0] rsp_rdata [N],
output logic [ 1:0] rsp_error [N],
output logic [ N-1:0] rsp_rvalid_o, // Pulse
output logic [SramDw-1:0] rsp_rdata_o[N],
output logic [ 1:0] rsp_error_o[N],
// SRAM Interface
output logic sram_req,
output logic [SramAw-1:0] sram_addr,
output logic sram_write,
output logic [SramDw-1:0] sram_wdata,
input sram_rvalid,
input [SramDw-1:0] sram_rdata,
input [1:0] sram_rerror
output logic sram_req_o,
output logic [SramAw-1:0] sram_addr_o,
output logic sram_write_o,
output logic [SramDw-1:0] sram_wdata_o,
input sram_rvalid_i,
input [SramDw-1:0] sram_rdata_i,
input [1:0] sram_rerror_i
);
@ -52,13 +52,13 @@ module prim_sram_arbiter #(
req_t req_packed [N];
for (genvar i = 0 ; i < N ; i++) begin : gen_reqs
assign req_packed[i] = {req_write[i], req_addr[i], req_wdata[i]};
assign req_packed[i] = {req_write_i[i], req_addr_i[i], req_wdata_i[i]};
end
req_t sram_packed;
assign sram_write = sram_packed.write;
assign sram_addr = sram_packed.addr;
assign sram_wdata = sram_packed.wdata;
assign sram_write_o = sram_packed.write;
assign sram_addr_o = sram_packed.addr;
assign sram_wdata_o = sram_packed.wdata;
if (ArbiterImpl == "PPC") begin : gen_arb_ppc
prim_arbiter_ppc #(
@ -67,11 +67,11 @@ module prim_sram_arbiter #(
) u_reqarb (
.clk_i,
.rst_ni,
.req_i ( req ),
.req_i,
.data_i ( req_packed ),
.gnt_o ( gnt ),
.gnt_o,
.idx_o ( ),
.valid_o ( sram_req ),
.valid_o ( sram_req_o ),
.data_o ( sram_packed ),
.ready_i ( 1'b1 )
);
@ -82,11 +82,11 @@ module prim_sram_arbiter #(
) u_reqarb (
.clk_i,
.rst_ni,
.req_i ( req ),
.req_i,
.data_i ( req_packed ),
.gnt_o ( gnt ),
.gnt_o,
.idx_o ( ),
.valid_o ( sram_req ),
.valid_o ( sram_req_o ),
.data_o ( sram_packed ),
.ready_i ( 1'b1 )
);
@ -95,10 +95,10 @@ module prim_sram_arbiter #(
end
logic [N-1:0] steer; // Steering sram_rvalid
logic sram_ack; // Ack for rvalid. |sram_rvalid
logic [N-1:0] steer; // Steering sram_rvalid_i
logic sram_ack; // Ack for rvalid. |sram_rvalid_i
assign sram_ack = sram_rvalid & (|steer);
assign sram_ack = sram_rvalid_i & (|steer);
// Request FIFO
prim_fifo_sync #(
@ -109,20 +109,20 @@ module prim_sram_arbiter #(
.clk_i,
.rst_ni,
.clr_i (1'b0),
.wvalid (sram_req && !sram_write), // Push only for read
.wready (), // TODO: Generate Error
.wdata (gnt),
.depth (), // Not used
.rvalid (), // TODO; Generate error if sram_rvalid but rvalid==0
.rready (sram_ack),
.rdata (steer)
.wvalid_i (sram_req_o & ~sram_write_o), // Push only for read
.wready_o (), // TODO: Generate Error
.wdata_i (gnt_o),
.depth_o (), // Not used
.rvalid_o (), // TODO; Generate error if sram_rvalid_i but rvalid==0
.rready_i (sram_ack),
.rdata_o (steer)
);
assign rsp_rvalid = steer & {N{sram_rvalid}};
assign rsp_rvalid_o = steer & {N{sram_rvalid_i}};
for (genvar i = 0 ; i < N ; i++) begin : gen_rsp
assign rsp_rdata[i] = sram_rdata;
assign rsp_error[i] = sram_rerror; // No SECDED yet
assign rsp_rdata_o[i] = sram_rdata_i;
assign rsp_error_o[i] = sram_rerror_i; // No SECDED yet
end
endmodule

View file

@ -27,50 +27,38 @@ module prim_subreg #(
output logic [DW-1:0] qs
);
logic wr_en ;
logic wr_en;
logic [DW-1:0] wr_data;
if ((SWACCESS == "RW") || (SWACCESS == "WO")) begin : gen_w
assign wr_en = we | de ;
assign wr_data = (we == 1'b1) ? wd : d ; // SW higher priority
end else if (SWACCESS == "RO") begin : gen_ro
// Unused we, wd
assign wr_en = de ;
assign wr_data = d ;
end else if (SWACCESS == "W1S") begin : gen_w1s
// If SWACCESS is W1S, then assume hw tries to clear.
// So, give a chance HW to clear when SW tries to set.
// If both try to set/clr at the same bit pos, SW wins.
assign wr_en = we | de ;
assign wr_data = (de ? d : q) | (we ? wd : '0);
end else if (SWACCESS == "W1C") begin : gen_w1c
// If SWACCESS is W1C, then assume hw tries to set.
// So, give a chance HW to set when SW tries to clear.
// If both try to set/clr at the same bit pos, SW wins.
assign wr_en = we | de ;
assign wr_data = (de ? d : q) & (we ? ~wd : '1);
end else if (SWACCESS == "W0C") begin : gen_w0c
assign wr_en = we | de ;
assign wr_data = (de ? d : q) & (we ? wd : '1);
end else if (SWACCESS == "RC") begin : gen_rc
// This swtype is not recommended but exists for compatibility.
// WARN: we signal is actually read signal not write enable.
assign wr_en = we | de ;
assign wr_data = (de ? d : q) & (we ? '0 : '1);
end else begin : gen_hw
assign wr_en = de ;
assign wr_data = d ;
prim_subreg_arb #(
.DW ( DW ),
.SWACCESS ( SWACCESS )
) wr_en_data_arb (
.we,
.wd,
.de,
.d,
.q,
.wr_en,
.wr_data
);
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
qe <= 1'b0;
end else begin
qe <= we;
end
end
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) qe <= 1'b0;
else qe <= we ;
if (!rst_ni) begin
q <= RESVAL;
end else if (wr_en) begin
q <= wr_data;
end
end
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) q <= RESVAL ;
else if (wr_en) q <= wr_data;
end
assign qs = q;
endmodule

View file

@ -0,0 +1,79 @@
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// Write enable and data arbitration logic for register slice conforming to Comportibility guide.
module prim_subreg_arb #(
parameter int DW = 32 ,
parameter SWACCESS = "RW" // {RW, RO, WO, W1C, W1S, W0C, RC}
) (
// From SW: valid for RW, WO, W1C, W1S, W0C, RC.
// In case of RC, top connects read pulse to we.
input we,
input [DW-1:0] wd,
// From HW: valid for HRW, HWO.
input de,
input [DW-1:0] d,
// From register: actual reg value.
input [DW-1:0] q,
// To register: actual write enable and write data.
output logic wr_en,
output logic [DW-1:0] wr_data
);
if ((SWACCESS == "RW") || (SWACCESS == "WO")) begin : gen_w
assign wr_en = we | de;
assign wr_data = (we == 1'b1) ? wd : d; // SW higher priority
// Unused q - Prevent lint errors.
logic [DW-1:0] unused_q;
assign unused_q = q;
end else if (SWACCESS == "RO") begin : gen_ro
assign wr_en = de;
assign wr_data = d;
// Unused we, wd, q - Prevent lint errors.
logic unused_we;
logic [DW-1:0] unused_wd;
logic [DW-1:0] unused_q;
assign unused_we = we;
assign unused_wd = wd;
assign unused_q = q;
end else if (SWACCESS == "W1S") begin : gen_w1s
// If SWACCESS is W1S, then assume hw tries to clear.
// So, give a chance HW to clear when SW tries to set.
// If both try to set/clr at the same bit pos, SW wins.
assign wr_en = we | de;
assign wr_data = (de ? d : q) | (we ? wd : '0);
end else if (SWACCESS == "W1C") begin : gen_w1c
// If SWACCESS is W1C, then assume hw tries to set.
// So, give a chance HW to set when SW tries to clear.
// If both try to set/clr at the same bit pos, SW wins.
assign wr_en = we | de;
assign wr_data = (de ? d : q) & (we ? ~wd : '1);
end else if (SWACCESS == "W0C") begin : gen_w0c
assign wr_en = we | de;
assign wr_data = (de ? d : q) & (we ? wd : '1);
end else if (SWACCESS == "RC") begin : gen_rc
// This swtype is not recommended but exists for compatibility.
// WARN: we signal is actually read signal not write enable.
assign wr_en = we | de;
assign wr_data = (de ? d : q) & (we ? '0 : '1);
// Unused wd - Prevent lint errors.
logic [DW-1:0] unused_wd;
assign unused_wd = wd;
end else begin : gen_hw
assign wr_en = de;
assign wr_data = d;
// Unused we, wd, q - Prevent lint errors.
logic unused_we;
logic [DW-1:0] unused_wd;
logic [DW-1:0] unused_q;
assign unused_we = we;
assign unused_wd = wd;
assign unused_q = q;
end
endmodule

View file

@ -0,0 +1,157 @@
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// Shadowed register slice conforming to Comportibility guide.
module prim_subreg_shadow #(
parameter int DW = 32 ,
parameter SWACCESS = "RW", // {RW, RO, WO, W1C, W1S, W0C, RC}
parameter logic [DW-1:0] RESVAL = '0 // reset value
) (
input clk_i,
input rst_ni,
// From SW: valid for RW, WO, W1C, W1S, W0C, RC.
// SW reads clear phase unless SWACCESS is RO.
input re,
// In case of RC, top connects read pulse to we.
input we,
input [DW-1:0] wd,
// From HW: valid for HRW, HWO.
input de,
input [DW-1:0] d,
// Output to HW and Reg Read
output logic qe,
output logic [DW-1:0] q,
output logic [DW-1:0] qs,
// Error conditions
output logic err_update,
output logic err_storage
);
// Subreg control signals
logic phase_clear;
logic phase_q;
logic staged_we, shadow_we, committed_we;
logic staged_de, shadow_de, committed_de;
// Subreg status and data signals
logic staged_qe, shadow_qe, committed_qe;
logic [DW-1:0] staged_q, shadow_q, committed_q;
logic [DW-1:0] committed_qs;
// Effective write enable and write data signals.
// These depend on we, de and wd, d, q as well as SWACCESS.
logic wr_en;
logic [DW-1:0] wr_data;
prim_subreg_arb #(
.DW ( DW ),
.SWACCESS ( SWACCESS )
) wr_en_data_arb (
.we ( we ),
.wd ( wd ),
.de ( de ),
.d ( d ),
.q ( q ),
.wr_en ( wr_en ),
.wr_data ( wr_data )
);
// Phase clearing:
// - SW reads clear phase unless SWACCESS is RO.
// - In case of RO, SW should not interfere with update process.
assign phase_clear = (SWACCESS == "RO") ? 1'b0 : re;
// Phase tracker:
// - Reads from SW clear the phase back to 0.
// - Writes have priority (can come from SW or HW).
always_ff @(posedge clk_i or negedge rst_ni) begin : phase_reg
if (!rst_ni) begin
phase_q <= 1'b0;
end else if (wr_en) begin
phase_q <= ~phase_q;
end else if (phase_clear) begin
phase_q <= 1'b0;
end
end
// The staged register:
// - Holds the 1's complement value.
// - Written in Phase 0.
assign staged_we = we & ~phase_q;
assign staged_de = de & ~phase_q;
prim_subreg #(
.DW ( DW ),
.SWACCESS ( SWACCESS ),
.RESVAL ( ~RESVAL )
) staged_reg (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.we ( staged_we ),
.wd ( ~wd ),
.de ( staged_de ),
.d ( ~d ),
.qe ( staged_qe ),
.q ( staged_q ),
.qs ( )
);
// The shadow register:
// - Holds the 1's complement value.
// - Written in Phase 1.
// - Writes are ignored in case of update errors.
// - Gets the value from the staged register.
assign shadow_we = we & phase_q & ~err_update;
assign shadow_de = de & phase_q & ~err_update;
prim_subreg #(
.DW ( DW ),
.SWACCESS ( SWACCESS ),
.RESVAL ( ~RESVAL )
) shadow_reg (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.we ( shadow_we ),
.wd ( staged_q ),
.de ( shadow_de ),
.d ( staged_q ),
.qe ( shadow_qe ),
.q ( shadow_q ),
.qs ( )
);
// The committed register:
// - Written in Phase 1.
// - Writes are ignored in case of update errors.
assign committed_we = shadow_we;
assign committed_de = shadow_de;
prim_subreg #(
.DW ( DW ),
.SWACCESS ( SWACCESS ),
.RESVAL ( RESVAL )
) committed_reg (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.we ( committed_we ),
.wd ( wd ),
.de ( committed_de ),
.d ( d ),
.qe ( committed_qe ),
.q ( committed_q ),
.qs ( committed_qs )
);
// Error detection - all bits must match.
assign err_update = (~staged_q != wr_data) ? phase_q & wr_en : 1'b0;
assign err_storage = (~shadow_q != committed_q);
// Remaining output assignments
assign qe = staged_qe | shadow_qe | committed_qe;
assign q = committed_q;
assign qs = committed_qs;
endmodule

View file

@ -53,8 +53,8 @@ module prim_sync_reqack (
) req_sync (
.clk_i (clk_dst_i),
.rst_ni (rst_dst_ni),
.d (src_req_q),
.q (dst_req)
.d_i (src_req_q),
.q_o (dst_req)
);
// Move ACK over to REQ side.
@ -63,8 +63,8 @@ module prim_sync_reqack (
) ack_sync (
.clk_i (clk_src_i),
.rst_ni (rst_src_ni),
.d (dst_ack_q),
.q (src_ack)
.d_i (dst_ack_q),
.q_o (src_ack)
);
// REQ-side FSM (source domain)

View file

@ -5,7 +5,6 @@
import os
import re
import shutil
import subprocess
import sys
import yaml
@ -45,6 +44,7 @@ def _prim_cores(cores, prim_name=None):
if (vlnv['vendor'] == 'lowrisc' and
vlnv['library'].startswith('prim_') and
(prim_name is None or vlnv['name'] == prim_name)):
return core
return None
@ -159,6 +159,14 @@ def _parse_module_header(generic_impl_filepath, module_name):
}
def test_parse_parameter_port_list():
assert _parse_parameter_port_list("parameter integer P") == {'P'}
assert _parse_parameter_port_list("parameter logic [W-1:0] P") == {'P'}
assert _parse_parameter_port_list("parameter logic [W-1:0] P = '0") == {'P'}
assert _parse_parameter_port_list("parameter logic [W-1:0] P = 'b0") == {'P'}
assert _parse_parameter_port_list("parameter logic [W-1:0] P = 2'd0") == {'P'}
def _parse_parameter_port_list(parameter_port_list):
""" Parse a list of ports in a module header into individual parameters """
@ -177,9 +185,9 @@ def _parse_parameter_port_list(parameter_port_list):
# XXX: Not covering the complete grammar, e.g. `parameter x, y`
RE_PARAMS = (
r'parameter\s+'
r'(?:[a-zA-Z0-9\]\[:\s\$]+\s+)?' # type
r'(?:[a-zA-Z0-9\]\[:\s\$-]+\s+)?' # type
r'(?P<name>\w+)' # name
r'(?:\s*=\s*[^,;]+)' # initial value
r'(?:\s*=\s*[^,;]+)?' # initial value
)
re_params = re.compile(RE_PARAMS)
parameters = set()
@ -189,9 +197,8 @@ def _parse_parameter_port_list(parameter_port_list):
def _check_gapi(gapi):
if not 'cores' in gapi:
if 'cores' not in gapi:
print("Key 'cores' not found in GAPI structure. "
"At least FuseSoC 1.11 is needed. "
"Install a compatible version with "
"'pip3 install --user -r python-requirements.txt'.")
return False
@ -293,7 +300,7 @@ def _generate_abstract_impl(gapi):
techlibs = _techlibs(prim_cores)
if not 'generic' in techlibs:
if 'generic' not in techlibs:
raise ValueError("Techlib generic is required, but not found for "
"primitive %s." % prim_name)
print("Implementations for primitive %s: %s" %
@ -371,7 +378,8 @@ def _generate_abstract_impl(gapi):
f,
encoding="utf-8",
default_flow_style=False,
sort_keys=False)
sort_keys=False,
Dumper=YamlDumper)
print("Core file written to %s" % (abstract_prim_core_filepath, ))

View file

@ -13,5 +13,10 @@ waive -rules SELF_ASSIGN -regexp {LHS signal 'inout_io' encountered on the RHS o
-comment "This implements a keeper termination (it's basically an explicit TRIREG)"
waive -rules DRIVE_STRENGTH -regexp {Drive strength .* encountered on assignment to 'inout_io'} -location {prim_generic_pad_wrapper.sv} \
-comment "The pad simulation model uses driving strength attributes to emulate different IO terminations."
waive -rules INPUT_NOT_READ -regexp {Input port 'attr\_i\[.:6\]' is not read from} -location {prim_generic_pad_wrapper.sv}\
waive -rules INPUT_NOT_READ -regexp {Input port 'attr\_i*' is not read from} -location {prim_generic_pad_wrapper.sv} \
-comment "Some IO attributes may not be implemented."
waive -rules Z_USE -regexp {Constant with 'Z literal value '1'bz' encountered} -location {prim_generic_pad_wrapper.sv} \
-comment "This z assignment is correct."
waive -rules PARAM_NOT_USED -regexp {Parameter 'Variant' not used in module 'prim_generic_pad_wrapper'} -location {prim_generic_pad_wrapper.sv} \
-comment "This parameter has been provisioned for later and is currently unused."

View file

@ -0,0 +1,40 @@
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_generic:clock_buf"
description: "clock buffer"
filesets:
files_rtl:
files:
- rtl/prim_generic_clock_buf.sv
file_type: systemVerilogSource
files_verilator_waiver:
depend:
# common waivers
- lowrisc:lint:common
files:
file_type: vlt
files_ascentlint_waiver:
depend:
# common waivers
- lowrisc:lint:common
files:
file_type: waiver
files_veriblelint_waiver:
depend:
# common waivers
- lowrisc:lint:common
- lowrisc:lint:comportable
targets:
default:
filesets:
- tool_verilator ? (files_verilator_waiver)
- tool_ascentlint ? (files_ascentlint_waiver)
- tool_veriblelint ? (files_veriblelint_waiver)
- files_rtl

View file

@ -0,0 +1,45 @@
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_generic:clock_inv"
description: "Clock inverter with scanmode bypass mux"
filesets:
files_rtl:
depend:
- lowrisc:prim:assert
- lowrisc:prim:clock_mux2
files:
- rtl/prim_generic_clock_inv.sv
file_type: systemVerilogSource
files_verilator_waiver:
depend:
# common waivers
- lowrisc:lint:common
files:
# - lint/prim_generic_clock_inv.vlt
file_type: vlt
files_ascentlint_waiver:
depend:
# common waivers
- lowrisc:lint:common
files:
# - lint/prim_generic_clock_inv.waiver
file_type: waiver
files_veriblelint_waiver:
depend:
# common waivers
- lowrisc:lint:common
- lowrisc:lint:comportable
targets:
default:
filesets:
- tool_verilator ? (files_verilator_waiver)
- tool_ascentlint ? (files_ascentlint_waiver)
- tool_veriblelint ? (files_veriblelint_waiver)
- files_rtl

View file

@ -0,0 +1,40 @@
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_generic:flop"
description: "generic flop"
filesets:
files_rtl:
files:
- rtl/prim_generic_flop.sv
file_type: systemVerilogSource
files_verilator_waiver:
depend:
# common waivers
- lowrisc:lint:common
files:
file_type: vlt
files_ascentlint_waiver:
depend:
# common waivers
- lowrisc:lint:common
files:
file_type: waiver
files_veriblelint_waiver:
depend:
# common waivers
- lowrisc:lint:common
- lowrisc:lint:comportable
targets:
default:
filesets:
- tool_verilator ? (files_verilator_waiver)
- tool_ascentlint ? (files_ascentlint_waiver)
- tool_veriblelint ? (files_veriblelint_waiver)
- files_rtl

View file

@ -0,0 +1,40 @@
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_generic:flop_2sync"
description: "Generic synchronizer cell"
filesets:
files_rtl:
files:
- rtl/prim_generic_flop_2sync.sv
file_type: systemVerilogSource
files_verilator_waiver:
depend:
# common waivers
- lowrisc:lint:common
files:
file_type: vlt
files_ascentlint_waiver:
depend:
# common waivers
- lowrisc:lint:common
files:
file_type: waiver
files_veriblelint_waiver:
depend:
# common waivers
- lowrisc:lint:common
- lowrisc:lint:comportable
targets:
default:
filesets:
- tool_verilator ? (files_verilator_waiver)
- tool_ascentlint ? (files_ascentlint_waiver)
- tool_veriblelint ? (files_veriblelint_waiver)
- files_rtl

View file

@ -8,6 +8,7 @@ description: "prim"
filesets:
files_rtl:
depend:
- lowrisc:prim:assert
- lowrisc:prim:util_memload
files:
- rtl/prim_generic_ram_2p.sv

View file

@ -0,0 +1,14 @@
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
`include "prim_assert.sv"
module prim_generic_clock_buf (
input clk_i,
output logic clk_o
);
assign clk_o = clk_i;
endmodule // prim_generic_clock_buf

View file

@ -5,7 +5,7 @@
// Clock inverter
// Varies on the process
module prim_clock_inverter #(
module prim_generic_clock_inv #(
parameter bit HasScanMode = 1'b1
) (
input clk_i,
@ -15,10 +15,10 @@ module prim_clock_inverter #(
if (HasScanMode) begin : gen_scan
prim_clock_mux2 i_dft_tck_mux (
.clk0_i ( ~clk_i ),
.clk1_i ( clk_i ), // bypass the inverted clock for testing
.sel_i ( scanmode_i ),
.clk_o ( clk_no )
.clk0_i ( ~clk_i ),
.clk1_i ( clk_i ), // bypass the inverted clock for testing
.sel_i ( scanmode_i ),
.clk_o ( clk_no )
);
end else begin : gen_noscan
logic unused_scanmode;
@ -26,4 +26,4 @@ module prim_clock_inverter #(
assign clk_no = ~clk_i;
end
endmodule
endmodule : prim_generic_clock_inv

View file

@ -77,20 +77,20 @@ module prim_generic_flash #(
flash_ctrl_pkg::flash_part_e part_q;
prim_fifo_sync #(
.Width (AddrW + $bits(flash_ctrl_pkg::flash_part_e)),
.Pass (0),
.Depth (2)
.Width (AddrW + $bits(flash_ctrl_pkg::flash_part_e)),
.Pass (0),
.Depth (2)
) i_slice (
.clk_i,
.rst_ni,
.clr_i (1'b0),
.wvalid (rd_i),
.wready (),
.wdata ({part_i, addr_i}),
.depth (),
.rvalid (rd_q),
.rready (hold_cmd), //whenver command is held, pop
.rdata ({part_q, addr_q})
.clr_i (1'b0),
.wvalid_i(rd_i),
.wready_o(),
.wdata_i ({part_i, addr_i}),
.depth_o (),
.rvalid_o(rd_q),
.rready_i(hold_cmd), //whenver command is held, pop
.rdata_o ({part_q, addr_q})
);
@ -102,7 +102,7 @@ module prim_generic_flash #(
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
held_addr <= '0;
held_part <= flash_ctrl_pkg::DataPart;
held_part <= flash_ctrl_pkg::FlashPartData;
held_wdata <= '0;
end else if (hold_cmd) begin
held_addr <= rd_q ? addr_q : addr_i;
@ -155,7 +155,7 @@ module prim_generic_flash #(
mem_req = 'h0;
mem_wr = 'h0;
mem_addr = 'h0;
mem_part = flash_ctrl_pkg::DataPart;
mem_part = flash_ctrl_pkg::FlashPartData;
mem_wdata = 'h0;
time_cnt_inc = 1'h0;
time_cnt_clr = 1'h0;
@ -291,7 +291,7 @@ module prim_generic_flash #(
.DataBitsPerMask(DataWidth)
) u_mem (
.clk_i,
.req_i (mem_req & (mem_part == flash_ctrl_pkg::DataPart)),
.req_i (mem_req & (mem_part == flash_ctrl_pkg::FlashPartData)),
.write_i (mem_wr),
.addr_i (mem_addr),
.wdata_i (mem_wdata),
@ -305,7 +305,7 @@ module prim_generic_flash #(
.DataBitsPerMask(DataWidth)
) u_info_mem (
.clk_i,
.req_i (mem_req & (mem_part == flash_ctrl_pkg::InfoPart)),
.req_i (mem_req & (mem_part == flash_ctrl_pkg::FlashPartInfo)),
.write_i (mem_wr),
.addr_i (mem_addr[0 +: InfoAddrW]),
.wdata_i (mem_wdata),
@ -313,6 +313,6 @@ module prim_generic_flash #(
.rdata_o (rd_data_info)
);
assign rd_data_o = held_part == flash_ctrl_pkg::DataPart ? rd_data_main : rd_data_info;
assign rd_data_o = held_part == flash_ctrl_pkg::FlashPartData ? rd_data_main : rd_data_info;
endmodule // prim_generic_flash

View file

@ -0,0 +1,26 @@
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
`include "prim_assert.sv"
module prim_generic_flop # (
parameter int Width = 1,
localparam int WidthSubOne = Width-1,
parameter logic [WidthSubOne:0] ResetValue = 0
) (
input clk_i,
input rst_ni,
input [Width-1:0] d_i,
output logic [Width-1:0] q_o
);
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
q_o <= ResetValue;
end else begin
q_o <= d_i;
end
end
endmodule // prim_generic_flop

View file

@ -0,0 +1,43 @@
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// Generic double-synchronizer flop
// This may need to be moved to prim_generic if libraries have a specific cell
// for synchronization
module prim_generic_flop_2sync #(
parameter int Width = 16,
localparam int WidthSubOne = Width-1, // temp work around #2679
parameter logic [WidthSubOne:0] ResetValue = '0
) (
input clk_i, // receive clock
input rst_ni,
input [Width-1:0] d_i,
output logic [Width-1:0] q_o
);
logic [Width-1:0] intq;
prim_flop #(
.Width(Width),
.ResetValue(ResetValue)
) u_sync_1 (
.clk_i,
.rst_ni,
.d_i,
.q_o(intq)
);
prim_flop #(
.Width(Width),
.ResetValue(ResetValue)
) u_sync_2 (
.clk_i,
.rst_ni,
.d_i(intq),
.q_o
);
endmodule

View file

@ -8,46 +8,87 @@
`include "prim_assert.sv"
module prim_generic_pad_wrapper #(
parameter int unsigned AttrDw = 6
parameter int Variant = 0, // currently ignored
parameter int AttrDw = 10,
parameter bit WarlOnly = 0 // If set to 1, no pad is instantiated and only warl_o is driven
) (
inout wire inout_io, // bidirectional pad
output logic in_o, // input data
input ie_i, // input enable
input out_i, // output data
input oe_i, // output enable
// additional attributes {drive strength, keeper, pull-up, pull-down, open-drain, invert}
input [AttrDw-1:0] attr_i
// additional attributes
input [AttrDw-1:0] attr_i,
output logic [AttrDw-1:0] warl_o
);
// get pad attributes
logic kp, pu, pd, od, inv;
typedef enum logic {STRONG_DRIVE = 1'b0, WEAK_DRIVE = 1'b1} drv_e;
drv_e drv;
assign {drv, kp, pu, pd, od, inv} = attr_i[5:0];
// Supported attributes:
// [x] Bit 0: input/output inversion,
// [x] Bit 1: Virtual open drain enable.
// [x] Bit 2: Pull enable.
// [x] Bit 3: Pull select (0: pull down, 1: pull up).
// [x] Bit 4: Keeper enable.
// [ ] Bit 5: Schmitt trigger enable.
// [ ] Bit 6: Slew rate (0: slow, 1: fast).
// [x] Bit 7/8: Drive strength (00: weakest, 11: strongest).
// [ ] Bit 9: Reserved.
assign warl_o = AttrDw'(10'h19F);
// input inversion
assign in_o = inv ^ inout_io;
if (WarlOnly) begin : gen_warl
assign inout_io = 1'bz;
assign in_o = 1'b0;
// virtual open drain emulation
logic oe, out;
assign out = out_i ^ inv;
assign oe = oe_i & ((od & ~out) | ~od);
logic [AttrDw-1:0] unused_attr;
logic unused_ie, unused_oe, unused_out, unused_inout;
assign unused_ie = ie_i;
assign unused_oe = oe_i;
assign unused_out = out_i;
assign unused_attr = attr_i;
assign unused_inout = inout_io;
end else begin : gen_pad
// get pad attributes
logic unused_sm, kp, unused_sr, ps, pe, od, inv;
typedef enum logic [1:0] {DRIVE_00 = 2'b00,
DRIVE_01 = 2'b01,
DRIVE_10 = 2'b10,
DRIVE_11 = 2'b11} drv_e;
drv_e drv;
assign {drv, unused_sr, unused_sm, kp, ps, pe, od, inv} = attr_i[8:0];
// driving strength attributes are not supported by verilator
if (AttrDw > 9) begin : gen_unused_attr
logic [AttrDw-9-1:0] unused_attr;
assign unused_attr = attr_i[AttrDw-1:9];
end
// input inversion
logic in;
assign in = inv ^ inout_io;
// virtual open drain emulation
logic oe, out;
assign out = out_i ^ inv;
assign oe = oe_i & ((od & ~out) | ~od);
// driving strength attributes are not supported by verilator
`ifdef VERILATOR
assign inout_io = (oe) ? out : 1'bz;
assign inout_io = (oe) ? out : 1'bz;
// received data driver
assign in_o = (ie_i) ? in : 1'bz;
`else
// different driver types
assign (strong0, strong1) inout_io = (oe && drv == STRONG_DRIVE) ? out : 1'bz;
assign (pull0, pull1) inout_io = (oe && drv == WEAK_DRIVE) ? out : 1'bz;
// pullup / pulldown termination
// default to high-Z in case both PU and PD are asserted (safety mechanism).
assign (highz0, weak1) inout_io = pu & ~pd;
assign (weak0, highz1) inout_io = pu | ~pd;
// fake trireg emulation
assign (weak0, weak1) inout_io = (kp) ? inout_io : 1'bz;
// different driver types
assign (strong0, strong1) inout_io = (oe && drv != DRIVE_00) ? out : 1'bz;
assign (pull0, pull1) inout_io = (oe && drv == DRIVE_00) ? out : 1'bz;
// pullup / pulldown termination
assign (highz0, weak1) inout_io = pe & ps; // enabled and select = 1
assign (weak0, highz1) inout_io = pe & ~ps; // enabled and select = 0
// fake trireg emulation
assign (weak0, weak1) inout_io = (kp) ? inout_io : 1'bz;
// received data driver
assign in_o = (ie_i) ? in : 1'bz;
`endif
end
// assertions
`ASSERT_INIT(AttrDwCheck_A, AttrDw >= 7)
`ASSERT_INIT(AttrDwCheck_A, AttrDw >= 9)
endmodule : prim_generic_pad_wrapper

View file

@ -34,8 +34,8 @@ module prim_generic_ram_1p #(
for (genvar k = 0; k < MaskWidth; k++) begin : gen_wmask
assign wmask[k] = &wmask_i[k*DataBitsPerMask +: DataBitsPerMask];
// Ensure that all mask bits within a group have the same value
`ASSERT(MaskCheck_A, req_i |->
// Ensure that all mask bits within a group have the same value for a write
`ASSERT(MaskCheck_A, req_i && write_i |->
wmask_i[k*DataBitsPerMask +: DataBitsPerMask] inside {{DataBitsPerMask{1'b1}}, '0},
clk_i, '0)
end

View file

@ -5,7 +5,7 @@
// Synchronous dual-port SRAM register model
// This module is for simulation and small size SRAM.
// Implementing ECC should be done inside wrapper not this model.
`include "prim_assert.sv"
module prim_generic_ram_2p #(
parameter int Width = 32, // bit
parameter int Depth = 128,
@ -44,11 +44,11 @@ module prim_generic_ram_2p #(
assign a_wmask[k] = &a_wmask_i[k*DataBitsPerMask +: DataBitsPerMask];
assign b_wmask[k] = &b_wmask_i[k*DataBitsPerMask +: DataBitsPerMask];
// Ensure that all mask bits within a group have the same value
`ASSERT(MaskCheckPortA_A, a_req_i |->
// Ensure that all mask bits within a group have the same value for a write
`ASSERT(MaskCheckPortA_A, a_req_i && a_write_i |->
a_wmask_i[k*DataBitsPerMask +: DataBitsPerMask] inside {{DataBitsPerMask{1'b1}}, '0},
clk_a_i, '0)
`ASSERT(MaskCheckPortB_A, b_req_i |->
`ASSERT(MaskCheckPortB_A, b_req_i && b_write_i |->
b_wmask_i[k*DataBitsPerMask +: DataBitsPerMask] inside {{DataBitsPerMask{1'b1}}, '0},
clk_b_i, '0)
end

View file

@ -7,37 +7,72 @@
module prim_xilinx_pad_wrapper #(
parameter int unsigned AttrDw = 2
parameter int Variant = 0, // currently ignored
parameter int AttrDw = 10,
parameter bit WarlOnly = 0 // If set to 1, no pad is instantiated and only warl_o is driven
) (
inout wire inout_io, // bidirectional pad
output logic in_o, // input data
input ie_i, // input enable
input out_i, // output data
input oe_i, // output enable
// additional attributes
input [AttrDw-1:0] attr_i
input [AttrDw-1:0] attr_i,
output logic [AttrDw-1:0] warl_o
);
// get pad attributes
logic od, inv;
assign {od, inv} = attr_i[1:0];
// Supported attributes:
// [x] Bit 0: input/output inversion,
// [x] Bit 1: Virtual open drain enable.
// [ ] Bit 2: Pull enable.
// [ ] Bit 3: Pull select (0: pull down, 1: pull up).
// [ ] Bit 4: Keeper enable.
// [ ] Bit 5: Schmitt trigger enable.
// [ ] Bit 6: Slew rate (0: slow, 1: fast).
// [ ] Bit 7/8: Drive strength (00: weakest, 11: strongest).
// [ ] Bit 9: Reserved.
assign warl_o = AttrDw'(2'h3);
// input inversion
logic in;
assign in_o = inv ^ in;
if (WarlOnly) begin : gen_warl
assign inout_io = 1'bz;
assign in_o = 1'b0;
// virtual open drain emulation
logic oe_n, out;
assign out = out_i ^ inv;
// oe_n = 0: enable driver
// oe_n = 1: disable driver
assign oe_n = ~oe_i | (out & od);
logic [AttrDw-1:0] unused_attr;
logic unused_ie, unused_oe, unused_out, unused_inout;
assign unused_ie = ie_i;
assign unused_oe = oe_i;
assign unused_out = out_i;
assign unused_attr = attr_i;
assign unused_inout = inout_io;
end else begin : gen_pad
// driver
IOBUF i_iobuf (
.T(oe_n),
.I(out),
.O(in),
.IO(inout_io)
);
// get pad attributes
logic od, inv;
assign {od, inv} = attr_i[1:0];
if (AttrDw > 9) begin : gen_unused_attr
logic [AttrDw-9-1:0] unused_attr;
assign unused_attr = attr_i[AttrDw-1:9];
end
// input inversion and buffer
logic in;
assign in_o = (ie_i) ? inv ^ in : 1'bz;
// virtual open drain emulation
logic oe_n, out;
assign out = out_i ^ inv;
// oe_n = 0: enable driver
// oe_n = 1: disable driver
assign oe_n = ~oe_i | (out & od);
// driver
IOBUF i_iobuf (
.T ( oe_n ),
.I ( out ),
.O ( in ),
.IO ( inout_io )
);
end
endmodule : prim_xilinx_pad_wrapper

View file

@ -1,3 +1,6 @@
# Copyright lowRISC contributors.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
${'####################################################################################################'}
${'## Copyright lowRISC contributors. ##'}
${'## Licensed under the Apache License, Version 2.0, see LICENSE for details. ##'}