FPGA笔记一
1. wire和reg基础知识:
- wire只能被assign连续赋值,reg只能在initial和always中赋值。wire使用在连续赋值语句中,而reg使用在过程赋值语句中。reg类型数据的默认值为不定值x , wire类型的变量没有连接到驱动元件上,则该变量就是高阻变量z。
- 输入端口可以由wire/reg驱动,但输入端口只能是wire;输出端口可以使wire/reg类型,输出端口只能驱动wire;若输出端口在过程块中赋值则为reg型,若在过程块外赋值则为net型。用关键词inout声明一个双向端口, inout端口不能声明为reg类型,只能是wire类型;输入和双向端口不能声明为寄存器类型。
2. inout特别说明:
- inout端口不能被赋值为reg型,因此,不能用于always语句中。
- if等条件语句只能用于initial语句及always语句。
- 因此,对于inout端口的逻辑判断,要用到?:条件表达式来控制高阻的赋值并结合assign进行。
- 需要有一个中转的寄存器,这样,在always语句中,才可以将输入的信号赋给输出(用inout代替纯output)
- 高阻态不要用于芯片内部,应该用逻辑引到引脚处,然后用高阻来实现。
- 三态门的介绍:
- 三态电路是一种重要的总线接口电路。这里的三态,是指它的输出既可以是一般二值逻辑电路的正常的“0”状态和“1”状态,又可以保持特有的高阻抗状态,第三种状态——高阻状态的门电路 (高阻态相当于隔断状态)。 处于高阻抗状态时,其输出相当于断开状态,没有任何逻辑控制功能。三态电路的输出逻辑状态的控制,是通过一个输入引脚 实现的。当G为低电平输入时,三态电路呈现正常的“0”或“1”的输出;当G为高电平输入时,三态电路给出高阻态输出。
3. assign和always描述组合逻辑的差别:
- verilog描述组合逻辑一般常用的有两种:assign赋值语句和always@(*)语句。差别如下:
-
always@(*)描述组合逻辑时,begin和end之间是串行执行;而用assign则是并行,相当于描述的是连线。
4. assign的使用:
- assign相当于连线,一般是将一个变量的值不间断地赋值给另一个变量,就像把这两个变量连在一起,所以习惯性的当做连线用,比如把一个模块的输出给另一个模块当输入。
- assign的功能属于组合逻辑的范畴,应用范围可概括为以下三点:
- 持续赋值;
- 连线;
- 对wire型变量赋值,wire是线网,相当于实际的连接线,如果要用assign直接连接,就用wire型变量。wire型变量的值 随 时变化。其实以上三点是相通的。
- 要更好的把握assign的使用,Verilog中有几个要点需要深入理解和掌握:
- 在Verilog module中的所有过程块(如initial块和always块)、连续赋值语句(如assign语句)和实例引用都是并行的。 在同一module中这三者出现的先后顺序没有关系。
- 只有连续赋值语句assign和实例引用语句可以独立于过程块而存在于module的功能定义部分。
- 连续赋值assign语句独立于过程块,所以不能在always过程块中使用assign语句。
5. 移位运算:
- ******特别注意:左移时,位宽增加;右移时,位宽不变。
- 空位用0补齐。
6. 什么时候用wire?什么时候用reg?
- 只要是always块内部的变量输出,都用reg类型。但是always块并不总是时序逻辑,有时是组合逻辑,所以reg型变量有时候可能实际上是线网类型的。
- 所谓寄存器类型就是暂存一个数据,保持数据不变,而输入数据的状态是变化的,只能用作wire型。由于输入信号是由模块外部决定的,与外部模块是通过线连接的,所以用wire,不用reg。输出信号也如此,与外部电路模块是通过导线连接的,所以用wire,不用reg。如果用了reg,这也就是寄存器会报错的原因。
- wire表示直通,即只要输入有变化,输出马上无条件地反映;reg表示一定要有触发,输出才会反映输入。
- wire使用在连续赋值语句中,而reg使用在过程赋值语句中。在连续赋值语句中,表达式右侧的计算结果可以立即更新表达式的左侧。在理解上,相当于一个逻辑之后直接连了一条线,这个逻辑对应于表达式的右侧,而这条线就对应于wire。在过程赋值语句中,表达式右侧的计算结果在某种条件的触发下放到一个变量当中,而这个变量可以声明成reg类型的。
- 在设计中,输入信号一般来说你是不知道上一级是寄存器输出还是组合逻辑输出,那么对于本级来说就是一根导线,也就是wire型。而输出信号则由你自己来决定是寄存器输出还是组合逻辑输出,wire型、reg型都可以。但一般的,整个设计的外部输出(即最顶层模块的输出),要求是寄存器输出,较稳定、扇出能力也较好。
- 用关键词inout声明一个双向端口, inout端口不能声明为reg类型,只能是wire类型;
7. 什么时候用阻塞赋值(=)?什么时候用非阻塞赋值(<=)?
- 用always块描述时序逻辑时用非阻塞赋值(<=)。
- 用always块描述组合逻辑时用阻塞赋值(=)。
- 用always块描述时序和组合混合逻辑时用非阻塞赋值(<=)。
- 避免在多个always块中对同一变量赋值。
- 赋值语句执行时,阻塞赋值的先计算右端表达式的值,然后立刻将值赋给左边变量;非阻塞赋值的也是先计算右端表达式的值,但是要等待延时后再将值赋给左边(同样因为D触发器)。
- 在串行语句中,阻塞赋值语句按照排列顺序依次执行;非阻塞赋值语句没有先后之分,并行执行,排在前面语句不影响后面语句。
8. 数组的使用
- reg [127:0] char[31:0]; 表示一个有32元素的一维数组,数组中的元素是位宽为128的变量。char[15] [120]; 前面的方括号表示是第几位的数组,后面的方括号表示的是值的第几位。
9. 实例元件
- 如:and and_d(q, a, b);
- 采用实例元件的方法和在电路图输入方式下,调入库元件是一样。在括号中键入元件的名字和相连的引脚即可,表示在设计中用到一个跟与门(and)一样的名为and_d的与门,其输入端为a, b,输出为q。注意要求每个实例元件的名字必须是不一样的,以避免与其他调用与门(and)的实例混淆。
10.负数表示
- 一个数字可以被定义为负数,只需在位宽表达式前加一个减号,减号必须写在数字定义表达式的最前面。注意减号不可以放在位宽和进制之间也不可以放在进制和具体的数之间。见下例:
- -5'd4 //合法格式
- 5'-d4 //非法格式
11.下划线(underscore_)
- 下划线可以用来分隔开数的表达以提高程序可读性。但不可以用在位宽和进制处,只能用在具体的数字之间。见下例:
-
16'b1010_1011_1111_1010 //合法格式 8'b_0011_1010 //非法格式
12.使用Parameter注意(参考https://zhuanlan.zhihu.com/p/72011463)
- 下面是一个多层次模块构成的电路,在一个模块中改变另一个模块的参数时,需要使用defparam命令
-
module Test; wire W; Top T ( ); endmodule module Top; wire W Block B1 ( ); Block B2 ( ); endmodule module Block; parameter P = 0; endmodule module Annotate; defparam Test.T.B1.P = 2, Test.T.B2.P = 3; endmodule
13. "按位异或"运算符^(也称之为XOR运算符)
- 按位异或运算就是将两个操作数的相应位进行异或运算。
- 其运算规则见下表:(行和对应的列进行按位异或,记忆方法就是按照字面意思去理解,只有两个数不同的时候才进行或运算。)
14. "按位同或"运算符^~
- 按位同或运算就是将两个操作数的相应位先进行异或运算再进行非运算.(记忆方法跟异或反着来就行了)
- 其运算规则见下表:
15."==="和"=="的区别
- "==="和"=="都表示等于,它们之间的区别如下表:
-
16.位拼接运算符
- 即把某些信号的某些位详细地列出来,中间用逗号分开,最后用大括号括起来表示一个整体信号。见下例:
-
{a,b[3:0],w,3’b101}
- 也可以写成为
-
{a,b[3],b[2],b[1],b[0],w,1’b1,1’b0,1’b1}
17.顺序块与并行块(begin...end与fork...join)
顺序块有以下特点:
- 块内的语句是按顺序执行的,即只有上面一条语句执行完后下面的语句才能执行。
- 每条语句的延迟时间是相对于前一条语句的仿真时间而言的。
- 直到最后一条语句执行完,程序流程控制才跳出该语句块。
并行块有以下四个特点:
- 块内语句是同时执行的,即程序流程控制一进入到该并行块,块内语句则开始同时并行地执行。
- 块内每条语句的延迟时间是相对于程序流程控制进入到块内时的仿真时间的。
- 延迟时间是用来给赋值语句提供执行时序的。
- 当按时间时序排序在最后的语句执行完后或一个disable语句执行时,程序流程控制跳出该程序块。
注意fork-join块是典型的不可综合语句,并且在一些仿真器时效率较差。
18.由于使用条件语句不当在设计中生成了原本没想到有的锁存器
- 如果用到if语句,最好写上else项。
- 如果用case语句,最好写上default项。
- 遵循上面两条原则,就可以避免发生这种错误,使设计者更加明确设计目标,同时也增强了Verilog程序的可读性。