Разделение доменов в UVM

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

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

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

затем данные получат водители агентов; если вы раскомментируете его, они остановятся. Однако, если вы поместите jump внутри блока fork, это произойдет.

Если вы переместите настройку домена в основную фазу тестового класса, данные перейдут, но переход от jump к 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
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
460
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Фазы выполнения 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

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

Андрей Солодовников 28.06.2019 16:33

Вот статья, которая привела меня к идее использования фазовых переходов: sunburst-design.com/papers/HunterSNUGSV_UVM_Resets_paper.pdf

Андрей Солодовников 28.06.2019 16:33

Относительно пункта 'iii': в документации сказано, что это излишне: If called from build, hier won't recurse into all chilren (which don't exist yet).

Андрей Солодовников 28.06.2019 16:43

@АндрейСолодовников Что касается «hier», похоже, вы знаете больше, чем я. Если вы думаете, что прыжок по фазе — это выход, то не позволяйте мне вас останавливать.

Matthew Taylor 28.06.2019 16:56

Я автор статьи (sunburst-design.com/papers/HunterSNUGSV_UVM_Resets_paper.pd‌​f). Прыжки по фазам — это не хак. Он используется на многих тестовых стендах в моей организации и очень надежен. Ваша проблема в том, что драйверы не должны запускать свои потоки во время основной фазы. (см. статью)

Brian 15.03.2022 18:20

Другие вопросы по теме