【FPGA/verilog -入门学习11】verilogTestbench中的文本文件写入,读出,打印等操作

news2024/10/5 19:09:12

本文参考:Verilog中的系统任务(显示/打印类)--$display, $write,$strobe,$monitor-CSDN博客

Verilog:parameter、localparam的区别和用法-CSDN博客

Verilog的系统任务----$fopen、$fclose和$fdisplay, $fwrite,$fstrobe,$fmonitor_verilog fopen-CSDN博客

Verilog的系统任务----$readmemh和$readmemb-CSDN博客

1,$display

$display可以直接打印一条文本信息,并在每一次$display执行后会自动换行,比如:

`timescale 1ns/1ns
module test_tb();
 
initial begin
    $display("China NO1!");
    $display("USA NO2!");
end

2,$write

$write的用法与$display一致,区别在于,一条$write语句执行完后,不会自动换行。比如下面的代码:

 
`timescale 1ns/1ns
module test_tb();
 
initial begin
    $write("China NO1!");
    $write("USA NO2!");
end

这两个系统函数除了直接打印文本外,也可以打印变量的值,其格式为(以$display为例):

$display("%b %b",a,b) ;

3,$strobe

$strobe 为选通显示任务。$strobe 使用方法与 $display 一致,但打印信息的时间和 $display 有所差异(也可以直接打印文本)。

当许多语句与 $display 任务在同一时间内执行时,这些语句和 $display 的执行顺序是不确定的,一般按照程序的顺序结构执行。

两者的区别在于:$strobe命令会在当前时间部结束时完成;

而$display是只要仿真器看到就会立即执行。

$strobe 是在其他语句执行完毕之后,才执行显示任务。例如:

 `timescale 1ns/1ns
module test_tb();
 
reg [3:0]  a ;
initial begin
    $strobe("begin!");
    a = 1 ;
    #1 ;
    a <= a + 1 ;
    //第一次显示
    $display("$display excuting result: %d.", a);
    $strobe("$strobe excuting result: %d.", a);
    #1 ;
    $display();
    //第二次显示
    $display("$display excuting result: %d.", a);
    $strobe("$strobe excuting result: %d.", a);
    $strobe("end!");
end
endmodule 

总结:$display() 和他前面一条语句同时执行,没有延时,

而 $strobe 会等待上一条指令执行完成后输出

可以看到,$strobe与$display的打印内容不是一致的。

这是因为该语句: a <= a + 1 ;也就是说a的第二次赋值是非阻塞赋值,而非阻塞赋值是需要时间的。

在第一次打印时,$display不会管你a是阻塞赋值还是非阻塞赋值,它就直接打印a当前的值1。而$strobe则会等到非阻塞赋值完成后再打印,所以其打印的值为2。

在第二次打印时,又延时了1ns,所以此时的非阻塞赋值完成,那么$strobe与$display的打印内容就均为2了。

所以$strobe这个系统任务通常是用来打印当前非阻塞赋值的变量值的。

4,$monitor

$monitor 为监测任务,用于变量的持续监测。只要变量发生了变化,$monitor 就会打印显示出对应的信息。 其使用方法与 $display一致。

下面的代码用$monitor 来实现监控a,b,c这3个变量,只要其中一个发生了变化,就会立马在终端打印。


`timescale 1ns/1ns
 
module test_tb();
 
reg [1:0]  a ;
reg [1:0]  b ;
reg [1:0]  c ;
 
initial begin
    a = 0 ;
    b = 0 ;
    c = 0 ;
 
    $monitor("a=%d b=%d c=%d",a,b,c);
    #50 $finish;    //50ns后停止
end
 
always #10 begin        //每10ns,随机生成a,b,c
    a = {$random}%4;
    b = {$random}%4;
    c = {$random}%4;
end
 

终端打印结果如下:

5,$fopen

  • $fopen:打开指定文件
  • $fclose:关闭指定文件
integer        handle1;                                 //定义句柄1
handle1 = $fopen("file_name",type)       //以指定类型(type)的方式来打开文件,并将其返回值赋给handle

integer        handle1;                                                           //定义句柄1
handle1 = $fopen("D:/file_test/file_test1.txt","w");          //以w类型(写)的方式来打开文件,并将其返回值赋给handle1

6,$fdisplay, $fwrite,$fstrobe,$fmonitor

这4个函数都可以对指定文件进行打印或写入操作,其用法与对应的$display, $write,$strobe,$monitor几乎一致。建议参考以上用法

