如何写testbench

合集下载

verilogtestbench写法

verilogtestbench写法

verilogtestbench写法Verilog测试平台(testbench)技术(⼀) 收藏对设计进⾏功能仿真和时序仿真时,需要给待测模块提供激励输⼊。

对于由Verilog语⾔描述的设计模块,最好的⽅法⾃然同样是⽤Verilog语⾔对待测模块施加激励和检测模块的输出响应。

实际应⽤中,Verilog测试平台(testben ch)就是⽤来提供上述功能的。

Verilog测试平台是⼀个例化的待测(MUT)Verilog 模块,给它施加激励并观测其输出。

由于测试平台是⽤Verilog语⾔描述的,因此可以应⽤到不同的仿真环境中。

待测模块和与之对应的测试平台组成⼀个仿真模型,应⽤这个模型可以在不同的测试环境中⽤相同的激励对待测模块进⾏调试。

下⾯就对不同电路类型分别介绍verilog测试平台的语⾔结构。

⼀、测试平台1.组合电路测试设计组合电路的测试平台时,待测模块及其功能决定了激烈的选择与测试次数。

对于⼀个已有的待测模块,测试平台中需要声明与待测模块输⼊输出端⼝对应的变量。

与输⼊端⼝相连接的变量定义为reg,与输出端⼝相连接的变量定义为wire,例化时将测试平台中声明的变量与待测模块的输⼊输出端⼝相关联。

使⽤initial语句控制程序运⾏,initial语句是⼀种过程结构,在initial块中可使⽤延迟控制语句来控制initial块中的程序流动。

这⾥对⼀个简单的算术逻辑单元(ALU)为例进⾏测试,下⾯是该单元Verilog 描述。

/***************************************************************** ********///多动能ALU的Verilog代码'timescale 1ns/100psmodule alu_4bit(a,b,f,oe,y,p,ov,a_gt_b,a_eg_b,a_lt_b);input [3:0] a,b;input [1:0] f;input oe;input [3:0] y;output p,ov,a_gt_b,a_eg_b,a_lt_b; reg [4:0] im_y;always @(a or b or f)beginov=1'b0;im_y=0;case(f)2'b00:beginim_y=a+b;if(im_y>5'b01111)ov=1'b1;end2'b01:beginim_y=a-b;if(im_y>5'b01111)ov=1'b1;end2'b10:im_y[3:0]=a&b;2'b11:im_y[3:0]=a^b;default:im_y[3:0]=4'b0000;endcaseendalways @(a or b)beginif(a>b){a_gt_b,a_ge_b,a_lt_b}=3'b100;else if(a{a_gt_b,a_ge_b,a_lt_b}=3'b001;else{a_gt_b,a_ge_b,a_lt_b}=3'b010;endassign p=^im_y[3:0];assign y=oe?im_y[3:0]:4'bz;endmodule/***************************************************************** ********/模块alu_4bit是四功能的算术逻辑单元,输⼊包括数据信号a、b和功能信号f,输出包括数据信号y和ALU⽣成的奇偶校验信号p、溢出信号ov及⽐较信号。

编写高效率的testbench

编写高效率的testbench

编写高效率的testbench简介:由于设计的规模越来越大也越来越复杂,数字设计的验证已经成为一个日益困难和繁琐的任务。

验证工程师们依靠一些验证工具和方法来应付这个挑战。

对于几百万门的大型设计,工程师们一般使用一套形式验证(formal verification)工具。

然而对于一些小型的设计,设计工程师常常发现用带有testbench的HDL仿真器就可以很好地进行验证。

Testbench已经成为一个验证高级语言(HLL --High-Level Language) 设计的标准方法。

通常testbench完成如下的任务:1.实例化需要测试的设计(DUT);2.通过对DUT模型加载测试向量来仿真设计;3.将输出结果到终端或波形窗口中加以视觉检视;4.另外,将实际结果和预期结果进行比较。

通常testbench用工业标准的VHDL或Verilog硬件描述语言来编写。

Testbench调用功能设计,然后进行仿真。

复杂的testbench完成一些附加的功能—例如它们包含一些逻辑来选择产生合适的设计激励或比较实际结果和预期结果。

后续的章节描述了一个仔细构建的testbench的结构,并且提供了一个自动比较实际结果与预期结果的进行自我检查的testbench例子。

图1给出了一个如上所描述步骤的标准HDL验证流程。

由于testbench使用VHDL或Verilog来描述,testbench的验证过程可以根据不同的平台或不同的软件工具实现。

