VHDL与Verilog硬件描述语言TestBench的编写

  VHDL与Verilog硬件描述语言在数字电路的设计中使用的非常普遍,无论是哪种语言,仿真都是必不可少的。而且随着设计复杂度的提高,仿真工具的重要性就越来越凸显出来。在一些小的设计中,用TestBench来进行仿真是一个很不错的选择。VHDL与Verilog语言的语法规则不同,它们的TestBench的具体写法也不同,但是应包含的基本结构大体相似,在VHDL的仿真文件中应包含以下几点:实体和结构体声明、信号声明、顶层设计实例化、提供激励;Verilog的仿真文件应包括:模块声明、信号声明、顶层设计实例化、提供激励。大致思想都是相似的。

  简单的说,TestBench就是一种验证手段,从软件层面对设计的硬件电路进行仿真。具体来讲,一般是在你的仿真文件里,产生激励信号,作用于被仿真的设计文件DUT(Design
Under Test),产生相应的输出,然后根据输出信号检验设计的电路是否存在问题或者存在哪些问题。

  下面以FPGA板中驱动流水灯的一段程序为例,简单介绍一下两种语言的TestBench的编写。

 1 module led_run(clk,rst,led);
2 input clk,rst;
3 output reg [7:0] led;
4 reg [25:0] clk_cnt;
5 reg clk_tmp;
6 reg [3:0] temp;
7
8 always@(posedge clk or negedge rst)
9 begin
10 if(!rst)
11 begin
12 clk_cnt<=26‘d0;
13 clk_tmp<=1‘b1;
14 end
15 else
16 begin
17 if(clk_cnt==26‘b11111111111111111111111111)
18 begin
19 clk_cnt<=26‘d0;
20 clk_tmp<=~clk_tmp;
21 end
22 else
23 clk_cnt<=clk_cnt+1‘b1;
24 end
25 end
26
27 always@(posedge clk_tmp or negedge rst)
28 begin
29 if(!rst)
30 temp<=4‘d15;
31 else
32 temp<=temp+1‘b1;
33 end
34
35 always@(temp)
36 begin
37 case(temp)
38 4‘d0 :led<=8‘b11111110;
39 4‘d1 :led<=8‘b11111100;
40 4‘d2 :led<=8‘b11111000;
41 4‘d3 :led<=8‘b11110000;
42 4‘d4 :led<=8‘b11100000;
43 4‘d5 :led<=8‘b11000000;
44 4‘d6 :led<=8‘b10000000;
45 4‘d7 :led<=8‘b00000000;
46 4‘d8 :led<=8‘b00000001;
47 4‘d9 :led<=8‘b00000011;
48 4‘d10:led<=8‘b00000111;
49 4‘d11:led<=8‘b00001111;
50 4‘d12:led<=8‘b00011111;
51 4‘d13:led<=8‘b00111111;
52 4‘d14:led<=8‘b01111111;
53 4‘d15:led<=8‘b11111111;
54 default:;
55 endcase
56 end
57
58 endmodule

  上面是一段流水灯的代码,控制8位流水灯依次点亮,再依次熄灭。第一个always语句完成分频功能,第二个always语句用于计数,共16个值,第三个always语句根据计数的值选择LED灯的状态。其中clk、rst分别为时钟和复位信号,led为驱动流水灯的输出信号。接下来针对这一设计编写其TestBench文件。

 1 /************TestBench*************/
2 module tb_led_run;
3 reg clk,rst;
4 wire led;
5
6 initial
7 begin
8 rst=1;
9 #30 rst=0;
10 #40 rst=1;
11 end
12
13 initial
14 begin
15 clk=1;
16 forever #20 clk=~clk;
17 end
18
19 led_run led1(.clk(clk),.rst(rst),.led(led));
20 endmodule

  由于只需要时钟和复位信号即可,故在其仿真文件并不复杂,建立测试模块,进行信号声明,在两个initial中分别提供clk和rst信号,最后进行例化。当然注意一点,在仿真时要把分频模块去掉,或者将分频系数改小,否则仿真时不容易观察波形。下面是在Modelsim中仿真得到的波形(分频模块改为2分频)。

  总结起来,Verilog的TestBench有着相对固定的写法:

module test_bench;
端口声明语句

initial
begin
产生时钟信号
end

initial
begin
提供激励源
end

例化语句
endmodule

  最主要的是在initial语句中进行激励的生成,这要根据具体的设计来分析。

  下面对比介绍VHDL语言TestBench的写法。同样的功能,驱动流水灯,VHDL的程序如下:

 1 LIBRARY IEEE;
