The complete implementation presented in this post can be downloaded from GitHub.
That being said, let’s go through the implementation, step-by-step.
Step 1. Define enumeration items that identify the two FIFOs
typedef enum {FIFO_MSGS, FIFO_RESP} fifo_t;
Step 2. Implement the singleton using a class that inherits uvm_object
class fifo_protection extends uvm_object;
// singleton instance
protected static fifo_protection m_inst;
typedef uvm_object_registry#(fifo_protection, "fifo_protection") type_id;
// constructor
function new(string name="fifo_protection");
super.new(name);
endfunction
// Creates/returns the singleton instance
static function fifo_protection get();
if(m_inst == null)
m_inst = fifo_protection::type_id::create("fifo_protection");
return m_inst;
endfunction
virtual function string get_type_name ();
return "fifo_protection";
endfunction
// override of the create function to create the fifo_table instance
function uvm_object create (string name="");
fifo_protection tmp = new(name);
return tmp;
endfunction
endclass
Step 3. Add the objection-related fields
Add the objection list which contains one objection for each FIFO. Add other utility fields which enable the objections or specify their resource limit.
// list of objections: one for each FIFO
local uvm_objection objs[fifo_t];
// list of fifo limits
local int objs_limit[fifo_t];
// enable flag that allows us to enable/disable fifo protections
local bit objs_en[fifo_t];
Step 4. Add objection initialization function
function void init_protection(fifo_t kind, int limit, bit en);
objs[kind] = new($sformatf("obj_%s", kind.name()));
objs_limit[kind] = limit;
objs_en[kind] = en;
endfunction
Step 5. Add resource locking/freeing API
task lock(fifo_t kind, int count=1);
if (!objs_en[kind])
`uvm_warning("FIFO_PROTECTION_LOCK_WRN",
$sformatf("The objection %s is not enabled.", kind.name()))
wait_for_resources(kind, count);
objs[kind].raise_objection(this, "", count);
endtask
function void free(fifo_t kind, int count=1);
if (!objs_en[kind])
`uvm_warning("FIFO_PROTECTION_FREE_WRN",
$sformatf("The objection %s is not enabled.", kind.name()))
objs[kind].drop_objection(this, "", count);
endfunction
function int get_resource_count(fifo_t kind);
if (!objs_en[kind])
`uvm_warning("FIFO_PROTECTION_GET_RESOURCE_COUNT_WRN",
$sformatf("The objection %s is not enabled.", kind.name()))
return objs[kind].get_objection_count(this);
endfunction
Step 6. Add objection status API
function bit are_all_free();
fifo_t ft = ft.first();
are_all_free = 1;
forever begin
are_all_free &= (get_resource_count(ft) == 0);
if ( ft == ft.last )
break;
ft = ft.next;
end
endfunction
Step 7. Add debug API
function string dump();
fifo_t ft = ft.first();
dump = "";
forever begin
dump=$sformatf("%s%s=%d/%d, ", dump, ft.name(),
(objs_limit[ft]-get_resource_count(ft)), objs_limit[ft]);
if ( ft == ft.last )
break;
ft = ft.next;
end
dump=$sformatf("fifo_protection available resources: %s", dump);
endfunction
Step 8. Create a global variable for the singleton
fifo_protection fifo_prot_ston = fifo_protection::get();
Step 9. Initialize protections
One can initialize protections for various FIFOs in the build_phase() of one’s verification environment:
fifo_prot_ston.init_protection(FIFO_MSGS, 16, 1);
fifo_prot_ston.init_protection(FIFO_RESP, 4096, 1);
One can read more about the limit argument here.
Step 10. Lock and free resources
Locking and freeing of resources is explained here.
For MESSAGE data flow one needs to:
- lock 1 resource just before sending a MESSAGE (in MESSAGE sequence, just before `uvm_do)
- release 1 resource as soon as the RAM write access is verified against the original MESSAGE packet
// lock resources in MESSAGE sequence, just before `uvm_do
fifo_prot_ston.lock(FIFO_MSGS, 1);
`uvm_do(msg_item)
……………………
// free resources in scoreboard, right after the RAM-write access is verified
fifo_prot_ston.free(FIFO_MSGS, 1);
Similarly for READ data flow one needs to:
- lock “number of READ bytes” resources as soon as the input monitor detects a READ request. Given my particular example the resource locking could be done later than MESSAGE resource lock.
- Free “number of READ bytes” resources after scoreboard checks the READ response going out on the input interface
// lock resources in scoreboard as soon as a READ request is detected on the input interface by the input monitor
fifo_prot_ston.lock(FIFO_RESP, read_req.size);
……………………
// free resources in scoreboard, right-after the READ-response on input interface is verified
fifo_prot_ston.free(FIFO_RESP, read_resp.size);
How to disable the protection
There might be scenarios that require to overfill one or more of the FIFOs. In that case it is sufficient to disable the objections for the given FIFO using the dedicated API:
fifo_prot_ston.set_enable(FIFO_RESP, 0);
It is recommended to disable one FIFO at a time and have different tests for each FIFO overflow scenario.
That’s all! Enjoy!