由于VHDL或Verilog是公开的通用标准,使用VHDL或Verilog编写的testbench以后也可以毫无困难地重用(reuse)。

图1使用Testbench的HDL验证流程构建TestbenchTestbench用VHDL或Verilog来编写。

由于testbench只用来进行仿真,它们没有那些适用于综合的RTL语言子集的语法约束限制,而是所有的行为结构都可以使用。

因而testbench可以编写的更为通用,使得它们可以更容易维护。

VHDL——如何写简单的testbench

VHDL——如何写简单的testbench

use ieee.std_logic_1164.all;use ieee.std_logic_arith.all;--use ieee.std_logic_unsigned.all;entity cnt6 isport(clr,en,clk :in std_logic;q :out std_logic_vector(2 downto 0) );end entity;architecture rtl of cnt6 issignal tmp :std_logic_vector(2 downto 0); beginprocess(clk)-- variable q6:integer;beginif(clk'event and clk='1') thenif(clr='0')thentmp<="000";elsif(en='1') thenif(tmp="101")thentmp<="000";elsetmp<=unsigned(tmp)+'1';end if;end if;end if;q<=tmp;-- qa<=q(0);-- qb<=q(1);-- qc<=q(2);end process;end rtl;二、六进制计数器testbench的代码signal en :std_logic:='0';signal clk :std_logic:='0';signal q :std_logic_vector(2 downto 0);constant clk_period :time :=20 ns;begininstant:cnt6 port map(clk=>clk,en=>en,clr=>clr,q=>q);clk_gen:processbeginwait for clk_period/2;clk<='1';wait for clk_period/2;clk<='0';end process;clr_gen:processbeginclr<='0';wait for 30 ns;clr<='1';wait;end process;en_gen:processbeginen<='0';wait for 50ns;en<='1';wait;end process;end rtl;--测试平台文件(testbench)的基本结构library ieee;use ieee.std_logic_1164.all;entity test_bench is --测试平台文件的空实体(不需要端口定义) end test_bench;architecture tb_behavior of test_bench iscomponent entity_under_test --被测试元件的声明port(list-of-ports-theri-types-and-modes);end component;begininstantiation:entity_under_test port map(port-associations);process() --产生时钟信号……end process;process() --产生激励源……end process;end tb_behavior;------------------------------------------------------------------- --简单计数程序源码library ieee;use ieee.std_logic_1164.all;use ieee.std_logic_unsigned.all;use ieee.std_logic_unsigned.all;entity sim_counter isport(clk :in std_logic;reset :in std_logic;count :out std_logic_vector(3 downto 0));end entity;architecture behavioral of sim_counter issignal temp :std_logic_vector(3 downto 0);beginprocess(clk,reset)beginif reset='1' thentemp<="0000";elsif clk'event and clk='1' thentemp<=temp+1;end if;end process;count<=temp;end behavioral;------------------------------------------------------------------- --简单计数程序,测试文件代码(testbench)library ieee;use ieee.std_logic_1164.all;use ieee.std_logic_unsigned.all;use ieee.numeric_std.all;entity counter_tb_vhd is --测试平台实体end counter_tb_vhd;architecture behavior of counter_tb_vhd is--被测试元件(DUT)的声明component sim_counterport(clk :in std_logic;reset :in std_logic;count :out std_logic_vector(3 downto 0));end component;--输入信号signal clk:std_logic:='0';signal reset :std_logic:='0';--输出信号signal count :std_logic_vector(3 downto 0);constant clk_period :time :=20 ns; --时钟周期的定义begindut:sim_counter port map(clk=>clk,reset=>reset,counter=>counter);clk_gen:processbeginclk='1';wait for clk_period/2;clk='0';wait for clk_period/2;end process;tb:process --激励信号beginwait for 20 ns;reset<='1';wait for 20 ns;reset<='0';wait for 200 ns;wait; --will wait forever;end process;end;--激励信号的产生方式--1.以一定的离散时间间隔产生激励信号的波形--2.基于实体的状态产生激励信号,也就是说基于实体的输出响应产生激励信号--两种常用的复位信号--1.周期性的激励信号,如时钟--2.时序变化的激励型号,如复位--eg.产生不对称时钟信号w_clk<='0' after period/4 when w_clk='1' else'1' after 3*period/4 when w_clk='0' else'0';--eg.产生堆成时钟信号,process语句clk_gen1:processconstan clk_period := 40 ns;beginclk='1';wait for clk_period/2;clk='0';wait for clk_period/2;end process;四、如果自己不想写这些testbench的这些固定格式,可以在quartus 里自动生成testbench文件的模板,然后往里面写信号就行了步骤:processing->start->start test bench template write这里需要注意的是要在仿真选项里选择一个仿真工具,然后才会生成testbench自动生成的testbench模板格式如下:-- Copyright (C) 1991-2008 Altera Corporation-- Your use of Altera Corporation's design tools, logic functions-- and other software and tools, and its AMPP partner logic-- functions, and any output files from any of the foregoing-- (including device programming or simulation files), and any-- associated documentation or information are expressly subject-- to the terms and conditions of the Altera Program License-- Subscription Agreement, Altera MegaCore Function License-- Agreement, or other applicable license agreement, including,-- without limitation, that your use is for the sole purpose of-- programming logic devices manufactured by Altera and sold by-- Altera or its authorized distributors. Please refer to the-- applicable agreement for further details.-- ***************************************************************************-- This file contains a Vhdl test bench template that is freely editable to-- suit user's needs .Comments are provided in each section to help the user -- fill out necessary details.-- ***************************************************************************-- Generated on "03/13/2011 20:05:04"-- Vhdl Test Bench template for design : cnt6---- Simulation tool : ModelSim (VHDL)--LIBRARY ieee;USE ieee.std_logic_1164.all;ENTITY cnt6_vhd_tst ISEND cnt6_vhd_tst;ARCHITECTURE cnt6_arch OF cnt6_vhd_tst IS-- constants-- signalsSIGNAL clk : STD_LOGIC;SIGNAL clr : STD_LOGIC;SIGNAL en : STD_LOGIC;SIGNAL q : STD_LOGIC_VECTOR(2 DOWNTO 0);COMPONENT cnt6PORT (clk : IN STD_LOGIC;clr : IN STD_LOGIC;en : IN STD_LOGIC;q : OUT STD_LOGIC_VECTOR(2 DOWNTO 0));END COMPONENT;BEGINi1 : cnt6PORT MAP (-- list connections between master ports and signalsclk => clk,clr => clr,en => en,q => q);init : PROCESS-- variable declarationsBEGIN-- code that executes only onceWAIT;END PROCESS init;always : PROCESS-- optional sensitivity list-- ( )-- variable declarationsBEGIN-- code executes for every event on sensitivity list WAIT;END PROCESS always;END cnt6_arch;。

test bench 教程

test bench 教程

最近项目上要用到FPGA,之前用的一直是verilog,后面换成了VHDL。

对ISE一窍不通啊,研究了一些testbench文件的编写,record一下。

借用一下博文/lovelink/item/ff34ce9b12f45988581461ac的话。

首先对TESTBENCH作一个形象一些的比喻吧,它就象是一个面包板(做过电路实验吧),他对外没有任何接口,但它要向要插在他上面的器件提供接口,这样才能正确的插入,还有它必须对插在它上面的器件提供正常的信号。

当然在它上面还必须要有这个器件。

这时就完成了一个TESTBENCH。

应该大概明白了其中的意思了吧。

好了,根据上面的比喻我们可以非常明确的知道一个TESTBENCH要写一些什么东西,首先它对外无接口,所以它的实体部分是空的。

在它上面要有相应的器件,所以在它的结构体中要申明我们要测试的器件,也就是component的申明。

还有就是它要对器件提供接口,所以它的结构体应该提供一些信号,并且要对这些信号进行正确的测试赋值。

当然还要进行一些插入工作,就是信号的对应工作。

这样一个TESTBENCH就完成了。

原理很简单的,应该很容易明白。

不过在真正的测试中可能不会用太多的这种方式吧,应该会选用测试向量吧,这个的准确性更高一些。

不过怎么样写测试向量,这到是一个有大学问的东西,因为当我们的管脚很多的时候,测试的向量数目是要心指数增长的,当然不可能把所有的情况都测试完成了,只有是测试其中的一部分,这儿怎么样写出有代表性的一组测试向量是很有学问的,应该说是研究的热点吧。

几个testbench要用到的重要语句:(1)wait:无限等待,表示永远挂起,对于汉语wait语句的进程来说,进程在一开始执行一次后面就不执行了;(2)wait on 信号表:敏感信号等待语句,等待敏感信号表中的信号发生变化才执行;(3)wait until 表达式:条件等待语句,当条件表达式中所含的信号发生了变化,并为true时,进程才脱离等待状态;(4)wait for 时间表达式:此语句中声明了一个时间段,从从执行到当前的wait语句开始,只要这个时间段内,进程处于等待状态,超过这段时间,进程自动恢复执行该等待语句的下一条语句。

如何搭建SoC项目的基本Testbench(eetop)

如何搭建SoC项目的基本Testbench(eetop)

先啰嗦几句。

其实老早就想写这个帖子,自己犯懒一直木有写。

前阵子写了一个初版,然后发给了几个做验证的朋友看了看,普遍反映没看明白. 说是我写的东西和我搭的环境结合的太过紧密了,不结合代码,理解的不透彻。

可惜代码是公司的,我不能把代码发出来。

我后来写了一个带很多代码截屏的版本,但是很抱歉没法发到论坛上来。

我个人觉得下面的文字已经能表达我的想法和思想了,希望能对帖的有一点帮助吧。

---------------------------------------------写这个文档的目的是让大家对搭建SoC项目的Testbench有一个比较清晰的认识,可以根据这个文档来一步一步的搭建起一个SoC项目的基本的testbench。

本文档重点是指导大家搭建基本环境,以及能解决搭建Testbench过程中容易遗漏的问题或者容易遇到的“地雷”。

我搭的SoC项目的testbench会有一些相对特殊的点:1)要有嵌入式的软件。

