Search code examples
while-loopsystem-veriloguvmtest-bench

Unable to exit while loop in UVM monitor


This might be a silly mistake from my side that I have overlooked but I'm fairly new to UVM and I tried tinkering with my code for a while before this. I'm trying to send in a stream of 8 bit data within a packet using Data valid stall protocol from my UVM driver to the DUT. I'm facing an issue with my input monitor not being able to pick up these transactions that are driven.

I have a while loop with a condition that the valid bit must be high and the stall bit should be low. As long as this condition holds good, the monitor needs to pick up the data byte and push into the queue. I know for a fact that the data is being picked up and pushed to a queue as I used $display statements along the way. The problem is arising once all the data bytes are received and the valid bit goes low. Ideally, this should cause the exit from the while loop but isn't doing so. Any help here would be appreciated. I have attached a snippet of the code below. Thanks in advance.

virtual task main_phase (uvm_phase phase);

   $display("Run phase of input monitor");

    collect_transfer();

endtask: main_phase


virtual task collect_transfer();

    fork

        forever begin

            wait_for_valid_transaction_cycle();

            create_and_populate_pkt();

            broadcast_pkt();

            @(iP0_vif.cb_iP0_MON);

        end

    join_none

endtask: collect_transfer


virtual task wait_for_valid_transaction_cycle();

    wait(iP0_vif.cb_iP0_MON.ip_valid && ~iP0_vif.cb_iP0_MON.ip_stall);

endtask: wait_for_valid_transaction_cycle


virtual task create_and_populate_pkt();

    pkt = Router_seq_item :: type_id :: create("pkt");

    pkt.valid = iP0_vif.cb_iP0_MON.ip_valid;

    pkt.sop = iP0_vif.cb_iP0_MON.ip_sop;

    $display("before data collection");

    while(iP0_vif.cb_iP0_MON.ip_valid === `HIGH && iP0_vif.cb_iP0_MON.ip_stall === `LOW) begin

            $display("After checking for stall");

            pkt.data = iP0_vif.cb_iP0_MON.ip_data;

            $display(pkt.data);

            pkt.data_q.push_front(pkt.data);

            pkt.eop = iP0_vif.cb_iP0_MON.ip_eop;

            $display("print check in input monitor @ time = %0t", $time);

            @(iP0_vif.cb_iP0_MON);

    end

    $display("before printing input packet from monitor");

    Check_for_port_route_and_populate_packet_field(pkt);

    print_packet(pkt);

 endtask: create_and_populate_pkt

The $display statement "before printing input packet from monitor" is not being displayed.

HIGH is defined as a binary 1 and LOW is defined as a binary 0.

The output of the code in terms of display statements is as below.

before data collection
before checking for stall
After checking for stall
2
print check in input monitor @ time = 105
before checking for stall
After checking for stall
1
print check in input monitor @ time = 115
before checking for stall
After checking for stall
3
print check in input monitor @ time = 125

Waveform capture of the interface signals being driven to the DUT


Solution

  • It's possible that the main phase objection is being dropped elsewhere in your environment. UVM will automatically kill any threads that were spawned during a phase when it ends.

    To fix this, do not object to the main phase in your monitor. Objecting to that phase is the responsibility of the threads creating the stimulus. Instead, you should be launching this monitor during the run_phase, which will ensure that your loop is not killed until the end of simulation.

    Also, during the shutdown phase, you will want your monitor to object whenever it is currently seeing a packet. This will ensure that simulation doesn't end as soon as stimulus has been sent in, giving your other monitors time to collect responses from the DUT.