UVM验证方法学_phase机制

phase机制是uvm最重要的几个机制之一,它使得uvm的运行仿真层次化,使得各种例化先后次序正确,保证了验证环境与DUT的正确交互。


一、phase机制概述

uvm中的phase按照是否消耗仿真时间分为function phase和task phase两类,不消耗仿真时间的为function phase,而消耗仿真时间的为task phase。

uvm中的phase:

phase机制的意义是使得UVM的运行层次化,使得各种例化先后次序正确。UVM的phase主要有9个,外加12个小phase,这12个小的phase称为run-time phase。其中除了run phase和12个小的phase是task之外,其余的都是function。比较常用的phase有build_phase、connect_phase、reset_phase、main_phase、run_phase、report_phase、final_phase等。

为什么要引入这12个小的phase?分成小的phase是为了实现更加精细化的控制。reset、configure、main、shutdown四个phase是核心,这四个phase通常模拟DUT的正常工作方式:

(1)在reset_phase对DUT进行复位、初始化等操作。

(2)在configure_phase则进行DUT的配置。

(3)在main_phase主要是DUT的运行。

(4)在shutdown_phase主要是一些与DUT断电相关的操作。

通过这种细分实现对DUT更加精确的控制,同时也可以让我们实现在phase间的跳转,更便于去构建一些场景。

二、phase执行顺序

phase的执行顺序可以分为时间和空间。

(1)时间顺序

先说时间,在时间层面所有的phase会按照顺序自上向下依次执行。其中12个小的phase与run_phase是并行的关系。

run_phase和main_phase之间的关系:
objection机制是UVM中唯一可以控制仿真开始和结束的方式。在task phase中,至少有一个task phase要在消耗第一条消耗仿真时间的语句执行之前挂起objection。
(1)如果12个分支中有一个phase(比如main_phase)挂起了objection ,那么run_phase 中则不需要挂起objection 就可以执行其中的代码;但是这时,run_phase的运行时间被动地受这个挂起objection的分支phase的控制。
(2)而如果在run_phase中挂起了objection,没有在main_phase中挂起,main_phase中的操作则不会执行,此时的运行时间完全由run_phase控制。

请注意不要混淆,这里的时间顺序并不是指消耗仿真时间,只有task phase才会消耗仿真时间!所有的function phase都会在0时刻完成。

对于task phase,uvm内置了phase的同步。只有同一个phase全部执行完毕,才会执行下一个phase。但是从整个环境的角度来看,各个task phase之间是没有空白的。

(2)空间顺序

再说空间,uvm中规定层次越高,优先级越高,层次即为在uvm树中的位置,uvm_top是树根,越靠近树根,则层次越高。

我们可以再思考一下,层次越高,就会越接近用户。我们会在uvm_test_top(也就是testcase)中启动不同的sequence,来实现不同的测试场景,而env则是在uvm_test_top中才会完成例化,向下依此类推。

值得注意的是,uvm的设计哲学就是在build_phase中完成例化,在connect_phase中完成连接,这种分块式设计。所以build_phase比较特殊,由于树形结构实例化必须从树根开始,也就是自顶向下运行。但是例如connect_phase则是自底向上运行,因为组件的连接必须从最基础的部件开始。所以对于空间来说:

只有build phase和final phase是自顶向下运行,其余phase都是自底向上运行。

可以使用print_topology来打印树形结构,可以清晰看到各个组件之间的关联。例如:

