《芯片漫游指南》backbone

本文档概述了IC验证的基础知识,包括针对ctrl-reg的测试、SV组件的设计及其实现,激励发生器的随机化等内容。此外,还介绍了UVM(Universal Verification Methodology)的使用,包括工厂机制、核心基类、phase机制等关键概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

笔者最近在看 IC 验证部分,由于时间有限,就初略做了一点 backbone 的笔记,简单梳理了从第八章到十一章大概介绍的知识点

1.针对ctrl-reg的测试

1. regs_cr_if

​ 提供整个系统的 clk 时钟和 rstn 复位信号

2. regs_ini_if

​ 测试 cmd 以及 输出输入 data

3. regs_rsp_if

​ 读取 slave 的相关信息

2. sv组件

1. stm_ini

连接 regs_ini_if 模块,

module regs_ini_if(
  input         clk,
  input         rstn,
  output [ 1:0] cmd,
  output [ 7:0] cmd_addr,
  output [31:0] cmd_data_w,
  input  [31:0] cmd_data_r
);
    .......
endmodule

module stm_ini;
 /*
 	这里相当于直接引用了 regs_ini_if 的接口,比如我要用其中的clk,直接敲入 vif.clk即可
 */
    virtual interface regs_ini_if vif;
    
    typedef struct{
      bit [ 1:0] cmd;
      bit [ 7:0] cmd_addr;
      bit [31:0] cmd_data_w;
      bit [31:0] cmd_data_r;
    } trans;

    trans ts[];//声明动态数组
   	//定义基本的行为
    task op_wr(trans t);
      @(posedge vif.clk);
      vif.cmd <= t.cmd;
      vif.cmd_addr <= t.cmd_addr;
      vif.cmd_data_w <= t.cmd_data_w;
    endtask
    task op_rd(trans t);
        .......
    task op_idle();
        ......
    task op_parse(trans t);
      case(t.cmd)
        WR: op_wr(t);
        RD: op_rd(t);
        IDLE: op_idle();
        default: $error("Invalid CMD!");
      endcase
    endtask
     
    initial begin: stmgen
      wait(vif != null);
      @(posedge vif.rstn);
      foreach(ts[i]) begin
        op_parse(ts[i]);
      end
    end
endmodule

module tests;
 /*
 	详细阐述测试向量
 */
    int fin;//控制仿真的结束

    task test_wr;
      tb.ini.ts = new[2];
      tb.ini.ts[0].cmd         = WR;
      tb.ini.ts[0].cmd_addr    = 0;
      tb.ini.ts[0].cmd_data_w  = 32'h0000_FFFF;
      tb.ini.ts[0].cmd         = RD;
      tb.ini.ts[0].cmd_addr    = 0;
      fin = 150;
    endtask

    task test_rd;
      tb.ini.ts = new[2];
      tb.ini.ts[0].cmd         = RD;
      tb.ini.ts[0].cmd_addr    = 'h10;
      tb.ini.ts[1].cmd         = RD;
      tb.ini.ts[1].cmd_addr    = 'h14;
      fin = 200;
    endtask
endmodule        

// 实现stimulator、test vector 、tb的分立
module tb;
    
 .......
    
endmodule    

2. stimulate package

类内部的方法必须是 taskfunction ,不能使用 alwaysinitial 默认定义了构造函数 new()

成员覆盖

子类作用域中出现与父类相同的变量名或方法名,则以子类的作用域为准。这里要注意类的对象句柄的传递。

basic_test t;//static   binding
test_wr wr;

initial begin
    wr = new();
    t = wr;
    ...
end
//执行t.test(),则只会搜寻 basic_test::test 方法,而不会执行test_wr::test

要调用正确的方法则需要动态绑定,指调用方法时,在运行时确定句柄指向对象的类型,再动态指向应该调用的方法。所以可以把父类定义为 **虚方法**

class basic_test;
    ...
    virtual task test(stm_ini ini);
        $display("basic_test::test");
    endtask
    ...
endclass

Tips:

  • 定义父类方法,如果该方法可能会被覆盖或者继承,应该声明为虚方法。
  • 定义虚方法,应定义在底层父类中。
  • 虚方法通过 virtual 声明,且只用声明一次,子类无需声明。
  • 虚方法继承需要遵循相同的参数和返回类型。

编译器遇到对象赋值只做静态检查,而静态检查只允许子类句柄赋值给父类句柄

那要实现动态检查则需要 $cast( , )函数。

对象的复制不能通过 “ = ” (这只是句柄的赋值)

复制对象通过创建新的对象(开辟新的空间),将目标对象的成员变量值复制给新对象成员

实现对象复制需要注意:

  • 分为成员复制函数 copy_data() 和新对象生成函数 copy() 俩个方法
  • 复制方法声明为虚函数
  • 实现 copy_data() 过程中应注意句柄的类型转换

3.激励发生器的随机化

