Analysis_tlm_fifo only gets latest trans

Hi guys,

I encounter a issue when I using analysis fifo making transaction from monitor to scoreboard.
analysis fifos are declared in env:


function void my_env::build_phase(uvm_phase phase);
    super.build_phase(phase);
    i_agt = in_agent::type_id::create("i_agt", this);
    src_i_agt = src_in_agent::type_id::create("src_i_agt", this);
    o_agt = out_agent::type_id::create("o_agt", this);
    i_agt.is_active = UVM_ACTIVE;
    src_i_agt.is_active = UVM_PASSIVE;
    o_agt.is_active = UVM_PASSIVE;
    bus_agt = bus_agent::type_id::create("bus_agt", this);
    bus_agt.is_active = UVM_ACTIVE;
    mdl = my_model::type_id::create("mdl", this);
    scb = my_scoreboard::type_id::create("scb", this);
    agt_scb_fifo = new("agt_scb_fifo", this);
    agt_mdl_fifo = new("agt_mdl_fifo", this);
    src_i_agt_2_mdl_fifo = new("src_i_agt_2_mdl_fifo", this);
    mdl_scb_fifo = new("mdl_scb_fifo", this);
endfunction
function void my_env::connect_phase(uvm_phase phase);
   super.connect_phase(phase);
   i_agt.ap.connect(agt_mdl_fifo.analysis_export);
   src_i_agt.ap.connect(src_i_agt_2_mdl_fifo.analysis_export);
   mdl.port.connect(agt_mdl_fifo.blocking_get_export);
   mdl.src_port.connect(src_i_agt_2_mdl_fifo.blocking_get_export);
   mdl.ap.connect(mdl_scb_fifo.analysis_export);
   scb.exp_port.connect(mdl_scb_fifo.blocking_get_export);
   o_agt.ap.connect(agt_scb_fifo.analysis_export);
   scb.act_port.connect(agt_scb_fifo.blocking_get_export); 
   mdl.p_rm = this.p_rm;
   i_agt.mon.p_rm = this.p_rm;
endfunction

I have port.write() when I initial any transaction, and I have