UVM_INFO @ 33626.00ns: reporter [UVMTOP] UVM testbench topology:
------------------------------------------------------------------
Name                       Type                        Size  Value
------------------------------------------------------------------
uvm_test_top               tc_sanity                   -     @471 
  fifo_env                 env                         -     @479 
    rd_agt                 rd_agent                    -     @495 
      drv                  rd_driver                   -     @621 
        rsp_port           uvm_analysis_port           -     @638 
        seq_item_port      uvm_seq_item_pull_port      -     @629 
      mon                  rd_monitor                  -     @770 
        ap                 uvm_analysis_port           -     @780 
      sqr                  rd_sequencer                -     @647 
        rsp_export         uvm_analysis_export         -     @655 
        seq_item_export    uvm_seq_item_pull_imp       -     @761 
        arbitration_queue  array                       0     -    
        lock_queue         array                       0     -    
        num_last_reqs      integral                    32    'd1  
        num_last_rsps      integral                    32    'd1  
    rdmon_scb_fifo         uvm_tlm_analysis_fifo #(T)  -     @564 
      analysis_export      uvm_analysis_imp            -     @608 
      get_ap               uvm_analysis_port           -     @599 
      get_peek_export      uvm_get_peek_imp            -     @581 
      put_ap               uvm_analysis_port           -     @590 
      put_export           uvm_put_imp                 -     @572 
    scb                    scoreboard                  -     @503 
      rd_port              uvm_blocking_get_port       -     @803 
      wr_port              uvm_blocking_get_port       -     @794 
    wr_agt                 wr_agent                    -     @487 
      drv                  wr_driver                   -     @939 
        rsp_port           uvm_analysis_port           -     @956 
        seq_item_port      uvm_seq_item_pull_port      -     @947 
      mon                  wr_monitor                  -     @965 
        ap                 uvm_analysis_port           -     @975 
      sqr                  wr_sequencer                -     @816 
        rsp_export         uvm_analysis_export         -     @824 
        seq_item_export    uvm_seq_item_pull_imp       -     @930 
        arbitration_queue  array                       0     -    
        lock_queue         array                       0     -    
        num_last_reqs      integral                    32    'd1  
        num_last_rsps      integral                    32    'd1  
    wrmon_scb_fifo         uvm_tlm_analysis_fifo #(T)  -     @511 
      analysis_export      uvm_analysis_imp            -     @555 
      get_ap               uvm_analysis_port           -     @546 
      get_peek_export      uvm_get_peek_imp            -     @528 
      put_ap               uvm_analysis_port           -     @537 
      put_export           uvm_put_imp                 -     @519 
------------------------------------------------------------------

我们可以用build_phase和connect_phase来举例,比如:

UVM_INFO @ 0: reporter [RNTST] Running test tc_sanity...
UVM_INFO ../tc/tc_sanity.sv(30) @ 0.00ns: uvm_test_top [uvm_test_top] build_phase active.
UVM_INFO ../ver/env.sv(33) @ 0.00ns: uvm_test_top.fifo_env [fifo_env] build_phase active.
UVM_INFO ../ver/scoreboard.sv(36) @ 0.00ns: uvm_test_top.fifo_env.scb [scb] build_phase active.
UVM_INFO ../ver/wr_agent/wr_agent.sv(32) @ 0.00ns: uvm_test_top.fifo_env.wr_agt [wr_agt] build_phase active.
UVM_INFO ../ver/wr_agent/wr_driver.sv(31) @ 0.00ns: uvm_test_top.fifo_env.wr_agt.drv [drv] build_phase active.
UVM_INFO ../ver/wr_agent/wr_monitor.sv(29) @ 0.00ns: uvm_test_top.fifo_env.wr_agt.mon [mon] build_phase active.
UVM_INFO ../ver/wr_agent/wr_sequencer.sv(28) @ 0.00ns: uvm_test_top.fifo_env.wr_agt.sqr [sqr] build_phase active.

UVM_INFO ../ver/scoreboard.sv(43) @ 0.00ns: uvm_test_top.fifo_env.scb [scb] connect_phase active.
UVM_INFO ../ver/wr_agent/wr_driver.sv(39) @ 0.00ns: uvm_test_top.fifo_env.wr_agt.drv [drv] connect_phase active.
UVM_INFO ../ver/wr_agent/wr_monitor.sv(38) @ 0.00ns: uvm_test_top.fifo_env.wr_agt.mon [mon] connect_phase active.
UVM_INFO ../ver/wr_agent/wr_sequencer.sv(33) @ 0.00ns: uvm_test_top.fifo_env.wr_agt.sqr [sqr] connect_phase active.
UVM_INFO ../ver/wr_agent/wr_agent.sv(42) @ 0.00ns: uvm_test_top.fifo_env.wr_agt [wr_agt] connect_phase active.
UVM_INFO ../ver/env.sv(46) @ 0.00ns: uvm_test_top.fifo_env [fifo_env] connect_phase active.
UVM_INFO ../tc/tc_sanity.sv(36) @ 0.00ns: uvm_test_top [uvm_test_top] connect_phase active.

可以清晰的看到build_phase的运行是自顶向下,而connect_phase的运行是自底向上。
 

三、phase机制中uvm树的遍历

