VerilogHDL及其Testbench编写方法

  • 格式:pdf
  • 大小:237.96 KB
  • 文档页数:6

学习总结系列之五――Verilog HDL/Testbench篇 Verilog HDL及其Testbench总结 (欢迎批评指正:jackhuan@tom.com)

1 Verilog HDL的基本观点 1) 观点1:module内每个基本模块之间是并行运行的。 2) 观点2:每个模块相当于一个连续赋值的过程。 3) 观点3:方程和任务是共享代码的最基本方式。 4) 观点4:同语言可用于生成模拟激励和指定测试的验证约束条件。 5) 观点5:库的概念相当于Visual C++中的DLL概念。 6) 观点6:文件与文件之间的关系可以使用C++中的*.h和*.cpp之关系理解。

2 设计建模的三种方式 1) 行为描述方式。过程化结构,每个结构之间是并行的。 2) 数据流方式。连续赋值语句方式,每个赋值语句之间是并行的,且赋值语句和结构之间是并行的。 3) 结构化方式。门和模块实例化语句。

3 两者数据类型 1) 线网数据类型wire:表示构件间的物理连线; 2) 寄存器数据类型reg:表示抽象的数据存储元件。

4 几个概念 1) 模块(module)。模块是Verilog HDL的基本描述耽误,用于描述某个设计的功能或结构及其与其它模块通信的外部端口。一个设计的结构可以使用开关级原语、门级原语和用户定义的原语方式描述;数据流行为使用使用连续赋值语句进行描述;时序行为使用过程结构描述。模块的声明部分和语句可以散布在模块中的任何地方,但变量、寄存器、线网和参数说明必须在使用前出现。 2) 只有寄存器类型数据(reg/integer)能够在initial和always语句中被赋值。 3) 阻塞性和非阻塞性赋值。理解这两个概念在学习verilog HDL中非常重要。决定了时序的正确与否。阻塞性赋值的概念是在该条赋值语句执行完成后再执行后面的语句,也就是说在执行该语句时,后面的语句是挂起的。而非阻塞性赋值的结果在何时执行是不知道的,但是可以预见在某个时间步内该语句一定能够执行完成,从这个意义上来看,非阻塞性赋值的语句类似于并行语句,稍有处理不当,会引发多驱动源问题。关于多驱动源问题,在我的VHDL总结中有所表述,此处不在费墨。 4) 用户定义原语(UDP)。UDP的定义不依赖于模块定义,因此出现在模块定义之外,也可以在单独的文本文件中定义UDP。UDP只能有一个输出或一个/多个输入端口。UDP的行为以真值表的形式描述。 5) 并行语句块和顺序语句块。并行语句块中的各语句并行执行。当并行语句块中的最后动作执行完成是,顺序语句块的语句继续执行。也就是说,并行语句块中的所有语句必须在控制转出语句块之前完成执行。并行语句块

