综合和仿真
1、Verilog描述出硬件功能后需要使用综合器对其代码进行解释并将代码转化为实际电路表示,也称为网表,该过程通过综合器完成。(Quartus、ISE、VIVADO)
2、仿真
在综合前先对代码进行仿真测试,最后在将程序烧写进FPGA。Verilog可以描述电路,也可以用于测试。大部分是用于仿真测试。
可综合设计
Verilog是描述硬件电路的,建立在硬件电路的基础上,有些语法结构是以仿真测试为目的,不能与实际硬件电路对应起来。使用这些语法的时候,将一个语法描述的程序映射成实际硬件电路中的结构是不能实现的——不可综合语法
综合就是把编写的RTL代码转换为对应的实际电路。EDA综合工具会去元件库里调用一个元件,将这些“逻辑”电路用“门”电路搭起来。即,编译RTL代码,从库里选择用到的门器件,把器件按逻辑搭建为门电路。
不可综合——找不到对应的门器件实现相应的代码。
模块结构——端口定义、参数定义、I/O说明、内部信号声明、功能定义
模块,Verilog基本描述单位,用于描述某个设计的功能或结构及与其他模块通信的外部接口。在概念上相当于器件,可以在一个模块中调用另一个模块,一个电路可以由多个模块组成。项目设计思想:模块套模块,自顶向下。
1、模块名和端口定义
模块的名字和输入输出口。模块以module开始,endmodule结束。模块名是模块的唯一标识符,命名时以模块的功能命名,模块名和文件名相同。模块的端口表示模块的输入输出口名,是与其他模块联系的标识。
module 模块名(端口1,端口2,。。。。);
2、参数定义
将常量用符号代替,以增加代码的可读性和可修改性。
parameter DATA_W = x;
3、接口定义
I/O说明,模块的接口可以是输入端口、输出端口或双向端口。
输入端口: input[信号位宽-1:0] 端口名1;
input[信号位宽-1:0] 端口名2;....
输出端口:output[信号位宽-1:0] 端口名1;
output[信号位宽-1:0] 端口名2;....
双向端口:inout[信号位宽-1:0] 端口名1;
inout[信号位宽-1:0] 端口名2;....
4、信号类型
这些信号是在模块内使用到的信号,并且与端口有关的wire和reg类型变量。信号类型默认wire,位宽为1。
reg[width-1:0] R 变量1,R 变量2.....;
wire[width-1:0] W 变量1,W 变量2....;
5、功能描述
逻辑功能的定义,
(1)assign声明语句; assign a = b&c.
(2)always块;
(3)模块例化;
6、模块例化
数字系统的设计一般采用自顶向下,将系统划分为几个功能模块,每个功能模块划分我为我下一层的子模块。每个模块对应一个module,module设计为一个Verilog HDL程序文件。
模块能够在另一个模块中被引用,建立描述的层次。形式:
module_nameinstance_name(port_association);
信号端口可通过位置或名称关联,但关联方式不可混用。关联形式:
port_expr //通过位置
.PortName (port_expr) //通过名称
在例化的端口映射中采用名字关联,实例化中,有些管脚未用到,可在映射中采用空白处理;
信号类型
主要两种信号类型:线网类型(net type)、寄存器类型(reg type)。信号的默认位宽为1,
位宽为1的wire型信号:wire a,位宽为8的信号:wire [7:0];信号的位宽取决于该信号的最大值。能表示的无符号数最大值:
-1,n表示位宽,
wire型:
对结构化器件之间的物理连线,不存储逻辑值,必须由器件驱动。通常用assign进行赋值,assign A = B ^ C。
wire型语法定义:
wire [msb: lsb] wire1,wire2, ...,wireN;
msb: lsb:定义了范围,位宽,8'b0---8'b1111_1111;必须为常数值;默认值为1位;默认为wire型。
reg型:
寄存器类型,用于对存储单元的描述,D型触发器、ROM等。寄存器型信号的特点:某种触发机制下分配了一个值,在下一触发机制到来之前保留原值。reg型变量不一定是存储单元,在always语句中进行描述的必须是用reg型的变量。
reg型语法:
reg [msb:lsb] reg1,reg2,...,regN;
wire与reg的区别:
reg信号不一定能生成寄存器,在本模块中使用always设计的信号都定义为reg型,其他信号均为wire型;
功能描述-组合逻辑
assign语句:
连续赋值语句,将一个变量的值不间断的赋值给另一个变量,两个变量之间类似于用导线连接,
assign语法:
assign a = b (逻辑运算符)c ...;
持续赋值;连线;对wire型变量赋值,wire是线网,相当于连接线,若要用assign直接连线,就用wire型变量,wire型变量的值随时发生变化。多条assign连续赋值语句之间相互独立、并行执行。
always语句
条件循环语句,执行机制是通过一个敏感变量表的事件驱动来实现,
语法格式:
always @(敏感事件)begin
程序语句
end
当敏感事件满足时,就执行一次“程序语句”。每满足一次,就执行一次程序语句。
当敏感信号很多时,“*”代替,*表示程序语句中所有的条件信号,a b d sel
时序逻辑:信号边沿触发的称为时序逻辑。
注意:只有放在敏感列表并边沿触发的才是时钟。放在敏感列表中边沿触发,且“程序语句”中先判断了rst_n的值,表示rst_n优先级最高,一般为复位信号。
设计时:
组合逻辑的always语句中敏感变量必须写全,或*代替;
组合逻辑器件的赋值采用阻塞赋值“=”,时序逻辑器件的赋值采用非阻塞赋值“<=”。
功能描述—时序逻辑
always语句
时序逻辑一般有:同步复位的时序逻辑、异步复位的时序逻辑。同步复位中复位不是立即有效,而是在时钟上升沿时复位才有效。代码结构:
always@(posedge clk) bengin
if(rst_n == 1'b0)
代码语句;
else begin
代码语句;
end
end
异步复位中复位立即有效,与时钟无关。代码结构:
always@(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0)
代码语句;
else begin
代码语句;
end
end
时钟
每个固定时间上下变化的信号,一次上升沿与相邻一次的上升沿相隔的时间为时钟周期,其倒数为时钟频率,1s---->1Hz。
阻塞赋值与非阻塞赋值
always语句中,Verilog支持两种类型的赋值:阻塞赋值(=)、非阻塞赋值(<=)。
阻塞赋值:在一个“begin...end”的多行赋值语句中,先执行当前行的赋值语句,在执行下一行的赋值语句。
非阻塞赋值:在一个“begin...end”的多行赋值语句中,同时并列执行每一行。
组合逻辑中应使用阻塞赋值“=”,时序逻辑中应使用非阻塞赋值“<=”。