Разделение доменов в UVM - PullRequest
1 голос

Для сброса отдельных агентов тестовой среды я пытаюсь перенести их в отдельные домены.Однако я столкнулся с трудностью: когда я устанавливаю отдельный домен для агента, последовательные элементы перестают поступать в драйвер этого агента.

Ниже приведен простейший пример, который я могу написать.Если вы закомментируете строки

    ag1.set_domain (d1);
    ag2.set_domain (d2);

, драйверы агентов получат данные, если вы раскомментируете их, они остановятся.Однако, если вы поместите переход внутри блока fork, это произойдет.
Если вы переместите настройку домена в основную фазу тестового класса, данные будут отправлены, но переход к pre_reset_phase не произойдет.

`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 = "apb_seq_item");
            super.new(name);
        endfunction: new
    endclass: seq_item

    class m_sequence extends uvm_sequence#(seq_item);
        `uvm_object_utils(m_sequence)

        function new(string name = "");
            super.new(name);
        endfunction: new

        task body();
            repeat(5) begin
                req = seq_item::type_id::create("ap_it");
                start_item(req);
                req.randomize();
                finish_item(req);
            end
        endtask: body
    endclass: m_sequence

    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 agent extends uvm_agent;
        `uvm_component_utils(agent)
        uvm_analysis_port#(seq_item) ap;

        uvm_sequencer#(seq_item)     seqr;
        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));
            seqr= uvm_sequencer#(seq_item) ::type_id::create(.name("uvm_sequenver"), .parent(this) );
            drv = driver        ::type_id::create(.name("driver"), .parent(this) );
        endfunction: build_phase

        function void connect_phase(uvm_phase phase);
            super.connect_phase(phase);
            drv.seq_item_port.connect(seqr.seq_item_export);
        endfunction: connect_phase

        task pre_reset_phase(uvm_phase phase);
            fork
                super.pre_reset_phase(phase);
            join_none
            `uvm_info(get_type_name(),"jumped into pre_reset_phase",UVM_NONE);
        endtask
    endclass: agent
    class env extends uvm_env;
        `uvm_component_utils(env)

        agent ag1;
        agent ag2;
        uvm_domain d1;
        uvm_domain d2;
        function new(string name, uvm_component parent);
            super.new(name,parent);
        endfunction: new

        function void build_phase(uvm_phase phase);
            super.build_phase(phase);
            ag1 = agent::type_id::create("ag1", this);
            ag2 = agent::type_id::create("ag2", this);
            d1 = new("d1");
            d2 = new("d2");

            ag1.set_domain(d1);
            ag2.set_domain(d2);
        endfunction: build_phase
    endclass: env

    class test extends uvm_test;
        `uvm_component_utils(test)
        env e;
        m_sequence seq1;
        m_sequence seq2;

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

        function void build_phase(uvm_phase phase);
            super.build_phase(phase);
            e = env::type_id::create("env",this);
        endfunction
        task main_phase(uvm_phase phase);
            fork
                super.main_phase(phase);
            join_none
            phase.raise_objection(this);
            seq1  = m_sequence::type_id::create("se1");
            seq2  = m_sequence::type_id::create("se2");
            fork
                seq1.start(e.ag1.seqr);
                seq2.start(e.ag2.seqr);
            join
            e.d1.jump(uvm_pre_reset_phase::get());
            phase.drop_objection(this);
        endtask
    endclass: test
endpackage

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

1 Ответ

2 голосов
/ 28 июня 2019

фазы выполнения UVM используются для управления порядком происходящих событий .Если дела выполняются на разных этапах, то вы можете гарантировать, что что-то сделанное на более позднем этапе произойдет раньше, чем что-то сделанное на более раннем этапе.

Ваш исходный код создает два новых фазовых домена и помещает двух агентов в эти новые домены.Остальная часть тестового стенда находится в исходном домене.Если вы не синхронизируете домены, вы больше не можете гарантировать, в каком порядке будут происходить события.

Итак, я внес несколько изменений в ваш код:

i) Я добавилссылка на последовательность в агенте:

   m_sequence seq;

