This file defines the following OVM consumer components.
| OVM Consumers | |
| This file defines the following OVM consumer components. | |
| ovm_consumer | A generic OVM driver/consumer component that can get transactions from a blocking get port or receive transactions via is blocking put export. |
| blocking_get_port | When connected, a consumer process will continually get from the port and call put with the received transaction. |
| analysis_port | The put method will also write the transaction to this port for coverage, scoreboarding or other analysis. |
| blockling_put_export | Transactions put to this export will be forwarded to the put method, where the received transaction is executed. |
| run | If the blocking_get_port is connected, a the run task will continually get from the port and put the transaction for immediate execution. |
| put | Called via the <blocking_put_port> or run process, this process “executes” the transaction by printing a message and waiting a bit of time. |
| ovm_driver_req | This consumer’s run task will continually retrieve and execute transaction items from this port in one of two ways, chosen randomly ofr -- either using get_next_item/item_done or peek/get. |
| seq_item_port | Transactions are fetched from this port. |
| ap | Processed requests are published to this port. |
| ovm_driver_rsp | This consumer’s run task will continually retrieve, execute, and send back a response in one of three ways, chosen randomly-- either using peek/get, get/delay/put, or get_next_item/item_done. |
| seq_item_port | When connected, a consumer process will continually get from the port and call put with the response. |
| ovm_subscribe | This consumer receives transactions via the ovm_analysis_export inherited from its ovm_subscriber base class. |
| analysis_export | Transactions are received via this inherited analysis export. |
A generic OVM driver/consumer component that can get transactions from a blocking get port or receive transactions via is blocking put export. If the blocking_get_port has been connected, this consumer will continually get and execute transactions from that port. Transactions coming in from the <blocking_get_export> will also be executed. A semaphore is used to arbitrate these two potential sources of transactions.
class ovm_consumer #(type T=int) extends ovm_component;
typedef ovm_consumer #(T) this_type;
`ovm_component_param_utils(this_type)
// Port: blocking_get_port
//
// When connected, a consumer process will continually get from
// the port and call <put> with the received transaction. This
// port may be left unconnected.
ovm_blocking_get_port #(T) blocking_get_port;
// Port: analysis_port
//
// The <put> method will also write the transaction to this port
// for coverage, scoreboarding or other analysis. This port may
// be left unconnected.
ovm_analysis_port #(T) analysis_port;
// Port: blockling_put_export
//
// Transactions put to this export will be forwarded to the <put>
// method, where the received transaction is executed. (In this
// case, we merely print the fact a transaction was received.)
// A semaphore is used to govern access by both this port and the
// active process that putting transaction that were gotten from
// the blocking_get_port.
ovm_blocking_put_imp #(T,this_type) blocking_put_export;
function new(string name, ovm_component parent=null);
super.new(name,parent);
blocking_put_export = new("blocking_put_export",this);
blocking_get_port = new("blocking_get_port",this,0);
analysis_port = new("analysis_port",this);
endfunction
const string type_name = {"ovm_consumer #(",T::type_name,")"};
virtual function string get_type_name();
return type_name;
endfunction
int num_trans=0;
local semaphore lock = new(1);
// Task: run
//
// If the <blocking_get_port> is connected, a the run task will
// continually get from the port and <put> the transaction for
// immediate execution. If <put> is busy with a transaction
// recevied from the blocking_put_export, this process will block
// until the transaction is complete.
task run();
T tr;
if (blocking_get_port.size()<=0)
return;
forever begin
blocking_get_port.get(tr);
put(tr);
end
endtask
// Task: put
//
// Called via the <blocking_put_port> or <run> process, this
// process "executes" the transaction by printing a message
// and waiting a bit of time. It uses a semaphore to prevent
// multiple callers from colliding.
task put (T tr);
lock.get();
num_trans++;
ovm_report_info("recevied", tr.convert2string());
analysis_port.write(tr);
#100;
lock.put();
endtask
endclassWhen connected, a consumer process will continually get from the port and call put with the received transaction. This port may be left unconnected.
The put method will also write the transaction to this port for coverage, scoreboarding or other analysis. This port may be left unconnected.
Transactions put to this export will be forwarded to the put method, where the received transaction is executed. (In this case, we merely print the fact a transaction was received.) A semaphore is used to govern access by both this port and the active process that putting transaction that were gotten from the blocking_get_port.
task run()
If the blocking_get_port is connected, a the run task will continually get from the port and put the transaction for immediate execution. If put is busy with a transaction recevied from the blocking_put_export, this process will block until the transaction is complete.
This consumer’s run task will continually retrieve and execute transaction items from this port in one of two ways, chosen randomly ofr -- either using get_next_item/item_done or peek/get.
class ovm_driver_req extends ovm_component;
`ovm_component_utils(ovm_driver_req)
// Port: seq_item_port
//
// Transactions are fetched from this port. Although this port is bidirectional,
// this component will not return responses.
ovm_seq_item_pull_port #(ovm_apb_rw) seq_item_port;
// Port: ap
//
// Processed requests are published to this port.
ovm_analysis_port #(ovm_apb_rw) ap;
function new(string name, ovm_component parent=null);
super.new(name,parent);
seq_item_port = new("seq_item_port",this);
ap = new("ap",this);
endfunction
int max_trans = 100;
int num_trans = 0;
local integer unsigned m[int];
function void mem_model(ref ovm_apb_rw tr);
if(tr.cmd == ovm_apb_rw::WR)
m[tr.addr] = tr.data;
else begin
if (m.exists(tr.addr))
tr.data = m[tr.addr];
else
tr.data = 'hx;
end
endfunction
task run();
ovm_apb_rw req;
ovm_apb_rw pop;
while (num_trans < max_trans) begin
randcase
// get_next_item/item_done
1: begin
seq_item_port.get_next_item(req);
mem_model(req);
#10;
seq_item_port.item_done();
ovm_report_info("OVM Consumer",
{"via GET_NEXT_ITEM/ITEM_DONE - ", req.convert2string()});
end
// peek/get
1: begin
seq_item_port.peek(req);
mem_model(req);
#10;
seq_item_port.get(pop);
ovm_report_info("OVM Consumer",
{"via PEEK/GET - ", req.convert2string()});
end
endcase
ap.write(req);
num_trans++;
end
endtask
endclassTransactions are fetched from this port. Although this port is bidirectional, this component will not return responses.
Processed requests are published to this port.
This consumer’s run task will continually retrieve, execute, and send back a response in one of three ways, chosen randomly-- either using peek/get, get/delay/put, or get_next_item/item_done.
class ovm_driver_rsp extends ovm_component;
`ovm_component_param_utils(ovm_driver_rsp)
// Port: seq_item_port
//
// When connected, a consumer process will continually get from
// the port and call <put> with the response.
ovm_seq_item_pull_port #(ovm_apb_rw) seq_item_port;
function new(string name, ovm_component parent=null);
super.new(name,parent);
seq_item_port = new("seq_item_port",this);
endfunction
int max_trans=100;
int num_trans=0;
local integer unsigned m[int];
function ovm_apb_rw mem_model(ref ovm_apb_rw tr);
ovm_apb_rw rsp;
$cast(rsp,tr.clone());
if(tr.cmd == ovm_apb_rw::WR) begin
m[tr.addr] = tr.data;
end
else begin
if (m.exists(tr.addr))
rsp.data = m[tr.addr];
else
rsp.data = 'hx;
end
rsp.set_id_info(tr);
return rsp;
endfunction // mem_model
task run();
ovm_apb_rw req;
ovm_apb_rw rsp;
while (num_trans < max_trans) begin
randcase
// peek/get
1: begin
ovm_report_info("OVM Consumer","Using peek/get");
seq_item_port.peek(req);
rsp = mem_model(req);
seq_item_port.get(req);
#10;
seq_item_port.put_response(rsp);
ovm_report_info("OVM Consumer",
{ " via PEEK/GET - ",
"req=",req.convert2string(), " rsp=", rsp.convert2string() });
end
// get-delay-put
1: begin
ovm_report_info("OVM Consumer","Using get-delay-put");
seq_item_port.get(req);
rsp = mem_model(req);
#10 seq_item_port.put_response(rsp);
ovm_report_info("OVM Consumer",
{ " via GET/DELAY/PUT - ",
"req=",req.convert2string(), " rsp=", rsp.convert2string() });
end
// get_next_item/item_done
1: begin
ovm_report_info("OVM Consumer","Using get_next_item/item_done");
seq_item_port.get_next_item(req);
rsp = mem_model(req);
seq_item_port.item_done();
#10;
seq_item_port.put_response(rsp);
ovm_report_info("OVM Consumer",
{ " via GET_NEXT_ITEM/ITEM_DONE/PUT_RESPONSE - ",
"req=",req.convert2string(), " rsp=", rsp.convert2string() });
end
endcase
end
endtask
endclassWhen connected, a consumer process will continually get from the port and call put with the response.
This consumer receives transactions via the ovm_analysis_export inherited from its ovm_subscriber base class.
class ovm_subscribe #(type T=int) extends ovm_subscriber #(T);
// Port: analysis_export
//
// Transactions are received via this inherited analysis export.
ovm_analysis_port #(T) ap;
function new(string name, ovm_component parent=null);
super.new(name, parent);
ap = new("ap",this);
endfunction
virtual function void write(T t);
ovm_transaction o_tr;
vmm_data v_tr;
if ($cast(o_tr,t)) begin
ovm_report_info("received_ovm",o_tr.convert2string());
ap.write(t);
end
else if ($cast(v_tr,t))
ovm_report_info("received_vmm",v_tr.psdisplay());
endfunction
endclassTransactions are received via this inherited analysis export.
Called via the blocking_put_port or run process, this process “executes” the transaction by printing a message and waiting a bit of time.
task put ( T tr )
If the blocking_get_port is connected, a the run task will continually get from the port and put the transaction for immediate execution.
task run()