A number of steps on the OO-ladder have already been taken. First of all, there is the interface that does all the pin-interconnecting. One layer above there are the driver and the monitor. These two components translate between the software world and the hardware world.
The driver is instructed by the generator, through the use of transactions. In this final section the path will be completed.
First, there is the checker, that verifies the result as seen by the monitor against a golden value.
And, finally, there is a scoreboard that collects all the results.
Neither of these components will introduce new concepts, but for the sake of completeness they are discussed here. However, coming up with the golden reference will require some more work.
`include "transaction.sv"
class checkers;
mailbox #(transaction) gen2che;
mailbox #(shortint) mon2che;
mailbox #(bit) che2scb;
function new(mailbox #(shortint) m2c, mailbox #(bit) c2s);
this.mon2che = m2c;
this.che2scb = c2s;
endfunction : new
task run;
shortint expected_result, received_result;
string s;
$timeformat(-9,0," ns" , 10);
s = $sformatf("[%t | CHE] I will start checking", $time);
$display(s);
forever
begin
this.mon2che.get(received_result);
/* do something to get the.
For now, have this placeholder */
received_result = expected_result;
if (received_result == expected_result)
begin
this.che2scb.put(bit'(1));
end else begin
this.che2scb.put(bit'(0));
end
end
endtask
endclass : checkers
The checker uses multiple mailboxes. There is one incoming communication channel from the generator. This will be required to be able to determine the golden value; there is another incoming channel from the monitor for providing the obtained result, and finally, there is one outgoing channel to the scoreboard (for keeping score).
Please note that checker is a keyword in SystemVerilog. Hence, the name of the class is checkers.
When the expected outcome, or golden value is determined, the checker compares whether or not this value matches with obtained result. In the example, there is simply a placeholder.
Its decision is then sent to the scoreboard. Note the type to which the che2scb mailbox is fixed.
An example of a scoreboard is given here. There should be nothing out-of-the-usual here.
One point that is worth mentioning is the conclusion that all blocks up-until-this-point are running forever. (Or they will be if you look at the entire code for this example 😉)
A closer look at the scoreboard shows that this run( ) function only runs for a certain amount of test vectors.
class scoreboard;
mailbox #(bit) che2scb;
int NO_tests;
int no_tests_done;
int no_tests_ok;
int no_tests_nok;
function new(mailbox c2s);
this.che2scb = c2s;
NO_tests = 0;
no_tests_done = 0;
no_tests_ok = 0;
no_tests_nok = 0;
endfunction : new
task run(int NOT);
byte result;
string s;
this.NO_tests = NOT;
$timeformat(-9,0," ns" , 10);
s = $sformatf("[%t | SCB] I will start keeping score", $time);
$display(s);
while (this.no_tests_done < this.NO_tests)
begin
this.che2scb.get(result);
no_tests_done++;
if (result > 0)
begin
no_tests_ok++;
//$display("[SCB] successful test registered");
end else begin
no_tests_nok++;
//$display("[SCB] unsuccessful test registered");
end
end /* while*/
endtask : run
task showReport;
$display("[SCB] Test report");
$display("[SCB] ------------");
$display("[SCB] # tests done : %0d", this.no_tests_done);
$display("[SCB] # tests ok : %0d", this.no_tests_ok);
$display("[SCB] # tests failed : %0d", this.no_tests_nok);
$display("[SCB] # tests success rate : %0.2f", this.no_tests_ok/this.no_tests_done*100);
endtask : showReport
endclass : scoreboard