Verilog十大基本功2(testbench的设计文件读取和写入操作源代码)
Verilog设计练习十例及答案

设计练习进阶前言:在前面九章学习的基础上,通过本章的练习,一定能逐步掌握Verilog HDL设计的要点。
我们可以先理解样板模块中每一条语句的作用,然后对样板模块进行综合前和综合后仿真,再独立完成每一阶段规定的练习。
当十个阶段的练习做完后,便可以开始设计一些简单的逻辑电路和系统。
很快我们就能过渡到设计相当复杂的数字逻辑系统。
当然,复杂的数字逻辑系统的设计和验证,不但需要系统结构的知识和经验的积累,还需要了解更多的语法现象和掌握高级的Verilog HDL系统任务,以及与C语言模块接口的方法(即PLI),这些已超出的本书的范围。
有兴趣的同学可以阅读Verilog语法参考资料和有关文献,自己学习,我们将在下一本书中介绍Verilog较高级的用法。
练习一.简单的组合逻辑设计目的: 掌握基本组合逻辑电路的实现方法。
这是一个可综合的数据比较器,很容易看出它的功能是比较数据a与数据b,如果两个数据相同,则给出结果1,否则给出结果0。
在Verilog HDL中,描述组合逻辑时常使用assign 结构。
注意equal=(a==b)1:0,这是一种在组合逻辑实现分支判断时常使用的格式。
模块源代码:" qual(equal),.a(a),.b(b)); 简单时序逻辑电路的设计目的:掌握基本时序逻辑电路的实现。
在Verilog HDL中,相对于组合逻辑电路,时序逻辑电路也有规定的表述方式。
在可综合的Verilog HDL模型,我们通常使用always块和@(posedge clk)或@(negedge clk)的结构来表述时序逻辑。
下面是一个1/2分频器的可综合模型。
eset(reset),.clk_in(clk),.clk_out(clk_out));endmodule仿真波形:练习:依然作clk_in的二分频clk_out,要求输出与上例的输出正好反相。
编写测试模块,给出仿真波形。
练习三. 利用条件语句实现较复杂的时序逻辑电路目的:掌握条件语句在Verilog HDL中的使用。
systemverilogfortestbench

SystemVerilog for Testbench1、并发性和控制(Concurrency and Control)并发(Concurrency)可以允许你从一个父进程中同时运行多个并行的进程。
它给你的需要执行并行的验证环境带来更多的主动性和灵活性。
一个典型的例子是,给设计加激励,之后检查并行的结果。
这使你的tb能及时果断地作出反应,以便修改激励(甚至在模拟完也可)。
用fork-join结构来实现并发(Concurrency)。
父进程的join-back依赖于并行进程是否完成。
Mailbox:对于进程内部的通信,一种叫做mailbox的结构允许任何进程将消息发送到其他的任何进程。
接受的进程也能够使用wait命令和发送的进程来同步。
Semaphores:信号量(semaphores)是为了防止一个资源被许多个并行的进程争抢的情况。
比如在一个信号在任何时刻只能有一个进程执行它。
Events:进程中的事件(events)用 -> 操作符来触发。
这些被触发的事件被其他的进程用事件控制结构来接受,为的是使得触发进程同步。
2、带约束的随机激励(Random Stimulus Generation with Constraints)验证的过程是要证明你的设计是全面测试过的。
随机激励确保测试角落情形的到达和测试。
这是一个重要的组成部分,以确保验证的时间和精力是最有效的方式进行的。
SystemVerilog提供一个非常强有力的机制来产生随机刺激。
它是基于类的对象(class-object)随机化,这意味着一个类的对象随机变量自动通过调用预定义的随机方法与对象相关联。
约束(Constraints)进一步增强随机化的功能。
他们有两个主要优点:(1)您可以添加任意权重的刺激,使某些激励信号比其他的信号更频繁地产生,也就是你可以设置一个激励产生的分布函数,(2)您可以使用现有的设计来改变这种状态权重,从而为下一个状态做限制。
verilog testbench语法

