blob: 6ad9e7173e80a916f47f4d9186c3da469789345c [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 flash_phy_prim_monitor extends dv_base_monitor #(
.ITEM_T (flash_phy_prim_item),
.CFG_T (flash_phy_prim_agent_cfg),
.COV_T (flash_phy_prim_agent_cov)
);
`uvm_component_utils(flash_phy_prim_monitor)
// the base class provides the following handles for use:
// flash_phy_prim_agent_cfg: cfg
// flash_phy_prim_agent_cov: cov
uvm_analysis_port #(flash_phy_prim_item) eg_rtl_port[NumBanks];
uvm_analysis_port #(flash_phy_prim_item) rd_cmd_port[NumBanks];
uvm_analysis_port #(flash_phy_prim_item) eg_rtl_lm_port[NumBanks];
flash_phy_prim_item w_item[NumBanks];
flash_phy_prim_item r_item[NumBanks];
flash_phy_prim_item lm_item[NumBanks];
logic [PhyDataW-1:0] write_buffer[NumBanks][$];
`uvm_component_new
function void build_phase(uvm_phase phase);
super.build_phase(phase);
foreach (eg_rtl_port[i]) begin
eg_rtl_port[i] = new($sformatf("eg_rtl_port[%0d]", i), this);
rd_cmd_port[i] = new($sformatf("rd_cmd_port[%0d]", i), this);
eg_rtl_lm_port[i] = new($sformatf("eg_rtl_lm_port[%0d]", i), this);
end
endfunction
task reset_task;
forever begin
@(negedge cfg.vif.rst_n);
foreach (write_buffer[i]) write_buffer[i] = '{};
end
endtask // reset_task
task run_phase(uvm_phase phase);
if (cfg.scb_otf_en) begin
`DV_SPINWAIT(wait(cfg.mon_start);,
"timeout waiting for mon_start", 100_000)
fork
super.run_phase(phase);
monitor_core();
reset_task();
join_none
end
endtask
// Capture read request from flash_core
task monitor_core();
`DV_SPINWAIT(wait(cfg.vif.rst_n == 1);,
"timeout waiting for reset deassert", 100_000)
if (cfg.scb_otf_en) begin
for (int i = 0; i < NumBanks; ++i) begin
automatic int j = i;
fork begin
// Assuming tb.dut.u_eflash.gen_flash_cores[bank].u_core.u_rd.req_i
// is one cycle per transaction.
forever begin
@cfg.vif.cb;
#0.1ns;
if (cfg.vif.rreq[j] & cfg.vif.rdy[j]) begin
r_item[j] = flash_phy_prim_item::type_id::create($sformatf("r_item[%0d]", j));
r_item[j].req = cfg.vif.req[j];
eg_rtl_port[j].write(r_item[j]);
end
end
end join_none
end
end
endtask
// collect transactions forever - already forked in dv_base_monitor::run_phase
virtual protected task collect_trans(uvm_phase phase);
`DV_SPINWAIT(wait(cfg.vif.rst_n == 1);,
"timeout waiting for reset deassert", 100_000)
`uvm_info(`gfn, $sformatf("flash_phy_prim_monitor %s", (cfg.scb_otf_en)? "enabled" :
"disabled"), UVM_MEDIUM)
if (cfg.scb_otf_en) begin
fork
for (int i = 0; i < NumBanks; ++i) begin
automatic int j = i;
fork begin
forever begin
@cfg.vif.cb;
#0.1ns;
if (cfg.vif.rsp[j].ack) begin
if (cfg.vif.req[j].rd_req & cfg.vif.req[j].prog_req) begin
`uvm_error(`gfn, $sformatf("Both prog and rd req are set"))
end else if (~cfg.vif.req[j].rd_req & cfg.vif.req[j].prog_req) begin
// collect transaction for last time check
collect_lm_item(j);
collect_wr_data(j);
end else if (cfg.vif.req[j].rd_req) begin
collect_rd_cmd(j);
end else if (cfg.vif.req[j].pg_erase_req | cfg.vif.req[j].bk_erase_req |
cfg.vif.req[j].erase_suspend_req) begin
// collect erase error transactions
collect_lm_item(j);
end
end
end
end join_none
end
join_none
end
endtask // collect_trans
task collect_rd_cmd(int bank);
flash_phy_prim_item rcmd;
rcmd = flash_phy_prim_item::type_id::create("rcmd");
rcmd.req = cfg.vif.req[bank];
rd_cmd_port[bank].write(rcmd);
endtask // collect_rd_cmd
task collect_wr_data(int bank);
if (write_buffer[bank].size() == 0) begin
w_item[bank] = flash_phy_prim_item::type_id::create($sformatf("w_item[%0d]", bank));
w_item[bank].req = cfg.vif.req[bank];
w_item[bank].rsp = cfg.vif.rsp[bank];
`uvm_info(`gfn, $sformatf("MON%0d s_addr:%x",bank, w_item[bank].req.addr), UVM_HIGH)
end
write_buffer[bank].push_back(cfg.vif.req[bank].prog_full_data);
if (cfg.vif.req[bank].prog_last) begin
w_item[bank].fq = write_buffer[bank];
eg_rtl_port[bank].write(w_item[bank]);
`uvm_info(`gfn, $sformatf("MON%0d: wbuf:%0d fq:%0d", bank,
write_buffer[bank].size(), w_item[bank].fq.size()), UVM_HIGH)
write_buffer[bank] = {};
end
endtask // collect_item
function void collect_lm_item(int bank);
flash_phy_prim_item item;
`uvm_create_obj(flash_phy_prim_item, item)
item.req = cfg.vif.req[bank];
item.rsp = cfg.vif.rsp[bank];
eg_rtl_lm_port[bank].write(item);
`uvm_info("lm_debug", $sformatf("I sent bank%0d", bank),UVM_MEDIUM)
endfunction // collect_lm_item
endclass