对于 MCDF 激励发生器的激励作用主要体现在:

  • 时钟和复位激励
  • 寄存器配置激励
  • 从端通道数据输入
  • 整形器响应端的反馈

激励生成顺序:

  1. 时钟和复位信号
  2. 配置寄存器
  3. 预先设置整形器响应端
  4. 给从端通道写入数据

packed vs unpacked

到这里都是对 ctrl_reg 的外部接口测试

4.检测器采样

开始测试 slave_channel

主要介绍了 interface clocking 的特性 以及 monitor 搭建

5.组件间的通信

SV 自带的通信**“三宝”**

1.通知的需求

event 事件触发

event start;

wait(start.triggered);//判断是否触发

@start;//线程多次通知需求需要用 @

2.资源共享需求

semaphore(旗语) 来保管 钥匙

semaphore key;

key.get(); //锁资源

key.put();//释放资源

3.数据通信需求

mailbox --> 存取方法 : put() get()

queue --> 存取方法 :push_back() pop_front()

“三宝”:可以参考这篇

1.event:

最小信息量触发,单一的通知功能

2.semaphore

共享资源安全卫士

3.mailbox

精小的 SV 原生 FIFO

到这里基本完成 slave 、arbiter 、 registers 的模块验证

6.比较器和参考模型

开始验证 formatter

分三类检查

1.异常检查

这块主要查复位,各端口信号是否正常复位

2.常规检查

  1. 拆分检查
  2. 整体检查

3.时序检查

完成所有组件的检测包括 check 如何实现

7.测试环境的报告规范

3.SV系统集成

1.包的意义

package 和 library 的区别

这块讨论了 package 使用的若干细节

2.验证环境组装

提出了 agent 的概念,并讨论模块验证的复用性 比如 check(这块还是有点模糊)

3.测试场景生成

进一步的封装 test 类 ----> vector 类 (生成随机数据)

​ 1. vector 类

test 类 -->|

​ 2. env

停止线程的俩种方式

  1. disable thread_trigger
  2. disable fork

并进一步介绍了几种关于线程控制的函数

然后介绍了向量群落的并发控制(挺有用的)

4.灵活化的配置

active agent: 含有stimulator的对象

passive agent

设置变量控制组件行为

5.环境的复用性

4.UVM世界观

之前的实验都是在Mentor QuestaSim 实现

此次是用 Synopsys VCS

1.工厂机制

factory 三大核心要素:注册、创建和覆盖

实例或类型替代在 uvm 中称为覆盖( override )

验证环境主要有

1.环境层次 uvm_component类

2.环境属性和数据传输 uvm_object类 ( uvm_componet 继承于 uvm_object )

factory 运用步骤:

  1. 将类注册到工厂(`uvm_component_utils)
  2. 例化前设置覆盖对象和类型(optional)
  3. 对象创建

详细介绍了 factory 注册的过程

! factory 的覆盖机制只会影响通过 factory 注册并且创建的对象,比如:

c2 = comp1::type_id::create("c2", null);

2.核心基类

​ uvm_void (root class)

​ |

​ / \

uvm_object uvm_port_base

uvm_object:提供与数据操作的相关服务

介绍

copy()

compare()

print() 提供了几种打印格式

pack() & unpack()

3.phase机制

保证验证环境的连接关系

阐述 UVM 开始仿真的过程 run_test()

以及如何结束 UVM 仿真

4.config机制

uvm_config_db 配置类

作用:

1.将 virtual interface 传递到环境

2.设置单一变量

3.传递配置对象到环境

除了上面 uvm_config_db 配置外还可以使用 uvm_resource_db 类实现

以及 set_config_ *()/get_config_ *()

5.消息管理

提供了4个消息函数

5.UVM结构

这章给出待测设计 MCDFUVM 验证结构

介绍构成环境的常见组件类:

1.uvm_driver

从 uvm_sequencer 获取 transaction ,经过转化在接口中对 DUT 进行时序激励

class uvm_driver #(type REQ = uvm_sequence_item, type RSP = REQ) extends uvm_component;

2.uvm_monitor

监测接口数据

3.uvm_sequencer

像一个管道,从中传送连续的激励事物,最终通过 LTM 端口送至 driver 一侧。

4.uvm_agent

一个标准的验证环境 “单位” 。通常包括 一个 driver、一个 monitor、一个 sequencer

uvm_active_passive_enum is_active = UVM_ACTIVE;
//active mode : enable driver monitor sequencer
//passive mode : enable monitor

agent 需要在 build_phase()connect_phase() 等函数中通过选择语句对 driver 和 sequencer 来进行有条件的例化和连接

5.uvm_scoreboard

功能同 checker 即对数据比对和报告。

6.uvm_env

uvm_env 包含多个 uvm_agent 和其他 component

是一个结构化的容器,可以容纳其他组件

7.uvm_test

是验证环境建立的唯一入口,只有通过这个才能正常运转 UVM 的 phase 机制

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

不吃人的坤坤坤坤坤

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

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

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

打赏作者

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

抵扣说明:

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

余额充值