其实在上面的代码中能够看到,build_phase中scoreboard执行是要先于wr_agent的,这是因为uvm中字典序所导致的。scoreboard的s在字典序中要先于w,如果将scoreboard的例化名称改为z_scoreboard,则会晚于wr_agent执行。实际使用中这种顺序理论上不应该产生影响,但是假如要求一定是某种固定的执行顺序,那么这种代码存在很高风险,应立即进行修改。

从树形结构上来说,scoreboard级别是高于agent中的组件的,但是他们build_phase的执行顺序其实并不确定。UVM中采用的是深度优先的原则,即会先执行完某一条树枝,才会去执行下一条树枝。例如agent和scoreboard,他们的层次相同,在执行时会先将agent中包含的组件全部执行完成,才去执行scoreboard,这就是深度优先原则。我们可以总结为:

横向按照字典序,纵向按照深度原则。

四、phase的super

通过super对父类的内容进行继承,其中build_phase的super语句最重要且必须存在,其他phase的super则可以省略。查看uvm源码,可以看到除了build_phase之外其他的phase几乎没有做任何相关的事情:

// phase methods
//--------------
// these are prototypes for the methods to be implemented in user components
// build_phase() has a default implementation, the others have an empty default

function void uvm_component::build_phase(uvm_phase phase);
  m_build_done = 1;
  build();
endfunction

// Backward compatibility build function

function void uvm_component::build();
  m_build_done = 1;
  apply_config_settings(print_config_matches);
  if(m_phasing_active == 0) begin
    uvm_report_warning("UVM_DEPRECATED", "build()/build_phase() has been called explicitly, outside of the phasing system. This usage of build is deprecated and may lead to unexpected behavior.");
  end
endfunction

// these phase methods are common to all components in UVM. For backward
// compatibility, they call the old style name (without the _phse)

function void uvm_component::connect_phase(uvm_phase phase);
  connect();
  return; 
endfunction
function void uvm_component::start_of_simulation_phase(uvm_phase phase);
  start_of_simulation();
  return; 
endfunction
function void uvm_component::end_of_elaboration_phase(uvm_phase phase);
  end_of_elaboration();
  return; 
endfunction
task          uvm_component::run_phase(uvm_phase phase);
  run();
  return; 
endtask
function void uvm_component::extract_phase(uvm_phase phase);
  extract();
  return; 
endfunction
function void uvm_component::check_phase(uvm_phase phase);
  check();
  return; 
endfunction
function void uvm_component::report_phase(uvm_phase phase);
  report();
  return; 
endfunction


// These are the old style phase names. In order for runtime phase names
// to not conflict with user names, the _phase postfix was added.

function void uvm_component::connect();             return; endfunction
function void uvm_component::start_of_simulation(); return; endfunction
function void uvm_component::end_of_elaboration();  return; endfunction
task          uvm_component::run();                 return; endtask
function void uvm_component::extract();             return; endfunction
function void uvm_component::check();               return; endfunction
function void uvm_component::report();              return; endfunction
function void uvm_component::final_phase(uvm_phase phase);         return; endfunction

// these runtime phase methods are only called if a set_domain() is done

task uvm_component::pre_reset_phase(uvm_phase phase);      return; endtask
task uvm_component::reset_phase(uvm_phase phase);          return; endtask
task uvm_component::post_reset_phase(uvm_phase phase);     return; endtask
task uvm_component::pre_configure_phase(uvm_phase phase);  return; endtask
task uvm_component::configure_phase(uvm_phase phase);      return; endtask
task uvm_component::post_configure_phase(uvm_phase phase); return; endtask
task uvm_component::pre_main_phase(uvm_phase phase);       return; endtask
task uvm_component::main_phase(uvm_phase phase);           return; endtask
task uvm_component::post_main_phase(uvm_phase phase);      return; endtask
task uvm_component::pre_shutdown_phase(uvm_phase phase);   return; endtask
task uvm_component::shutdown_phase(uvm_phase phase);       return; endtask
task uvm_component::post_shutdown_phase(uvm_phase phase);  return; endtask

不过为了代码风格的统一,我还是会给每个phase都加上。

五、phase的跳转

这里先说一下跳转,后面在专门讨论复位的时候会再次用到它,因为跳转对于复位实现来说是必要的。跳转中最难的地方在于清理和准备工作,组件之间的fifo需要全部清空,组件内部的队列也需要全部清空,如果清空做不好可能会引发很多未知问题。

