这学期的数电课进行了很大的改革,要求学生使用FPGA开发板进行课内实验,还有专门的数电实验课,课程结束后还有为期两周的课程设计,近几年,由于深度学习、异构计算等的兴起,FPGA的地位也是显著上升,FPGA强大的并行计算能力决定了它极高的上限,当然对设计人员的要求也是很高的。本来我是不怎么想学FPGA的,但是学校这么安排,而且自己看了看也觉得有点意思,所以学一学也是挺不错的,说不定会有什么用处呢。
与C的区别
Verilog是硬件描述语言,在编译下载到FPGA后会生成电路,是并行运行的
C的软件编程语言,编译下载到单片机后是存储器中的一组指令,串行执行
逻辑值:0,1,x,z
b,o,d,h 二 八 十 十六
4'd2表示二进制数2(4位宽)
注意:位宽为2进制的位宽,不指定的话为32位位宽,直接写数默认是32位十进制数
可以加下划线提高可读性16'b1001_1010_1010_1001=16'h9AA9
定义变量、模块名、信号名
字母、数字、$、_组合而成 首字母是数字或_ 区分大小写
推荐写法:大小写不混写、普通内部信号小写、命名体现含义
三大类:寄存器、线网、参数
前两者在数字电路中真正起作用
寄存器类型
抽象的数据存储单元,可以通过赋值语句改变寄存器存储的值,关键字reg,reg类型的默认初始值x
reg类型只能在always和initial语句中被赋值
如果该过程语句描述的是时序逻辑,即always语句带有时钟信号,则该寄存器变量对应为触发器
如果是组合逻辑,即不带时钟信号,则该寄存器变量对应为硬件连线
不给位宽默认为1
注意:定义时不能赋值
reg[31:0] delay_cnt;//32位
reg key_reg;//1位
线网类型
结构实体(例如门)之间的物理连线
wire和tri类型,常用wire
不能存储值,值是由驱动它的值决定的
驱动元件:门、连续赋值语句、assign赋值语句
没有接驱动元件是高阻
wire key_flag;//一位,指定位数同上
参数类型
常量
parameter定义常量
parameter H_SYNC = 11'd41;
采用标识符代表一个常量可以提高程序可读性和可维护性
用于表示状态机状态、表示位宽、延迟大小
在模块调用中通过参数的传递改变调用模块汇总已定义的参数
1、算术运算符
同C
2、关系运算符
同C
3、逻辑运算符
同C
4、条件运算符
同C三目运算符
5、位运算符
^按位异或
~取反
&按位与
|按位或
位数小的前面补零补到位数相同进行操作
6、移位运算符
同C
不同点:左移时位宽增加,右移位宽不变
7、拼接运算符
{} {a,b} 将a,b拼接起来作为一个新信号
例:c={a,b[3:0]};
优先级排序和C类似单目到多目递增
两种,同C
常用关键字
基本的设计单元是模块block(类似C的函数)
模块由两个部分组成,一部分描述接口,一部分描述逻辑功能
可综合模块:能对应的实际电路
四个主要的部分:端口定义、IO说明、内部信号说明、功能定义
功能定义部分有三种方法:
1、assign语句
描述组合逻辑
2、always语句
描述组合/时序逻辑
3、例化实例元件
如:and #2 u1(q,a,b);
上述三种逻辑功能是并行的
在always块中,逻辑是顺序执行的,而多个always块之间是并行的
模块的调用
在模块调用时,信号通过模块端口在模块之间传递
以上为例化端口和端口连接的实例
注意输出daunt必须连接到一个wire类型的变量上去,变量传递时位宽要一致
另一种端口连接方式(不推荐,对顺序要求严格)
initial和always
initial
只执行一次,常用于测试文件的编写,用来产生仿真测试信号(激励信号),或者用于对存储器变量赋初值
always
语句一直在不断地重复活动,但是只有和一定的时间控制结合在一起才有作用
always的时间控制可以是沿触发也可以是电平触发,可以是单个信号也可以是多个信号,多个信号用or连接(敏感列表)
posedge上升沿 negedge下降沿
顺序块又叫过程块
沿触发的always块常用来描述时序逻辑
电平触发的always块常用来描述组合逻辑
如果组合逻辑块语句输入变量多,可以用*表示对后面语句块中所有的输入变量的变化都是敏感的
组合逻辑和时序逻辑是逻辑功能的不同
组合逻辑中,任意时刻的输出仅仅取决于该时刻的输入,与电路原来的状态无关
时序逻辑中,任意时刻的输出不仅取决于当时的输入信号而且还取决于电路原来的状态,或者说还与以前的输入有关,因此时序逻辑必须具备记忆功能
阻塞赋值 如b=a
阻塞幅值可以认为只有一个操作:计算RHS并更新LHS
所谓阻塞的概念是指在同一个always块中,后面的赋值语句是在前一句赋值语句结束后才开始赋值的
非阻塞赋值 如b <= a;
可以看成两个操作:赋值开始时计算RHS;赋值结束时更新LHS
概念是指在计算非阻塞赋值的RHS以及更新LHS期间,允许其他的非阻塞赋值语句同时计算RHS和更新LHS
只能用于对寄存器类型的变量进行赋值,因此只能用于initial块和always块等过程块中
在描述组合逻辑的always块中用阻塞幅值,这种电路结构只与输入电平的变化有关系
在描述时序逻辑的always块中用非阻塞赋值,这种电路结构往往与触发沿有关系,只有在触发沿时才可能发生赋值变化
注意:在同一个always块中不要即用非阻塞幅值又用阻塞幅值
不允许在多个块中对一个变量进行赋值
if-else语句(与C类似)
case语句
没有switch
分支表达式的值需要互不相同
所有表达式的位宽必须完全相等(不能用'bx等写法)
casez比较时不考虑表达式中的高阻态
casex不考虑高阻态和不定值