class my_scoreboard extends uvm_scoreboard;
   audio_transaction  expect_queue[$];
   uvm_blocking_get_port #(audio_transaction)  exp_port;
   uvm_blocking_get_port #(audio_transaction)  act_port;
   `uvm_component_utils(my_scoreboard)
   extern function new(string name, uvm_component parent = null);
   extern virtual function void build_phase(uvm_phase phase);
   extern virtual task main_phase(uvm_phase phase);
endclass 
function void my_scoreboard::build_phase(uvm_phase phase);
   super.build_phase(phase);
   exp_port = new("exp_port", this);
   act_port = new("act_port", this);
endfunction 

When I use “exp_port.get(get_expect);” and “act_port.get(get_actual);”
It seems only the latest transaction popped out from the fifos.
I’ve tried to print out all packets written into the fifos and popped out from them. There is an evident difference between them.
It seems if the “get()” happens after any write(), it gets nothing but a future trans. The “get()” has to be earlier than “writes()”. Why does this happen? How to fix this?

In reply to Leo Lian:

Since you don’t show any code which relates to the writing/reading of your analysis ports, I’m going to guess that you don’t clone your transaction prior to writing. This results in re-using the same transaction handle which will overwrite your data.

In reply to cgales:

Sorry that I forgot to paste those parts.
In my monitor:


task out_monitor::main_phase(uvm_phase phase);
   audio_transaction tr;
   while(1) begin
      collect_one_pkt(tr);
      ap.write(tr);
   end
endtask

task out_monitor::collect_one_pkt(output audio_transaction tr);

    tr = new("tr");
    tr.data_l = new[1];
    tr.data_r = new[1];
    `uvm_info("out_monitor", "begin to collect one pkt", UVM_HIGH);
    @(posedge vif.AUD_DAT_VLD);
    tr.data_l[0] = vif.AUD_DAT_L;
    tr.data_r[0] = vif.AUD_DAT_R;
    `uvm_info("out_monitor", "one pkt collected", UVM_HIGH);
//    tr.print();
endtask

In my scoreboard:


task my_scoreboard::main_phase(uvm_phase phase);
    audio_transaction  get_expect,  get_actual, tmp_tran;
    bit result;
    bit first_sample_f;

    super.main_phase(phase);
    first_sample_f = 1;
    while (1) 
//    fork
    begin
    //expected trans
    begin
        exp_port.get(get_expect);
        expect_queue.push_back(get_expect);
        `uvm_info("my_scoreboard", "expect_queue push", UVM_HIGH)
        `uvm_info("my_scoreboard", get_expect.sprint(), UVM_HIGH);
    end
    //actual trans
    begin
        act_port.get(get_actual);
        if(first_sample_f)
        begin
            act_port.get(get_actual);
            first_sample_f = 0;
        end
        //tailor the actual packet according to the stimulus
        if(expect_queue.size() > 0)
        begin
            tmp_tran = expect_queue.pop_front();
            if(tmp_tran.sample_width)
            begin
                get_actual.data_l[0][23:16] = 8'h0;
                get_actual.data_r[0][23:16] = 8'h0;
            end
            if(~tmp_tran.channel[0])    get_actual.data_l.delete();
            if(~tmp_tran.channel[1])    get_actual.data_r.delete();
            result = get_actual.compare(tmp_tran);
            if(result)
            begin 
                `uvm_info("my_scoreboard", "Compare SUCCESSFULLY", UVM_HIGH)
            end
            else
            begin
                $display("the expect pkt is");
                tmp_tran.print();
                $display("the actual pkt is");
                get_actual.print();
            end
        end
        else
        begin
            `uvm_error("my_scoreboard", "Received from DUT, while Expect Queue is empty");
            $display("the unexpected pkt is");
            get_actual.print();
        end
    end
//    join
    end
endtask

The situation is that when I use “fork/join” in the scoreboard main_phase loop, since some unexpected actual trans may be got before the coresponding expected trans, one piece of error message will be printed; if I use “begin/end” instead, the “act_port” always gets the latest trans. As the “get()” occurs after the exp_port.get(), even if there’s any unexpected actual trans, they won’t be noticed.

The issue that you mentioned, that pointers refer to the same object written to the fifo, seems not the cause, as I have “new()” before each write.

In reply to Leo Lian:

The analysis_export does n ozt have any storage capabilities, i.e. you see only the last transaction. You need analysis_fifos to store your transactions.

In reply to chr_sue:

I’ve connected analysis_port in monitor to the analysis_export of a fifo in env. How do I store transactions in analysis_fifo?

In reply to Leo Lian:

This happens with the write command of the monitor to the AP.
But how do you retrieve the data from these analysis fifos?

In reply to chr_sue:

I retrieve data by “get()” from blocking_get_export of the fifo.
I already have write() to analysis_port in the monitor, but what’s wrong in my implement?

In reply to Leo Lian:

I do not really understand your architecture. Especially why you need the queue. You have already 2 tlm fifos in your environment.
BTW, they should be in the scoreboard, then your structure becomes more easy.
The process should be like this:
When you receive a transaction on your output side you have to make a get on the input tlm, retrieving a tarnsaction from there and providing this to your ref model. The output of your ref model delivers you an transaction of the same type as the output transaction has and you can make a compare.

If you could provide me a complete example I could help in some more detail. Currently it is more guessing what I do.
If you don’t want to share your code here publically you can send me an email christoph@christoph-suehnel.de

In reply to chr_sue:

I’ve sent you an email with some detailed codes and info. Thanks for your support. Looking for your response.

With the help of chr_sue, I find that in my reference model, before I write each trans into the analysis port which is finally connected to a fifo in the scoreboard, I forget to clone them. If I only write handles that points to the same object into a fifo, the content of the trans will be modified later. As they are already in the fifo, those changes will not be noticed, so the cause of the bug is very difficult to be found. The bug itself is even not obvious to be awared of.
Many thanks to chr_sue. He helps a lot.

In reply to Leo Lian:

Hi Leo,
I believe you are using expected as well as actual trans. By any chance, are you using a uvm_subscriber as well, as a part of your scoreboard architecture to put your reference model? If so, is it the recommended architecture?

Thanks,
Sri

In reply to sri205:

No, I don’t use any subscriber.
There’s no other export of the fifo connected to anything.