# OVM Consumers

This file defines the following OVM consumer components.

Summary

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.

### 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. 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
>     endclass

### 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.

### 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.

### 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.

### run

> 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.

### put

> task put ( | T | tr | )

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.

### 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.

>     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

>     endclass

### seq_item_port

Transactions are fetched from this port. Although this port is bidirectional, this component will not return responses.

### 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.

>     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

>     endclass

### 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.

>     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

>     endclass

### analysis_export

Transactions are received via this inherited analysis export.

> task put ( | T | tr | )

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 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.
When connected, a consumer process will continually get from the port and call put with the received transaction.