blob: 565b11c384a233b49e14dbeac33d4406c346590b [file]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
// If using this, instantiate it somewhere that "u_model" will resolve to the corresponding instance
// of the otbn_core_model module. For example, you might instantiate it in your testbench next to
// your model. In that case, SystemVerilog's symbol resolution rules ("go up until it works") should
// do the right thing.
interface otbn_model_if
import keymgr_pkg::otbn_key_req_t;
#(
// Size of the instruction memory, in bytes
parameter int ImemSizeByte = 4096,
localparam int ImemAddrWidth = prim_util_pkg::vbits(ImemSizeByte)
) (
input logic clk_i,
input logic rst_ni,
input otbn_key_req_t keymgr_key_i
);
import uvm_pkg::*;
// Inputs to DUT
logic [7:0] cmd_q; // CMD register
logic cmd_qe; // CMD register enable
// Outputs from DUT
bit err; // Something went wrong
bit [31:0] stop_pc; // PC at end of operation
otbn_pkg::err_bits_t err_bits; // Error bits; updated when STATUS switches to idle
// Mirrored registers
bit [7:0] status; // STATUS register
chandle handle; // Handle for DPI calls to C model
clocking cb @(posedge clk_i);
endclocking
// Wait until reset or change of status.
task automatic wait_status();
automatic bit [7:0] old_status = status;
while (rst_ni === 1'b1 && status == old_status) begin
@(negedge clk_i or negedge rst_ni);
end
endtask
// Mark the entirety of IMEM as invalid
//
// Call this on a negedge of clk_i to ensure sequencing with the otbn_model_step on the following
// posedge.
function automatic void invalidate_imem();
`uvm_info("otbn_model_if", "Invalidating IMEM", UVM_HIGH)
`DV_CHECK_FATAL(u_model.otbn_model_invalidate_imem(handle) == 0,
"Failed to invalidate IMEM", "otbn_model_if")
endfunction
// Mark the entirety of DMEM as invalid
//
// Call this on a negedge of clk_i to ensure sequencing with the otbn_model_step on the following
// posedge.
function automatic void invalidate_dmem();
`uvm_info("otbn_model_if", "Invalidating DMEM", UVM_HIGH)
`DV_CHECK_FATAL(u_model.otbn_model_invalidate_dmem(handle) == 0,
"Failed to invalidate DMEM", "otbn_model_if")
endfunction
// Ask the Python model to compute a CRC step for a memory write
//
// This doesn't actually update any model state (we pass in the old state and delta, and the
// function returns the new state). But we still call out to Python because that avoids us having
// to write our own CRC function and ensures that the RTL matches the standardised CRC-32-IEEE
// checksum.
function automatic bit [31:0] step_crc(bit [47:0] item, bit [31:0] crc_state);
`DV_CHECK_FATAL(u_model.otbn_model_step_crc(handle, item, crc_state) == 0,
"Failed to update CRC", "otbn_model_if")
return crc_state;
endfunction
// Pass loop warp rules to the model
function automatic void take_loop_warps(chandle memutil);
u_model.otbn_take_loop_warps(handle, memutil);
endfunction
function automatic bit has_loop_warps(chandle memutil);
return u_model.otbn_has_loop_warps(memutil) != 0;
endfunction
task automatic send_err_escalation(bit [31:0] err_val);
`uvm_info("otbn_model_if", "Escalating errors", UVM_HIGH)
force u_model.wakeup_iss = 1;
`DV_CHECK_FATAL(u_model.otbn_model_send_err_escalation(handle, err_val, 1'b0) == 0,
"Failed to escalate errors", "otbn_model_if")
@(posedge clk_i or negedge rst_ni);
force u_model.wakeup_iss = 0;
release u_model.wakeup_iss;
endtask: send_err_escalation
task automatic lock_immediately(bit [31:0] err_val);
string lock_path = "tb.u_model.lock_immediately_q";
`uvm_info("otbn_model_if", "Locking immediately after error", UVM_HIGH)
force u_model.wakeup_iss = 1;
`DV_CHECK_FATAL(u_model.otbn_model_send_err_escalation(handle, err_val, 1'b1) == 0,
"Failed to lock immediately",
"otbn_model_if")
`DV_CHECK_FATAL(uvm_hdl_deposit(lock_path, 1'b1) == 1,
"Failed to let SV model know about locking",
"otbn_model_if")
@(posedge clk_i or negedge rst_ni);
force u_model.wakeup_iss = 0;
release u_model.wakeup_iss;
endtask: lock_immediately
function automatic void set_software_errs_fatal(bit new_val);
`uvm_info("otbn_model_if", "writing to software_errs_fatal", UVM_HIGH);
`DV_CHECK_FATAL(u_model.otbn_model_set_software_errs_fatal(handle, new_val) == 0,
"Failed to set software_errs_fatal", "otbn_model_if")
endfunction
function automatic void otbn_set_no_sec_wipe_chk();
`uvm_info("otbn_model_if", "writing to no_sec_wipe_data_chk", UVM_HIGH);
`DV_CHECK_FATAL(u_model.otbn_set_no_sec_wipe_chk(handle) == 0,
"Failed to set no_sec_wipe_data_chk", "otbn_model_if")
endfunction
function automatic void otbn_disable_stack_check();
`uvm_info("otbn_model_if", "Disabling stack integrity checks", UVM_HIGH);
`DV_CHECK_FATAL(u_model.otbn_disable_stack_check(handle) == 0,
"Failed to disable stack integrity checks", "otbn_model_if")
endfunction
// The err signal is asserted by the model if it fails to find the DUT or if it finds a mismatch
// in results. It should never go high.
`ASSERT(NoModelErrs, !err)
endinterface