ii) Я добавил код в основную фазу агента, чтобы (а) выдвинуть возражение и (б) запустить последовательность.Теперь (а) каждая последовательность запускается в нужное время в своем домене, и (б) критически важно, чтобы фаза не заканчивалась до тех пор, пока последовательность не будет завершена.(Вы возражаете против окончания фазы, поэтому теперь каждому main_phase нужно свое собственное возражение.)

    task main_phase(uvm_phase phase);
      phase.raise_objection(this);
      `uvm_info(get_type_name(),"jumped into main_phase",UVM_NONE);
      seq.start(seqr);
      phase.drop_objection(this);
    endtask

iii) Я добавил дополнительный параметр к вашему вызову метода set_domain, чтобы потомки объектаагенты также помещаются в новый домен (по умолчанию это не так):

      ag1.set_domain(d1,1);
      ag2.set_domain(d2,1);

iv) Я поместил код для создания последовательностей в configure_phase теста.Я сомневаюсь, что это гарантирует, что последовательности создаются до начала основных фаз, так что это работает скорее благодаря удаче, чем суждению.(Вам необходимо использовать тот факт, что фазы гарантируют порядок выполнения, чтобы точно настроить это.)

    task configure_phase(uvm_phase phase);
      e.ag1.seq  = m_sequence::type_id::create("se1");
      e.ag2.seq  = m_sequence::type_id::create("se2");
    endtask

v) Наконец, чтобы гарантировать, что скачок фазы произойдет после завершения последовательностей, я добавилзадержка перед его выполнением:

        #1 e.d1.jump(uvm_pre_reset_phase::get());

Это что-то вроде хака.Опять же, учитывая, что вы попали в мир фазовых доменов, вы, вероятно, захотите использовать фазы, чтобы гарантировать это.

Но наконец ... фазовые прыжки - это что-то вроде хака.Я бы рекомендовал использовать его только в качестве крайней меры.Не существует ли более простого, более традиционного способа повторения последовательности для домена 1?


`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 = "apb_seq_item");
            super.new(name);
        endfunction: new
    endclass: seq_item

    class m_sequence extends uvm_sequence#(seq_item);
        `uvm_object_utils(m_sequence)

        function new(string name = "");
            super.new(name);
        endfunction: new

        task body();
            repeat(5) begin
                req = seq_item::type_id::create("ap_it");
                start_item(req);
                req.randomize();
                finish_item(req);
            end
        endtask: body
    endclass: m_sequence

    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 agent extends uvm_agent;
        `uvm_component_utils(agent)
         uvm_analysis_port#(seq_item) ap;
       m_sequence seq;

        uvm_sequencer#(seq_item)     seqr;
        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));
            seqr= uvm_sequencer#(seq_item) ::type_id::create(.name("uvm_sequenver"), .parent(this) );
            drv = driver        ::type_id::create(.name("driver"), .parent(this) );
        endfunction: build_phase

        function void connect_phase(uvm_phase phase);
            super.connect_phase(phase);
            drv.seq_item_port.connect(seqr.seq_item_export);
        endfunction: connect_phase

        task pre_reset_phase(uvm_phase phase);
            fork
                super.pre_reset_phase(phase);
            join_none
            `uvm_info(get_type_name(),"jumped into pre_reset_phase",UVM_NONE);
        endtask

        task main_phase(uvm_phase phase);
          phase.raise_objection(this);
          `uvm_info(get_type_name(),"jumped into main_phase",UVM_NONE);
          seq.start(seqr);
          phase.drop_objection(this);
        endtask
    endclass: agent
    class env extends uvm_env;
        `uvm_component_utils(env)

        agent ag1;
        agent ag2;
        uvm_domain d1;
        uvm_domain d2;
        function new(string name, uvm_component parent);
            super.new(name,parent);
        endfunction: new

        function void build_phase(uvm_phase phase);
            super.build_phase(phase);
            ag1 = agent::type_id::create("ag1", this);
            ag2 = agent::type_id::create("ag2", this);
            d1 = new("d1");
            d2 = new("d2");

            ag1.set_domain(d1,1);
            ag2.set_domain(d2,1);
        endfunction: build_phase
    endclass: env

    class test extends uvm_test;
        `uvm_component_utils(test)
        env e;      

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

        function void build_phase(uvm_phase phase);
            super.build_phase(phase);
            e = env::type_id::create("env",this);
        endfunction

        task configure_phase(uvm_phase phase);
          e.ag1.seq  = m_sequence::type_id::create("se1");
          e.ag2.seq  = m_sequence::type_id::create("se2");
        endtask

        task main_phase(uvm_phase phase);
            fork
                super.main_phase(phase);
            join_none
            phase.raise_objection(this);          
            #1 e.d1.jump(uvm_pre_reset_phase::get());
            phase.drop_objection(this);
        endtask
    endclass: test
endpackage

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

https://www.edaplayground.com/x/imV

...