blob: f8d1a2e70a8c1b6d79b93e1fa626123a3ac8294e [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 rstmgr_scoreboard extends cip_base_scoreboard #(
.CFG_T(rstmgr_env_cfg),
.RAL_T(rstmgr_reg_block),
.COV_T(rstmgr_env_cov)
);
`uvm_component_utils(rstmgr_scoreboard)
// local variables
static const string sw_rst_ctrl_n_preffix = "sw_rst_ctrl_n_";
// TLM agent fifos
// local queues to hold incoming packets pending comparison
`uvm_component_new
function void build_phase(uvm_phase phase);
super.build_phase(phase);
// TODO: remove once support alert checking
do_alert_check = 0;
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
endfunction
task run_phase(uvm_phase phase);
super.run_phase(phase);
fork
monitor_por();
monitor_capture();
monitor_tlul_rst();
join_none
endtask
// Start coverage collection after the very first POR negedge, since that transition is not
// useful for coverage.
local task monitor_por();
int stretch_start;
int reset_count;
if (!cfg.en_cov) return;
@(negedge cfg.rstmgr_vif.por_n);
forever
@cfg.rstmgr_vif.por_n begin
if (cfg.rstmgr_vif.por_n == 1'b1) stretch_start = cfg.rstmgr_vif.aon_cycles;
else begin
int stretch_cycles = cfg.rstmgr_vif.aon_cycles - stretch_start;
++reset_count;
`DV_CHECK_GT(stretch_cycles, 0)
cov.reset_stretcher_cg.sample(stretch_cycles, reset_count);
end
end
endtask
local task monitor_capture();
if (!cfg.en_cov) return;
forever
@cfg.rstmgr_vif.reset_info begin
if (cfg.rstmgr_vif.reset_info != '0) begin
cov.alert_info_capture_cg.sample(cfg.rstmgr_vif.reset_info, cfg.rstmgr_vif.alert_info_en);
cov.cpu_info_capture_cg.sample(cfg.rstmgr_vif.reset_info, cfg.rstmgr_vif.cpu_info_en);
end
end
endtask
// Monitor tlul reset to update csr_utils_pkg::under_reset variable. This is needed
// because the tlul reset in rstmgr is generated internally, unlike any other modules
// where it is controlled by clk_rst_vif.
local task monitor_tlul_rst();
forever
@cfg.m_tl_agent_cfg.vif.rst_n begin
if (!cfg.m_tl_agent_cfg.vif.rst_n) begin
`uvm_info(`gfn, "tl got reset", UVM_MEDIUM)
under_reset = 1;
end else begin
`uvm_info(`gfn, "tl got out of reset", UVM_MEDIUM)
under_reset = 0;
clear_outstanding_access();
end
end
endtask
// This converts the trailing digits in a name to a number.
// It is fatal if there are no trailing digits.
local function int get_index_from_multibit_name(string name);
string suffix;
int last_char_index = name.len() - 1;
int i;
for (i = 0; i <= last_char_index; ++i) begin
byte character = name[last_char_index - i];
if (character < "0" || character > "9") break;
end
`DV_CHECK(i > 0)
suffix = name.substr(last_char_index - i, last_char_index);
return suffix.atoi();
endfunction
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.
// TODO Add support for reading registers with separate write-enable.
case (csr.get_name())
// add individual case item for each csr
"alert_test": begin
// Write only.
do_read_check = 1'b0;
end
"reset_req": begin
end
"reset_info": begin
// RW1C.
do_read_check = 1'b0;
end
"alert_regwen": begin
// RW0C.
// do_read_check = 1'b0;
end
"alert_info_ctrl": begin
// The en bit is cleared by the hardware.
do_read_check = 1'b0;
end
"alert_info_attr": begin
// Read only.
do_read_check = 1'b0;
end
"alert_info": begin
// Read only.
do_read_check = 1'b0;
if (cfg.en_cov) begin
cov.alert_info_access_cg.sample(ral.alert_info_ctrl.index.get());
end
end
"cpu_regwen": begin
// RW0C.
// do_read_check = 1'b0;
end
"cpu_info_ctrl": begin
// The en bit is cleared by the hardware.
do_read_check = 1'b0;
end
"cpu_info_attr": begin
// Read only.
do_read_check = 1'b0;
end
"cpu_info": begin
// Read only.
do_read_check = 1'b0;
if (cfg.en_cov) begin
cov.cpu_info_access_cg.sample(ral.cpu_info_ctrl.index.get());
end
end
"err_code": begin
// Set by hardware.
do_read_check = 1'b0;
end
default: begin
if (!uvm_re_match({sw_rst_ctrl_n_preffix, "*"}, csr.get_name())) begin
`uvm_info(`gfn, $sformatf("write to %0s with 0x%x", csr.get_name(), item.a_data),
UVM_MEDIUM)
do_read_check = 1'b0;
if (cfg.en_cov && addr_phase_write) begin
logic enable;
int i = get_index_from_multibit_name(csr.get_name());
enable = ral.sw_rst_regwen[i].get();
cov.sw_rst_cg_wrap[i].sample(enable, item.a_data);
end
end else if (!uvm_re_match("sw_rst_regwen_*", csr.get_name())) begin
// Nothing yet.
end else begin
`uvm_fatal(`gfn, $sformatf("invalid csr: %0s", csr.get_full_name()))
end
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
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);
// post test checks - ensure that all local fifos and queues are empty
endfunction
endclass