Is there a way to connect uvm_tlm_analysis_fifo to uvm_driver?

I need to connect a module output to it's input controlled by uvm_driver. I see it this way.

                  -----       ---------------------
                 | MON |---->|uvm_tlm_analysis_fifo|
                  -----       ---------------------
                    ^                    |
                    |                    |
 -------------      |      -------       |
|             |---------->| slave |      v
|     DUT     |            -------    --------
|             |<---------------------| master |
 -------------                        --------

I tried the following.

typedef class seq_item extends uvm_sequence_item;
typedef class driver extends uvm_driver(seq_item);

class agent extends uvm_agent;
    `uvm_component_utils(agent)
    uvm_analysis_port#(seq_item) ap;
    uvm_tlm_analysis_fifo#(seq_item) fifo;
    driver                       drv;

    function new(string name, uvm_component parent);
        super.new(name,parent);
    endfunction: new

    function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        ap  = new("ap", this);
        fifo= new("fifo",this); 
        drv = driver::type_id::create("driver", this);
    endfunction: build_phase

    function void connect_phase(uvm_phase phase);
        super.connect_phase(phase);
        ap.connect(fifo.analysis_export);
        drv.seq_item_port.connect(fifo.get_peek_export);
    endfunction: connect_phase

    task main_phase(uvm_phase phase);
        seq_item trans;
        phase.raise_objection(this);
        repeat(5) begin
            trans = seq_item::type_id::create("inTrans");
            assert(trans.randomize());
            ap.write(trans);
        end
        phase.drop_objection(this);
    endtask
endclass: agent

Here Minimal, Reproducible Example.

`include "uvm_macros.svh"
package t;
    import uvm_pkg::*;
    class seq_item extends uvm_sequence_item;
        `uvm_object_utils(seq_item)

        rand bit [31:0]            data;
        function new(string name = "seq_item");
            super.new(name);
        endfunction: new
    endclass: seq_item

    class driver extends uvm_driver#(seq_item);
        `uvm_component_utils(driver)
        function new (string name, uvm_component parent);
            super.new(name, parent);
        endfunction: new

        task main_phase(uvm_phase phase);
            fork
                super.main_phase(phase);
            join_none
            forever begin
                seq_item_port.get_next_item(req);
                `uvm_info(get_type_name(),$psprintf("Got item with data: %h",req.data),UVM_NONE);
                seq_item_port.item_done();
            end
        endtask: main_phase
    endclass: driver

    class test extends uvm_test;
        `uvm_component_utils(test)
        uvm_analysis_port#(seq_item) ap;
        uvm_tlm_analysis_fifo#(seq_item) fifo;

        driver                       drv;

        function new(string name, uvm_component parent);
            super.new(name,parent);
        endfunction: new
        function void build_phase(uvm_phase phase);
            super.build_phase(phase);
            ap  = new(.name("apb_ap"), .parent(this));
            fifo= new("fifo",this); 
            drv = driver        ::type_id::create(.name("driver"), .parent(this) );
        endfunction: build_phase

        function void connect_phase(uvm_phase phase);
            super.connect_phase(phase);
            ap.connect(fifo.analysis_export);
            drv.seq_item_port.connect(fifo.get_peek_export);
        endfunction: connect_phase

        task main_phase(uvm_phase phase);
            seq_item trans;
            phase.raise_objection(this);
            repeat(5) begin
                trans = seq_item::type_id::create("inTrans");
                assert(trans.randomize());
                ap.write(trans);
            end
            phase.drop_objection(this);
        endtask
    endclass: test
endpackage

module top();
    import uvm_pkg::*;
    import t::*;
    initial begin
        run_test();
    end
endmodule

It's generates following errors.

 ** Error: (vsim-7065) 5.sv(51): Illegal assignment to class mtiUvm.uvm_pkg::uvm_port_base #(class mtiUvm.uvm_pkg::uvm_sqr_if_base #(class work.t::seq_item, class work.t::seq_item)) from class mtiUvm.uvm_pkg::uvm_get_peek_imp #(class work.t::seq_item, class mtiUvm.uvm_pkg::uvm_tlm_fifo_base #(class work.t::seq_item))
#    Time: 0 ns  Iteration: 0  Region: /t File: 5.sv
# ** Error: (vsim-8754) 5.sv(51): Actual input arg. of type 'class mtiUvm.uvm_pkg::uvm_get_peek_imp #(class work.t::seq_item, class mtiUvm.uvm_pkg::uvm_tlm_fifo_base #(class work.t::seq_item))' for formal 'provider' of 'connect' is not compatible with the formal's type 'class mtiUvm.uvm_pkg::uvm_port_base #(class mtiUvm.uvm_pkg::uvm_sqr_if_base #(class work.t::seq_item, class work.t::seq_item))'.

As I get, I can't connect fifo to master's seq_item_port. Is there a way to implement such scheme? If driver can really get items just from sequencer, how to manually write items from sequencer to seq_item_port?

Upvotes: 2

Views: 1243

Answers (2)

