blob: 66acbe9d3d2d0001c4945ee3dd49f5397a0d80bf [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
class edn_scoreboard extends cip_base_scoreboard #(
.CFG_T(edn_env_cfg),
.RAL_T(edn_reg_block),
.COV_T(edn_env_cov)
);
`uvm_component_utils(edn_scoreboard)
virtual edn_cov_if cov_vif;
// TLM agent fifos
uvm_tlm_analysis_fifo#(push_pull_item#(.HostDataWidth(csrng_pkg::CSRNG_CMD_WIDTH)))
cs_cmd_fifo;
uvm_tlm_analysis_fifo#(push_pull_item#(.HostDataWidth(csrng_pkg::FIPS_GENBITS_BUS_WIDTH)))
genbits_fifo;
uvm_tlm_analysis_fifo#(push_pull_item#(.HostDataWidth(FIPS_ENDPOINT_BUS_WIDTH)))
endpoint_fifo[MAX_NUM_ENDPOINTS];
uvm_tlm_analysis_fifo#(bit) rsp_sts_fifo;
// local queues to hold incoming packets pending comparison
bit[FIPS_ENDPOINT_BUS_WIDTH - 1:0] endpoint_data_q[$];
// Sample interrupt pins at read data phase. This is used to compare with intr_state read value.
bit [NumEdnIntr-1:0] intr_pins;
`uvm_component_new
function void build_phase(uvm_phase phase);
super.build_phase(phase);
genbits_fifo = new("genbits_fifo", this);
cs_cmd_fifo = new("cs_cmd_fifo", this);
rsp_sts_fifo = new("cs_rsp_sts_fifo", this);
for (int i = 0; i < MAX_NUM_ENDPOINTS; i++) begin
endpoint_fifo[i] = new($sformatf("endpoint_fifo[%0d]", i), this);
end
if (!uvm_config_db#(virtual edn_cov_if)::get(null, "*.env" , "edn_cov_if", cov_vif)) begin
`uvm_fatal(`gfn, $sformatf("Failed to get edn_cov_if from uvm_config_db"))
end
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
endfunction
task run_phase(uvm_phase phase);
super.run_phase(phase);
fork
process_genbits_fifo();
process_rsp_sts_fifo();
join_none
for (int i = 0; i < MAX_NUM_ENDPOINTS; i++) begin
automatic int j = i;
fork
begin
process_endpoint_fifo(j);
end
join_none;
end
endtask
virtual task process_tl_access(tl_seq_item item, tl_channels_e channel, string ral_name);
uvm_reg csr;
bit do_read_check = 1'b1;
bit write = item.is_write();
uvm_reg_addr_t csr_addr = cfg.ral_models[ral_name].get_word_aligned_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.ral_models[ral_name].csr_addrs}) begin
csr = cfg.ral_models[ral_name].default_map.get_reg_by_offset(csr_addr);
`DV_CHECK_NE_FATAL(csr, null)
end
else begin
`uvm_fatal(`gfn, $sformatf("Access unexpected addr 0x%0h", csr_addr))
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
// for write, update local variable and fifo at address phase
// 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
if (addr_phase_read) intr_pins = cfg.intr_vif.pins;
if (data_phase_read) begin
bit [NumEdnIntr-1:0] intr_en = `gmv(ral.intr_enable);
foreach (intr_pins[i]) begin
edn_intr_e intr = edn_intr_e'(i);
`DV_CHECK_CASE_EQ(intr_pins[i], (intr_en[i] & item.d_data[i]),
$sformatf("Interrupt_pin: %0s", intr.name));
if (cfg.en_cov) begin
cov.intr_cg.sample(i, intr_en[i], item.d_data[i]);
cov.intr_pins_cg.sample(i, intr_pins[i]);
end
end
end
do_read_check = 1'b0;
end
"intr_enable": begin
// FIXME
end
"intr_test": begin
if (addr_phase_write && cfg.en_cov) begin
bit [NumEdnIntr-1:0] intr_en = `gmv(ral.intr_enable);
bit [NumEdnIntr-1:0] intr_exp = `gmv(ral.intr_state) | item.a_data;
foreach (intr_exp[i]) begin
cov.intr_test_cg.sample(i, item.a_data[i], intr_en[i], intr_exp[i]);
end
end
end
"ctrl": begin
end
"sw_cmd_req": begin
end
"sw_cmd_sts": begin
do_read_check = 1'b0;
end
"boot_ins_cmd": begin
end
"boot_gen_cmd": begin
end
"sum_sts": begin
end
"generate_cmd": begin
end
"reseed_cmd": begin
end
"max_num_reqs_between_reseeds": begin
end
"recov_alert_sts": begin
end
"alert_test", "main_sm_state", "err_code", "err_code_test", "regwen": begin
// Do nothing.
// TODO: Found error in stress_all_with_rand_reset. Check if need to verify them.
end
"main_sm_state": begin
do_read_check = 1'b0;
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 (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()))
end
void'(csr.predict(.value(item.d_data), .kind(UVM_PREDICT_READ)));
end
endtask
task process_genbits_fifo();
push_pull_item#(.HostDataWidth(csrng_pkg::FIPS_GENBITS_BUS_WIDTH)) genbits_item;
bit[ENDPOINT_BUS_WIDTH - 1:0] endpoint_data;
bit fips;
forever begin
genbits_fifo.get(genbits_item);
fips = genbits_item.h_data[csrng_pkg::GENBITS_BUS_WIDTH];
for (int i = 0; i < csrng_pkg::GENBITS_BUS_WIDTH/ENDPOINT_BUS_WIDTH; i++) begin
endpoint_data = genbits_item.h_data >> (i * ENDPOINT_BUS_WIDTH);
endpoint_data_q.push_back({fips, endpoint_data});
end
end
endtask
task process_rsp_sts_fifo();
bit rsp_sts;
forever begin
rsp_sts_fifo.get(rsp_sts);
if ((cfg.boot_req_mode == MuBi4False) && (cfg.auto_req_mode == MuBi4False)) begin
// Check register value if not boot_req_mode/auto_req_mode
csr_spinwait(.ptr(ral.sw_cmd_sts.cmd_sts), .exp_data(rsp_sts));
end
end
endtask
task process_endpoint_fifo(uint endpoint);
push_pull_item#(.HostDataWidth(FIPS_ENDPOINT_BUS_WIDTH)) endpoint_item;
uint index, q_size;
bit match;
forever begin
endpoint_fifo[endpoint].get(endpoint_item);
index = 0;
match = 0;
q_size = endpoint_data_q.size();
do begin
if (endpoint_item.d_data == endpoint_data_q[index]) begin
match = 1;
endpoint_data_q.delete(index);
end
else if (index == q_size - 1) begin
`uvm_fatal(`gfn, $sformatf("No match for endpoint_data: %h", endpoint_item.d_data))
end
else begin
index++;
end
end
while (!match);
end
endtask
virtual function void reset(string kind = "HARD");
super.reset(kind);
// reset local fifos queues and variables
endfunction
function void check_phase(uvm_phase phase);
super.check_phase(phase);
// TODO: post test checks - ensure that all local fifos and queues are empty
endfunction
endclass