blob: 8b8323037620651a8e0b3cd879e8b7ade1ea8177 [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 pattgen_monitor extends dv_base_monitor #(
.ITEM_T (pattgen_item),
.CFG_T (pattgen_agent_cfg),
.COV_T (pattgen_agent_cov)
);
`uvm_component_utils(pattgen_monitor)
`uvm_component_new
bit reset_asserted = 1'b0;
// analysis ports connected to scb
uvm_analysis_port #(pattgen_item) item_port[NUM_PATTGEN_CHANNELS];
function void build_phase(uvm_phase phase);
super.build_phase(phase);
for (uint i = 0; i < NUM_PATTGEN_CHANNELS; i++) begin
item_port[i] = new($sformatf("item_port[%0d]", i), this);
end
endfunction : build_phase
virtual task run_phase(uvm_phase phase);
wait(cfg.vif.rst_ni);
collect_trans(phase);
endtask : run_phase
virtual protected task collect_trans(uvm_phase phase);
for (uint i = 0; i < NUM_PATTGEN_CHANNELS; i++) begin
fork
automatic uint channel = i;
collect_channel_trans(channel);
reset_thread();
mon_pcl(channel);
join_none
end
endtask : collect_trans
virtual task collect_channel_trans(uint channel);
bit bit_data;
uint bit_cnt;
pattgen_item dut_item;
forever begin
wait(cfg.en_monitor);
dut_item = pattgen_item::type_id::create("dut_item");
bit_cnt = 0;
`uvm_info(`gfn, $sformatf("PATTGEN_MON%d start: bit_cnt:%0d len:%0d",
channel, bit_cnt, cfg.length[channel]), UVM_MEDIUM)
fork
begin : isolation_thread
fork
// capture pattern bits
begin
do begin
wait(cfg.vif.rst_ni);
get_pattgen_bit(channel, bit_data);
`uvm_info(`gfn, $sformatf("\n--> monitor: channel %0d, polar %b, data[%0d] %b",
channel, cfg.polarity[channel], bit_cnt, bit_data),
UVM_HIGH)
dut_item.data_q.push_back(bit_data);
bit_cnt++;
end while (bit_cnt < cfg.length[channel]);
// must see the channel_done intr is asserted because reset can be issued
// immediately right after the last bit
wait(cfg.channel_done[channel]);
// avoid race condition (counter is achieved and reset is issued at the same time)
if (!reset_asserted && !cfg.error_injected[channel]) begin
// monitor only pushes item if chan_done intr is asserted
item_port[channel].write(dut_item);
`uvm_info(`gfn, $sformatf("\n--> monitor: send dut_item for channel %0d\n%s",
channel, dut_item.sprint()), UVM_MEDIUM)
bit_cnt = 0;
cfg.channel_done[channel] = 1'b0;
end
end
// handle reset
@(posedge reset_asserted);
// handle errored channels
error_channel_process(channel, bit_cnt, dut_item);
join_any
disable fork;
end : isolation_thread
join
end
endtask : collect_channel_trans
virtual task reset_thread();
forever begin
@(negedge cfg.vif.rst_ni);
reset_asserted = 1'b1;
// implement other clean-up actions under reset here
cfg.error_injected = '{default:0};
cfg.length = '{default:0};
cfg.channel_done = '{default:0};
@(posedge cfg.vif.rst_ni);
reset_asserted = 1'b0;
end
endtask : reset_thread
virtual task error_channel_process(uint channel, ref uint bit_cnt, ref pattgen_item item);
@(posedge cfg.error_injected[channel]);
bit_cnt = 0;
`uvm_info(`gfn, $sformatf("\n--> monitor: drop dut_item for channel %0d\n%s",
channel, item.sprint()), UVM_DEBUG)
@(negedge cfg.error_injected[channel]);
endtask: error_channel_process
// update of_to_end to prevent sim finished when there is any activity on the bus
// ok_to_end = 0 (bus busy) / 1 (bus idle)
virtual task monitor_ready_to_end();
forever begin
@(cfg.vif.pcl_tx, cfg.vif.pda_tx);
ok_to_end = (cfg.vif.pcl_tx === {NUM_PATTGEN_CHANNELS{1'b0}}) &&
(cfg.vif.pda_tx === {NUM_PATTGEN_CHANNELS{1'b0}});
end
endtask : monitor_ready_to_end
// collect bits alligned by polarized clock
virtual task get_pattgen_bit(uint channel, output bit bit_o);
bit stop_thread = 1'b0;
`DV_CHECK_LT_FATAL(channel, NUM_PATTGEN_CHANNELS, "invalid channel index")
while (!stop_thread) begin
fork
begin : isolation_thread
fork
begin
get_pcl_edge(channel);
bit_o = cfg.vif.pda_tx[channel];
stop_thread = 1'b1;
end
// if polarity is updated, fork is disabled and the first thread is rerun with
// updated polarity value to capture data
@(cfg.polarity[channel]);
join_any
disable fork;
end : isolation_thread
join
end
endtask : get_pattgen_bit
// Monitor vif.pcl_tx[channel]
// This task runs with cfg.chk_prediv[channel].
// if chk_prediv is set, check free running counter 'free_run_cnt'
// is matched with expected 'div' value to assure
// pattgen clk div is accurate.
virtual task mon_pcl(int channel);
int free_run_cnt, skip_one_cyc;
wait(cfg.chk_prediv[channel]);
get_pcl_edge(channel);
`uvm_info(`gfn, $sformatf("monitor: start mon_pcl channel %0d", channel), UVM_MEDIUM)
fork
forever begin
@(posedge cfg.vif.clk_i);
free_run_cnt++;
end
forever begin
get_pcl_edge(channel);
#1;
`DV_CHECK_EQ(free_run_cnt, cfg.div[channel])
free_run_cnt = 0;
end
join_none
endtask // mon_pcl
// Wait edge based on the polarity
task get_pcl_edge(int channel);
if (cfg.polarity[channel]) begin
@(negedge cfg.vif.pcl_tx[channel]);
end else begin
@(posedge cfg.vif.pcl_tx[channel]);
end
endtask
endclass : pattgen_monitor