verilog testbench语法Verilog testbench 是用来对 Verilog 设计进行仿真验证的代码。
它提供了一系列的输入信号和时钟,以及对输出结果的预期值进行比较,以验证设计的正确性。
以下是 Verilog testbench 的基本语法:1. 模块定义:```module testbench_name;// 输入输出信号声明// 实例化需要测试的模块// 给输入信号赋值// 检查输出信号和预期结果是否相符endmodule```2. 时钟定义:```reg clk; // 定义时钟信号always #5 clk = ~clk; // 定义时钟周期```3. 输入信号声明和赋值:```reg input1;wire expected_output;reg [3:0] array_input [7:0];// 给输入信号赋值initial begininput1 = 1'b0;#10;input1 = 1'b1;#10;//...end```4. 实例化需要测试的模块:```// 通过实例化需要测试的模块// 给模块的输入端口连接输入信号// 给模块的输出端口连接输出信号// 在 testbench 中实例化被测试的模块//...```5. 检查输出信号和预期结果:```// 在仿真过程中,通过比较输出信号和预期结果来验证设计的正确性// 根据需要使用相应的比较语句,如 `==`, `!=`, `===`, `!==`, `>`, `<` 等// 在每个时钟周期末检查预期输出结果//...```这些是 Verilog testbench 的基本语法。
在具体的测试中,需要根据设计的功能和需求来给输入信号赋值,并检查输出信号和预期结果是否一致。
verilog 文件操作函数

在Verilog中,文件操作函数主要用于读取和写入文件。
这些函数使得Verilog能够与外部文件进行交互,例如读取初始化文件、写入仿真输出等。
以下是一些常用的Verilog文件操作函数:1. **$fopen(file, mode):**- 打开文件,返回一个文件句柄。
- `file` 是文件名,`mode` 是文件打开模式("r"表示只读,"w"表示只写,"a"表示追加,等等)。
```verilogreg [7:0] file_handle;initial beginfile_handle = $fopen("example.txt", "w");// 在这里执行文件操作$fclose(file_handle);end```2. **$fclose(file):**- 关闭之前打开的文件。
- `file` 是文件句柄。
3. **$fwrite(file, format, ...):**- 格式化写入文件。
- `file` 是文件句柄,`format` 是格式字符串,`...` 是要写入文件的数据。
```verilogreg [7:0] file_handle;initial beginfile_handle = $fopen("output.txt", "w");$fwrite(file_handle, "Data: %0d, %b", 10, 4'b1010);$fclose(file_handle);end```4. **$fdisplay(file, format, ...):**- 类似于`$fwrite`,但输出到仿真控制台而不是文件。
5. **$fscanf(file, format, ...):**- 格式化读取文件。
Verilog测试模块的编写

reg clk; initial
begin clk=0; #(period)
forever #(period/2) clk=!clk end
reg go; wire clk; nand #(period/2) ul (clk,clk,go); initial begin
go=0; #(period) go=1; end
语法详细讲解
存储建模
目标 学会如何用Verilog对存储器建模。 学会如何用Verilog中对双向(即输入/输出)端口, (inout)建模。
语法详细讲解ቤተ መጻሕፍቲ ባይዱ
存储器建模
存储器建模必须注意以下两个方面的问题: ▪ 声明存储器容量的大小。 ▪ 明确对存储器访问操作的权限。
例如:指出可以对存储器做以下哪几种操作: 1)只读 2)读写 3)同步读写 4)多次读,同时进行一次写 5)多次同步读写,同时提供一些方法保证一致性
inout [3:0] data; inout [3:0] addr; input read, write; reg [3:0] memory [0:15]; //4 bits, 16 个单元
//从存储器读出到总线上
assign data=read? memory[addr]:4’bz;
//从总线写入存储器
注:这两个时钟模型有些不同,行为描述的模型延迟期间一直是低电平, 而门级描述的模型开始延迟有半个周期是不确定的。
语法详细讲解
怎样使用任务
举例说明如何使用任务:
module bus_ctrl_tb; reg [7:0] data; reg data_valid, data_rd; cpu ul(data_valid,data,data_rd); initial begin cpu_driver (8’b0000_0000); cpu_driver (8’b1010_1010); cpu_driver (8’b0101_0101); end
system verilog read file

