mirror of
https://github.com/openhwgroup/cve2.git
synced 2025-04-24 05:57:28 -04:00
Update lowrisc_ip to lowRISC/opentitan@5cae0cf1
Update code from upstream repository https://github.com/lowRISC/opentitan to revision 5cae0cf1fac783e0d0df8c8597bf65322a696a56 * Allow different assertion "backends" in prim_assert.sv (Rupert Swarbrick) * [prim_prince/doc] Update documentation (Michael Schaffner) * [prim_prince] Add option to instantiate a registers half-way (Michael Schaffner) * [prim_cipher_pkg] Reuse sbox4_8bit to build wider sbox layers (Michael Schaffner) * [dv/prim] add PRESENT testbench (Udi Jonnalagadda) * [uvmdvgen] Scoreboard update. (Srikrishna Iyer) * [flash_ctrl dv] Fix V1 tests (Srikrishna Iyer) * [prim_cipher_pkg] Replicate common subfunctions for other widths (Michael Schaffner) * [prim/present] fix PRESENT decryption bugs (Udi Jonnalagadda) * [prim/present] fix some PRESENT encryption bugs (Udi Jonnalagadda) * [dv] Add get_mem DPI function to Verilator simutil (Stefan Wallentowitz) * [lint/entropy_src] Add the entropy source to the lint regression (Michael Schaffner) * [style-lint] Fix some common style lint warnings (Michael Schaffner) * first set of security checks added to D2 checklist (Scott Johnson) * [fpv/tooling] add FPV class extension in dvsim (Cindy Chen) * [dvsim/lint] Minor fixes for printout issues and result parser status (Michael Schaffner) * [syn] Print detailed messages to .md if publication is disabled (Michael Schaffner) * [prim_util] Do not use $clog2() in Xcelium (Philipp Wagner) * [prim] Update ResetValue parameter in prim_flop_2sync (Timothy Chen) * Modified some command-line arguments for DSim (Aimee Sutton) * [prim_util] Make prim_util a package (Philipp Wagner) * [dv] Move mem checking to scb (Weicai Yang) * [lint] Make PINCONNECTEMPTY Verilator waiver common (Philipp Wagner) * [prim] - Fix generic flash enum reference (Timothy Chen) * [prim_ram_*adv] Mark cfg port as unused (Philipp Wagner) * [prim_fifo_sync] Use vbits() for simpler code (Philipp Wagner) * [prim_flash] Add reset to held_part (Eunchan Kim) * [lint] Add more lint waivers (Philipp Wagner) * [dv] Add random backdoor for csr_hw_reset (Weicai Yang) * [dv] Add set_freq_khz in clk_rst_if (Weicai Yang) * [prim] Close GAPI file handle in primgen (Philipp Wagner) * [fpv/prim_packer] fix CI failure due to index out of bound (Cindy Chen) * [prim_arbiter_*] Propagate parameter changes (Michael Schaffner) * [prim_arbiter_tree] Fix incorrect arbitration behavior (Michael Schaffner) * [prim_arbiter_ppc] Add more FPV fairness checks (Michael Schaffner) * [prim_ram*] Add an assertion that checks wmask consistency (Michael Schaffner) * [memutil] Increase max memory width to 256bit (Tom Roberts) * [flash] - Add flash info page support (Timothy Chen) Signed-off-by: Rupert Swarbrick <rswarbrick@lowrisc.org>
This commit is contained in:
parent
1aa4d5a32b
commit
f35a407906
76 changed files with 2617 additions and 692 deletions
2
vendor/lowrisc_ip.lock.hjson
vendored
2
vendor/lowrisc_ip.lock.hjson
vendored
|
@ -9,6 +9,6 @@
|
|||
upstream:
|
||||
{
|
||||
url: https://github.com/lowRISC/opentitan
|
||||
rev: c91b50f357a76dae2ada104e397f6a91f72a33da
|
||||
rev: 5cae0cf1fac783e0d0df8c8597bf65322a696a56
|
||||
}
|
||||
}
|
||||
|
|
13
vendor/lowrisc_ip/common_ifs/clk_rst_if.sv
vendored
13
vendor/lowrisc_ip/common_ifs/clk_rst_if.sv
vendored
|
@ -69,13 +69,18 @@ interface clk_rst_if #(
|
|||
if (wait_posedge && (rst_n === 1'b0)) @(posedge rst_n);
|
||||
endtask
|
||||
|
||||
// set the clk frequency in mhz
|
||||
function automatic void set_freq_mhz(real freq_mhz);
|
||||
clk_freq_mhz = freq_mhz;
|
||||
// set the clk frequency in khz
|
||||
function automatic void set_freq_khz(int freq_khz);
|
||||
clk_freq_mhz = $itor(freq_khz) / 1000;
|
||||
clk_period_ps = 1000_000 / clk_freq_mhz;
|
||||
recompute = 1'b1;
|
||||
endfunction
|
||||
|
||||
// set the clk frequency in mhz
|
||||
function automatic void set_freq_mhz(int freq_mhz);
|
||||
set_freq_khz(freq_mhz * 1000);
|
||||
endfunction
|
||||
|
||||
// call this function at t=0 (from tb top) to enable clk and rst_n to be driven
|
||||
function automatic void set_active(bit drive_clk_val = 1'b1, bit drive_rst_n_val = 1'b1);
|
||||
time t = $time;
|
||||
|
@ -218,7 +223,7 @@ interface clk_rst_if #(
|
|||
// start driving clk only after the first por reset assertion. The fork/join means that we'll
|
||||
// wait a whole number of clock periods, which means it's possible for the clock to synchronise
|
||||
// with the "expected" timestamps.
|
||||
bit done = 1'b0;
|
||||
bit done;
|
||||
fork
|
||||
begin
|
||||
wait_for_reset(.wait_posedge(1'b0));
|
||||
|
|
24
vendor/lowrisc_ip/csr_utils/csr_seq_lib.sv
vendored
24
vendor/lowrisc_ip/csr_utils/csr_seq_lib.sv
vendored
|
@ -158,6 +158,8 @@ endclass
|
|||
// checks. It is run as the first step of the CSR HW reset test.
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
class csr_write_seq extends csr_base_seq;
|
||||
static bit test_backdoor_path_done; // only run once
|
||||
bit en_rand_backdoor_write;
|
||||
`uvm_object_utils(csr_write_seq)
|
||||
|
||||
`uvm_object_new
|
||||
|
@ -165,7 +167,20 @@ class csr_write_seq extends csr_base_seq;
|
|||
virtual task body();
|
||||
uvm_reg_data_t wdata;
|
||||
|
||||
// check all hdl paths are valid
|
||||
if (!test_backdoor_path_done) begin
|
||||
uvm_reg_mem_hdl_paths_seq hdl_check_seq;
|
||||
hdl_check_seq = uvm_reg_mem_hdl_paths_seq::type_id::create("hdl_check_seq");
|
||||
foreach (models[i]) begin
|
||||
hdl_check_seq.model = models[i];
|
||||
hdl_check_seq.start(null);
|
||||
end
|
||||
test_backdoor_path_done = 1;
|
||||
end
|
||||
|
||||
foreach (test_csrs[i]) begin
|
||||
dv_base_reg dv_csr;
|
||||
bit backdoor;
|
||||
// check if parent block or register is excluded from write
|
||||
if (m_csr_excl_item.is_excl(test_csrs[i], CsrExclWrite, CsrHwResetTest)) begin
|
||||
`uvm_info(`gtn, $sformatf("Skipping register %0s due to CsrExclWrite exclusion",
|
||||
|
@ -178,7 +193,14 @@ class csr_write_seq extends csr_base_seq;
|
|||
|
||||
`DV_CHECK_STD_RANDOMIZE_FATAL(wdata)
|
||||
wdata &= get_mask_excl_fields(test_csrs[i], CsrExclWrite, CsrHwResetTest, m_csr_excl_item);
|
||||
csr_wr(.csr(test_csrs[i]), .value(wdata), .blocking(0));
|
||||
|
||||
`downcast(dv_csr, test_csrs[i])
|
||||
if (en_rand_backdoor_write && !dv_csr.get_is_ext_reg()) begin
|
||||
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(backdoor,
|
||||
backdoor dist {0 :/ 7, 1 :/ 3};)
|
||||
end
|
||||
|
||||
csr_wr(.csr(test_csrs[i]), .value(wdata), .blocking(0), .backdoor(backdoor));
|
||||
end
|
||||
endtask
|
||||
|
||||
|
|
21
vendor/lowrisc_ip/csr_utils/csr_utils_pkg.sv
vendored
21
vendor/lowrisc_ip/csr_utils/csr_utils_pkg.sv
vendored
|
@ -63,7 +63,6 @@ package csr_utils_pkg;
|
|||
function automatic void get_csr_addrs(input uvm_reg_block ral, ref uvm_reg_addr_t csr_addrs[$]);
|
||||
uvm_reg csrs[$];
|
||||
ral.get_registers(csrs);
|
||||
csr_addrs.delete();
|
||||
foreach (csrs[i]) begin
|
||||
csr_addrs.push_back(csrs[i].get_address());
|
||||
end
|
||||
|
@ -232,8 +231,7 @@ package csr_utils_pkg;
|
|||
input bit predict = 0,
|
||||
input uvm_reg_map map = null);
|
||||
if (backdoor) begin
|
||||
csr_poke(csr, value, check);
|
||||
if (predict) void'(csr.predict(.value(value), .kind(UVM_PREDICT_DIRECT)));
|
||||
csr_poke(csr, value, check, predict);
|
||||
end else if (blocking) begin
|
||||
csr_wr_sub(csr, value, check, path, timeout_ns, map);
|
||||
if (predict) void'(csr.predict(.value(value), .kind(UVM_PREDICT_WRITE)));
|
||||
|
@ -286,13 +284,24 @@ package csr_utils_pkg;
|
|||
// backdoor write csr
|
||||
task automatic csr_poke(input uvm_reg csr,
|
||||
input uvm_reg_data_t value,
|
||||
input uvm_check_e check = UVM_CHECK);
|
||||
input uvm_check_e check = UVM_CHECK,
|
||||
input bit predict = 0);
|
||||
uvm_status_e status;
|
||||
string msg_id = {csr_utils_pkg::msg_id, "::csr_poke"};
|
||||
uvm_reg_data_t old_mirrored_val = csr.get_mirrored_value();
|
||||
|
||||
csr.poke(.status(status), .value(value));
|
||||
if (check == UVM_CHECK) begin
|
||||
`DV_CHECK_EQ(status, UVM_IS_OK, "", error, msg_id)
|
||||
if (check == UVM_CHECK && status != UVM_IS_OK) begin
|
||||
string str;
|
||||
uvm_hdl_path_concat paths[$];
|
||||
csr.get_full_hdl_path(paths);
|
||||
foreach (paths[0].slices[i]) str = $sformatf("%0s\n%0s", str, paths[0].slices[i].path);
|
||||
`uvm_fatal(msg_id, $sformatf("poke failed for %0s, check below paths %0s",
|
||||
csr.get_full_name(), str))
|
||||
end
|
||||
// poke always updates predict value, if predict == 0, revert back to old mirrored value
|
||||
if (!predict) begin
|
||||
void'(csr.predict(.value(old_mirrored_val), .kind(UVM_PREDICT_DIRECT)));
|
||||
end
|
||||
endtask
|
||||
|
||||
|
|
|
@ -11,10 +11,6 @@ class dv_base_reg_field extends uvm_reg_field;
|
|||
|
||||
// when use UVM_PREDICT_WRITE and the CSR access is WO, this function will return the default
|
||||
// val of the register, rather than the written value
|
||||
// TODO, need to handle predict value when backdoor write happens WO reg
|
||||
// 1. for read, design ties the read data to default value
|
||||
// 2. when backdoor write updates internal reg, backdoor read can get the written value, but
|
||||
// frontdoor read always returns the default value.
|
||||
virtual function uvm_reg_data_t XpredictX(uvm_reg_data_t cur_val,
|
||||
uvm_reg_data_t wr_val,
|
||||
uvm_reg_map map);
|
||||
|
|
2
vendor/lowrisc_ip/dv_lib/dv_base_env_cfg.sv
vendored
2
vendor/lowrisc_ip/dv_lib/dv_base_env_cfg.sv
vendored
|
@ -6,6 +6,8 @@ class dv_base_env_cfg #(type RAL_T = dv_base_reg_block) extends uvm_object;
|
|||
|
||||
bit is_active = 1;
|
||||
bit en_scb = 1; // can be changed at run-time
|
||||
bit en_scb_tl_err_chk = 1;
|
||||
bit en_scb_mem_chk = 1;
|
||||
bit en_cov = 1;
|
||||
bit has_ral = 1;
|
||||
bit under_reset = 0;
|
||||
|
|
2
vendor/lowrisc_ip/dv_lib/dv_base_test.sv
vendored
2
vendor/lowrisc_ip/dv_lib/dv_base_test.sv
vendored
|
@ -32,6 +32,8 @@ class dv_base_test #(type CFG_T = dv_base_env_cfg,
|
|||
|
||||
// knob to en/dis scb (enabled by default)
|
||||
void'($value$plusargs("en_scb=%0b", cfg.en_scb));
|
||||
void'($value$plusargs("en_scb_tl_err_chk=%0b", cfg.en_scb_tl_err_chk));
|
||||
void'($value$plusargs("en_scb_mem_chk=%0b", cfg.en_scb_mem_chk));
|
||||
// knob to cfg all agents with zero delays
|
||||
void'($value$plusargs("zero_delays=%0b", cfg.zero_delays));
|
||||
endfunction : build_phase
|
||||
|
|
1
vendor/lowrisc_ip/dv_lib/dv_base_vseq.sv
vendored
1
vendor/lowrisc_ip/dv_lib/dv_base_vseq.sv
vendored
|
@ -172,6 +172,7 @@ class dv_base_vseq #(type RAL_T = dv_base_reg_block,
|
|||
m_csr_write_seq.models = cfg.ral_models;
|
||||
m_csr_write_seq.set_csr_excl_item(csr_excl);
|
||||
m_csr_write_seq.external_checker = cfg.en_scb;
|
||||
m_csr_write_seq.en_rand_backdoor_write = 1;
|
||||
if (!enable_asserts_in_hw_reset_rand_wr) $assertoff;
|
||||
m_csr_write_seq.start(null);
|
||||
|
||||
|
|
|
@ -45,8 +45,8 @@ bool VerilatorMemUtil::RegisterMemoryArea(const std::string name,
|
|||
size_t width_bit) {
|
||||
MemArea mem = {.name = name, .location = location, .width_bit = width_bit};
|
||||
|
||||
assert((width_bit <= 128) &&
|
||||
"TODO: Memory loading only supported up to 128 bits.");
|
||||
assert((width_bit <= 256) &&
|
||||
"TODO: Memory loading only supported up to 256 bits.");
|
||||
|
||||
auto ret = mem_register_.emplace(name, mem);
|
||||
if (ret.second == false) {
|
||||
|
|
9
vendor/lowrisc_ip/dvsim/FlowCfg.py
vendored
9
vendor/lowrisc_ip/dvsim/FlowCfg.py
vendored
|
@ -13,7 +13,7 @@ import sys
|
|||
import hjson
|
||||
|
||||
from Deploy import Deploy
|
||||
from utils import VERBOSE, md_results_to_html, parse_hjson, subst_wildcards
|
||||
from utils import VERBOSE, md_results_to_html, parse_hjson, print_msg_list, subst_wildcards
|
||||
|
||||
|
||||
# Interface class for extensions.
|
||||
|
@ -86,6 +86,7 @@ class FlowCfg():
|
|||
# Full and summary results in md text.
|
||||
self.results_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
|
||||
|
@ -116,7 +117,7 @@ class FlowCfg():
|
|||
This method takes 2 args.
|
||||
flow_cfg_file: This is the flow cfg file to be parsed.
|
||||
is_entry_point: the cfg file that is passed on the command line is
|
||||
the entry point cfg. If the cfg file is a part of an inport_cfgs
|
||||
the entry point cfg. If the cfg file is a part of an import_cfgs
|
||||
or use_cfgs key, then it is not an entry point.
|
||||
'''
|
||||
hjson_dict = parse_hjson(flow_cfg_file)
|
||||
|
@ -485,7 +486,9 @@ class FlowCfg():
|
|||
|
||||
def gen_email_html_summary(self):
|
||||
if self.is_master_cfg:
|
||||
gen_results = self.results_summary_md
|
||||
# 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
|
||||
results_html = md_results_to_html(self.results_title, self.css_file, gen_results)
|
||||
|
|
279
vendor/lowrisc_ip/dvsim/FpvCfg.py
vendored
Normal file
279
vendor/lowrisc_ip/dvsim/FpvCfg.py
vendored
Normal file
|
@ -0,0 +1,279 @@
|
|||
# Copyright lowRISC contributors.
|
||||
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import logging as log
|
||||
from pathlib import Path
|
||||
|
||||
import hjson
|
||||
from tabulate import tabulate
|
||||
|
||||
from OneShotCfg import OneShotCfg
|
||||
from utils import subst_wildcards
|
||||
|
||||
|
||||
class FpvCfg(OneShotCfg):
|
||||
"""Derivative class for FPV purposes.
|
||||
"""
|
||||
def __init__(self, flow_cfg_file, proj_root, args):
|
||||
super().__init__(flow_cfg_file, proj_root, args)
|
||||
self.header = ["name", "errors", "warnings", "proven", "cex", "undetermined",
|
||||
"covered", "unreachable", "pass_rate", "cov_rate"]
|
||||
self.summary_header = ["name", "pass_rate", "stimuli_cov", "coi_cov", "prove_cov"]
|
||||
|
||||
def __post_init__(self):
|
||||
super().__post_init__()
|
||||
self.results_title = self.name.upper() + " FPV Results"
|
||||
|
||||
def parse_dict_to_str(self, input_dict, excl_keys = []):
|
||||
# This is a helper function to parse dictionary items into a string.
|
||||
# This function has an optional input "excl_keys" for user to exclude
|
||||
# printing out certain items according to their keys.
|
||||
# Note this function did not sort the input dictionary's key value
|
||||
# before printing the keys and items. If input dictionary is not an
|
||||
# OrderedDictionary, print out key order is not predictable.
|
||||
# This function works for Hjson lib outputs because the lib uses an
|
||||
# OrderDict when it reads dictionaries.
|
||||
# Example Input:
|
||||
# {
|
||||
# "unreachable": ["prop1, prop2, prop3"],
|
||||
# "cex" : ["prop1"],
|
||||
# }
|
||||
# Example Output:
|
||||
# string = "unreachable:
|
||||
# ```
|
||||
# prop1
|
||||
# prop2
|
||||
# prop3
|
||||
# ```
|
||||
# cex:
|
||||
# ```
|
||||
# prop1
|
||||
# ```"
|
||||
output_str = ""
|
||||
for key, item in input_dict.items():
|
||||
if (key not in excl_keys) and item:
|
||||
output_str += "\n" + key + ":\n"
|
||||
output_str += "```\n"
|
||||
output_str += "\n".join(item)
|
||||
output_str += "\n```\n"
|
||||
return output_str
|
||||
|
||||
def get_fpv_summary_results(self, result):
|
||||
summary = []
|
||||
fpv_summary = result.get("fpv_summary")
|
||||
if fpv_summary is None:
|
||||
results_str = "No fpv_summary found\n"
|
||||
summary.append("N/A")
|
||||
else:
|
||||
colalign = ("center", ) * len(self.header)
|
||||
table = [self.header]
|
||||
table.append([
|
||||
self.name,
|
||||
str(fpv_summary["errors"]) + " E ",
|
||||
str(fpv_summary["warnings"]) + " W ",
|
||||
str(fpv_summary["proven"]) + " G ",
|
||||
str(fpv_summary["cex"]) + " E ",
|
||||
str(fpv_summary["undetermined"]) + " W ",
|
||||
str(fpv_summary["covered"]) + " G ",
|
||||
str(fpv_summary["unreachable"]) + " E ",
|
||||
fpv_summary["pass_rate"],
|
||||
fpv_summary["cov_rate"]
|
||||
])
|
||||
summary.append(fpv_summary["pass_rate"])
|
||||
if len(table) > 1:
|
||||
results_str = tabulate(table, headers="firstrow", tablefmt="pipe",
|
||||
colalign=colalign)
|
||||
else:
|
||||
results_str = "No content in fpv_summary\n"
|
||||
summary.append("N/A")
|
||||
return results_str, summary
|
||||
|
||||
def get_fpv_coverage_results(self, result):
|
||||
summary = []
|
||||
fpv_coverage = result.get("fpv_coverage")
|
||||
if fpv_coverage is None:
|
||||
results_str = "No fpv_coverage found\n"
|
||||
summary = ["N/A", "N/A", "N/A"]
|
||||
else:
|
||||
cov_header = ["stimuli", "coi", "proof"]
|
||||
cov_colalign = ("center", ) * len(cov_header)
|
||||
cov_table = [cov_header]
|
||||
cov_table.append([
|
||||
fpv_coverage["stimuli"],
|
||||
fpv_coverage["coi"],
|
||||
fpv_coverage["proof"]
|
||||
])
|
||||
summary.append(fpv_coverage["stimuli"])
|
||||
summary.append(fpv_coverage["coi"])
|
||||
summary.append(fpv_coverage["proof"])
|
||||
|
||||
if len(cov_table) > 1:
|
||||
results_str = tabulate(cov_table, headers="firstrow",
|
||||
tablefmt="pipe", colalign=cov_colalign)
|
||||
|
||||
else:
|
||||
results_str = "No content in fpv_coverage\n"
|
||||
summary = ["N/A", "N/A", "N/A"]
|
||||
return results_str, summary
|
||||
|
||||
def gen_results_summary(self):
|
||||
# Gathers the aggregated results from all sub configs
|
||||
# The results_summary will only contain the passing rate and
|
||||
# percentages of the stimuli, coi, and proven coverage
|
||||
# The email_summary will contain all the information from results_md
|
||||
log.info("Create summary of FPV results")
|
||||
|
||||
results_str = "## " + self.results_title + " (Summary)\n\n"
|
||||
results_str += "### " + self.timestamp_long + "\n\n"
|
||||
|
||||
colalign = ("center", ) * len(self.summary_header)
|
||||
table = [self.summary_header]
|
||||
for cfg in self.cfgs:
|
||||
try:
|
||||
table.append(cfg.result_summary[cfg.name])
|
||||
except KeyError as e:
|
||||
table.append([cfg.name, "ERROR", "N/A", "N/A", "N/A"])
|
||||
log.error("cfg: %s could not find generated results_summary: %s", cfg.name, e)
|
||||
if len(table) > 1:
|
||||
self.results_summary_md = results_str + tabulate(
|
||||
table, headers="firstrow", tablefmt="pipe", colalign=colalign)
|
||||
else:
|
||||
self.results_summary_md = results_str
|
||||
|
||||
log.info("[result summary]: %s", self.results_summary_md)
|
||||
|
||||
# Generate email results summary
|
||||
colalign = ("left", ) + ("center", ) * (len(self.header) - 1)
|
||||
email_table = [self.header]
|
||||
error_message = ""
|
||||
|
||||
for cfg in self.cfgs:
|
||||
email_result = cfg.result.get("fpv_summary")
|
||||
if email_result is not None:
|
||||
email_table.append([
|
||||
cfg.name,
|
||||
str(email_result["errors"]) + " E ",
|
||||
str(email_result["warnings"]) + " W ",
|
||||
str(email_result["proven"]) + " G ",
|
||||
str(email_result["cex"]) + " E ",
|
||||
str(email_result["undetermined"]) + " W ",
|
||||
str(email_result["covered"]) + " G ",
|
||||
str(email_result["unreachable"]) + " E ",
|
||||
email_result["pass_rate"],
|
||||
email_result["cov_rate"]
|
||||
])
|
||||
messages = cfg.result.get("messages")
|
||||
if messages is not None:
|
||||
# TODO: temp disable printing out "fpv_warnings" in results_summary
|
||||
# Will clean up FPV warnings first, then display "fpv_warnings"
|
||||
error = self.parse_dict_to_str(messages, ["fpv_warnings"])
|
||||
if error:
|
||||
error_message += "\n#### " + cfg.name + "\n"
|
||||
error_message += error
|
||||
|
||||
if len(email_table) > 1:
|
||||
self.email_summary_md = results_str + tabulate(
|
||||
email_table, headers="firstrow", tablefmt="pipe", colalign=colalign)
|
||||
self.email_summary_md += error_message
|
||||
|
||||
return self.results_summary_md
|
||||
|
||||
def _gen_results(self):
|
||||
# This function is called after the regression and looks for
|
||||
# results.hjson file with aggregated results from the FPV run.
|
||||
# The hjson file is required to follow this format:
|
||||
# {
|
||||
# "messages": {
|
||||
# "errors" : []
|
||||
# "warnings" : []
|
||||
# "cex" : ["property1", "property2"...],
|
||||
# "undetermined": [],
|
||||
# "unreachable" : [],
|
||||
# },
|
||||
#
|
||||
# "fpv_summary": {
|
||||
# "errors" : 0
|
||||
# "warnings" : 2
|
||||
# "proven" : 20,
|
||||
# "cex" : 5,
|
||||
# "covered" : 18,
|
||||
# "undetermined": 7,
|
||||
# "unreachable" : 2,
|
||||
# "pass_rate" : "90 %",
|
||||
# "cover_rate" : "90 %"
|
||||
# },
|
||||
# }
|
||||
# The categories for property results are: proven, cex, undetermined,
|
||||
# covered, and unreachable.
|
||||
#
|
||||
# If coverage was enabled then results.hjson will also have an item that
|
||||
# shows FPV coverage. It will have the following format:
|
||||
# "fpv_coverage": {
|
||||
# stimuli: "90 %",
|
||||
# coi : "90 %",
|
||||
# proof : "80 %"
|
||||
# }
|
||||
results_str = "## " + self.results_title + "\n\n"
|
||||
results_str += "### " + self.timestamp_long + "\n"
|
||||
results_str += "### FPV Tool: " + self.tool.upper() + "\n"
|
||||
results_str += "### LogFile dir: " + self.scratch_path + "/default\n\n"
|
||||
|
||||
summary = [self.name] # cfg summary for publish results
|
||||
|
||||
if len(self.build_modes) != 1:
|
||||
mode_names = [mode.name for mode in self.build_modes]
|
||||
log.error("FPV only supports mode 'default', but found these modes: %s", mode_names)
|
||||
else:
|
||||
mode = self.build_modes[0]
|
||||
result_data = Path(subst_wildcards(self.build_dir, {"build_mode": mode.name}) +
|
||||
'/results.hjson')
|
||||
try:
|
||||
with open(result_data, "r") as results_file:
|
||||
self.result = hjson.load(results_file, use_decimal=True)
|
||||
except IOError as err:
|
||||
log.warning("%s", err)
|
||||
self.result = {
|
||||
"messages": {
|
||||
"errors": ["IOError: %s" % err],
|
||||
}
|
||||
}
|
||||
|
||||
fpv_result_str, fpv_summary = self.get_fpv_summary_results(self.result)
|
||||
results_str += fpv_result_str
|
||||
summary += fpv_summary
|
||||
|
||||
if self.cov:
|
||||
results_str += "\n\n## Coverage Results\n"
|
||||
results_str += ("### Coverage html file dir: " +
|
||||
self.scratch_path + "/default/formal-icarus\n\n")
|
||||
cov_result_str, cov_summary = self.get_fpv_coverage_results(self.result)
|
||||
results_str += cov_result_str
|
||||
summary += cov_summary
|
||||
|
||||
messages = self.result.get("messages")
|
||||
if messages is not None:
|
||||
results_str += self.parse_dict_to_str(messages)
|
||||
|
||||
# Write results to the scratch area
|
||||
self.results_md = results_str
|
||||
results_file = self.scratch_path + "/results_" + self.timestamp + ".md"
|
||||
with open(results_file, 'w') as f:
|
||||
f.write(self.results_md)
|
||||
|
||||
log.info("[results page]: [%s] [%s]", self.name, results_file)
|
||||
|
||||
# Generate result summary
|
||||
if not self.cov:
|
||||
summary += ["N/A", "N/A", "N/A"]
|
||||
self.result_summary[self.name] = summary
|
||||
|
||||
return self.results_md
|
||||
|
||||
def _publish_results(self):
|
||||
'''This does nothing: detailed messages from FPV runs are not published
|
||||
|
||||
Our agreement with tool vendors allows us to publish the summary
|
||||
results (as in gen_results_summary), but not anything more detailed.
|
||||
'''
|
||||
return
|
47
vendor/lowrisc_ip/dvsim/LintCfg.py
vendored
47
vendor/lowrisc_ip/dvsim/LintCfg.py
vendored
|
@ -12,20 +12,7 @@ from pathlib import Path
|
|||
from tabulate import tabulate
|
||||
|
||||
from OneShotCfg import OneShotCfg
|
||||
from utils import subst_wildcards
|
||||
|
||||
|
||||
# helper function for printing messages
|
||||
def _print_msg_list(msg_list_name, msg_list):
|
||||
md_results = ""
|
||||
if msg_list:
|
||||
md_results += "### %s\n" % msg_list_name
|
||||
md_results += "```\n"
|
||||
for msg in msg_list:
|
||||
md_results += msg + "\n\n"
|
||||
md_results += "```\n"
|
||||
return md_results
|
||||
|
||||
from utils import print_msg_list, subst_wildcards
|
||||
|
||||
class LintCfg(OneShotCfg):
|
||||
"""Derivative class for linting purposes.
|
||||
|
@ -185,22 +172,22 @@ class LintCfg(OneShotCfg):
|
|||
self.result_summary["lint_errors"] += self.result["lint_errors"]
|
||||
|
||||
# Append detailed messages if they exist
|
||||
if sum([
|
||||
len(self.result["warnings"]),
|
||||
len(self.result["errors"]),
|
||||
len(self.result["lint_warnings"]),
|
||||
len(self.result["lint_errors"])
|
||||
]):
|
||||
fail_msgs += "\n## Errors and Warnings for Build Mode `'" + mode.name + "'`\n"
|
||||
fail_msgs += _print_msg_list("Tool Errors",
|
||||
self.result["errors"])
|
||||
fail_msgs += _print_msg_list("Tool Warnings",
|
||||
self.result["warnings"])
|
||||
fail_msgs += _print_msg_list("Lint Errors",
|
||||
self.result["lint_errors"])
|
||||
fail_msgs += _print_msg_list("Lint Warnings",
|
||||
self.result["lint_warnings"])
|
||||
# fail_msgs += _print_msg_list("Lint Infos", results["lint_infos"])
|
||||
hdr_key_pairs = [("Tool Warnings", "warnings"),
|
||||
("Tool Errors", "errors"),
|
||||
("Lint Warnings", "lint_warnings"),
|
||||
("Lint Errors", "lint_errors")]
|
||||
|
||||
has_msg = False
|
||||
for _, key in hdr_key_pairs:
|
||||
if key in self.result:
|
||||
has_msg = True
|
||||
break
|
||||
|
||||
if has_msg:
|
||||
fail_msgs += "\n### Errors and Warnings for Build Mode `'" + mode.name + "'`\n"
|
||||
for hdr, key in hdr_key_pairs:
|
||||
msgs = self.result.get(key)
|
||||
fail_msgs += print_msg_list("#### " + hdr, msgs, self.max_msg_count)
|
||||
|
||||
if len(table) > 1:
|
||||
self.results_md = results_str + tabulate(
|
||||
|
|
3
vendor/lowrisc_ip/dvsim/OneShotCfg.py
vendored
3
vendor/lowrisc_ip/dvsim/OneShotCfg.py
vendored
|
@ -58,6 +58,7 @@ class OneShotCfg(FlowCfg):
|
|||
self.build_modes = []
|
||||
self.run_modes = []
|
||||
self.regressions = []
|
||||
self.max_msg_count = -1
|
||||
|
||||
# Flow results
|
||||
self.result = OrderedDict()
|
||||
|
@ -73,7 +74,7 @@ class OneShotCfg(FlowCfg):
|
|||
self.links = {}
|
||||
self.build_list = []
|
||||
self.deploy = []
|
||||
|
||||
self.cov = args.cov
|
||||
# Parse the cfg_file file tree
|
||||
self.parse_flow_cfg(flow_cfg_file)
|
||||
self._post_parse_flow_cfg()
|
||||
|
|
25
vendor/lowrisc_ip/dvsim/SynCfg.py
vendored
25
vendor/lowrisc_ip/dvsim/SynCfg.py
vendored
|
@ -12,7 +12,7 @@ import hjson
|
|||
from tabulate import tabulate
|
||||
|
||||
from OneShotCfg import OneShotCfg
|
||||
from utils import subst_wildcards
|
||||
from utils import print_msg_list, subst_wildcards
|
||||
|
||||
|
||||
class SynCfg(OneShotCfg):
|
||||
|
@ -343,6 +343,29 @@ class SynCfg(OneShotCfg):
|
|||
else:
|
||||
results_str += "No power report found\n\n"
|
||||
|
||||
# Append detailed messages if they exist
|
||||
# Note that these messages are omitted in publication mode
|
||||
hdr_key_pairs = [("Flow Warnings", "flow_warnings"),
|
||||
("Flow Errors", "flow_errors"),
|
||||
("Analyze Warnings", "analyze_warnings"),
|
||||
("Analyze Errors", "analyze_errors"),
|
||||
("Elab Warnings", "elab_warnings"),
|
||||
("Elab Errors", "elab_errors"),
|
||||
("Compile Warnings", "compile_warnings"),
|
||||
("Compile Errors", "compile_errors")]
|
||||
|
||||
has_msg = False
|
||||
for _, key in hdr_key_pairs:
|
||||
if key in self.result['messages']:
|
||||
has_msg = True
|
||||
break
|
||||
|
||||
if has_msg and not self.args.publish:
|
||||
results_str += "\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)
|
||||
|
||||
# TODO: add support for pie / bar charts for area splits and
|
||||
# QoR history
|
||||
|
||||
|
|
4
vendor/lowrisc_ip/dvsim/dvsim.py
vendored
4
vendor/lowrisc_ip/dvsim/dvsim.py
vendored
|
@ -29,6 +29,7 @@ import textwrap
|
|||
from signal import SIGINT, signal
|
||||
|
||||
import Deploy
|
||||
import FpvCfg
|
||||
import LintCfg
|
||||
import SimCfg
|
||||
import SynCfg
|
||||
|
@ -147,7 +148,8 @@ def make_config(args, proj_root):
|
|||
factories = {
|
||||
'ascentlint': LintCfg.LintCfg,
|
||||
'veriblelint': LintCfg.LintCfg,
|
||||
'dc': SynCfg.SynCfg
|
||||
'dc': SynCfg.SynCfg,
|
||||
'jaspergold': FpvCfg.FpvCfg
|
||||
}
|
||||
|
||||
factory = factories.get(args.tool, SimCfg.SimCfg)
|
||||
|
|
27
vendor/lowrisc_ip/dvsim/utils.py
vendored
27
vendor/lowrisc_ip/dvsim/utils.py
vendored
|
@ -350,3 +350,30 @@ def htmc_color_pc_cells(text):
|
|||
for item in subst_list:
|
||||
text = text.replace(item, subst_list[item])
|
||||
return text
|
||||
|
||||
|
||||
def print_msg_list(msg_list_title, msg_list, max_msg_count=-1):
|
||||
'''This function prints a list of messages to Markdown.
|
||||
|
||||
The argument msg_list_title contains a string for the list title, whereas
|
||||
the msg_list argument contains the actual list of message strings.
|
||||
max_msg_count limits the number of messages to be printed (set to negative
|
||||
number to print all messages).
|
||||
|
||||
Example:
|
||||
|
||||
print_msg_list("### Tool Warnings", ["Message A", "Message B"], 10)
|
||||
'''
|
||||
md_results = ""
|
||||
if msg_list:
|
||||
md_results += msg_list_title + "\n"
|
||||
md_results += "```\n"
|
||||
for k, msg in enumerate(msg_list):
|
||||
if k <= max_msg_count or max_msg_count < 0:
|
||||
md_results += msg + "\n\n"
|
||||
else:
|
||||
md_results += "Note: %d more messages have been suppressed (max_msg_count = %d) \n\n" % (
|
||||
len(msg_list) - max_msg_count, max_msg_count)
|
||||
break
|
||||
md_results += "```\n"
|
||||
return md_results
|
||||
|
|
1
vendor/lowrisc_ip/lint/Makefile
vendored
1
vendor/lowrisc_ip/lint/Makefile
vendored
|
@ -17,6 +17,7 @@ REPORT_DIR ?= reports
|
|||
IPS ?= ip-aes \
|
||||
ip-alert_handler \
|
||||
ip-clkmgr \
|
||||
ip-entropy_src \
|
||||
ip-flash_ctrl \
|
||||
ip-gpio \
|
||||
ip-hmac \
|
||||
|
|
|
@ -111,7 +111,7 @@ def main():
|
|||
# lint infos do not count as failures
|
||||
nr_errors = len(results["errors"]) + len(results["lint_errors"])
|
||||
nr_warnings = len(results["warnings"]) + len(results["lint_warnings"])
|
||||
if nr_errors > 0 and nr_warnings > 0:
|
||||
if nr_errors > 0 or nr_warnings > 0:
|
||||
print("Lint not successful, got %d warnings and %d errors." %
|
||||
(nr_warnings, nr_errors))
|
||||
sys.exit(1)
|
||||
|
|
|
@ -118,7 +118,7 @@ def main():
|
|||
nr_warnings = len(results["warnings"]) + len(results["lint_warnings"])
|
||||
print("Lint not successful, got %d warnings and %d errors." %
|
||||
(nr_warnings, nr_errors))
|
||||
if nr_errors > 0 and nr_warnings > 0:
|
||||
if nr_errors > 0 or nr_warnings > 0:
|
||||
sys.exit(1)
|
||||
sys.exit(0)
|
||||
|
||||
|
|
|
@ -4,3 +4,8 @@
|
|||
//
|
||||
// common waiver rules for verilator
|
||||
|
||||
`verilator_config
|
||||
|
||||
// Do not warn about unconnected pins in module instantiations, e.g.
|
||||
// `.optional_output ()`.
|
||||
lint_off -rule PINCONNECTEMPTY
|
||||
|
|
42
vendor/lowrisc_ip/prim/doc/prim_prince.md
vendored
42
vendor/lowrisc_ip/prim/doc/prim_prince.md
vendored
|
@ -5,7 +5,7 @@ title: "Primitive Component: PRINCE Scrambler"
|
|||
# Overview
|
||||
|
||||
`prim_prince` is an (unhardened) implementation of the [64bit PRINCE block cipher](https://en.wikipedia.org/wiki/Prince_(cipher)).
|
||||
It is a fully unrolled combinational implementation with a configurable number of rounds.
|
||||
It is a fully unrolled combinational implementation with a configurable number of rounds (data and key state registers placed half-way in the design can optionally be enabled).
|
||||
Due to the mirrored construction of this cipher, the same circuit can be used for encryption and decryption, as described below.
|
||||
Further, the primitive supports a 32bit block cipher flavor which is not specified in the original paper.
|
||||
|
||||
|
@ -22,35 +22,47 @@ DataWidth | int | Block size, can be 32 or 64.
|
|||
KeyWidth | int | Key size, can be 64 for block size 32, or 128 for block size 64
|
||||
NumRounds | int | Half the number of the reflected PRINCE rounds. Can range from 1 to 5. The effective number of non-linear layers is 2 + 2 * NumRounds.
|
||||
UseOldKeySched | bit | If set to 1, fall back to the original keyschedule (not recommended). Defaults to 0.
|
||||
HalfwayDataReg | bit | If set to 1, instantiates a data register half-way in the data path
|
||||
HalfwayKeyReg | bit | If set to 1, instantiates a key register half-way in the data path. This is only required if the key is not static and changes with every new data input.
|
||||
|
||||
## Signal Interfaces
|
||||
|
||||
Name | In/Out | Description
|
||||
-------------|--------|---------------------------------
|
||||
clk_i | input | Clock input
|
||||
rst_ni | input | Reset input
|
||||
valid_i | input | Data valid input
|
||||
data_i | input | Plaintext input
|
||||
data_i | input | Plaintext input
|
||||
key_i | input | Key input
|
||||
dec_i | input | Assert for decryption
|
||||
valid_o | output | Data valid output
|
||||
data_o | output | Output of the ciphertext
|
||||
|
||||
# Theory of Operations
|
||||
|
||||
```
|
||||
/----------------\
|
||||
dec_i | |
|
||||
------------>| PRINCE |
|
||||
key_i | |
|
||||
=====/======>| DataWidth |
|
||||
[KeyWidth] | KeyWidth |
|
||||
| NumRounds |
|
||||
data_i | UseOldKeySched | data_o
|
||||
=====/======>| |=====/=======>
|
||||
[DataWidth] | | [DataWidth]
|
||||
| |
|
||||
\----------------/
|
||||
/-----------------\
|
||||
clk_i / rst_ni | |
|
||||
-------------->| |
|
||||
dec_i | |
|
||||
-------------->| PRINCE |
|
||||
valid_i | | valid_o
|
||||
-------------->| DataWidth |--------------->
|
||||
key_i | KeyWidth |
|
||||
=====/========>| NumRounds |
|
||||
[KeyWidth] | UseOldKeySched | data_o
|
||||
| HalfwayDataReg |=======/=======>
|
||||
data_i | HalfwayKeyReg | [DataWidth]
|
||||
=====/========>| |
|
||||
[DataWidth] | |
|
||||
| |
|
||||
\-----------------/
|
||||
```
|
||||
|
||||
The PRINCE module is fully unrolled and combinational, meaning that it does not have any clock, reset or handshaking inputs.
|
||||
The only inputs are the key and the plaintext, and the only output is the ciphertext.
|
||||
The PRINCE module is fully unrolled and combinational by default.
|
||||
But since data and key state registers can optionally be enabled, the primitive also has a clock, reset and valid input besides the key and plaintext inputs.
|
||||
On the output side it exposes the ciphertext with its corresponding valid signal.
|
||||
|
||||
The internal construction follows the the algorithm described in the original [paper](https://eprint.iacr.org/2012/529.pdf).
|
||||
The block size is 64bit and the key size is 128bit.
|
||||
|
|
|
@ -43,4 +43,4 @@ endif
|
|||
# Include the tool Makefile below #
|
||||
# Dont add anything else below it! #
|
||||
####################################
|
||||
include ${DV_DIR}/../../../dv/tools/Makefile
|
||||
include ${DV_DIR}/../../../../dv/tools/Makefile
|
27
vendor/lowrisc_ip/prim/dv/prim_present/crypto_dpi_present/boxes.inc
vendored
Normal file
27
vendor/lowrisc_ip/prim/dv/prim_present/crypto_dpi_present/boxes.inc
vendored
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* S-Boxes and P-Boxes for
|
||||
* Implementation of PRESENT in C
|
||||
* v2.1, 10/13/2008
|
||||
*
|
||||
* Implementation is located at http://www.lightweightcrypto.org/implementations.php,
|
||||
* under the title "Testvectors for PRESENT".
|
||||
*
|
||||
* Thomas Siebert, thomas.siebert@rub.de
|
||||
*/
|
||||
|
||||
const uint8_t Sbox[16] = {12, 5, 6, 11, 9, 0, 10, 13, 3, 14, 15, 8, 4, 7, 1, 2};
|
||||
|
||||
const uint8_t SboxInv[16] = {5, 14, 15, 8, 12, 1, 2, 13,
|
||||
11, 4, 6, 3, 0, 7, 9, 10};
|
||||
|
||||
const uint8_t PboxInv[64] = {0, 16, 32, 48, 1, 17, 33, 49, 2, 18, 34, 50, 3,
|
||||
19, 35, 51, 4, 20, 36, 52, 5, 21, 37, 53, 6, 22,
|
||||
38, 54, 7, 23, 39, 55, 8, 24, 40, 56, 9, 25, 41,
|
||||
57, 10, 26, 42, 58, 11, 27, 43, 59, 12, 28, 44, 60,
|
||||
13, 29, 45, 61, 14, 30, 46, 62, 15, 31, 47, 63};
|
||||
|
||||
const uint8_t Pbox[64] = {0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48,
|
||||
52, 56, 60, 1, 5, 9, 13, 17, 21, 25, 29, 33, 37,
|
||||
41, 45, 49, 53, 57, 61, 2, 6, 10, 14, 18, 22, 26,
|
||||
30, 34, 38, 42, 46, 50, 54, 58, 62, 3, 7, 11, 15,
|
||||
19, 23, 27, 31, 35, 39, 43, 47, 51, 55, 59, 63};
|
196
vendor/lowrisc_ip/prim/dv/prim_present/crypto_dpi_present/comline.inc
vendored
Normal file
196
vendor/lowrisc_ip/prim/dv/prim_present/crypto_dpi_present/comline.inc
vendored
Normal file
|
@ -0,0 +1,196 @@
|
|||
/*
|
||||
* Commandline-Option-Fetcher for
|
||||
* Implementation of PRESENT in C
|
||||
* v2.1, 10/13/2008
|
||||
*
|
||||
* Implementation is located at http://www.lightweightcrypto.org/implementations.php,
|
||||
* under the title "Testvectors for PRESENT".
|
||||
*
|
||||
* Thomas Siebert, thomas.siebert@rub.de
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
|
||||
//----------------------------------
|
||||
// Function prototype
|
||||
//----------------------------------
|
||||
// void comline_fetch_options( struct Options * , int , char ** );
|
||||
|
||||
//----------------------------------
|
||||
// Struct declaration
|
||||
//----------------------------------
|
||||
struct Options {
|
||||
_Bool Error;
|
||||
_Bool Mode;
|
||||
_Bool KeySize80;
|
||||
uint8_t Verbose;
|
||||
uint64_t KeyHigh;
|
||||
uint64_t KeyLow;
|
||||
uint64_t Text;
|
||||
uint16_t Rounds;
|
||||
};
|
||||
|
||||
#define Encrypt_Mode 1
|
||||
#define Decrypt_Mode 0
|
||||
|
||||
//----------------------------------
|
||||
// Functions
|
||||
//----------------------------------
|
||||
void comline_fetch_options(struct Options *sOpt, int argc, char **const argv) {
|
||||
int c;
|
||||
_Bool Opt_Decrypt = 0, Opt_Encrypt = 0, Opt_File = 0, Opt_Verbose = 0;
|
||||
char *Opt_Text = NULL, *Opt_Key = NULL, *Opt_Rounds = NULL;
|
||||
FILE *KeyFile = NULL, *TextFile = NULL;
|
||||
int keyres;
|
||||
|
||||
sOpt->Error = 0;
|
||||
sOpt->Verbose = 1;
|
||||
|
||||
while ((c = getopt(argc, argv, "defv:r:k:t:")) !=
|
||||
-1) // Cycle through Options
|
||||
{
|
||||
switch (c) // set flags
|
||||
{
|
||||
case 'd':
|
||||
if (Opt_Encrypt || Opt_Decrypt)
|
||||
sOpt->Error = 1;
|
||||
else
|
||||
Opt_Decrypt = 1;
|
||||
break;
|
||||
case 'e':
|
||||
if (Opt_Encrypt || Opt_Decrypt)
|
||||
sOpt->Error = 1;
|
||||
else
|
||||
Opt_Encrypt = 1;
|
||||
break;
|
||||
case 'f':
|
||||
if (Opt_File)
|
||||
sOpt->Error = 1;
|
||||
else
|
||||
Opt_File = 1;
|
||||
break;
|
||||
case 'v':
|
||||
if (Opt_Verbose)
|
||||
sOpt->Error = 1;
|
||||
else if (optarg != NULL) {
|
||||
if (strcmp(optarg, "0") == 0)
|
||||
sOpt->Verbose = 0;
|
||||
else if (strcmp(optarg, "1") == 0)
|
||||
sOpt->Verbose = 1;
|
||||
else if (strcmp(optarg, "2") == 0)
|
||||
sOpt->Verbose = 2;
|
||||
else
|
||||
sOpt->Error = 1;
|
||||
} else
|
||||
sOpt->Error = 1;
|
||||
Opt_Verbose = 1;
|
||||
break;
|
||||
case 'k':
|
||||
if (Opt_Key != NULL)
|
||||
sOpt->Error = 1;
|
||||
else
|
||||
Opt_Key = optarg;
|
||||
break;
|
||||
case 'r':
|
||||
if (Opt_Rounds)
|
||||
sOpt->Error = 1;
|
||||
else
|
||||
Opt_Rounds = optarg;
|
||||
break;
|
||||
case 't':
|
||||
if (Opt_Text != NULL)
|
||||
sOpt->Error = 1;
|
||||
else
|
||||
Opt_Text = optarg;
|
||||
break;
|
||||
case '?':
|
||||
sOpt->Error = 1;
|
||||
break;
|
||||
}
|
||||
} // End Option-Cycle
|
||||
|
||||
// Set Error if Parameters missing
|
||||
if (Opt_Key == NULL || Opt_Text == NULL || (!(Opt_Decrypt || Opt_Encrypt))) {
|
||||
sOpt->Error = 1;
|
||||
}
|
||||
|
||||
else {
|
||||
// Handle Rounds Parameter
|
||||
if (Opt_Rounds != NULL) // if Round Param there...
|
||||
{
|
||||
if (strlen(Opt_Rounds) < 6) // check length
|
||||
{
|
||||
uint32_t Rounds;
|
||||
sscanf(Opt_Rounds, "%5" SCNu32 "", &Rounds); // get round no.
|
||||
if ((Rounds > 65534) || Rounds == 0)
|
||||
sOpt->Error = 1; // check 0<Rounds<65535
|
||||
else
|
||||
sOpt->Rounds = Rounds; // override roundno.
|
||||
} else
|
||||
sOpt->Error = 1;
|
||||
} else
|
||||
sOpt->Rounds = 32; //...else use standard
|
||||
|
||||
// Check if decrypt or encrypt mode
|
||||
if (Opt_Encrypt)
|
||||
sOpt->Mode = Encrypt_Mode;
|
||||
else
|
||||
sOpt->Mode = Decrypt_Mode;
|
||||
|
||||
// Read key and text (file mode)
|
||||
if (Opt_File) {
|
||||
KeyFile = fopen(Opt_Key, "r");
|
||||
TextFile = fopen(Opt_Text, "r");
|
||||
|
||||
if (!((KeyFile == NULL) || (TextFile) == NULL)) {
|
||||
fseek(KeyFile, 0, SEEK_END);
|
||||
if ((ftell(KeyFile)) >= 32) {
|
||||
fseek(KeyFile, 0, SEEK_SET);
|
||||
if (fscanf(KeyFile, "%016" SCNx64 "", &sOpt->KeyHigh) == 0)
|
||||
sOpt->Error = 1;
|
||||
if (fscanf(KeyFile, "%016" SCNx64 "", &sOpt->KeyLow) == 0)
|
||||
sOpt->Error = 1;
|
||||
sOpt->KeySize80 = 0;
|
||||
} else if ((ftell(KeyFile)) >= 20) {
|
||||
fseek(KeyFile, 0, SEEK_SET);
|
||||
if (fscanf(KeyFile, "%016" SCNx64 "", &sOpt->KeyHigh) == 0)
|
||||
sOpt->Error = 1;
|
||||
if (fscanf(KeyFile, "%04" SCNx16 "", &sOpt->KeyLow) == 0)
|
||||
sOpt->Error = 1;
|
||||
sOpt->KeySize80 = 1;
|
||||
} else
|
||||
sOpt->Error = 1;
|
||||
if (fscanf(TextFile, "%016" SCNx64 "", &sOpt->Text) == EOF)
|
||||
sOpt->Error = 1;
|
||||
} else
|
||||
sOpt->Error = 1;
|
||||
if (!(KeyFile == NULL))
|
||||
fclose(KeyFile);
|
||||
if (!(TextFile == NULL))
|
||||
fclose(TextFile);
|
||||
}
|
||||
|
||||
// Read key and text (commandline mode)
|
||||
else {
|
||||
if (((strlen(Opt_Key) != 32) && (strlen(Opt_Key) != 20)) ||
|
||||
(strlen(Opt_Text) != 16)) { // if wrong length...
|
||||
sOpt->Error = 1; // set error
|
||||
}
|
||||
|
||||
if (!(sOpt->Error)) // if no error...
|
||||
{
|
||||
sscanf(Opt_Key, "%016" SCNx64 "", &sOpt->KeyHigh); // get values
|
||||
if (strlen(Opt_Key) == 20) // set key + size
|
||||
{
|
||||
sOpt->KeySize80 = 1;
|
||||
sscanf(Opt_Key + 16, "%016" SCNx16 "", &sOpt->KeyLow);
|
||||
} else {
|
||||
sOpt->KeySize80 = 0;
|
||||
sscanf(Opt_Key + 16, "%016" SCNx64 "", &sOpt->KeyLow);
|
||||
}
|
||||
sscanf(Opt_Text, "%016" SCNx64 "", &sOpt->Text);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
64
vendor/lowrisc_ip/prim/dv/prim_present/crypto_dpi_present/crypto_dpi_present.c
vendored
Normal file
64
vendor/lowrisc_ip/prim/dv/prim_present/crypto_dpi_present/crypto_dpi_present.c
vendored
Normal file
|
@ -0,0 +1,64 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#include "present.inc"
|
||||
#include "svdpi.h"
|
||||
|
||||
typedef unsigned long long int ull_t;
|
||||
|
||||
// Helper function used only by this C file.
|
||||
// Returns the key schedule corresponding to the input key.
|
||||
uint64_t *get_key_schedule(uint64_t key_high, uint64_t key_low,
|
||||
uint8_t num_rounds, uint8_t key_size_80) {
|
||||
return key_schedule(key_high, key_low, num_rounds, (_Bool)key_size_80, 0);
|
||||
}
|
||||
|
||||
extern void c_dpi_key_schedule(uint64_t key_high, uint64_t key_low,
|
||||
uint8_t num_rounds, uint8_t key_size_80,
|
||||
svBitVecVal *key_array) {
|
||||
uint64_t *key_schedule = (uint64_t *)malloc(num_rounds * sizeof(uint64_t));
|
||||
uint64_t key;
|
||||
svBitVecVal key_hi;
|
||||
svBitVecVal key_lo;
|
||||
|
||||
// get the key schedule from the C model
|
||||
key_schedule = get_key_schedule(key_high, key_low, num_rounds, key_size_80);
|
||||
|
||||
// write the key schedule to simulation
|
||||
int i;
|
||||
for (i = 0; i < num_rounds; i++) {
|
||||
key = key_schedule[i];
|
||||
key_hi = (svBitVecVal)(key >> 32);
|
||||
key_lo = (svBitVecVal)(key & 0xFFFFFFFF);
|
||||
key_array[i * 2] = key_lo;
|
||||
key_array[i * 2 + 1] = key_hi;
|
||||
}
|
||||
|
||||
// free allocated memory
|
||||
free(key_schedule);
|
||||
}
|
||||
|
||||
extern uint64_t c_dpi_encrypt(uint64_t plaintext, uint64_t key_high,
|
||||
uint64_t key_low, uint8_t num_rounds,
|
||||
uint8_t key_size_80) {
|
||||
uint64_t encrypt_result;
|
||||
uint64_t *key_schedule = (uint64_t *)malloc(num_rounds * sizeof(uint64_t));
|
||||
|
||||
key_schedule = get_key_schedule(key_high, key_low, num_rounds, key_size_80);
|
||||
encrypt_result = (uint64_t)encrypt(plaintext, key_schedule, num_rounds, 0);
|
||||
free(key_schedule);
|
||||
return encrypt_result;
|
||||
}
|
||||
|
||||
extern uint64_t c_dpi_decrypt(uint64_t ciphertext, uint64_t key_high,
|
||||
uint64_t key_low, uint8_t num_rounds,
|
||||
uint8_t key_size_80) {
|
||||
uint64_t decrypt_result;
|
||||
uint64_t *key_schedule = (uint64_t *)malloc(sizeof(uint64_t));
|
||||
|
||||
key_schedule = get_key_schedule(key_high, key_low, num_rounds, key_size_80);
|
||||
decrypt_result = (uint64_t)decrypt(ciphertext, key_schedule, num_rounds, 0);
|
||||
free(key_schedule);
|
||||
return decrypt_result;
|
||||
}
|
21
vendor/lowrisc_ip/prim/dv/prim_present/crypto_dpi_present/crypto_dpi_present.core
vendored
Normal file
21
vendor/lowrisc_ip/prim/dv/prim_present/crypto_dpi_present/crypto_dpi_present.core
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
CAPI=2:
|
||||
# Copyright lowRISC contributors.
|
||||
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
name: "lowrisc:dv:crypto_dpi_present:0.1"
|
||||
description: "PRESENT block cipher reference implementation in C from Ruhr-University Bochum"
|
||||
filesets:
|
||||
files_dv:
|
||||
files:
|
||||
- boxes.inc: {file_type: cSource, is_include_file: true}
|
||||
- comline.inc: {file_type: cSource, is_include_file: true}
|
||||
- verbose.inc: {file_type: cSource, is_include_file: true}
|
||||
- present.inc: {file_type: cSource, is_include_file: true}
|
||||
- crypto_dpi_present.c: {file_type: cSource}
|
||||
- crypto_dpi_present_pkg.sv: {file_type: systemVerilogSource}
|
||||
file_type: cSource
|
||||
|
||||
targets:
|
||||
default:
|
||||
filesets:
|
||||
- files_dv
|
120
vendor/lowrisc_ip/prim/dv/prim_present/crypto_dpi_present/crypto_dpi_present_pkg.sv
vendored
Normal file
120
vendor/lowrisc_ip/prim/dv/prim_present/crypto_dpi_present/crypto_dpi_present_pkg.sv
vendored
Normal file
|
@ -0,0 +1,120 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package crypto_dpi_present_pkg;
|
||||
|
||||
// dep packages
|
||||
import uvm_pkg::*;
|
||||
|
||||
// parameters
|
||||
|
||||
// This is defined here so we can size all arrays properly.
|
||||
parameter int unsigned NumRounds = 31;
|
||||
|
||||
// DPI-C imports
|
||||
import "DPI-C" context function void c_dpi_key_schedule(
|
||||
input longint unsigned key_high,
|
||||
input longint unsigned key_low,
|
||||
input int unsigned num_rounds,
|
||||
input int unsigned key_size_80,
|
||||
output bit [NumRounds:0][63:0] key_schedule
|
||||
);
|
||||
|
||||
import "DPI-C" context function longint c_dpi_encrypt(
|
||||
input longint unsigned plaintext,
|
||||
input longint unsigned key_high,
|
||||
input longint unsigned key_low,
|
||||
input int unsigned num_rounds,
|
||||
input int unsigned key_size_80
|
||||
);
|
||||
|
||||
import "DPI-C" context function longint c_dpi_decrypt(
|
||||
input longint unsigned ciphertext,
|
||||
input longint unsigned key_high,
|
||||
input longint unsigned key_low,
|
||||
input int unsigned num_rounds,
|
||||
input int unsigned key_size_80
|
||||
);
|
||||
|
||||
// Helper Functions
|
||||
function automatic void get_keys(input bit [127:0] key,
|
||||
input bit key_size_80,
|
||||
output bit [63:0] key_high,
|
||||
output bit [63:0] key_low);
|
||||
key_high = (key_size_80) ? key[79:16] : key[127:64];
|
||||
key_low = (key_size_80) ? key[15:0] : key[63:0];
|
||||
endfunction
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// SV wrapper functions to be used by the testbench //
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
// This function takes in a 128 bit key by default, it determines how to
|
||||
// split this key for the DPI calls based on the value of key_size_80.
|
||||
//
|
||||
// This returns the list of round keys used during the course of the algorithm.
|
||||
function automatic void sv_dpi_present_get_key_schedule(
|
||||
input bit [127:0] key,
|
||||
input bit key_size_80,
|
||||
output bit [NumRounds:0][63:0] key_schedule
|
||||
);
|
||||
bit [63:0] key_high, key_low;
|
||||
bit [(NumRounds*2)+1:0][31:0] compressed_key_schedule;
|
||||
|
||||
get_keys(key, key_size_80, key_high, key_low);
|
||||
|
||||
c_dpi_key_schedule(key_high, key_low, NumRounds+1, key_size_80, compressed_key_schedule);
|
||||
|
||||
for (int i = 0; i < NumRounds+1; i++) begin
|
||||
key_schedule[i][31:0] = compressed_key_schedule[i*2];
|
||||
key_schedule[i][63:32] = compressed_key_schedule[i*2+1];
|
||||
end
|
||||
|
||||
endfunction
|
||||
|
||||
// This function encrypts the input plaintext with the PRESENT encryption
|
||||
// algorithm using the specified number of rounds.
|
||||
//
|
||||
// This produces a list of all intermediate values produced after each round
|
||||
// of the algorithm, including the final encrypted ciphertext value.
|
||||
function automatic void sv_dpi_present_encrypt(
|
||||
input bit [63:0] plaintext,
|
||||
input bit [127:0] key,
|
||||
input bit key_size_80,
|
||||
output bit [NumRounds-1:0][63:0] encrypted_values
|
||||
);
|
||||
|
||||
bit [63:0] key_high, key_low;
|
||||
|
||||
get_keys(key, key_size_80, key_high, key_low);
|
||||
|
||||
for (int i = 1; i <= NumRounds; i++) begin
|
||||
encrypted_values[i-1] = c_dpi_encrypt(plaintext, key_high, key_low, i+1, key_size_80);
|
||||
end
|
||||
|
||||
endfunction
|
||||
|
||||
// This function decrypts the input ciphertext with the PRESENT decryption
|
||||
// algorithm using the specified number of rounds.
|
||||
//
|
||||
// This produces a list of all intermediate values produced after each round
|
||||
// of the algorithm, including the final decrypted plaintext value.
|
||||
function automatic void sv_dpi_present_decrypt(
|
||||
input bit [NumRounds-1:0][63:0] ciphertext,
|
||||
input bit [127:0] key,
|
||||
input bit key_size_80,
|
||||
output bit [NumRounds-1:0][63:0] decrypted_values
|
||||
);
|
||||
|
||||
bit [63:0] key_high, key_low;
|
||||
|
||||
get_keys(key, key_size_80, key_high, key_low);
|
||||
|
||||
for (int i = 1; i <= NumRounds; i++) begin
|
||||
decrypted_values[i-1] = c_dpi_decrypt(ciphertext[i-1], key_high, key_low, i+1, key_size_80);
|
||||
end
|
||||
|
||||
endfunction
|
||||
|
||||
endpackage
|
396
vendor/lowrisc_ip/prim/dv/prim_present/crypto_dpi_present/present.inc
vendored
Normal file
396
vendor/lowrisc_ip/prim/dv/prim_present/crypto_dpi_present/present.inc
vendored
Normal file
|
@ -0,0 +1,396 @@
|
|||
/*
|
||||
* Implementation of PRESENT in C
|
||||
* v2.1, 10/13/2008
|
||||
*
|
||||
* Implementation is located at http://www.lightweightcrypto.org/implementations.php,
|
||||
* under the title "Testvectors for PRESENT".
|
||||
*
|
||||
* Thomas Siebert, thomas.siebert@rub.de
|
||||
*
|
||||
*
|
||||
* Your Compiler currently should support
|
||||
* the ANSI-C99-standard.
|
||||
*
|
||||
* Tested with gcc (with Option -std=c99)
|
||||
*/
|
||||
|
||||
//----------------------------------
|
||||
// Includes
|
||||
//----------------------------------
|
||||
#include "verbose.inc" //For verbose output
|
||||
#include "comline.inc" //Command Line
|
||||
#include "boxes.inc" //S-Boxes and P-Boxes
|
||||
#include <stdlib.h>
|
||||
|
||||
//----------------------------------
|
||||
// Macros for bit manipulation
|
||||
//----------------------------------
|
||||
//returns...
|
||||
#define high45_64(h45in) ((uint64_t)h45in >> 9) // 45 msb as lsb
|
||||
#define high61_64(h4in) ((uint64_t)h4in >> 3) // 61 msb as lsb
|
||||
#define high4_64(h4in) ((uint64_t)h4in >> 60) // 4 msb as lsb
|
||||
#define high8to4_64(h8in) (((uint64_t)h8in >> 56) & 0x0F) // 4 msb as 2. lsb
|
||||
#define high16_64(h16in) ((uint64_t)h16in >> 48) // 16 msb as lsb
|
||||
#define high1_64(h1in) ((uint64_t)h1in >> 63) // msb as lsb
|
||||
#define low4_64(l4in) ((uint64_t)l4in << 60) // 4 lsb as msb
|
||||
#define low8to4_64(l4in) ((uint64_t)l4in << 56) // 4 lsb as 2. msb
|
||||
#define low16_64(l4in) ((uint64_t)l4in << 48) // 4 lsb as msb
|
||||
#define rotate1l_64(r1lin) \
|
||||
(high1_64(r1lin) | (r1lin << 1)) // input rotated left (1x)
|
||||
#define rotate1r_64(r1rin) \
|
||||
(high1_64(r1rin) | (r1rin >> 1)) // input rotated right (1x)
|
||||
#define rotate4l_64(r4lin) \
|
||||
(high4_64(r4lin) | (r4lin << 4)) // input rotated left (4x)
|
||||
#define rotate4r_64(r4rin) \
|
||||
(high4_64(r4rin) | (r4rin >> 4)) // input rotated right (4x)
|
||||
|
||||
//----------------------------------
|
||||
// Function prototypes
|
||||
//----------------------------------
|
||||
uint64_t encrypt(uint64_t, uint64_t *, uint16_t, _Bool);
|
||||
uint64_t decrypt(uint64_t, uint64_t *, uint16_t, _Bool);
|
||||
uint64_t *key_schedule(uint64_t, uint64_t, uint16_t, _Bool, _Bool);
|
||||
|
||||
// We have commented out the main(...) function of the C model as the testbench is directly
|
||||
// calling encrypt(), decrypt(), and key_schedule() functions.
|
||||
// It also contains unnecessary command line parsing functionality that is not needed for
|
||||
// the testbench.
|
||||
//
|
||||
//----------------------------------
|
||||
// Start of code
|
||||
//----------------------------------
|
||||
// int main( int argc, char ** const argv )
|
||||
//{
|
||||
// // Initialize variables
|
||||
// uint64_t result;
|
||||
// struct Options Opt;
|
||||
//
|
||||
// // Get Commandline Options
|
||||
// comline_fetch_options( &Opt, argc, argv );
|
||||
//
|
||||
// // Banner
|
||||
// if ( Opt.Verbose != 0 )
|
||||
// {
|
||||
// printf( "---------------------------------------\n" );
|
||||
// printf( "PRESENT Commandline Tool v2.1\n" );
|
||||
// printf( "Thomas Siebert, thomas.siebert@rub.de\n" );
|
||||
// printf( "---------------------------------------\n\n" );
|
||||
// }
|
||||
//
|
||||
// if ( !Opt.Error )
|
||||
// {
|
||||
// uint64_t *subkey;
|
||||
//
|
||||
// if ( Opt.Mode == Encrypt_Mode )
|
||||
// {
|
||||
// // Put out Values
|
||||
// if ( Opt.Verbose != 0 )
|
||||
// {
|
||||
// printf( "Starting values\n" );
|
||||
// printf( "Plaintext: %016"PRIx64" \n", Opt.Text);
|
||||
// if (Opt.KeySize80) printf( "Given Key (80bit):
|
||||
//%016"PRIx64" %04"PRIx64"\n\n", Opt.KeyHigh, (Opt.KeyLow&0xFFFF) ); else
|
||||
//printf( "Given Key (128bit): %016"PRIx64" %016"PRIx64"\n\n", Opt.KeyHigh,
|
||||
//Opt.KeyLow );
|
||||
// }
|
||||
//
|
||||
// // Generate Subkeys
|
||||
// subkey=key_schedule( Opt.KeyHigh, Opt.KeyLow, Opt.Rounds,
|
||||
//Opt.KeySize80, (Opt.Verbose>1) );
|
||||
//
|
||||
// // Start Encryption
|
||||
// if ( Opt.Verbose != 0 ) printf( "Starting
|
||||
//encryption...\n" ); result=encrypt(Opt.Text, subkey, Opt.Rounds,
|
||||
//(Opt.Verbose>1) ); if ( Opt.Verbose != 0 ) printf( "Resulting Cipher:
|
||||
//%016"PRIx64" \n\n", result); else printf( "%016"PRIx64"\n", result);
|
||||
// }
|
||||
//
|
||||
// else if ( Opt.Mode == Decrypt_Mode )
|
||||
// {
|
||||
// // Put out Values
|
||||
// if ( Opt.Verbose != 0 )
|
||||
// {
|
||||
// printf( "Starting values\n" );
|
||||
// printf( "Ciphertext: %016"PRIx64" \n",
|
||||
//Opt.Text); if (Opt.KeySize80) printf( "Given Key (80bit): %016"PRIx64"
|
||||
//%04"PRIx64"\n\n", Opt.KeyHigh, (Opt.KeyLow&0xFFFF) ); else printf( "Given Key
|
||||
//(128bit): %016"PRIx64" %016"PRIx64"\n\n", Opt.KeyHigh, Opt.KeyLow );
|
||||
// }
|
||||
//
|
||||
// // Generate Subkeys
|
||||
// subkey=key_schedule( Opt.KeyHigh, Opt.KeyLow, Opt.Rounds,
|
||||
//Opt.KeySize80, (Opt.Verbose>1) );
|
||||
//
|
||||
// // Start Decryption
|
||||
// if ( Opt.Verbose != 0 ) printf( "Starting
|
||||
//decryption...\n" ); result=decrypt(Opt.Text, subkey, Opt.Rounds,
|
||||
//(Opt.Verbose>1) ); if ( Opt.Verbose != 0 ) printf( "Resulting Plaintext:
|
||||
//%016"PRIx64" \n", result); else printf( "%016"PRIx64"\n", result);
|
||||
// }
|
||||
//
|
||||
// free(subkey);
|
||||
//
|
||||
// }
|
||||
//
|
||||
// else
|
||||
// {
|
||||
// // Put out Syntax
|
||||
// printf( "Syntax:\n");
|
||||
// printf( "PRESENT -d|e [-f] [-r rounds] [-v level] -k key -t
|
||||
//text\n\n"); printf( "Choose -d to decrypt, or -e to encrypt one block\n\n");
|
||||
// printf( "-f (optional): File input, see below\n");
|
||||
// printf( "-r rounds (optional): Change number of rounds (up
|
||||
//to 65534, standard is 32)\n"); printf( "-v level (optional): Specify verbose
|
||||
//level:\n"); printf( " 0 for result-output only\n"); printf( " 1 for output
|
||||
//of mode, input, result (standard)\n"); printf( " 2 for roundwise
|
||||
//output\n\n"); printf( "-k key: Key in hexadecimal (length: *EXACTLY* 20
|
||||
//chars(80bit)/32 chars(128bit))\n"); printf( "-t text: Text in hexadecimal
|
||||
//(length: *EXACTLY* 16 chars)\n"); printf( "If -f is set, key and text
|
||||
//represent files containing the values,\n"); printf( "otherwise they must be
|
||||
//passed directly via commandline.\n\n"); printf( "Returned Errorlevel: 0 if
|
||||
//successful, 1 if non-successful\n");
|
||||
// }
|
||||
// return Opt.Error;
|
||||
//}
|
||||
|
||||
//----------------------------------
|
||||
// Key Scheduling
|
||||
//----------------------------------
|
||||
uint64_t *key_schedule(uint64_t key_high, uint64_t key_low, uint16_t Rounds,
|
||||
_Bool KeySize80, _Bool Output) {
|
||||
uint64_t temp64;
|
||||
uint64_t i;
|
||||
|
||||
uint64_t *subkey = (uint64_t *)malloc(Rounds * sizeof(uint64_t));
|
||||
|
||||
if (subkey != NULL) {
|
||||
if (Output)
|
||||
v_key_start();
|
||||
|
||||
if (KeySize80) {
|
||||
key_low &= 0xFFFF;
|
||||
|
||||
if (Output)
|
||||
v_k80_init(key_high, key_low);
|
||||
|
||||
for (i = 0; i < Rounds; i++) {
|
||||
subkey[i] = key_high;
|
||||
|
||||
//----------------------------------
|
||||
// Shift
|
||||
//----------------------------------
|
||||
temp64 = key_high;
|
||||
key_high <<= 61;
|
||||
key_high |= (key_low << 45);
|
||||
key_high |= (temp64 >> 19);
|
||||
key_low = (temp64 >> 3) & 0xFFFF;
|
||||
|
||||
if (Output && (i + 2 <= Rounds))
|
||||
v_k80_shift(key_high, key_low);
|
||||
|
||||
//----------------------------------
|
||||
// S-Box
|
||||
//----------------------------------
|
||||
temp64 = high4_64(key_high); // get highest nibble
|
||||
key_high &= 0x0FFFFFFFFFFFFFFF; // kill highest nibble
|
||||
temp64 = Sbox[temp64];
|
||||
key_high |= low4_64(temp64); // put new value to highest nibble (sbox)
|
||||
|
||||
if (Output && (i + 2 <= Rounds))
|
||||
v_k80_sbox(key_high, key_low);
|
||||
|
||||
//----------------------------------
|
||||
// Round Salt
|
||||
//----------------------------------
|
||||
key_low ^= (((i + 1) & 0x01) << 15);
|
||||
key_high ^= ((i + 1) >> 1);
|
||||
|
||||
if (Output && (i + 2 <= Rounds))
|
||||
v_k80_round(key_high, key_low, i);
|
||||
}
|
||||
} else // 128 Bit
|
||||
{
|
||||
if (Output)
|
||||
v_k128_init(key_high, key_low);
|
||||
|
||||
for (i = 0; i < Rounds; i++) {
|
||||
subkey[i] = key_high;
|
||||
|
||||
//----------------------------------
|
||||
// Shift
|
||||
//----------------------------------
|
||||
temp64 = high61_64(key_high);
|
||||
key_high <<= 61;
|
||||
key_high |= high61_64(key_low);
|
||||
key_low <<= 61;
|
||||
key_low |= temp64;
|
||||
|
||||
if (Output && (i + 2 <= Rounds))
|
||||
v_k128_shift(key_high, key_low);
|
||||
|
||||
//----------------------------------
|
||||
// S-Box
|
||||
//----------------------------------
|
||||
temp64 = high4_64(key_high); // get highest nibble
|
||||
key_high &= 0x0FFFFFFFFFFFFFFF; // kill highest nibble
|
||||
temp64 = Sbox[temp64];
|
||||
key_high |= low4_64(temp64); // put new value to highest nibble (sbox)
|
||||
temp64 = high8to4_64(key_high); // get 2. highest nibble
|
||||
key_high &= 0xF0FFFFFFFFFFFFFF; // kill 2. highest nibble
|
||||
temp64 = Sbox[temp64];
|
||||
key_high |=
|
||||
low8to4_64(temp64); // put new value to 2. highest nibble (sbox)
|
||||
|
||||
if (Output && (i + 2 <= Rounds))
|
||||
v_k128_sbox(key_high, key_low);
|
||||
|
||||
//----------------------------------
|
||||
// Round Salt
|
||||
//----------------------------------
|
||||
key_low ^= (((i + 1) & 0x03) << 62); // add counter to lower key part
|
||||
key_high ^= ((i + 1) >> 2); // add counter to higher key part
|
||||
|
||||
if (Output && (i + 2 <= Rounds))
|
||||
v_k128_round(key_high, key_low, i);
|
||||
}
|
||||
}
|
||||
if (Output)
|
||||
v_final();
|
||||
} else {
|
||||
printf("RAM problem!\n");
|
||||
exit(0);
|
||||
}
|
||||
return subkey;
|
||||
}
|
||||
|
||||
//----------------------------------
|
||||
// Encryption
|
||||
//----------------------------------
|
||||
uint64_t encrypt(uint64_t in, uint64_t *subkey, uint16_t Rounds,
|
||||
_Bool Roundwise) { // Start encryption
|
||||
|
||||
#define out in
|
||||
uint16_t RoundNr;
|
||||
uint64_t text;
|
||||
|
||||
if (Roundwise)
|
||||
v_enc_start(in);
|
||||
|
||||
for (RoundNr = 1; RoundNr < Rounds; RoundNr++) { // Start "for"
|
||||
uint16_t temp;
|
||||
#define SboxNr temp
|
||||
#define PBit temp
|
||||
|
||||
if (Roundwise)
|
||||
v_roundstart(RoundNr, subkey[RoundNr - 1]);
|
||||
|
||||
//----------------------------------
|
||||
// Xor with roundkey
|
||||
//----------------------------------
|
||||
text = in ^ subkey[RoundNr - 1];
|
||||
|
||||
if (Roundwise)
|
||||
v_after_xor(text);
|
||||
|
||||
//----------------------------------
|
||||
// S-Boxes
|
||||
//----------------------------------
|
||||
for (SboxNr = 0; SboxNr < 16; SboxNr++) {
|
||||
uint16_t SboxVal;
|
||||
|
||||
SboxVal = text & 0x0F; // get lowest nibble
|
||||
text &= 0xFFFFFFFFFFFFFFF0; // kill lowest nibble
|
||||
text |= Sbox[SboxVal]; // put new value to lowest nibble (sbox)
|
||||
text = rotate4l_64(text); // next(rotate by one nibble)
|
||||
}
|
||||
|
||||
if (Roundwise)
|
||||
v_after_s(text);
|
||||
|
||||
//----------------------------------
|
||||
// P-Box
|
||||
//----------------------------------
|
||||
for (PBit = 0, out = 0; PBit < 64; PBit++) {
|
||||
out = rotate1l_64(out); // next(rotate by one bit)
|
||||
out |= ((text >> 63 - Pbox[PBit]) &
|
||||
1); // put new value to lowest bit (pbox)
|
||||
}
|
||||
|
||||
if (Roundwise)
|
||||
v_after_p(in);
|
||||
|
||||
} // End "for"
|
||||
|
||||
text = in ^ subkey[RoundNr - 1];
|
||||
|
||||
if (Roundwise)
|
||||
v_enc_final(text, subkey[RoundNr - 1]);
|
||||
|
||||
return text;
|
||||
|
||||
} // End encryption
|
||||
|
||||
//----------------------------------
|
||||
// Decryption
|
||||
//----------------------------------
|
||||
uint64_t decrypt(uint64_t in, uint64_t *subkey, uint16_t Rounds,
|
||||
_Bool Roundwise) { // Start decryption
|
||||
#define out in
|
||||
uint16_t RoundNr;
|
||||
uint64_t text;
|
||||
|
||||
if (Roundwise)
|
||||
v_dec_start(in);
|
||||
|
||||
for (RoundNr = 1; RoundNr <= Rounds; RoundNr++) { // Start "for"
|
||||
uint64_t key_temp;
|
||||
uint16_t temp;
|
||||
#define SboxNr temp
|
||||
#define PBit temp
|
||||
|
||||
if (Roundwise)
|
||||
v_roundstart(RoundNr, subkey[Rounds - RoundNr]);
|
||||
|
||||
//----------------------------------
|
||||
// Xor with roundkey
|
||||
//----------------------------------
|
||||
text = in ^ subkey[Rounds - RoundNr];
|
||||
|
||||
if (Roundwise)
|
||||
v_after_xor(text);
|
||||
|
||||
//----------------------------------
|
||||
// P-Box
|
||||
//----------------------------------
|
||||
for (PBit = 0, out = 0; PBit < 64; PBit++) {
|
||||
out = rotate1l_64(out); // next(rotate by one bit)
|
||||
out |= ((text >> 63 - PboxInv[PBit]) &
|
||||
1); // put new value to lowest bit (pbox)
|
||||
}
|
||||
|
||||
if (Roundwise)
|
||||
v_after_p(out);
|
||||
|
||||
//----------------------------------
|
||||
// S-Boxes
|
||||
//----------------------------------
|
||||
for (SboxNr = 0; SboxNr < 16; SboxNr++) {
|
||||
uint16_t SboxVal;
|
||||
|
||||
SboxVal = out & 0x0F;
|
||||
out &= 0xFFFFFFFFFFFFFFF0;
|
||||
out |= SboxInv[SboxVal];
|
||||
out = rotate4l_64(out);
|
||||
}
|
||||
|
||||
if (Roundwise)
|
||||
v_after_s(out);
|
||||
|
||||
} // End "for"
|
||||
|
||||
if (Roundwise)
|
||||
v_final();
|
||||
|
||||
return text;
|
||||
|
||||
} // End decryption
|
125
vendor/lowrisc_ip/prim/dv/prim_present/crypto_dpi_present/verbose.inc
vendored
Normal file
125
vendor/lowrisc_ip/prim/dv/prim_present/crypto_dpi_present/verbose.inc
vendored
Normal file
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* Verbose-Functions for
|
||||
* Implementation of PRESENT in C
|
||||
* v2.1, 10/13/2008
|
||||
*
|
||||
* Implementation is located at http://www.lightweightcrypto.org/implementations.php,
|
||||
* under the title "Testvectors for PRESENT".
|
||||
*
|
||||
* Thomas Siebert, thomas.siebert@rub.de
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
//----------------------------------
|
||||
// Function prototypes
|
||||
//----------------------------------
|
||||
void v_enc_start(uint64_t);
|
||||
void v_enc_final(uint64_t, uint64_t);
|
||||
void v_dec_start(uint64_t);
|
||||
void v_roundstart(uint16_t, uint64_t);
|
||||
void v_after_xor(uint64_t);
|
||||
void v_after_s(uint64_t);
|
||||
void v_after_p(uint64_t);
|
||||
void v_final(void);
|
||||
void v_k80_init(uint64_t, uint64_t);
|
||||
void v_k80_shift(uint64_t, uint64_t);
|
||||
void v_k80_sbox(uint64_t, uint64_t);
|
||||
void v_k80_round(uint64_t, uint64_t, uint16_t);
|
||||
void v_k128_init(uint64_t, uint64_t);
|
||||
void v_k128_shift(uint64_t, uint64_t);
|
||||
void v_k128_sbox(uint64_t, uint64_t);
|
||||
void v_k128_round(uint64_t, uint64_t, uint16_t);
|
||||
void v_key_start(void);
|
||||
|
||||
//----------------------------------
|
||||
// Functions
|
||||
//----------------------------------
|
||||
void v_enc_start(uint64_t v_plain) {
|
||||
printf("************************************\n");
|
||||
printf("Verbose output of PRESENT-encryption\n");
|
||||
printf("************************************\n\n");
|
||||
printf("Given Plaintext: %016" PRIx64 " \n\n", v_plain);
|
||||
}
|
||||
|
||||
void v_dec_start(uint64_t v_plain) {
|
||||
printf("************************************\n");
|
||||
printf("Verbose output of PRESENT-decryption\n");
|
||||
printf("************************************\n\n");
|
||||
printf("Given Ciphertext: %016" PRIx64 " \n", v_plain);
|
||||
}
|
||||
|
||||
void v_roundstart(uint16_t v_round, uint64_t v_key) {
|
||||
printf("--------------------------------------\n");
|
||||
printf("Round %" PRIu16 "\n", v_round);
|
||||
printf("Subkey: %016" PRIx64 "\n\n", v_key);
|
||||
printf("Text after...\n");
|
||||
}
|
||||
|
||||
void v_enc_final(uint64_t v_final_text, uint64_t v_key) {
|
||||
printf("--------------------------------------\n");
|
||||
printf("Final Round\n\n");
|
||||
printf("Subkey: %016" PRIx64 "\n", v_key);
|
||||
printf("Text: %016" PRIx64 " \n\n", v_final_text);
|
||||
v_final();
|
||||
}
|
||||
|
||||
void v_final(void) {
|
||||
printf("************************************\n");
|
||||
printf("End of verbose output\n");
|
||||
printf("************************************\n");
|
||||
}
|
||||
|
||||
void v_after_xor(uint64_t v_xor) {
|
||||
printf("...Key-Xor: %016" PRIx64 " \n", v_xor);
|
||||
}
|
||||
|
||||
void v_after_s(uint64_t v_s) { printf(".....S-Box: %016" PRIx64 " \n", v_s); }
|
||||
|
||||
void v_after_p(uint64_t v_p) { printf(".....P-Box: %016" PRIx64 " \n", v_p); }
|
||||
|
||||
void v_k128_init(uint64_t key_high, uint64_t key_low) {
|
||||
printf("Input: %016" PRIx64 " %016" PRIx64 "\n\n", key_high, key_low);
|
||||
printf("Subkey Round 1: >>%016" PRIx64 "<<\n\n", key_high);
|
||||
}
|
||||
|
||||
void v_k128_shift(uint64_t key_high, uint64_t key_low) {
|
||||
printf("...after Shift: %016" PRIx64 " %016" PRIx64 "\n", key_high, key_low);
|
||||
}
|
||||
|
||||
void v_k128_sbox(uint64_t key_high, uint64_t key_low) {
|
||||
printf("...after S-Box: %016" PRIx64 " %016" PRIx64 "\n", key_high, key_low);
|
||||
}
|
||||
|
||||
void v_k128_round(uint64_t key_high, uint64_t key_low, uint16_t i) {
|
||||
printf("Subkey Round %" PRIu16 " (after Salt): >>%016" PRIx64 "<< %016" PRIx64
|
||||
"\n\n",
|
||||
i + 2, key_high, key_low);
|
||||
}
|
||||
|
||||
void v_k80_init(uint64_t key_high, uint64_t key_low) {
|
||||
printf("Input: %016" PRIx64 " %04" PRIx64 "\n\n", key_high,
|
||||
(key_low & 0xFFFF));
|
||||
printf("Subkey Round 1: >>%016" PRIx64 "<<\n\n", key_high);
|
||||
}
|
||||
|
||||
void v_k80_shift(uint64_t key_high, uint64_t key_low) {
|
||||
printf("...after Shift: %016" PRIx64 " %04" PRIx64 "\n", key_high, key_low);
|
||||
}
|
||||
|
||||
void v_k80_sbox(uint64_t key_high, uint64_t key_low) {
|
||||
printf("...after S-Box: %016" PRIx64 " %04" PRIx64 "\n", key_high, key_low);
|
||||
}
|
||||
|
||||
void v_k80_round(uint64_t key_high, uint64_t key_low, uint16_t i) {
|
||||
printf("Subkey Round %" PRIu16 " (after Salt): >>%016" PRIx64 "<< %04" PRIx64
|
||||
"\n\n",
|
||||
i + 2, key_high, key_low);
|
||||
}
|
||||
void v_key_start(void) {
|
||||
printf("**************************************\n");
|
||||
printf("Verbose output of PRESENT-Key-Schedule\n");
|
||||
printf("**************************************\n\n");
|
||||
}
|
26
vendor/lowrisc_ip/prim/dv/prim_present/prim_present_sim.core
vendored
Normal file
26
vendor/lowrisc_ip/prim/dv/prim_present/prim_present_sim.core
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
CAPI=2:
|
||||
# Copyright lowRISC contributors.
|
||||
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
name: "lowrisc:dv:prim_present_sim:0.1"
|
||||
description: "PRESENT block cipher DV sim target"
|
||||
filesets:
|
||||
files_rtl:
|
||||
depend:
|
||||
- lowrisc:prim:all
|
||||
file_type: systemVerilogSource
|
||||
|
||||
files_dv:
|
||||
depend:
|
||||
- lowrisc:dv:crypto_dpi_present:0.1
|
||||
files:
|
||||
- tb/prim_present_tb.sv
|
||||
file_type: systemVerilogSource
|
||||
|
||||
targets:
|
||||
sim:
|
||||
toplevel: prim_present_tb
|
||||
filesets:
|
||||
- files_rtl
|
||||
- files_dv
|
||||
default_tool: vcs
|
61
vendor/lowrisc_ip/prim/dv/prim_present/prim_present_sim_cfg.hjson
vendored
Normal file
61
vendor/lowrisc_ip/prim/dv/prim_present/prim_present_sim_cfg.hjson
vendored
Normal file
|
@ -0,0 +1,61 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
{
|
||||
// Name of the sim cfg - typically same as the name of the DUT.
|
||||
name: prim_present
|
||||
|
||||
// Top level dut name (sv module).
|
||||
dut: prim_present
|
||||
|
||||
// Top level testbench name (sv module).
|
||||
tb: prim_present_tb
|
||||
|
||||
// Simulator used to sign off this block
|
||||
tool: vcs
|
||||
|
||||
// Fusesoc core file used for building the file list.
|
||||
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"
|
||||
|
||||
// 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: ""
|
||||
|
||||
// List of test specifications.
|
||||
tests: [
|
||||
{
|
||||
name: prim_present_sanity
|
||||
}
|
||||
]
|
||||
|
||||
// List of regressions.
|
||||
regressions: [
|
||||
{
|
||||
name: sanity
|
||||
tests: ["prim_present_sanity"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
14
vendor/lowrisc_ip/prim/dv/prim_present/prim_present_testplan.hjson
vendored
Normal file
14
vendor/lowrisc_ip/prim/dv/prim_present/prim_present_testplan.hjson
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
name: "prim_present"
|
||||
import_testplans: []
|
||||
entries: [
|
||||
{
|
||||
name: sanity
|
||||
desc: '''Simple PRESENT test - feed golden and random testvectors into
|
||||
both the encryption and decryption algorithms and verify that all
|
||||
outputs match those from the reference model.'''
|
||||
milestone: V2
|
||||
tests: ["prim_present_sanity"]
|
||||
}
|
||||
]
|
||||
}
|
243
vendor/lowrisc_ip/prim/dv/prim_present/tb/prim_present_tb.sv
vendored
Normal file
243
vendor/lowrisc_ip/prim/dv/prim_present/tb/prim_present_tb.sv
vendored
Normal file
|
@ -0,0 +1,243 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
// Testbench module for prim_present, drives various test vectors into all
|
||||
// implementations and compares intermediate and final output against
|
||||
// C-reference model, for both encryption and decryption.
|
||||
//
|
||||
// This testbench only tests the PRESENT block cipher in its 64-bit data
|
||||
// and 128-bit key configuration, other configurations with different sets of
|
||||
// widths remain untested.
|
||||
|
||||
module prim_present_tb;
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// config
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
// Default to {data_width:64, key_width:128} configuration.
|
||||
// Data width and key width can be overriden from command-line if desired.
|
||||
|
||||
`ifdef DATA_WIDTH
|
||||
localparam int unsigned DataWidth = `DATA_WIDTH;
|
||||
`else
|
||||
localparam int unsigned DataWidth = 64;
|
||||
`endif
|
||||
|
||||
`ifdef KEY_WIDTH
|
||||
localparam int unsigned KeyWidth = `KEY_WIDTH;
|
||||
`else
|
||||
localparam int unsigned KeyWidth = 128;
|
||||
`endif
|
||||
|
||||
// Max number of rounds according to spec.
|
||||
// We redefine this parameter here to avoid clutter from the long package identifier.
|
||||
localparam int unsigned NumRounds = crypto_dpi_present_pkg::NumRounds;
|
||||
|
||||
// used to index the data arrays
|
||||
localparam bit Encrypt = 1'b0;
|
||||
localparam bit Decrypt = 1'b1;
|
||||
|
||||
// this parameter is required for the DPI model.
|
||||
localparam KeySize80 = (KeyWidth == 80);
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// DUTs for both encryption and decryption
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
// data_in[0]: encryption, data_in[1]: decryption.
|
||||
// Same scheme used for key_in, data_out, key_out.
|
||||
logic [1:0][NumRounds-1:0][DataWidth-1:0] data_in;
|
||||
logic [1:0][NumRounds-1:0][KeyWidth-1 :0] key_in;
|
||||
logic [1:0][NumRounds-1:0][DataWidth-1:0] data_out;
|
||||
logic [1:0][NumRounds-1:0][KeyWidth-1 :0] key_out;
|
||||
|
||||
for (genvar j = 0; j < 2; j++) begin : gen_encrypt_decrypt
|
||||
for (genvar k = 0; k < NumRounds; k++) begin : gen_duts
|
||||
prim_present #(
|
||||
.DataWidth ( DataWidth ),
|
||||
.KeyWidth ( KeyWidth ),
|
||||
.NumRounds ( k+1 ),
|
||||
.Decrypt ( j )
|
||||
) dut (
|
||||
.data_i ( data_in[j][k] ),
|
||||
.key_i ( key_in[j][k] ),
|
||||
.data_o ( data_out[j][k] ),
|
||||
.key_o ( key_out[j][k] )
|
||||
);
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// API called by the testbench to drive/check stimulus
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
// Top level API task that should be called to run a full pass
|
||||
// of encryption and decryption on some input data and key.
|
||||
task test_present(bit [DataWidth-1:0] plaintext,
|
||||
bit [KeyWidth-1:0] key);
|
||||
|
||||
bit [NumRounds:0][63:0] key_schedule;
|
||||
bit [NumRounds-1:0][DataWidth-1:0] encrypted_text;
|
||||
|
||||
crypto_dpi_present_pkg::sv_dpi_present_get_key_schedule(key, KeySize80, key_schedule);
|
||||
|
||||
$display("Starting encryption pass with data[0x%0x] and key[0x%0x]!", plaintext, key);
|
||||
check_encryption(plaintext, key, key_schedule, encrypted_text);
|
||||
|
||||
$display("Starting decryption pass!");
|
||||
check_decryption(encrypted_text, key, key_out[Encrypt]);
|
||||
|
||||
endtask
|
||||
|
||||
|
||||
|
||||
// Helper task to drive plaintext and key into each encryption instance.
|
||||
// Calls a subroutine to perform checks on the outputs (once they are available).
|
||||
task check_encryption(input bit [DataWidth-1:0] plaintext,
|
||||
input bit [KeyWidth-1:0] key,
|
||||
input bit [NumRounds:0][63:0] key_schedule,
|
||||
output bit [NumRounds-1:0][DataWidth-1:0] expected_ciphertext);
|
||||
|
||||
// Drive input into encryption instances.
|
||||
for (int unsigned i = 0; i < NumRounds; i++) begin
|
||||
data_in[Encrypt][i] = plaintext;
|
||||
key_in[Encrypt][i] = key;
|
||||
end
|
||||
|
||||
// Wait a bit for the DUTs to finish calculations.
|
||||
#100ns;
|
||||
|
||||
// query DPI model for expected encrypted output.
|
||||
crypto_dpi_present_pkg::sv_dpi_present_encrypt(plaintext, key,
|
||||
KeySize80, expected_ciphertext);
|
||||
|
||||
check_output(key_schedule[NumRounds:1], expected_ciphertext,
|
||||
key_out[Encrypt], data_out[Encrypt], "Encryption");
|
||||
endtask
|
||||
|
||||
|
||||
// Helper task to drive ciphertext and key into each decryption instance.
|
||||
// Calls a subroutine to perform checks on the outputs (once they are available).
|
||||
task check_decryption(input bit [NumRounds-1:0][DataWidth-1:0] ciphertext,
|
||||
input bit [KeyWidth-1:0] key,
|
||||
input bit [NumRounds-1:0][KeyWidth-1:0] decryption_keys);
|
||||
|
||||
// the expected plaintext after decryption will be provided by the C model.
|
||||
bit [NumRounds-1:0][DataWidth-1:0] expected_plaintext;
|
||||
|
||||
// the expected key after decryption will simply be the original key.
|
||||
// the C model only provides a key schedule, which is not useful here.
|
||||
bit [NumRounds-1:0][63:0] expected_key;
|
||||
for (int i = 0; i < NumRounds; i++) begin
|
||||
expected_key[i] = key[KeyWidth-1:KeyWidth-64];
|
||||
end
|
||||
|
||||
// Drive input into decryption instances.
|
||||
data_in[Decrypt] = ciphertext;
|
||||
key_in[Decrypt] = decryption_keys;
|
||||
|
||||
// Wait a bit for the DUTs to finish calculations.
|
||||
#100ns;
|
||||
|
||||
// query DPI model for expected decrypted output.
|
||||
crypto_dpi_present_pkg::sv_dpi_present_decrypt(ciphertext, key, KeySize80, expected_plaintext);
|
||||
|
||||
check_output(expected_key, expected_plaintext,
|
||||
key_out[Decrypt], data_out[Decrypt], "Decryption");
|
||||
endtask
|
||||
|
||||
|
||||
// Helper subroutine to compare key and data output values from
|
||||
// the C-reference model and the DUTs.
|
||||
//
|
||||
// For each instance of PRESENT (whether encryption or decryption),
|
||||
// we need to perform two checks:
|
||||
// 1) Check that the output key matches the corresponding key in the schedule.
|
||||
// 2) Check that the output data matches the output of the reference model.
|
||||
//
|
||||
// If any comparison error is seen, this task short-circuits immediately,
|
||||
// printing out some debug information and the correct failure signature.
|
||||
task check_output(input bit [NumRounds-1:0][63:0] expected_key,
|
||||
input bit [NumRounds-1:0][DataWidth-1:0] expected_text,
|
||||
input bit [NumRounds-1:0][KeyWidth-1:0] actual_key,
|
||||
input bit [NumRounds-1:0][DataWidth-1:0] actual_data,
|
||||
input string msg);
|
||||
|
||||
bit error = 1'b0;
|
||||
|
||||
for (int unsigned i = 0; i < NumRounds; i++) begin
|
||||
// compare the output key to the corresponding key in the schedule.
|
||||
if (expected_key[i] != actual_key[i][KeyWidth-1:KeyWidth-64]) begin
|
||||
error = 1'b1;
|
||||
$error("%s output key mismatch at round %0d! Expected[0x%0x] - Actual[0x%0x]",
|
||||
msg, i, expected_key[i], actual_key[i][KeyWidth-1:KeyWidth-64]);
|
||||
break;
|
||||
end
|
||||
// compare encrypted output text to reference model
|
||||
if (expected_text[i] != actual_data[i]) begin
|
||||
error = 1'b1;
|
||||
$error("%s output text mismatch at round %0d! Expected[0x%0x] - Actual[0x%0x]",
|
||||
msg, i, expected_text[i], actual_data[i]);
|
||||
break;
|
||||
end
|
||||
end
|
||||
if (error) $fatal("TEST FAILED CHECKS");
|
||||
endtask
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// main testbench body
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
initial begin : p_stimuli
|
||||
|
||||
// The key and plaintext/ciphertext to be fed into PRESENT instances.
|
||||
bit [KeyWidth-1:0] key;
|
||||
bit [DataWidth-1:0] plaintext;
|
||||
|
||||
$timeformat(-12, 0, " ps", 12);
|
||||
|
||||
/////////////////////////////
|
||||
// Test the 4 golden vectors.
|
||||
/////////////////////////////
|
||||
|
||||
plaintext = '0;
|
||||
key = '0;
|
||||
test_present(plaintext, key);
|
||||
|
||||
plaintext = '0;
|
||||
key = '1;
|
||||
test_present(plaintext, key);
|
||||
|
||||
plaintext = '1;
|
||||
key = '0;
|
||||
test_present(plaintext, key);
|
||||
|
||||
plaintext = '1;
|
||||
key = '1;
|
||||
test_present(plaintext, key);
|
||||
|
||||
// Test random vectors
|
||||
for (int i = 0; i < 5000; i++) begin
|
||||
if (!std::randomize(plaintext)) begin
|
||||
$fatal("Randomization of plaintext failed!");
|
||||
end
|
||||
if (!std::randomize(key)) begin
|
||||
$fatal("Randomization of key failed!");
|
||||
end
|
||||
test_present(plaintext, key);
|
||||
end
|
||||
|
||||
|
||||
// Final error checking and print out the test signature (expected by simulation flow).
|
||||
$display("All encryption and decryption passes were successful!");
|
||||
$display("TEST PASSED CHECKS");
|
||||
$finish();
|
||||
end
|
||||
|
||||
|
||||
endmodule : prim_present_tb
|
|
@ -8,10 +8,7 @@ filesets:
|
|||
files_formal:
|
||||
depend:
|
||||
- lowrisc:prim:all
|
||||
# TODO: add more dependencies here if needed
|
||||
files:
|
||||
- vip/prim_arbiter_ppc_assert_fpv.sv
|
||||
- tb/prim_arbiter_ppc_bind_fpv.sv
|
||||
- tb/prim_arbiter_ppc_fpv.sv
|
||||
file_type: systemVerilogSource
|
||||
|
||||
|
|
|
@ -8,10 +8,7 @@ filesets:
|
|||
files_formal:
|
||||
depend:
|
||||
- lowrisc:prim:all
|
||||
# TODO: add more dependencies here if needed
|
||||
files:
|
||||
- vip/prim_arbiter_tree_assert_fpv.sv
|
||||
- tb/prim_arbiter_tree_bind_fpv.sv
|
||||
- tb/prim_arbiter_tree_fpv.sv
|
||||
file_type: systemVerilogSource
|
||||
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
module prim_arbiter_ppc_bind_fpv;
|
||||
|
||||
|
||||
bind prim_arbiter_ppc prim_arbiter_ppc_assert_fpv #(
|
||||
.N(N),
|
||||
.DW(DW)
|
||||
) i_prim_arbiter_ppc_assert_fpv (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.req_i,
|
||||
.data_i,
|
||||
.gnt_o,
|
||||
.idx_o,
|
||||
.valid_o,
|
||||
.data_o,
|
||||
.ready_i
|
||||
);
|
||||
|
||||
|
||||
endmodule : prim_arbiter_ppc_bind_fpv
|
|
@ -6,24 +6,31 @@
|
|||
// Intended to be used with a formal tool.
|
||||
|
||||
module prim_arbiter_ppc_fpv #(
|
||||
parameter int unsigned N = 4,
|
||||
parameter int unsigned DW = 32
|
||||
parameter int unsigned N = 8,
|
||||
parameter int unsigned DW = 32,
|
||||
parameter bit EnDataPort = 1,
|
||||
parameter bit EnReqStabA = 1,
|
||||
localparam int IdxW = $clog2(N)
|
||||
) (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
input [N-1:0] req_i,
|
||||
input [DW-1:0]data_i [N],
|
||||
output logic[N-1:0] gnt_o,
|
||||
output logic[$clog2(N)-1:0] idx_o,
|
||||
output logic valid_o,
|
||||
output logic[DW-1:0] data_o,
|
||||
input ready_i
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
|
||||
input [ N-1:0] req_i,
|
||||
input [DW-1:0] data_i [N],
|
||||
output logic [ N-1:0] gnt_o,
|
||||
output logic [IdxW-1:0] idx_o,
|
||||
|
||||
output logic valid_o,
|
||||
output logic [DW-1:0] data_o,
|
||||
input ready_i
|
||||
);
|
||||
|
||||
|
||||
prim_arbiter_ppc #(
|
||||
.N(N),
|
||||
.DW(DW)
|
||||
.DW(DW),
|
||||
.EnDataPort(EnDataPort),
|
||||
.EnReqStabA(EnReqStabA)
|
||||
) i_prim_arbiter_ppc (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
module prim_arbiter_tree_bind_fpv;
|
||||
|
||||
|
||||
bind prim_arbiter_tree prim_arbiter_tree_assert_fpv #(
|
||||
.N(N),
|
||||
.DW(DW),
|
||||
.Lock(Lock)
|
||||
) i_prim_arbiter_tree_assert_fpv (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.req_i,
|
||||
.data_i,
|
||||
.gnt_o,
|
||||
.idx_o,
|
||||
.valid_o,
|
||||
.data_o,
|
||||
.ready_i
|
||||
);
|
||||
|
||||
|
||||
endmodule : prim_arbiter_tree_bind_fpv
|
|
@ -6,25 +6,31 @@
|
|||
// Intended to be used with a formal tool.
|
||||
|
||||
module prim_arbiter_tree_fpv #(
|
||||
parameter int unsigned N = 4,
|
||||
parameter int unsigned DW = 32,
|
||||
parameter bit Lock = 1'b1
|
||||
parameter int N = 8,
|
||||
parameter int DW = 32,
|
||||
parameter bit EnDataPort = 1,
|
||||
parameter bit EnReqStabA = 1,
|
||||
localparam int IdxW = $clog2(N)
|
||||
) (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
input [N-1:0] req_i,
|
||||
input [DW-1:0]data_i [N],
|
||||
output logic[N-1:0] gnt_o,
|
||||
output logic[$clog2(N)-1:0] idx_o,
|
||||
output logic valid_o,
|
||||
output logic[DW-1:0] data_o,
|
||||
input ready_i
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
|
||||
input [ N-1:0] req_i,
|
||||
input [DW-1:0] data_i [N],
|
||||
output logic [ N-1:0] gnt_o,
|
||||
output logic [IdxW-1:0] idx_o,
|
||||
|
||||
output logic valid_o,
|
||||
output logic [DW-1:0] data_o,
|
||||
input ready_i
|
||||
);
|
||||
|
||||
|
||||
prim_arbiter_tree #(
|
||||
.N(N),
|
||||
.DW(DW),
|
||||
.Lock(Lock)
|
||||
.EnDataPort(EnDataPort),
|
||||
.EnReqStabA(EnReqStabA)
|
||||
) i_prim_arbiter_tree (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
|
@ -37,4 +43,5 @@ module prim_arbiter_tree_fpv #(
|
|||
.ready_i
|
||||
);
|
||||
|
||||
|
||||
endmodule : prim_arbiter_tree_fpv
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
// Assertions for prim_arbiter_ppc.
|
||||
// Intended to be used with a formal tool.
|
||||
|
||||
`include "prim_assert.sv"
|
||||
|
||||
module prim_arbiter_ppc_assert_fpv #(
|
||||
parameter int unsigned N = 4,
|
||||
parameter int unsigned DW = 32
|
||||
) (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
input [N-1:0] req_i,
|
||||
input [DW-1:0]data_i [N],
|
||||
input logic[N-1:0] gnt_o,
|
||||
input logic[$clog2(N)-1:0] idx_o,
|
||||
input logic valid_o,
|
||||
input logic[DW-1:0] data_o,
|
||||
input ready_i
|
||||
);
|
||||
|
||||
///////////////////////////////
|
||||
// Declarations & Parameters //
|
||||
///////////////////////////////
|
||||
|
||||
/////////////////
|
||||
// Assumptions //
|
||||
/////////////////
|
||||
|
||||
// `ASSUME(MyAssumption_M, ..., clk_i, !rst_ni)
|
||||
|
||||
////////////////////////
|
||||
// Forward Assertions //
|
||||
////////////////////////
|
||||
|
||||
// `ASSERT(MyFwdAssertion_A, ..., clk_i, !rst_ni)
|
||||
|
||||
/////////////////////////
|
||||
// Backward Assertions //
|
||||
/////////////////////////
|
||||
|
||||
// `ASSERT(MyBkwdAssertion_A, ..., clk_i, !rst_ni)
|
||||
|
||||
endmodule : prim_arbiter_ppc_assert_fpv
|
|
@ -1,48 +0,0 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
// Assertions for prim_arbiter_tree.
|
||||
// Intended to be used with a formal tool.
|
||||
|
||||
`include "prim_assert.sv"
|
||||
|
||||
module prim_arbiter_tree_assert_fpv #(
|
||||
parameter int unsigned N = 4,
|
||||
parameter int unsigned DW = 32,
|
||||
parameter bit Lock = 1'b1
|
||||
) (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
input [N-1:0] req_i,
|
||||
input [DW-1:0]data_i [N],
|
||||
input logic[N-1:0] gnt_o,
|
||||
input logic[$clog2(N)-1:0] idx_o,
|
||||
input logic valid_o,
|
||||
input logic[DW-1:0] data_o,
|
||||
input ready_i
|
||||
);
|
||||
|
||||
///////////////////////////////
|
||||
// Declarations & Parameters //
|
||||
///////////////////////////////
|
||||
|
||||
/////////////////
|
||||
// Assumptions //
|
||||
/////////////////
|
||||
|
||||
// `ASSUME(MyAssumption_M, ..., clk_i, !rst_ni)
|
||||
|
||||
////////////////////////
|
||||
// Forward Assertions //
|
||||
////////////////////////
|
||||
|
||||
// `ASSERT(MyFwdAssertion_A, ..., clk_i, !rst_ni)
|
||||
|
||||
/////////////////////////
|
||||
// Backward Assertions //
|
||||
/////////////////////////
|
||||
|
||||
// `ASSERT(MyBkwdAssertion_A, ..., clk_i, !rst_ni)
|
||||
|
||||
endmodule : prim_arbiter_tree_assert_fpv
|
12
vendor/lowrisc_ip/prim/lint/prim.vlt
vendored
12
vendor/lowrisc_ip/prim/lint/prim.vlt
vendored
|
@ -1,4 +1,14 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
`verilator_config
|
||||
|
||||
// prim_subreg
|
||||
// for RO wd is not used
|
||||
lint_off -rule UNUSED -file "*/rtl/prim_subreg.sv" -match "Signal is not used: 'wd'"
|
||||
|
||||
// prim_fifo_sync
|
||||
// In passthrough mode, clk and reset are not read form within this module
|
||||
lint_off -rule UNUSED -file "*/rtl/prim_fifo_sync.sv" -match "*clk_i*"
|
||||
lint_off -rule UNUSED -file "*/rtl/prim_fifo_sync.sv" -match "*rst_ni*"
|
||||
|
|
2
vendor/lowrisc_ip/prim/lint/prim.waiver
vendored
2
vendor/lowrisc_ip/prim/lint/prim.waiver
vendored
|
@ -57,7 +57,5 @@ waive -rules {HIER_BRANCH_NOT_READ} -location {tlul_fifo_sync.sv} -regexp {Conne
|
|||
|
||||
# primitivies: prim_ram_2p_wrapper
|
||||
#
|
||||
#waive -rules INPUT_NOT_READ -location {prim_ram_*_wrapper*} -regexp {cfg_i} \
|
||||
# -comment "Register model doesn't need config port"
|
||||
#waive -rules NOT_READ -location {prim_ram_*_wrapper*} -regexp {(a|b)_rdata_(q|d)\[38} \
|
||||
# -comment "Syndrome is not going out to the interface"
|
||||
|
|
|
@ -46,7 +46,6 @@ targets:
|
|||
- '-CFLAGS "-std=c++11 -Wall -DVM_TRACE_FMT_FST -DTOPLEVEL_NAME=prim_sync_reqack_tb -g -O0"'
|
||||
- '-LDFLAGS "-pthread -lutil -lelf"'
|
||||
- "-Wall"
|
||||
- "-Wno-PINCONNECTEMPTY"
|
||||
# XXX: Cleanup all warnings and remove this option
|
||||
# (or make it more fine-grained at least)
|
||||
- "-Wno-fatal"
|
||||
|
|
1
vendor/lowrisc_ip/prim/prim.core
vendored
1
vendor/lowrisc_ip/prim/prim.core
vendored
|
@ -10,6 +10,7 @@ filesets:
|
|||
files_rtl:
|
||||
depend:
|
||||
- lowrisc:prim:assert
|
||||
- lowrisc:prim:util
|
||||
- lowrisc:prim:diff_decode # for prim_alert_sender/receiver
|
||||
- lowrisc:prim:pad_wrapper
|
||||
- lowrisc:prim:prim_pkg
|
||||
|
|
3
vendor/lowrisc_ip/prim/prim_assert.core
vendored
3
vendor/lowrisc_ip/prim/prim_assert.core
vendored
|
@ -9,6 +9,9 @@ filesets:
|
|||
files_rtl:
|
||||
files:
|
||||
- rtl/prim_assert.sv : {is_include_file : true}
|
||||
- rtl/prim_assert_dummy_macros.svh : {is_include_file : true}
|
||||
- rtl/prim_assert_yosys_macros.svh : {is_include_file : true}
|
||||
- rtl/prim_assert_standard_macros.svh : {is_include_file : true}
|
||||
file_type: systemVerilogSource
|
||||
|
||||
targets:
|
||||
|
|
2
vendor/lowrisc_ip/prim/prim_util.core
vendored
2
vendor/lowrisc_ip/prim/prim_util.core
vendored
|
@ -8,7 +8,7 @@ description: "Utilities"
|
|||
filesets:
|
||||
files_rtl:
|
||||
files:
|
||||
- rtl/prim_util.svh : {is_include_file : true}
|
||||
- rtl/prim_util_pkg.sv
|
||||
file_type: systemVerilogSource
|
||||
|
||||
targets:
|
||||
|
|
135
vendor/lowrisc_ip/prim/rtl/prim_arbiter_ppc.sv
vendored
135
vendor/lowrisc_ip/prim/rtl/prim_arbiter_ppc.sv
vendored
|
@ -5,45 +5,51 @@
|
|||
// N:1 arbiter module
|
||||
//
|
||||
// Verilog parameter
|
||||
// N: Number of request ports
|
||||
// DW: Data width
|
||||
// N: Number of request ports
|
||||
// DW: Data width
|
||||
// DataPort: Set to 1 to enable the data port. Otherwise that port will be ignored.
|
||||
// EnReqStabA: Checks whether requests remain asserted until granted
|
||||
//
|
||||
// This is the original implementation of the arbiter which relies on parallel prefix
|
||||
// computing optimization to optimize the request / arbiter tree. Not all synthesis tools
|
||||
// may support this.
|
||||
// This is the original implementation of the arbiter which relies on parallel prefix computing
|
||||
// optimization to optimize the request / arbiter tree. Not all synthesis tools may support this.
|
||||
//
|
||||
// Note that the currently winning request is held if the data sink is not ready.
|
||||
// This behavior is required by some interconnect protocols (AXI, TL). Note that
|
||||
// this implies that an asserted request must stay asserted
|
||||
// until it has been granted. Note that for PPC, this option cannot
|
||||
// be disabled.
|
||||
// Note that the currently winning request is held if the data sink is not ready. This behavior is
|
||||
// required by some interconnect protocols (AXI, TL). The module contains an assertion that checks
|
||||
// this behavior.
|
||||
//
|
||||
// Also, this module contains a request stability assertion that checks that requests stay asserted
|
||||
// until they have been served. This assertion can be optionally disabled by setting EnReqStabA to
|
||||
// zero. This is a non-functional parameter and does not affect the designs behavior.
|
||||
//
|
||||
// See also: prim_arbiter_tree
|
||||
|
||||
`include "prim_assert.sv"
|
||||
|
||||
module prim_arbiter_ppc #(
|
||||
parameter int unsigned N = 4,
|
||||
parameter int unsigned N = 8,
|
||||
parameter int unsigned DW = 32,
|
||||
|
||||
// Configurations
|
||||
// EnDataPort: {0, 1}, if 0, input data will be ignored
|
||||
parameter int EnDataPort = 1,
|
||||
parameter bit EnDataPort = 1,
|
||||
|
||||
// Non-functional parameter to switch on the request stability assertion
|
||||
parameter bit EnReqStabA = 1,
|
||||
|
||||
// Derived parameters
|
||||
localparam int unsigned IdxW = $clog2(N)
|
||||
localparam int IdxW = $clog2(N)
|
||||
) (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
|
||||
input [ N-1:0] req_i,
|
||||
input [DW-1:0] data_i [N],
|
||||
output logic [ N-1:0] gnt_o,
|
||||
output logic [IdxW-1:0] idx_o,
|
||||
input [ N-1:0] req_i,
|
||||
input [DW-1:0] data_i [N],
|
||||
output logic [ N-1:0] gnt_o,
|
||||
output logic [IdxW-1:0] idx_o,
|
||||
|
||||
output logic valid_o,
|
||||
output logic [DW-1:0] data_o,
|
||||
input ready_i
|
||||
output logic valid_o,
|
||||
output logic [DW-1:0] data_o,
|
||||
input ready_i
|
||||
);
|
||||
|
||||
`ASSERT_INIT(CheckNGreaterZero_A, N > 0)
|
||||
|
@ -118,20 +124,23 @@ module prim_arbiter_ppc #(
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
////////////////
|
||||
// assertions //
|
||||
////////////////
|
||||
// grant shall be higher index than prev. unless no higher requests exist
|
||||
`ASSERT(RoundRobin_A, valid_o && ready_i && $past(ready_i) && $past(valid_o) &&
|
||||
|(masked_req) |-> idx_o > $past(idx_o))
|
||||
|
||||
end
|
||||
|
||||
////////////////
|
||||
// assertions //
|
||||
////////////////
|
||||
|
||||
// KNOWN assertions on outputs, except for data as that may be partially X in simulation
|
||||
// e.g. when used on a BUS
|
||||
`ASSERT_KNOWN(ValidKnown_A, valid_o)
|
||||
`ASSERT_KNOWN(GrantKnown_A, gnt_o)
|
||||
`ASSERT_KNOWN(IdxKnown_A, idx_o)
|
||||
|
||||
// grant index shall be higher index than previous index, unless no higher requests exist.
|
||||
`ASSERT(RoundRobin_A,
|
||||
##1 valid_o && ready_i && $past(ready_i) && $past(valid_o) &&
|
||||
|(req_i & ~((N'(1) << $past(idx_o)+1) - 1)) |->
|
||||
idx_o > $past(idx_o))
|
||||
// we can only grant one requestor at a time
|
||||
`ASSERT(CheckHotOne_A, $onehot0(gnt_o))
|
||||
// A grant implies that the sink is ready
|
||||
|
@ -148,27 +157,69 @@ module prim_arbiter_ppc #(
|
|||
`ASSERT(NoReadyValidNoGrant_A, !(ready_i || valid_o) |-> gnt_o == 0)
|
||||
// check index / grant correspond
|
||||
`ASSERT(IndexIsCorrect_A, ready_i && valid_o |-> gnt_o[idx_o] && req_i[idx_o])
|
||||
|
||||
if (EnDataPort) begin: gen_data_port_assertion
|
||||
// data flow
|
||||
`ASSERT(DataFlow_A, ready_i && valid_o |-> data_o == data_i[idx_o])
|
||||
// KNOWN assertions on outputs, except for data as that may be partially X in simulation
|
||||
// e.g. when used on a BUS
|
||||
`ASSERT_KNOWN(ValidKnown_A, valid_o)
|
||||
`ASSERT_KNOWN(GrantKnown_A, gnt_o)
|
||||
`ASSERT_KNOWN(IdxKnown_A, idx_o)
|
||||
|
||||
`ifndef SYNTHESIS
|
||||
// A grant implies a request
|
||||
int unsigned k; // this is a symbolic variable
|
||||
`ASSUME(KStable_M, ##1 $stable(k), clk_i, !rst_ni)
|
||||
`ASSUME(KRange_M, k < N, clk_i, !rst_ni)
|
||||
`ASSERT(GntImpliesReq_A, gnt_o[k] |-> req_i[k])
|
||||
end
|
||||
|
||||
if (EnReqStabA) begin : gen_lock_assertion
|
||||
// requests must stay asserted until they have been granted
|
||||
`ASSUME(ReqStaysHighUntilGranted_M, (|req_i) && !ready_i |=>
|
||||
`ASSUME(ReqStaysHighUntilGranted0_M, (|req_i) && !ready_i |=>
|
||||
(req_i & $past(req_i)) == $past(req_i))
|
||||
// check that the arbitration decision is held if the sink is not ready
|
||||
`ASSERT(LockArbDecision_A, |req_i && !ready_i |=> idx_o == $past(idx_o))
|
||||
end
|
||||
|
||||
// FPV-only assertions with symbolic variables
|
||||
`ifdef FPV_ON
|
||||
// symbolic variables
|
||||
int unsigned k;
|
||||
bit ReadyIsStable;
|
||||
bit ReqsAreStable;
|
||||
|
||||
// constraints for symbolic variables
|
||||
`ASSUME(KStable_M, ##1 $stable(k))
|
||||
`ASSUME(KRange_M, k < N)
|
||||
// this is used enable checking for stable and unstable ready_i and req_i signals in the same run.
|
||||
// the symbolic variables act like a switch that the solver can trun on and off.
|
||||
`ASSUME(ReadyIsStable_M, ##1 $stable(ReadyIsStable))
|
||||
`ASSUME(ReqsAreStable_M, ##1 $stable(ReqsAreStable))
|
||||
`ASSUME(ReadyStable_M, ##1 !ReadyIsStable || $stable(ready_i))
|
||||
`ASSUME(ReqsStable_M, ##1 !ReqsAreStable || $stable(req_i))
|
||||
|
||||
// A grant implies a request
|
||||
`ASSERT(GntImpliesReq_A, gnt_o[k] |-> req_i[k])
|
||||
|
||||
// if request and ready are constantly held at 1, we should eventually get a grant
|
||||
`ASSERT(NoStarvation_A,
|
||||
ReqsAreStable && ReadyIsStable && ready_i && req_i[k] |->
|
||||
strong(##[0:$] gnt_o[k]))
|
||||
|
||||
// if N requests are constantly asserted and ready is constant 1, each request must
|
||||
// be granted exactly once over a time window of N cycles for the arbiter to be fair.
|
||||
for (genvar n = 1; n <= N; n++) begin : gen_fairness
|
||||
integer gnt_cnt;
|
||||
`ASSERT(Fairness_A,
|
||||
ReqsAreStable && ReadyIsStable && ready_i && req_i[k] &&
|
||||
$countones(req_i) == n |->
|
||||
##n gnt_cnt == $past(gnt_cnt, n) + 1)
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin : p_cnt
|
||||
if (!rst_ni) begin
|
||||
gnt_cnt <= 0;
|
||||
end else begin
|
||||
gnt_cnt <= gnt_cnt + gnt_o[k];
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if (EnReqStabA) begin : gen_lock_assertion_fpv
|
||||
// requests must stay asserted until they have been granted
|
||||
`ASSUME(ReqStaysHighUntilGranted1_M, req_i[k] & !gnt_o[k] |=>
|
||||
req_i[k], clk_i, !rst_ni)
|
||||
end
|
||||
`endif
|
||||
|
||||
endmodule
|
||||
endmodule : prim_arbiter_ppc
|
||||
|
||||
|
|
305
vendor/lowrisc_ip/prim/rtl/prim_arbiter_tree.sv
vendored
305
vendor/lowrisc_ip/prim/rtl/prim_arbiter_tree.sv
vendored
|
@ -5,43 +5,58 @@
|
|||
// N:1 arbiter module
|
||||
//
|
||||
// Verilog parameter
|
||||
// N: Number of request ports
|
||||
// DW: Data width
|
||||
// Lock: Lock arbiter decision when destination is not ready
|
||||
// N: Number of request ports
|
||||
// DW: Data width
|
||||
// DataPort: Set to 1 to enable the data port. Otherwise that port will be ignored.
|
||||
// EnReqStabA: Checks whether requests remain asserted until granted
|
||||
//
|
||||
// Hand optimized version which implements a binary tree to optimize
|
||||
// timing. In particular, arbitration decisions and data mux steering happen
|
||||
// simultaneously on the corresponding tree level, which leads to improved propagation
|
||||
// delay compared to a solution that arbitrates first, followed by a data mux selection.
|
||||
// This is a tree implementation of a round robin arbiter. It has the same behavior as the PPC
|
||||
// implementation in prim_arbiter_ppc, and also uses a prefix summing approach to determine the next
|
||||
// request to be granted. The main difference with respect to the PPC arbiter is that the leading 1
|
||||
// detection and the prefix summation are performed with a binary tree instead of a sequential loop.
|
||||
// Also, if the data port is enabled, the data is muxed based on the local arbitration decisions at
|
||||
// each node of the arbiter tree. This means that the data can propagate through the tree
|
||||
// simultaneously with the requests, instead of waiting for the arbitration to determine the winner
|
||||
// index first. As a result, this design has a shorter critical path than other implementations,
|
||||
// leading to better ovberall timing.
|
||||
//
|
||||
// If Lock is turned on, the currently winning request is held if the
|
||||
// data sink is not ready. This behavior is required by some interconnect
|
||||
// protocols (AXI, TL), and hence it is turned on by default.
|
||||
// Note that this implies that an asserted request must stay asserted
|
||||
// until it has been granted.
|
||||
// Note that the currently winning request is held if the data sink is not ready. This behavior is
|
||||
// required by some interconnect protocols (AXI, TL). The module contains an assertion that checks
|
||||
// this behavior.
|
||||
//
|
||||
// Also, this module contains a request stability assertion that checks that requests stay asserted
|
||||
// until they have been served. This assertion can be optionally disabled by setting EnReqStabA to
|
||||
// zero. This is a non-functional parameter and does not affect the designs behavior.
|
||||
//
|
||||
// See also: prim_arbiter_ppc
|
||||
|
||||
`include "prim_assert.sv"
|
||||
|
||||
module prim_arbiter_tree #(
|
||||
parameter int unsigned N = 4,
|
||||
parameter int unsigned DW = 32,
|
||||
// holds the last arbiter decision in case the sink is not ready
|
||||
// this should be enabled when used in AXI or TL protocols.
|
||||
parameter bit Lock = 1'b1
|
||||
parameter int N = 8,
|
||||
parameter int DW = 32,
|
||||
|
||||
// Configurations
|
||||
// EnDataPort: {0, 1}, if 0, input data will be ignored
|
||||
parameter bit EnDataPort = 1,
|
||||
|
||||
// Non-functional parameter to switch on the request stability assertion
|
||||
parameter bit EnReqStabA = 1,
|
||||
|
||||
// Derived parameters
|
||||
localparam int IdxW = $clog2(N)
|
||||
) (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
|
||||
input [ N-1:0] req_i,
|
||||
input [DW-1:0] data_i [N],
|
||||
output logic [ N-1:0] gnt_o,
|
||||
output logic [$clog2(N)-1:0] idx_o,
|
||||
input [ N-1:0] req_i,
|
||||
input [DW-1:0] data_i [N],
|
||||
output logic [ N-1:0] gnt_o,
|
||||
output logic [IdxW-1:0] idx_o,
|
||||
|
||||
output logic valid_o,
|
||||
output logic [DW-1:0] data_o,
|
||||
input ready_i
|
||||
output logic valid_o,
|
||||
output logic [DW-1:0] data_o,
|
||||
input ready_i
|
||||
);
|
||||
|
||||
`ASSERT_INIT(CheckNGreaterZero_A, N > 0)
|
||||
|
@ -58,34 +73,16 @@ module prim_arbiter_tree #(
|
|||
|
||||
// align to powers of 2 for simplicity
|
||||
// a full binary tree with N levels has 2**N + 2**N-1 nodes
|
||||
localparam int unsigned NumLevels = $clog2(N);
|
||||
logic [N-1:0] req;
|
||||
logic [2**(NumLevels+1)-2:0] req_tree;
|
||||
logic [2**(NumLevels+1)-2:0] gnt_tree;
|
||||
logic [2**(NumLevels+1)-2:0][NumLevels-1:0] idx_tree;
|
||||
logic [2**(NumLevels+1)-2:0][DW-1:0] data_tree;
|
||||
logic [NumLevels-1:0] rr_q;
|
||||
logic [2**(IdxW+1)-2:0] req_tree;
|
||||
logic [2**(IdxW+1)-2:0] prio_tree;
|
||||
logic [2**(IdxW+1)-2:0] rdy_tree;
|
||||
logic [2**(IdxW+1)-2:0] sel_tree;
|
||||
logic [2**(IdxW+1)-2:0] mask_tree;
|
||||
logic [2**(IdxW+1)-2:0][IdxW-1:0] idx_tree;
|
||||
logic [2**(IdxW+1)-2:0][DW-1:0] data_tree;
|
||||
logic [2**IdxW-1:0] prio_mask_d, prio_mask_q;
|
||||
|
||||
// req_locked
|
||||
if (Lock) begin : gen_lock
|
||||
logic [N-1:0] mask_d, mask_q;
|
||||
// if the request cannot be served, we store the current request bits
|
||||
// and apply it as a mask to the incoming requests in the next cycle.
|
||||
assign mask_d = (valid_o && (!ready_i)) ? req : {N{1'b1}};
|
||||
assign req = mask_q & req_i;
|
||||
|
||||
always_ff @(posedge clk_i) begin : p_lock_regs
|
||||
if (!rst_ni) begin
|
||||
mask_q <= {N{1'b1}};
|
||||
end else begin
|
||||
mask_q <= mask_d;
|
||||
end
|
||||
end
|
||||
end else begin : gen_no_lock
|
||||
assign req = req_i;
|
||||
end
|
||||
|
||||
for (genvar level = 0; level < NumLevels+1; level++) begin : gen_tree
|
||||
for (genvar level = 0; level < IdxW+1; level++) begin : gen_tree
|
||||
//
|
||||
// level+1 C0 C1 <- "Base1" points to the first node on "level+1",
|
||||
// \ / these nodes are the children of the nodes one level below
|
||||
|
@ -97,89 +94,114 @@ module prim_arbiter_tree #(
|
|||
// C0 = 2**(level+1) - 1 + 2*offset = Base1 + 2*offset
|
||||
// C1 = 2**(level+1) - 1 + 2*offset + 1 = Base1 + 2*offset + 1
|
||||
//
|
||||
localparam int unsigned Base0 = (2**level)-1;
|
||||
localparam int unsigned Base1 = (2**(level+1))-1;
|
||||
localparam int Base0 = (2**level)-1;
|
||||
localparam int Base1 = (2**(level+1))-1;
|
||||
|
||||
for (genvar offset = 0; offset < 2**level; offset++) begin : gen_level
|
||||
localparam int unsigned Pa = Base0 + offset;
|
||||
localparam int unsigned C0 = Base1 + 2*offset;
|
||||
localparam int unsigned C1 = Base1 + 2*offset + 1;
|
||||
localparam int Pa = Base0 + offset;
|
||||
localparam int C0 = Base1 + 2*offset;
|
||||
localparam int C1 = Base1 + 2*offset + 1;
|
||||
|
||||
// this assigns the gated interrupt source signals, their
|
||||
// corresponding IDs and priorities to the tree leafs
|
||||
if (level == NumLevels) begin : gen_leafs
|
||||
if (level == IdxW) begin : gen_leafs
|
||||
if (offset < N) begin : gen_assign
|
||||
// forward path
|
||||
assign req_tree[Pa] = req[offset];
|
||||
assign idx_tree[Pa] = offset;
|
||||
assign data_tree[Pa] = data_i[offset];
|
||||
// backward (grant) path
|
||||
assign gnt_o[offset] = gnt_tree[Pa];
|
||||
// forward path (requests and data)
|
||||
// all requests inputs are assigned to the request tree
|
||||
assign req_tree[Pa] = req_i[offset];
|
||||
// we basically split the incoming request vector into two halves with the following
|
||||
// priority assignment. the prio_mask_q register contains a prefix sum that has been
|
||||
// computed using the last winning index, and hence masks out all requests at offsets
|
||||
// lower or equal the previously granted index. hence, all higher indices are considered
|
||||
// first in the arbitration tree nodes below, before considering the lower indices.
|
||||
assign prio_tree[Pa] = req_i[offset] & prio_mask_q[offset];
|
||||
// input for the index muxes (used to compute the winner index)
|
||||
assign idx_tree[Pa] = offset;
|
||||
// input for the data muxes
|
||||
assign data_tree[Pa] = data_i[offset];
|
||||
|
||||
// backward path (grants and prefix sum)
|
||||
// grant if selected, ready and request asserted
|
||||
assign gnt_o[offset] = req_i[offset] & sel_tree[Pa] & ready_i;
|
||||
// only update mask if there is a valid request
|
||||
assign prio_mask_d[offset] = (|req_i) ?
|
||||
mask_tree[Pa] | sel_tree[Pa] & ~ready_i :
|
||||
prio_mask_q[offset];
|
||||
end else begin : gen_tie_off
|
||||
// forward path
|
||||
assign req_tree[Pa] = '0;
|
||||
assign idx_tree[Pa] = '0;
|
||||
assign data_tree[Pa] = '0;
|
||||
assign prio_mask_d[offset] = '0;
|
||||
end
|
||||
// this creates the node assignments
|
||||
end else begin : gen_nodes
|
||||
// NOTE: the code below has been written in this way in order to work
|
||||
// around a synthesis issue in Vivado 2018.3 and 2019.2 where the whole
|
||||
// module would be optimized away if these assign statements contained
|
||||
// ternary statements to implement the muxes.
|
||||
//
|
||||
// TODO: rewrite these lines with ternary statmements onec the problem
|
||||
// has been fixed in the tool.
|
||||
//
|
||||
// See also originating issue:
|
||||
// https://github.com/lowRISC/opentitan/issues/1355
|
||||
// Xilinx issue:
|
||||
// https://forums.xilinx.com/t5/Synthesis/Simulation-Synthesis-Mismatch-with-Vivado-2018-3/m-p/1065923#M33849
|
||||
// local helper variable
|
||||
logic sel;
|
||||
always_comb begin : p_node
|
||||
// forward path (requests and data)
|
||||
// each node looks at its two children, and selects the one with higher priority
|
||||
sel = ~req_tree[C0] | ~prio_tree[C0] & prio_tree[C1];
|
||||
// propagate requests
|
||||
req_tree[Pa] = req_tree[C0] | req_tree[C1];
|
||||
prio_tree[Pa] = prio_tree[C1] | prio_tree[C0];
|
||||
// data and index muxes
|
||||
idx_tree[Pa] = (sel) ? idx_tree[C1] : idx_tree[C0];
|
||||
data_tree[Pa] = (sel) ? data_tree[C1] : data_tree[C0];
|
||||
|
||||
// forward path
|
||||
logic sel; // local helper variable
|
||||
// this performs a (local) round robin arbitration using the associated rr counter bit
|
||||
assign sel = ~req_tree[C0] | req_tree[C1] & rr_q[NumLevels-1-level];
|
||||
// propagate requests
|
||||
assign req_tree[Pa] = req_tree[C0] | req_tree[C1];
|
||||
// muxes
|
||||
assign idx_tree[Pa] = ({NumLevels{sel}} & idx_tree[C1]) |
|
||||
({NumLevels{~sel}} & idx_tree[C0]);
|
||||
assign data_tree[Pa] = ({DW{sel}} & data_tree[C1]) |
|
||||
({DW{~sel}} & data_tree[C0]);
|
||||
// backward (grant) path
|
||||
assign gnt_tree[C0] = gnt_tree[Pa] & ~sel;
|
||||
assign gnt_tree[C1] = gnt_tree[Pa] & sel;
|
||||
// backward path (grants and prefix sum)
|
||||
// this propagates the selction index back and computes a hot one mask
|
||||
sel_tree[C0] = sel_tree[Pa] & ~sel;
|
||||
sel_tree[C1] = sel_tree[Pa] & sel;
|
||||
// this performs a prefix sum for masking the input requests in the next cycle
|
||||
mask_tree[C0] = mask_tree[Pa];
|
||||
mask_tree[C1] = mask_tree[Pa] | sel_tree[C0];
|
||||
end
|
||||
end
|
||||
end : gen_level
|
||||
end : gen_tree
|
||||
|
||||
// the results can be found at the tree root
|
||||
assign idx_o = idx_tree[0];
|
||||
assign data_o = data_tree[0];
|
||||
assign valid_o = req_tree[0];
|
||||
// propagate the grant back to the requestors
|
||||
assign gnt_tree[0] = valid_o & ready_i;
|
||||
|
||||
// this is the round robin counter
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs
|
||||
if (!rst_ni) begin
|
||||
rr_q <= '0;
|
||||
end else begin
|
||||
if (gnt_tree[0] && (rr_q == N-1)) begin
|
||||
rr_q <= '0;
|
||||
end else if (gnt_tree[0]) begin
|
||||
rr_q <= rr_q + 1'b1;
|
||||
end
|
||||
end
|
||||
if (EnDataPort) begin : gen_data_port
|
||||
assign data_o = data_tree[0];
|
||||
end else begin : gen_no_dataport
|
||||
logic [DW-1:0] unused_data [N];
|
||||
assign unused_data = data_i;
|
||||
assign data_o = '1;
|
||||
end
|
||||
|
||||
assign idx_o = idx_tree[0];
|
||||
assign valid_o = req_tree[0];
|
||||
|
||||
// the select tree computes a hot one signal that indicates which request is currently selected
|
||||
assign sel_tree[0] = 1'b1;
|
||||
// the mask tree is basically a prefix sum of the hot one select signal computed above
|
||||
assign mask_tree[0] = 1'b0;
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin : p_mask_reg
|
||||
if (!rst_ni) begin
|
||||
prio_mask_q <= '0;
|
||||
end else begin
|
||||
prio_mask_q <= prio_mask_d;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
////////////////
|
||||
// assertions //
|
||||
////////////////
|
||||
|
||||
// KNOWN assertions on outputs, except for data as that may be partially X in simulation
|
||||
// e.g. when used on a BUS
|
||||
`ASSERT_KNOWN(ValidKnown_A, valid_o)
|
||||
`ASSERT_KNOWN(GrantKnown_A, gnt_o)
|
||||
`ASSERT_KNOWN(IdxKnown_A, idx_o)
|
||||
|
||||
// grant index shall be higher index than previous index, unless no higher requests exist.
|
||||
`ASSERT(RoundRobin_A,
|
||||
##1 valid_o && ready_i && $past(ready_i) && $past(valid_o) &&
|
||||
|(req_i & ~((N'(1) << $past(idx_o)+1) - 1)) |->
|
||||
idx_o > $past(idx_o))
|
||||
// we can only grant one requestor at a time
|
||||
`ASSERT(CheckHotOne_A, $onehot0(gnt_o))
|
||||
// A grant implies that the sink is ready
|
||||
|
@ -196,29 +218,68 @@ module prim_arbiter_tree #(
|
|||
`ASSERT(NoReadyValidNoGrant_A, !(ready_i || valid_o) |-> gnt_o == 0)
|
||||
// check index / grant correspond
|
||||
`ASSERT(IndexIsCorrect_A, ready_i && valid_o |-> gnt_o[idx_o] && req_i[idx_o])
|
||||
|
||||
if (EnDataPort) begin: gen_data_port_assertion
|
||||
// data flow
|
||||
`ASSERT(DataFlow_A, ready_i && valid_o |-> data_o == data_i[idx_o])
|
||||
// KNOWN assertions on outputs, except for data as that may be partially X in simulation
|
||||
// e.g. when used on a BUS
|
||||
`ASSERT_KNOWN(ValidKnown_A, valid_o)
|
||||
`ASSERT_KNOWN(GrantKnown_A, gnt_o)
|
||||
`ASSERT_KNOWN(IdxKnown_A, idx_o)
|
||||
end
|
||||
|
||||
if (EnReqStabA) begin : gen_lock_assertion
|
||||
// requests must stay asserted until they have been granted
|
||||
`ASSUME(ReqStaysHighUntilGranted0_M, (|req_i) && !ready_i |=>
|
||||
(req_i & $past(req_i)) == $past(req_i))
|
||||
// check that the arbitration decision is held if the sink is not ready
|
||||
`ASSERT(LockArbDecision_A, |req_i && !ready_i |=> idx_o == $past(idx_o))
|
||||
end
|
||||
|
||||
// FPV-only assertions with symbolic variables
|
||||
`ifdef FPV_ON
|
||||
// symbolic variables
|
||||
int unsigned k;
|
||||
bit ReadyIsStable;
|
||||
bit ReqsAreStable;
|
||||
|
||||
// constraints for symbolic variables
|
||||
`ASSUME(KStable_M, ##1 $stable(k))
|
||||
`ASSUME(KRange_M, k < N)
|
||||
// this is used enable checking for stable and unstable ready_i and req_i signals in the same run.
|
||||
// the symbolic variables act like a switch that the solver can trun on and off.
|
||||
`ASSUME(ReadyIsStable_M, ##1 $stable(ReadyIsStable))
|
||||
`ASSUME(ReqsAreStable_M, ##1 $stable(ReqsAreStable))
|
||||
`ASSUME(ReadyStable_M, ##1 !ReadyIsStable || $stable(ready_i))
|
||||
`ASSUME(ReqsStable_M, ##1 !ReqsAreStable || $stable(req_i))
|
||||
|
||||
`ifndef SYNTHESIS
|
||||
// A grant implies a request
|
||||
int unsigned k; // this is a symbolic variable
|
||||
`ASSUME(KStable_M, ##1 $stable(k), clk_i, !rst_ni)
|
||||
`ASSUME(KRange_M, k < N, clk_i, !rst_ni)
|
||||
`ASSERT(GntImpliesReq_A, gnt_o[k] |-> req_i[k])
|
||||
|
||||
if (Lock) begin : gen_lock_assertion
|
||||
// requests must stay asserted until they have been granted
|
||||
`ASSUME(ReqStaysHighUntilGranted_M, (|req_i) && !ready_i |=>
|
||||
(req_i & $past(req_i)) == $past(req_i), clk_i, !rst_ni)
|
||||
// check that the arbitration decision is held if the sink is not ready
|
||||
`ASSERT(LockArbDecision_A, |req_i && !ready_i |=> idx_o == $past(idx_o))
|
||||
// if request and ready are constantly held at 1, we should eventually get a grant
|
||||
`ASSERT(NoStarvation_A,
|
||||
ReqsAreStable && ReadyIsStable && ready_i && req_i[k] |->
|
||||
strong(##[0:$] gnt_o[k]))
|
||||
|
||||
// if N requests are constantly asserted and ready is constant 1, each request must
|
||||
// be granted exactly once over a time window of N cycles for the arbiter to be fair.
|
||||
for (genvar n = 1; n <= N; n++) begin : gen_fairness
|
||||
integer gnt_cnt;
|
||||
`ASSERT(Fairness_A,
|
||||
ReqsAreStable && ReadyIsStable && ready_i && req_i[k] &&
|
||||
$countones(req_i) == n |->
|
||||
##n gnt_cnt == $past(gnt_cnt, n) + 1)
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin : p_cnt
|
||||
if (!rst_ni) begin
|
||||
gnt_cnt <= 0;
|
||||
end else begin
|
||||
gnt_cnt <= gnt_cnt + gnt_o[k];
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if (EnReqStabA) begin : gen_lock_assertion_fpv
|
||||
// requests must stay asserted until they have been granted
|
||||
`ASSUME(ReqStaysHighUntilGranted1_M, req_i[k] & !gnt_o[k] |=>
|
||||
req_i[k], clk_i, !rst_ni)
|
||||
end
|
||||
`endif
|
||||
|
||||
endmodule
|
||||
endmodule : prim_arbiter_tree
|
||||
|
|
170
vendor/lowrisc_ip/prim/rtl/prim_assert.sv
vendored
170
vendor/lowrisc_ip/prim/rtl/prim_assert.sv
vendored
|
@ -24,101 +24,59 @@
|
|||
// Helper macros //
|
||||
///////////////////
|
||||
|
||||
// local helper macro to reduce code clutter. undefined at the end of this file
|
||||
`ifndef VERILATOR
|
||||
`ifndef SYNTHESIS
|
||||
`define INC_ASSERT
|
||||
`endif
|
||||
`endif
|
||||
|
||||
// Converts an arbitrary block of code into a Verilog string
|
||||
`define PRIM_STRINGIFY(__x) `"__x`"
|
||||
|
||||
// ASSERT_RPT is available to change the reporting mechanism when an assert fails
|
||||
`define ASSERT_RPT(__name) \
|
||||
`ifdef UVM \
|
||||
assert_rpt_pkg::assert_rpt($sformatf("[%m] %s (%s:%0d)", \
|
||||
__name, `__FILE__, `__LINE__)); \
|
||||
`else \
|
||||
$error("[ASSERT FAILED] [%m] %s (%s:%0d)", __name, `__FILE__, `__LINE__); \
|
||||
`endif
|
||||
|
||||
///////////////////////////////////////
|
||||
// Simple assertion and cover macros //
|
||||
///////////////////////////////////////
|
||||
|
||||
// Default clk and reset signals used by assertion macros below.
|
||||
`define ASSERT_DEFAULT_CLK clk_i
|
||||
`define ASSERT_DEFAULT_RST !rst_ni
|
||||
|
||||
// Immediate assertion
|
||||
// Note that immediate assertions are sensitive to simulation glitches.
|
||||
`define ASSERT_I(__name, __prop) \
|
||||
`ifdef INC_ASSERT \
|
||||
__name: assert (__prop) \
|
||||
else begin \
|
||||
`ASSERT_RPT(`PRIM_STRINGIFY(__name)) \
|
||||
end \
|
||||
`endif
|
||||
// Converts an arbitrary block of code into a Verilog string
|
||||
`define PRIM_STRINGIFY(__x) `"__x`"
|
||||
|
||||
// Assertion in initial block. Can be used for things like parameter checking.
|
||||
`define ASSERT_INIT(__name, __prop) \
|
||||
`ifdef INC_ASSERT \
|
||||
initial begin \
|
||||
__name: assert (__prop) \
|
||||
else begin \
|
||||
`ASSERT_RPT(`PRIM_STRINGIFY(__name)) \
|
||||
end \
|
||||
end \
|
||||
`endif
|
||||
// The basic helper macros are actually defined in "implementation headers". The macros should do
|
||||
// the same thing in each case (except for the dummy flavour), but in a way that the respective
|
||||
// tools support.
|
||||
//
|
||||
// If the tool supports assertions in some form, we also define INC_ASSERT (which can be used to
|
||||
// hide signal definitions that are only used for assertions).
|
||||
//
|
||||
// The list of basic macros supported is:
|
||||
//
|
||||
// ASSERT_I: Immediate assertion. Note that immediate assertions are sensitive to simulation
|
||||
// glitches.
|
||||
//
|
||||
// ASSERT_INIT: Assertion in initial block. Can be used for things like parameter checking.
|
||||
//
|
||||
// ASSERT_FINAL: Assertion in final block. Can be used for things like queues being empty at end of
|
||||
// sim, all credits returned at end of sim, state machines in idle at end of sim.
|
||||
//
|
||||
// ASSERT: Assert a concurrent property directly. It can be called as a module (or
|
||||
// interface) body item.
|
||||
//
|
||||
// Note: We use (__rst !== '0) in the disable iff statements instead of (__rst ==
|
||||
// '1). This properly disables the assertion in cases when reset is X at the
|
||||
// beginning of a simulation. For that case, (reset == '1) does not disable the
|
||||
// assertion.
|
||||
//
|
||||
// ASSERT_NEVER: Assert a concurrent property NEVER happens
|
||||
//
|
||||
// ASSERT_KNOWN: Assert that signal has a known value (each bit is either '0' or '1') after reset.
|
||||
// It can be called as a module (or interface) body item.
|
||||
//
|
||||
// COVER: Cover a concurrent property
|
||||
//
|
||||
// ASSUME: Assume a concurrent property
|
||||
//
|
||||
// ASSUME_I: Assume an immediate property
|
||||
|
||||
// Assertion in final block. Can be used for things like queues being empty
|
||||
// at end of sim, all credits returned at end of sim, state machines in idle
|
||||
// at end of sim.
|
||||
`define ASSERT_FINAL(__name, __prop) \
|
||||
`ifdef INC_ASSERT \
|
||||
final begin \
|
||||
__name: assert (__prop || $test$plusargs("disable_assert_final_checks")) \
|
||||
else begin \
|
||||
`ASSERT_RPT(`PRIM_STRINGIFY(__name)) \
|
||||
end \
|
||||
end \
|
||||
`endif
|
||||
|
||||
// Assert a concurrent property directly.
|
||||
// It can be called as a module (or interface) body item.
|
||||
`define ASSERT(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \
|
||||
`ifdef INC_ASSERT \
|
||||
__name: assert property (@(posedge __clk) disable iff ((__rst) !== '0) (__prop)) \
|
||||
else begin \
|
||||
`ASSERT_RPT(`PRIM_STRINGIFY(__name)) \
|
||||
end \
|
||||
`endif
|
||||
// Note: Above we use (__rst !== '0) in the disable iff statements instead of
|
||||
// (__rst == '1). This properly disables the assertion in cases when reset is X at
|
||||
// the beginning of a simulation. For that case, (reset == '1) does not disable the
|
||||
// assertion.
|
||||
|
||||
// Assert a concurrent property NEVER happens
|
||||
`define ASSERT_NEVER(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \
|
||||
`ifdef INC_ASSERT \
|
||||
__name: assert property (@(posedge __clk) disable iff ((__rst) !== '0) not (__prop)) \
|
||||
else begin \
|
||||
`ASSERT_RPT(`PRIM_STRINGIFY(__name)) \
|
||||
end \
|
||||
`endif
|
||||
|
||||
// Assert that signal has a known value (each bit is either '0' or '1') after reset.
|
||||
// It can be called as a module (or interface) body item.
|
||||
`define ASSERT_KNOWN(__name, __sig, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \
|
||||
`ifdef INC_ASSERT \
|
||||
`ASSERT(__name, !$isunknown(__sig), __clk, __rst) \
|
||||
`endif
|
||||
|
||||
// Cover a concurrent property
|
||||
`define COVER(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \
|
||||
`ifdef INC_ASSERT \
|
||||
__name: cover property (@(posedge __clk) disable iff ((__rst) !== '0) (__prop)); \
|
||||
`ifdef VERILATOR
|
||||
`include "prim_assert_dummy_macros.svh"
|
||||
`elsif SYNTHESIS
|
||||
`include "prim_assert_dummy_macros.svh"
|
||||
`elsif YOSYS
|
||||
`include "prim_assert_yosys_macros.svh"
|
||||
`define INC_ASSERT
|
||||
`else
|
||||
`include "prim_assert_standard_macros.svh"
|
||||
`define INC_ASSERT
|
||||
`endif
|
||||
|
||||
//////////////////////////////
|
||||
|
@ -127,46 +85,18 @@
|
|||
|
||||
// Assert that signal is an active-high pulse with pulse length of 1 clock cycle
|
||||
`define ASSERT_PULSE(__name, __sig, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \
|
||||
`ifdef INC_ASSERT \
|
||||
`ASSERT(__name, $rose(__sig) |=> !(__sig), __clk, __rst) \
|
||||
`endif
|
||||
`ASSERT(__name, $rose(__sig) |=> !(__sig), __clk, __rst)
|
||||
|
||||
// Assert that a property is true only when an enable signal is set. It can be called as a module
|
||||
// (or interface) body item.
|
||||
`define ASSERT_IF(__name, __prop, __enable, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \
|
||||
`ifdef INC_ASSERT \
|
||||
`ASSERT(__name, (__enable) |-> (__prop), __clk, __rst) \
|
||||
`endif
|
||||
`ASSERT(__name, (__enable) |-> (__prop), __clk, __rst)
|
||||
|
||||
// Assert that signal has a known value (each bit is either '0' or '1') after reset if enable is
|
||||
// set. It can be called as a module (or interface) body item.
|
||||
`define ASSERT_KNOWN_IF(__name, __sig, __enable, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \
|
||||
`ifdef INC_ASSERT \
|
||||
`ASSERT_KNOWN(__name``KnownEnable, __enable, __clk, __rst) \
|
||||
`ASSERT_IF(__name, !$isunknown(__sig), __enable, __clk, __rst) \
|
||||
`endif
|
||||
|
||||
///////////////////////
|
||||
// Assumption macros //
|
||||
///////////////////////
|
||||
|
||||
// Assume a concurrent property
|
||||
`define ASSUME(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \
|
||||
`ifdef INC_ASSERT \
|
||||
__name: assume property (@(posedge __clk) disable iff ((__rst) !== '0) (__prop)) \
|
||||
else begin \
|
||||
`ASSERT_RPT(`PRIM_STRINGIFY(__name)) \
|
||||
end \
|
||||
`endif
|
||||
|
||||
// Assume an immediate property
|
||||
`define ASSUME_I(__name, __prop) \
|
||||
`ifdef INC_ASSERT \
|
||||
__name: assume (__prop) \
|
||||
else begin \
|
||||
`ASSERT_RPT(`PRIM_STRINGIFY(__name)) \
|
||||
end \
|
||||
`endif
|
||||
`ASSERT_IF(__name, !$isunknown(__sig), __enable, __clk, __rst)
|
||||
|
||||
//////////////////////////////////
|
||||
// For formal verification only //
|
||||
|
|
16
vendor/lowrisc_ip/prim/rtl/prim_assert_dummy_macros.svh
vendored
Normal file
16
vendor/lowrisc_ip/prim/rtl/prim_assert_dummy_macros.svh
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Macro bodies included by prim_assert.sv for tools that don't support assertions. See
|
||||
// prim_assert.sv for documentation for each of the macros.
|
||||
|
||||
`define ASSERT_I(__name, __prop)
|
||||
`define ASSERT_INIT(__name, __prop)
|
||||
`define ASSERT_FINAL(__name, __prop)
|
||||
`define ASSERT(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST)
|
||||
`define ASSERT_NEVER(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST)
|
||||
`define ASSERT_KNOWN(__name, __sig, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST)
|
||||
`define COVER(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST)
|
||||
`define ASSUME(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST)
|
||||
`define ASSUME_I(__name, __prop)
|
67
vendor/lowrisc_ip/prim/rtl/prim_assert_standard_macros.svh
vendored
Normal file
67
vendor/lowrisc_ip/prim/rtl/prim_assert_standard_macros.svh
vendored
Normal file
|
@ -0,0 +1,67 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Macro bodies included by prim_assert.sv for tools that support full SystemVerilog and SVA syntax.
|
||||
// See prim_assert.sv for documentation for each of the macros.
|
||||
|
||||
// ASSERT_RPT is available to change the reporting mechanism when an assert fails
|
||||
`define ASSERT_RPT(__name) \
|
||||
`ifdef UVM \
|
||||
assert_rpt_pkg::assert_rpt($sformatf("[%m] %s (%s:%0d)", \
|
||||
__name, `__FILE__, `__LINE__)); \
|
||||
`else \
|
||||
$error("[ASSERT FAILED] [%m] %s (%s:%0d)", __name, `__FILE__, `__LINE__); \
|
||||
`endif
|
||||
|
||||
`define ASSERT_I(__name, __prop) \
|
||||
__name: assert (__prop) \
|
||||
else begin \
|
||||
`ASSERT_RPT(`PRIM_STRINGIFY(__name)) \
|
||||
end
|
||||
|
||||
`define ASSERT_INIT(__name, __prop) \
|
||||
initial begin \
|
||||
__name: assert (__prop) \
|
||||
else begin \
|
||||
`ASSERT_RPT(`PRIM_STRINGIFY(__name)) \
|
||||
end \
|
||||
end
|
||||
|
||||
`define ASSERT_FINAL(__name, __prop) \
|
||||
final begin \
|
||||
__name: assert (__prop || $test$plusargs("disable_assert_final_checks")) \
|
||||
else begin \
|
||||
`ASSERT_RPT(`PRIM_STRINGIFY(__name)) \
|
||||
end \
|
||||
end
|
||||
|
||||
`define ASSERT(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \
|
||||
__name: assert property (@(posedge __clk) disable iff ((__rst) !== '0) (__prop)) \
|
||||
else begin \
|
||||
`ASSERT_RPT(`PRIM_STRINGIFY(__name)) \
|
||||
end
|
||||
|
||||
`define ASSERT_NEVER(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \
|
||||
__name: assert property (@(posedge __clk) disable iff ((__rst) !== '0) not (__prop)) \
|
||||
else begin \
|
||||
`ASSERT_RPT(`PRIM_STRINGIFY(__name)) \
|
||||
end
|
||||
|
||||
`define ASSERT_KNOWN(__name, __sig, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \
|
||||
`ASSERT(__name, !$isunknown(__sig), __clk, __rst)
|
||||
|
||||
`define COVER(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \
|
||||
__name: cover property (@(posedge __clk) disable iff ((__rst) !== '0) (__prop));
|
||||
|
||||
`define ASSUME(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \
|
||||
__name: assume property (@(posedge __clk) disable iff ((__rst) !== '0) (__prop)) \
|
||||
else begin \
|
||||
`ASSERT_RPT(`PRIM_STRINGIFY(__name)) \
|
||||
end
|
||||
|
||||
`define ASSUME_I(__name, __prop) \
|
||||
__name: assume (__prop) \
|
||||
else begin \
|
||||
`ASSERT_RPT(`PRIM_STRINGIFY(__name)) \
|
||||
end
|
47
vendor/lowrisc_ip/prim/rtl/prim_assert_yosys_macros.svh
vendored
Normal file
47
vendor/lowrisc_ip/prim/rtl/prim_assert_yosys_macros.svh
vendored
Normal file
|
@ -0,0 +1,47 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Macro bodies included by prim_assert.sv for formal verification with Yosys. See prim_assert.sv
|
||||
// for documentation for each of the macros.
|
||||
|
||||
`define ASSERT_I(__name, __prop) \
|
||||
always_comb begin : __name \
|
||||
assert (__prop); \
|
||||
end
|
||||
|
||||
`define ASSERT_INIT(__name, __prop) \
|
||||
initial begin : __name \
|
||||
assert (__prop); \
|
||||
end
|
||||
|
||||
// This doesn't make much sense for a formal tool (we never get to the final block!)
|
||||
`define ASSERT_FINAL(__name, __prop)
|
||||
|
||||
`define ASSERT(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \
|
||||
always_ff @(posedge __clk) begin \
|
||||
if (! (__rst !== '0)) __name: assert (__prop); \
|
||||
end
|
||||
|
||||
`define ASSERT_NEVER(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \
|
||||
always_ff @(posedge __clk) begin \
|
||||
if (! (__rst !== '0)) __name: assert (! (__prop)); \
|
||||
end
|
||||
|
||||
// Yosys uses 2-state logic, so this doesn't make sense here
|
||||
`define ASSERT_KNOWN(__name, __sig, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST)
|
||||
|
||||
`define COVER(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \
|
||||
always_ff @(posedge __clk) begin : __name \
|
||||
cover ((! (__rst !== '0)) && (__prop)); \
|
||||
end
|
||||
|
||||
`define ASSUME(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \
|
||||
always_ff @(posedge __clk) begin \
|
||||
if (! (__rst !== '0)) __name: assume (__prop); \
|
||||
end
|
||||
|
||||
`define ASSUME_I(__name, __prop) \
|
||||
always_comb begin : __name \
|
||||
assume (__prop); \
|
||||
end
|
76
vendor/lowrisc_ip/prim/rtl/prim_cipher_pkg.sv
vendored
76
vendor/lowrisc_ip/prim/rtl/prim_cipher_pkg.sv
vendored
|
@ -235,8 +235,10 @@ package prim_cipher_pkg;
|
|||
key_out = 128'(key_in << 61) | 128'(key_in >> (128-61));
|
||||
// sbox on uppermost 4 bits
|
||||
key_out[127 -: 4] = PRESENT_SBOX4[key_out[127 -: 4]];
|
||||
// xor in round counter on bits 19 to 15
|
||||
key_out[19:15] ^= round_idx;
|
||||
// sbox on second nibble from top
|
||||
key_out[123 -: 4] = PRESENT_SBOX4[key_out[123 -: 4]];
|
||||
// xor in round counter on bits 66 to 62
|
||||
key_out[66:62] ^= round_idx;
|
||||
return key_out;
|
||||
endfunction : present_update_key128
|
||||
|
||||
|
@ -246,13 +248,13 @@ package prim_cipher_pkg;
|
|||
logic [4:0] round_idx,
|
||||
// total number of rounds employed
|
||||
logic [4:0] round_cnt);
|
||||
logic [63:0] key_out;
|
||||
logic [63:0] key_out = key_in;
|
||||
// xor in round counter on bits 19 to 15
|
||||
key_out[19:15] ^= 6'(round_cnt) + 1 - round_idx;
|
||||
key_out[19:15] ^= round_cnt + 1 - round_idx;
|
||||
// sbox on uppermost 4 bits
|
||||
key_out[63 -: 4] = PRESENT_SBOX4_INV[key_out[63 -: 4]];
|
||||
// rotate by 61 to the right
|
||||
key_out = 64'(key_in >> 61) | 64'(key_in << (64-61));
|
||||
key_out = 64'(key_out >> 61) | 64'(key_out << (64-61));
|
||||
return key_out;
|
||||
endfunction : present_inv_update_key64
|
||||
|
||||
|
@ -260,13 +262,13 @@ package prim_cipher_pkg;
|
|||
logic [4:0] round_idx,
|
||||
// total number of rounds employed
|
||||
logic [4:0] round_cnt);
|
||||
logic [79:0] key_out;
|
||||
logic [79:0] key_out = key_in;
|
||||
// xor in round counter on bits 19 to 15
|
||||
key_out[19:15] ^= 6'(round_cnt) + 1 - round_idx;
|
||||
key_out[19:15] ^= round_cnt + 1 - round_idx;
|
||||
// sbox on uppermost 4 bits
|
||||
key_out[79 -: 4] = PRESENT_SBOX4_INV[key_out[79 -: 4]];
|
||||
// rotate by 61 to the right
|
||||
key_out = 80'(key_in >> 61) | 80'(key_in << (80-61));
|
||||
key_out = 80'(key_out >> 61) | 80'(key_out << (80-61));
|
||||
return key_out;
|
||||
endfunction : present_inv_update_key80
|
||||
|
||||
|
@ -274,13 +276,15 @@ package prim_cipher_pkg;
|
|||
logic [4:0] round_idx,
|
||||
// total number of rounds employed
|
||||
logic [4:0] round_cnt);
|
||||
logic [127:0] key_out;
|
||||
// xor in round counter on bits 19 to 15
|
||||
key_out[19:15] ^= 6'(round_cnt) + 1 - round_idx;
|
||||
logic [127:0] key_out = key_in;
|
||||
// xor in round counter on bits 66 to 62
|
||||
key_out[66:62] ^= round_cnt + 1 - round_idx;
|
||||
// sbox on second highest nibble
|
||||
key_out[123 -: 4] = PRESENT_SBOX4_INV[key_out[123 -: 4]];
|
||||
// sbox on uppermost 4 bits
|
||||
key_out[127 -: 4] = PRESENT_SBOX4_INV[key_out[127 -: 4]];
|
||||
// rotate by 61 to the right
|
||||
key_out = 128'(key_in >> 61) | 128'(key_in << (128-61));
|
||||
key_out = 128'(key_out >> 61) | 128'(key_out << (128-61));
|
||||
return key_out;
|
||||
endfunction : present_inv_update_key128
|
||||
|
||||
|
@ -324,11 +328,29 @@ package prim_cipher_pkg;
|
|||
// Common Subfunctions //
|
||||
/////////////////////////
|
||||
|
||||
function automatic logic [7:0] sbox4_8bit(logic [7:0] state_in, logic [15:0][3:0] sbox4);
|
||||
logic [7:0] state_out;
|
||||
// note that if simulation performance becomes an issue, this loop can be unrolled
|
||||
for (int k = 0; k < 8/4; k++) begin
|
||||
state_out[k*4 +: 4] = sbox4[state_in[k*4 +: 4]];
|
||||
end
|
||||
return state_out;
|
||||
endfunction : sbox4_8bit
|
||||
|
||||
function automatic logic [15:0] sbox4_16bit(logic [15:0] state_in, logic [15:0][3:0] sbox4);
|
||||
logic [15:0] state_out;
|
||||
// note that if simulation performance becomes an issue, this loop can be unrolled
|
||||
for (int k = 0; k < 2; k++) begin
|
||||
state_out[k*8 +: 8] = sbox4_8bit(state_in[k*8 +: 8], sbox4);
|
||||
end
|
||||
return state_out;
|
||||
endfunction : sbox4_16bit
|
||||
|
||||
function automatic logic [31:0] sbox4_32bit(logic [31:0] state_in, logic [15:0][3:0] sbox4);
|
||||
logic [31:0] state_out;
|
||||
// note that if simulation performance becomes an issue, this loop can be unrolled
|
||||
for (int k = 0; k < 32/4; k++) begin
|
||||
state_out[k*4 +: 4] = sbox4[state_in[k*4 +: 4]];
|
||||
for (int k = 0; k < 4; k++) begin
|
||||
state_out[k*8 +: 8] = sbox4_8bit(state_in[k*8 +: 8], sbox4);
|
||||
end
|
||||
return state_out;
|
||||
endfunction : sbox4_32bit
|
||||
|
@ -336,17 +358,35 @@ package prim_cipher_pkg;
|
|||
function automatic logic [63:0] sbox4_64bit(logic [63:0] state_in, logic [15:0][3:0] sbox4);
|
||||
logic [63:0] state_out;
|
||||
// note that if simulation performance becomes an issue, this loop can be unrolled
|
||||
for (int k = 0; k < 64/4; k++) begin
|
||||
state_out[k*4 +: 4] = sbox4[state_in[k*4 +: 4]];
|
||||
for (int k = 0; k < 8; k++) begin
|
||||
state_out[k*8 +: 8] = sbox4_8bit(state_in[k*8 +: 8], sbox4);
|
||||
end
|
||||
return state_out;
|
||||
endfunction : sbox4_64bit
|
||||
|
||||
function automatic logic [7:0] perm_8bit(logic [7:0] state_in, logic [7:0][2:0] perm);
|
||||
logic [7:0] state_out;
|
||||
// note that if simulation performance becomes an issue, this loop can be unrolled
|
||||
for (int k = 0; k < 8; k++) begin
|
||||
state_out[perm[k]] = state_in[k];
|
||||
end
|
||||
return state_out;
|
||||
endfunction : perm_8bit
|
||||
|
||||
function automatic logic [15:0] perm_16bit(logic [15:0] state_in, logic [15:0][3:0] perm);
|
||||
logic [15:0] state_out;
|
||||
// note that if simulation performance becomes an issue, this loop can be unrolled
|
||||
for (int k = 0; k < 16; k++) begin
|
||||
state_out[perm[k]] = state_in[k];
|
||||
end
|
||||
return state_out;
|
||||
endfunction : perm_16bit
|
||||
|
||||
function automatic logic [31:0] perm_32bit(logic [31:0] state_in, logic [31:0][4:0] perm);
|
||||
logic [31:0] state_out;
|
||||
// note that if simulation performance becomes an issue, this loop can be unrolled
|
||||
for (int k = 0; k < 32; k++) begin
|
||||
state_out[k] = state_in[perm[k]];
|
||||
state_out[perm[k]] = state_in[k];
|
||||
end
|
||||
return state_out;
|
||||
endfunction : perm_32bit
|
||||
|
@ -355,7 +395,7 @@ package prim_cipher_pkg;
|
|||
logic [63:0] state_out;
|
||||
// note that if simulation performance becomes an issue, this loop can be unrolled
|
||||
for (int k = 0; k < 64; k++) begin
|
||||
state_out[k] = state_in[perm[k]];
|
||||
state_out[perm[k]] = state_in[k];
|
||||
end
|
||||
return state_out;
|
||||
endfunction : perm_64bit
|
||||
|
|
|
@ -53,7 +53,7 @@ module prim_diff_decode #(
|
|||
|
||||
prim_flop_2sync #(
|
||||
.Width(1),
|
||||
.ResetValue(0)
|
||||
.ResetValue('0)
|
||||
) i_sync_p (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
|
@ -63,7 +63,7 @@ module prim_diff_decode #(
|
|||
|
||||
prim_flop_2sync #(
|
||||
.Width(1),
|
||||
.ResetValue(1)
|
||||
.ResetValue(1'b1)
|
||||
) i_sync_n (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
|
|
6
vendor/lowrisc_ip/prim/rtl/prim_fifo_sync.sv
vendored
6
vendor/lowrisc_ip/prim/rtl/prim_fifo_sync.sv
vendored
|
@ -12,8 +12,7 @@ module prim_fifo_sync #(
|
|||
parameter int unsigned Depth = 4,
|
||||
parameter bit OutputZeroIfEmpty = 1'b1, // if == 1 always output 0 when FIFO is empty
|
||||
// derived parameter
|
||||
localparam int unsigned DepthWNorm = $clog2(Depth+1),
|
||||
localparam int unsigned DepthW = (DepthWNorm == 0) ? 1 : DepthWNorm
|
||||
localparam int DepthW = prim_util_pkg::vbits(Depth+1)
|
||||
) (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
|
@ -51,8 +50,7 @@ module prim_fifo_sync #(
|
|||
// Normal FIFO construction
|
||||
end else begin : gen_normal_fifo
|
||||
|
||||
// consider Depth == 1 case when $clog2(1) == 0
|
||||
localparam int unsigned PTRV_W = $clog2(Depth) + ~|$clog2(Depth);
|
||||
localparam int unsigned PTRV_W = prim_util_pkg::vbits(Depth);
|
||||
localparam int unsigned PTR_WIDTH = PTRV_W+1;
|
||||
|
||||
logic [PTR_WIDTH-1:0] fifo_wptr, fifo_rptr;
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
module prim_flop_2sync #(
|
||||
parameter int Width = 16,
|
||||
parameter bit ResetValue = 0
|
||||
parameter logic [Width-1:0] ResetValue = '0
|
||||
) (
|
||||
input clk_i, // receive clock
|
||||
input rst_ni,
|
||||
|
@ -18,8 +18,8 @@ module prim_flop_2sync #(
|
|||
|
||||
always_ff @(posedge clk_i or negedge rst_ni)
|
||||
if (!rst_ni) begin
|
||||
intq <= {Width{ResetValue}};
|
||||
q <= {Width{ResetValue}};
|
||||
intq <= ResetValue;
|
||||
q <= ResetValue;
|
||||
end else begin
|
||||
intq <= d;
|
||||
q <= intq;
|
||||
|
|
6
vendor/lowrisc_ip/prim/rtl/prim_packer.sv
vendored
6
vendor/lowrisc_ip/prim/rtl/prim_packer.sv
vendored
|
@ -200,8 +200,10 @@ module prim_packer #(
|
|||
// Assumption: mask_i should be contiguous ones
|
||||
// e.g: 0011100 --> OK
|
||||
// 0100011 --> Not OK
|
||||
`ASSUME(ContiguousOnesMask_M,
|
||||
valid_i |-> $countones(mask_i ^ {mask_i[InW-2:0],1'b0}) <= 2)
|
||||
if (InW > 1) begin : gen_mask_assert
|
||||
`ASSUME(ContiguousOnesMask_M,
|
||||
valid_i |-> $countones(mask_i ^ {mask_i[InW-2:0],1'b0}) <= 2)
|
||||
end
|
||||
|
||||
// Assume data pattern to reduce FPV test time
|
||||
//`ASSUME_FPV(FpvDataWithin_M,
|
||||
|
|
114
vendor/lowrisc_ip/prim/rtl/prim_prince.sv
vendored
114
vendor/lowrisc_ip/prim/rtl/prim_prince.sv
vendored
|
@ -2,15 +2,14 @@
|
|||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
// This module is an implementation of the 64bit PRINCE block cipher. It is a
|
||||
// fully unrolled combinational implementation with configurable number of
|
||||
// rounds. Due to the reflective construction of this cipher, the same circuit
|
||||
// can be used for encryption and decryption, as described below. Further, the
|
||||
// primitive supports a 32bit block cipher flavor which is not specified in the
|
||||
// original paper. It should be noted, however, that the 32bit version is
|
||||
// **not** secure and must not be used in a setting where cryptographic cipher
|
||||
// strength is required. The 32bit variant is only intended to be used as a
|
||||
// lightweight data scrambling device.
|
||||
// This module is an implementation of the 64bit PRINCE block cipher. It is a fully unrolled
|
||||
// combinational implementation with configurable number of rounds. Optionally, registers for the
|
||||
// data and key states can be enabled, if this is required. Due to the reflective construction of
|
||||
// this cipher, the same circuit can be used for encryption and decryption, as described below.
|
||||
// Further, the primitive supports a 32bit block cipher flavor which is not specified in the
|
||||
// original paper. It should be noted, however, that the 32bit version is **not** secure and must
|
||||
// not be used in a setting where cryptographic cipher strength is required. The 32bit variant is
|
||||
// only intended to be used as a lightweight data scrambling device.
|
||||
//
|
||||
// See also: prim_present, prim_cipher_pkg
|
||||
//
|
||||
|
@ -33,11 +32,20 @@ module prim_prince #(
|
|||
parameter int NumRoundsHalf = 5,
|
||||
// This primitive uses the new key schedule proposed in https://eprint.iacr.org/2014/656.pdf
|
||||
// Setting this parameter to 1 falls back to the original key schedule.
|
||||
parameter bit UseOldKeySched = 1'b0
|
||||
parameter bit UseOldKeySched = 1'b0,
|
||||
// This instantiates a data register halfway in the primitive.
|
||||
parameter bit HalfwayDataReg = 1'b0,
|
||||
// This instantiates a key register halfway in the primitive.
|
||||
parameter bit HalfwayKeyReg = 1'b0
|
||||
) (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
|
||||
input valid_i,
|
||||
input [DataWidth-1:0] data_i,
|
||||
input [KeyWidth-1:0] key_i,
|
||||
input dec_i, // set to 1 for decryption
|
||||
input dec_i, // set to 1 for decryption
|
||||
output logic valid_o,
|
||||
output logic [DataWidth-1:0] data_o
|
||||
);
|
||||
|
||||
|
@ -45,26 +53,46 @@ module prim_prince #(
|
|||
// key expansion //
|
||||
///////////////////
|
||||
|
||||
logic [DataWidth-1:0] k0, k0_prime, k1, k0_new;
|
||||
|
||||
logic [DataWidth-1:0] k0, k0_prime_d, k1_d, k0_new_d, k0_prime_q, k1_q, k0_new_q;
|
||||
always_comb begin : p_key_expansion
|
||||
k0 = key_i[DataWidth-1:0];
|
||||
k0_prime = {k0[0], k0[DataWidth-1:2], k0[DataWidth-1] ^ k0[1]};
|
||||
k1 = key_i[2*DataWidth-1 : DataWidth];
|
||||
k0 = key_i[DataWidth-1:0];
|
||||
k0_prime_d = {k0[0], k0[DataWidth-1:2], k0[DataWidth-1] ^ k0[1]};
|
||||
k1_d = key_i[2*DataWidth-1 : DataWidth];
|
||||
|
||||
// modify key for decryption
|
||||
if (dec_i) begin
|
||||
k0 = k0_prime;
|
||||
k0_prime = key_i[DataWidth-1:0];
|
||||
k1 ^= prim_cipher_pkg::PRINCE_ALPHA_CONST[DataWidth-1:0];
|
||||
k0 = k0_prime_d;
|
||||
k0_prime_d = key_i[DataWidth-1:0];
|
||||
k1_d ^= prim_cipher_pkg::PRINCE_ALPHA_CONST[DataWidth-1:0];
|
||||
end
|
||||
end
|
||||
|
||||
if (UseOldKeySched) begin : gen_legacy_keyschedule
|
||||
assign k0_new = k1;
|
||||
assign k0_new_d = k1_d;
|
||||
end else begin : gen_new_keyschedule
|
||||
// improved keyschedule proposed by https://eprint.iacr.org/2014/656.pdf
|
||||
assign k0_new = k0;
|
||||
assign k0_new_d = k0;
|
||||
end
|
||||
|
||||
if (HalfwayKeyReg) begin : gen_key_reg
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin : p_key_reg
|
||||
if (!rst_ni) begin
|
||||
k1_q <= '0;
|
||||
k0_prime_q <= '0;
|
||||
k0_new_q <= '0;
|
||||
end else begin
|
||||
if (valid_i) begin
|
||||
k1_q <= k1_d;
|
||||
k0_prime_q <= k0_prime_d;
|
||||
k0_new_q <= k0_new_d;
|
||||
end
|
||||
end
|
||||
end
|
||||
end else begin : gen_no_key_reg
|
||||
// just pass the key through in this case
|
||||
assign k1_q = k1_d;
|
||||
assign k0_prime_q = k0_prime_d;
|
||||
assign k0_new_q = k0_new_d;
|
||||
end
|
||||
|
||||
//////////////
|
||||
|
@ -77,7 +105,7 @@ module prim_prince #(
|
|||
// pre-round XOR
|
||||
always_comb begin : p_pre_round_xor
|
||||
data_state[0] = data_i ^ k0;
|
||||
data_state[0] ^= k1;
|
||||
data_state[0] ^= k1_d;
|
||||
data_state[0] ^= prim_cipher_pkg::PRINCE_ROUND_CONST[0][DataWidth-1:0];
|
||||
end
|
||||
|
||||
|
@ -105,38 +133,58 @@ module prim_prince #(
|
|||
assign data_state_xor = data_state_round ^
|
||||
prim_cipher_pkg::PRINCE_ROUND_CONST[k][DataWidth-1:0];
|
||||
// improved keyschedule proposed by https://eprint.iacr.org/2014/656.pdf
|
||||
if (k % 2 == 1) assign data_state[k] = data_state_xor ^ k0_new;
|
||||
else assign data_state[k] = data_state_xor ^ k1;
|
||||
if (k % 2 == 1) assign data_state[k] = data_state_xor ^ k0_new_d;
|
||||
else assign data_state[k] = data_state_xor ^ k1_d;
|
||||
end
|
||||
|
||||
// middle part
|
||||
logic [DataWidth-1:0] data_state_middle;
|
||||
logic [DataWidth-1:0] data_state_middle_d, data_state_middle_q, data_state_middle;
|
||||
if (DataWidth == 64) begin : gen_middle_d64
|
||||
always_comb begin : p_middle_d64
|
||||
data_state_middle = prim_cipher_pkg::sbox4_64bit(data_state[NumRoundsHalf],
|
||||
data_state_middle_d = prim_cipher_pkg::sbox4_64bit(data_state[NumRoundsHalf],
|
||||
prim_cipher_pkg::PRINCE_SBOX4);
|
||||
data_state_middle = prim_cipher_pkg::prince_mult_prime_64bit(data_state_middle);
|
||||
data_state_middle = prim_cipher_pkg::prince_mult_prime_64bit(data_state_middle_q);
|
||||
data_state_middle = prim_cipher_pkg::sbox4_64bit(data_state_middle,
|
||||
prim_cipher_pkg::PRINCE_SBOX4_INV);
|
||||
end
|
||||
end else begin : gen_middle_d32
|
||||
always_comb begin : p_middle_d32
|
||||
data_state_middle = prim_cipher_pkg::sbox4_32bit(data_state_middle[NumRoundsHalf],
|
||||
data_state_middle_d = prim_cipher_pkg::sbox4_32bit(data_state_middle[NumRoundsHalf],
|
||||
prim_cipher_pkg::PRINCE_SBOX4);
|
||||
data_state_middle = prim_cipher_pkg::prince_mult_prime_32bit(data_state_middle);
|
||||
data_state_middle = prim_cipher_pkg::prince_mult_prime_32bit(data_state_middle_q);
|
||||
data_state_middle = prim_cipher_pkg::sbox4_32bit(data_state_middle,
|
||||
prim_cipher_pkg::PRINCE_SBOX4_INV);
|
||||
end
|
||||
end
|
||||
|
||||
if (HalfwayDataReg) begin : gen_data_reg
|
||||
logic valid_q;
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin : p_data_reg
|
||||
if (!rst_ni) begin
|
||||
valid_q <= 1'b0;
|
||||
data_state_middle_q <= '0;
|
||||
end else begin
|
||||
valid_q <= valid_i;
|
||||
if (valid_i) begin
|
||||
data_state_middle_q <= data_state_middle_d;
|
||||
end
|
||||
end
|
||||
end
|
||||
assign valid_o = valid_q;
|
||||
end else begin : gen_no_data_reg
|
||||
// just pass data through in this case
|
||||
assign data_state_middle_q = data_state_middle_d;
|
||||
assign valid_o = valid_i;
|
||||
end
|
||||
|
||||
assign data_state[NumRoundsHalf+1] = data_state_middle;
|
||||
|
||||
// backward pass
|
||||
for (genvar k = 1; k <= NumRoundsHalf; k++) begin : gen_bwd_pass
|
||||
logic [DataWidth-1:0] data_state_xor0, data_state_xor1;
|
||||
// improved keyschedule proposed by https://eprint.iacr.org/2014/656.pdf
|
||||
if (k % 2 == 1) assign data_state_xor0 = data_state[NumRoundsHalf+k] ^ k0_new;
|
||||
else assign data_state_xor0 = data_state[NumRoundsHalf+k] ^ k1;
|
||||
if (k % 2 == 1) assign data_state_xor0 = data_state[NumRoundsHalf+k] ^ k0_new_q;
|
||||
else assign data_state_xor0 = data_state[NumRoundsHalf+k] ^ k1_q;
|
||||
// the construction is reflective, hence the subtraction with NumRoundsHalf
|
||||
assign data_state_xor1 = data_state_xor0 ^
|
||||
prim_cipher_pkg::PRINCE_ROUND_CONST[10-NumRoundsHalf+k][DataWidth-1:0];
|
||||
|
@ -165,8 +213,8 @@ module prim_prince #(
|
|||
always_comb begin : p_post_round_xor
|
||||
data_o = data_state[2*NumRoundsHalf+1] ^
|
||||
prim_cipher_pkg::PRINCE_ROUND_CONST[11][DataWidth-1:0];
|
||||
data_o ^= k1;
|
||||
data_o ^= k0_prime;
|
||||
data_o ^= k1_q;
|
||||
data_o ^= k0_prime_q;
|
||||
end
|
||||
|
||||
////////////////
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
// mask cannot be used and has to be tied to {Width{1'b1}}.
|
||||
|
||||
`include "prim_assert.sv"
|
||||
`include "prim_util.svh"
|
||||
|
||||
module prim_ram_1p_adv #(
|
||||
parameter int Depth = 512,
|
||||
|
@ -29,7 +28,7 @@ module prim_ram_1p_adv #(
|
|||
parameter bit EnableInputPipeline = 0, // Adds an input register (read latency +1)
|
||||
parameter bit EnableOutputPipeline = 0, // Adds an output register (read latency +1)
|
||||
|
||||
localparam int Aw = vbits(Depth)
|
||||
localparam int Aw = prim_util_pkg::vbits(Depth)
|
||||
) (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
|
@ -47,6 +46,8 @@ module prim_ram_1p_adv #(
|
|||
input [CfgW-1:0] cfg_i
|
||||
);
|
||||
|
||||
logic [CfgW-1:0] unused_cfg = cfg_i;
|
||||
|
||||
`ASSERT_INIT(CannotHaveEccAndParity_A, !(EnableParity && EnableECC))
|
||||
|
||||
// While we require DataBitsPerMask to be per Byte (8) at the interface in case Byte parity is
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
// mask cannot be used and has to be tied to {Width{1'b1}}.
|
||||
|
||||
`include "prim_assert.sv"
|
||||
`include "prim_util.svh"
|
||||
|
||||
module prim_ram_2p_adv #(
|
||||
parameter int Depth = 512,
|
||||
|
@ -29,7 +28,7 @@ module prim_ram_2p_adv #(
|
|||
parameter bit EnableInputPipeline = 0, // Adds an input register (read latency +1)
|
||||
parameter bit EnableOutputPipeline = 0, // Adds an output register (read latency +1)
|
||||
|
||||
localparam int Aw = vbits(Depth)
|
||||
localparam int Aw = prim_util_pkg::vbits(Depth)
|
||||
) (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
// mask cannot be used and has to be tied to {Width{1'b1}}.
|
||||
|
||||
`include "prim_assert.sv"
|
||||
`include "prim_util.svh"
|
||||
|
||||
module prim_ram_2p_async_adv #(
|
||||
parameter int Depth = 512,
|
||||
|
@ -29,7 +28,7 @@ module prim_ram_2p_async_adv #(
|
|||
parameter bit EnableInputPipeline = 0, // Adds an input register (read latency +1)
|
||||
parameter bit EnableOutputPipeline = 0, // Adds an output register (read latency +1)
|
||||
|
||||
localparam int Aw = vbits(Depth)
|
||||
localparam int Aw = prim_util_pkg::vbits(Depth)
|
||||
) (
|
||||
input clk_a_i,
|
||||
input clk_b_i,
|
||||
|
@ -58,6 +57,8 @@ module prim_ram_2p_async_adv #(
|
|||
input [CfgW-1:0] cfg_i
|
||||
);
|
||||
|
||||
logic [CfgW-1:0] unused_cfg = cfg_i;
|
||||
|
||||
`ASSERT_INIT(CannotHaveEccAndParity_A, !(EnableParity && EnableECC))
|
||||
|
||||
// While we require DataBitsPerMask to be per Byte (8) at the interface in case Byte parity is
|
||||
|
|
|
@ -76,7 +76,7 @@ module prim_sram_arbiter #(
|
|||
.ready_i ( 1'b1 )
|
||||
);
|
||||
end else if (ArbiterImpl == "BINTREE") begin : gen_tree_arb
|
||||
prim_arbiter_arb #(
|
||||
prim_arbiter_tree #(
|
||||
.N (N),
|
||||
.DW(ARB_DW)
|
||||
) u_reqarb (
|
||||
|
|
47
vendor/lowrisc_ip/prim/rtl/prim_util.svh
vendored
47
vendor/lowrisc_ip/prim/rtl/prim_util.svh
vendored
|
@ -1,47 +0,0 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Utility macros
|
||||
|
||||
`ifndef PRIM_UTIL_SVH
|
||||
`define PRIM_UTIL_SVH
|
||||
|
||||
/**
|
||||
* Math function: Number of bits needed to address |value| items.
|
||||
*
|
||||
* 0 for value == 0
|
||||
* vbits = 1 for value == 1
|
||||
* ceil(log2(value)) for value > 1
|
||||
*
|
||||
*
|
||||
* The primary use case for this function is the definition of registers/arrays
|
||||
* which are wide enough to contain |value| items.
|
||||
*
|
||||
* This function identical to $clog2() for all input values except the value 1;
|
||||
* it could be considered an "enhanced" $clog2() function.
|
||||
*
|
||||
*
|
||||
* Example 1:
|
||||
* parameter Items = 1;
|
||||
* localparam ItemsWidth = vbits(Items); // 1
|
||||
* logic [ItemsWidth-1:0] item_register; // items_register is now [0:0]
|
||||
*
|
||||
* Example 2:
|
||||
* parameter Items = 64;
|
||||
* localparam ItemsWidth = vbits(Items); // 6
|
||||
* logic [ItemsWidth-1:0] item_register; // items_register is now [5:0]
|
||||
*
|
||||
* Note: If you want to store the number "value" inside a register, you need
|
||||
* a register with size vbits(value + 1), since you also need to store
|
||||
* the number 0.
|
||||
*
|
||||
* Example 3:
|
||||
* logic [vbits(64)-1:0] store_64_logic_values; // width is [5:0]
|
||||
* logic [vbits(64 + 1)-1:0] store_number_64; // width is [6:0]
|
||||
*/
|
||||
function automatic integer vbits(integer value);
|
||||
return (value == 1) ? 1 : $clog2(value);
|
||||
endfunction
|
||||
|
||||
`endif // PRIM_UTIL_SVH
|
26
vendor/lowrisc_ip/prim/rtl/prim_util_memload.sv
vendored
26
vendor/lowrisc_ip/prim/rtl/prim_util_memload.sv
vendored
|
@ -30,10 +30,10 @@
|
|||
export "DPI-C" function simutil_verilator_set_mem;
|
||||
|
||||
function int simutil_verilator_set_mem(input int index,
|
||||
input bit [127:0] val);
|
||||
input bit [255:0] val);
|
||||
|
||||
// Function will only work for memories <= 128 bits
|
||||
if (Width > 128) begin
|
||||
// Function will only work for memories <= 256 bits
|
||||
if (Width > 256) begin
|
||||
return 0;
|
||||
end
|
||||
|
||||
|
@ -44,6 +44,26 @@
|
|||
mem[index] = val[Width-1:0];
|
||||
return 1;
|
||||
endfunction
|
||||
|
||||
// Function for getting a specific element in |mem|
|
||||
export "DPI-C" function simutil_verilator_get_mem;
|
||||
|
||||
function int simutil_verilator_get_mem(input int index,
|
||||
output bit [255:0] val);
|
||||
|
||||
// Function will only work for memories <= 256 bits
|
||||
if (Width > 256) begin
|
||||
return 0;
|
||||
end
|
||||
|
||||
if (index >= Depth) begin
|
||||
return 0;
|
||||
end
|
||||
|
||||
val = 0;
|
||||
val[Width-1:0] = mem[index];
|
||||
return 1;
|
||||
endfunction
|
||||
`endif
|
||||
|
||||
initial begin
|
||||
|
|
86
vendor/lowrisc_ip/prim/rtl/prim_util_pkg.sv
vendored
Normal file
86
vendor/lowrisc_ip/prim/rtl/prim_util_pkg.sv
vendored
Normal file
|
@ -0,0 +1,86 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
|
||||
/**
|
||||
* Utility functions
|
||||
*/
|
||||
package prim_util_pkg;
|
||||
/**
|
||||
* Math function: $clog2 as specified in Verilog-2005
|
||||
*
|
||||
* Do not use this function if $clog2() is available.
|
||||
*
|
||||
* clog2 = 0 for value == 0
|
||||
* ceil(log2(value)) for value >= 1
|
||||
*
|
||||
* This implementation is a synthesizable variant of the $clog2 function as
|
||||
* specified in the Verilog-2005 standard (IEEE 1364-2005).
|
||||
*
|
||||
* To quote the standard:
|
||||
* The system function $clog2 shall return the ceiling of the log
|
||||
* base 2 of the argument (the log rounded up to an integer
|
||||
* value). The argument can be an integer or an arbitrary sized
|
||||
* vector value. The argument shall be treated as an unsigned
|
||||
* value, and an argument value of 0 shall produce a result of 0.
|
||||
*/
|
||||
function automatic integer _clog2(integer value);
|
||||
integer result;
|
||||
value = value - 1;
|
||||
for (result = 0; value > 0; result = result + 1) begin
|
||||
value = value >> 1;
|
||||
end
|
||||
return result;
|
||||
endfunction
|
||||
|
||||
|
||||
/**
|
||||
* Math function: Number of bits needed to address |value| items.
|
||||
*
|
||||
* 0 for value == 0
|
||||
* vbits = 1 for value == 1
|
||||
* ceil(log2(value)) for value > 1
|
||||
*
|
||||
*
|
||||
* The primary use case for this function is the definition of registers/arrays
|
||||
* which are wide enough to contain |value| items.
|
||||
*
|
||||
* This function identical to $clog2() for all input values except the value 1;
|
||||
* it could be considered an "enhanced" $clog2() function.
|
||||
*
|
||||
*
|
||||
* Example 1:
|
||||
* parameter Items = 1;
|
||||
* localparam ItemsWidth = vbits(Items); // 1
|
||||
* logic [ItemsWidth-1:0] item_register; // items_register is now [0:0]
|
||||
*
|
||||
* Example 2:
|
||||
* parameter Items = 64;
|
||||
* localparam ItemsWidth = vbits(Items); // 6
|
||||
* logic [ItemsWidth-1:0] item_register; // items_register is now [5:0]
|
||||
*
|
||||
* Note: If you want to store the number "value" inside a register, you need
|
||||
* a register with size vbits(value + 1), since you also need to store
|
||||
* the number 0.
|
||||
*
|
||||
* Example 3:
|
||||
* logic [vbits(64)-1:0] store_64_logic_values; // width is [5:0]
|
||||
* logic [vbits(64 + 1)-1:0] store_number_64; // width is [6:0]
|
||||
*/
|
||||
function automatic integer vbits(integer value);
|
||||
`ifdef XCELIUM
|
||||
// The use of system functions was not allowed here in Verilog-2001, but is
|
||||
// valid since (System)Verilog-2005, which is also when $clog2() first
|
||||
// appeared.
|
||||
// Xcelium < 19.10 does not yet support the use of $clog2() here, fall back
|
||||
// to an implementation without a system function. Remove this workaround
|
||||
// if we require a newer Xcelium version.
|
||||
// See #2579 and #2597.
|
||||
return (value == 1) ? 1 : prim_util_pkg::_clog2(value);
|
||||
`else
|
||||
return (value == 1) ? 1 : $clog2(value);
|
||||
`endif
|
||||
endfunction
|
||||
|
||||
endpackage
|
3
vendor/lowrisc_ip/prim/util/primgen.py
vendored
3
vendor/lowrisc_ip/prim/util/primgen.py
vendored
|
@ -383,7 +383,8 @@ def _get_action_from_gapi(gapi, default_action):
|
|||
|
||||
def main():
|
||||
gapi_filepath = sys.argv[1]
|
||||
gapi = yaml.load(open(gapi_filepath), Loader=YamlLoader)
|
||||
with open(gapi_filepath) as f:
|
||||
gapi = yaml.load(f, Loader=YamlLoader)
|
||||
|
||||
if not _check_gapi(gapi):
|
||||
sys.exit(1)
|
||||
|
|
|
@ -9,6 +9,7 @@ filesets:
|
|||
files_rtl:
|
||||
depend:
|
||||
- lowrisc:prim:ram_1p
|
||||
- lowrisc:ip:flash_ctrl_pkg
|
||||
files:
|
||||
- rtl/prim_generic_flash.sv
|
||||
file_type: systemVerilogSource
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
//
|
||||
|
||||
module prim_generic_flash #(
|
||||
parameter int PagesPerBank = 256, // pages per bank
|
||||
parameter int InfosPerBank = 1, // info pages per bank
|
||||
parameter int PagesPerBank = 256, // data pages per bank
|
||||
parameter int WordsPerPage = 256, // words per page
|
||||
parameter int DataWidth = 32, // bits per word
|
||||
parameter bit SkipInit = 1, // this is an option to reset flash to all F's at reset
|
||||
|
@ -16,17 +17,18 @@ module prim_generic_flash #(
|
|||
localparam int WordW = $clog2(WordsPerPage),
|
||||
localparam int AddrW = PageW + WordW
|
||||
) (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
input rd_i,
|
||||
input prog_i,
|
||||
input pg_erase_i,
|
||||
input bk_erase_i,
|
||||
input [AddrW-1:0] addr_i,
|
||||
input [DataWidth-1:0] prog_data_i,
|
||||
output logic ack_o,
|
||||
output logic [DataWidth-1:0] rd_data_o,
|
||||
output logic init_busy_o
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
input rd_i,
|
||||
input prog_i,
|
||||
input pg_erase_i,
|
||||
input bk_erase_i,
|
||||
input [AddrW-1:0] addr_i,
|
||||
input flash_ctrl_pkg::flash_part_e part_i,
|
||||
input [DataWidth-1:0] prog_data_i,
|
||||
output logic ack_o,
|
||||
output logic [DataWidth-1:0] rd_data_o,
|
||||
output logic init_busy_o
|
||||
);
|
||||
|
||||
// Emulated flash macro values
|
||||
|
@ -37,6 +39,8 @@ module prim_generic_flash #(
|
|||
|
||||
// Locally derived values
|
||||
localparam int WordsPerBank = PagesPerBank * WordsPerPage;
|
||||
localparam int WordsPerInfoBank = InfosPerBank * WordsPerPage;
|
||||
localparam int InfoAddrW = $clog2(WordsPerInfoBank);
|
||||
|
||||
typedef enum logic [2:0] {
|
||||
StReset = 'h0,
|
||||
|
@ -59,18 +63,21 @@ module prim_generic_flash #(
|
|||
logic mem_req;
|
||||
logic mem_wr;
|
||||
logic [AddrW-1:0] mem_addr;
|
||||
flash_ctrl_pkg::flash_part_e mem_part;
|
||||
logic [DataWidth-1:0] held_rdata;
|
||||
logic [DataWidth-1:0] held_wdata;
|
||||
logic [DataWidth-1:0] mem_wdata;
|
||||
logic hold_cmd;
|
||||
logic [AddrW-1:0] held_addr;
|
||||
flash_ctrl_pkg::flash_part_e held_part;
|
||||
|
||||
// insert a fifo here to break the large fanout from inputs to memories on reads
|
||||
logic rd_q;
|
||||
logic [AddrW-1:0] addr_q;
|
||||
flash_ctrl_pkg::flash_part_e part_q;
|
||||
|
||||
prim_fifo_sync #(
|
||||
.Width (AddrW),
|
||||
.Width (AddrW + $bits(flash_ctrl_pkg::flash_part_e)),
|
||||
.Pass (0),
|
||||
.Depth (2)
|
||||
) i_slice (
|
||||
|
@ -79,11 +86,11 @@ module prim_generic_flash #(
|
|||
.clr_i (1'b0),
|
||||
.wvalid (rd_i),
|
||||
.wready (),
|
||||
.wdata (addr_i),
|
||||
.wdata ({part_i, addr_i}),
|
||||
.depth (),
|
||||
.rvalid (rd_q),
|
||||
.rready (hold_cmd), //whenver command is held, pop
|
||||
.rdata (addr_q)
|
||||
.rdata ({part_q, addr_q})
|
||||
);
|
||||
|
||||
|
||||
|
@ -95,9 +102,11 @@ 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_wdata <= '0;
|
||||
end else if (hold_cmd) begin
|
||||
held_addr <= rd_q ? addr_q : addr_i;
|
||||
held_part <= rd_q ? part_q : part_i;
|
||||
held_wdata <= prog_data_i;
|
||||
end
|
||||
end
|
||||
|
@ -146,6 +155,7 @@ module prim_generic_flash #(
|
|||
mem_req = 'h0;
|
||||
mem_wr = 'h0;
|
||||
mem_addr = 'h0;
|
||||
mem_part = flash_ctrl_pkg::DataPart;
|
||||
mem_wdata = 'h0;
|
||||
time_cnt_inc = 1'h0;
|
||||
time_cnt_clr = 1'h0;
|
||||
|
@ -185,6 +195,7 @@ module prim_generic_flash #(
|
|||
// reads begin immediately
|
||||
hold_cmd = 1'b1;
|
||||
mem_addr = addr_q;
|
||||
mem_part = part_q;
|
||||
mem_req = 1'b1;
|
||||
time_cnt_inc = 1'b1;
|
||||
st_d = StRead;
|
||||
|
@ -206,6 +217,7 @@ module prim_generic_flash #(
|
|||
end
|
||||
StRead: begin
|
||||
mem_addr = held_addr;
|
||||
mem_part = held_part;
|
||||
if (time_cnt < ReadCycles) begin
|
||||
mem_req = 1'b1;
|
||||
time_cnt_inc = 1'b1;
|
||||
|
@ -216,6 +228,7 @@ module prim_generic_flash #(
|
|||
if (rd_q) begin
|
||||
hold_cmd = 1'b1;
|
||||
mem_addr = addr_q;
|
||||
mem_part = part_q;
|
||||
mem_req = 1'b1;
|
||||
time_cnt_set1 = 1'b1;
|
||||
st_d = StRead;
|
||||
|
@ -232,6 +245,7 @@ module prim_generic_flash #(
|
|||
end
|
||||
StProg: begin
|
||||
mem_addr = held_addr;
|
||||
mem_part = held_part;
|
||||
|
||||
// if data is already 0, cannot program to 1 without erase
|
||||
mem_wdata = held_wdata & held_rdata;
|
||||
|
@ -253,6 +267,7 @@ module prim_generic_flash #(
|
|||
mem_wdata = {DataWidth{1'b1}};
|
||||
|
||||
mem_addr = held_addr + index_cnt[AddrW-1:0];
|
||||
mem_part = held_part;
|
||||
time_cnt_inc = (time_cnt < time_limit_q);
|
||||
index_cnt_inc = (index_cnt < index_limit_q);
|
||||
end else begin
|
||||
|
@ -268,18 +283,36 @@ module prim_generic_flash #(
|
|||
endcase // unique case (st_q)
|
||||
end // always_comb
|
||||
|
||||
logic [DataWidth-1:0] rd_data_main, rd_data_info;
|
||||
|
||||
prim_ram_1p #(
|
||||
.Width(DataWidth),
|
||||
.Depth(WordsPerBank),
|
||||
.DataBitsPerMask(DataWidth)
|
||||
) u_mem (
|
||||
.clk_i,
|
||||
.req_i (mem_req),
|
||||
.req_i (mem_req & (mem_part == flash_ctrl_pkg::DataPart)),
|
||||
.write_i (mem_wr),
|
||||
.addr_i (mem_addr),
|
||||
.wdata_i (mem_wdata),
|
||||
.wmask_i ({DataWidth{1'b1}}),
|
||||
.rdata_o (rd_data_o)
|
||||
.rdata_o (rd_data_main)
|
||||
);
|
||||
|
||||
prim_ram_1p #(
|
||||
.Width(DataWidth),
|
||||
.Depth(WordsPerInfoBank),
|
||||
.DataBitsPerMask(DataWidth)
|
||||
) u_info_mem (
|
||||
.clk_i,
|
||||
.req_i (mem_req & (mem_part == flash_ctrl_pkg::InfoPart)),
|
||||
.write_i (mem_wr),
|
||||
.addr_i (mem_addr[0 +: InfoAddrW]),
|
||||
.wdata_i (mem_wdata),
|
||||
.wmask_i ({DataWidth{1'b1}}),
|
||||
.rdata_o (rd_data_info)
|
||||
);
|
||||
|
||||
assign rd_data_o = held_part == flash_ctrl_pkg::DataPart ? rd_data_main : rd_data_info;
|
||||
|
||||
endmodule // prim_generic_flash
|
||||
|
|
|
@ -31,10 +31,13 @@ module prim_generic_ram_1p #(
|
|||
logic [Width-1:0] mem [Depth];
|
||||
logic [MaskWidth-1:0] wmask;
|
||||
|
||||
always_comb begin
|
||||
for (int i=0; i < MaskWidth; i = i + 1) begin : create_wmask
|
||||
wmask[i] = &wmask_i[i*DataBitsPerMask +: DataBitsPerMask];
|
||||
end
|
||||
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 |->
|
||||
wmask_i[k*DataBitsPerMask +: DataBitsPerMask] inside {{DataBitsPerMask{1'b1}}, '0},
|
||||
clk_i, '0)
|
||||
end
|
||||
|
||||
// using always instead of always_ff to avoid 'ICPD - illegal combination of drivers' error
|
||||
|
|
|
@ -40,13 +40,18 @@ module prim_generic_ram_2p #(
|
|||
logic [MaskWidth-1:0] a_wmask;
|
||||
logic [MaskWidth-1:0] b_wmask;
|
||||
|
||||
always_comb begin
|
||||
for (int i=0; i < MaskWidth; i = i + 1) begin : create_wmask
|
||||
a_wmask[i] = &a_wmask_i[i*DataBitsPerMask +: DataBitsPerMask];
|
||||
b_wmask[i] = &b_wmask_i[i*DataBitsPerMask +: DataBitsPerMask];
|
||||
end
|
||||
end
|
||||
for (genvar k = 0; k < MaskWidth; k++) begin : gen_wmask
|
||||
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 |->
|
||||
a_wmask_i[k*DataBitsPerMask +: DataBitsPerMask] inside {{DataBitsPerMask{1'b1}}, '0},
|
||||
clk_a_i, '0)
|
||||
`ASSERT(MaskCheckPortB_A, b_req_i |->
|
||||
b_wmask_i[k*DataBitsPerMask +: DataBitsPerMask] inside {{DataBitsPerMask{1'b1}}, '0},
|
||||
clk_b_i, '0)
|
||||
end
|
||||
|
||||
// Xilinx FPGA specific Dual-port RAM coding style
|
||||
// using always instead of always_ff to avoid 'ICPD - illegal combination of drivers' error
|
||||
|
|
8
vendor/lowrisc_ip/uvmdvgen/checklist.md.tpl
vendored
8
vendor/lowrisc_ip/uvmdvgen/checklist.md.tpl
vendored
|
@ -57,6 +57,9 @@ Code Quality | [LINT_PASS][] | Not Started |
|
|||
Code Quality | [CDC_SETUP][] | Not Started |
|
||||
Code Quality | [FPGA_TIMING][] | Not Started |
|
||||
Code Quality | [CDC_SYNCMACRO][] | Not Started |
|
||||
Security | [SEC_CM_IMPLEMENTED][] | Not Started |
|
||||
Security | [SEC_NON_RESET_FLOPS][] | Not Started |
|
||||
Security | [SEC_SHADOW_REGS][] | Not Started |
|
||||
Review | Reviewer(s) | Not Started |
|
||||
Review | Signoff date | Not Started |
|
||||
|
||||
|
@ -73,8 +76,11 @@ Review | Signoff date | Not Started |
|
|||
[STYLE_X]: {{<relref "/doc/project/checklist.md#style-x" >}}
|
||||
[LINT_PASS]: {{<relref "/doc/project/checklist.md#lint-pass" >}}
|
||||
[CDC_SETUP]: {{<relref "/doc/project/checklist.md#cdc-setup" >}}
|
||||
[CDC_SYNCMACRO]: {{<relref "/doc/project/checklist.md#cdc-syncmacro" >}}
|
||||
[FPGA_TIMING]: {{<relref "/doc/project/checklist.md#fpga-timing" >}}
|
||||
[CDC_SYNCMACRO]: {{<relref "/doc/project/checklist.md#cdc-syncmacro" >}}
|
||||
[SEC_CM_IMPLEMENTED]: {{<relref "/doc/project/checklist.md#sec-cm-implemented" >}}
|
||||
[SEC_NON_RESET_FLOPS]: {{<relref "/doc/project/checklist.md#sec-non-reset-flops" >}}
|
||||
[SEC_SHADOW_REGS]: {{<relref "/doc/project/checklist.md#sec-shadow-regs" >}}
|
||||
|
||||
### D3
|
||||
|
||||
|
|
25
vendor/lowrisc_ip/uvmdvgen/scoreboard.sv.tpl
vendored
25
vendor/lowrisc_ip/uvmdvgen/scoreboard.sv.tpl
vendored
|
@ -66,6 +66,11 @@ class ${name}_scoreboard extends dv_base_scoreboard #(
|
|||
bit write = item.is_write();
|
||||
uvm_reg_addr_t csr_addr = get_normalized_addr(item.a_addr);
|
||||
|
||||
bit addr_phase_read = (!write && channel == AddrChannel);
|
||||
bit addr_phase_write = (write && channel == AddrChannel);
|
||||
bit data_phase_read = (!write && channel == DataChannel);
|
||||
bit data_phase_write = (write && channel == DataChannel);
|
||||
|
||||
// if access was to a valid csr, get the csr handle
|
||||
if (csr_addr inside {cfg.csr_addrs}) begin
|
||||
csr = ral.default_map.get_reg_by_offset(csr_addr);
|
||||
|
@ -75,11 +80,9 @@ class ${name}_scoreboard extends dv_base_scoreboard #(
|
|||
`uvm_fatal(`gfn, $sformatf("Access unexpected addr 0x%0h", csr_addr))
|
||||
end
|
||||
|
||||
if (channel == AddrChannel) begin
|
||||
// if incoming access is a write to a valid csr, then make updates right away
|
||||
if (write) begin
|
||||
void'(csr.predict(.value(item.a_data), .kind(UVM_PREDICT_WRITE), .be(item.a_mask)));
|
||||
end
|
||||
// if incoming access is a write to a valid csr, then make updates right away
|
||||
if (addr_phase_write) begin
|
||||
void'(csr.predict(.value(item.a_data), .kind(UVM_PREDICT_WRITE), .be(item.a_mask)));
|
||||
end
|
||||
|
||||
// process the csr req
|
||||
|
@ -87,13 +90,23 @@ class ${name}_scoreboard extends dv_base_scoreboard #(
|
|||
// for read, update predication at address phase and compare at data phase
|
||||
case (csr.get_name())
|
||||
// add individual case item for each csr
|
||||
"intr_state": begin
|
||||
// FIXME
|
||||
do_read_check = 1'b0;
|
||||
end
|
||||
"intr_enable": begin
|
||||
// FIXME
|
||||
end
|
||||
"intr_test": begin
|
||||
// FIXME
|
||||
end
|
||||
default: begin
|
||||
`uvm_fatal(`gfn, $sformatf("invalid csr: %0s", csr.get_full_name()))
|
||||
end
|
||||
endcase
|
||||
|
||||
// On reads, if do_read_check, is set, then check mirrored_value against item.d_data
|
||||
if (!write && channel == DataChannel) begin
|
||||
if (data_phase_read) begin
|
||||
if (do_read_check) begin
|
||||
`DV_CHECK_EQ(csr.get_mirrored_value(), item.d_data,
|
||||
$sformatf("reg name: %0s", csr.get_full_name()))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue