参考书籍:《Verilog HDL 数字设计与综合》第二版,本文档为第二章的学习笔记。
主要讲解设计方法,理解数字电路设计中的基本的层次建模概念。
目录
前言
- 理解数字电路设计中自底向上和自顶向下的设计方法
- 解释Verilog中模块和模块实例之间的区别
- 从4中不同抽象角度描述同一模块
- 解释数字电路仿真中的各个组成部分,定义激励快和功能块
3.1 设计方法学
电路设计者通常使用开关级原语创建了一个底层功能块库。
逻辑设计者通常使用自顶向下的方法将整个设计分解为库单元构成的结构描述。
在FPGA开发过程中通常使用自顶向下的设计方法。
3.2 模块
3.2.1 模块构成
module <模块名> ( <模块端口列表> );
...
<模块的内容>
...
endmodule
Verilog既可以进行行为级描述,也可以进行结构级描述,故在每个模块内部可以在4个抽象层次中进行描述,模块对外功能都是一样的,仅与外部环境有关,而与抽象层次无关。(黑箱)
抽象层次定义:
- 行为或算法级:只注重实现的算法,不关心 其具体的硬件实现细节。(与c语言类似)
- 数据流级:通过在寄存器之间流动的数据流对模块进行描述。(FPGA开发主要使用的层级)
- 门级:从组成电路的逻辑门及相互之间的关系的角度来设计模块(类似于门级逻辑电路)
- 开关级:最底的层级,使用开关、存储节点及其互连关系设计模块(必须有较好的开关功底)
一般来说,抽象层次越高,那么设计的灵活性和工艺无关性就越强 ;随着抽象层级的降低,灵活性和工艺无关性逐渐变差,微小调整都可能导致对设计的多处修改。
在数字电路设计中,术语寄存器传输级(RTL)描述在很多情况下是指能够被逻辑综合工具接受的行为级和数据流级的混合描述。
3.2.2 模块实例
模块中不可以出现模块(即不允许模块嵌套)
对3.1中的四位脉动进位计数器进行,编写Verilog代码。
从模板创建对象的过程称实例化,创建的对象称实例。
//引用了4个T触发器
//定义名为ripple_carry_counter(脉动进位计数器)的模块
module ripple_carry_counter (q , clk , reset);
output [3:0] q ; //输出端口声明
input clk , reset ; //输入端口声明
//生成了4个T触发器T_FF的实例,每个实例都有自己的名字,每个实例都传递一组信号
//注意每个实例都是T_FF模块的副本
T_FF tff0 ( q[0] , clk , reset ) ;
T_FF tff1 ( q[1] , q[0] , reset ) ;
T_FF tff2 ( q[2] , q[1] , reset ) ;
T_FF tff3 ( q[3] , q[2] , reset ) ;
endmodule
//定义名为T_FF(T触发器)的模块,由于引用了D触发器,假设已经在别处定义
module T_FF ( q , clk ,reset );
output q ;
input clk , reset ;
wire d ; //声明网线变量d
D_FF dff1 ( q , d ,clk ,reset) ; //调用D_FF,取名为dff0
not n1( d , q) ; //非门(not)是Verilog语言内部原语部件
endmoudle
3.3 逻辑仿真
3.3.1 逻辑仿真构成
对设计的模块添加激励,通过检查其输出波形来验证功能的正确性。激励快有两种设计方法:
- 在激励块中调用(实例引用)并直接驱动设计块,顶层块即激励块
- 在一个虚拟的顶层块中调用(实例引用)激励快与设计块
在实际FPGA开发时多使用方法1 ,直接将顶层块作为激励块。
3.3.2 实例
3.3.2.1 设计块
module E2_6(
output [3:0] q ,
input clk , reset
);
//实例化脉动进位计数器
ripple_carry_counter RCC1 (q , clk , rest);
endmodule
//脉动进位计数噿
module ripple_carry_counter (q, clk, reset);
output [3:0] q ;
input clk , reset ;
//生成4个触发器(T_FF)的实例,并进行命名
T_FF tff0(q[0],clk,reset);
T_FF tff1(q[1],q[0],reset);
T_FF tff2(q[2],q[1],reset);
T_FF tff3(q[3],q[3],reset);
endmodule
//触发器T_FF
module T_FF(q, clk, reset );
output q;
input clk , reset;
wire d; //网线型变釿
//实例化D触发噿
D_FF dff(q, d, clk, reset);
not n1(d, q); //将q=~d
endmodule
//D触发器D_FF
module D_FF(q, d, clk, reset);
output q;
input d, clk, reset;
reg q; //寄存器型变量
//可以有许多新的结构但是不考虑
always @( posedge reset or negedge clk)
if(reset)
q <= 1'b0;
else
q <= d;
endmodule
3.3.2.2 激励块
module tb_E2_6();
reg clk;
reg reset;
wire [3:0] q;
//引用已经设计好的模块实例
E2_6 E1 (q, clk, reset);
//控制驱动设计块的始终信号,时钟周期为10个时间单使
initial
clk = 1'b0;
always
#5 clk = ~clk; //沿5个时间单位反转一欿
//控制驱动设计块的reset信号
initial
begin
reset = 1'b1;
#15 reset = 1'b0;
#180 reset = 1'b1;
#10 reset = 1'b0;
#20 ; //终止仿真
end
//监视输出
initial
$monitor ($time, " Output q = %d", q);
endmodule
使用Vivado软件进行编程仿真,结果如下;