2 USE IEEE.STD_LOGIC_1164.ALL;
3 USE IEEE.STD_LOGIC_UNSIGNED.ALL;
4
5 ENTITY led_run IS
6 PORT(clk:in std_logic;
7 rst:in std_logic;
8 led:out std_logic_vector(7 downto 0):="11111111" );
9 END led_run;
10
11 ARCHITECTURE arc_led_run OF led_run IS
12 signal temp:std_logic_vector(3 downto 0);
13 signal clk_cnt:std_logic_vector(25 downto 0);
14 signal clk_tmp:std_logic:=‘1‘;
15 BEGIN
16 divider:PROCESS(clk,rst)
17 BEGIN
18 if(rst=‘0‘) then
19 clk_cnt<="00000000000000000000000000";
20 elsif(clk‘event and clk=‘1‘) then
21 clk_cnt<=clk_cnt+1;
22 if(clk_cnt="11111111111111111111111111") then
23 clk_cnt<="00000000000000000000000000";
24 clk_tmp<=NOT clk_tmp;
25 end if;
26 end if;
27 END PROCESS;
28
29 PROCESS(clk_tmp,rst)
30 BEGIN
31 if(rst=‘0‘) then
32 temp<="1111"; --all the led off
33 elsif(clk_tmp‘event and clk_tmp=‘1‘) then
34 temp<=temp+1;
35 end if;
36 END PROCESS;
37
38 PROCESS(temp)
39 BEGIN
40 case temp is
41 when"0000"=>led<="11111110";
42 when"0001"=>led<="11111100";
43 when"0010"=>led<="11111000";
44 when"0011"=>led<="11110000";
45 when"0100"=>led<="11100000";
46 when"0101"=>led<="11000000";
47 when"0110"=>led<="10000000";
48 when"0111"=>led<="00000000";
49 when"1000"=>led<="00000001";
50 when"1001"=>led<="00000011";
51 when"1010"=>led<="00000111";
52 when"1011"=>led<="00001111";
53 when"1100"=>led<="00011111";
54 when"1101"=>led<="00111111";
55 when"1110"=>led<="01111111";
56 when"1111"=>led<="11111111";
57 when others=>NULL;
58 end case;
59 END PROCESS;
60
61 END arc_led_run;

  根据语法要求,首先声明库,接着定义实体和结构体。在结构体中用三个进程(PROCESS)分别实现分频、计数、流水灯状态分配的功能,功能相当于上面Verilog程序中的三个always语句。接下来写TestBench文件:

 1 ---------------TestBench-----------------
2 LIBRARY IEEE;
3 USE IEEE.STD_LOGIC_1164.ALL;
4
5
6 ENTITY tb_led_run IS --空实体
7 END tb_led_run;
8
9
10 ARCHITECTURE arc_tb_led_run OF tb_led_run IS --结构体
11
12 COMPONENT led_run IS --元件声明
13 PORT(clk:in std_logic;
14 rst:in std_logic;
15 led:out std_logic_vector(7 downto 0));
16 END COMPONENT;
17
18 signal clk,rst:std_logic;
19 signal led:std_logic_vector(7 downto 0);
20 constant clk_period:time:=5 ns;
21
22 BEGIN
23
24 DUT:led_run PORT MAP(clk=>clk,rst=>rst,led=>led); --元件例化
25
26 clk_gen:PROCESS
27 BEGIN
28 clk<=‘1‘;
29 wait for clk_period/2;
30 clk<=‘0‘;
31 wait for clk_period/2;
32 END PROCESS;
33
34 tb:PROCESS
35 BEGIN
36 rst<=‘0‘;
37 wait for 12 ns;
38 rst<=‘1‘;
39 wait;
40 END PROCESS;
41
42 END arc_tb_led_run;

  在这个TestBench中同样只需要提供clk和rst信号,分别在两个进程实现,Modelsim中的仿真结果如下(同样在仿真的时候将分频系数改为2):

  总结一下,VHDL的TestBench写法也有相对固定的格式:

library ieee;                              --库声明
use ieee.std_logic_1164.all;

entity test_bench is --测试平台文件的空实体(不需要端口定义)
end test_bench;

architecture tb_behavior of test_bench is --结构体
component entity_under_test --被测试元件的声明
port(
list-of-ports-theri-types-and-modes
);
end component;

begin
instantiation:entity_under_test port map --元件例化
(
port-associations
);

process() --产生时钟信号
……
end process;

process() --产生激励源
……
end process;

end tb_behavior;

  相对与Verilog语言来说,VHDL的TestBench除了自身的库声明以及Entity和Architecture之外,还需要进行元件的声明,即将被测试的设计声明为一个元件,然后对其例化。在激励的产生方面与Verilog思路相同。 

  从上面的程序可以看出,Verilog语言相对比较随意一些,从C语言编程中继承了多种操作符和结构;而VHDL的语法则比较严谨,有固定的格式。但在功能的实现上二者大同小异。比如Verilog中的always语句,在VHDL中可以找到PROCESS与之对应,当然更多的是不同。两种语言均可在不同的抽象层次对电路进行描述:系统级、算法级、寄存器传输级、逻辑门级和开关电路级,但是VHDL更擅长系统级,而Verilog更方便底层描述。在学习硬件描述语言的时候不妨对比学习一下,相信会对电路设计的理解更加深一层。

VHDL与Verilog硬件描述语言TestBench的编写,码迷,mamicode.com

时间: 2024-10-12 21:38:57

VHDL与Verilog硬件描述语言TestBench的编写的相关文章

WSDL(WebService描述语言)文件介绍