As I suspected, I can't implement questions scheme without sequencer. So result scheme will be follow:

                  -----       ---------
                 | MON |---->|sequencer|
                  -----      |   ------|
                    ^        |  | fifo |
                    |         --------- 
 -------------      |    -------     |
|             |-------->| slave |    v
|     DUT     |          -------  --------
|             |<-----------------| master |
 -------------                    --------

Question was how make sequencer write to seq_item_export without running a sequence. To achieve this, as pointed in answer above I was needed to implement get_next_item task in a custom sequencer class like this:

class fifo_sequencer#(type REQ=uvm_sequence_item,RSP=REQ) extends uvm_sequencer#(REQ,RSP);
    `uvm_component_param_utils(fake_sequencer#(REQ,RSP))

    uvm_tlm_analysis_fifo#(REQ) fifo;

    function new(string name, uvm_component parent);
        super.new(name, parent);
        fifo = new("fifo", this);
    endfunction

    task get_next_item(output REQ t);
        fifo.get_peek_export.get(t);
    endtask

    function void item_done(RSP item = null);
        if (item != null) begin
            seq_item_export.put_response(item);
        end
    endfunction
endclass

Note that in addition to get_next_item task, item_done function must also be implemented (or you may get an Item_done() called with no outstanding requests fatal_error).
Thus Minimal, Reproducible Example will transfer into:

`include "uvm_macros.svh"
package t;
    import uvm_pkg::*;

    class seq_item extends uvm_sequence_item;
        `uvm_object_utils(seq_item)

        rand bit [31:0]            data;
        function new(string name = "seq_item");
            super.new(name);
        endfunction: new
    endclass: seq_item

    class driver extends uvm_driver#(seq_item);
        `uvm_component_utils(driver)
        function new (string name, uvm_component parent);
            super.new(name, parent);
        endfunction: new

        task main_phase(uvm_phase phase);
            fork
                super.main_phase(phase);
            join_none
            forever begin
                seq_item_port.get_next_item(req);
                `uvm_info(get_type_name(),$psprintf("Got item with data: %h",req.data),UVM_NONE);
                seq_item_port.item_done();
            end
        endtask: main_phase
    endclass: driver

    class fifo_sequencer#(type REQ=uvm_sequence_item,RSP=REQ) extends uvm_sequencer#(REQ,RSP);
        `uvm_component_param_utils(fifo_sequencer#(REQ,RSP))

        uvm_tlm_analysis_fifo#(REQ) fifo;

        function new(string name, uvm_component parent);
            super.new(name, parent);
            fifo = new("fifo", this);
        endfunction

        task get_next_item(output REQ t);
            fifo.get_peek_export.get(t);
        endtask

        function void item_done(RSP item = null);
            if (item != null) begin
                seq_item_export.put_response(item);
            end
        endfunction
    endclass

    class test extends uvm_test;
        `uvm_component_utils(test)
        uvm_analysis_port#(seq_item) ap;

        driver                      drv;
        fifo_sequencer#(seq_item)   sqr;

        function new(string name, uvm_component parent);
            super.new(name,parent);
        endfunction: new
        function void build_phase(uvm_phase phase);
            super.build_phase(phase);
            ap  = new("apb_ap", this);
            sqr = fifo_sequencer#(seq_item) ::type_id::create("sequencer", this);
            drv = driver                    ::type_id::create("driver", this);
        endfunction: build_phase

        function void connect_phase(uvm_phase phase);
            super.connect_phase(phase);
            ap.connect(sqr.fifo.analysis_export);
            drv.seq_item_port.connect(sqr.seq_item_export);
        endfunction: connect_phase

        task main_phase(uvm_phase phase);
            seq_item trans;
            phase.raise_objection(this);
            repeat(5) begin
                trans = seq_item::type_id::create("inTrans");
                assert(trans.randomize());
                ap.write(trans);
            end
            phase.drop_objection(this);
        endtask
    endclass: test
endpackage

module top();
    import uvm_pkg::*;
    import t::*;
    initial begin
        run_test();
    end
endmodule

Upvotes: 3

Serge
Serge

Reputation: 12354

You need a uvm_sequencer with seq_item_export to connect to the driver's seq_item_port. You do not have one.

If you want to use the fifo path, you need to create and connect a generic port in the driver class.

This is a message generated by vcs:

Error-[ICTTFC] Incompatible complex type usage
Incompatible complex type usage in task or function call.
The following expression is incompatible with the formal parameter of the 
function. The type of the actual is 'class uvm_pkg::uvm_get_peek_imp#(class 
t::seq_item,class uvm_pkg::uvm_tlm_fifo_base#(class t::seq_item))', while 
the type of the formal is 'class uvm_pkg::uvm_port_base#(class 
uvm_pkg::uvm_sqr_if_base#(class t::seq_item,class t::seq_item))'. 
Expression: this.fifo.get_peek_export
Source info: this.drv.seq_item_port.connect(this.fifo.get_peek_export)

As far as I can see from it, you still need to create a port as well as an implementation of your own seq_item_export with a task of passing of sequence items between them. I think that you can create a fake sequencer to handle it (and leave the driver alone).

Upvotes: 1

Related Questions