Update code from upstream repository
https://github.com/lowRISC/opentitan to revision
4cf2479b8e6c9b68b9fe1adba202443d3dbe3ff3

* [prim_trivium] Allow dynamically disabling the lockup protection
  (Pirmin Vogel)
* [scrambling] Add reference to RFC issue (Michael Schaffner)
* [edn] Move prim_edn_req out of prim (Rupert Swarbrick)
* [reggen] Remove the devmode input (Michael Schaffner)
* [prim, rom_ctrl] Remove S&P layer from data scrambling (Michael
  Schaffner)
* [prim] Fix typo in Trivium/Bivium stream cipher primitives (Pirmin
  Vogel)
* [prim] Add scratch Verilator testbench for Trivium/Bivium primitives
  (Pirmin Vogel)
* [prim] Add Trivium/Bivium stream cipher primitives (Pirmin Vogel)
* [chip,dv] update makefile for real_key rom test (Jaedon Kim)
* [dvsim] cast self.seed to 'int' (Jaedon Kim)
* [dvsim] Change systemverilog seed to 32 bits (Hakim Filali)
* [dv] Specialize dv_spinwait_* documentation comments (Rupert
  Swarbrick)

Signed-off-by: Michael Schaffner <msf@opentitan.org>
This commit is contained in:
Michael Schaffner 2024-01-18 18:51:56 -08:00
parent 123d46b4d6
commit 94a7446277
31 changed files with 1250 additions and 365 deletions

View file

@ -9,6 +9,6 @@
upstream:
{
url: https://github.com/lowRISC/opentitan
rev: e6a0e9a1363d33789283ea6ba3c4d94d41f2dee5
rev: 4cf2479b8e6c9b68b9fe1adba202443d3dbe3ff3
}
}

View file

