A “scoreboard” is a verification component that checks the data sent to the DUT against the data received from the DUT. The fundamental flow of the scoreboard is simple:
- Items sent to the DUT are added to the scoreboard and stored in its data base.
- Items returned from the DUT (and collected by the monitors) are added to the scoreboard to be matched against the items sent.
Basically, the matching algorithm is as follows:
- When a new match item is transmitted to the scoreboard, search the add items in the data base to find the first item that is identical to the matchitem.
- If no match is found, issue a DUT error like “DUT sent an unexpected item.”
- At the end of the test, if the scoreboard data base contains items that have not been matched, issue a DUT error like “The scoreboard is not empty at end of test.”
The following code implements this matching algorithm in e:
extend scoreboard {
match(new_item : packet) is {
var match_idx :=
// the index of item with 0 differences
first_index (
deep_compare_physical(new_item, it, 1).size() == 0);
check SCBD_MATCH_FOUND that match_idx != UNDEF else
dut_error(“no item matching ”, match_item);
};
};
This algorithm has two main drawbacks.
The first drawback is that this algorithm cannot handle DUTs in which the out data is not of same type as the in data. What if, for example, the DUT is a bridge connecting two buses, each of a different protocol? For checking such a DUT, the scoreboard must compare items of bus A with items of Bus B.
The other drawback is the potential for performance degradation. If the items list gets long, searching it for each and every new match item might take too long.
This blog suggests an alternative algorithm for the data compare. This algorithm relies on the efficiency of keyed lists--hash tables-- as opposed to searching regular lists.
The process we suggest is this:
- For every data item added to the scoreboard, calculate a number that is unique to this item’s data. This number will be the key of the item in the scoreboard items list.
- When looking for a match in the items list, instead of traversing the list comparing items, use the efficient keyed list method--key_index()--for finding an item with a matching key.
One way to calculate the hash number is to use the known hash function CRC32. You can pack the data item into a bit list and calculate a CRC on the list using the ecrc_32() method. If two items have the same CRC, there is a very high probability that these items are identical. You can choose, of course, any other hash function you prefer.
This solution not only provides desirable performance, it also tackles the other drawback mentioned above – when the data is packed into a bits list, the comparison does not rely on the type of the data item. Furthermore, you can decide which of the fields to pack. For example, if the address field is expected to be changed by the DUT, do not pack this field.
Implementation for this kind of scoreboard defines two types – one type is the scoreboard item, containing an integer (to be the key) and a data item. The other type is the scoreboard itself. A basic scoreboard should include a list of scoreboard items and add and match methods.
The following e code shows an example of a scoreboard template:
<'
template struct scoreboard_item of (<add_item'type> : struct) {
uid : int;
item : <add_item'type>;
};
template unit scoreboard of (<add_item'type> : struct,
<match_item'type> : struct) {
add_ip : in interface_port of tlm_analysis of
<add_item'type> using prefix=add_ is instance;
match_ip : in interface_port of tlm_analysis of
<match_item'type> using prefix=match_ is instance;
!all_items : list (key:uid) of scoreboard_item of <add_item'type>;
// add_write()
// adding an item –
// calculate the crc and use as the key
add_write(add_item : <add_item'type>) is {
var data_bits := pack(packing.high, add_item);
var uid := data_bits.crc_32(0, data_bits.size()/8);
var new_item : scoreboard_item of
<add_item'type> = new with {
.item = add_item;
.uid = uid;
};
all_items.add(new_item);
};
// match_write()
// finding a match –
// calculate crc, and find an item with same crc
match_write(match_item : <match_item'type>) is {
var data_bits := pack(packing.high, match_item);
var match_uid := data_bits.crc_32(0,
data_bits.size()/8);
var match_index := all_items.key_index(match_uid);
check SCBD_MATCH_FOUND that match_index != UNDEF else
dut_error("no item matching ", match_item);
if match_index != UNDEF {
all_items.delete(match_index);
};
};
// check()
// at end of run check that the scoreboard is empty,
// all items were matched
check() is also {
check SCBD_NO_EMPTY that all_items is empty else
dut_error("scoreboard is not empty at end of test ",
all_items);
};
};
'>
To use this template for creating a scoreboard, instantiate it with the required types, and connect its ports to relevant monitors. The following code instantiates a scoreboard handling the types packet_s and transfer_s:
<’
unit env {
scbd : scoreboard of (packet_s, transfer_s) is instance;
};
‘>
The code shown here is basic, but efficient. It is based on the assumption that the probability of two different items having the same key is zero. If you suspect that this will not be the case, you can alter the implementation. You can chose a different hash function, and you can also modify the scbd_item struct so that it contains more than one data item. You could even implement a “classic” hash table, with a linked list of all items with same key:
<'
template struct scoreboard_item of
(<add_item'type> : struct) {
uid : int;
item : <add_item'type>;
next : scoreboard_item of <add_item'type>;
};
'>
You are welcome to copy the templates shown here to use to create your own scoreboard. And if you have cool ideas for enhancing the scoreboard, you are more than welcome to share them here, with your fellow verification engineers.
Efrat Shneydor, Team Specman