In this phase, we will write a receiver and use the receiver in environment class to collect the packets coming from the switch output_interface.
Receiver
Receiver collects the data bytes from the interface signal. And then unpacks the bytes in to packet using unpack_bytes method and pushes it into Rcvr2Sb_port for score boarding.
Receiver class is written in Reveicer.sv file.
Receiver class is defined by extending uvm_component class. It will drive the received transaction to scoreboard using uvm_analysis_port.
1) Define Receiver class by extending uvm_component.
`ifndef GUARD_RECEIVER
`define GUARD_RECEIVER
class Receiver extends uvm_component;
endclass : Receiver
`endif
2) Declare configuration class object.
Configuration cfg;
3) Declare an integer to hold the receiver number.
integer id;
4) Declare a virtual interface of dut out put side.
virtual output_interface.OP output_intf;
5) Declare analysis port which is used by receiver to send the received transaction to scoreboard.
uvm_analysis_port #(Packet) Rcvr2Sb_port;
6) Declare the utility macro. This utility macro provides the implementation of creat() and get_type_name() methods.
`uvm_component_utils(Receiver)
7) Define the constructor.
function new (string name, uvm_component parent);
super.new(name, parent);
endfunction : new
8) Define the build method and construct the Rcvr2Sb_port.
10) Define the run() method. This method collects the packets from the DUT output interface and unpacks it into high level transaction using transactions unpack_bytes() method.
virtualtask run();
Packet pkt;
fork forever begin // declare the queue and dynamic array here
// so they are automatically allocated for every packet
bit [7:0] bq[$],bytes[];
repeat(2) @(posedge output_intf.clock);
while (output_intf.cb.ready)
begin bq.push_back(output_intf.cb.data_out);
@(posedge output_intf.clock);
end bytes = new[bq.size()] (bq); // Copy queue into dyn array
virtualtask run();
Packet pkt;
fork forever begin // declare the queue and dynamic array here
// so they are automatically allocated for every packet
bit [7:0] bq[$],bytes[];
repeat(2) @(posedge output_intf.clock);
while (output_intf.cb.ready)
begin bq.push_back(output_intf.cb.data_out);
@(posedge output_intf.clock);
end bytes = new[bq.size()] (bq); // Copy queue into dyn array
We will update the Environment class and take instance of receiver and run the testcase.
1) Declare 4 receivers.
Receiver Rcvr[4];
2) In the build() method construct the Receivers using create() methods. Also update the id variable of the receiver object.
foreach(Rcvr[i]) begin Rcvr[i] = Receiver::type_id::create($psprintf("Rcvr%0d",i),this);
Rcvr[i].id = i;
end
(S) Environment class source code
`ifndef GUARD_ENV `define GUARD_ENV
class Environment extends uvm_env;
`uvm_component_utils(Environment)
Sequencer Seqncr; Driver Drvr;
Receiver Rcvr[4];
function new(string name , uvm_component parent = null); super.new(name, parent); endfunction: new
virtual function void build(); super.build(); uvm_report_info(get_full_name(),"START of build ",UVM_LOW); Drvr = Driver::type_id::create("Drvr",this); Seqncr = Sequencer::type_id::create("Seqncr",this);
foreach(Rcvr[i]) begin Rcvr[i] = Receiver::type_id::create($psprintf("Rcvr%0d",i),this);
Rcvr[i].id = i;
end
uvm_report_info(get_full_name(),"END of build ",UVM_LOW); endfunction virtual function void connect(); super.connect(); uvm_report_info(get_full_name(),"START of connect ",UVM_LOW); Drvr.seq_item_port.connect(Seqncr.seq_item_export); uvm_report_info(get_full_name(),"END of connect ",UVM_LOW); endfunction