verilog学习笔记(一)
因为参与的新项目需要用fpga,所以自己学了一下verilog语言。整理一些比较基础的内容。
verilog程序最重要的结构就是模块module,它在形式上与c语言的函数很像,但是由于verilog是面向硬件的语言,因此在设计思想上与c语言是有一定的差别的。
一个verilog模块通常必须有的变量:clk时钟,rst置位,input输入,output输出
下面是一些verilog中常用的声明。
Parameter常量
Wire输入输出信号缺省时默认是wire,是assign关键字指定的组合逻辑信号
Wire [n:1] a1,...,ai 每个总线有n个线路,共i个总线
Reg 在always块里的指定信号,常代表触发器寄存器
Reg[4:1] a 一个4位的名为a的reg信号 编号从1到4由低位到高位
Reg变量可以是正数或负数,但是在运算时视为正数
如果需要中间赋值或运算,需声明成reg类型
一个verilog模块的主要结构如下
Module 模块名(端口列表); Wire reg 和其他类型声明; Assign数据流声明; Always initial块,行为语句 #verilog中各个always块都是并行执行的,不存在谁先谁后的关系 ... 任务和函数... ... Endmodule
always @(posedge clk) #上升沿到来时触发
verilog数据常量定义:
数字表达式:<位宽><进制><数字>
'b:二进制 4'b1110 表示4位二进制数1110
'h:十六进制 8'hef、4'ha
'd:十进制 2'd3、4'd15(不能写16,4位宽最大15)等
顶层程序调用底层module和c语言函数格式类似,通过module定义的端口传递参数,但是使用思想不同。
模组类名 实例名(端口变量)
端口变量尽量书写规范
.a(A) #.模组定义端口变量(实际变量)
Case语句的本质是分支比较,两个值的比较,若分支和case后面的值相等则运行相应分支语句,因此case后面的值可以是常值。
verilog文件开头一般有timescale
`timescale 仿真时间单位/时间精度
verilog基本运算:
verilog有两种赋值符号分别是<=和=。
<=是非阻塞赋值,在always块完成后才赋值;
=是阻塞赋值,赋值完成后才进入下一句;
一般时序逻辑用<=,组合逻辑用=。
~ 按位取反 比如:11110 取反后为00001
!逻辑取反 ,如!非0 为0 !0 为1
&&:代表逻辑与。
&:代表与门运算(按位与)。
^异或处理,对一个变量里面1的个数是奇数偶数的判断,偶数为0,奇数为1
实际是对该变量相邻位逐一求异或。
1 组合逻辑:
组合逻辑的特点是任意时刻的输出仅仅取决于该时刻的输入,与电路原本的状态无关,逻辑中不牵涉跳变沿信号的处理,组合逻辑的verilog描述方式有两种:
(1):always @(电平敏感信号列表)
always模块的敏感列表为所有判断条件信号和输入信号,但一定要注意敏感列表的完整性。在always 模块中可以使用if、case 和for 等各种RTL 关键字结构。由于赋值语句有阻塞赋值和非阻塞赋值两类,建议读者使用阻塞赋值语句“=”。always 模块中的信号必须定义为reg 型,不过最终的实现结果中并没有寄存器。这是由于在组合逻辑电路描述中,将信号定义为reg型,只是为了满足语法要求。
(2):assign描述的赋值语句。
信号只能被定义为wire型。
2 时序逻辑:
时序逻辑是Verilog HDL 设计中另一类重要应用,其特点为任意时刻的输出不仅取决于该时刻的输入,而且还和电路原来的状态有关。电路里面有存储元件(各类触发器,在FPGA 芯片结构中只有D 触发器)用于记忆信息,从电路行为上讲,不管输入如何变化,仅当时钟的沿(上升沿或下降沿)到达时,才有可能使输出发生变化。
与组合逻辑不同的是:
(1)在描述时序电路的always块中的reg型信号都会被综合成寄存器,这是和组合逻辑电路所不同的。
(2)时序逻辑中推荐使用非阻塞赋值“<=”。
(3)时序逻辑的敏感信号列表只需要加入所用的时钟触发沿即可,其余所有的输入和条件判断信号都不用加入,这是因为时序逻辑是通过时钟信号的跳变沿来控制的。
(*keep = "true"*)
有时候在chipscope中很难找到你预期的信号,这往往是被综合器优化掉了,或者更改了信号名.有效的方法是在源代码中加上约束语句,这样就不用对代码做大的改动.
fifo:
Fist in first out。先入先出的数据缓存器,没有外部读写地址线,可同时读写。
同步FIFO和异步FIFO。
同步FIFO只有一个时钟,也就是说写端和读端的时钟是一样的。
异步FIFO读端和写端两个时钟则是不一样的。包括同频异相,异频异相。
FIFO用途:
数据缓冲器。比如你写端burst一个数据,没有fifo缓冲的话就炸了。Fifo会把写端的突发数据缓存,读端可以慢慢的读出来。
跨时钟域。异步fifo主要使用在不同时钟域的边缘,用来同步数据到另一个时钟域。
对于异步读写时钟不同的fifo需要求fifo深度,深度是写需要的时间内读端没有读完的数据量(word),下面是在网上找到的一个比较好的解释fifo深度的例子