区别在于$display等函数是直接在仿真中进行打印,而$fdisplay等函数是对指定文件进行打印,需要通过句柄来指定是对具体哪个文件进行操作。如:

        reg                data;

        integer        handle1;                                                         //定义句柄1

        handle1 = $fopen("D:/file_test/file_test1.txt","w");       //以w类型(写)的方式来打开文件,并将其返回值赋给handle1

//对指定文件写入数据

        $fdisplay(handle1,"%d\n",data);                                    //按照十进制格式写入数据到handle1对应的文件中,只能逐个写入

7,$fclose

$fclose系统任务用来关闭指定文件,关闭后即无法对该文件进行操作。其格式如下:

$fclose(handle1);        //关闭文件file_test1,至此文件操作结束

8,$readmemh和$readmemb

$readmemh(h,hexadecimal,十六进制)用来读取16进制的数据

$readmemb(b,binary,二进制)则用来读取2进制的数据。

$readmemb("<数据文件名>",<数组名>)

$readmemb ("<数据文件名>",<数组名>,<起始地址>)

$readmemb ("<数据文件名>",<存贮器名>,<起始地址>,<结束地址>)

$readmemh("<数据文件名>",<数组名>)

$readmemh ("<数据文件名>",<数组名>,<起始地址>)

$readmemh ("<数据文件名>",<数组名>,<起始地址>,<结束地址>)

使用方法1:不指定起始地址和结束对应地址

$readmemh("<数据文件名>",<数组名>)


`timescale 1ns / 1ns
 
module tb_read_test();
 
integer i;     
reg [7:0] mem_test [9:0];        //mem_test是位宽8bit,个数为10的数组
 
initial $readmemh("D:/read_test/read_test.srcs/sim_1/new/data.txt",mem_test);    //绝对路径
 
//显示数组的10个值
initial begin
    for(i=0; i<10; i=i+1)
        $display("%d: %h", i, mem_test[i]);
end

仿真结果如下:

  1. 去除部分数据文件中的数据,导致数组无法被填满(注释掉后面4个数据):

仿真结果如下:

数据文件仅有6个数据,而数组个数为10,所以数组的后4个数据仍没有被赋值。

使用方法2:指定起始地址,但不指定结束地址

即$readmemh ("<数据文件名>",<数组名>,<起始地址>),此时会将从数据文件中读到的第1个数据填入数组的起始地址,此后类推,直到数组被填满。而之前被起始地址跳过的数组的数据则不会被赋值。如果数据的个数大于数据文件中数据的个数,则数组无法被填满,未被填满的部分则依然是未知状态。

指定数据从数组的地址2开始赋值,则地址2应该被赋值0,地址3被赋值1,···等等。而地址0和地址1则仍保持未赋值状态:

`timescale 1ns / 1ns
 
module tb_read_test();
 
integer i; 
reg [7:0] mem_test [9:0];//mem_test是位宽8bit,个数为10的数组
 
initial $readmemh("D:/read_test/read_test.srcs/sim_1/new/data.txt",mem_test,2);//绝对路径,从地址2开始
 
//显示数组的10个值
initial begin
for(i=0; i<10; i=i+1)
$display("%d: %h", i, mem_test[i]);
end
 
endmodule

仿真结果如下:

从地址2开始依次被赋值00~07,而地址0和地址1则仍保持未赋值状态。

使用方法3:同时指定起始地址和结束地址

即$readmemh ("<数据文件名>",<数组名>,<起始地址>,<结束地址>),此时会将从数据文件中读到的第1个数据填入数组的起始地址,此后类推,直到指定的终结地址对应的数组也被赋值。处于起始地址和终结地址构成的区间范围外的地址对应的数组则不会被赋值。如果数据的个数大于数据文件中数据的个数,则数组无法被填满,未被填满的部分则依然是未知状态。

指定数据从数组的地址2开始赋值,直到地址8终结,则地址2应该被赋值0,地址3被赋值1,···等等,直到地址8也被赋值。而地址0、1、9则仍保持未赋值状态:

