2

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?

  • what does it mean that you "cannot connect"? what did you try? – Serge Jul 16 '19 at 10:48
  • Which error did you have? you have not provided the `driver` and `seq_item` class definitions. – Serge Jul 16 '19 at 12:21
  • @Serge, added Minimal, Reproducible Example and its error. I have not previously specified the contents of the seq_item and driver classes, since it is completely irrelevant in this question and will only distract. seq_item can be either a complex class with a bunch of fields, or an empty blank inherited from uvm_sequence_item. A driver can be either axi4_s_master_driver, or simply a driver that pulls seq_items and immediately calls item_done. Solution lies somewhere at the agent or environment level. – Андрей Солодовников Jul 16 '19 at 12:46

2 Answers2

3

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
1

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

Serge
  • 11,616
  • 3
  • 18
  • 28
  • Yes, I know about the option of connecting the sequencer to the driver, but I do not know how to write to the sequencer port manually (as noted in the question), because in traditional use, the sequences start on it, but I cannot transfer data from fifo to the sequence. Modifying the driver also seems to me a bad idea, since the already written axi4_stream master is used, and the beauty of uvm is reuse. – Андрей Солодовников Jul 16 '19 at 14:16