关于我的UVM验证的第一个程序

本文介绍了作者使用UVM进行验证的第一个程序,涉及FAS Regen组件,该组件用于修复OTN帧的FAS信号。程序包括fas_regenv_env、otu4_data_interface、otu_top_harness和FASRegenTest四个部分,利用two kingdom factory技巧进行数据接口的override。详细阐述了如何实现数据接口的自定义、数据进入DUT的过程以及FASPolicy模块的功能,最后提到了FASRegenChecker和顶层测试用例FASRegenTest。
部署运行你感兴趣的模型镜像

这是我写的第一个测试

首先这个程序是TPO516的RX方向的一个component 我们管这个部分叫做FAS Regen. 它的作用就是给一个overhead被破坏掉的OTN frame重新插入正确的fas信号既f6f6f6282828,一共48bit.

这个程序一共有4部分组成,分别是:fas regen_env下的fasregen_checker和otu4_data_interface;在顶层中的otu_top_harness,以及top test case:FASRegenTest。

这个程序用了一个叫做two kingdom factory的trick 他的目的是利用OTU4DataInterface::type_id::set_type_override(FASRegenInterface::get_type());这句话来overide out4data_interface.即叫做custmize function。

第一步,借鉴别人的datainterface code:

/×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××

×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××

`ifndef OTU4DataInterface_sv
`define OTU4DataInterface_sv


class OTU4DataInterface extends uvm_component;
  `uvm_component_utils(OTU4DataInterface)
  
  function new(string name = "", uvm_component parent = null);
    super.new(name, parent);
  endfunction
  
  virtual task sync();
    
  endtask
  
  virtual task read(output bit [319:0] data, output bit enable);
    
  endtask 
  
endclass


`endif //OTU4DataInterface_sv

//可以看到在这个code中,sync()和 read()function都是空的 方便以后override。

××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××

××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××/

第二步 在图—top— harness里面写入FasRegenInterface.这个程序是用来override datapathinterface的function。首先这个方程需要找到两个来个ntc_otu_top_320的接口。一个为enable一个为inpute data。在top320中RX PATH,INSERT FAS BYTE中enable 信号为rx_lite_frm_oof_fas_en,data为fas regen data. 将这两个信号赋给harness中的readfunction的 data和enable,这样就完成了data的进入dut的这个过程。这个语句always @(posedge sys_clk) fas_regen_enable <= dut.rx_lite_frm_oof_fas_en;使fas—en比regen—enable早一拍。

/×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××

×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××

logic fas_regen_enable;


  always @(posedge sys_clk) fas_regen_enable <= dut.rx_lite_frm_oof_fas_en;


  class FASRegenInterface extends OTU4DataInterface;
    `uvm_component_utils(FASRegenInterface)


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


    virtual task sync();
      @(posedge sys_clk);
    endtask


    virtual task read(output bit[319:0] data, output bit enable);
      data = dut.rx_fas_regen_data;
      enable = fas_regen_enable;
    endtask
    
  endclass 

××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××

***************************************************************************************************************************/

下一个module是fas policy。他的作用是把6个fas bytes打乱,然后进入dut。

/**********************************************************************************************************************************

************************************************************************************************************************************

`ifndef FASPolicy_sv
`define FASPolicy_sv


class FASPolicy extends OTNPolicyBase;


  local rand int      random_frames;
  
  local bit           frame_count_flag       =   1'b0;
 
  local rand bit     [47:0] mask;
  local rand bit     bad_fas;
  local int          good_fas_dist = 1;  //deault value
  local int          bad_fas_dist = 1;


  /**
   * @literal constraints dictating the orders in which random variables are solved
   */
  constraint solve_order        {solve bad_fas before mask;}


  /**
   * @literal constraint - frame_size: Ensures that the number of frames is between 0 and 2000
   */
  constraint frame_size         {random_frames > 0; random_frames < 2000;}
      
  constraint fas_dist           {bad_fas dist {0:=good_fas_dist, 1:=bad_fas_dist};}//指定bad fas为1。good为2  weighted distribution,非配数据.
  constraint mask_value         {(bad_fas) -> mask != 48'h0; (!bad_fas) -> mask == 48'h0;} //bad fas = 1. mask dont equal to 0 and do xor with fas byte.-> is implication constrain, it is equal !A//B. 这句话中表示若左面真的是 badfas,则右面mask一定能够不为0. 若左面为goodfas 则右面mask一定为0


  /**
   * <hl>Constructor</hl>
   *
   * @param name -
   */


  function new(string name);
    super.new(name);
    setRandomizeControl(ON_TRANSACTION); //on transaction means random function will active when execute function begin.
  endfunction
  
  function void post_randomize();
    if(!frame_count_flag) begin
      this.max_lifecycle = random_frames;
    end
  endfunction
    
  /**
   * The number of frames for which the Policy will execute
   *
   * @param frame_count
   */
  
  function void setFrameCount(int frame_count);
    frame_count_flag = 1'b1;
    setMaxLifecycle(frame_count);
  endfunction   


  function void setRandomizeDist (int good_fas_dist, int bad_fas_dist);
    this.good_fas_dist = good_fas_dist;
    this.bad_fas_dist = bad_fas_dist;       // 把这个class里面的bad_fas_dist给了setrandomizeddist中的bad—fas-dist。这个变量不再这个文件中
  endfunction 


  /**
   *Execute is called once per frame. Physically inserts FAS bytes into the frame.
   *
   * @param txn -
   * @param cntxt -
   */
  
  function void execute(OTNFrame txn, ExecutionContext cntxt);
    if(!this.randomize()) `uvm_fatal("RANDOMIZATION_ERROR", "Failed to randomize FASPolicy")// 有random都需要这个语句来开始执行random function.
    `uvm_info("FASPolicy", $sformatf("bad_fas = %0d, mask = %0h", bad_fas, mask), UVM_MEDIUM)
    txn.getAlignment().setFAS(48'hf6f6f6282828 ^ mask); //因为mask是一个random,当mask为1 就开始破坏fas。
  endfunction
      
endclass


`endif //FASPolicy_sv

******************************************************************************************************************************************

******************************************************************************************************************************************/

下一部分是checker, 他负责检查从dut出来的数据, 看看是否是正确的fasbyte.

/****************************************************************************************************************************************************

******************************************************************************************************************************************************

`ifndef FASRegenChecker_sv
`define FASRegenChecker_sv


class FASRegenChecker extends uvm_component;
  `uvm_component_utils(FASRegenChecker)
   
  local OTU4DataInterface datapath;


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


  virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    datapath = OTU4DataInterface::type_id::create("datapath", this);
  endfunction


  virtual task run_phase(uvm_phase phase);
    forever begin
      bit [319:0] data;  //一clock cycle有320byte

      bit         enable;


      datapath.sync();
      datapath.read(data, enable);


      if(enable) begin
        if(data[319:272] == 48'hf6f6f6282828) begin 进行比较 判断
           `uvm_info("CHECKER", "FAS found - Simulation of the current frame is passing!", UVM_MEDIUM)
        end
        else begin
           `uvm_error("CHECKER", "FAS not correct - Simulation of the current frame fails!")
        end
      end
    end
  endtask


endclass


`endif //FASRegenChecker_sv

*********************************************************************************************************************************************************

**********************************************************************************************************************************************************/

下一个就是顶层的testcase,这个需要在questa 里面运行

/**************************************************************************************************************************************************

****************************************************************************************************************************************************

`ifndef FASRegenTest_sv
`define FASRegenTest_sv


class FASRegenTest extends BaseTest;                                                 //因为我没有env这个class所以我需要extends BaseTest 这里包含了环境配置
  `uvm_component_utils(FASRegenTest)


  protected FASRegenChecker check;
  protected ProcessStack       stack;                     //policy need stack to run
  protected FASPolicy          good_fas;                  //例化policy
  protected FASPolicy          fas_corrupt;
  protected Node               node;                             //在mld模块右侧
  function new(string name = "", uvm_component parent = null);
    super.new(name, parent);
  endfunction


  virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);                                                                                            //    不是 super。phase                
    check = FASRegenChecker::type_id::create("check", this);                                     //声明的变量都需要在这里contruct
    good_fas = new("good_fas");
    fas_corrupt = new("fas_corrupt");
  endfunction


virtual function void connect_phase(uvm_phase phase);
    Node nodes [$];
    MasterGraph graph = Framework::getInstance().getMasterGraph();
    graph.getTransceiverNodes("mld_xcvr", nodes);
    node = nodes[0];
  
    stack = ProcessStack::construct("OTNFrame", node, "mld_xcvr", ProcessStack::SRC);
    good_fas.setRandomizeDist(1, 0);                                                        //全是 goodfas
    good_fas.setFrameCount(250);                                                              // goodfas运行250frame
    fas_corrupt.setRandomizeDist(2, 5);                                                       //badfas domains 2/7,goodfas 5/7
    fas_corrupt.setFrameCount(1000);                                                            //对1000frame 进行corrupt
    stack.add(good_fas).next().add(fas_corrupt).finish();
endfunction




  virtual task main_phase(uvm_phase phase);
   phase.raise_objection(this);
   stack.start(phase, 1'b0);
   phase.drop_objection(this);
  endtask


endclass


`endif //FASRegenTest_sv

**************************************************************************************************************************************************

**************************************************************************************************************************************************/



