首页
游戏
影视
直播
广播
听书
音乐
图片
更多
看书
微视
主播
统计
友链
留言
关于
论坛
邮件
推荐
我的硬盘
我的搜索
我的记录
我的文件
我的图书
我的笔记
我的书签
我的微博
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设置
软件方案
新浪备份
有道备份
页面
游戏
影视
直播
广播
听书
音乐
图片
看书
微视
主播
统计
友链
留言
关于
论坛
邮件
推荐
我的硬盘
我的搜索
我的记录
我的文件
我的图书
我的笔记
我的书签
我的微博
搜索到
5
篇与
的结果
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 点赞
2025-12-31
Vscode自动生成verilog例化
前言veirlog模块例化的时候,辣么多的信号端子,手动例化又慢又容易出错,葵花妈妈开课啦,孩子手残老犯错怎么办?当然是脚本一劳永逸,妈妈再也不担心手残党。流程(1)在vscode中安装如下插件。(2)在电脑中安装python3以上的环境。下载地址:https://www.python.org/downloads/release/python-373/安装记得一定要勾选添加路径,记得管理员安装。重启你的电脑。在cmd窗口输入python即可验证是否安装成功!(3)安装chardet。为确保插件可用,这个需要安装。参考链接:https://blog.csdn.net/sinat_28631741/article/details/80483064方式一 源码按照:第一步:下载压缩文件,例如: 'chardet-3.0.4.tar.gz'; 第二步:解压文件到python安装位置下的‘site-packages’目录下,例如:‘D:\python2.7\Lib\site-packages’; 第三步:打开终端命令窗口,进入解压的‘chardet’目录下,执行命令:python setup.py install (4)修改插件的原始py文件,觉得开发者的py有瑕疵,让帅气的同事重新整了个,把以下代码替换进原始py文件即可。在打开v文件的vscode下按ctrl+p,输入instance可出现下述界面。替换此py文件的代码即可。 #! /usr/bin/env python ''' vTbgenerator.py -- generate verilog module Testbench generated bench file like this: fifo_sc #( .DATA_WIDTH ( 8 ), .ADDR_WIDTH ( 8 ) ) u_fifo_sc ( .CLK ( CLK ), .RST_N ( RST_N ), .RD_EN ( RD_EN ), .WR_EN ( WR_EN ), .DIN ( DIN [DATA_WIDTH-1 :0] ), .DOUT ( DOUT [DATA_WIDTH-1 :0] ), .EMPTY ( EMPTY ), .FULL ( FULL ) ); Usage: python vTbgenerator.py ModuleFileName.v ''' import random import re import sys from queue import Queue import chardet def delComment(Text): """ removed comment """ single_line_comment = re.compile(r"//(.*)$", re.MULTILINE) multi_line_comment = re.compile(r"/\*(.*?)\*/", re.DOTALL) Text = multi_line_comment.sub('\n', Text) Text = single_line_comment.sub('\n', Text) return Text def delBlock(Text): """ removed task and function block """ Text = re.sub(r'\Wtask\W[\W\w]*?\Wendtask\W', '\n', Text) Text = re.sub(r'\Wfunction\W[\W\w]*?\Wendfunction\W', '\n', Text) return Text def findName(inText): """ find module name and port list""" p = re.search(r'([a-zA-Z_][a-zA-Z_0-9]*)\s*', inText) mo_Name = p.group(0).strip() return mo_Name def paraDeclare(inText, portArr): """ find parameter declare """ pat = r'\s' + portArr + r'\s[\w\W]*?[;,)]' ParaList = re.findall(pat, inText) return ParaList def portDeclare(inText, portArr): """find port declare, Syntax: input [ net_type ] [ signed ] [ range ] list_of_port_identifiers return list as : (port, [range]) """ port_definition = re.compile( r'\b' + portArr + r''' (\s+(wire|reg)\s+)* (\s*signed\s+)* (\s*\[.*?:.*?\]\s*)* (?P<port_list>.*?) (?= \binput\b | \boutput\b | \binout\b | ; | \) ) ''', re.VERBOSE | re.MULTILINE | re.DOTALL ) pList = port_definition.findall(inText) t = [] for ls in pList: if len(ls) >= 2: t = t + portDic(ls[-2:]) return t def portDic(port): """delet as : input a =c &d; return list as : (port, [range]) """ pRe = re.compile(r'(.*?)\s*=.*', re.DOTALL) pRange = port[0] pList = port[1].split(',') pList = [i.strip() for i in pList if i.strip() != ''] pList = [(pRe.sub(r'\1', p), pRange.strip()) for p in pList] return pList def formatPort(AllPortList, isPortRange=1): PortList = AllPortList str = '' if PortList != []: l1 = max([len(i[0]) for i in PortList])+2 l3 = max(18, l1) strList = [] str = ',\n'.join([' ' * 4 + '.' + i[0].ljust(l3) + '(' + (i[0]) + ')' for i in AllPortList]) strList = strList + [str] str = ',\n\n'.join(strList) return str def formatDeclare(PortList, portArr, initial=""): str = '' if PortList != []: str = '\n'.join([portArr.ljust(4) + ' '+(i[1]+min(len(i[1]), 1)*' ' + i[0]) + ';' for i in PortList]) return str def formatPara(ParaList): paraDec = '' paraDef = '' if ParaList != []: s = '\n'.join(ParaList) pat = r'([a-zA-Z_][a-zA-Z_0-9]*)\s*=\s*([\w\W]*?)\s*[;,)]' p = re.findall(pat, s) l1 = max([len(i[0]) for i in p]) l2 = max([len(i[1]) for i in p]) paraDec = '\n'.join(['parameter %s = %s;' % (i[0].ljust(l1 + 1), i[1].ljust(l2)) for i in p]) paraDef = '#(\n' + ',\n'.join([' .' + i[0].ljust(l1 + 1) + '( ' + i[1].ljust(l2)+' )' for i in p]) + ')\n' return paraDec, paraDef def portT(inText, ioPadAttr): x = {} count_list = [] order_list = [] for i in ioPadAttr: p = port_index_list(inText, i) for j in p: count_list.append(j) x[j] = i count_list = quick_sort(count_list, 0, len(count_list)-1) for c in count_list: order_list.append(x.get(c)) return order_list def quick_sort(myList, start, end): if start < end: i, j = start, end base = myList[i] while i < j: while (i < j) and (myList[j] >= base): j = j - 1 myList[i] = myList[j] while (i < j) and (myList[i] <= base): i = i + 1 myList[j] = myList[i] myList[i] = base quick_sort(myList, start, i - 1) quick_sort(myList, j + 1, end) return myList def formatPort_order(padAttr, orderList): for p in padAttr: q = Queue() for i in padAttr.get(p): q.put(i) padAttr[p] = q AllPortList = [] for o in orderList: AllPortList.append(padAttr.get(o).get()) return AllPortList def port_index_list(intext, text): l = [] t = intext index = t.find(text) while index > -1: t = t.replace(text, random_str(len(text)), 1) l.append(index) index = t.find(text) return l def random_str(size): s = '' for i in range(size): s += str(random.randint(0, 9)) return s def getPortMap(AllPortList, ioPadAttr): if len(AllPortList) != len(ioPadAttr): return p_map = {} for i in range(len(AllPortList)): p_map[ioPadAttr[i]] = AllPortList[i] return p_map def writeTestBench(input_file): """ write testbench to file """ with open(input_file, 'rb') as f: f_info = chardet.detect(f.read()) f_encoding = f_info['encoding'] with open(input_file, encoding=f_encoding) as inFile: inText = inFile.read() # removed comment,task,function inText = delComment(inText) inText = delBlock(inText) # moduel ... endmodule # moPos_begin = re.search(r'(\b|^)module\b', inText).end() moPos_end = re.search(r'\bendmodule\b', inText).start() inText = inText[moPos_begin:moPos_end] name = findName(inText) paraList = paraDeclare(inText, 'parameter') paraDec, paraDef = formatPara(paraList) ioPadAttr = ['input', 'output', 'inout'] orlder = portT(inText, ioPadAttr) input = portDeclare(inText, ioPadAttr[0]) output = portDeclare(inText, ioPadAttr[1]) inout = portDeclare(inText, ioPadAttr[2]) portList = formatPort(formatPort_order( getPortMap([input, output, inout], ioPadAttr), orlder)) input = formatDeclare(input, 'reg') output = formatDeclare(output, 'wire') inout = formatDeclare(inout, 'wire') # write Instance # module_parameter_port_list if(paraDec != ''): print("// %s Parameters\n%s\n" % (name, paraDec)) # list_of_port_declarations #print("// %s Inputs\n%s\n" % (name, input)) #print("// %s Outputs\n%s\n" % (name, output)) #if(inout != ''): # print("// %s Bidirs\n%s\n" % (name, inout)) print("\n") # UUT print("%s %s inst_%s (\n%s\n);" % (name, paraDef, name, portList)) if __name__ == '__main__': writeTestBench(sys.argv[1]) (5)享受一下吧。比如我们有如下代码:crtl+p,输入instance,按回车即可。 复制粘贴大发好。以上。转载于:https://www.cnblogs.com/kingstacker/p/9944259.html
2025年12月31日
3 阅读
0 评论
0 点赞
2025-06-06
SystemVerilog和SystemC协同验证环境介绍(1)
先说结论:使用有公开源代码的uvmc,可以在不同仿真工具之间自由切换,vcs 也有自己的库但是只能在vcs 中使用,不能在xrun 和 子门子的EDA 仿真工具中使用。下图是一个典型的sv和sc协同验证环境的testbench。systemverilog大家都比较熟悉了,UVM就是基于sv创建的一个验证方法学的库。但是systemc用的就比较少。一般情况下,systemc用于:事务级别建模和验证HW / SW协同设计SOC架构分析和优化sv和sc协同验证环境,主要应用于:使用SystemC TL模型作为SystemVerilog测试平台中的参考模型(可重用)通过常用的SV测试平台确保RTL和SystemC TL模型的一致性SC和SV具有互操作性SC模块可以实例化SV,反之亦然具有混合语言组件的单模块层次结构SC和SV调度程序需要统一的语义混合语言系统应该像使用单一语言一样工作 引脚级:SC信号可以绑定到SV端口,反之亦然支持标准转化集使用简单,但很少能匹配设计流程要求TL:SC调用SV任务/函数,SV调用SC方法符合大多数设计流程要求更高的仿真和建模效率那么怎么将SV和SC两种不同的语言连接起来呢?大家都知道dpi可以作为c和sv之间互相访问的桥梁,那么它作为SV和SC之间的桥梁够用吗?当然不够。DPI只能调用非阻塞方法/任务/函数,但是不能调用耗时的任务/方法。仅指定C接口,而不能指定C ++,而不能指定SystemCDPI不能用于遍历SystemC层次结构,处理实例或对象不容易实现DPI构建为与单线程非时序的C程序的接口Mentor也开源了UVM Connect的库。UVM Connect是一个基于开源UVM的库,提供TLM1和TLM2连接以及SystemC和SystemVerilog UVM模型和组件之间的对象传递。它还提供了一个UVM Command API,用于从SystemC(或C或C ++)访问和控制UVM仿真。 UVM Connect允许您在UVM验证中重用SystemC架构模型作为参考模型和/或重用SystemVerilog UVM代理来验证SystemC中的模型。它还有效地扩展了您的VIP产品组合,因为您现在可以使用两种语言访问VIP。通过UVM Connect,您可以轻松开发集成的验证环境,从而充分利用每种语言的优势,最大限度地提高验证效率。UVM版本2.3增加了新的“快速打包程序”功能,可在通过TLM2连接传递通用有效负载时提高性能。它们还增加了对无限数据有效负载的支持以及对配置扩展的有限支持。附录:SV和SC语言之间的数据类型映射原文链接:https://blog.csdn.net/zhajio/article/details/81780576
2025年06月06日
6 阅读
0 评论
0 点赞
2025-06-03
sv中的功能覆盖率常用用法
下面是ieee文档自我提取的一些用法,这一篇的用法,更加全面:covergroup常用用法;covergroup cg_0; cp_name coverpoint signal_name{ bins bin_name0 = {[0:63],65};//两个bin, [0:63],65, 只要有里面的值收到了,就全覆盖 bins bin_name1[] = { [127:150],[148:191] }; // 65个bin,即[]中的每一个值都是一个bin; bins bin_name2 = { [1000:$] };//$表示结尾,即最大值; bins bin_name3[] = default;//其他的所有值,都划分到other, 也是要全部都收到; } endgroupbins with的用法; cp_name: coverpoint signal_name{ bins bin_name[] = {[0:255]} with (item % 3 == 0);//0-255中3的余数为0的部分,构成bin; } 也可以将with的内容封装成function; coverpoint b { bins func[] = b with (myfunc(item)); }wildcard; wildcard bins g12_15 = { 4'b11?? };//只要在1100~1111间的任何一个踩到了,就收到了; wildcard bins g12_15_array[] = { 4'b11?? };//加了[], 会给每一个符合条件的都产生一个binignore_bins; 当没有明确定义某一个coverpoint的bins时,EDA仿真工具会生成和收集所有可能的bins,当其中某些bins在RTL中永远都不可能覆盖到,可以使用ignore_bins进行忽略covergroup cg23; coverpoint a { ignore_bins ignore_vals = {7,8};//不收集7,8; ignore_bins ignore_trans = (1=>3=>5);//不收集1,3,5这个序列; } endgroupillegal_bins; 某个值不可能收到,收到后报错;起到类似checker的作用;covergroup cg3; coverpoint b { illegal_bins bad_vals = {1,2,3}; illegal_bins bad_trans = (4=>5=>6); } endgroupcross;bit [31:0] a_var; bit [3:0] b_var; covergroup cov3 @(posedge clk); A: coverpoint a_var { bins yy[] = { [0:9] }; } CC: cross b_var, A;//两个coverpoint进行cross; endgroupcross中指定bins;int i,j; covergroup ct; coverpoint i { bins i[] = { [0:1] }; } coverpoint j { bins j[] = { [0:1] }; } x1: cross i,j; x2: cross i,j { ignore_bins i_zero = binsof(i) intersect { 0 };//i中不包含0; //binsof(x) intersect (y);//x的取值中,只收取为y的值; } endgroupbinsof 与 && / ||的组合;covergroup address_cov () @ (posedge ce); ADDRESS : coverpoint addr { bins addr0 = {0}; bins addr1 = {1}; } CMD : coverpoint cmd { bins READ = {0}; bins WRITE = {1}; bins IDLE = {2}; } CRS_USER_ADDR_CMD : cross ADDRESS, CMD { bins USER_ADDR0_READ = binsof(CMD) intersect {0};//默认的bins本来应该是2*3=6个,但是这里只定义了两个bins <addr0,READ> <addr1,READ> bins u2 = binsof(ADDRESS.addr0) || binsof(CMD.READ);// bins 数目为4,包括<addr0,READ>,<addr0,WRITE>,<addr0,IDLE>,<addr1,READ> bins u3 = binsof(ADDRESS.addr0) && binsof(CMD.READ);// bins 数目为1,包括<addr0,READ> } CRS_AUTO_ADDR_CMD : cross ADDRESS, CMD { ignore_bins AUTO_ADDR_READ = binsof(CMD) intersect {0}; ignore_bins AUTO_ADDR_WRITE = binsof(CMD) intersect {1} && binsof(ADDRESS) intersect{0}; }(原文链接:https://blog.csdn.net/bleauchat/article/details/90445713)matches; 感觉上像是一个下线; bins apple = X with (a+b < 257) matches 127;// 127~257? 带参数的covergroup;module mod_m; logic [31:0] a, b; covergroup cg(int cg_lim); coverpoint a; coverpoint b; aXb : cross a, b { function CrossQueueType myFunc1(int f_lim); for (int i = 0; i < f_lim; ++i) myFunc1.push_back('{i,i}); endfunction bins one = myFunc1(cg_lim); bins two = myFunc2(cg_lim); function CrossQueueType myFunc2(logic [31:0] f_lim); for (logic [31:0] i = 0; i < f_lim; ++i) myFunc2.push_back('{2*i,2*i}); endfunction } endgroup cg cg_inst = new(3);//每一个例化的时候再指定参数; endmodule结果如下:cg_inst.aXb.one = <0.0> , <1.1>,<2.2>cg_inst.aXb.two = <0.0>,<2.2>,<4.4>,instance;每个覆盖率例化的时候,是所有的合在一起收集,还是每个例化的地方,单独收集对应的覆盖率; 每个覆盖率单独例化的时候,可以指定最终呈现的名字;covergroup g1 (int w, string instComment) @(posedge clk) ; // track coverage information for each instance of g1 in addition // to the cumulative coverage information for covergroup type g1 option.per_instance = 1; // comment for each instance of this covergroup option.comment = instComment;一些基本的选项,通常不使用; //auto_bin_max, cross_auto_bin_max, goal, weight等等; //参考如下:(221条消息) [SV]SystemVerilog Coverage Options用法總結及案例_元直数字电路验证的博客-CSDN博客_coveragegroup option也可以参考table 19-2;设置采样时刻;一般来讲,是不指定采样时刻,然后再rm中比对通过后,手动sample, 可以保证采集数据的合理性和正确性;也可以指定拍拍采集;covergroup g1 (int w, string instComment) @(posedge clk) ;数据边界描述;[ $ : value ] => The set of values less than or equal to value[ value : $ ] => The set of values greater or equal to value————————————————版权声明:本文为CSDN博主「newyork major」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/zhangshangjie1/article/details/129121286
2025年06月03日
29 阅读
0 评论
0 点赞
2025-05-27
SV中inout与ref区别
一、Inout是什么?inout百度翻译为“双向,双向总线”,顾名思义就是该类型端口既能做输入又能做输出。很多需要交互的芯片外部的有些管脚都会使用inout类型,尤其是需要与外界做双向通信的数据总线与地址总线。在需要用到inout类型搭建仿真验证平台时,需要注意以下两个方面:1.在例化端口时,需将顶层的inout型的信号必须变为wire型;2.在编写assign语句时,其必须放在initial或always块外部。想对inout型的信号进行读写操作时需使用assign语句,具体代码如下:module TB(); wire data_inout; reg data_reg; reg db_link; initial begin .......... end assign data_inout = db_link ? data_reg : 1'hz; endmodule二、Ref是什么?Ref为Reference的缩写,百度翻译为“参考,引用”。通过查阅资料,ref类型会使参数按照引用传递。下面为本人在验证工作时碰到的一个例子:设计(DUT)源程序部分代码:module DUT; endmodule验证环境 (Test_Bench—cpu_mod) 部分代码:`timescale 1ns/1ps module cpu_mod; parameter cpu_period = 33.33; parameter cpu_period*2 = 66.67; parameter cpu_period*9 = 299.97; initial begin write_flag = 0; end task automatic cpu_write (input [15:0] addr , input [15:0] data , ref logic cs); dut.if.ebi_rd_wr = 1'b1; cs = 1 ; #cpu_period; dut.if.ebi_addr = addr ; dut.if.ebi_rd_wr = 1'b0 ; dut.if.ebi_ts = 1'b0 ; cs = 0 ; #cpu_period*2; dut.if.ebi_ts = 1'b1 ; write_flag = 1 ; cpu_wdata = data ; dut.if.ebi_we_be0 = 1'b0 ; dut.if.ebi_we_be1 = 1'b0 ; #cpu_period*9; dut.if.ebi_rd_wr = 1'b1 ; dut.if.ebi_we_be0 = 1'b1 ; dut.if.ebi_we_be1 = 1'b1 ; #cpu_period; write_flag = 0 ; dut.if.ebi_addr = 16'hz ; cpu_wdata = 16'h0 ; cs = 1 ; endtask endmodule测试用例 (Test_Case) 部分代码:`timescale 1ns/1ps module testcase(interface dut_if); bit [15:0] cpu_addr1 = 16'h1803; bit [15:0] cpu_data1 = 16'h1234; initial begin #150ms; cpu_mod.cpu_write (cpu_addr1,cpu_data1,dut_if.ebi_cs3); end endmodule 1)代码结构的思路待更新2)代码结构的说明待更新三、两者区别是什么?当task和function的形式参数被声明为input类型时,input类型的形参只是进行了数值的拷贝;而当task和function的形式参数被声明为output类型时,output类型的形参会在return时刻将数值拷贝至接收方。这就不难得出 inout 类型不仅会在输入时进行数值的拷贝,而且会在输出时将数值拷贝至接收方。Ref 类型的形参,我们做的不是拷贝,而是 引用 。对于task来讲,ref类型的参数,其外部是可见的,换句话说在外部对ref的形参数值进行的修改,task是可见且同步变化的;而inout类型的参数,task得到的仅仅是一个拷贝过来的数值,在整个task运行期间,外部的数值无论发生什么变化,对于task而言是未知的,同理task对该数值在其内部进行的修改,只有task运行结束后,外部才会获得该值。四、两者联系/区别总结Inout 与 Ref 均可以在task与function中传入传出数据;Inout 在外部传递的参数改变时,其调用的task或function无法实时更新,只有当调用的task或function执行完毕后才会发生变化;Ref 在外部传递的参数改变时,其调用的task或function能够实时更新数值;Ref 操作不需要消耗仿真时间,而 Inout 则需要消耗仿真时间。————————————————版权声明:本文为CSDN博主「进击的砰砰砰」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/weixin_42493102/article/details/122311686
2025年05月27日
0 阅读
0 评论
0 点赞