System Verilog 是一种硬件设计语言,它提供了丰富的特性来描述硬件行为和结构。
在 System Verilog 中,可以使用文件 I/O 操作来读取外部文件并将其内容加载到仿真环境中。
1. System Verilog 中的文件 I/O在 System Verilog 中,可以使用 $fopen、$fclose、$fscanf 等内置函数来进行文件 I/O 操作。
其中,$fopen 用于打开一个文件,$fclose 用于关闭一个文件,$fscanf 用于从文件中读取数据。
2. 读取文件的基本步骤要在 System Verilog 中读取文件,通常需要经过以下几个基本步骤:(1) 使用 $fopen 打开一个文件,并将返回的文件句柄保存到一个变量中。
(2) 使用 $fscanf 从文件中读取数据,并将读取的数据保存到变量中。
(3) 使用 $fclose 关闭文件。
3. 读取文件的示例代码下面是一个使用 System Verilog 读取文件的简单示例代码:```verilogmodule read_file;initial begin// 打开文件int file_h;file_h = $fopen("input.txt", "r");// 读取数据int data;$fscanf(file_h, "d", data);// 关闭文件$fclose(file_h);endendmodule```在这个示例中,首先使用 $fopen 打开一个名为 "input.txt" 的文件,并将返回的文件句柄保存到变量 file_h 中。
然后使用 $fscanf 从文件中读取一个整数,并将读取的整数保存到变量 data 中。
最后使用$fclose 关闭文件。
4. 读取文件的注意事项在使用 System Verilog 读取文件时,有一些需要注意的事项:(1) 需要确保所读取的文件存在,否则 $fopen 会返回一个无效的文件句柄。
(完整版)实例解读Testbench编写方法

实例解读Testbench编写方法前言:在进行quartusII设计时,不少人刚开始觉得仿真极其不方便,还需要编写测试文件,浪费时间精力。
不过小编想告诉大家,其实testbench编写很容易学,不外乎wait for 语句的堆叠就可以了,至于高深的用法,对一般程序都涉及不到,没必要弄得那么复杂。
下面看看实例吧,将详细说明testbench的编写:我们可以通过Quartus自动生成一个Testbench的模板,选择Processing —〉 Start -〉Start Test Bench Template Writer,等待完成后打开刚才生成的Testbench,默认是保存在sim ulation\modelsim文件夹下的.vt格式文件.打开vt文件后可以看到Quartus已经为我们完成了一些基本工作,包括端口部分的代码和接口变量的声明,我们要做的就是在这个做好的模具里添加我们需要的测试代码.一个最基本的Testbench包含三个部分,信号定义、模块接口和功能代码.‘timescale 1ns/ 1ps表示仿真的单位时间为1ns,精度为1ps.想要进行仿真首先要规定时间单位,而且最好在Testbench里面统一规定时间单位,而不要在工程代码里定义,因为不同的模块如果时间单位不同可能会为仿真带来一些问题,而timescale本身对综合也就是实际电路没有影响。
其实Testbench本身可以看做一个模块或者设备(本例中的模块名为add_vlg_tst),和你自己编写的模块进行通信。
通过Testbench模块向待测模块输出信号作为激励,同时接收从待测模块输出的信号来查看结果.因此,在待测模块中的reg型信号在Testbench中就变成了wire,待测模块中的wire型信号在Testb ench中则对应为reg型。
那么inout怎么办呢,inout型信号也要设成wire,同时要用一个reg型信号作为输出寄存器,同时设置一个三态门,由一个使能信号控制,如:assign inout_sig = out_en ? out_reg : 1’bz;处理完接口和声明之后,需要自己设置一些激励信号,激励信号的内容就是肯能会输入到待测模块中的波形.下面我们就来写一个简单的测试程序.实例:60进制计数器源代码:library ieee;use ieee.std_logic_1164。
verilog代码