1学习总结系列之五――Verilog HDL/Testbench篇 带有定界符fork—join,顺序语句块带有定界符begin—end。对该段的理解似乎很困难,有些拗口。必须在多实践的基础上才能正确理解这段话。 6) 任务。一个任务就像一个过程,它可以从描述的不同位置执行共同的代码段。共同的代码段用任务定义编写成任务,这样它就能够从设计描述的不同位置通过任务调用被调用。任务可以包含时序控制,并且任务也能够调用其它任务和函数。任务可以有也可以没有参数。值通过参数转入或转出。除输入参数外(参数从任务中接收值),任务还能带有参数输出。任务的输入和输出在任务的开始处声明,这些输入和输出的顺序决定了它们在任务调用中的顺序。这和C++中的指针作为形参传递何其类似啊! 7) 函数。函数如同任务一样,也可以在模块中的不同位置执行共同代码。函数与任务的不同之处在于函数只能返回一个值,它不能包含任何延时和时序控制(必须立即执行),并且它不能调用其它任务。此外,函数必须至少带有一个输入,在函数中允许没有输入输出说明。函数可以调用其它函数。一种在不同模块共享任务和函数的方法是在文本文件中编写共享任务和函数的定义,然后使用`include指令在需要的模块中包含这些定义。 8) 系统任务和系统函数。在编写testbench时使用。包括显示任务($display/$monitor/$strobe)、文件I/O任务($fopen/$fdisplay/$fmonitor/ $fstrobe/$fwrite/$readmemb)、时间标度任务($timeformat)、模拟控制任务($stop/$finish)、模拟时间函数($time)、变换函数($rtoi/$itor)和概率分布函数($random([seed]))。 9) 事件。事件是独立于线网和寄存器两者类型以外的数据类型。这有些类似于Windows编程中多线程事件。事件的命名必须在使用前声明。使用触发语句创建事件。多用于状态机中。 10) 竞争。多驱动源问题。 11) testbench波形产生的方法。理解always、forever和repeat。

5 ModelSim SE的配置 ModelSim SE的仿真配置方法很重要,其体系结果类似于Visual C++。如果精通Visual C++编程。理解Modelsim SE的仿真体系结构就很方便了。 配置Modelsim SE主要是配置其仿真库。配置时,将主目录下的modelsim.ini修改为读写。配置后在改为只读,防止在仿真过程中被修改。 加库过程(以Xilinx为例):修改当前路径→create library→mapping→compile(文件过多可多次分批编译)。 需要库$Xilinx\verilog\src\unisims、$Xilinx\verilog\src\Xilinx –CoreLib和$Xilinx\verilog\src\simprims。 在ISE中,testbench文件要关联到simulation only,设计文件关联到synthesis/imp+simulation。编译,即可执行仿真。

6 一个例子 6.1 设计文件和testbench文件 本例子仅仅说明是如何写testbench以及如何仿真的。 四位同步全加器,使用一个时钟clk同步。

2学习总结系列之五――Verilog HDL/Testbench篇 Adder4.v文件 module adder4(clk,cin, a, b, sum, cout); input cin,clk; input [3:0] a,b; output [3:0] sum; output cout; reg[3:0] sum; reg cout; always@(posedge clk) begin {cout,sum} = a+b+cin; end endmodule

testAdder4.v文件 module testadder4; reg bclk,bcin; reg[3:0] ba,bb; wire[3:0] bsum; wire bcout; //initialize clock initial begin bclk = 1'b0; #40 bclk = 1'b1; repeat(30) #20 bclk = ~bclk; $stop; end //initialize ba and bb initial begin ba = 4'b0000; bb = 4'b0000; #50 ba = 6; #20 bb = 8; #60 ba = 9; #40 ba = 4; #60 bb = 3; end //initialize bcin initial begin bcin = 1'b0; #60 bcin = 1'b1; #200 bcin = 1'b0; #160 bcin = 1'b1; end //instantiation adder4 uut(bclk,bcin,ba,bb,bsum,bcout); endmodule

3学习总结系列之五――Verilog HDL/Testbench篇 6.2 使用ISE8.2i启动Modelsim SE6.1b。 step1:启动ISE,创建新工程adder4。

step2:选择仿真器modelsim SE-verilog。 step3:添加资源文件。

step4:设置文件关联

step5:语法检查 step6:启动仿真 4学习总结系列之五――Verilog HDL/Testbench篇 step7:设置集成工具Modelsim step8:得到仿真结果 6.3 直接使用Modelsim SE仿真 step1:配置好Modelsim SE仿真环境,如5所述。 Step2:启动Modelsim SE。 Step3:更改路径。

step4:创建工程

5学习总结系列之五――Verilog HDL/Testbench篇 step5:添加源文件

step6:编译。 Step7:启动仿真――双击图示位置。

step8:的仿真波形 说明 1) 上面仅仅是行为仿真,没有涉及时序仿真,仅作入门只用。 2) 有些语句说的比较笼统,是笔者经过一定的工程摸索后的总结,要理解可能需要大量的实践。 3) 如果有不当之处,请批评指正。

6