这里包括两部分,一是初始化的bootloader(一般是固化在rom或者存放在外部的flash里),一是boot起来以后放在外部易失性存储介质上的应用层的程序。

2)正常启动起来(一级boot可以切到应用程序了)以后,为了简化流程,我们要使用ISS的环境。

--- 这是比较特殊的一个点3)环境主要脚本的维护和修改。

主要是单个仿真和批量仿真(regression)核心脚本4)为了优化仿真和编译速度,我们要能把不用的模块dummy掉。

5)文件列表的处理6)SoC软件与Testbench都能访问的“共享空间”的处理7)公用函数的准备,比如根据CPU看到的地址空间直接访问外部DRAM的数组,进行初始化写、数据写和数据读操作。

8)环境变量的维护。

9)Define文件的维护10)DDRC的替换(一个是AXI_SLV_VIP的替换,一个是简单AXI_SLV模型的替换)磨刀不误砍柴工,把需要的东西提前准备好,搭建Testbench就像搭积木一样简单快速了。

Verilog-testbench的写法

Verilog-testbench的写法

数字集成电路设计入门--从HDL到版图于敦山北大微电子学系第十五章Verilog Test Bench使用简介学习内容:•用一个复杂的test bench复习设计的组织与仿真•建立test bench通常使用的编码风格及方法设计组织虚线表示编译时检测输入文件是否存在及可读并允许生成输出文件。