Testbench编写的三步骤:1、对被测试的设计的丁岑接口进行例化。
2、给被测试的设计的输入输出添加激励。
3、判断被测试的设计的输出响应是否满足设计要求。
简单的Testbench包括:时钟产生、复位产生、其他的激励产生,和对比输出观察;1.最简单的TESTBENCH第一种时钟产生方式://时钟产生//定义时周期是20ns,已定义timescale 1ns /1ps注意这里的1s=10^9ns = 10^12ps Parameter PERIOD = 20;Initial beginClk = 0;Forever //永远执行#(PERIOD/2)clk = ~clk; //每10ns实现时钟的翻转,20ns就是一个时钟周期end第二种时钟产生方式://时钟产生//定义时周期是20ns,已定义timescale 1ns /1ps注意这里的1s=10^9ns = 10^12ps Parameter PERIOD = 20;Always begin //脚本一运行就进入always的无限循环中#(PERIOD/2)clk = 0;#(PERIOD/2)clk = 1;end//简单的复位脚本Initial begin//复位低电平有效,已定义“timescale 1ns / 1ps”Rst_n = 0;#100; //100ns延时Rst_n = 1;// 撤销复位.......End//可重用的复位脚本//复位产生Initial beginReset_task(100); //复位100ns,已定义“timescale 1ns / 1ps”......EndTask reset_task;Input[15:0]reset_time; //复位时间BeginReset = 0;#reset_time;Reset = 1;end//推荐书籍:《设计与验证verilog HDL》吴继华王城。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Verilog十大基本功2(testbench的设计文件读取和写入操作源代码)需求说明:Verilog设计基础内容:testbench的设计读取文件写入文件来自:时间的诗原文:/times_poem/article/details/52036592十大基本功之 testbench1. 激励的产生对于 testbench 而言,端口应当和被测试的 module 一一对应。
端口分为 input,output 和 inout 类型产生激励信号的时候,input 对应的端口应当申明为 reg,output 对应的端口申明为 wire,inout 端口比较特殊,下面专门讲解。
1)直接赋值一般用 initial 块给信号赋初值,initial 块执行一次,always 或者forever 表示由事件激发反复执行。
举例,一个 module[plain] view plain copy1.`timescale 1ns/1ps2.3.module exam();4.reg rst_n;5.reg clk;6.reg data;7.8.initial9.begin10.clk = 1'b0;11.rst = 1'b1;12.#1013.rst = 1'b0;14.#50015.rst = 1'b1;16.end17.18.always19.begin20.#10 clk = ~clk;21.end22.23.endmodule大家应该注意到有个#符号,该符号的意思是指延迟相应的时间单位。
该时间单位由 timscale 决定.一般在testbench 的开头定义时间单位和仿真精度,比如`timescale 1ns/1ps前面一个是代表时间单位,后面一个代表仿真时间精度。
以上面的例子而言,一个时钟周期是 20 个单位,也就是 20ns。
而仿真时间精度的概念就是,你能看到1.001ns 时对应的信号值,而假如 timescale 1ns/1ns,1.001ns 时候的值就无法看到。
对于一个设计而言,时间刻度应该统一,如果设计文件和testbench 里面的时间刻度不一致,仿真器默认以 testbench 为准。
一个较好的办法是写一个 global.v 文件,然后用 include 的办法,可以防止这个问题。
对于反复执行的操作,可写成 task,然后调用,比如[plain] view plain copy1.task load_count;2.3.input [3:0] load_value;4.begin5.@(negedge clk_50);6.$display($time, " << Loading the counter with %h >>", lo ad_value);7.load_l = 1’b0;8.count_in = load_value;9.@(negedge clk_50);10.load_l = 1’b1;11.end12.endtask //of load_count13.14.initial15.begin16.load_count(4’hA); // 调用 task17.end其他像 forever,for,function 等等语句用法类似,虽然不一定都能综合,但是用在 testbench 里面很方便,大家可以自行查阅参考文档2)文件输入有时候,需要大量的数据输入,直接赋值的话比较繁琐,可以先生成数据,再将数据读入到寄存器中,需要时取出即可。
用$readmemb 系统任务从文本文件中读取二进制向量(可以包含输入激励和输出期望值)。
$readmemh 用于读取十六进制文件。
例如:[plain] view plain copy1.reg [7:0] mem[256:1] // a 8-bit, 256-word 定义存储器 mem2.initial $readmemh ( "E:/readhex/mem.dat", mem ) // 将.d at 文件读入寄存器 mem 中3.initial $readmemh ( "E:/readhex/mem.dat", mem, 128, 1 ) // 参数为寄存器加载数据的地址始终文件调入和打印中,我们 $fread $fwrite 用的更多一些, 大家可以自行查阅参考文档2. 查看仿真结果对于简单的 module 来说,要在 modelsim 的仿真窗口里面看波形,就用 add wave ..命令比如,testbench 的顶层 module 名叫tb,要看时钟信号,就用add wave tb.clk要查看所有信号的时候,就用 add wave /*当然,也可以在workspace 下的sim 窗口里面右键单击instance 来添加波形对于复杂的仿真,免不了要记录波形和数据到文件里面去。
1)波形文件记录(这部分暂时我没用到呢!)常见的波形文件一般有两种, vcd 和 fsdb, debussy 是个很好的工具,支持 fsdb,所以最好是 modelsim+debussy 的组合默认情况下, modelsim 不认识 fsdb,所以需要先装 debussy,再生成 fsdb 文件。
$dumpfile 和$dumpvar 是 verilog 语言中的两个系统任务,可以调用这两个系统任务来创建和将指定信息导入 VCD 文件.对于fsdb 文件来说,对应的命令是fsdbDumpfile,dumpfsdbvars(什么是 VCD 文件? 答: VCD 文件是在对设计进行的仿真过程中,记录各种信号取值变化情况的信息记录文件。
EDA工具通过读取 VCD 格式的文件,显示图形化的仿真波形,所以,可以把 VCD 文件简单地视为波形记录文件.)下面分别描述它们的用法并举例说明之。
[plain] view plain copy1.$dumpfile 系统任务:为所要创建的 VCD 文件指定文件名。
2.举例( "//"符号后的内容为注释文字):3.initial4.$dumpfile ("myfile.dump"); //指定 VCD 文件的名字为 myfile.dump,仿真信息将记录到此文件5.$dumpvar 系统任务:指定需要记录到 VCD 文件中的信号,可以指定某一模块层次上的所有信号,也可以单独指定某一6.个信号。
7.典型语法为$dumpvar(level, module_name); 参数 level 为一个整数,用于指定层次数,参数 module 则指定要记录的模块。
8.整句的意思就是,对于指定的模块,包括其下各个层次(层次数由 level 指定)的信号,都需要记录到 VCD 文件中去。
9.10.11.举例:12.initial13.$dumpvar (0, top); //指定层次数为 0,则 top 模块及其下面各层次的所有信号将被记录14.15.initial16.$dumpvar (1, top); //记录模块实例 top 以下一层的信号17.//层次数为 1,即记录 top 模块这一层次的信号18.//对于 top 模块中调用的更深层次的模块实例,则不记录其信号变化19.20.initial21.$dumpvar (2, top); //记录模块实例 top 以下两层的信号22.23.//即 top 模块及其下一层的信号将被记录24.假设模块 top 中包含有子模块 module1,而我们希望记录 top.module1 模块以下两层的信号,则语法举例如下:25.initial26.$dumpvar (2, top.module1); //模块实例 top.module1 及其下一层的信号将被记录27.假设模块 top 包含信号 signal1 和 signal2(注意是变量而不是子模块), 如我们希望只记录这两个信号,则语法举例如下:28.29.initial30.$dumpvar (0, top.signal1, top.signal2); //虽然指定了层次数,但层次数是不影响单独指定的信号的//即指定层次数和单独指定的信号无关我们甚至可以在同一个$dumpvar 的调用中,同时指定某些层次上的所有信号和某个单独的信号,假设模块 top 包含信号 signal1,同时包含有子模块 module1,如果我们不但希望记录 signal1 这个独立的信号,而且还希望记录子模块 module1以下三层的所有信号,则语法举例如下:[plain] view plain copy1.initial2.$dumpvar (3, top.signal1, top.module1); //指定层次数和单独指定的信号无关3.//所以层次数 3 只作用于模块 top.module1, 而与信号4.top.signal1 无关上面这个例子和下面的语句是等效的:[plain] view plain copy1.initial2.begin3.$dumpvar (0, top.signal1);4.$dumpvar (3, top.module1);5.end6.7.$dumpvar 的特别用法(不带任何参数):8.initial9.$dumpvar; //无参数,表示设计中的所有信号都将被记录最后,我们将$dumpfile 和$dumpvar 这两个系统任务的使用方法在下面的例子中综合说明,假设我们有一个设计实例,名为 i_design,此设计中包含模块 module1,模块 module1 下面还有很多层次,我们希望对这个设计进行仿真,并将仿真过程中模块 module1 及其以下所有层次中所有信号的变化情况,记录存储到名为 mydesign.dump 的 VCD 文件中去,则例示如下:[plain] view plain copy1.initial2.begin3.$dumpfile ("mydesign.dump"); //指定 VCD 文件名为 mydesign.dump4.$dumpvar (0, i_design.module1); //记录 i_design.module1 模块及其下面层次中所有模块的所有信号5.end对于生成 fsdb 文件而言,也是类似的[plain] view plain copy1.initial2.begin3.$fsdbDumpfile("tb_xxx.fsdb");4.$fsdbDumpvars(0,tb_xxx);5.end2)文件输出结果integer out_file; // out_file 是一个文件描述,需要定义为integer 类型out_file = $fopen ( " cpu.data " ); // cpu.data 是需要打开的文件,也就是最终的输出文本设计中的信号值可以通过$fmonitor, $fdisplay,$fwrite其中$fmonitor 只要有变化就一直记录, $fdisplay 和$fwrite 需要触发条件才记录例子:[plain] view plain copy1.initial begin2.$fmonitor(file_id, "%m: %t in1=%d o1=%h", $time, in1, o 1);3.end4.always@(a or b)5.begin6.$fwrite(file_id,"At time%t a=%b b=%b",$realtime,a,b);7.end8.3 参考“A Verilog HDL Test Bench Primier.pdf”1) DUT(Design Under Test)部分[plain] view plain copy1.//-------------------------------------------------2.// File: count16.v3.// Purpose: Verilog Simulation Example4.//-------------------------------------------------5.`timescale 1 ns / 100 ps6.module count16 (7.clk,8.rst_n,9.load_l,10.enable_l,t_in,12.oe_l,13.14.count,15.count_tri16.);17.18.input clk;19.input rst_n;20.21.input load_l;22.input enable_l;23.input [3:0] cnt_in;24.input oe_l;25.26.output [3:0] count;27.output [3:0] count_tri;28.29.reg [3:0] count;30.31.// tri-state buffers32.assign count_tri = (!oe_l) ? count : 4'bZZZZ;33.34.35.// synchronous 4 bit counter36.37.always @ (posedge clk or negedge rst_n)38.if (!rst_n) begin39.count <= 4'd0;40.end41.else begin42.if (!load_l) begin43.count <= cnt_in;44.end45.else if (!enable_l) begin46.count <= count + 1;47.end48.end49.50.endmodule //of count162) Test Bench[plain] view plain copy1.//-------------------------------------------------2.// File: tb.v3.// Purpose: Verilog Simulation Example4.// Test Bench5.//-----------------------------------------------------------6.`timescale 1ns / 100ps7.module tb ();8.9.//---------------------------------------------------------10.// inputs to the DUT are reg type11.reg clk_50;12.reg rst_n;13.reg load_l;14.reg enable_l;15.16.reg [3:0] count_in;17.reg oe_l;18.19.//--------------------------------------------------------20.// outputs from the DUT are wire type21.wire [3:0] cnt_out;22.wire [3:0] count_tri;23.24.25.//----------------------------------------------------------26.// create a 50Mhz clock27.always #10 clk_50 = ~clk_50; // every ten nanosecond s invert28.29.30.//-----------------------------------------------------------31.// initial blocks are sequential and start at time 032.initial33.begin34.$display($time, " << Starting the Simulation >>");35.clk_50 = 1'd0;36.37.// at time 038.rst_n = 0;39.40.// reset is active41.enable_l = 1'd1;42.43.// disabled44.load_l = 1'd1;45.46.// disabled47.count_in = 4'h0;48.oe_l = 4'b0;49.50.// enabled51.#20 rst_n = 1'd1;52.53.// at time 20 release reset54.$display($time, " << Coming out of reset >>");55.56.@(negedge clk_50); // wait till the negedge of57.// clk_50 then continue58.load_count(4'hA);59.60.// call the load_count task61.62.@(negedge clk_50);63.$display($time, " << Turning ON the count enable >> ");64.65.enable_l = 1'b0;66.// turn ON enable67.// let the simulation run,68.// the counter should roll69.wait (cnt_out == 4'b0001); // wait until the count70.71.// equals 1 then continue72.$display($time, " << count = %d - Turning OFF the co unt enable >>",cnt_out);73.enable_l = 1'b1;74.#40;75.76.// let the simulation run for 40ns77.// the counter shouldn't count78.$display($time, " << Turning OFF the OE >>");79.oe_l = 1'b1;80.81.82.// disable OE, the outputs of83.// count_tri should go high Z.84.#20;85.$display($time, " << Simulation Complete >>");86.$stop;87.88.// stop the simulation89.end90.91.92.//--------------------------------------------------------------93.// This initial block runs concurrently with the other94.// blocks in the design and starts at time 095.96.initial begin97.// $monitor will print whenever a signal changes98.// in the design99.$monitor(100.$time,101." clk_50=%b, rst_n=%b, enable_l=%b, load_l=%b, cou nt_in=%h, cnt_out=%h, oe_l=%b, count_tri=%h",102.clk_50, rst_n, enable_l, load_l, count_in, cnt_out, oe_l, c ount_tri103.);104.end105.106.107.//--------------------------------------------------------------108.// The load_count task loads the counter with the valu e passed109.task load_count;110.input [3:0] load_value;112.begin113.@(negedge clk_50);114.$display($time, " << Loading the counter with %h >>" , load_value);115.load_l = 1'b0;116.count_in = load_value;117.118.@(negedge clk_50);119.load_l = 1'b1;120.end121.endtask //of load_count122.123.124.125.//---------------------------------------------------------126.// instantiate the Device Under Test (DUT)127.// using named instantiation128.count16 count16_m0 (129..clk (clk_50),130..rst_n (rst_n),131..load_l (load_l),t_in (count_in),133..enable_l (enable_l),134..oe_l (oe_l),135.136..count (cnt_out),137..count_tri (count_tri)138.);140.141.142.//---------------------------------------------------------143.// read and write data144.reg [7:0] mem[10:1];//read data from file145.146.initial $readmemh ("F:/IC/prj/testbench/prj0/data/me m.dat", mem ); // 将.dat 文件读入寄存器 mem 中147.148.149.//设计中的信号值可以通过$fmonitor, $fdisplay,$fwrite 150.//其中$fmonitor 只要有变化就一直记录, $fdisplay 和$fwrite 需要触发条件才记录151.152.integer file_out; // out_file 是一个文件描述,需要定义为 integer 类型153.initial file_out = $fopen("F:/IC/prj/testbench/prj0/data /wr_mem.dat", "w");154.155.// wr_mem.dat 是需要打开的文件,也就是最终的输出文本156.157.always @(posedge clk_50)158.if (/*tb.count16_m0.*/enable_l == 1'd0) begin159.$fwrite (file_out, "%h\n", cnt_out[3:0]);160.// $fdisplay(file_out, "%h", cnt_out[3:0]);161.end162.164.endmodule //of cnt16_tb3) sim.do文件[plain] view plain copy1.#Time: 2016-07-262.#By : times_poem3.4.quit -sim5.6.cd F:/IC/prj/testbench/prj07.8.if [file exists work] {9.vdel -all10.}11.12.vlib work13.14.vlog ./*.v15.vlog ./src/*.v16.17.vsim -t ps -novopt work.tb18.19.log -r /*20.do wave.do21.22.run -all。