SV Verification - 3Scoreboad Verification Results
This article uses the system verilog language to verify a router.v module. The reference document is "SystemVerilog Testbench Lab Guide" published by Synopsys in 2012
The top-level file is shown in the figure below. The components in this section are all called in the test.sv file.
1. Scoreboard class
Create a new check class to compare input and output packets. The main function of the check class is to use mailbox es to communicate between Drivers and Recivers. A new covergroup method is added to this class. Use the covergroup function to verify how many packets need to be sent to the router in order to test all input and output ports. Add functional verification to the Scoreboard to verify the testbanch process and test all input and output combined ports. End the simulation when finished.
class Scoreboard; string name; // unique identifier event DONE; // flag to indicate goal reached Packet refPkt[$]; // reference Packet array Packet pkt2send; // Packet object from Drivers Packet pkt2cmp; // Packet object from Receivers pkt_mbox driver_mbox; // mailbox for Packet objects from Drivers pkt_mbox receiver_mbox; // mailbox for Packet objects from Receivers bit[3:0] sa, da; // functional coverage properties covergroup router_cov; coverpoint sa; coverpoint da; cross sa, da; endgroup extern function new(string name = "Scoreboard", pkt_mbox driver_mbox = null, receiver_mbox = null); extern virtual task start(); extern virtual function void check(); endclass: Scoreboard
In the start() task, when a Packet package is found from receiver_mbox, the package will be assigned to pkt2cmp. Then wrap everything in driver_mbox into the refPkt[$] queue. Then in check(), the pkt2cmp packet is compared with the output port reference packet in refPkt specified by da in the packet, and if no reference packet is found in refPkt, an error message is printed.
function Scoreboard::new(string name, pkt_mbox driver_mbox, receiver_mbox); if (TRACE_ON) $display("[TRACE]%0t %s:%m", $time, name); this.name = name; if (driver_mbox == null) driver_mbox = new(); this.driver_mbox = driver_mbox; if (receiver_mbox == null) receiver_mbox = new(); this.receiver_mbox = receiver_mbox; router_cov = new(); endfunction: new task Scoreboard::start(); if (TRACE_ON) $display("[TRACE]%0t %s:%m", $time, name); fork forever begin receiver_mbox.get(pkt2cmp); while (driver_mbox.num()) begin Packet pkt; driver_mbox.get(pkt); refPkt.push_back(pkt); end check(); end join_none endtask: start
In the check() task, use the real variable coverage_result to save the verification coverage result, use the compare() method to compare the data of the received and sent packets, and use the display() method to print debugging information.
In the start() task driver_mbox, all packages are assigned to refPkt[ ] team List back ， Find arrive r e f P k t [ ] queue, find refPkt[ ] queue, find the starting data in refPkt and assign it to pkt2send, and then compare the pkt2cmp with the pkt2cmp package. Then assign the variables sa and da in the pkt2cmp package to the class variables, and trigger the router_cov.sample() function verification function. Finally, use $get_coverage () to get the verification coverage. When the number of received packets reaches the value of the global variable run_for_n_packets or the verification coverage reaches 100%, the event signal DONE is triggered to stop the simulation.
function void Scoreboard::check(); int index[$]; string message; static int pkts_checked = 0; real coverage_result = 0.0; if (TRACE_ON) $display("[TRACE]%0t %s:%m", $time, name); index = refPkt.find_first_index() with (item.da == pkt2cmp.da); if (index.size() <= 0) begin $display("\n%m\n[ERROR]%0t %s not found in Reference Queue\n", $time, pkt2cmp.name); pkt2cmp.display("ERROR"); $finish; end pkt2send = refPkt[index]; refPkt.delete(index); if (!pkt2send.compare(pkt2cmp, message)) begin $display("\n%m\n[ERROR]%0t Packet #%0d %s\n", $time, pkts_checked, message); pkt2send.display("ERROR"); pkt2cmp.display("ERROR"); $finish; end this.sa = pkt2send.sa; this.da = pkt2send.da; router_cov.sample(); coverage_result = $get_coverage(); $display("[NOTE]%0t Packet #%0d %s Cvrg = %3.2f", $time, pkts_checked++, message, coverage_result); if ((pkts_checked >= run_for_n_packets) || ( coverage_result == 100.0)) ->DONE; endfunction: check
2. The result of running the code
At the beginning of the simulation, the reset() task will be executed first. It can be seen that 15 clock cycles after the reset_n signal is reset, frame_n will be pulled low, and only when frame_n pulls down the corresponding channel will its din have randomized data. .
Each channel will send three signals of address, beat, and data. As shown in the figure below, the signal corresponding to the first four clock cycles of the din channel is 4'b1111, indicating that its output address is channel 15. Then, after waiting for four clock beats, it is found that the data of the dout channel is consistent with the data of the din channel.
The simulation results without adding functional verification, the packets sent 2000 times are verified correctly.
Add the simulation results of the verification function, and the verification ends automatically when the functional verification rate reaches 100%.