test bench 组织stimulus要验证的设计简单的test bench•简单的test bench 向要验证的设计提供向量,人工验证输出。

•复杂的test bench 是自检测的,其结果自动验证。

复杂的test bench激励验证结果要验证的设计并行块•fork…join块在测试文件中很常用。

他们的并行特性使用户可以说明绝对时间,并且可以并行的执行复杂的过程结构,如循环或任务。

module inline_ tb;reg [7: 0] data_ bus;// instance of DUTinitial forkdata_bus = 8'b00;Time | data_ bus0 | 8’b0000_0000 10 | 8’b0100_0101 30 | 8’b0100_0110 40 | 8’b0100_0111 45 | 8’b1000_1110#10 data_bus = 8'h45;#20 repeat (10) #10 data_bus = data_bus + 1;#25 repeat (5) #20 data_bus = data_bus<< 1;#140 data_bus = 8'h0f;joinendmodule上面的两个repeat循环从不同时间开始,并行执行。

象这样的特殊的激励集在单个的begin…end块中将很难实现。

50 | 8’b1000_1111 60 | 8’b1001_0000 65 | 8’b0010_0000 70 | 8’b0010_0001 80 | 8’b0010_0010 85 | 8’b0100_0100 90 | 8’b0100_0101 100 | 8’b0100_0110 105 | 8’b1000_1100 110 | 8’b1000_1101 120 | 8’b1000_1110 125 | 8’b0001_1100 140 | 8’b0000_1111包含文件•包含文件用于读入代码的重复部分或公共数据。

如何编写testbench的总结(非常实用的总结)

如何编写testbench的总结(⾮常实⽤的总结)1.激励的设置相应于被测试模块的输⼊激励设置为reg型,输出相应设置为wire类型,双向端⼝inout在测试中需要进⾏处理。

⽅法1:为双向端⼝设置中间变量inout_reg作为该inout的输出寄存,inout⼝在testbench中要定义为wire型变量,然后⽤输出使能控制传输⽅向。

