Search code examples
system-verilogfifouvm

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?


Solution

  • 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