Skip to content

Commit

Permalink
[otbn,dv] Implementation of RND Interface in DV
Browse files Browse the repository at this point in the history
This commit includes processing 32b packages from EDN instead of
probing DUT and setting 256b directly. Also includes changes in
Mock EDN for Verilator simulations.

Signed-off-by: Canberk Topal <ctopal@lowrisc.org>
  • Loading branch information
ctopal authored and rswarbrick committed Oct 5, 2021
1 parent 90b438a commit 5480504
Show file tree
Hide file tree
Showing 15 changed files with 232 additions and 99 deletions.
19 changes: 6 additions & 13 deletions hw/ip/otbn/dv/model/iss_wrapper.cc
Original file line number Diff line number Diff line change
Expand Up @@ -229,17 +229,6 @@ static bool read_ext_reg(const std::string &reg_name,
return true;
}

static std::string wlen_val_to_hex_str(uint32_t val[8]) {
std::ostringstream oss;

oss << std::hex << "0x";
for (int i = 7; i >= 0; --i) {
oss << std::setfill('0') << std::setw(8) << val[i];
}

return oss.str();
}

ISSWrapper::ISSWrapper() : tmpdir(new TmpDir()) {
std::string model_path(find_otbn_model());

Expand Down Expand Up @@ -368,9 +357,13 @@ void ISSWrapper::start() {
mirrored_.status = 1;
}

void ISSWrapper::edn_rnd_data(uint32_t edn_rnd_data[8]) {
void ISSWrapper::edn_rnd_cdc_done() {
run_command("edn_rnd_cdc_done\n", nullptr);
}

void ISSWrapper::edn_step(uint32_t edn_rnd_data) {
std::ostringstream oss;
oss << "edn_rnd_data " << wlen_val_to_hex_str(edn_rnd_data) << "\n";
oss << "edn_step " << std::hex << "0x" << edn_rnd_data << "\n";
run_command(oss.str(), nullptr);
}

Expand Down
8 changes: 6 additions & 2 deletions hw/ip/otbn/dv/model/iss_wrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,12 @@ struct ISSWrapper {
void start();

// Provide data for RND. ISS will stall when RND is read and RND data isn't
// available
void edn_rnd_data(uint32_t edn_rnd_data[8]);
// available. RND data is available only when 8 32b packages are sent and
// also RTL signals CDC is done.
void edn_step(uint32_t edn_rnd_data);

// Signals 256b EDN random number is valid in the RTL.
void edn_rnd_cdc_done();

// Signal URND reseed at beginning of execution is complete
void edn_urnd_reseed_complete();
Expand Down
38 changes: 29 additions & 9 deletions hw/ip/otbn/dv/model/otbn_core_model.sv
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
module otbn_core_model
import otbn_pkg::*;
import otbn_model_pkg::*;
import edn_pkg::*;
#(
// Size of the instruction memory, in bytes
parameter int ImemSizeByte = 4096,
Expand All @@ -28,17 +29,19 @@ module otbn_core_model
// real implementation running alongside and we check DMEM contents on completion.
parameter string DesignScope = ""
)(
input logic clk_i,
input logic rst_ni,
input logic clk_i,
input logic clk_edn_i,
input logic rst_ni,
input logic rst_edn_ni,

input logic start_i, // start the operation
output bit done_o, // operation done
input logic start_i, // start the operation
output bit done_o, // operation done

output err_bits_t err_bits_o, // valid when done_o is asserted
output err_bits_t err_bits_o, // valid when done_o is asserted

input logic edn_rnd_data_valid_i, // provide RND data from EDN
input logic [WLEN-1:0] edn_rnd_data_i,
input logic edn_urnd_data_valid_i, // URND reseed from EDN is valid
input edn_pkg::edn_rsp_t edn_rnd_i, // EDN response interface
input logic edn_rnd_cdc_done_i, // RND from EDN is valid (DUT perspective)
input logic edn_urnd_data_valid_i, // URND reseed from EDN is valid

output bit [7:0] status_o, // STATUS register
output bit [31:0] insn_cnt_o, // INSN_CNT register
Expand Down Expand Up @@ -82,6 +85,20 @@ module otbn_core_model

bit unused_raw_err_bits;

logic unused_rnd_rsp_fips;

// EDN Stepping is done with the EDN clock for also asserting the CDC measures in the design.
always_ff @(posedge clk_edn_i or negedge rst_edn_ni) begin
if (!rst_edn_ni) begin
// If we are in reset there is nothing to do.
end else begin
if (edn_rnd_i.edn_ack) begin
edn_model_step(model_handle,
edn_rnd_i.edn_bus);
end
end
end

always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
if (model_state != 0) begin
Expand All @@ -97,7 +114,6 @@ module otbn_core_model
model_state <= otbn_model_step(model_handle,
start_i,
model_state,
edn_rnd_data_valid_i, edn_rnd_data_i,
edn_urnd_data_valid_i,
status_d,
insn_cnt_d,
Expand All @@ -110,10 +126,14 @@ module otbn_core_model
end else begin
// If we're not running and we're not being told to start, there's nothing to do.
end
if (edn_rnd_cdc_done_i) begin
edn_model_rnd_cdc_done(model_handle);
end
end
end

assign unused_raw_err_bits = ^raw_err_bits_q[31:$bits(err_bits_t)];
assign unused_rnd_rsp_fips = edn_rnd_i.edn_fips;

assign err_bits_o = raw_err_bits_q[$bits(err_bits_t)-1:0];

Expand Down
37 changes: 22 additions & 15 deletions hw/ip/otbn/dv/model/otbn_model.cc
Original file line number Diff line number Diff line change
Expand Up @@ -249,29 +249,31 @@ int OtbnModel::start() {
return 0;
}

int OtbnModel::step(svLogic edn_rnd_data_valid,
svLogicVecVal *edn_rnd_data, /* logic [255:0] */
svLogic edn_urnd_data_valid,
void OtbnModel::edn_step(svLogicVecVal *edn_rnd_data /* logic [31:0] */) {
ISSWrapper *iss = ensure_wrapper();

iss->edn_step(edn_rnd_data->aval);
}

void OtbnModel::edn_rnd_cdc_done() {
ISSWrapper *iss = ensure_wrapper();
iss->edn_rnd_cdc_done();
}

int OtbnModel::step(svLogic edn_urnd_data_valid,
svBitVecVal *status /* bit [7:0] */,
svBitVecVal *insn_cnt /* bit [31:0] */,
svBitVecVal *err_bits /* bit [31:0] */,
svBitVecVal *stop_pc /* bit [31:0] */) {
assert(edn_rnd_data && err_bits && insn_cnt && err_bits && stop_pc);
assert(insn_cnt && err_bits && stop_pc);

ISSWrapper *iss = ensure_wrapper();
if (!iss)
return -1;

assert(!is_xz(edn_rnd_data_valid));
assert(!is_xz(edn_urnd_data_valid));

try {
if (edn_rnd_data_valid) {
uint32_t int_edn_rnd_data[8];
set_rnd_data(int_edn_rnd_data, edn_rnd_data);
iss->edn_rnd_data(int_edn_rnd_data);
}

if (edn_urnd_data_valid) {
iss->edn_urnd_reseed_complete();
}
Expand Down Expand Up @@ -548,9 +550,14 @@ OtbnModel *otbn_model_init(const char *mem_scope, const char *design_scope,

void otbn_model_destroy(OtbnModel *model) { delete model; }

void edn_model_step(OtbnModel *model,
svLogicVecVal *edn_rnd_data /* logic [31:0] */) {
model->edn_step(edn_rnd_data);
}

void edn_model_rnd_cdc_done(OtbnModel *model) { model->edn_rnd_cdc_done(); }

unsigned otbn_model_step(OtbnModel *model, svLogic start, unsigned model_state,
svLogic edn_rnd_data_valid,
svLogicVecVal *edn_rnd_data, /* logic [255:0] */
svLogic edn_urnd_data_valid,
svBitVecVal *status /* bit [7:0] */,
svBitVecVal *insn_cnt /* bit [31:0] */,
Expand Down Expand Up @@ -599,8 +606,8 @@ unsigned otbn_model_step(OtbnModel *model, svLogic start, unsigned model_state,
return model_state;

// Step the model once
switch (model->step(edn_rnd_data_valid, edn_rnd_data, edn_urnd_data_valid,
status, insn_cnt, err_bits, stop_pc)) {
switch (
model->step(edn_urnd_data_valid, status, insn_cnt, err_bits, stop_pc)) {
case 0:
// Still running: no change
break;
Expand Down
10 changes: 7 additions & 3 deletions hw/ip/otbn/dv/model/otbn_model.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,16 @@ class OtbnModel {
// zero. Returns 0 on success; -1 on failure.
int start();

// EDN Step sends ISS the RND data when ACK signal is high.
void edn_step(svLogicVecVal *edn_rnd_data /* logic [31:0] */);

// Signals that RTL is finished processing RND data from EDN
void edn_rnd_cdc_done();

// Step once in the model. Returns 1 if the model has finished, 0 if not and
// -1 on failure. If gen_trace is true, pass trace entries to the trace
// checker. If the model has finished, writes otbn.ERR_BITS to *err_bits.
int step(svLogic edn_rnd_data_valid,
svLogicVecVal *edn_rnd_data, /* logic [255:0] */
svLogic edn_urnd_data_valid, svBitVecVal *status /* bit [7:0] */,
int step(svLogic edn_urnd_data_valid, svBitVecVal *status /* bit [7:0] */,
svBitVecVal *insn_cnt /* bit [31:0] */,
svBitVecVal *err_bits /* bit [31:0] */,
svBitVecVal *stop_pc /* bit [31:0] */);
Expand Down
11 changes: 8 additions & 3 deletions hw/ip/otbn/dv/model/otbn_model_dpi.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ OtbnModel *otbn_model_init(const char *mem_scope, const char *design_scope,
// Delete an OtbnModel
void otbn_model_destroy(OtbnModel *model);

// Call edn_step function of OtbnModel
void edn_model_step(OtbnModel *model,
svLogicVecVal *edn_rnd_data /* logic [31:0] */);

// Signal RTL is finished processing RND data to Model
void edn_model_rnd_cdc_done(OtbnModel *model);

// The main entry point to the OTBN model, exported from here and used in
// otbn_core_model.sv.
//
Expand Down Expand Up @@ -52,11 +59,9 @@ void otbn_model_destroy(OtbnModel *model);
// the contents of DMEM from the ISS and inject them into the simulation
// memory.
//
// If start is true, we start the model and then step once (as described
// If start is true, we start the model and then step once (as
// above).
unsigned otbn_model_step(OtbnModel *model, svLogic start, unsigned model_state,
svLogic edn_rnd_data_valid,
svLogicVecVal *edn_rnd_data, /* logic [255:0] */
svLogic edn_urnd_data_valid,
svBitVecVal *status /* bit [7:0] */,
svBitVecVal *insn_cnt /* bit [31:0] */,
Expand Down
8 changes: 6 additions & 2 deletions hw/ip/otbn/dv/model/otbn_model_pkg.sv
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,16 @@ package otbn_model_pkg;

import "DPI-C" function void otbn_model_destroy(chandle model);

import "DPI-C" function void edn_model_step(chandle model,
logic [31:0] edn_rnd_data);

import "DPI-C" function
void edn_model_rnd_cdc_done(chandle model);

import "DPI-C" context function
int unsigned otbn_model_step(chandle model,
logic start,
int unsigned model_state,
logic edn_rnd_data_valid,
logic [WLEN-1:0] edn_rnd_data,
logic edn_urnd_data_valid,
inout bit [7:0] status,
inout bit [31:0] insn_cnt,
Expand Down
67 changes: 60 additions & 7 deletions hw/ip/otbn/dv/otbnsim/sim/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,15 @@ def __init__(self) -> None:
self._err_bits = 0
self.pending_halt = False

self._new_rnd_data = None # type: Optional[int]
self._urnd_reseed_complete = False

self.rnd_256b_counter = 0
self.rnd_cdc_pending = False
self.rnd_cdc_counter = 0
self.rnd_256b = 0
self.rnd_cached_tmp = None # type: Optional[int]
self.counter = 0

def get_next_pc(self) -> int:
if self._pc_next_override is not None:
return self._pc_next_override
Expand All @@ -66,8 +72,46 @@ def set_next_pc(self, next_pc: int) -> None:
assert(self.is_pc_valid(next_pc))
self._pc_next_override = next_pc

def set_rnd_data(self, rnd_data: int) -> None:
self._new_rnd_data = rnd_data
def step_edn(self, rnd_data: int) -> None:
# Take the new data
assert 0 <= rnd_data < (1 << 32)

# There should not be a pending RND result before an EDN step.
assert not self.rnd_cdc_pending

# Collect 32b packages in a 256b variable
self.rnd_256b = ((self.rnd_256b << 32) | rnd_data) & ((1 << 256) - 1)

if self.rnd_256b_counter == 7:
# Reset the 32b package counter and wait until receiving done
# signal from RTL
self.rnd_256b_counter = 0
self.rnd_cdc_pending = True
else:
# Count until 8 valid packages are received
self.rnd_256b_counter += 1
return

# Reset the 32b package counter and wait until receiving done
# signal from RTL
self.rnd_256b_counter = 0
self.rnd_cdc_pending = True

def rnd_completed(self) -> None:
# This will be called when all the packages are received and processed
# by RTL. Model will set RND register, pending flag and internal
# variables will be cleared.

# These must be true since model calculates RND data faster than RTL.
# But the synchronisation of the data should not take more than
# 5 cycles ideally.
assert self.rnd_cdc_pending
assert self.rnd_cdc_counter < 6

self.wsrs.RND.set_unsigned(self.rnd_256b)
self.rnd_256b = 0
self.rnd_cdc_pending = False
self.rnd_cdc_counter = 0

def set_urnd_reseed_complete(self) -> None:
self._urnd_reseed_complete = True
Expand Down Expand Up @@ -110,14 +154,14 @@ def commit(self, sim_stalled: bool) -> None:
# If error bits are set, pending_halt should have been set as well.
assert self._err_bits == 0

if self._new_rnd_data:
self.wsrs.RND.set_unsigned(self._new_rnd_data)
self._new_rnd_data = None
# If model is waiting for a RTL done signal regarding RND while also executing instructions,
# increase the counter
if self.rnd_cdc_pending:
self.rnd_cdc_counter += 1

if self._urnd_stall:
if self._urnd_reseed_complete:
self._urnd_stall = False

return

# If self._start_stall, this is the end of the stall cycle at the start
Expand Down Expand Up @@ -170,7 +214,15 @@ def start(self) -> None:

# Reset CSRs, WSRs, loop stack and call stack
self.csrs = CSRFile()

# Save the RND value when starting another run because when a SW
# run finishes we still keep RND data.
old_rnd = self.wsrs.RND._random_value

self.wsrs = WSRFile()
if old_rnd is not None:
self.wsrs.RND.set_unsigned(old_rnd)

self.loop_stack = LoopStack()
self.gprs.start()

Expand All @@ -188,6 +240,7 @@ def stop(self) -> None:
clear the busy flag and write STOP_PC.
'''

if self._err_bits:
# Abort all pending changes, including changes to external registers.
self._abort()
Expand Down
2 changes: 1 addition & 1 deletion hw/ip/otbn/dv/otbnsim/sim/wsr.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ def commit(self) -> None:

def request_value(self) -> bool:
'''Signals intent to read RND, returns True if a value is available'''
if self._random_value:
if self._random_value is not None:
return True

self.pending_request = True
Expand Down
Loading

0 comments on commit 5480504

Please sign in to comment.