一.WSDL 1.WSDL 文档的组成部分 <portType>:web service 执行的操作 <message>:web service 使用的消息 <types>:web service 使用的数据类型 <binding>:web service 使用的通信协议  2.WSDL元素介绍 WSDL规范为了不会产生歧义,定义了特有名词来表述功能与服务. <portType> :<portType>元素是最重要的 WSDL 元素.

使用C语言为python编写动态模块(1)--从底层深度解析python中的对象以及变量

楔子 我们知道可以通过使用C语言编写动态链接库的方式来给python加速,但是方式是通过ctypes来加载,通过类CDLL将动态链接库加载进来得到一个对象之后,通过这个对象来调用动态链接库里面的函数.那么问题来了,我们可不可以使用C语言为python编写模块呢?然后在使用的时候不使用ctypes加载动态库的方式,而是通过python的关键字import进行加载. 答案是可以的,我们知道可以通过编写py文件的方式来得到一个模块,那么也可以使用C语言来编写C源文件,然后再通过python解释器进行编

每天一点GO语言——Linux环境下安装Go语言环境以及编写Go语言程序初体验

每天一点GO语言--Linux环境下安装Go语言环境以及编写Go语言程序初体验 一.安装Go语言环境 [[email protected] opt]# yum -y install wget git [[email protected] opt]# wget -c https://studygolang.com/dl/golang/go1.10.3.linux-amd64.tar.gz [[email protected] opt]# tar -zxvf go1.10.3.linux-amd64

用verilog来描述组合逻辑电路

1,什么是组合逻辑电路? 逻辑电路在任何时刻产生的稳定的输出信号仅仅取决于该时刻的输入信号,而与过去的输入信号无关,即与输入信号作用前的状态无关,这样的电路称为组合逻辑电路. 上图给出了一个典型的数字逻辑电路模型,其中的输入信号为X={X1,...,Xn},Y={Y1,...,Yn}为对应的输出信号,输入与输出的关系可以表示为:Y=F(X). 2,组合逻辑电路有哪些特点? 组合逻辑电路具有两个特点: (1).由逻辑门电路组成,不含有任何的记忆元件: (2).电路是单向传输的,电路中不存在任何反馈

从硬件到语言,详解C++的内存对齐(memory alignment)

转载请保留以下声明 作者:赵宗晟 出处:https://www.cnblogs.com/zhao-zongsheng/p/9099603.html 很多写C/C++的人都知道"内存对齐"的概念以及规则,但不一定对他有很深入的了解.这篇文章试着从硬件到C++语言.更彻底地讲一下C++的内存对齐. 什么是内存对齐(memory alignment) 首先,什么是内存对齐(memory alignment)?这个是从硬件层面出现的概念.大家都知道,可执行程序是由一系列CPU指令构成的.CPU

移位寄存器的设计(VHDL)及testbench的编写

移位寄存器是一种常用的存储元件,此处由D触发器构成,如下图所示. 当时钟边沿到来时,存储在移位寄存器的数据朝一个方向移动一个BIT位. 移位寄存器的功能主要为:串并转换,并串转换和同步延迟. vhdl代码如下: 1 library ieee; 2 use ieee.std_logic_1164.all; 3 4 entity shiftreg_rb is --实体说明及端口说明 5 port( 6 si,clr_bar,clk:in std_logic; 7 qout:buffer std_lo

数据结构:Binary and other trees(数据结构,算法及应用(C++叙事描述语言)文章8章)

8.1 Trees -->root,children, parent, siblings, leaf; level, degree of element 的基本概念 8.2 Binary Trees -->什么样的tree是Binary Tree 8.3. Properties of Binary Tree -->树的节点数与height的关系 -->full binary tree 到complete binary tree的概念 -->complete binary tr

使用C语言为python编写动态模块(2)--解析python中的对象如何在C语言中传递并返回

楔子 编写扩展模块,需要有python源码层面的知识,我们之前介绍了python中的对象.但是对于编写扩展模块来讲还远远不够,因为里面还需要有python中模块的知识,比如:如何创建一个模块.如何初始化python环境等等.因此我们还需要了解一些前奏的知识,如果你的python基础比较好的话,那么我相信你一定能看懂,当然我们一开始只是介绍一个大概,至于细节方面我们会在真正编写扩展模块的时候会说. 关于使用C为python编写扩展模块,我前面还有一篇博客,强烈建议先去看那篇博客,对你了解Pytho

使用C语言为python编写动态模块(3)--在C中实现python中的类

楔子 这次我们来介绍python中的类型在C中是如何实现的,我们在C中创建python的int对象,可以使用PyLong_FromLong.创建python的list对象可以使用PyList_New,那么如何在C中构建一个python中的类呢? 对于构建一个类,我们肯定需要以下步骤: 创建一个类扩展 添加类的参数 添加类的方法 添加类的属性,比如可以设置.获取属性 添加类的继承 解决类的循环引用导致的内存泄露问题和自定义垃圾回收 前面几个步骤是必须的,但是容易把最后一个问题给忽略掉.我们在pyt