eg:inout [0:0] bi_dir_port;wire [0:0] bi_dir_port;reg [0:0] bi_dir_port_reg;reg bi_dir_port_oe;assign bi_dir_port=bi_dir_port_oe?bi_dir_port_reg:1'bz;⽤bi_dir_port_oe控制端⼝数据⽅向,并利⽤中间变量寄存器改变其值。

等于两个模块之间⽤inout双向⼝互连。

往端⼝写(就是往模块⾥⾯输⼊)⽅法2:使⽤force和release语句,这种⽅法不能准确反映双向端⼝的信号变化,但这种⽅法可以反映块内信号的变化。

具体如⽰:module test();wire data_inout;reg data_reg;reg link;#xx; //延时force data_inout=1'bx; //强制作为输⼊端⼝...............#xx;release data_inout; //释放输⼊端⼝endmodule从⽂本⽂件中读取和写⼊向量1)读取⽂本⽂件:⽤ $readmemb系统任务从⽂本⽂件中读取⼆进制向量(可以包含输⼊激励和输出期望值)。

$readmemh ⽤于读取⼗六进制⽂件。

例如:reg [7:0] mem[1:256] // a 8-bit, 256-word 定义存储器meminitial $readmemh ( "mem.data", mem ) // 将.dat⽂件读⼊寄存器mem中initial $readmemh ( "mem.data", mem, 128, 1 ) // 参数为寄存器加载数据的地址始终2)输出⽂本⽂件:打开输出⽂件⽤?$fopen 例如:integer out_file; // out_file 是⼀个⽂件描述,需要定义为 integer类型out_file = $fopen ( " cpu.data " ); // cpu.data 是需要打开的⽂件,也就是最终的输出⽂本设计中的信号值可以通过$fmonitor, $fdisplay,2. Verilog和Ncverilog命令使⽤库⽂件或库⽬录ex). ncverilog -f run.f -v lib/lib.v -y lib2 +libext+.v //⼀般编译⽂件在run.f中, 库⽂件在lib.v中,lib2⽬录中的.v⽂件系统⾃动搜索使⽤库⽂件或库⽬录,只编译需要的模块⽽不必全部编译3.Verilog Testbench信号记录的系统任务:1). SHM数据库可以记录在设计仿真过程中信号的变化. 它只在probes有效的时间内记录你set probe on的信号的变化.ex). $shm_open("waves.shm"); //打开波形数据库$shm_probe(top, "AS"); // set probe on "top",第⼆个参数: A -- signals of the specific scropeS -- Ports of the specified scope and below, excluding library cellsC -- Ports of the specified scope and below, including library cellsAS -- Signals of the specified scope and below, excluding library cellsAC -- Signals of the specified scope and below, including library cells还有⼀个 M ,表⽰当前scope的memories, 可以跟上⾯的结合使⽤, "AM" "AMS" "AMC"什么都不加表⽰当前scope的ports;$shm_close //关闭数据库2). VCD数据库也可以记录在设计仿真过程中信号的变化. 它只记录你选择的信号的变化.ex). $dumpfile("filename"); //打开数据库$dumpvars(1, top.u1); //scope = top.u1, depth = 1第⼀个参数表⽰深度, 为0时记录所有深度; 第⼆个参数表⽰scope,省略时表当前的scope.$dumpvars; //depth = all scope = all$dumpvars(0); //depth = all scope = current$dumpvars(1, top.u1); //depth = 1 scope = top.u1$dumpoff //暂停记录数据改变,信号变化不写⼊库⽂件中$dumpon //重新恢复记录3). Debussy fsdb数据库也可以记录信号的变化,它的优势是可以跟debussy结合,⽅便调试.如果要在ncverilog仿真时,记录信号, ⾸先要设置debussy:a. setenv LD_LIBRARY_PATH :$LD_LIBRARY_PATH(path for debpli.so file (/share/PLI/nc_xl//nc_loadpli1))b. while invoking ncverilog use the +ncloadpli1 option.ncverilog -f run.f +debug +ncloadpli1=debpli:deb_PLIPtrfsdb数据库⽂件的记录⽅法,是使⽤$fsdbDumpfile和$fsdbDumpvars系统函数,使⽤⽅法参见VCD注意: 在⽤ncverilog的时候,为了正确地记录波形,要使⽤参数: "+access+rw", 否则没有读写权限在记录信号或者波形时需要指出被记录信号的路径,如:tb.module.u1.clk.………………………………………………………………………………………………………关于信号记录的系统任务的说明:在testbench中使⽤信号记录的系统任务,就可以将⾃⼰需要的部分的结果以及波形⽂件记录下来(可采⽤sigalscan⼯具查看),适⽤于对较⼤的系统进⾏仿真,速度快,优于全局仿真。