`timescale 1ns / 1ns
 
module tb_read_test();
 
integer i; 
reg [7:0] mem_test [9:0];//mem_test是位宽8bit,个数为10的数组
 
initial $readmemh("D:/read_test/read_test.srcs/sim_1/new/data.txt",mem_test,2,8);//绝对路径,从地址2开始
 
//显示数组的10个值
initial begin
for(i=0; i<10; i=i+1)
$display("%d: %h", i, mem_test[i]);
end
 
endmodule

仿真结果如下:

从地址2开始直到地址8依次被赋值00~06,而地址0、1、9则仍保持未赋值状态。

9,parameter、localparam的区别和用法

一、区别

parameter: 可以在实例化时修改参数值

localparam:只能在当前模块使用,不能进行实例化

二、用法

2.1 设计文件中parameter的用法

直接在模块名后面 #(parameter 参数名=参数值)

2.2 例化模块时parameter的用法

在模块名后面直接 #(.参数名 (参数值))

实列操作

需求1:

雷码转换设计的仿真测试结果写入txt文本

使用绝对路径(注意绝对路径下的文件夹命名都要遵循verilog变量命名规范)

需求分析:

1,创建文件夹,创建文件

2,将内容写入文件

3,关闭文件

`timescale 1ns/1ps
module testbench_top();


//参数定义
 `define CLK_PERIORD 20    

 
//接口申明
reg i_clk;
reg i_rst_n;
reg i_en;
reg[9:0] i_data;
wire o_vld;    //有效信号
wire[15:0] o_data;

vlg_design vlg_design_inst (
    .i_clk(i_clk),
    .i_rst_n(i_rst_n),
    .i_en(i_en),
    .i_data(i_data),
    .o_vld(o_vld),
    .o_data(o_data) 
    );        
    
integer i;

initial  begin
i_en <= 0;
i_clk <= 0;
i_rst_n <= 0;
i_data <= 0;
#2000;
i_rst_n <= 1;
end

always #(`CLK_PERIORD/2) i_clk = ~i_clk;

//产生激励
initial begin
    @(posedge i_clk);
    @(posedge i_rst_n);    
    i_en <= 1;
    @(posedge i_clk);    
    for (i = 1;i <= 1024;i = i+1) begin
        i_data <= i;
        @(posedge i_clk);
    end
    @(posedge i_clk);
    i_en <= 0;
    #50_000;
    $fclose(handle1);  //关闭文件
    $stop;
end

//实时显示,并写入文件
always@(posedge i_clk) begin
    if(o_vld) begin
        $display("%d",o_data);
        $fdisplay(handle1,"%d",o_data);  //往handle1 句柄的文件中写入文件
    end
    else ; 
end
//创建file_test1.txt 文件
integer   handle1; //定义句柄1
initial begin
  //以w类型(写)的方式来打开文件,并将其返回值赋给handle1  
  //使用绝对路径(注意绝对路径下的文件夹命名都要遵循verilog变量命名规范)
  //注意绝对路径的文件夹要存在,文件可以新生成,即先手动新建outputfile 文件夹
  handle1 = $fopen("./outputfile/file_test1.txt","w");   
end

endmodule

需求2:

txt文本文件中8位格雷码数据的读取与使用

/
//EDA工具平台:Vivado 2019.1 + ModelSim SE-64 10.5 
//开发套件型号: STAR 入门FPGA开发套件
//版   权  申   明: 本例程由《深入浅出玩转FPGA》作者“特权同学”原创,
//                仅供特权同学相关FPGA开发套件学习使用,谢谢支持
//官方淘宝店铺: http://myfpga.taobao.com/
//微 信 公 众 号:“FPGA快乐学习”
//                欢迎关注,获取更多更新的FPGA学习资料 
/
`timescale 1ns/1ps

module testbench_top();
    

//参数定义

`define CLK_PERIORD        10        //时钟周期设置为10ns(100MHz)    
parameter GRAY_MSB    = 7;



//接口申明
    
reg clk;
reg rst_n;
reg i_en;
reg[GRAY_MSB:0] i_data;
wire o_vld;
wire[GRAY_MSB:0] o_gray;

    
//对被测试的设计进行例化
    
vlg_design    #(
    .MSB(GRAY_MSB)
)    
uut_vlg_design(
    .i_clk(clk),
    .i_rst_n(rst_n),
    .i_en(i_en),
    .i_data(i_data),
    .o_vld(o_vld),
    .o_gray(o_gray)
    );    
    

//复位和时钟产生

    //时钟和复位初始化、复位产生
initial begin
    clk <= 0;
    rst_n <= 0;
    #1000;
    rst_n <= 1;
end
    
    //时钟产生
always #(`CLK_PERIORD/2) clk = ~clk;


//文本文件的读取
reg[7:0] data_mem[255:0];

initial $readmemb("./input_file/8bit_grayencode.txt",data_mem);
    


//测试激励产生

