• UVM环境中reset复位的处理



    前言

    复位存在于每一个验证环境中,简单的同时,也是我们最容易忽略的功能点。在验证环境中,通常复位信号的处理,就是在top顶层产生时钟时,做一个复位的动作。这样做的好处是简单,但是如果我们想在仿真过程中,加入一个复位的动作,实现起来就比较麻烦,对于接口上,复位后驱动的复位值,也难以实现。
    本文主要介绍一种通用的方法,专门用来处理复位,具备很好的移植性,复用性,使用起来也非常方便,将复位相关的内容,单独拿出来处理,能够解决常规验证环境中,无法中间加入复位动作的痛点。
    本文的思路是,先将复位信号单独拿出来进行处理,再介绍如何处理其他驱动接口上的复位值。


    一、单独处理reset复位信号

    单独处理reset复位信号的思路是,为复位信号单独建立一个agent,再建立复位信号的sequence,通过将复位信号的sequence,送入复位agent下sequencer中的reset_phase,其他驱动接口的sequence送入main_phase,从而实现系统仿真前的复位。

    1.1 复位agent的实现

    复位agent中包括driver、monitor、sequencer。这部分代码可以直接复用。

    reset_agent.sv

    typedef class reset_driver;
    typedef class reset_monitor;
    
    class reset_agent extends uvm_agent;
      typedef uvm_sequencer#(reset_tr) reset_sequencer;
    
      virtual reset_io vif;          // DUT virtual interface
      reset_sequencer  sqr;
      reset_driver     drv;
      reset_monitor    mon;
      
      `uvm_component_utils(reset_agent)
    
      function new(string name, uvm_component parent);
        super.new(name, parent);
        `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
      endfunction: new
    
      virtual function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
        `uvm_info("RSTCFG", $sformatf("Reset agent %s setting for is_active is: %p", this.get_name(), is_active), UVM_MEDIUM);
    
        uvm_config_db#(virtual reset_io)::get(this, "", "reset_if", vif);
        uvm_config_db#(virtual reset_io)::set(this, "*", "vif", vif);
    
        if (is_active == UVM_ACTIVE) begin
          sqr = reset_sequencer::type_id::create("sqr", this);
          drv = reset_driver::type_id::create("drv", this);
        end
        mon = reset_monitor::type_id::create("mon", this);
      endfunction: build_phase
    
      virtual function void connect_phase(uvm_phase phase);
        super.connect_phase(phase);
        `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
        if (is_active == UVM_ACTIVE) begin
          drv.seq_item_port.connect(sqr.seq_item_export);
        end
      endfunction: connect_phase
    
      virtual function void end_of_elaboration_phase(uvm_phase phase);
        super.end_of_elaboration_phase(phase);
        `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
        if (vif == null) begin
          `uvm_fatal("CFGERR", "Interface for reset agent not set");
        end
      endfunction: end_of_elaboration_phase
    
    endclass
    
    /*
    class reset_tr extends uvm_sequence_item;
      typedef enum {ASSERT, DEASSERT} kind_e;
      rand kind_e kind;
      rand int unsigned cycles = 1;
    
      `uvm_object_utils_begin(reset_tr)
        `uvm_field_enum(kind_e, kind, UVM_ALL_ON)
        `uvm_field_int(cycles, UVM_ALL_ON)
      `uvm_object_utils_end
    
      function new(string name = "reset_tr");
        super.new(name);
        `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
      endfunction: new
    endclass
    */
    
    class reset_driver extends uvm_driver #(reset_tr);
      virtual reset_io vif;          // DUT virtual interface
      `uvm_component_utils(reset_driver)
    
      function new(string name, uvm_component parent);
        super.new(name, parent);
        `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
      endfunction: new
    
      virtual function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
    
        uvm_config_db#(virtual reset_io)::get(this, "", "vif", vif);
      endfunction: build_phase
    
      virtual function void end_of_elaboration_phase(uvm_phase phase);
        super.end_of_elaboration_phase(phase);
        `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
        if (vif == null) begin
          `uvm_fatal("CFGERR", "Interface for reset driver not set");
        end
      endfunction: end_of_elaboration_phase
    
      virtual task run_phase(uvm_phase phase);
        `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
    
        forever begin
          seq_item_port.get_next_item(req);
          drive(req);
          seq_item_port.item_done();
        end
      endtask: run_phase
    
      virtual task drive(reset_tr tr);
        `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
        if (tr.kind == reset_tr::ASSERT) begin
          vif.reset_n = 1'b0;
          repeat(tr.cycles) @(vif.mst);
        end else begin
          vif.reset_n <= '1;
          repeat(tr.cycles) @(vif.mst);
        end
      endtask: drive
    endclass
    
    class reset_monitor extends uvm_monitor;
      virtual reset_io vif;          // DUT virtual interface
      uvm_analysis_port #(reset_tr) analysis_port;
      uvm_event reset_event = uvm_event_pool::get_global("reset");
      `uvm_component_utils(reset_monitor)
    
      function new(string name, uvm_component parent);
        super.new(name, parent);
        `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
      endfunction: new
    
      virtual function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
    
        uvm_config_db#(virtual reset_io)::get(this, "", "vif", vif);
        analysis_port = new("analysis_port", this);
      endfunction: build_phase
    
      virtual function void end_of_elaboration_phase(uvm_phase phase);
        super.end_of_elaboration_phase(phase);
        `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
        if (vif == null) begin
          `uvm_fatal("CFGERR", "Interface for reset monitor not set");
        end
      endfunction: end_of_elaboration_phase
    
      virtual task run_phase(uvm_phase phase);
        `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
    
        forever begin
          reset_tr tr = reset_tr::type_id::create("tr", this);
          detect(tr);
          analysis_port.write(tr);//此处可以空置,不连没关系
        end
      endtask: run_phase
    
      virtual task detect(reset_tr tr);
        `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
        @(vif.reset_n);
        assert(!$isunknown(vif.reset_n));
        if (vif.reset_n == 1'b0) begin
          tr.kind = reset_tr::ASSERT;
          reset_event.trigger();
        end else begin
          tr.kind = reset_tr::DEASSERT;
          reset_event.reset();
        end
      endtask: detect
    endclass
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166

    1.2 复位transaction和interface

    这部分代码拿过来复用就好了。

    reset_tr.sv

    class reset_tr extends uvm_sequence_item;
      typedef enum {ASSERT, DEASSERT} kind_e;
      rand kind_e kind;
      rand int unsigned cycles = 1;
    
      `uvm_object_utils_begin(reset_tr)
        `uvm_field_enum(kind_e, kind, UVM_ALL_ON)
        `uvm_field_int(cycles, UVM_ALL_ON)
      `uvm_object_utils_end
    
      function new(string name = "reset_tr");
        super.new(name);
        `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
      endfunction: new
    endclass
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    reset_io.sv

    `ifndef RESET_IO__SV
    `define RESET_IO__SV
    
    interface reset_io(input logic clk);
    	logic        reset_n;
    
    	clocking mst @(posedge clk);
    		output reset_n;
    	endclocking
    
    	clocking mon @(posedge clk);
    		input reset_n;
    	endclocking
    
    	modport dut(input reset_n);
    endinterface: reset_io
    `endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    1.3 environment

    在env中声明和例化1.2节中的复位agent。host_agent用于配置寄存器,这里env只展示了部分代码。

    top_env_ral_env.sv

    `ifndef TOP_ENV_RAL_ENV__SV
    `define TOP_ENV_RAL_ENV__SV
    `include "top_env.sv"
    class top_env_ral_env extends uvm_env;
       host_agent host_agt;
       reset_agent reset_agt;//1、申明
    
        `uvm_component_utils(top_env_ral_env)
    
       extern function new(string name="top_env_ral_env", uvm_component parent=null);
       extern virtual function void build_phase(uvm_phase phase);
       extern function void start_of_simulation_phase(uvm_phase phase);
    endclass: top_env_ral_env
    
    function top_env_ral_env::new(string name= "top_env_ral_env",uvm_component parent=null);
       super.new(name,parent);
    endfunction:new
    
    function void top_env_ral_env::build_phase(uvm_phase phase);
       super.build_phase(phase);
       host_agt = host_agent::type_id::create("host_agt",this);
       reset_agt = reset_agent::type_id::create("reset_agt",this); //2、例化
    endfunction: build_phase
    
    function void top_env_ral_env::start_of_simulation_phase(uvm_phase phase);
       super.start_of_simulation_phase(phase);
       `ifdef UVM_VERSION_1_0
       uvm_top.print_topology();  
       factory.print();          
       `endif
       
       `ifdef UVM_VERSION_1_1
    	uvm_root::get().print_topology(); 
        uvm_factory::get().print();      
       `endif
    
       `ifdef UVM_POST_VERSION_1_1
    	uvm_root::get().print_topology(); 
        uvm_factory::get().print();      
       `endif
       //ToDo : Implement this phase here 
    endfunction: start_of_simulation_phase
    
    `endif // TOP_ENV_RAL_ENV__SV
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    1.4 复位sequence

    编写复位的sequence,用于控制复位信号。这部分代码可以直接拿来复用。

    reset_sequence.sv

    class reset_sequence extends uvm_sequence #(reset_tr);
      `uvm_object_utils(reset_sequence)
    
      function new(string name = "reset_sequence");
        super.new(name);
        `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
    
        `ifndef UVM_VERSION_1_1
         set_automatic_phase_objection(1);
        `endif
      endfunction: new
    
      virtual task body();
        `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
    
        // For UVM-1.1 & UVM-1.2
        //
        `ifndef UVM_VERSION
          `uvm_do_with(req, {kind == DEASSERT; cycles == 2;});
          `uvm_do_with(req, {kind == ASSERT; cycles == 1;});
          `uvm_do_with(req, {kind == DEASSERT; cycles == 15;});
        //
        // For IEEE UVM
        //
        `else
          `uvm_do(req,,, {kind == DEASSERT; cycles == 2;});
          `uvm_do(req,,, {kind == ASSERT; cycles == 1;});
          `uvm_do(req,,, {kind == DEASSERT; cycles == 15;});
        `endif
    
      endtask: body
    
      `ifdef UVM_VERSION_1_1
      virtual task pre_start();
        `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
        if ((get_parent_sequence() == null) && (starting_phase != null)) begin
          starting_phase.raise_objection(this);
        end
      endtask: pre_start
    
      virtual task post_start();
        `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
        if ((get_parent_sequence() == null) && (starting_phase != null)) begin
          starting_phase.drop_objection(this);
        end
      endtask: post_start
      `endif
    
    endclass: reset_sequence
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    1.5 Top_env_test

    在base_test中,将复位的sequence,送入复位agent下sequencer的reset_phase中,而配置寄存器的host_bfm_sequence则送入的是main_phase中,通过UVM phase的执行顺序,来保证复位在前,配置寄存器在后。

    `ifndef TEST__SV
    `define TEST__SV
    
    typedef class top_env_ral_env;
    
    class base_test extends uvm_test;
    
      `uvm_component_utils(base_test)
    
      top_env_ral_env env;
    
      function new(string name, uvm_component parent);
        super.new(name, parent);
      endfunction
    
      virtual function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        env = top_env_ral_env::type_id::create("env", this);
    
    	uvm_config_db #(uvm_object_wrapper)::set(this, "env.reset_agt.sqr.reset_phase", 
    					"default_sequence", reset_sequence::get_type());//reset_phase
        uvm_config_db #(uvm_object_wrapper)::set(this, "env.host_agt.sqr.main_phase",
                        "default_sequence", host_bfm_sequence::get_type()); //main_phase
      endfunction
      
    endclass : base_test
    
    `endif //TEST__SV
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    1.6 Top_env_tb

    在tb中,将top层的interface传递到env中。

    `ifndef TOP_ENV_TB_MOD__SV
    `define TOP_ENV_TB_MOD__SV
    
    `include "mstr_slv_intfs.incl"
    module top_env_tb_mod;
    
    import uvm_pkg::*;
    
    `include "top_env_ral_env.sv"
    `include "top_env_test.sv"  //ToDo: Change this name to the testcase file-name
    	
       initial begin
          uvm_config_db #(virtual host_io)::set(null,"","host_if",top_env_top.host_if);
          uvm_config_db #(virtual reset_io)::set(null,"","reset_if",top_env_top.reset_if);//全局set
          run_test();
       end
    
    endmodule: top_env_tb_mod
    
    `endif // TOP_ENV_TB_MOD__SV
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    1.7 Top_env_top

    在top层,分别例化tb和DUT。

    `ifndef TOP_ENV_TOP__SV
    `define TOP_ENV_TOP__SV
    
    module top_env_top();
    
       logic clk;
       logic rst;
    
       // Clock Generation
       parameter sim_cycle = 10;
       
       // Reset Delay Parameter
       parameter rst_delay = 50;
    
       always 
          begin
             #(sim_cycle/2) clk = ~clk;
          end
          
       host_io   host_if(clk);
       reset_io  reset_if(clk);
          
       top_env_tb_mod test(); // 1、例化testbench
       
       // ToDo: Include Dut instance here
      router    dut(.clk(clk), .reset_n(reset_if.reset_n), .io(router_if), .host(host_if));  // 2、例化DUT
          
       //Driver reset depending on rst_delay
       initial
          begin
             clk = 0;  //这一条必须要,不然时钟没有初始值,仿真会挂死
          //  rst = 1;
          //#1 rst = 0;
          //   repeat (rst_delay) @(clk);
          //   rst = 1'b1;
          //   @(clk);
       end
    
        initial begin
    	    $fsdbDumpfile("novas.fsdb");
    	    $fsdbDumpvars("+all");
    	    $fsdbDumpMDA(0, top_env_top);
        end
        
    endmodule: top_env_top
    
    `endif // TOP_ENV_TOP__SV
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    1.8 小结

    到此为止,展示了一个完整的,通过sequence去控制复位信号的处理方法,这其中大部分代码,可以直接在不同的环境中复用。

    二、处理其他驱动接口的复位值

    第一章中演示了复位信号的处理方法,除了复位信号,环境中还有许多其他的信号,在系统处于复位的时候,需要特定的驱动值。
    最简单的一个思路就是,为这些驱动信号,单独创建一个复位值的sequence,然后将这个sequence送入对应agent的reset_phase中。
    这样做会存在一些问题,由于不同的组件的reset_phase之间,没有严格的执行先后的顺序,会出现驱动信号的复位sequence先执行,造成在仿真的0时刻,在还没有复位信号的情况下,0时刻输入到DUT的信号处于已知值。
    在这里插入图片描述
    处理外部信号的正确方法是让信号在0时刻默认为它们的默认状态(x表示逻辑,z表示连线)。然后,在testbench中,当检测到复位信号时,将这些信号设置为适当的复位值。
    在这里插入图片描述
    解决方法是加入一个顶层的复位的sqr和seq。

    2.1 顶层管理复位的sqr和seq

    在顶层管理的sqr中,声明两个sqr,一个reset_sequencer,另一个host_sequencer。
    top_reset_sequencer.sv

    typedef class host_data;
    class top_reset_sequencer extends uvm_sequencer;
      `uvm_component_utils(top_reset_sequencer)
    
      typedef uvm_sequencer#(reset_tr) reset_sequencer;
      typedef uvm_sequencer#(host_data) host_sequencer;
    
      reset_sequencer  r_sqr;
      host_sequencer h_sqr;
    
      function new(string name, uvm_component parent);
        super.new(name, parent);    
        `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
      endfunction: new
    endclass: top_reset_sequencer
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    顶层管理的seq中的信息含量比较大,通过以下几点来分解:
    1、举手和放手通用性处理。对于高于UVM1.1版本,则通过在new函数中,通过set_automatic_phase_objection(1)来实现,对于UVM1.1版本,则在pre_start和post_start中进行举手和放手。这部分代码适用任何sequence。
    2、p_sequencer的应用。由于调用了`uvm_declare_p_sequencer(top_reset_sequencer)这个宏,所以所有的seq,都可以通过p_sequencer来下发。
    3、reset_event的使用。由于在body任务中,seq通过fork–join的方式并行下发,为了控制复位信号先执行,驱动信号后执行,这里通过利用了一个全局复位的事件reset_event,这个复位事件在复位agent下的monitor中进行触发,从而保证先给复位信号,再给驱动信号。

    top_reset_sequence.sv

    typedef  class host_reset_sequence ;
    class top_reset_sequence extends uvm_sequence;
      `uvm_object_utils(top_reset_sequence)
      `uvm_declare_p_sequencer(top_reset_sequencer)
      uvm_event reset_event = uvm_event_pool::get_global("reset");
      
      reset_sequence                    r_seq;
      host_reset_sequence    h_seq;
    
      function new(string name="virtual_reset_sequence");
        super.new(name);    
        `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
    
        `ifndef UVM_VERSION_1_1
         set_automatic_phase_objection(1);
        `endif
      endfunction: new
    
      virtual task body();
        `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
    
        fork
          // For UVM-1.1 & UVM-1.2
          `ifndef UVM_VERSION
            `uvm_do_on(r_seq, p_sequencer.r_sqr);
          // For IEEE UVM
          `else
            `uvm_do(r_seq, p_sequencer.r_sqr);
          `endif
    
          // For UVM-1.1 & UVM-1.2
          `ifndef UVM_VERSION
            begin
              reset_event.wait_on();
              `uvm_do_on(h_seq, p_sequencer.h_sqr);
            end
          // For IEEE UVM
          `else
            begin
              reset_event.wait_on();
              `uvm_do(h_seq, p_sequencer.h_sqr);
            end
          `endif
        join
    
      endtask: body
    
      `ifdef UVM_VERSION_1_1
      virtual task pre_start();
        `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
        if ((get_parent_sequence() == null) && (starting_phase != null)) begin
          starting_phase.raise_objection(this);
        end
      endtask: pre_start
    
      virtual task post_start();
        `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
        if ((get_parent_sequence() == null) && (starting_phase != null)) begin
          starting_phase.drop_objection(this);
        end
      endtask: post_start
      `endif
    
    endclass: top_reset_sequence
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64

    2.2 base_test

    增加的top_reset_sequencer被声明例化在base_test中,同时在connect_phase中,要将其与底层的sqr连接起来。另外,原有组件中reset_phase需要被清空,再将top_reset_sequence送入到top_reset_sqr.reset_phase。
    这样做的另外一个好处是,如果顶层需要在仿真过程中,加入一个复位的过程,那么只需要将其他main_phase清空后,再将top_reset_sequence送入top_reset_sqr.main_phase中。

    top_env_test.sv

    `ifndef TEST__SV
    `define TEST__SV
    
    typedef class top_env_ral_env;
    class base_test extends uvm_test;
      `uvm_component_utils(base_test)
    
      top_env_ral_env env;
      top_reset_sequencer top_reset_sqr;// 1、声明
    
      function new(string name, uvm_component parent);
        super.new(name, parent);
      endfunction
    
      virtual function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        env = top_env_ral_env::type_id::create("env", this);
    	top_reset_sqr = top_reset_sequencer::type_id::create("top_reset_sqr", this);//2、例化
    
        uvm_config_db #(uvm_object_wrapper)::set(this, "env.host_agt.sqr.main_phase",
                        "default_sequence", host_bfm_sequence::get_type()); 
    	  
    	uvm_config_db #(uvm_object_wrapper)::set(this, "env.*.sqr.reset_phase", 
    					"default_sequence", null);
        uvm_config_db #(uvm_object_wrapper)::set(this, "top_reset_sqr.reset_phase", 
    	    			"default_sequence", top_reset_sequence::get_type());
      endfunction
      
        virtual function void connect_phase(uvm_phase phase);
        super.connect_phase(phase);
        `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
    
        top_reset_sqr.r_sqr = env.reset_agt.sqr;//3、连接
        top_reset_sqr.h_sqr = env.host_agt.sqr;
    
      endfunction: connect_phase
    endclass : base_test
    `endif //TEST__SV
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    2.3 host_reset_sequence

    这里再介绍一下,top_reset_sequence中host_reset_sequence的实现。实现的主要思路是,通过uvm_config_db去get到host的interface,然后在task body中直接对其进行赋值。
    具体的是现实:
    1、声明p_sqr。
    2、例化。在pre_start中,通过get_sequencer来获取句柄实现例化。
    3、获取host的interface。借助p_sqr.get_parent()来获取路径,从而得到interface的句柄,进而可以对其进行赋值。

    host_reset_sequence.sv

    class host_sequence_base extends uvm_sequence #(host_data);
      `uvm_object_utils(host_sequence_base)
    
      virtual host_io    vif;
      uvm_sequencer_base p_sqr;// 1、声明
    
      function new(string name = "host_sequence_base");
        super.new(name);
        `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
    
        `ifndef UVM_VERSION_1_1
         set_automatic_phase_objection(1);
        `endif
      endfunction: new
    
      virtual task pre_start();
        `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
        p_sqr = get_sequencer();// 2、通过获取句柄来例化
    
        `ifdef UVM_VERSION_1_1
        if ((get_parent_sequence() == null) && (starting_phase != null)) begin
          starting_phase.raise_objection(this);
        end
        `endif
    
        if (uvm_config_db#(virtual host_io)::get(p_sqr.get_parent(), "", "host_if", vif)) begin// 3、获取host的interface
          `uvm_info("HOST_SEQ_CFG", "Has access to host interface", UVM_HIGH);
        end
        else
    	    `uvm_fatal("HOST_SEQ_CFG", "Has not access to host interface")
      endtask: pre_start
    
      `ifdef UVM_VERSION_1_1
      virtual task post_start();
        `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
        if ((get_parent_sequence() == null) && (starting_phase != null)) begin
          starting_phase.drop_objection(this);
        end
      endtask: post_start
      `endif
    
    endclass: host_sequence_base
    
    
    class host_reset_sequence extends host_sequence_base;
      `uvm_object_utils(host_reset_sequence)
    
      function new(string name = "host_reset_sequence");
        super.new(name);
        `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
      endfunction: new
    
      virtual task body();
        vif.wr_n = 1'b1;
        vif.rd_n = 1'b1;
        vif.address ='z;
        vif.data = 'z;
      endtask: body
    endclass: host_reset_sequence
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59

    2.4 小结

    这里提供了一种处理驱动信号复位值的方法,类似的方法可以用在其他多组驱动接口上。


    总结

    本文主要介绍了一种复位信号,以及驱动信号复位值的处理方法,虽然增加了验证组件,实现起来较为复杂,但是能够解决常规方法,无法在仿真过程中加入复位的痛点,具备很好的灵活性,实现的代码具备高度的复用性和可移植性。

    附上工程代码链接
    https://download.csdn.net/download/hh199203/86512045

  • 相关阅读:
    Linux Mint(Ubuntu)上 安装 效率神器 utools
    安信证券携手共议量化行业的赋能发展
    前端+后端项目 - 论坛信息管理系统(Web+servlet+MySQL+JDBC)
    德迅云安全和您聊聊关于DDOS高防ip的一些方面
    【Linux】进程间通信
    探索arkui(1)--- 布局(线性/层叠/弹性)
    src实战-两处nacos未授权访问
    Android案例手册 - 实现一个华容道拼图游戏
    分类神经网络2:ResNet模型复现
    随机数Random
  • 原文地址:https://blog.csdn.net/hh199203/article/details/126745399