VHDL的testbench的编写

VHDL的testbench的编写大多数硬件设计人员对verilog的testbench比较熟悉,那是因为verilog被设计出来的目的就是为了用于测试使用,也正是因为这样verilog的语法规则才被设计得更像C语言,而verilog发展到后来却因为它更接近C语言的语法规则,设计起来更加方便,不像VHDL那也死板严密,所以verilog 又渐渐受到硬件设计者们的青睐。

但其实VHDL在最开始也是具有测试能力的,而且它的语法严密,但我们同样可以用它来编写我们的测试文件。

下面以一个8bit计数器为例子给出个简单的testbench模板及注释:通过编写testbench来仿真和通过拖波形来仿真,最大的好处就是,当测试数据无比庞大时,可以简易得通过testbench中的算法来实现,而另一个更为重要的方面就是,可以通过testbench对数据文件进行读写操作,从而简化我们的仿真工作。

首先介绍下时间控制语句——wait:(其实wait语句是通过控制仿真的两种状态——执行和挂起,来控制时间的)1.wait——无线等待;语法【wait;】,类似于Verilog中的¥Stop2.wait on——敏感信号量变化;语法【wait on 信号;】,表示当信号发生变化的时候,仿真开始继续执行,从而结束挂起状态3.wait until——条件满足;语法【waituntil 表达式】,表达式为一个布尔表达式,表示当表达式为“真”时,仿真继续执行,结束挂起状态4.wait for——时间控制;语法【waitfor 时间表达式】,例:【wait for 30ns;】VHDL也提供了文件I/O的操作,以下简单介绍在我们大部分情况下如何通过VHDL来进行文件操作。

file类型:文件句柄,用于定义文件。

语法1【file 文件变量名:text is 读取或者写入类型“文件名”;】text——文件类型为文本类型,读取类型为in,写入类型为out;语法2【file 文件变量名:text;】只是定义了文件变量名,并没有给赋予初值。

Testbench写法总结


outer_port_tb_wire,inner_port_tb_wire);
end
else
begin
$display("\n **** time=%t ****",$time);
$display("ERROR! out_en=%d",out_en_tb);
$display("ERROR! outer_port_tb_wire != inner_port_tb_wire" );
$display("ERROR! outer_port_tb_wire=%d, inner_port_tb_wire=%d",
outer_port_tb_wire,inner_port_tb_wire);
end
end
endmodule
验证该双向端口的testbench结构如图2所示。
这是一个self-checking testbench,可以自动检查仿真结果是否正确,并在Modelsim控制台上打印出提示信息。图中Monitor完成信号采样、结果自动比较的功能。
testbench的工作过程为
1)out_en=1时,双向端口处于输出状态,testbench给inner_port_tb_reg信号赋值,然后读取outer_port_tb_wire的值,如果两者一致,双向端口工作正常。
module tb();
reg[7:0] inner_port_tb_reg;
wire[7:0] inner_port_tb_wire;
reg[7:0] outer_port_tb_reg;
wire[7:0] outer_port_tb_wire;

我的testbench书写总结