@ -360,14 +360,13 @@
`define GET_PARITY(val, odd=0) (^val ^ odd)
`endif
// Wait a task or statement with exit condition
// Kill the thread when either the wait statement is completed or exit condition occurs
// input WAIT_ need to be a statement. Here are some examples
// `DV_SPINWAIT(wait(...);, "Wait for ...")
// `DV_SPINWAIT(
// while (1) begin
// ...
// end)
// Wait for a statement but stop early if the EXIT statement completes.
//
// Example usage:
//
// `DV_SPINWAIT_EXIT(do_something_time_consuming();,
// wait(stop_now_flag);,
// "The stop flag was set when we were working")
`ifndef DV_SPINWAIT_EXIT
`define DV_SPINWAIT_EXIT(WAIT_, EXIT_, MSG_ = "exit condition occurred!", ID_ =`gfn) \
begin \
@ -398,7 +397,7 @@
end
`endif
// wait a task or statement with timer watchdog
// Wait for a statement, but exit early after a timeout
`ifndef DV_SPINWAIT
`define DV_SPINWAIT(WAIT_, MSG_ = "timeout occurred!", TIMEOUT_NS_ = default_spinwait_timeout_ns, ID_ =`gfn) \
`DV_SPINWAIT_EXIT(WAIT_, `DV_WAIT_TIMEOUT(TIMEOUT_NS_, ID_, MSG_);, "", ID_)

View file

@ -36,7 +36,6 @@ package dv_utils_pkg;
// typedef parameterized pins_if for ease of implementation for interrupts and alerts
typedef virtual pins_if #(NUM_MAX_INTERRUPTS) intr_vif;
typedef virtual pins_if #(1) devmode_vif;
// interface direction / mode - Host or Device
typedef enum bit {

View file

@ -59,7 +59,6 @@ virtual function bit [38:0] rom_encrypt_read32(bit [bus_params_pkg::BUS_AW-1:0]
zero_key[i] = '0;
end
data_arr = sram_scrambler_pkg::sp_decrypt(data_arr, 39, zero_key);
for (int i = 0; i < 39; i++) begin
data[i] = data_arr[i] ^ keystream[i];
end

View file

@ -237,10 +237,10 @@ package sram_scrambler_pkg;
// SRAM data encryption is more involved, we need to run 2 rounds of PRINCE on the nonce and key
// and then XOR the result with the data.
//
// After that, the XORed data neeeds to them be passed through the S&P network one byte at a time.
// Optionally, the XORed data can be passed through the S&P network.
function automatic state_t encrypt_sram_data(logic data[], int data_width, int sp_width,
logic addr[], int addr_width,
logic key[], logic nonce[]);
logic key[], logic nonce[], bit use_sp_layer = 0);
logic keystream[] = new[SRAM_BLOCK_WIDTH];
logic data_enc[] = new[data_width];
logic byte_to_enc[] = new[8];
@ -262,31 +262,33 @@ package sram_scrambler_pkg;
data_enc[i] = data[i] ^ keystream[i % ks_width];
end
if (data_width == sp_width) begin
// pass the entire word through the subst/perm network at once (the next cases would give the
// same results too, but this should be a bit more efficient)
data_enc = sp_encrypt(data_enc, data_width, zero_key);
end else if (sp_width == 8) begin
// pass each byte of the encoded result through the subst/perm network (special case of the
// general code below)
for (int i = 0; i < data_width / 8; i++) begin
byte_to_enc = data_enc[i*8 +: 8];
enc_byte = sp_encrypt(byte_to_enc, 8, zero_key);
data_enc[i*8 +: 8] = enc_byte;
end
end else begin
// divide the word into sp_width chunks to pass it through the subst/perm network
for (int chunk_lsb = 0; chunk_lsb < data_width; chunk_lsb += sp_width) begin
int bits_remaining = data_width - chunk_lsb;
int chunk_width = (bits_remaining < sp_width) ? bits_remaining : sp_width;
logic chunk[] = new[chunk_width];
for (int j = 0; j < chunk_width; j++) begin
chunk[j] = data_enc[chunk_lsb + j];
if (use_sp_layer) begin
if (data_width == sp_width) begin
// pass the entire word through the subst/perm network at once (the next cases would give the
// same results too, but this should be a bit more efficient)
data_enc = sp_encrypt(data_enc, data_width, zero_key);
end else if (sp_width == 8) begin
// pass each byte of the encoded result through the subst/perm network (special case of the
// general code below)
for (int i = 0; i < data_width / 8; i++) begin
byte_to_enc = data_enc[i*8 +: 8];
enc_byte = sp_encrypt(byte_to_enc, 8, zero_key);
data_enc[i*8 +: 8] = enc_byte;
end
chunk = sp_encrypt(chunk, chunk_width, zero_key);
for (int j = 0; j < chunk_width; j++) begin
data_enc[chunk_lsb + j] = chunk[j];
end else begin
// divide the word into sp_width chunks to pass it through the subst/perm network
for (int chunk_lsb = 0; chunk_lsb < data_width; chunk_lsb += sp_width) begin
int bits_remaining = data_width - chunk_lsb;
int chunk_width = (bits_remaining < sp_width) ? bits_remaining : sp_width;
logic chunk[] = new[chunk_width];
for (int j = 0; j < chunk_width; j++) begin
chunk[j] = data_enc[chunk_lsb + j];
end
chunk = sp_encrypt(chunk, chunk_width, zero_key);
for (int j = 0; j < chunk_width; j++) begin
data_enc[chunk_lsb + j] = chunk[j];
end
end
end
end
@ -296,7 +298,7 @@ package sram_scrambler_pkg;
function automatic state_t decrypt_sram_data(logic data[], int data_width, int sp_width,
logic addr[], int addr_width,
logic key[], logic nonce[]);
logic key[], logic nonce[], bit use_sp_layer = 0);
logic keystream[] = new[SRAM_BLOCK_WIDTH];
logic data_dec[] = new[data_width];
logic byte_to_dec[] = new[8];
@ -312,40 +314,47 @@ package sram_scrambler_pkg;
// Generate the keystream
keystream = gen_keystream(addr, addr_width, key, nonce);
if (data_width == sp_width) begin
// pass the entire word through the subst/perm network at once (the next cases would give the
// same results too, but this should be a bit more efficient)
data_dec = sp_decrypt(data, data_width, zero_key);
end else if (sp_width == 8) begin
// pass each byte of the data through the subst/perm network (special case of the general code
// below)
for (int i = 0; i < data_width / 8; i++) begin
byte_to_dec = data[i*8 +: 8];
dec_byte = sp_decrypt(byte_to_dec, 8, zero_key);
data_dec[i*8 +: 8] = dec_byte;
if (use_sp_layer) begin
if (data_width == sp_width) begin
// pass the entire word through the subst/perm network at once (the next cases would give the
// same results too, but this should be a bit more efficient)
data_dec = sp_decrypt(data, data_width, zero_key);
end else if (sp_width == 8) begin
// pass each byte of the data through the subst/perm network (special case of the general code
// below)
for (int i = 0; i < data_width / 8; i++) begin
byte_to_dec = data[i*8 +: 8];
dec_byte = sp_decrypt(byte_to_dec, 8, zero_key);
data_dec[i*8 +: 8] = dec_byte;
end
end else begin
// divide the word into sp_width chunks to pass it through the subst/perm network
for (int chunk_lsb = 0; chunk_lsb < data_width; chunk_lsb += sp_width) begin
int bits_remaining = data_width - chunk_lsb;
int chunk_width = (bits_remaining < sp_width) ? bits_remaining : sp_width;
logic chunk[] = new[chunk_width];
for (int j = 0; j < chunk_width; j++) begin
chunk[j] = data[chunk_lsb + j];
end
chunk = sp_decrypt(chunk, chunk_width, zero_key);
for (int j = 0; j < chunk_width; j++) begin
data_dec[chunk_lsb + j] = chunk[j];
end
end
end
// XOR result data with the keystream
for (int i = 0; i < data_width; i++) begin
data_dec[i] = data_dec[i] ^ keystream[i % ks_width];
end
end else begin
// divide the word into sp_width chunks to pass it through the subst/perm network
for (int chunk_lsb = 0; chunk_lsb < data_width; chunk_lsb += sp_width) begin
int bits_remaining = data_width - chunk_lsb;
int chunk_width = (bits_remaining < sp_width) ? bits_remaining : sp_width;
logic chunk[] = new[chunk_width];
for (int j = 0; j < chunk_width; j++) begin
chunk[j] = data[chunk_lsb + j];
end
chunk = sp_decrypt(chunk, chunk_width, zero_key);
for (int j = 0; j < chunk_width; j++) begin
data_dec[chunk_lsb + j] = chunk[j];
end
// XOR result data with the keystream
for (int i = 0; i < data_width; i++) begin
data_dec[i] = data[i] ^ keystream[i % ks_width];
end
end
// XOR result data with the keystream
for (int i = 0; i < data_width; i++) begin
data_dec[i] = data_dec[i] ^ keystream[i % ks_width];
end
return data_dec;
endfunction : decrypt_sram_data

View file

@ -19,9 +19,9 @@ pre_build:
mkdir -p ${build_dir}
ifneq (${pre_build_cmds},)
# pre_build_cmds are likely changing the in-tree sources. We hence use FLOCK
# utility to prevent multiple builds that may be running in parallel from
# stepping on each other. TODO: Enforce the list of pre_build_cmds is
# identical across all build modes.
# utility to prevent multiple builds that may be running in parallel from
# stepping on each other. TODO: Enforce the list of pre_build_cmds is
# identical across all build modes.
${LOCK_ROOT_DIR} "cd ${build_dir} && ${pre_build_cmds}"
endif
@ -124,6 +124,7 @@ ifneq (${sw_images},)
--output=label_kind | cut -f1 -d' '); \
if [[ $${kind} == "opentitan_test" \
|| $${bazel_label} == "//sw/device/lib/testing/test_rom:test_rom_sim_dv" \
|| $${bazel_label} == "//sw/device/silicon_creator/rom:rom_with_real_keys_sim_dv" \
|| $${bazel_label} == "//sw/device/silicon_creator/rom:rom_with_fake_keys_sim_dv" ]]; then \
for artifact in $$($${bazel_cmd} cquery $${bazel_airgapped_opts} \
$${bazel_label} \
@ -229,18 +230,18 @@ cov_analyze:
${cov_analyze_cmd} ${cov_analyze_opts}
.PHONY: build \
pre_build \
gen_sv_flist \
do_build \
post_build \
build_result \
run \
pre_run \
sw_build \
simulate \
post_run \
run_result \
debug_waves \
cov_merge \
cov_analyze \
cov_report
pre_build \
gen_sv_flist \
do_build \
post_build \
build_result \
run \
pre_run \
sw_build \
simulate \
post_run \
run_result \
debug_waves \
cov_merge \
cov_analyze \
cov_report

View file

@ -23,7 +23,7 @@
- address and size aren't aligned, e.g. `a_address = 0x01`, `a_size != 0`
- size is greater than 2
- OpenTitan defined error cases
- access unmapped address, expect `d_error = 1` when `devmode_i == 1`
- access unmapped address, expect `d_error = 1`
- write a CSR with unaligned address, e.g. `a_address[1:0] != 0`
- write a CSR less than its width, e.g. when CSR is 2 bytes wide, only write 1 byte
- write a memory with `a_mask != '1` when it doesn't support partial accesses

View file

@ -113,7 +113,7 @@
run_opts: ["-licqueue",
"-ucli -do {run_script}",
"+ntb_random_seed={seed}",
"+ntb_random_seed={svseed}",
// Disable the display of the SystemVerilog assert and cover statement summary
// at the end of simulation. This summary is list of assertions that started but
// did not finish because the simulation terminated, or assertions that did not
@ -134,7 +134,7 @@
// Individual test specific coverage data - this will be deleted if the test fails
// so that coverage from failiing tests is not included in the final report.
cov_db_test_dir_name: "{run_dir_name}.{seed}"
cov_db_test_dir_name: "{run_dir_name}.{svseed}"
cov_db_test_dir: "{cov_db_dir}/snps/coverage/db/testdata/{cov_db_test_dir_name}"
// Merging coverage.

View file

@ -69,9 +69,7 @@
// "--x-initial unique",
]
run_opts: [// Set random seed.
// "+verilator+seed+{seed}",
]
run_opts: []
// Supported wave dumping formats (in order of preference).
supported_wave_formats: ["fst"]

View file

@ -68,7 +68,7 @@
"-64bit -xmlibdirname {build_db_dir}",
// Use the same snapshot name set during the build step.
"-r {tb}",
"+SVSEED={seed}",
"+SVSEED={svseed}",
"{uvm_testname_plusarg}",
"{uvm_testseq_plusarg}",
// Ignore "IEEE 1800-2009 SystemVerilog simulation semantics" warning
@ -129,7 +129,7 @@
// Individual test specific coverage data - this will be deleted if the test fails
// so that coverage from failiing tests is not included in the final report.
cov_db_test_dir_name: "{run_dir_name}.{seed}"
cov_db_test_dir_name: "{run_dir_name}.{svseed}"
cov_db_test_dir: "{cov_db_dir}/{cov_db_test_dir_name}"
// Merging coverage.

View file

@ -162,9 +162,10 @@ void ScrambledEcc32MemArea::WriteBuffer(uint8_t buf[SV_MEM_WIDTH_BYTES],
std::vector<uint8_t> ScrambledEcc32MemArea::ReadUnscrambled(
const uint8_t buf[SV_MEM_WIDTH_BYTES], uint32_t src_word) const {
std::vector<uint8_t> scrambled_data(buf, buf + GetPhysWidthByte());
return scramble_decrypt_data(
scrambled_data, GetPhysWidth(), 39, AddrIntToBytes(src_word, addr_width_),
addr_width_, GetScrambleNonce(), GetScrambleKey(), repeat_keystream_);
return scramble_decrypt_data(scrambled_data, GetPhysWidth(), 39,
AddrIntToBytes(src_word, addr_width_),
addr_width_, GetScrambleNonce(),
GetScrambleKey(), repeat_keystream_, false);
}
void ScrambledEcc32MemArea::ReadBuffer(std::vector<uint8_t> &data,
@ -196,7 +197,8 @@ void ScrambledEcc32MemArea::ScrambleBuffer(uint8_t buf[SV_MEM_WIDTH_BYTES],
// Scramble data with integrity
scramble_buf = scramble_encrypt_data(
scramble_buf, GetPhysWidth(), 39, AddrIntToBytes(dst_word, addr_width_),
addr_width_, GetScrambleNonce(), GetScrambleKey(), repeat_keystream_);
addr_width_, GetScrambleNonce(), GetScrambleKey(), repeat_keystream_,
false);
// Copy scrambled data to write buffer
std::copy(scramble_buf.begin(), scramble_buf.end(), &buf[0]);

View file

@ -322,7 +322,7 @@ std::vector<uint8_t> scramble_encrypt_data(
const std::vector<uint8_t> &data_in, uint32_t data_width,
uint32_t subst_perm_width, const std::vector<uint8_t> &addr,
uint32_t addr_width, const std::vector<uint8_t> &nonce,
const std::vector<uint8_t> &key, bool repeat_keystream) {
const std::vector<uint8_t> &key, bool repeat_keystream, bool use_sp_layer) {
assert(data_in.size() == ((data_width + 7) / 8));
assert(addr.size() == ((addr_width + 7) / 8));
@ -335,28 +335,32 @@ std::vector<uint8_t> scramble_encrypt_data(
auto data_enc = xor_vectors(data_in, keystream);
return scramble_subst_perm_full_width(data_enc, data_width, subst_perm_width,
true);
if (use_sp_layer) {
return scramble_subst_perm_full_width(data_enc, data_width,
subst_perm_width, true);
} else {
return data_enc;
}
}
std::vector<uint8_t> scramble_decrypt_data(
const std::vector<uint8_t> &data_in, uint32_t data_width,
uint32_t subst_perm_width, const std::vector<uint8_t> &addr,
uint32_t addr_width, const std::vector<uint8_t> &nonce,
const std::vector<uint8_t> &key, bool repeat_keystream) {
const std::vector<uint8_t> &key, bool repeat_keystream, bool use_sp_layer) {
assert(data_in.size() == ((data_width + 7) / 8));
assert(addr.size() == ((addr_width + 7) / 8));
// Data is decrypted by reversing substitution/permutation layer then XORing
// with keystream
auto data_sp_out = scramble_subst_perm_full_width(data_in, data_width,
subst_perm_width, false);
auto keystream =
scramble_gen_keystream(addr, addr_width, nonce, key, data_width,
kNumPrinceHalfRounds, repeat_keystream);
auto data_dec = xor_vectors(data_sp_out, keystream);
return data_dec;
if (use_sp_layer) {
// Data is decrypted by reversing substitution/permutation layer then XORing
// with keystream
auto data_sp_out = scramble_subst_perm_full_width(data_in, data_width,
subst_perm_width, false);
return xor_vectors(data_sp_out, keystream);
} else {
return xor_vectors(data_in, keystream);
}
}

View file

@ -40,13 +40,17 @@ std::vector<uint8_t> scramble_addr(const std::vector<uint8_t> &addr_in,
* @param repeat_keystream Repeat the keystream of one single PRINCE instance if
* set to true. Otherwise multiple PRINCE instances are
* used.
* @param use_sp_layer Use the S&P layer for data diffusion. In HW this is
* disabled by default since it interacts adversely with
* the end-to-end integrity scheme. See #20788 for
* context.
* @return Byte vector with decrypted data
*/
std::vector<uint8_t> scramble_decrypt_data(
const std::vector<uint8_t> &data_in, uint32_t data_width,
uint32_t subst_perm_width, const std::vector<uint8_t> &addr,
uint32_t addr_width, const std::vector<uint8_t> &nonce,
const std::vector<uint8_t> &key, bool repeat_keystream);
const std::vector<uint8_t> &key, bool repeat_keystream, bool use_sp_layer);
/** Encrypt scrambled data
* @param data_in Byte vector of data to encrypt
@ -60,12 +64,16 @@ std::vector<uint8_t> scramble_decrypt_data(
* @param repeat_keystream Repeat the keystream of one single PRINCE instance if
* set to true. Otherwise multiple PRINCE instances are
* used.
* @param use_sp_layer Use the S&P layer for data diffusion. In HW this is
* disabled by default since it interacts adversely with
* the end-to-end integrity scheme. See #20788 for
* context.
* @return Byte vector with encrypted data
*/
std::vector<uint8_t> scramble_encrypt_data(
const std::vector<uint8_t> &data_in, uint32_t data_width,
uint32_t subst_perm_width, const std::vector<uint8_t> &addr,
uint32_t addr_width, const std::vector<uint8_t> &nonce,
const std::vector<uint8_t> &key, bool repeat_keystream);
const std::vector<uint8_t> &key, bool repeat_keystream, bool use_sp_layer);
#endif // OPENTITAN_HW_IP_PRIM_DV_PRIM_RAM_SCR_CPP_SCRAMBLE_MODEL_H_

View file

@ -0,0 +1,7 @@
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
// waiver file for Trivium/Bivium stream cipher primitives
`verilator_config

View file

@ -0,0 +1,5 @@
# Copyright lowRISC contributors.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
#
# waiver file for Trivium/Bivium stream cipher primitives

View file

@ -0,0 +1,35 @@
Trivium/Bivium Stream Cipher Verilator Testbench
================================================
This directory contains a basic, scratch Verilator testbench targeting
functional verification of the Trivium/Bivium stream cipher primitives
during development.
How to build and run the testbench
----------------------------------
From the OpenTitan top level execute
```sh
fusesoc --cores-root=. run --setup --build \
lowrisc:dv_verilator:prim_trivium_tb
```
to build the testbench and afterwards
```sh
./build/lowrisc_dv_verilator_prim_trivium_tb_0/default-verilator/Vprim_trivium_tb \
--trace
```
to run it.
Details of the testbench
------------------------
- `rtl/prim_trivium_tb.sv`: SystemVerilog testbench, instantiates and
drives multiple, differently parameterized instances of the primitives,
checks key streams of the Trivium instances against a known good key
stream, signals test end and result (pass/fail) to C++ via output ports.
Change this file to e.g. configure different output widths.
- `cpp/prim_trivium_tb.cc`: Contains main function and instantiation of
SimCtrl, reads output ports of the testbench and signals simulation
termination to Verilator.

View 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
#include <functional>
#include <iostream>
#include <signal.h>
#include "Vprim_trivium_tb.h"
#include "sim_ctrl_extension.h"
#include "verilated_toplevel.h"
#include "verilator_sim_ctrl.h"
class PrimTriviumTB : public SimCtrlExtension {
using SimCtrlExtension::SimCtrlExtension;
public:
PrimTriviumTB(prim_trivium_tb *top);
void OnClock(unsigned long sim_time);
private:
prim_trivium_tb *top_;
};
// Constructor:
// - Set up top_ ptr
PrimTriviumTB::PrimTriviumTB(prim_trivium_tb *top)
: SimCtrlExtension{}, top_(top) {}
// Function called once every clock cycle from SimCtrl
void PrimTriviumTB::OnClock(unsigned long sim_time) {
if (top_->test_done_o) {
VerilatorSimCtrl::GetInstance().RequestStop(top_->test_passed_o);
}
}
int main(int argc, char **argv) {
int ret_code;
// Init verilog instance
prim_trivium_tb top;
// Init sim
VerilatorSimCtrl &simctrl = VerilatorSimCtrl::GetInstance();
simctrl.SetTop(&top, &top.clk_i, &top.rst_ni,
VerilatorSimCtrlFlags::ResetPolarityNegative);
// Create and register VerilatorSimCtrl extension
PrimTriviumTB primtriviumtb(&top);
simctrl.RegisterExtension(&primtriviumtb);
std::cout << "Simulation of Trivium/Bivium PRNG primitives" << std::endl
<< "============================================" << std::endl
<< std::endl;
// Get pass / fail from Verilator
ret_code = simctrl.Exec(argc, argv).first;
return ret_code;
}

View file

@ -0,0 +1,51 @@
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_verilator:prim_trivium_tb"
description: "Trivium/Bivium Stream Cipher Verilator TB"
filesets:
files_rtl:
depend:
- lowrisc:prim:trivium
files:
- rtl/prim_trivium_tb.sv
file_type: systemVerilogSource
files_dv_verilator:
depend:
- lowrisc:dv_verilator:simutil_verilator
files:
- cpp/prim_trivium_tb.cc
file_type: cppSource
targets:
default:
default_tool: verilator
filesets:
- files_rtl
- files_dv_verilator
toplevel: prim_trivium_tb
tools:
verilator:
mode: cc
verilator_options:
# Disabling tracing reduces compile times by multiple times, but doesn't have a
# huge influence on runtime performance. (Based on early observations.)
- '--trace'
- '--trace-fst' # this requires -DVM_TRACE_FMT_FST in CFLAGS below!
- '--trace-structs'
- '--trace-params'
- '--trace-max-array 1024'
# compiler flags
#
# -O
# Optimization levels have a large impact on the runtime performance of the
# simulation model. -O2 and -O3 are pretty similar, -Os is slower than -O2/-O3
- '-CFLAGS "-std=c++11 -Wall -DVM_TRACE_FMT_FST -DTOPLEVEL_NAME=prim_trivium_tb -g -O0"'
- '-LDFLAGS "-pthread -lutil -lelf"'
- "-Wall"
# XXX: Cleanup all warnings and remove this option
# (or make it more fine-grained at least)
- "-Wno-fatal"

View file

@ -0,0 +1,428 @@
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// Scratch verification testbench for Trivium/Bivium stream cipher primitives
module prim_trivium_tb (
input logic clk_i,
input logic rst_ni,
output logic test_done_o,
output logic test_passed_o
);
import prim_trivium_pkg::*;
// TB configuration
localparam int unsigned OutputWidth = 128;
localparam int unsigned PartialSeedWidth = 32;
localparam int unsigned TriviumLastStatePartFractional =
TriviumStateWidth % PartialSeedWidth != 0 ? 1 : 0;
localparam int unsigned TriviumNumStateParts =
TriviumStateWidth / PartialSeedWidth + TriviumLastStatePartFractional;
localparam int unsigned BiviumLastStatePartFractional =
BiviumStateWidth % PartialSeedWidth != 0 ? 1 : 0;
localparam int unsigned BiviumNumStateParts =
BiviumStateWidth / PartialSeedWidth + BiviumLastStatePartFractional;
// Counter to control the simulation.
localparam int unsigned CountWidth = 10;
logic [CountWidth-1:0] count_d, count_q;
assign count_d = count_q + 10'd1;
always_ff @(posedge clk_i or negedge rst_ni) begin : reg_count
if (!rst_ni) begin
count_q <= '0;
end else begin
count_q <= count_d;
end
end
/////////////
// Trivium //
/////////////
// Test vectors seem to be available for Trivium only. Thus only the Trivium instances are really
// verified against a known good key stream.
// In case the OutputWidth is not a divisor of 1152, the key stream is offset by the remainder of
// this division. Thus, we skip the checking of the instance seeded with key and IV.
localparam bit SkipSeedKeyIvInstance = 1152 % OutputWidth != '0;
localparam int unsigned TestVectorOutLen = 512;
localparam int unsigned NumOutputsToCheck = TestVectorOutLen / OutputWidth;
localparam int unsigned NumOutputBitsToCheck = NumOutputsToCheck * OutputWidth;
localparam int unsigned OutCtrWidth = prim_util_pkg::vbits(NumOutputsToCheck) + 1;
localparam int NumInstances = 3;
logic trivium_en, trivium_seed_en;
logic trivium_seed_ack_seed_state_partial;
logic trivium_seed_done_seed_key_iv;
logic trivium_seed_done_seed_state_full;
logic trivium_seed_done_seed_state_partial;
logic [KeyIvWidth-1:0] seed_key, seed_iv;
logic [TriviumStateWidth-1:0] seed_state_full;
logic [PartialSeedWidth-1:0] trivium_seed_state_partial;
logic [OutputWidth-1:0] key_seed_key_iv, key_seed_state_full, key_seed_state_partial;
// Trivium test vectors generated using
//
// https://asecuritysite.com/encryption/trivium
//
// Notes on the test vectors from the above site:
// - key and IV are 'byte' vectors starting with Byte n (most left) and ending with Byte 0 (most
// right). Within each byte, the LSB is the most left bit and the MSB being the
// most right bit.
// - The key stream is a 'byte' vector starting with Byte 0 (most left) and ending with
// Byte n (most right). Within each byte, the LSB is the most right bit and the MSB being the
// most left bit.
//
// In this testbench, we use bit vectors only with LSB being most left and the MSB being most
// right.
logic [TestVectorOutLen-1:0] key_stream_expected;
// // key = 0
// // iv = 0
// localparam logic [KeyIvWidth-1:0] VECTOR_0_KEY = 80'h0000_0000_0000_0000_0000;
// localparam logic [KeyIvWidth-1:0] VECTOR_0_IV = 80'h0000_0000_0000_0000_0000;
// localparam logic [TestVectorOutLen-1:0] VECTOR_0_KEY_STREAM =
// {128'hF2D4_A5B5_4C1A_8003_5980_746E_9849_5528,
// 128'h9A59_A29A_751A_4C2B_38B7_6802_0392_52F7,
// 128'hCDE9_B2A1_0F79_A8E7_2DCF_0719_1603_3256,
// 128'h7FC9_9F23_4E2E_7A51_1B05_5958_26BF_E0FB};
// localparam logic [TriviumStateWidth-1:0] VECTOR_0_STATE =
// {96'h92AC_487E_267F_5871_D3A1_896D,
// 96'hF514_AD2F_EA84_1320_40AE_4058,
// 96'hA21B_38EC_692A_E61D_7493_1A85};
// // key = 8000_0000_0000_0000_0000
// // iv = 0
// localparam logic [KeyIvWidth-1:0] VECTOR_1_KEY = 80'h0100_0000_0000_0000_0000;
// localparam logic [KeyIvWidth-1:0] VECTOR_1_IV = 80'h0000_0000_0000_0000_0000;
// localparam logic [TestVectorOutLen-1:0] VECTOR_1_KEY_STREAM =
// {128'hF980_FC54_74EF_E87B_B962_6ACC_CC20_FF98,
// 128'h807F_CFCE_928F_6CE0_EB21_0961_15F5_FBD2,
// 128'h649A_F249_C241_2055_0175_C864_1465_7BBB,
// 128'h0D54_2044_3AF1_8DAF_9C7A_0D73_FF86_EB38};
// localparam logic [TriviumStateWidth-1:0] VECTOR_1_STATE =
// {96'hC7D7_C89B_CC06_725B_3D94_7181,
// 96'h06F2_A065_6422_AF1F_A457_B81F,
// 96'h0D25_16A9_D565_893A_64C1_E50E};
// key = 0A5D_B003_56A9_FC4F_A2F5
// iv = 1F86_ED54_BB22_89F0_57BE
localparam logic [KeyIvWidth-1:0] VECTOR_2_KEY = 80'h50BA_0DC0_6A95_3FF2_45AF;
localparam logic [KeyIvWidth-1:0] VECTOR_2_IV = 80'hF861_B72A_DD44_910F_EA7D;
localparam logic [TestVectorOutLen-1:0] VECTOR_2_KEY_STREAM =
{128'h7258_8CB7_89E3_8615_0DFC_DA03_BDA3_A5AE,
128'h2F98_426C_4C75_C0F1_3BFB_6B2D_E2DD_6E54,
128'hB8F0_AB03_51B7_F538_3C17_FAC1_E8B0_913B,
128'h1838_E884_56D9_D2D0_ADCB_4B13_C510_94DE};
localparam logic [TriviumStateWidth-1:0] VECTOR_2_STATE =
{96'hE843_DB60_EB48_14D1_C198_620D,
96'hF21B_0322_0BAD_DAD5_A15A_3958,
96'hBC97_5171_D8C0_4C75_B395_11C4};
assign seed_key = VECTOR_2_KEY;
assign seed_iv = VECTOR_2_IV;
assign seed_state_full = VECTOR_2_STATE;
assign key_stream_expected = VECTOR_2_KEY_STREAM;
// Instantiate DUTs
prim_trivium #(
.BiviumVariant(0),
.OutputWidth (OutputWidth),
.SeedType (SeedTypeKeyIv)
) u_prim_trivium_seed_key_iv (
.clk_i (clk_i),
.rst_ni(rst_ni),
.en_i (trivium_en),
.allow_lockup_i (1'b0),
.seed_en_i (trivium_seed_en),
.seed_done_o (trivium_seed_done_seed_key_iv),
.seed_req_o (),
.seed_ack_i (trivium_seed_en),
.seed_key_i (seed_key),
.seed_iv_i (seed_iv),
.seed_state_full_i ('0), // unused
.seed_state_partial_i('0), // unused
.key_o(key_seed_key_iv),
.err_o()
);
prim_trivium #(
.BiviumVariant(0),
.OutputWidth (OutputWidth),
.SeedType (SeedTypeStateFull)
) u_prim_trivium_seed_state_full (
.clk_i (clk_i),
.rst_ni(rst_ni),
.en_i (trivium_en),
.allow_lockup_i (1'b0),
.seed_en_i (trivium_seed_en),
.seed_done_o (trivium_seed_done_seed_state_full),
.seed_req_o (),
.seed_ack_i (trivium_seed_en),
.seed_key_i ('0), // unused
.seed_iv_i ('0), // unused
.seed_state_full_i (seed_state_full),
.seed_state_partial_i('0), // unused
.key_o(key_seed_state_full),
.err_o()
);
prim_trivium #(
.BiviumVariant (0),
.OutputWidth (OutputWidth),
.SeedType (SeedTypeStatePartial),
.PartialSeedWidth(PartialSeedWidth)
) u_prim_trivium_seed_state_partial (
.clk_i (clk_i),
.rst_ni(rst_ni),
.en_i (trivium_en),
.allow_lockup_i (1'b0),
.seed_en_i (trivium_seed_en),
.seed_done_o (trivium_seed_done_seed_state_partial),
.seed_req_o (),
.seed_ack_i (trivium_seed_ack_seed_state_partial),
.seed_key_i ('0), // unused
.seed_iv_i ('0), // unused
.seed_state_full_i ('0), // unused
.seed_state_partial_i(trivium_seed_state_partial),
.key_o(key_seed_state_partial),
.err_o()
);
// Tracking of seed_done
logic [NumInstances-1:0] trivium_seed_done_d, trivium_seed_done_q;
assign trivium_seed_done_d = (trivium_seed_done_q &
// Clear back to zero upon staring a new reseed operation.
{NumInstances{~trivium_seed_en}}) |
// Register finishing of reseed operation.
{trivium_seed_done_seed_state_partial,
trivium_seed_done_seed_state_full,
trivium_seed_done_seed_key_iv};
always_ff @(posedge clk_i or negedge rst_ni) begin : reg_trivium_seed_done
if (!rst_ni) begin
trivium_seed_done_q <= '0;
end else begin
trivium_seed_done_q <= trivium_seed_done_d;
end
end
// Start the reseed operation right after coming out of reset.
assign trivium_seed_en = count_q == 10'd1;
// Start running once all instances have finished the reseed operation.
assign trivium_en = &trivium_seed_done_q;
// Provide the 9 partial seed parts.
assign trivium_seed_ack_seed_state_partial =
(count_q >= 10'd1) && (count_q < 10'd1 + TriviumNumStateParts[CountWidth-1:0]);
assign trivium_seed_state_partial =
seed_state_full[({22'h0, count_q} - 32'd1) * PartialSeedWidth +: PartialSeedWidth];
/////////////////////////////////
// Record generated key streams//
/////////////////////////////////
logic record;
assign record = trivium_en & (out_ctr_q < NumOutputsToCheck[OutCtrWidth-1:0]);
logic [OutCtrWidth-1:0] out_ctr_d, out_ctr_q;
assign out_ctr_d = record ? out_ctr_q + 1'b1 : out_ctr_q;
always_ff @(posedge clk_i or negedge rst_ni) begin : reg_out_ctr
if (!rst_ni) begin
out_ctr_q <= '0;
end else begin
out_ctr_q <= out_ctr_d;
end
end
logic [TestVectorOutLen-1:0] key_stream_actual_d [NumInstances];
logic [TestVectorOutLen-1:0] key_stream_actual_q [NumInstances];
always_comb begin
key_stream_actual_d = key_stream_actual_q;
if (record) begin
key_stream_actual_d[0][out_ctr_q * OutputWidth +: OutputWidth] = key_seed_key_iv;
key_stream_actual_d[1][out_ctr_q * OutputWidth +: OutputWidth] = key_seed_state_full;
key_stream_actual_d[2][out_ctr_q * OutputWidth +: OutputWidth] = key_seed_state_partial;
end
end
always_ff @(posedge clk_i or negedge rst_ni) begin : reg_key_stream_actual
if (!rst_ni) begin
key_stream_actual_q <= '{default: '0};
end else begin
key_stream_actual_q <= key_stream_actual_d;
end
end
///////////////////////////////////////////////
// Check responses, signal end of simulation //
///////////////////////////////////////////////
logic mismatch;
always_ff @(posedge clk_i) begin : tb_ctrl
test_done_o <= 1'b0;
test_passed_o <= 1'b1;
if (out_ctr_q == NumOutputsToCheck[OutCtrWidth-1:0]) begin
mismatch <= 1'b0;
for (int i = 0; i < NumInstances; i++) begin
if (!SkipSeedKeyIvInstance || i > 0) begin
if (key_stream_expected[NumOutputBitsToCheck-1:0]
== key_stream_actual_q[i][NumOutputBitsToCheck-1:0]) begin
$display("\nSUCCESS: Observed key stream of instance %1d matches expected data.", i);
end else begin
$display("\nERROR: Obeserved key stream of instance %1d doesn't match expected data.",
i);
mismatch <= 1'b1;
end
end
end
$display("Finishing simulation now.\n");
test_passed_o <= ~mismatch;
test_done_o <= 1'b1;
end
if (count_q == 10'd1000) begin
$display("\nDONE");
test_done_o <= 1'b1;
end
end
////////////
// Bivium //
////////////
// No test vectors seem to be available for Bivium. The 3 instances below are not checked against
// a known good key stream. It's still useful to instantiate the 3 different Bivium variants for
// visual inspection, for checking Verilator lint of all three variants, and for inspecting the
// partial reseed behavior while the primitive is running.
logic bivium_en, bivium_seed_en;
logic bivium_seed_done_seed_key_iv;
logic bivium_seed_done_seed_state_full;
logic bivium_seed_done_seed_state_partial;
logic bivium_seed_en_seed_state_partial, bivium_seed_ack_seed_state_partial;
logic [PartialSeedWidth-1:0] bivium_seed_state_partial;
// Instantiate DUTs
prim_trivium #(
.BiviumVariant(1),
.OutputWidth (OutputWidth),
.SeedType (SeedTypeKeyIv)
) u_prim_bivium_seed_key_iv (
.clk_i (clk_i),
.rst_ni(rst_ni),
.en_i (bivium_en),
.allow_lockup_i (1'b0),
.seed_en_i (bivium_seed_en),
.seed_done_o (bivium_seed_done_seed_key_iv),
.seed_req_o (),
.seed_ack_i (bivium_seed_en),
.seed_key_i (seed_key),
.seed_iv_i (seed_iv),
.seed_state_full_i ('0), // unused
.seed_state_partial_i('0), // unused
.key_o(key_seed_key_iv),
.err_o()
);
prim_trivium #(
.BiviumVariant(1),
.OutputWidth (OutputWidth),
.SeedType (SeedTypeStateFull)
) u_prim_bivium_seed_state_full (
.clk_i (clk_i),
.rst_ni(rst_ni),
.en_i (bivium_en),
.allow_lockup_i (1'b0),
.seed_en_i (bivium_seed_en),
.seed_done_o (bivium_seed_done_seed_state_full),
.seed_req_o (),
.seed_ack_i (bivium_seed_en),
.seed_key_i ('0), // unused
.seed_iv_i ('0), // unused
.seed_state_full_i (seed_state_full[BiviumStateWidth-1:0]),
.seed_state_partial_i('0), // unused
.key_o(key_seed_state_full),
.err_o()
);
prim_trivium #(
.BiviumVariant (1),
.OutputWidth (OutputWidth),
.StrictLockupProtection(0),
.SeedType (SeedTypeStatePartial),
.PartialSeedWidth (PartialSeedWidth)
) u_prim_bivium_seed_state_partial (
.clk_i (clk_i),
.rst_ni(rst_ni),
.en_i (bivium_en),
.allow_lockup_i (1'b1),
.seed_en_i (bivium_seed_en_seed_state_partial),
.seed_done_o (bivium_seed_done_seed_state_partial),
.seed_req_o (),
.seed_ack_i (bivium_seed_ack_seed_state_partial),
.seed_key_i ('0), // unused
.seed_iv_i ('0), // unused
.seed_state_full_i ('0), // unused
.seed_state_partial_i(bivium_seed_state_partial),
.key_o(),
.err_o()
);
// Tracking of seed_done
logic [NumInstances-1:0] bivium_seed_done_d, bivium_seed_done_q;
assign bivium_seed_done_d = (bivium_seed_done_q &
// Clear back to zero upon staring a new reseed operation.
{NumInstances{~bivium_seed_en}}) |
// Register finishing of reseed operation.
{bivium_seed_done_seed_state_partial,
bivium_seed_done_seed_state_full,
bivium_seed_done_seed_key_iv};
always_ff @(posedge clk_i or negedge rst_ni) begin : reg_bivium_seed_done
if (!rst_ni) begin
bivium_seed_done_q <= '0;
end else begin
bivium_seed_done_q <= bivium_seed_done_d;
end
end
// Start the reseed operation right after coming out of reset.
assign bivium_seed_en = count_q == 10'd1;
// Start running once all instances have finished the reseed operation.
assign bivium_en = &bivium_seed_done_q;
// The last instance is handled separately:
// First, we put the Bivium primitive into an all-zero state. Then, a single PartialSeedWidth
// seed is provided while the primitive is running. This allows inpsecting the diffusion pattern
// of the primitive (depending on the OutputWidth).
// Register to latch counter value when initial reseed operation finishes. This depends on
// PartialSeedWidth and OutputWidth.
logic [CountWidth-1:0] count_seed_done_q;
always_ff @(posedge clk_i or negedge rst_ni) begin : reg_count_seed_done
if (!rst_ni) begin
count_seed_done_q <= '0;
end else if (&bivium_seed_done_q && count_seed_done_q == '0) begin
count_seed_done_q <= count_q;
end
end
assign bivium_seed_en_seed_state_partial = bivium_seed_en ||
((count_seed_done_q != 0) && (count_q >= count_seed_done_q + 10'd1));
assign bivium_seed_ack_seed_state_partial =
((count_q >= 10'd1) && (count_q < 10'd1 + BiviumNumStateParts[CountWidth-1:0])) ||
bivium_seed_en_seed_state_partial;
assign bivium_seed_state_partial = &bivium_seed_done_q ? '1 : '0;
endmodule

View file

@ -1,21 +0,0 @@
CAPI=2:
# Copyright lowRISC contributors.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
name: "lowrisc:prim:edn_req:0.1"
description: "EDN synchronization and word packing IP."
filesets:
files_rtl:
depend:
- lowrisc:prim:all
- lowrisc:prim:assert
- lowrisc:ip:edn_pkg
files:
- rtl/prim_edn_req.sv
file_type: systemVerilogSource
targets:
default:
filesets:
- files_rtl

View file

@ -0,0 +1,44 @@
CAPI=2:
# Copyright lowRISC contributors.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
name: "lowrisc:prim:trivium:0.1"
description: "Trivium/Bivium Stream Cipher Primitives"
filesets:
files_rtl:
depend:
- lowrisc:prim:assert
- lowrisc:prim:util
files:
- rtl/prim_trivium_pkg.sv
- rtl/prim_trivium.sv
file_type: systemVerilogSource
files_verilator_waiver:
depend:
# common waivers
- lowrisc:lint:common
files:
- lint/prim_trivium.vlt
file_type: vlt
files_ascentlint_waiver:
depend:
# common waivers
- lowrisc:lint:common
files:
- lint/prim_trivium.waiver
file_type: waiver
files_veriblelint_waiver:
depend:
# common waivers
- lowrisc:lint:common
targets:
default:
filesets:
- tool_verilator ? (files_verilator_waiver)
- tool_ascentlint ? (files_ascentlint_waiver)
- tool_veriblelint ? (files_veriblelint_waiver)
- files_rtl

View file

@ -1,215 +0,0 @@
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// This module can be used as a "gadget" to adapt the native 32bit width of the EDN network
// locally to the width needed by the consuming logic. For example, if the local consumer
// needs 128bit, this module would request four 32 bit words from EDN and stack them accordingly.
//
// The module also uses a req/ack synchronizer to synchronize the EDN data over to the local
// clock domain. Note that this assumes that the EDN data bus remains stable between subsequent
// requests.
//
`include "prim_assert.sv"
module prim_edn_req
import prim_alert_pkg::*;
#(
parameter int OutWidth = 32,
// Repetition check for incoming edn data
parameter bit RepCheck = 0,
// Disable reset-related assertion checks inside prim_sync_reqack primitives.
parameter bit EnRstChks = 0,
// EDN Request latency checker
//
// Each consumer IP may have the maximum expected latency. MaxLatency
// parameter describes the expected latency in terms of the consumer clock
// cycles. If the edn request comes later than that, the assertion will be
// fired.
//
// The default value is 0, which disables the assertion.
parameter int unsigned MaxLatency = 0
) (
// Design side
input clk_i,
input rst_ni,
input req_chk_i, // Used for gating assertions. Drive to 1 during normal
// operation.
input req_i,
output logic ack_o,
output logic [OutWidth-1:0] data_o,
output logic fips_o,
output logic err_o, // current data_o failed repetition check
// EDN side
input clk_edn_i,
input rst_edn_ni,
output edn_pkg::edn_req_t edn_o,
input edn_pkg::edn_rsp_t edn_i
);
// Stop requesting words from EDN once desired amount of data is available.
logic word_req, word_ack;
assign word_req = req_i & ~ack_o;
logic [edn_pkg::ENDPOINT_BUS_WIDTH-1:0] word_data;
logic word_fips;
localparam int SyncWidth = $bits({edn_i.edn_fips, edn_i.edn_bus});
prim_sync_reqack_data #(
.Width(SyncWidth),
.EnRstChks(EnRstChks),
.DataSrc2Dst(1'b0),
.DataReg(1'b0)
) u_prim_sync_reqack_data (
.clk_src_i ( clk_i ),
.rst_src_ni ( rst_ni ),
.clk_dst_i ( clk_edn_i ),
.rst_dst_ni ( rst_edn_ni ),
.req_chk_i ( req_chk_i ),
.src_req_i ( word_req ),
.src_ack_o ( word_ack ),
.dst_req_o ( edn_o.edn_req ),
.dst_ack_i ( edn_i.edn_ack ),
.data_i ( {edn_i.edn_fips, edn_i.edn_bus} ),
.data_o ( {word_fips, word_data} )
);
if (RepCheck) begin : gen_rep_chk
logic [edn_pkg::ENDPOINT_BUS_WIDTH-1:0] word_data_q;
always_ff @(posedge clk_i) begin
if (word_ack) begin
word_data_q <= word_data;
end
end
// do not check until we have received at least the first entry
logic chk_rep;
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
chk_rep <= '0;
end else if (word_ack) begin
chk_rep <= 1'b1;
end
end
// Need to track if any of the packed words has failed the repetition check, i.e., is identical
// to the last packed word.
logic err_d, err_q;
assign err_d = (req_i && ack_o) ? 1'b0 : // clear
(chk_rep && word_ack && word_data == word_data_q) ? 1'b1 : // set
err_q; // keep
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
err_q <= 1'b0;
end else begin
err_q <= err_d;
end
end
assign err_o = err_q;
end else begin : gen_no_rep_chk // block: gen_rep_chk
assign err_o = '0;
end
prim_packer_fifo #(
.InW(edn_pkg::ENDPOINT_BUS_WIDTH),
.OutW(OutWidth),
.ClearOnRead(1'b0)
) u_prim_packer_fifo (
.clk_i,
.rst_ni,
.clr_i ( 1'b0 ), // not needed
.wvalid_i ( word_ack ),
.wdata_i ( word_data ),
// no need for backpressure since we're always ready to
// sink data at this point.
.wready_o ( ),
.rvalid_o ( ack_o ),
.rdata_o ( data_o ),
// we're always ready to receive the packed output word
// at this point.
.rready_i ( 1'b1 ),
.depth_o ( )
);
// Need to track if any of the packed words has been generated with a pre-FIPS seed, i.e., has
// fips == 1'b0.
logic fips_d, fips_q;
assign fips_d = (req_i && ack_o) ? 1'b1 : // clear
(word_ack) ? fips_q & word_fips : // accumulate
fips_q; // keep
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
fips_q <= 1'b1;
end else begin
fips_q <= fips_d;
end
end
assign fips_o = fips_q;
////////////////
// Assertions //
////////////////
// Check EDN data is valid: Not all zeros, all ones, or not the same as previous data.
`ifdef INC_ASSERT
//VCS coverage off
// pragma coverage off
logic [OutWidth-1:0] data_prev, data_curr;
always_ff @(posedge ack_o or negedge rst_ni) begin
if (!rst_ni) begin
data_prev <= '0;
data_curr <= '0;
end else if (ack_o) begin
data_curr <= data_o;
data_prev <= data_curr;
end
end
//VCS coverage on
// pragma coverage on
`ASSERT(DataOutputValid_A, ack_o |-> (data_o != 0) && (data_o != '1))
`ASSERT(DataOutputDiffFromPrev_A, data_prev != 0 |-> data_prev != data_o)
`endif
// EDN Max Latency Checker
`ifndef SYNTHESIS
if (MaxLatency != 0) begin: g_maxlatency_assertion
//VCS coverage off
// pragma coverage off
localparam int unsigned LatencyW = $clog2(MaxLatency+1);
logic [LatencyW-1:0] latency_counter;
logic reset_counter;
logic enable_counter;
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) latency_counter <= '0;
else if (reset_counter) latency_counter <= '0;
else if (enable_counter) latency_counter <= latency_counter + 1'b1;
end
assign reset_counter = ack_o;
assign enable_counter = req_i;
//VCS coverage on
// pragma coverage on
`ASSERT(MaxLatency_A, latency_counter <= MaxLatency)
// TODO: Is it worth to check req & ack pair?
// _________________________________
// req __/ \______
// ____
// ack ____________________________________/ \_
//
// | error
end // g_maxlatency_assertion
`else // SYNTHESIS
logic unused_param_maxlatency;
assign unused_param_maxlatency = ^MaxLatency;
`endif // SYNTHESIS
endmodule : prim_edn_req

View file

@ -34,8 +34,11 @@ module prim_ram_1p_scr import prim_ram_1p_pkg::*; #(
// to 2*5 + 1 effective rounds. Setting this to 2 halves this to approximately 5 effective rounds.
// Number of PRINCE half rounds, can be [1..5]
parameter int NumPrinceRoundsHalf = 2,
// Number of extra diffusion rounds. Setting this to 0 to disable diffusion.
parameter int NumDiffRounds = 2,
// Number of extra diffusion rounds. Setting this to 0 to disables diffusion.
// NOTE: this is zero by default, since the non-linear transformation of data bits can interact
// adversely with end-to-end ECC integrity. Only enable this if you know what you are doing
// (e.g. using this primitive in a different context with byte parity). See #20788 for context.
parameter int NumDiffRounds = 0,
// This parameter governs the block-width of additional diffusion layers.
// For intra-byte diffusion, set this parameter to 8.
parameter int DiffWidth = DataBitsPerMask,

View file

@ -0,0 +1,317 @@
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
// Trivium and Bivium stream cipher primitives
//
// This module implements the Trivium [1] and its reduced variant Bivium [2] (more precisely
// Bivium B) stream cipher primitives. Internally, they use 3 (Trivium) or 2 (Bivium) non-linear
// feedback shift registers (NFSRs). The number of output bits produced per update can flexibly
// be tuned using the OutputWidth parameter to match the needs of integrators. Up to an output
// width of 64 bits, the critical path stays unchanged. For output widths above 64 bits, the
// critical path starts to increase. The asymptotic area of the two primitives is 30 GE / output
// bit (Trivium) and 20 GE / output bit (Bivium). For a thorough analysis of the two primitives
// including security evaluation, as well as area and critical path figures, refer to [3].
//
// As thoroughly analyzed in [3], these primitives are suitable to be used as pseudo-random
// number generators for masking countermeasures in hardware.
//
// This implementation supports three different reseeding interfaces which can be selected using
// the SeedType parameter:
// 1. SeedTypeKeyIv: 2 x 80 bits for key and IV need to be provided. Before the key stream becomes
// usable, the primitive needs to be updated 1152 / OutputWidth (Trivium) or
// 708 / OutputWidth (Bivium) times. These initial updates are performed automatically by the
// primitives. Once the reseeding and the following initialization are done, this is indicated
// with the seed_done_o output.
// 2. SeedTypeStateFull: The full 288-bit (Trivium) or 177-bit (Bivium) state is reseeded in one
// shot.
// 3. SeedTypeStatePartial: PartialSeedWidth bits at a time are injected into the state. The
// primitive latches the seed_en_i signal and keeps requesting entropy until every
// PartialSeedWidth-wide part of the state has been overwritten once.
// To enable updating the primitive and using the key stream during the reseed operation, the
// number of output bits produced per update (OutputWidth) should be greater than the width of
// the smallest NFSR in the primitve (MinNfsrWidth = 84). Thanks to the strong diffusion
// properties of the primitives, the majority of state and key stream bits change after
// reseeding the first state part and performing the first couple of updates if OutputWidth is
// chosen sufficiently large. For Bivium, a quick evaluation hints that for OutputWidth equal
// to 84, the key stream seems usable after 3 updates and most state bits seem to change after
// 5 updates. For OutputWidth equal to 160, the key stream seems usable after only 2 updates and
// most state bits seem to change after 3 updates.
// If the next PartialSeedWidth bits of entropy arrive after having done at least one update
// but the new entropy hasn't sufficiently diffused yet into the state, there is a risk that
// previously injected entropy bits are partially or completely overwritten. It is the job of
// the integrator to ensure sufficiently many updates are performed between reseeding state
// parts. In practice, this should be relatively simple as there is typically a minimal latency
// between receiving entropy bits, e.g., due to clock domain crossings in the system.
// Independently of the chosen OutputWidth parameter, it's always safe to reseed the primitive
// while it's completely idle.
//
// For details, see the following specifications and papers:
// [1] De Canniere, "Trivium Specifications" available at
// https://www.ecrypt.eu.org/stream/p3ciphers/trivium/trivium_p3.pdf
// [2] Raddum "Cryptanalytic Results on Trivium" available at
// https://www.ecrypt.eu.org/stream/papersdir/2006/039.ps
// [3] Cassiers, "Randomness Generation for Secure Hardware Masking - Unrolled Trivium to the
// Rescue" available at https://eprint.iacr.org/2023/1134
`include "prim_assert.sv"
module prim_trivium import prim_trivium_pkg::*;
#(
parameter bit BiviumVariant = 0, // 0: Trivium, 1: Bivium
parameter int unsigned OutputWidth = 64, // Number of output bits generated per update.
parameter bit StrictLockupProtection = 1, // Upon entering an all zero state, 1: always
// restore to the default seed, or 0: allow
// to keep the all zero state if requested by
// allow_lockup_i.
parameter seed_type_e SeedType = SeedTypeStateFull, // Reseeding inteface selection, see
// prim_trivium_pkg.sv for possible values.
parameter int unsigned PartialSeedWidth = PartialSeedWidthDefault,
// derived parameter
localparam int unsigned StateWidth = BiviumVariant ? BiviumStateWidth : TriviumStateWidth,
parameter trivium_lfsr_seed_t RndCnstTriviumLfsrSeed = RndCnstTriviumLfsrSeedDefault,
// derived parameter
localparam logic [StateWidth-1:0] StateSeed = RndCnstTriviumLfsrSeed[StateWidth-1:0]
) (
input logic clk_i,
input logic rst_ni,
input logic en_i, // Update the primitive.
input logic allow_lockup_i, // Allow locking up in all zero state.
// Only taken into account if
// LockupParameter = 0
input logic seed_en_i, // Start reseeding (pulse or level).
output logic seed_done_o, // Reseeding is done (pulse).
output logic seed_req_o, // Seed REQ handshake signal
input logic seed_ack_i, // Seed ACK handshake signal
input logic [KeyIvWidth-1:0] seed_key_i, // Seed input for SeedTypeKeyIV
input logic [KeyIvWidth-1:0] seed_iv_i, // Seed input for SeedTypeKeyIV
input logic [StateWidth-1:0] seed_state_full_i, // Seed input for SeedTypeStateFull
input logic [PartialSeedWidth-1:0] seed_state_partial_i, // Seed input for SeedTypeStatePartial
output logic [OutputWidth-1:0] key_o, // Key stream output
output logic err_o // The primitive entered an all zero state and may have
// locked up or entered the default state defined by
// RndCnstTriviumLfsrSeed depending on the
// StrictLockupProtection parameter and the allow_lockup_i
// signal.
);
localparam int unsigned LastStatePartFractional = StateWidth % PartialSeedWidth != 0 ? 1 : 0;
localparam int unsigned NumStateParts = StateWidth / PartialSeedWidth + LastStatePartFractional;
localparam int unsigned NumBitsLastPart = StateWidth - (NumStateParts - 1) * PartialSeedWidth;
localparam int unsigned LastStatePart = NumStateParts - 1;
// Width of the variable determining which state part to overwrite with the next partial seed.
localparam int unsigned StateIdxWidth = prim_util_pkg::vbits(NumStateParts);
logic [StateWidth-1:0] state_d, state_q;
logic [StateWidth-1:0] state_update, state_seed;
logic seed_req_d, seed_req_q;
logic unused_seed;
logic update, update_init, wr_en_seed;
logic [StateIdxWidth-1:0] state_idx_d, state_idx_q;
logic last_state_part;
logic lockup, restore;
assign update = en_i | update_init;
assign wr_en_seed = seed_req_o & seed_ack_i;
assign lockup = ~(|state_q);
assign err_o = lockup;
//////////////////////////////////////////////////
// Regular state updating and output generation //
//////////////////////////////////////////////////
// The current key stream depends on the current state only.
if (BiviumVariant) begin : gen_update_and_output_bivium
always_comb begin
state_update = state_q;
for (int unsigned i = 0; i < OutputWidth; i++) begin
key_o[i] = bivium_generate_key_stream(state_update);
state_update = bivium_update_state(state_update);
end
end
end else begin : gen_update_and_output_trivium
always_comb begin
state_update = state_q;
for (int unsigned i = 0; i < OutputWidth; i++) begin
key_o[i] = trivium_generate_key_stream(state_update);
state_update = trivium_update_state(state_update);
end
end
end
///////////////
// Reseeding //
///////////////
if (SeedType == SeedTypeKeyIv) begin : gen_seed_type_key_iv
if (BiviumVariant) begin : gen_seed_type_key_iv_bivium
assign state_seed = bivium_seed_key_iv(seed_key_i, seed_iv_i);
end else begin : gen_seed_type_key_iv_trivium
assign state_seed = trivium_seed_key_iv(seed_key_i, seed_iv_i);
end
end else if (SeedType == SeedTypeStateFull) begin : gen_seed_type_state_full
assign state_seed = seed_state_full_i;
end else begin : gen_seed_type_state_partial
// If the primitive is idle and an update is not currently being requested (update = 1'b0), the
// parts not currently being reseeded remain constant, i.e., the update function above doesn't
// modify the state. This is required to put the primitive into a known state e.g. for known
// answer testing.
// If the primitive is busy and an update is requested, the update function always modifies
// the state (but the part currently being reseeded is solely determined by the new seed).
// Otherwise the primitive could potentially produce the same key stream output twice in a row.
always_comb begin
state_seed = !update ? state_q : state_update;
// The last part may be shorter than PartialSeedWidth.
if (last_state_part) begin
state_seed[StateWidth - 1 -: NumBitsLastPart] = seed_state_partial_i[NumBitsLastPart-1:0];
end else begin
state_seed[state_idx_q * PartialSeedWidth +: PartialSeedWidth] = seed_state_partial_i;
end
end
end
/////////////////////////////////
// State register and updating //
/////////////////////////////////
// The lockup protection can optionally be disabled at run time. This may be required to put the
// primitive into an all zero state, e.g., to switch off masking countermeasures for analysis if
// the primitive is used for generating masks. However, the err_o bit always signals this
// condition to the outside.
assign restore = lockup & (StrictLockupProtection | ~allow_lockup_i);
assign state_d = restore ? StateSeed :
wr_en_seed ? state_seed :
update ? state_update : state_q;
always_ff @(posedge clk_i or negedge rst_ni) begin : state_reg
if (!rst_ni) begin
state_q <= StateSeed;
end else begin
state_q <= state_d;
end
end
// Latch the seed enable signal and keep the request high until the last request is acknowledged.
assign seed_req_d = (seed_en_i | seed_req_q) & (~seed_ack_i | ~last_state_part);
always_ff @(posedge clk_i or negedge rst_ni) begin : seed_req_reg
if (!rst_ni) begin
seed_req_q <= 1'b0;
end else begin
seed_req_q <= seed_req_d;
end
end
assign seed_req_o = seed_en_i | seed_req_q;
if (SeedType == SeedTypeKeyIv) begin : gen_key_iv_seed_handling
// After receiving key and IV, the entire state needs to be updated 4 times before the key
// stream becomes usable. Depending on OutputWidth, a different number of initial updates are
// required for this. [3]
localparam int unsigned NumInitUpdatesFractional = (StateWidth * 4) % OutputWidth != 0 ? 1 : 0;
localparam int unsigned NumInitUpdates =
(StateWidth * 4) / OutputWidth + NumInitUpdatesFractional;
localparam int unsigned LastInitUpdate = NumInitUpdates - 1;
localparam int unsigned InitUpdatesCtrWidth = prim_util_pkg::vbits(NumInitUpdates);
logic [InitUpdatesCtrWidth-1:0] init_update_ctr_d, init_update_ctr_q;
logic init_update_d, init_update_q;
logic last_init_update;
// Count the number of initial updates done.
assign init_update_ctr_d = wr_en_seed ? '0 :
init_update_q ? init_update_ctr_q + 1'b1 : init_update_ctr_q;
always_ff @(posedge clk_i or negedge rst_ni) begin : init_update_ctr_reg
if (!rst_ni) begin
init_update_ctr_q <= '0;
end else begin
init_update_ctr_q <= init_update_ctr_d;
end
end
// Track whether we're currently doing the initial updates.
assign last_init_update = init_update_ctr_q == LastInitUpdate[InitUpdatesCtrWidth-1:0];
assign init_update_d = wr_en_seed ? 1'b1 :
last_init_update ? 1'b0 : init_update_q;
always_ff @(posedge clk_i or negedge rst_ni) begin : init_update_reg
if (!rst_ni) begin
init_update_q <= 1'b0;
end else begin
init_update_q <= init_update_d;
end
end
assign update_init = init_update_q;
// We're done after performing the initial updates.
assign seed_done_o = init_update_q & last_init_update;
// Tie off unused signals.
assign state_idx_d = '0;
assign state_idx_q = '0;
assign last_state_part = 1'b0;
assign unused_seed = ^{seed_state_full_i,
seed_state_partial_i,
state_idx_d,
state_idx_q,
last_state_part};
end else if (SeedType == SeedTypeStateFull) begin : gen_full_seed_handling
// Only one handshake is required.
assign seed_done_o = seed_req_o & seed_ack_i;
// Tie off unused signals.
assign update_init = 1'b0;
assign state_idx_d = '0;
assign state_idx_q = '0;
assign last_state_part = 1'b1;
assign unused_seed = ^{seed_key_i,
seed_iv_i,
seed_state_partial_i,
state_idx_d,
state_idx_q,
last_state_part};
end else begin : gen_partial_seed_handling
// Seed PartialSeedWidth bits of the state at a time. Track the part idx using a counter. The
// counter is reset when seeding the last part.
assign last_state_part = state_idx_q == LastStatePart[StateIdxWidth-1:0];
assign state_idx_d = wr_en_seed & last_state_part ? '0 :
wr_en_seed & ~last_state_part ? state_idx_q + 1'b1 : state_idx_q;
always_ff @(posedge clk_i or negedge rst_ni) begin : state_idx_reg
if (!rst_ni) begin
state_idx_q <= '0;
end else begin
state_idx_q <= state_idx_d;
end
end
// We're done upon receiving the last state part.
assign seed_done_o = seed_req_o & seed_ack_i & last_state_part;
// Tie off unused signals.
assign update_init = 1'b0;
assign unused_seed = ^{seed_key_i,
seed_iv_i,
seed_state_full_i};
end
/////////////////
// Asssertions //
/////////////////
// While performing a partial reseed of the state, the primitive can be updated. However, this
// should only be done if the number of produced bits per update / shift amount per update is
// greater than the width of the smallest NFSR (= 84) inside the primitve. Otherwise, there is a
// risk of overwriting the previously provided partial seed which reduces the amount of fresh
// entropy injected per full reseed operation.
`ASSERT(PrimTriviumPartialStateSeedWhileUpdate_A,
(SeedType == SeedTypeStatePartial) && seed_req_o && en_i |-> OutputWidth >= MinNfsrWidth)
endmodule

View file

@ -0,0 +1,159 @@
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
package prim_trivium_pkg;
typedef enum integer {
SeedTypeKeyIv, // 2 * 80 bits for key and IV, requires advancing the primitive
// 1152/OutputWidth (Trivium) or 708/OutputWidth (Bivium) times
// before the key stream becomes usable.
SeedTypeStateFull, // Seed the full state
SeedTypeStatePartial // Seed PartialSeedWidth bits of the state at a time.
} seed_type_e;
parameter int unsigned KeyIvWidth = 80;
parameter int unsigned PartialSeedWidthDefault = 32;
parameter int unsigned MinNfsrWidth = 84;
// These LFSR parameters have been generated with
// $ ./util/design/gen-lfsr-seed.py --width 288 --seed 31468618 --prefix "Trivium"
parameter int TriviumLfsrWidth = 288;
typedef logic [TriviumLfsrWidth-1:0] trivium_lfsr_seed_t;
parameter trivium_lfsr_seed_t RndCnstTriviumLfsrSeedDefault = {
32'h758a4420,
256'h31e1c461_6ea343ec_153282a3_0c132b57_23c5a4cf_4743b3c7_c32d580f_74f1713a
};
/////////////
// Trivium //
/////////////
parameter int unsigned TriviumMaxNfsrWidth = 111;
parameter int TriviumStateWidth = TriviumLfsrWidth;
function automatic logic [TriviumStateWidth-1:0] trivium_update_state(
logic [TriviumStateWidth-1:0] in
);
logic [TriviumStateWidth-1:0] out;
logic mul_90_91, mul_174_175, mul_285_286;
logic add_65_92, add_161_176, add_242_287;
// First state part intermediate results
mul_90_91 = in[90] & in[91];
add_65_92 = in[65] ^ in[92];
// Second state part intermediate results
mul_174_175 = in[174] & in[175];
add_161_176 = in[161] ^ in[176];
// Third state part intermediate results
mul_285_286 = in[285] & in[286];
add_242_287 = in[242] ^ in[287];
// Updates - feedback part
out[0] = in[68] ^ (mul_285_286 ^ add_242_287);
out[93] = in[170] ^ (add_65_92 ^ mul_90_91);
out[177] = in[263] ^ (mul_174_175 ^ add_161_176);
// Updates - shift part
out[92:1] = in[91:0];
out[176:94] = in[175:93];
out[287:178] = in[286:177];
return out;
endfunction
function automatic logic trivium_generate_key_stream(
logic [TriviumStateWidth-1:0] state
);
logic key;
logic add_65_92, add_161_176, add_242_287;
logic unused_state;
add_65_92 = state[65] ^ state[92];
add_161_176 = state[161] ^ state[176];
add_242_287 = state[242] ^ state[287];
key = add_161_176 ^ add_65_92 ^ add_242_287;
unused_state = ^{state[286:243],
state[241:177],
state[175:162],
state[160:93],
state[91:66],
state[64:0]};
return key;
endfunction
function automatic logic [TriviumStateWidth-1:0] trivium_seed_key_iv(
logic [KeyIvWidth-1:0] key,
logic [KeyIvWidth-1:0] iv
);
logic [TriviumStateWidth-1:0] state;
// [287:285] [284:173] [172:93] [92:80] [79:0]
state = {3'b111, 112'b0, iv, 13'b0, key};
return state;
endfunction
////////////
// Bivium //
////////////
parameter int unsigned BiviumMaxNfsrWidth = 93;
parameter int BiviumStateWidth = 177;
function automatic logic [BiviumStateWidth-1:0] bivium_update_state(
logic [BiviumStateWidth-1:0] in
);
logic [BiviumStateWidth-1:0] out;
logic mul_90_91, mul_174_175;
logic add_65_92, add_161_176;
// First state half intermediate results
mul_90_91 = in[90] & in[91];
add_65_92 = in[65] ^ in[92];
// Second state half intermediate results
mul_174_175 = in[174] & in[175];
add_161_176 = in[161] ^ in[176];
// Updates - feedback part
out[0] = in[68] ^ (mul_174_175 ^ add_161_176);
out[93] = in[170] ^ add_65_92 ^ mul_90_91;
// Updates - shift part
out[92:1] = in[91:0];
out[176:94] = in[175:93];
return out;
endfunction
function automatic logic bivium_generate_key_stream(
logic [BiviumStateWidth-1:0] state
);
logic key;
logic add_65_92, add_161_176;
logic unused_state;
add_65_92 = state[65] ^ state[92];
add_161_176 = state[161] ^ state[176];
key = add_161_176 ^ add_65_92;
unused_state = ^{state[175:162],
state[160:93],
state[91:66],
state[64:0]};
return key;
endfunction
function automatic logic [BiviumStateWidth-1:0] bivium_seed_key_iv(
logic [KeyIvWidth-1:0] key,
logic [KeyIvWidth-1:0] iv
);
logic [BiviumStateWidth-1:0] state;
// [176:173] [172:93] [92:80] [79:0]
state = {4'b0, iv, 13'b0, key};
return state;
endfunction
endpackage

View file

@ -41,13 +41,9 @@ module prim_generic_flash #(
output tlul_pkg::tl_d2h_t tl_o,
// Observability
input ast_pkg::ast_obs_ctrl_t obs_ctrl_i,
output logic [7:0] fla_obs_o,
input devmode_i
output logic [7:0] fla_obs_o
);
logic unused_devmode;
assign unused_devmode = devmode_i;
// convert this into a tlul write later
logic init;
assign init = 1'b1;
@ -126,8 +122,7 @@ module prim_generic_flash #(
.tl_o (tl_o),
.reg2hw (reg2hw),
.hw2reg (hw2reg),
.intg_err_o(intg_err),
.devmode_i (1'b1)
.intg_err_o(intg_err)
);
logic unused_reg_sig;

View file

@ -106,8 +106,7 @@ module prim_generic_otp
.tl_o (test_tl_o ),
.reg2hw (reg2hw ),
.hw2reg (hw2reg ),
.intg_err_o(intg_err ),
.devmode_i (1'b1 )
.intg_err_o(intg_err )
);
logic unused_reg_sig;

View file

@ -473,6 +473,8 @@ class RunTest(Deploy):
self.index = index
self.build_seed = sim_cfg.build_seed
self.seed = RunTest.get_seed()
# Systemverilog accepts seeds with a maximum size of 32 bits.
self.svseed = int(self.seed) & 0xFFFFFFFF
self.simulated_time = JobTime()
super().__init__(sim_cfg)

View file

@ -42,7 +42,7 @@ class SimCfg(FlowCfg):
# TODO: Find a way to set these in sim cfg instead
ignored_wildcards = [
"build_mode", "index", "test", "seed", "uvm_test", "uvm_test_seq",
"build_mode", "index", "test", "seed", "svseed", "uvm_test", "uvm_test_seq",
"cov_db_dirs", "sw_images", "sw_build_device", "sw_build_cmd",
"sw_build_opts"
]

View file

@ -41,7 +41,6 @@ In addition, it instantiates the following interfaces, connects them to the DUT
* ${name.upper()} IOs
* Interrupts ([`pins_if`]({{< relref "hw/dv/sv/common_ifs" >}}))
* Alerts ([`alert_esc_if`]({{< relref "hw/dv/sv/alert_esc_agent/doc" >}}))
* Devmode ([`pins_if`]({{< relref "hw/dv/sv/common_ifs" >}}))
${'###'} Common DV utility components
The following utilities provide generic helper tasks and functions to perform activities that are common across the project:

View file

@ -14,7 +14,6 @@ module tb;
`include "dv_macros.svh"
wire clk, rst_n;
wire devmode;
% if is_cip:
% if has_interrupts:
wire [NUM_MAX_INTERRUPTS-1:0] interrupts;
@ -27,7 +26,6 @@ module tb;
% if has_interrupts:
pins_if #(NUM_MAX_INTERRUPTS) intr_if(interrupts);
% endif
pins_if #(1) devmode_if(devmode);
tl_if tl_if(.clk(clk), .rst_n(rst_n));
% endif
% for agent in env_agents:
@ -72,7 +70,6 @@ module tb;
% if has_interrupts:
uvm_config_db#(intr_vif)::set(null, "*.env", "intr_vif", intr_if);
% endif
uvm_config_db#(devmode_vif)::set(null, "*.env", "devmode_vif", devmode_if);
uvm_config_db#(virtual tl_if)::set(null, "*.env.m_tl_agent*", "vif", tl_if);
% endif
% for agent in env_agents: