有没有办法将 uvm_tlm_analysis_fifo 连接到 uvm_driver?

Is there a way to connect uvm_tlm_analysis_fifo to uvm_driver?

我需要将模块输出连接到由 uvm_driver 控制的输入。 我是这样看的。

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

我尝试了以下方法。

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

这里是最小的、可重现的例子。

`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

它生成以下错误。

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

据我所知,我无法将 fifo 连接到 master 的 seq_item_port。有没有办法实施这样的计划?如果driver真的可以只从sequencer中获取item,如何手动将sequencer中的item写入seq_item_port?

您需要 uvm_sequencerseq_item_export 才能连接到 driver 的 seq_item_port。你没有。

如果要使用fifo路径,需要在driver class.

中创建并连接一个通用端口

这是 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)

据我所知,您仍然需要创建一个端口以及您自己的 seq_item_export 的实现,其任务是在它们之间传递序列项。我认为你可以创建一个假的音序器来处理它(并且单独留下 driver)。

正如我所怀疑的,没有定序器我无法实现问题方案。所以结果方案如下:

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

问题是如何让音序器在没有 运行 序列的情况下写入 seq_item_export。为了实现这一点,正如上面的回答所指出的,我需要在自定义 sequencer class 中实现 get_next_item 任务,如下所示:

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

请注意,除了 get_next_item task 之外,还必须实施 item_done function(否则您可能会得到 Item_done() called with no outstanding requests fatal_error)。
因此,最小的、可重现的示例将转换为:

`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