占空比为 50%的时钟`timescale 1ns/1ns //定义时间的尺度和精度,其中精度和小树部分挂钩parameter period=4’d10;reg clk; //时钟是输入给DUT的信号必须声明为reg类型initialbeginclk=1’b0; //定义clk的初始状态为低电平forever#( period/2) clk=~clk;endparameter period=4’d10;reg clk;initialbeginclk=1’b0; //定义clk的初始状态为低电平endalways #( period/2) clk=~clk;占空比非50%的时钟信号parameter HIGH_TIME=4,LOW_TIME=6;reg clk;initialbeginclk=1’b0; //定义clk的初始状态为低电平endalwaysbegin# LOW_TIME clk=1’b1;//0~LOW_TIME为低电平# HIGH_TIME clk=1’b0; //从low_time~(low_time+high_time)为高电平end固定数目的时钟信号parameter PulseCount=4,PERIOD=10;reg clk;initialbeginclk=1’b0; //定义clk的初始状态为低电平repeat(PulseCount) //相对于下面的语句重复执行4次#(PERIOD/2) clk=~clk;End//先低电平半个周期,然后再产生两个完整周期的脉冲,结束时clk为低电平parameter Phase_Shift=2;PERIOD=10;reg source_clk;wire derive_clk;//这里是wire好像没有多大用处,要是能用reg就有用了//用initial语句生成源时钟initialbeginclk=1’b0; //定义clk的初始状态为低电平forever#( PERIOD/2) source_clk=~source_clk;EndAssign #Phase_Shift derive_clk=source_clk; //生成派生时钟,要延后2ns2,对于仿真器,reg在没有赋初始值的情况下默认的值为’X’即不定值,而wire的默认值为’Z’即高阻态。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

如何编写testbench今天,我来带领大家写一个简单的testbench ,顺便讲解如何写好一个testbench 以及写testbench 时应该注意的地方。

在讲解testbench 之前,我们先看一下前面的那个AND_2程序的仿真图,如下:如上图中所标,在1处,B 已经为低电平了,但是输出C 仍然为高电平,这样求与运算就会出错。

在2处,A 和B 都是低电平了,C 仍然为高电平,直到下次出现时钟的上升沿为止,为什么会这样呢?编译的时候并没有报错,呵呵,出了怪事了啊!其实编译器只能检查处语法错误,无法检测到逻辑错误,这个图给出的结果和我们程序所表达的结果一样,但是这并不是我们所要的求与运算,我们想要的是A 和B 同时为高电平时,C 才输出高电平。

我们把程序的敏感列表改为:always@(posedge clk or negedge rst or A or B)就可以了,把A 的电平改变和B的电平改变都加进敏感列表,激励不变,所得到的仿真图:这才是我们所要的求与运算!好了,现在开始讲如何写testbench 。

Testbench 不像RTL 级代码,可以用高级行为语句,不用考虑其可综合性,这样就能写出高效的检测代码。

在语法上,testbench 和可综合代码一样,都是类C 结构。

好了,我们开始吧!1,建立工程等,与之前的一样,但是在创建文件的时候,我们一次创建两个。

取名分别为ParallelSerial_Mult 和ParallelSerial_Mult_test。

创建完成后,如下图:这两个代码分别如下:moduleParallelSerial_Mult(Clk,Rst,MultiplicandIn,MultiplierIn,Load,Product,Out_en);parameter N=8;parameter CYCLES=3;input Clk,Rst,Load;input[N-1:0]MultiplicandIn,MultiplierIn;output[2*N-1:0]Product;output Out_en;reg[2*N-1:0]Product;wire Out_en;reg[N-1:0]Multiplicand;reg[2*N-1:0]NextProduct;reg[CYCLES:0]Count;reg Busy;wire[N-1:0]Sum;wire Carry;assign{Carry,Sum}=Multiplicand+Product[2*N-1:N];assign Out_en=Count[CYCLES];always@(posedge Clk or negedge Rst)if(!Rst)beginMultiplicand<=0;Count<=0;Product<=0;Busy<=0;endelsebeginProduct<=NextProduct;if(Load)beginMultiplicand<=MultiplicandIn;Count<=0;Busy<=1'b1;endelsebeginif(Busy)Count<=Count+1'b1;if(Count[CYCLES])beginCount<=0;Busy<=1'b0;endendendalways@(Load or MultiplierIn or Product or Count[CYCLES]or Carry or Sum) casex({Product[0],Count[CYCLES],Load})3'bxx1:NextProduct={{N{1'b0}},MultiplierIn[N-1:0]};3'b100:NextProduct={Carry,Sum,Product[N-1:1]};3'b000:NextProduct={1'b0,Product[2*N-1:1]};default:NextProduct=Product;endcaseendmodule这个代码是书中第120页的8位乘法器。

module ParallelSerial_Mult_test;//ParallelSerial_Mult_test为仿真模块名,仿真模//块取名和模块取名一样,可以随意取名,只要//不是verilog的关键字就行。

一般都在所要测试//的模块名后加_test,这样便于归类管理。

reg Clk,Rst,Load;//各个施加激励端口的声明wire Out_en;//各个施加激励端口的声明reg[7:0]MultiplicandIn,MultiplierIn;//各个施加激励端口的声明reg[15:0]Product;//各个施加激励端口的声明initial//使用initial语句初始化,产生激励波形beginClk=0;//注意一定要给时钟赋初始值,因为信号的缺省值为z,如//果不赋初值,则反相后还是z,时钟就一直处于高阻z状态Rst=1;#2Rst=0;#30Rst=1;MultiplicandIn=2;MultiplierIn=3;#5Load=1;#15Load=0;endalways#10Clk=~Clk;//使用always语句初始化,产生激励波形ParallelSerial_Mult inst(.Clk(Clk),.Rst(Rst),//实例化所要测试的模块.Load(Load),.MultiplicandIn(MultiplicandIn),.MultiplierIn(MultiplierIn),.Out_en(Out_en),.Product(Product));Endmodule2,开始编译然后我们分别编译这两个文件(这样有利于查错,如果编译某个文件出错,我们只在某一个文件里查找,缩小范围,容易纠错),如下图:这一点和第一讲中的不一样。

当整个工程中只有一个文件时,用Compile All和Compile Selected是一样的。

在这里也可用Compile All,但是为了方便查错,我们用后者。

可以得到两个文件都是正确的,如下所示:这时候,我们再用Compile All编译所有文件,如下图:可以看到,多了两项,和前面分别编译一样。

然后开始仿真,记住:在这里,应该双击ParallelSerial_Mult_test文件,打开仿真界面,否则不能使用testbench来进行仿真:啊?怎么出错了?(如下图)不对啊!我们在上面编译没发现错误啊?可是···可是他就是报错了!错误为:Error:(vsim-3053)F:/EDA/ModelSim/Tearch/ParallelSerial_Mult/ParallelSerial_Mult_test.v(26):Illegal output or inout port connection(port'Product').显示是Product这个端口出错了!怎么回事呢?他说Product这个输入或输出端口是非法的!怎么非法了?错误在哪里?错误在哪里?源代码单独编译是对的,一起编译也是对的!仿真的时候为什么就成了非法?好吧!我们找不出来!算了,打个游戏吧,休息一下,敲了这么代码,我也累了(我当初就遇到了这个问题,而且在网上也确实没查到答案,实在无奈,一个人单机一把dota,可是然后呢?还是不会,就是这个问题,我一个多星期没碰Verilog编程)。

为什么在这里要花费这么多时间讲这个错误呢?对了!从错误中学习!在这里特别强调一下激励的设置。

相应于被测试模块的输入激励应该设置为reg 型,输出相应设置为wire型,双端口inout在测试中需要进行特别的处理。

(见最后)在本次testbench中,我们把Product端口写成了reg型,现在改为wire型。

然后再编译,重复前面的步骤,得到下图所示:好了,到此为止,一个使用testbench的仿真结束了,但是咱还没有正式讲如何写好一个testbench呢!由上面的例子,我们可以总结如下(也可以具体看示例代码注释说明):1、Module仿真模块名;2、各个施加激励的端口;3、使用initial或always语句来产生激励波形;4、例化设计模块;5、监控和比较输出响应;6、Endmodule在这个例子中,我们没有使用到监控和比较输出。

呵呵,Inout端口的处理方法如下:方法1:为双向端口设置中间变量inout_reg作为该inout的输出寄存,inout口在testbench中要定义为wire型变量,然后用输出使能控制传输方向。

eg:inout[0:0]bi_dir_port;wire[0:0]bi_dir_port;reg[0:0]bi_dir_port_reg;reg bi_dir_port_oe;assign bi_dir_port=bi_dir_port_oe?bi_dir_port_reg:1'bz;用bi_dir_port_oe控制端口数据方向,并利用中间变量寄存器改变其值。

等于两个模块之间用inout双向口互连。

往端口写(就是往模块里面输入)方法2:使用force和release语句,这种方法不能准确反映双向端口的信号变化,但这种方法可以反映块内信号的变化。

具体如示:module test();wire data_inout;reg data_reg;reg link;#xx;//延时force data_inout=1'bx;//强制作为输入端口...............#xx;release data_inout;//释放输入端口endmodule一下介绍一些书写Testbench的技巧:1.如果激励中有一些重复的项目,可以考虑将这些语句编写成一个task,这样会给书写和仿真带来很大方便。

例如,一个存储器的testbench的激励可以包含write,read等task。

2.如果DUT中包含双向信号(inout),在编写testbench时要注意。

需要一个reg变量来表示其输入,还需要一个wire变量表示其输出。

3.如果initial块语句过于复杂,可以考虑将其分为互补相干的几个部分,用数个initial 块来描述。

在仿真时,这些initial块会并发运行。

这样方便阅读和修改。

4.每个testbench都最好包含$stop语句,用以指明仿真何时结束。

呵呵,再次和大家分享一些学习的经验。

出错的地方请大家指正。

另外,这中写testbench 的方法也是一种低级的方法,入门级的,更高级的一般用从文本文件中读取和写入向量的方法。

相关文档
最新文档