您可能感兴趣的与本文相关的镜像

ACE-Step

ACE-Step

音乐合成
ACE-Step

ACE-Step是由中国团队阶跃星辰(StepFun)与ACE Studio联手打造的开源音乐生成模型。 它拥有3.5B参数量,支持快速高质量生成、强可控性和易于拓展的特点。 最厉害的是,它可以生成多种语言的歌曲,包括但不限于中文、英文、日文等19种语言

<think> 首先,用户的问题是关于UVM验证中前门访问的具体代码实例及讲解。用户提到:"我想获取使用UVM验证中前门访问的具体代码实例讲解",并引用了几个来源,包括UVM实战书中的内容。 从系统指令中,我需要: 1. 所有行内数学表达式必须使用$...$格式。 2. 独立公式必须使用$$...$$格式并单独成段。 3. LaTeX语法正确。 4. 使用中文回答。 5. 生成相关问题。 6. 回答中引用的段落末尾自然地添加引用标识,例如[^1]。 7. 回答结构清晰,帮助用户逐步解决问题,尽量保证回答真实可靠。 用户的问题没有涉及数学表达式,所以我不需要添加数学公式。重点是提供前门访问的代码实例和讲解。 回顾引用: - 引用[1]是关于UVM实战书的介绍。 - 引用[2]提到了一些UVM知识点,包括第3章UVM基础和第7章寄存器模型。 - 引用[3]:解释了寄存器模型的前门访问操作,通过sequence产生uvm_reg_bus_op变量。 - 引用[4]:关于NVDLA uvm验证环境,但似乎与问题不直接相关。 用户的问题核心是前门访问的代码实例。所以,我应该基于引用[3]来构建回答。 步骤: 1. **理解前门访问**:从引用[3],前门访问涉及读和写操作,使用uvm_reg_bus_op变量。 2. **提供代码实例**:我需要创建一个具体的代码示例来演示前门访问。既然引用提到通过sequence产生uvm_reg_bus_op,我应该包括一个sequence和寄存器模型的代码。 3. **讲解**:解释代码的关键部分。 4. **结构回答**: - 先介绍前门访问的概念。 - 然后给出代码示例。 - 最后讲解代码。 5. **生成相关问题**:在回答末尾,添加几个相关问题。 6. **引用标识**:在讲解中,自然地添加引用标识,比如提到引用[3]时加[^3]。 代码示例结构: - 假设有一个寄存器模型。 - 创建一个sequence来进行前门访问。 - 在sequence中使用uvm_reg的read/write方法。 典型代码: - 定义一个寄存器模型类(uvm_reg_block)。 - 在sequence中,调用reg_model的read或write方法,指定路径为前门(UVM_FRONTDOOR)。 例如: ```systemverilog class my_reg_sequence extends uvm_sequence #(uvm_sequence_item); uvm_reg my_reg; // 寄存器实例 uvm_status_e status; task body(); // 前门写操作 my_reg.write(status, 32'h1234, UVM_FRONTDOOR); // 前门读操作 uvm_reg_data_t data; my_reg.read(status, data, UVM_FRONTDOOR); endtask endclass ``` 讲解要点: - UVM_FRONTDOOR指定访问方式。 - uvm_reg_bus_op被内部使用来传输数据。 - 序列通过总线代理发送事务。 确保回答真实可靠:基于UVM标准实践。 生成相关问题: 1. 前门访问和后门访问的区别是什么? 2. 如何配置总线代理来处理前门访问? 3. 前门访问的优缺点有哪些? 最后,添加引用标识。 </think> ### UVM验证中前门访问的具体代码实例及讲解 在UVM(Universal Verification Methodology)验证中,**前门访问**是指通过总线协议(如APB、AHB等)对寄存器进行读写操作,模拟真实硬件行为。这种方法会生成总线事务(bus transaction),由sequence发起并通过总线driver执行。以下基于《UVM实战》第7章寄存器模型内容[^3],提供具体代码实例和逐步讲解。 #### 1. **前门访问的核心概念** 前门访问操作分为读和写两种。寄存器模型会创建一个`uvm_reg_bus_op`变量,存储操作类型(读/写)、地址和数据(写操作时)。该变量通过总线sequence发送到driver,最终驱动DUT(Design Under Test)[^3]。数学上,地址映射可表示为: $$ \text{物理地址} = \text{基地址} + \text{寄存器偏移量} $$ #### 2. **完整代码实例** 以下是一个基于APB总线的UVM前门访问示例,包含寄存器模型、sequence和测试组件。 ```systemverilog // 步骤1: 定义寄存器模型(继承自uvm_reg_block) class my_reg_block extends uvm_reg_block; rand uvm_reg reg_ctrl; // 控制寄存器 function new(string name = "my_reg_block"); super.new(name, UVM_NO_COVERAGE); endfunction virtual function void build(); // 创建寄存器实例:名称、宽度、是否volatile reg_ctrl = uvm_reg::type_id::create("reg_ctrl", , get_full_name()); reg_ctrl.configure(this, null, "CTRL_REG"); reg_ctrl.build(); // 构建寄存器字段(略) // 映射寄存器到物理地址(基地址0x1000,偏移量0x00) default_map = create_map("default_map", 'h1000, 1, UVM_LITTLE_ENDIAN); default_map.add_reg(reg_ctrl, 'h00, "RW"); endfunction endclass // 步骤2: 定义前门访问sequence class reg_frontdoor_seq extends uvm_sequence #(apb_transaction); my_reg_block reg_model; // 寄存器模型句柄 uvm_status_e status; // 操作状态(UVM_IS_OK/UVM_NOT_OK) task body(); uvm_reg_data_t read_data; // 存储读取的数据 // 前门写操作:写入值0x5A到reg_ctrl reg_model.reg_ctrl.write(status, 'h5A, .path(UVM_FRONTDOOR)); if (status != UVM_IS_OK) `uvm_error("SEQ", "Write operation failed") // 前门读操作:从reg_ctrl读取数据 reg_model.reg_ctrl.read(status, read_data, .path(UVM_FRONTDOOR)); if (status == UVM_IS_OK) `uvm_info("SEQ", $sformatf("Read data: 0x%0h", read_data), UVM_LOW) endtask endclass // 步骤3: 在测试用例中集成 class my_test extends uvm_test; my_reg_block reg_model; reg_frontdoor_seq seq; task run_phase(uvm_phase phase); // 创建并启动sequence seq = reg_frontdoor_seq::type_id::create("seq"); seq.reg_model = reg_model; // 传递模型句柄 seq.start(null); // 启动sequence endtask endclass ``` #### 3. **代码关键点讲解** - **寄存器模型构建** (`my_reg_block`): - `configure()`方法指定寄存器名称和父block。 - `create_map()`定义地址映射空间,`add_reg()`将寄存器绑定到偏移地址[^3]。 - 例如,`reg_ctrl`的物理地址为`0x1000 + 0x00 = 0x1000`。 - **前门访问sequence** (`reg_frontdoor_seq`): - `write(status, value, UVM_FRONTDOOR)`:发起写操作,`UVM_FRONTDOOR`参数指定访问方式。 - `read(status, data, UVM_FRONTDOOR)`:发起读操作,读取数据存入`read_data`。 - 内部生成`uvm_reg_bus_op`结构体,包含操作类型(读/写)、地址和数据[^3]。 - **操作流程**: 1. Sequence调用`write()`/`read()`方法。 2. 寄存器模型通过总线adapter将`uvm_reg_bus_op`转换为具体总线事务(如`apb_transaction`)。 3. 事务由driver驱动到DUT,完成硬件级访问。 #### 4. **前门访问的优缺点** - **优点**: - 模拟真实硬件行为,验证总线协议正确性。 - 支持并发访问和时序检查。 - **缺点**: - 速度较慢(相比后门访问),因涉及总线事务。 - 需要配置完整的总线环境(adapter、driver等)。 通过前门访问,验证工程师能确保寄存器在真实总线交互中的行为符合预期[^3]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值