首页
游戏
影视
直播
广播
听书
音乐
图片
更多
看书
微视
主播
统计
友链
留言
关于
论坛
邮件
推荐
我的硬盘
我的搜索
我的记录
我的文件
我的图书
我的笔记
我的书签
我的微博
Search
1
在IC617中进行xa+vcs数模混仿
81 阅读
2
科普:Memory Compiler生成的Register file和SRAM有何区别?
73 阅读
3
virtuoso和empyrean alps模拟仿真和混仿教程
73 阅读
4
后仿中$setup,$hold与$setuphold
44 阅读
5
文档内容搜索哪家强? 15款文件搜索软件横向评测
35 阅读
默认分类
芯片市场
数字电路
芯片后端
模拟电路
芯片验证
原型与样片验证
算法与架构
DFX与量产封装
PC&Server OS设置
移动OS设置
软件方案
新浪备份
有道备份
登录
Search
标签搜索
python
Docker
vscode
linux
systemverilog
vcs
STM32
PyQT
EDA
FPGA
gvim
cadence
Alist
xilinx
UVM
uos
macos
package
MCU
risc-v
bennyhe
累计撰写
378
篇文章
累计收到
31
条评论
首页
栏目
默认分类
芯片市场
数字电路
芯片后端
模拟电路
芯片验证
原型与样片验证
算法与架构
DFX与量产封装
PC&Server OS设置
移动OS设置
软件方案
新浪备份
有道备份
页面
游戏
影视
直播
广播
听书
音乐
图片
看书
微视
主播
统计
友链
留言
关于
论坛
邮件
推荐
我的硬盘
我的搜索
我的记录
我的文件
我的图书
我的笔记
我的书签
我的微博
搜索到
33
篇与
的结果
2026-01-08
UVM入门
验证技术的发展历程这是我们作为一名合格验证人员装B必备,如下图所示:2000年:Verisity Design(现在的Cadence公司)引进了Verification Advisor(vAdvisor)采用了e语言,包含了激励的产生,自动比对的策略,覆盖率模型。e语言是面向对象语言,这是业界开始使用面向对象语言 进行测试平台的建立。2002年:Verisity公司公布了第一个验证库——e可重用方法学(eRM)。2003年:Synopsys公司公布了可重用验证方法学库(RVM),这个方法学采用了Synopsys公司的vera语言。2006年:Mentor公司公布了高级验证方法学(AVM)。这个方法学主要是采用了OSCI SystemC的事务抽象层方法学(TLM)标准,它是用SystemVerilog和SystemC两种语言实现的。2006年:Synopsys公司推出了验证方法学手册(VMM),这个是RVM从vera语言过度到SystemVerilog的方法学。2007年:Cadence公司推出了通用可重用验证方法学(URM),主要是从eRM从E语言过度到SystemVerilog的方法学,同时加入了TLM接口,工厂模式替换,配置机制,策励类等。2008年:Cadence公司和Mentor公司共同推出了OVM2010年:Synopsys公司推出了VMM1.2,基本上沿用了OVM的TLM通信机制,并采用了TLM2.0(OSCI最新的标准),采用OVM提出的implicit phase,并且将验证流程继续细化,工厂模式替换机制,建立类层次(建立parent关系)。并且在此基础上,提出了vmm_timeline的概念,方便各个phase之间实现跳转,增加phase或删除phase。增加了rtl_config等概念。Synopsys公司也随即宣布最新版本的VCS 同时支持UVM。2010年:ACCELLERA采用了OVM作为基础,推出了UVM验证方法学。同时引入了VMM的callbacks一些概念。作为业界方法学统一的一个雏形。2011年2月:Accellera通过了通用验证方法学1.0版,并得到三大厂商(Cadence,Synopsys和Mentor Graphics现英飞凌)的共同支持。此后Accellera陆续推出了UVM1.1, UVM1.1a,UVM1.1b,UVM1.1c,UVM1.1d这几个版本。2014年6月,Accellera有推出了通用验证方法学1.2版。目前UVM最新版是UVM-1800.2-2017-1.0(版本号命名都变了哈)UVM(Universal Verification Methodology) UVM几乎完全继承了OVM,同时又采纳了Synopsys在VMM中的寄存器解决方案RAL。UVM继承了OVM和VMM的优点,克服了各自的缺点,代表了验证方法学的发展方向。UVM介绍UVM是一个以SystemVerilog为主体的验证平台开发框架,验证工程师利用其可重用组件可以构建具有标准化层次结构和接口的功能验证环境。UVM是一个库,在这个库中,几乎所有的东西都是使用类(class)来实现的。类是面向对象编程语言中最伟大的发明之一,是面向对象的精髓所在。使用UVM的第一条原则是:验证平台中所有的组件都应该派生自UVM中的类。当要实现一个功能时,首先应该想到的就是从UVM的某个类派生出一个新的类,类中可以有成员变量,也可以有函数和任务,通过成员变量、函数或任务实现所期望的功能。对于验证方法学来说,分层的测试平台是一个关键的概念。虽然分层似乎会使测试平台变得更复杂,但它能够把代码分而治之,有助于减轻工作负担,而且重复利用效率提升。基于UVM的验证平台可以类似分为五个层次:信号层、命令层、功能层、场景层和测试层:如何学习UVMUVM1.2版本包含121个文件,311个类。从经验来说,我们搭建一个普通的UVM验证环境,大约需要编写10个文件,20个类左右。这里分享一下对初学者的个人建议:第一阶段-基础:学习UVM之前, 熟悉SV是必须的,关于SV的系统学习首推“绿皮书”。工作中“asic-world”这个网站可以作为我们的查询手册。第二阶段-学习:有了SV的基础和OOP的思想,我们就可以开始学习UVM了(很多人入门是看《UVM实战》-张强著 )。这时我们需要了解UVM构架,各种component, phase管理机制等。最好配合实例代码一边看书一边敲代码做练习。第三阶段-应用:当然我们有的朋友会说:"我现在的公司还没有用UVM来搭环境呀,怎么应用啊?" 但是,没有条件我们可以创造条件呀! 网上这么多开源的IP,找一个自己感兴趣的,把自己当成验证主管,自己玩儿呗。或者把已经做过的项目再用UVM搭一遍(别说你没时间哦~第四阶段-研究:这个时候你已经是熟手,并能够独立搭建复用性很强的UVM环境了。这时可以去看看UVM源码,帮助同事解决实际工作中的各种问题。研究一下UVM代码自动生成,UVMF是什么等等
2026年01月08日
2 阅读
0 评论
0 点赞
2026-01-08
CPU 系统级验证 —— 指令集验证 ——OpenHW core-v 验证环境及文件分析
本文记录的相关源工程和文件为:core-v RISCV 核功能验证工程:https://github.com/openhwgroup/core-v-verifcore-v 验证策略:https://core-v-docs-verif-strat.readthedocs.io/en/latest/#core-v 系列核 cva6 工程:https://github.com/openhwgroup/cva6core-v 系列核 cv32e40p 工程:https://github.com/openhwgroup/cv32e40pLowRISCV Ibex 核工程:https://github.com/lowRISC/ibexcore-v RISCV 核相关说明文档:https://github.com/openhwgroup/core-v-docsRISCV ISA 指令流(instruction stream)生成器:https://github.com/openhwgroup/force-riscvcore-v 系列指令流(instruction stream)生成器:https://github.com/openhwgroup/core-v-isgsail 语言介绍:https://www.cl.cam.ac.uk/~pes20/sail/REMS 的 sail RISCV 开源项目:https://github.com/rems-project/sail-riscvopenHW 全称为 open-source hardware,是一个支持开源软件和硬件的非盈利组织。该组织开源的内容包括开源 CPU 核、相关 IP、工具和软件等。指令集验证指令集验证的需求能够使用操作数产生合法的基本整数运算指令在指令执行完成后能够检查通用寄存器的状态指令执行完成后能检查副效应,例如溢出等。指令集验证内容指令集的验证需要验证工程师思考该指令需要测试的特征是什么,为了确保指令的正确执行需要检查的内容是什么,为了确保该特征被测试需要进行哪些激励和配置等。验证的充不充分取决于验证人员对 CPU 微架构的理解和风险应对能力。(1)RISCV 基本指令定向测试设计出来的 CPU 首先需要兼容 RISCV 基本指令,即需要满足 RISCV 基本整数指令及相关标准指令集。主要测试的内容有:溢出检测及相关标志位下溢检测及相关标志位无指令执行的副效应,比如异常的通用处理寄存器变化,异常的条件代码使用 x0-x31 作为 rs1/rs2使用 x0-x31 作为 rdx0 寄存器的值始终为 0set/clear 所有立即数的比特位set/clear 源寄存器 rs1/rs2 的比特位根据 7/8 两条 set/clear 目的寄存器 rd 的比特位(2)自定义扩展指令定向测试对于自定义扩展指令集的验证,该验证需要修改相关的工具链并通过相关测试验证工具链的修改成功,再进行(1)中的测试。(3)随机约束测试对进行大量的随机指令测试指令集验证激励的种类指令集测试激励分为自检(self-checking)和预存(pre-existing)两种。自检测试激励运行时按照源文件中指令顺序依次,并同时将指令执行结果和参考值作检查,若出错则程序跳转到 fail,打断正常执行顺序,立即执行完成。类似的测试集有 riscv-tests、riscv-compilance-tests 等预存测试激励运行时不会打断执行顺序,执行的结果会和指令集模拟器(ISS)的结果作对比,最终统计对比的结果。类似的测试集有 riscv-dv 等指令集验证 pass/fail 的标志测试的 pass/fail 与上述激励的种类有关self checking:自检性质的测试激励在每条指令执行时就会同时将结果和参考值作对比,若失败则跳转到 failsignature check:特征检查,相对自检来说更加复杂深入。测试的结果将被用来计算该指令的某个特征,这将会和预先确定好的较标准特征作对比。采用该检查的为 riscv-complience-tests。check against ISS:与指令集模拟器对比检查。该情况下,testcase 并不知道测试的参考值,仅仅给 DUT 提供激励,testbench 会对比 DUT 和 ISS 的输出结果确定测试的 pass/fail。该检查较被经常使用,因为它是的 testcase 更加简单。采用该检查的如 riscv-dvcheck against RM:与参考模型对比检查,该检查方式与第三点类似,但相对 ISS 更加通用。通常用作 ISS 检测的补充。assertion check:通过断言判断是否执行出错。相关 CPU 核的验证工程cv32e40pCV32E40P (原先 PULP 开发的 RI5CY) 是一个 32bit 的 4 级流水线核,支持整数运算指令、乘法除法指令、单浮点运算指令、压缩指令以及 DSP 扩展指令(包括硬件循环、SIMD 扩展、位操作和增量指令)该核的验证环境有两套,一套是专门的 core testbench;一套是 UVM 环境搭建的 testbench,该环境下 testcase 的产生是可以基于 UVM 环境的(这种方式类似于 Ibex 核验证环境)。两套环境均由 systemverilog 编写。均包含了指令集验证、中断验证、CSR 寄存器验证、异常验证、debug 验证等。1 core testbench该工程是 PULP 遗留下的产物,OpenHW 做了一定修改并持续维护。验证环境中已集成了指令集模拟器。该工程的测试集激励包含指令兼容性测试(偏定向测试,如 riscv-tests 和 riscv-compilance-tests)和随机约束(google riscv-dv),和其他的一些 fireware 测试用例。测试环境结构如下:该 testbench 简单,运行较快,通过 verilator 运行,但是有额外的开销且不能获取覆盖率。2 UVM 验证环境(uvmt_cv32)cv32 核的 UVM 验证环境已搭建完成,在 DSIM(Metrics)运行也很稳定。验证环境中已集成了指令集模拟器。uvm 验证环境的 testcase 均是由 uvm 相关类生成,同时该环境还集成了 riscv-dv,但具体的激励生成还需要再分析。具体验证环境结构UVM 内部组件关系debug、interrupt、control/status 均通过 UVM_agent 组件产生,且通过 uvm_sequence 组件输入激励。UVM 运行流程采用 UVM 搭环境的优势a) 便于验证环境的结构建模b) UVM 环境类支持完全的 UVM 运行流程和 log 服务c) 使用 UVM sequence-item 类可以产生随即约束激励d) 使用内建于验证环境中的参考模型预测执行的结果。(imperas 有现成的开源 ISS)e) scoreboard 可以比较参考模型和 RTL 的结果。f) 功能覆盖率和代码覆盖率确保验证的完全性。且 UVM 测试环境可复用性较高,也可以用在 CVA6 核上。CVA6CVA6(ariane) 是一个 6 级流水线、单发射、顺序执行的 RV32GC 或 RV64GC 核,支持 M/U/S 三种模式,支持 linux 操作系统。该核现存的验证环境尚未成熟,但同样可以构建 UVM 的验证环境。该工程的指令集测试激励包括 riscv 官方测试套件(即 riscv-tests)。IbexIbex 不是 openHW 的 core-v 系列,而是 lowRISC 持续维护的较为成熟的一款核,验证环境也较为成熟,其结构和运行非常类似于 CV32E 和 CVA6 的激励随机约束。该验证环境激励的产生同样是基于 GOOGLE 的随机指令生成器验证环境特征运行有效性testcase 在验证环境中会持续运行完成,除非激励运行出错方便调试能够增加功能覆盖率能够对比检查 RTL 运行的结果指令集描述语言 ——sailsail 是 REMS 构建的一种描述指令集的语言,可以认为是一种机器可读的形式化 ISA 模型。REMS 是英国的一家学术组织,该组织已构建出 RV32IMAC 和 RV64IMAC 指令集的 sail model,链接见上。riscv 基金会有意用其来描述 RISCV 指令集。初步来看,sail 可以用来形式化 testbench 断言的参考模型,这些 assertion 可以根据 sail spec 来验证基于 RISCV ISA 的某微架构。目前该领域 OneSpin GapFree 已经在 sail model 和 RTL 代码间做了可比性的 check,该公司仍在探索如何充分使用 sail model该语言将持续关注。
2026年01月08日
2 阅读
0 评论
0 点赞
2026-01-07
推荐一款好用的IC设计中生成register model的工具
无意中发现一个开源的工具,使用systemRDL文件作为输入,可以生成寄存器相关的RTL module,UVM中使用的regmodel,C和verilog的头文件(包含寄存器某个字段的偏移以及mask bits),以及html的文档。资源如下:https://github.com/zhajio1988/Open_RegModel生成的html文档示例如下:https://systemrdl.github.io/RALBot-html————————————————版权声明:本文为CSDN博主「XtremeDV」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/zhajio/article/details/102620859开源uvm reg model (UVM 寄存器模型)生成工具open-register-design-toolOrdt is a tool for automation of IC register definition and documentation. It currently supports 2 input formats:SystemRDL - a stardard register description format released by Accellera.orgJSpec - a register description format used within Juniper NetworksThe tool can generate several outputs from SystemRDL or JSpec, including:SystemVerilog/Verilog RTL code description of registersUVM model of the registersC++ models of the registersXML and text file register descriptionsSystemRDL and JSpec (conversion)Easiest way to get started with ordt is to download a runnable jar from the release area.Ordt documentation can be found here.注:nvdla中使用SystemRDL格式描述寄存器模型,并使用jar xxx ordt.jar ......生成uvm reg model————————————————版权声明:本文为CSDN博主「XtremeDV」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/zhajio/article/details/82870523
2026年01月07日
2 阅读
0 评论
0 点赞
2026-01-07
Python在芯片中的应用:RTL自动生成、验证脚本、界面可视化等
今天还是这张图。最近一直在思考集成电路怎么与其它几个前沿领域相结合。今天来讲讲Python。Python其实不是人工智能、神经网络的专属语言,在芯片设计和验证领域也有非常多的应用。下面是一些的开源项目:RTL自动生成:https://github.com/nvdla/hw/blob/master/tools/bin/epython寄存器默型的自动生成:https://github.com/SystemRDL/systemrdl-compiler仿真脚本、回归脚本:https://github.com/zhajio1988/YASA自动生成UVM的方法:https://mp.weixin.qq.com/s/SvWRJBGggg0lqiD8YjEZ3QRISCV Core的仿真脚本:https://github.com/google/riscv-dv因为Python相对于其它语言如Perl,Tcl学习成本更低、资料更多、更容易上手,所以在实际项目中使用python的情况越来越多。当然并不是说Perl、Tcl不需要学了,老项目还需要继续维护。但是,打开大佬的代码后,却一脸懵逼。下面是Google RISCV Core验证项目的脚本run.py截图,大佬们都喜欢用Class来装逼,这个对于Python零基础或者初学者很不友好。函数还没学会,你叫我用class?整天看着UVM就已经够头疼的了,唉。连验证大佬炯哥的脚本也是。。。还有一大堆的import,望而生畏、望而却步。
2026年01月07日
4 阅读
0 评论
0 点赞
2026-01-04
systemverilog interface
systemverilog interface普通的模块使用法:注意我们这里只实现了部分功能。。。。不是完全的读写模块。。。。module mem_core( input logic wen, input logic ren, output logic mrdy=1, input logic [7:0] addr, input logic [7:0] mem_din, //写进mem output logic [7:0] mem_dout, //从mem读出 output logic status, input logic clk);logic[7:0] mem [7:0]; //初始化一个meminitial $readmemh("d:/init.txt",mem); //d:/init.txt 文件中是 @01 10 。//或者 assign mem [2'h01]=8'b00000111; 注意这里一定要用 initial 或者assign等语句,不能直接=task reply_read(input logic [7:0] data, integer delay); #delay; @(negedge clk) mrdy=1'b0; mem_dout=data; //从图中可看出这两句话几乎同时执行。 @(negedge clk) mrdy=1'b1;endtaskalways@(negedge ren) reply_read(mem[addr],10);endmodulemodule cpu_core( output logic wen=1, output logic ren=1, input logic mrdy, output logic [7:0] addr=0, input logic [7:0] cpu_din, output logic [7:0] cpu_dout, output logic status=0, input logic clk);task read_memory(input logic [7:0] raddr, output logic [7:0] data); @(posedge clk); ren=1'b0; addr=raddr; @(negedge mrdy); @(posedge clk); data=cpu_din; ren=1'b1; endtaskinitial beginlogic[7:0] read_data; read_memory(2'h01, read_data); $display("Read Result", $time,read_data);endendmodulemodule top; logic mrdy,wen,ren; logic[7:0] addr,d1,d2; wor status; logic clk=0;mem_core mem(., .mem_din(d1), .mem_dout(d2)); //采用对同名的信号做默认连接 cpu_core cpu(.*, .cpu_din(d2), .cpu_dout(d1));initial for(int i=0;i<=255;i++) #1 clk=!clk;endmoduleSystemverilog interface另外,SystemVerilog引入一个重要的数据类型:interface。其主要作用有两个:一是简化模块之间的连接;二是实现类和模块之间的通信;随着复杂度的提高,模块间互联变得复杂,SV引入接口,代表一捆连线的结构,具有智能同步和连接功能的代码;接口(interface)为硬件模块的端口提供了一个标准化的封装方式。用interface来封装接口的信号和功能。interface的定义是独立于模块的,通过关键字interface和endinterface包起来。此外,interface里面还可以带时钟、断言、方法等定义。 一个interface 也可以有input,output或是inout端口。当interface例化时,只有当变量或是线网声明在一个interface的端口列表中才能通过名字或是位置来互连.一种新加的和interface有关系的构造体是Modport 。它提供了module的interface端口和在特定的module中控制task和function使用的方向性信息。这些端口的方向可以在module中可以看到。接口使用无信号的连接方式。Modport将接口中信号分组并指定方向。就像下图中的黑色矩形块里面一样,黑盒,我们从外面看并不关心Modport的定义,只需要考虑clk。Systemverilog interfaceinterface membus(input logic clk, output wor status); logic mrdy; logic wen; logic ren; logic [7:0] addr; logic [7:0] c2m_data; logic [7:0] m2c_data;task reply_read(input logic [7:0] data, integer delay); #delay; @(negedge clk) mrdy=1'b0; m2c_data=data; @(negedge clk) mrdy=1'b1;endtask//Task和function可以定义在interface中,从而允许构造更抽象级的模型task read_memory(input logic [7:0] raddr, output logic [7:0] data); @(posedge clk); ren=1'b0; addr=raddr; @(negedge mrdy); @(posedge clk); data=m2c_data; ren=1'b1; endtaskmodport master(output wen, ren, addr, c2m_data, input mrdy, m2c_data, status, read_memory);modport slave(input wen, ren, addr, c2m_data, output mrdy, m2c_data, status, reply_read);//控制task和function使用的方向性信息,以便在下面的module中使用endinterfacemodule mem_core(membus.slave mb); //modport只需在模块首部指明(或者在()中),在模块例化时不需要指明使用接口时在模块和程序块之外声明接口变量;//接口信号必须采用非阻塞值赋值来驱动。 logic[7:0] mem [7:0]; assign mem [2'h01]=8'b00000111; assign mb.status=0; always@(negedge mb.ren) mb.reply_read(mem[mb.addr],100); //module可使用interface端口endmodulemodule cpu_core(membus.master mb); assign mb.status=0; initial beginlogic[7:0] read_data; mb.read_memory(2'h01, read_data); $display("Read Result", $time,read_data);endendmodulemodule top; wor status; logic clk=0; membus mb(clk,status); mem_core mem(.mb(mb.slave)); cpu_core cpu(.mb(mb.master));initial for(int i=0;i<=255;i++) #1 clk=!clk;endmoduleSystem verilog把测试平台的代码放在一个程序块中,包含代码和变量,我总结了几步使用interface的方法1、 首先定义一个interface interface arb_if(input bit clk); logic [1:0] grant, request; logic reset; clocking cb @(posedge clk); //在其中定义一个时钟块。供下面的测试program使用。测试program中所有使用到的信号都应该定义在其中 output request; //注意这里的方向是测试program中所需要的方向,一般跟DUT 中的相反 input grant; endclockingmodport TEST (clocking cb, // 使用modport,将信号分组 output reset); modport DUT (input request, reset, clk, output grant); modport MONITOR (input request, grant, reset, clk);endinterface2、定义一个基于interface参数的设计模块modulemodule arb (arb_if.DUT arbif); //该interface参数要实例化 reg last_winner; reg winner; reg [1:0] next_grant; reg [1:0] state, nxState; always @(posedge arbif.clk or posedge arbif.reset) begin 。。。 endendmodule 3、定义一个基于interface参数的测试程序program program automatic test (arb_if.TEST arbif); //该interface参数也要实例化task reset_test();begin$display("Task reset_test: asserting and checking reset"); arbif.reset <= 0; #100 arbif.reset <= 1; //测试program中所有使用到的信号都应该调用在interface中的时钟块里定义的信号 arbif.cb.request <= 0; repeat (2) @arbif.cb; arbif.reset <= 0; @arbif.cb; //测试program中是这样等待时钟边沿的。 a0: assert (arbif.cb.grant == 2'b00); 。。。 end endtask task request_grant_test();begin 。。。 end endtask //注意program中不允许使用always块。 initial begin repeat (10) @arbif.cb; reset_test(); request_grant_test(); repeat (10) @arbif.cb; $finish; endendprogram4、‘最后使用一个顶层模块将它们组合起来module top; bit clk; always #5 clk = !clk; arb_if arbif(clk); //实例化一个interface arb a1 (arbif); //实例化一个module,参数调用上面实例化的interface test t1(arbif); //实例化一个测试program,参数调用上面实例化的interfaceendmodule当然也可以隐式端口连接,值使用.*即可。module top; bit clk; always #5 clk = !clk; arb_if arbif(.*); arb a1 (.*); test t1(.*); endmodule虚接口:虚接口是物理接口的句柄interface 和 module是一样的, 都是静态的变量, 也就是在程序开始时, 内存中就有了其实例.但是在class里使用virtual interface时之前有两部必须提前完成:l 定义是将接口作为一个类进行定义。l 实例化:在RTL级的顶层中对接口进行实例化。先定义一个接口。interface Rx_if (input logic clk);logic [7:0] data; logic soc, en, clav, rclk; clocking cb @(posedge clk); output data, soc, clav; input en; endclocking : cb modport DUT (output en, rclk, input data, soc, clav); modport TB (clocking cb);endinterface : Rx_if例如网络交换机中DUT 的每一个通道都有一个接口。,一个Driver类可能会连接到很多接口。我们可以在Driver类中使用一个虚接口作为参数。 class Driver;virtual Rx_if.TB Rx; //想一想,如果不是虚接口,而是一个普通接口,就像一个普通模块一样,是一个静态变量。比如我们在顶层模块例化了这个接口 Rx, 那么下面所有的 实例化的 drv[i]都是对这同一个接口 Rx进行操作,这显然不是我们想要的。如果定义了virtual,则每个实例独立。......endclass然后在测试program中 创建一组虚接口program automatic test(Rx_if.TB Rx[4], Tx_if.TB Tx[4], output logic rst); ........Driver drv[4]; //实例化了4个 Driver 对象,每个 Driver对象带有1个实例化的虚接口 .........initial beginvirtual Rx_if.TB vRx_t=Rx; //创建一组虚接口,由于这里定义了virtual,所以实例化的时候可以有Rx[]. for (int i=0; i<4; i++) begin drv[i] = new(...., vRx[i]); end rst <= 1; repeat (10) @Rx[0].cb; rst <= 0; for (int i=0; i<4; i++) begin drv[i].run(5, driver_done); //发送....... end..........endprogram : test最后在顶层:module top; logic clk, rst;Rx_if Rx[4] (clk); ,,,, atm_router a1 (Rx[0], Rx[1], Rx[2], Rx[3], Tx[0], Tx[1], Tx[2], Tx[3], clk, rst);test t1 (Rx, Tx, rst);initial beginclk = 0; forever #20 clk = !clk; end endmodule : top定义一个interface,且实例化多个后,如果没有定义virtual,则在任何一个实例中修改了某个信号值,在其他实例中都会受到影响。如果定义了virtual,则每个实例独立。如果该interface只有一个实例,可用可不用virtual,有多个实例,需要virtual。再举个例子:8位计数器`timescale 1ns/1nsinterface X_if (input logic clk);logic [7:0] din, dout; logic reset_l, load; clocking cb @(posedge clk); output din, load; input dout; endclocking always @cb //接口里面也可以带子程序,断言,initial,always块等代码。 $strobe("@ : %m: dout= , din= , load= , reset= ", $time, dout, din, load, reset_l); modport DUT (input clk, din, reset_l, load, output dout); modport TB (clocking cb, output reset_l);endinterface// Simple 8-bit counter with load and active-low reset`timescale 1ns/1nsmodule DUT(X_if.DUT xi); logic [7:0] count; assign xi.dout = count; //们想要输出的结果就是计数器always @(posedge xi.clk or negedge xi.reset_l)begin if (!xi.reset_l) count = 0; else if (xi.load) count = xi.din; else count++; end endmodule////////////////////////////////`timescale 1ns/1nsprogram automatic test();parameter NUM_XI = 2; // Number of interface instancestypedef virtual X_if.TB vXi_t; vXi_t vxi[NUM_XI]; //虚接口数组 class Driver; //在测试程序中定义类 vXi_t xi; int id; function new(vXi_t xi, int id); this.xi = xi; this.id = id; endfunction task reset; fork begin $display("@ : %m: Start reset [ ]", $time, id); // Reset the device xi.reset_l <= 1; xi.cb.load <= 0; xi.cb.din <= 0; @(xi.cb) xi.reset_l <= 0; @(xi.cb) xi.reset_l <= 1; $display("@ : %m: End reset [ ]", $time, id); end join_none endtask task load; fork begin $display("@ : %m: Start load [ ]", $time, id); xi.cb.load <= 1; xi.cb.din <= id + 10; xi.cb.load <= 0; repeat (5) @(xi.cb); $display("@ : %m: End load [ ]", $time, id); end join_none endtask endclass Driver driver[]; initial begin // Connect the local virtual interfaces to the top $display("Test.v: There are NUM_XI = interfaces", NUM_XI); if (NUM_XI <= 0) $finish; driver = new[NUM_XI]; //创建driver, 每个DUT 要对应一个driver vxi = top.xi; //XMR跨模块连接。这种是推荐做法,就不用带参数了program automatic test(X_if xi[NUM_XI]); 了。//注意这里其实是把top模块中生成的xi[]数组的句柄传过来的for (int i=0; i《NUM_XI; i++) begin driver[i] = new(vxi[i], i); driver[i].reset; end foreach (driver[i]) driver[i].load; repeat (10) @(vxi[0].cb); $display("@ : Test completed", $time); $finish; end endprogram////////////////////////////////////////////////////////`timescale 1ns/1nsparameter NUM_XI = 2; // Number of interface instancesmodule top; // Clock generator bit clk; initial forever #20 clk = !clk;X_if xi [NUM_XI] (clk); // Instantiate N Xi interfaces// Generate N DUT instances generate for (genvar i=0; i《NUM_XI; i++)begin : dut DUT d (xi[i]); endendgenerate// Instantiate the testbench, overriding the parameter with number of instances test tb();endmodule : top
2026年01月04日
2 阅读
0 评论
0 点赞
1
2
...
7