initial begin
    i_en <= 'b0;
    i_data <= 'b0;
    $display("The value of GRAY_MSB is %0d",GRAY_MSB);
    @(posedge rst_n);    //等待复位完成
    
    @(posedge clk);
    i_en <= 'b1;
    i_data <= 'b0;    
    
    repeat(2**(GRAY_MSB+1)-1) begin
        @(posedge clk);
        i_en <= 'b1;
        i_data <= i_data+1;
    end
    @(posedge clk);
    i_en <= 'b0;
    #100;
    
    //$fclose(wfile);
    
    $stop;
end

/*integer wfile;

initial begin
    wfile = $fopen("./output_file/result_data.txt","w");
end*/

integer cnt;

always @(posedge clk) begin
    if(!rst_n) cnt <= 0;
    else if(o_vld) cnt <= cnt+1;
end

always @(posedge clk) begin
    if(o_vld) $display("%b\n%b\n\n",o_gray,data_mem[cnt]);
end
endmodule

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1317500.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SQL Server 远程连接服务器数据库

本文解决sql server的远程连接问题。需要开启防火墙&#xff0c;开启端口&#xff0c;并处理权限不足的报错: 【use 某数据库】The server principal "[server]" is not able to access the database "[database]" under the current security context. 【…

SCI一区级 | Matlab实现GWO-CNN-GRU-selfAttention多变量多步时间序列预测

SCI一区级 | Matlab实现GWO-CNN-GRU-selfAttention多变量多步时间序列预测 目录 SCI一区级 | Matlab实现GWO-CNN-GRU-selfAttention多变量多步时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.Matlab实现GWO-CNN-GRU-selfAttention灰狼算法优化卷积门控循环…

【接口技术】课堂word补充习题和讲解(乱序)

DAC & ADC 1&#xff1a;B 梯形电阻网络中的电阻是R和2R&#xff0c;只用了2种阻值 2&#xff1a;B LSBFSR/(2^n)5V / 2^10 5V / 1024 0.0048828125V 4.883mV 3&#xff1a;输入寄存器、DAC寄存器、D/A转换器 如下图所示 中断向量表&#xff0c;CSIP 多个元件互连的例题…

2023年12月5日,北京elastic Meetup 腾讯分享的搜索优化经验

1、减少长文本模糊匹配&#xff0c;降低 CPU 大量分词上的开销 长文本全文查询由于在查询时需要进行分词处理&#xff0c;因此在查询并发较大的情况下&#xff0c; cpu会先于IO被打满&#xff0c;从而出现大量的查询拒绝。 2、设置多副本提高并发和均衡单节点压力 Search查询请…

Linux访问MySQL数据库(包含实验案例)

1、访问MySQL数据库。 1.1、登录到MySQL服务器 经过安装后的初始化过程&#xff0c;MySQL数据库的默认管理员用户名为"root"&#xff0c;密码为空。 [rootyang ~]# mysql -u root //"-u"选项用于指定认证用户有密码的情况下&#xff0c;使用"-p&qu…

【OpenCV】 OpenCV 源码编译并实现 CUDA 加速 (Windows)

OpenCV 源码编译并实现 CUDA 加速 Windows 1. 环境准备1.1 软件环境1. 2 源码下载 2. CMake编译项目2.1 创建cmake项目2.2 设置编译配置2.3 解决异常2.3.1 文件下载异常2.3.2 解决CUDA版本异常 2.4 编译项目 3. Visual Studio 编译项目4. 项目测试5. 总结 OpenCV是一个基于Apac…

鸿蒙南向开发环境的搭建

在嵌入式开发中&#xff0c;很多开发者习惯于使用Windows进行代码的编辑&#xff0c;比如使用Windows的Visual StudioCode进行OpenHarmony代码的开发。但当前阶段&#xff0c;大部分的开发板源码还不支持在Windows环境下进行编译&#xff0c;如Hi3861、Hi3516系列开发板。因此&…

Hudi cleaning

核心概念 hudi提供了很多项数据服务来管理表中的数据&#xff0c;其中有一项服务称之为Cleaner&#xff08;数据清理服务&#xff09;。随着用户向表中写入的数据越多&#xff0c;对于每一次的更新&#xff0c;hudi都会产生一个版本的数据文件保存更新后的记录&#xff08;COP…

Javascript 嵌套函数 - 递归函数 - 内置函数详解

Javascript 嵌套函数 - 递归函数 - 内置函数详解 目录 Javascript 嵌套函数 - 递归函数 - 内置函数详解 一、嵌套函数 二、递归函数 三、内置函数 在了解了函数的定义和函数调用外&#xff0c;下面我们来介绍一下JavaScript中几种特殊的函数。 JavaScript特殊函数有3种&a…

工艺雕塑品牌网站搭建效果如何

工艺雕刻品往往受到不少人喜欢与较高的市场需求度&#xff0c;比如室内雕塑摆件、室外标志性雕刻品等&#xff0c;而对相关企业来说&#xff0c;品牌经营过程中也面临着一些难题&#xff1a; ① 品牌传播难 工艺雕刻品因为只有小部分人才会需要或采购&#xff0c;可能大部分民…

JAVA序列化(创建可复用的 Java 对象)

JAVA 序列化(创建可复用的 Java 对象) 保存(持久化)对象及其状态到内存或者磁盘 Java 平台允许我们在内存中创建可复用的 Java 对象&#xff0c;但一般情况下&#xff0c;只有当 JVM 处于运行时&#xff0c;这些对象才可能存在&#xff0c;即&#xff0c;这些对象的生命周期不…

暂退法(丢弃法)

在深度学习中&#xff0c;丢弃法&#xff08;Dropout&#xff09;是一种常用的正则化技术&#xff0c;旨在减少模型的过拟合现象&#xff0c;可能会比之前的权重衰减(Weight Decay)效果更好。通过在训练过程中随机丢弃一部分神经元&#xff0c;可以有效地减少神经网络中的参数依…

普冉(PUYA)单片机开发笔记(11): I2C通信-配置主从收发

概述 在上一篇《普冉&#xff08;PUYA&#xff09;单片机开发笔记(10): I2C通信-配置从机-CSDN博客》配置了 PY32F003 的 I2C 从机一侧&#xff0c;今天配置主机&#xff0c;并实现主-从机之间的报文收发。 为了完成这个实验&#xff0c;需要两块 PY32F003F18P 的开发板&…

001 Windows虚拟机

一、虚拟机安装Windows10 选自定义安装 升级是针对你电脑上有系统的情况下&#xff0c;你要升级&#xff1b;没有系统就选择自定义。 硬盘60G 直接单击下一步就是一个盘 如果你想对磁盘进行分区 分第一个区的时候它会去创建系统的保留分区和系统分区&#xff0c;然后还剩20…

Linux下C++程序瘦身

目录 一.前言二.如何瘦身三.如何读取调试信息文件四.其他 一.前言 我们知道&#xff0c;C程序如果带着调试信息的话会比较大&#xff0c;所以一般发布版本都会去掉调试信息&#xff0c;但是我们又希望如果程序崩溃了可以使用core转储文件进行调试&#xff0c;如果不带调试信息…

数据结构之----贪心算法

数据结构之----贪心算法 什么是贪心算法&#xff1f; 贪心算法是一种常见的解决优化问题的算法&#xff0c;其基本思想是在问题的每个决策阶段&#xff0c;都选择当前看起来最优的选择&#xff0c;即贪心地做出局部最优的决策&#xff0c;以期望获得全局最优解。 贪心算法简…

SpringBoot配置文件加载的优先级及自定义配置

Spring Boot使用一个非常特殊的PropertySource顺序&#xff0c;旨在允许合理的值重写&#xff0c;越靠前优先级越高。属性按以下顺序考虑&#xff1a; 开发者工具Devtools全局配置参数 在IDEA或Eclipse中&#xff0c;安装并启用Spring Boot Devtools插件。打开项目的Settings…

[Big Bird]论文解读:Big Bird: Transformers for Longer Sequences

文章目录 1 介绍2 模型架构3 结果 论文&#xff1a;Big Bird: Transformers for Longer Sequences 作者&#xff1a;Manzil Zaheer, Guru Guruganesh, Avinava Dubey, Joshua Ainslie, Chris Alberti, Santiago Ontanon, Philip Pham, Anirudh Ravula, Qifan Wang, Li Yang, Am…

【Java 并发】三大特性

在 Java 的高并发中&#xff0c;对于线程并发问题的分析通常可以通过 2 个主核心进行分析 JMM 抽象内存模型和 Happens-Before 规则三大特性: 原子性, 有序性和可见性 JMM 抽象内存模型和 Happens-Before 规则, 前面我们讨论过了。这里讨论一下三大特性。 1 原子性 定义: 一个…

HarmonyOS4.0从零开始的开发教程17给您的应用添加通知

HarmonyOS&#xff08;十五&#xff09;给您的应用添加通知 通知介绍 通知旨在让用户以合适的方式及时获得有用的新消息&#xff0c;帮助用户高效地处理任务。应用可以通过通知接口发送通知消息&#xff0c;用户可以通过通知栏查看通知内容&#xff0c;也可以点击通知来打开应…