编写和调试火葬场真是太酷了; 多么深刻地说明了调试在整个设计过程中的重要性,而仿真调试也是调试的重要组成部分。
为了巩固自己的写作技术,也为了和大家交流调试经验,写了这篇文章和大家分享。
为了调试和模拟一些数据处理模块,模块需要特定的数据输入,例如单频正弦波; 为了解决这个问题,我们可以使用诸如等工具生成文本数据,然后使用该数据读入; 您可以使用两种方法来操作文本数据
, , , 操作
, 等等
, , , 操作
从字面意思来看,就是读取数据,后缀b和h代表数据的基数; 同样,是将数据写入文件;
因此,在使用此类系统的内置函数时,首先必须有一个类型的变量。 定义方法如下:
reg [M-1:0] mem [N:1];
mem“变量”(应该称为寄存器组)有N个“一维”变量,每个“一维”变量的位宽为M; 你可以将mem理解为C语言中的一个二维数组,其中包含NA个一维数组,每个一维数组有M个元素,元素是位。
事实上,我们称M为mem的数据宽度,N为mem的数据深度。
以数据读取操作为例
initial
begin
$readmemb("data.txt", mem);
end
第一个参数是文件名,第二个参数是变量名; 至此,data.txt中的N行数据就存储在mem中了。 操作类似,不同的是data.txt中的数据要求是16进制。
那么有人可能会有疑问,如果有以下问题,mem中存储的数据会是什么样的:
图1 数据位宽小于M波形
图2 数据位宽小于M存储
图3 数据位宽大于M
图4 数据位宽大于M,VCS警告
经测试,如果M大于数据位宽,则可以正常读取数据,高位补0; 如果小于数据位宽,则无法正常读取数据。
与M小于数据位宽的情况一致,无法正常读取数据。
图5 行数小于N
图6 行数大于N
经测试,如果行数大于N,模拟器会发出警告,但可以正常读取数据。 当它小于N时,多余部分的值是不确定的。
数据已存储在mem中,但尚未进入模块的输入。 接下来的操作可以参考下面的代码:
reg [M-1:0] data_in;
integer index = 1;
initial
begin
forever
begin
@(posegde clk);
data_in = mem[index];
index = (index >= N) ? 1 : index + 1;
end
end
代码中,等待clk的上升沿,然后将mem的索引元素赋值给 ,然后完成索引加1的操作; 整个过程不断循环; 这里设置索引计数到N返回1的计数保护,防止无效数据出现。
然后连接到被测模块的数据输入口,数据就会发送进来。
图7 发送的数据波形
操作并依次将mem的数据存储为文本如下:
initial
begin
$writememb("new_data_b.txt", mem);
$writememh("new_data_h.txt", mem);
end
储存后
图片
图片
, 等等
语法本身与C类似,也具有文本操作功能,也与C类似。要使用文本操作,首先需要执行以下操作:
integer fid;
initial
begin
fid = $fopen("data.txt", "r");
//fid = $fopen("data.txt", "w"); //write
if (!fid)
$display("file open error");
end
像C语言中的fopen,第一个参数是文件名,第二个参数是操作模式,包括读(r,rb)、写(w,wb)等操作; 根据返回值判断文件操作是否有错误。
然后根据文本文件的数据格式,进行数据读取操作。
reg [M-1:0] data_in;
always @ (posedge clk)
$fscanf(fid, "%d %d %d", data_in, mem[0], mem[1]);
用法和C语言类似,第一个参数是文件句柄,第二个参数是格式参数,第三个是数据存储变量,但是不需要加&。 读取文件时,第二个参数和第三个参数需要对应,否则读取的数据可能错误。 (个人经验)
数据存储操作如下,之前fopen中使用w模式:
always @ (posegde clk)
$fwrite(fid, "%d, %d, %d\n", $signed(data_in), $signed(data_in)+1, $signed(data_in)+2);
数据可以按照第二个参数的格式存储在文本文件中。 还有一系列比如,相对来说,它的文件写入数据后会自动转到下一行,所以第二个参数不需要加“\n”; ftell 等功能。
注意,如果要以十进制存储负数,除了第二个参数使用%d外,第三个参数的寄存器变量也必须使用$转换为有符号数
图10 正常情况下读取文本操作后存储的数据
图11 当寄存器位宽小于数据位宽时,读取文本操作后存储的数据
注意,当存储的寄存器位宽小于数据位宽时,数据会自动截断,保留高位。
当我使用文件操作来存储被测模块的输出时,每个文件中的数据量(行)与理想数量不匹配。 经过查找各种原因,最后发现是我犯了低级错误,没有使用close。 文件句柄。
initial
begin
#1000;
$fclose(fid);
$finish;
end
在停止仿真之前,一定要关闭文件句柄,否则数据访问会出现不可预知的问题。
欢迎使用本文中使用的实验。 注意,使用下面的实验时,文件名必须是绝对路径; 在tb中,使用“”宏定义来判断操作还是文件操作,可以尝试修改宏定义的值来改变文件操作的函数类型;本文使用的资源可以从官方获取账号回复116;
两种方法的差异比较
,该方法只能访问二进制或十六进制数据,数据格式固定,不支持读取其他格式的多维数据,文件操作不灵活; 文本操作方便其他工具,比如处理数据
它是可综合语句,因此可以用来给模块中的变量赋值,但其他语句不是可综合语句,只能用于模拟测试
文件操作虽然支持各种格式的文本访问,但操作简单、简单; 如果需要回收数据,读取后可以通过重置索引来回收数据,而文本操作比较麻烦。
另外想问一下大家学习UVM有没有更好的学习资源或者学习方法。