跳转使用jump函数,比如:

            begin
                @(negedge this.wr_drv_if.wrst_n);
                phase.jump(uvm_reset_phase::get());
                `uvm_info(this.name,"2nd reset activated.",UVM_LOW)
            end

这里就是复位信号到来跳转至reset_phase。

当然能够做跳转的phase也有限制,在uvm_pre_reset_phase::get() 后的所有phase都可以:

uvm_build_phase::get();
uvm_connect_phase::get();
uvm_end_of_elaboration_phase::get();
uvm_start_of_simulation_phase::get();
uvm_run_phase::get();
uvm_pre_reset_phase::get();

// ----------------------------------------------------------
uvm_reset_phase::get();
uvm_post_reset_phase::get();
uvm_pre_configure_phase::get();
uvm_configure_phase::get();
uvm_post_configure_phase::get();
uvm_pre_main_phase::get();
uvm_main_phase::get();
uvm_post_main_phase::get();
uvm_pre_shutdown_phase::get();
uvm_shutdown_phase::get();
uvm_post_shutdown_phase::get();
uvm_extract_phase::get();
uvm_check_phase::get();
uvm_report_phase::get();
uvm_final_phase::get();

六、phase的调试和超时退出

除了使用uvm_info打印信息来帮助检查问题之外,uvm还提供命令行参数UVM_PHASE_TRACE来对phase机制进行调试。需要在仿真的命令后面加入:+UVM_PHASE_TRACE,或者加在makefile当中。

UVM_INFO /opt/Synopsys/VCS2014/etc/uvm-1.1/base/uvm_phase.svh(1381) @ 33626.00ns: reporter [PH/TRC/DONE] Phase 'common.report' (id=271) Completed phase
UVM_INFO /opt/Synopsys/VCS2014/etc/uvm-1.1/base/uvm_phase.svh(1403) @ 33626.00ns: reporter [PH/TRC/SCHEDULED] Phase 'common.final' (id=283) Scheduled from phase common.report
UVM_INFO /opt/Synopsys/VCS2014/etc/uvm-1.1/base/uvm_phase.svh(1124) @ 33626.00ns: reporter [PH/TRC/STRT] Phase 'common.final' (id=283) Starting phase
UVM_INFO /opt/Synopsys/VCS2014/etc/uvm-1.1/base/uvm_phase.svh(1381) @ 33626.00ns: reporter [PH/TRC/DONE] Phase 'common.final' (id=283) Completed phase
UVM_INFO /opt/Synopsys/VCS2014/etc/uvm-1.1/base/uvm_phase.svh(1403) @ 33626.00ns: reporter [PH/TRC/SCHEDULED] Phase 'common.common_end' (id=180) Scheduled from phase common.final
UVM_INFO /opt/Synopsys/VCS2014/etc/uvm-1.1/base/uvm_phase.svh(1124) @ 33626.00ns: reporter [PH/TRC/STRT] Phase 'common.common_end' (id=180) Starting phase
UVM_INFO /opt/Synopsys/VCS2014/etc/uvm-1.1/base/uvm_phase.svh(1381) @ 33626.00ns: reporter [PH/TRC/DONE] Phase 'common.common_end' (id=180) Completed phase

挂死是有时候会遇到的问题,一般是陷入了死循环无法终止。出现挂死的时候设置的drain_time就不会起作用,导致仿真无法结束。在uvm中通过uvm_root的set_timeout函数可以设置超时时间来强制结束(在top中使用$finish或者$stop是同样的效果)。

function void base_test::build_phase(uvm_phase phase);
    super.build_phase(phase);
    env = my_env::type_id::create("env", this);
    uvm_top.set_timeout(500ns, 0);
endfunction

set_timeout函数有两个参数,第一个参数是要设置的时间,第二个参数表示此设置是否可以被其后的其他set_timeout语句覆盖。如果达到规定时间后测试用例还没有运行完毕,则会给出一条uvm_fatal的提示信息,并退出仿真。


总结

phase机制是uvm最重要的几个机制之一,它使得uvm的运行仿真层次化,使得各种例化先后次序正确,保证了验证环境与DUT的正确交互。

验证平台是很复杂的,要搭建出一个验证平台是一件相当繁杂的事情,要正确地掌握并理顺这些步骤是一个相当艰难的过程。在不同时间做不同的事情,这就是uvm中phase的设计哲学。但是仅仅划分成phase是不够的,phase的自动执行功能极大地方便了用户。同时,phase机制的引入在很大程度上解决了因代码顺序杂乱可能会引发的问题,也在很大程度上减少了验证平台开发者的工作量。

<think>好的,我现在需要帮助用户了解如何使用SystemVerilog(SV)语言UVM平台中构建一个包含virtual sequence和virtual sequencer的系统,以实现内存的写入和读取功能。首先,我需要回顾UVM的基本结构,特别是virtual sequence和virtual sequencer的作用。 用户的要求是让数据写入内存并读取出来,所以需要内存模型(比如寄存器模型或RAM模型)、driver、sequencer以及对应的sequence。Virtual sequencer的作用是协调多个物理sequencer,而virtual sequence则负责协调不同的测试流程。 首先,应该确定需要哪些组件。可能需要一个顶层virtual sequencer来管理两个agent的sequencer:一个用于写,一个用于读。每个agent应该有自己的sequencer、driver和monitor。然后,virtual sequence会启动针对这两个agent的sequence,分别处理写入和读取操作。 接下来,内存模型部分可能需要一个适配器(adapter)来将寄存器访问转换为具体的总线事务。这里可能需要使用UVM寄存器模型(uvm_reg_block)来抽象内存,并通过predictor来更新寄存器的值。 然后,需要考虑如何同步写入和读取操作。例如,在写入数据后,可能需要等待一段时间或某种信号后再进行读取,以确保数据已经存储。这可以通过在virtual sequence中安排顺序来控制。 可能遇到的挑战包括正确连接virtual sequencer到各个agent的sequencer,确保寄存器模型正确地与总线事务交互,以及在读取时如何验证数据是否正确。需要确保在读取操作中,返回的数据与写入的数据一致,这可以通过scoreboard或直接在sequence中进行比较来实现。 现在需要分步骤构建代码: 1. 定义内存寄存器模型,包括地址和数据寄存器。 2. 创建agent组件,每个agent包含sequencer、driver和monitor。这里可能需要两个agent,分别处理写和读,或者一个agent处理双向操作。 3. 构建virtual sequencer,包含指向两个agent sequencer的指针。 4. 编写virtual sequence,启动写sequence和读sequence,可能需要在写之后启动读。 5. 在测试用例(test)中设置virtual sequence并启动。 6. 连接寄存器模型到adapter和predictor,确保总线事务能正确更新寄存器值。 7. 在driver中实现如何将transaction转换为具体的信号,比如总线协议。 8. 在scoreboard中比较写入和读取的数据,确保正确性。 需要注意的地方是,virtual sequencer本身并不处理transaction,只是提供对其他sequencer的引用。因此,在virtual sequence中需要明确指定哪个sequencer运行哪个sequence。 可能还需要在环境(env)中实例化virtual sequencer,并将各个agent的sequencer连接进去。此外,寄存器模型的集成需要正确配置adapter和map,以便地址映射正确。 最后,测试用例需要启动virtual sequence,并确保整个流程按顺序执行。例如,先启动写操作,等待完成后再启动读操作,然后比较数据是否正确。 可能还需要考虑并发性,比如使用fork-join或顺序执行来控制流程。此外,错误处理也需要考虑,比如写入失败或读取数据不匹配时的处理方式。 总结步骤后,现在可以开始编写示例代码的结构,并解释每个部分的作用。需要确保代码结构清晰,关键部分如virtual sequence和virtual sequencer的连接正确,寄存器模型的集成正确,以及验证组件(如scoreboard)的实现。</think>以下是用SystemVerilog实现包含virtual sequence和virtual sequencer的UVM平台架构示例,包含关键代码段和实现说明: --- ### **一、组件架构** ```text ┌───────────────────────┐ │ Test Class │ └───────────────────────┘ │ ▼ ┌───────────────────────┐ │ Virtual Sequence │ │ (mem_virtual_seq) │ └───────────────────────┘ │ ▼ ┌───────────────────────┐ │ Virtual Sequencer │ │ (mem_virt_sqr) │ └───────────────────────┘ ├─────────────┐ ▼ ▼ ┌───────────────────┐ ┌───────────────────┐ │ Write Sequencer │ │ Read Sequencer │ │ (mem_wr_sqr) │ │ (mem_rd_sqr) │ └───────────────────┘ └───────────────────┘ │ │ ▼ ▼ ┌───────────────────┐ ┌───────────────────┐ │ Write Driver │ │ Read Driver │ │ (mem_wr_drv) │ │ (mem_rd_drv) │ └───────────────────┘ └───────────────────┘ ``` --- ### **二、关键代码实现** #### **1. Virtual Sequencer定义** ```systemverilog class mem_virt_sqr extends uvm_sequencer; `uvm_component_utils(mem_virt_sqr) mem_wr_sqr wr_sqr; // 写操作sequencer mem_rd_sqr rd_sqr; // 读操作sequencer function new(string name, uvm_component parent); super.new(name, parent); endfunction endclass ``` #### **2. Virtual Sequence实现** ```systemverilog class mem_virtual_seq extends uvm_sequence; `uvm_object_utils(mem_virtual_seq) `uvm_declare_p_sequencer(mem_virt_sqr) // 声明virtual sequencer task body(); // 创建并启动写sequence mem_write_seq write_seq = mem_write_seq::type_id::create("write_seq"); write_seq.start(p_sequencer.wr_sqr); // 创建并启动读sequence mem_read_seq read_seq = mem_read_seq::type_id::create("read_seq"); read_seq.start(p_sequencer.rd_sqr); endtask endclass ``` #### **3. 具体Sequence实现(示例:写操作)** ```systemverilog class mem_write_seq extends uvm_sequence#(mem_transaction); `uvm_object_utils(mem_write_seq) rand logic [31:0] addr; rand logic [31:0] data; task body(); `uvm_create(req) // 创建transaction req.cmd = WRITE; // 设置写操作类型 req.addr = this.addr; // 设置目标地址 req.data = this.data; // 设置写入数据 `uvm_send(req) // 发送transaction endtask endclass ``` #### **4. 测试类(Testbench Top)** ```systemverilog class base_test extends uvm_test; `uvm_component_utils(base_test) mem_env env; function new(string name, uvm_component parent); super.new(name, parent); endfunction function void build_phase(uvm_phase phase); super.build_phase(phase); env = mem_env::type_id::create("env", this); endfunction task run_phase(uvm_phase phase); mem_virtual_seq vseq = mem_virtual_seq::type_id::create("vseq"); phase.raise_objection(this); vseq.start(env.virt_sqr); // 启动virtual sequence phase.drop_objection(this); endtask endclass ``` --- ### **三、关键实现机制** 1. **虚拟协调控制** - Virtual sequencer聚合多个物理sequencer - Virtual sequence通过`p_sequencer`句柄访问子sequencer 2. **数据一致性保障** ```systemverilog // 在Scoreboard中添加比较逻辑 class mem_scoreboard extends uvm_scoreboard; uvm_tlm_analysis_fifo#(mem_transaction) wr_fifo; uvm_tlm_analysis_fifo#(mem_transaction) rd_fifo; task run_phase(uvm_phase phase); forever begin mem_transaction wr_tr, rd_tr; wr_fifo.get(wr_tr); rd_fifo.get(rd_tr); if(wr_tr.data !== rd_tr.data) begin `uvm_error("SCBD", $sformatf("Data mismatch! Wrote:0x%h Read:0x%h", wr_tr.data, rd_tr.data)) end end endtask endclass ``` 3. **同步机制** - 使用`uvm_event`或`uvm_barrier`实现读写操作同步 - 在Sequence中使用`wait_for_grant()/send_request()` --- ### **四、运行流程** 1. 测试类实例化环境并启动virtual sequence 2. Virtual sequence并行/串行启动读写sequence 3. 写sequence生成写transaction并发送到写driver 4. 写driver通过物理接口执行内存写入 5. 读sequence生成读transaction并发送到读driver 6. 读driver执行内存读取并返回数据 7. Scoreboard比较写入和读取数据 --- ### **五、最佳实践建议** 1. 在Virtual sequence中使用`fork-join`控制并发 ```systemverilog task body(); fork write_seq.start(p_sequencer.wr_sqr); read_seq.start(p_sequencer.rd_sqr); join endtask ``` 2. 使用寄存器抽象层(RAL)进行地址映射 3. 添加覆盖率收集点(covergroup)监控地址/数据分布 4. 实现错误注入机制验证异常处理能力 需要根据具体总线协议(如APB/AHB/AXI)实现driver的物理层驱动逻辑,并完善monitor的功能实现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Clock_926

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值