文章目录
前言
一、简单的Verilog知识
1.1、Verilog端口定义
1.2、Verilog的标识符
1.3、Verilog的逻辑值
1.4、Verilog的数字进制
1.5、Verilog的数据类型
1.5.1、reg型
1.5.2、wire型
1.5.3、参数类型
1.6、Verilog的运算符
1.6.1、算术运算符
1.6.2、关系运算符
1.6.3、逻辑运算符
1.6.4、条件运算符
1.6.5、位运算符
1.6.6、移位运算符
1.6.7、拼接运算符
二、Verilog程序设计
2.1、Verilog程序框架搭建
2.2、Verilog程序注释
2.3、Verilog关键字
总结
前言
上文我们对Verilog语言有了一定的了解,知道了Verilog语言是一种硬件描述语言,他能够在EDA工具上综合成实际的电路,在FPGA或者单片机开发领域有着很高的地位。
我们学习一门语言,肯定需要学习它的语法结构,就像学习C语言一样,我们相应对某一事件重复操作,我们可以用for循环实现,这就是一种语法结构,弄清楚了会极大地提高我们的开发效率。Verilog语言的语法结构还是挺简单的,相信比其他语言来得容易。
下面我们看一端简单的代码来了解Verilog的端口定义基础知识:
module adder(
input [2:0] a ,
input [2:0] b ,
input cin ,output count ,
output [2:0] sum
);assign {count,sum} = a + b + cin;
endmodule
这个例子通过连续赋值语句描述了一个模块名为adder的三位加法器可以根据两个三比特数a、b和进位cin计算出和(sum)和进位(count)。
通过这个例子,一个模块由module开头,endmodule结束,紧跟着module后面的是模块名。模块名后面括号里面的是输入输出端口信号,input为输入端口,output为输出端口,中括号里面是位宽,当没有指定位宽时默认为32位宽,{}叫做位拼接运输符,中间用逗号隔开,后面我们会细讲。
标识符用于定义模块名、端口名和信号名等,上面代码里的adder就是一个标识符,也是模块名。Verilog的标识符可以是任意一组数字、字母、下划线等符号的组合,但是标识符的第一个字符必须是字母或者下划线。
标识符虽然可以任意定义,但是它是区分大小写的,比如Count和count就不是同一个标识符,这点需要注意。对于标识符的定义虽然没有限制,但是我们最好还是遵循一定的规则,以便于你以后回来对代码升级维护时一眼就能知道这个模块是干什么的。
关于标识符的规范,我这里有几个建议:
① 模块名定义最好见名知其意,定义的模块名最好和代码实现的功能相关,如sum等。
② 用下划线来隔开两个词组,看起来简单易懂,如cpu_addr就要比cpuaddr好很多。
③ 系统时钟和复位信号统一写法,系统时钟用clk,复位用rst_n。
④ 采用一些前缀或者后缀命名,如cnt_500ms、clk_50mhz等。
⑤ 参数统一大写,如TIME_SHOW。
⑥ 自定义的标识符不能与关键字同名。
逻辑电路中一般有4种逻辑值,表示4种逻辑状态:
逻辑 0:表示低电平,也就是对应电路中的接地(GND)。
逻辑 1:表示高电平,也就是对应电路中的电源(VCC)。
逻辑 X:表示未知态,有可能是高电平,也有可能是低电平。
逻辑 Z:表示高阻态,即表示一个悬空状态。
在Verilog语言中的进制格式主要有二进制、八进制、十进制和十六进制,一般我们常用的就是二进制、十进制和十六进制。
① 二进制:只有0和1两字符,满二进一,4’b0010表示4位二进制数字0010;
② 八进制:满八进一,4'o0011表示4位八进制数字0011;
③ 十进制:满十进一,4'd2表示4位十进制数字2;
④ 十六进制:满十六进1,4'ha表示4位十六进制数字a,十六进制的计数方式为0~f。
在进制换算中我们还需要注意:
① 换算为二进制后位宽的总长度 > 与数值进制符号对应的数值的实际位数时,则自动在与数值进制符号对应的数值的左边补0。如2'd10换算成二进制为4'b1010,则把2'd10补位为4'd0010。
② 换算为二进制后位宽的总长度 < 与数值进制符号对应的数值的实际位数时,自动截断与数值进制符号对应的数值左边超出的位数。
③ 数字中的下划线没有任何意义,只是为了提高可读性,如25_0000与250000相同。
在Verilog语法中,主要有三大数据类型,分别是寄存器类型,线网类型和参数类型。
寄存器是数据存储单元的抽象。寄存器数据类型的关键字是reg,通过赋值语句可以改变寄存器储存的值,但reg类型只能在always语句和initial语句中被赋值,并且它的值从一个赋值到另一个赋值过程中被保存下来。如果该过程语句描述的是时序逻辑,即always语句中带有时钟信号,则该寄存器变量对应为寄存器;如果该过程语句描述的是组合逻辑,即always语句中没有时钟信号,则该寄存器变量对应为硬件连线。寄存器类型的却省值是X,寄存器的数据类型有很多种,如reg、integer、real等,但我们常用的就是reg类型。
wire型数据常用来表示用于以assign关键字指定的组合逻辑信号。 线网类型表示Verilog结构化元件间的物理连线,它的值由驱动元件的值确定。如果没有驱动元件连接到线网,线网的缺省值为z(高阻态)。
所谓参数其实就是一个常量,我们在状态机定义、数据大小定义时都会用到参数,由于它可以在编译时修改参数的值,因此它又常被用于一些参数可调的模块中,使用户在实例化模块时,可以根据需要配置参数。
参数类型可以分为全局参数类型和局部参数类型,所谓全局参数类型是指该参数不仅在本模块中实用,在其他模块中还可以调用该参数。而局部参数类型就只在当前模块中有效。
Verilog HDL语言的运算符范围很广,运算符按其功能可分为:①算术运算符、②关系运算符、③逻辑运算符、④条件运算符、⑤位运算符、⑥移位运算符、⑦拼接运算符。
Verilog中的算术运算符有:+、-、*、/ 、%
算术运算符就是我们常说的加减乘除,数字逻辑处理有时候也需要进行数字运算,所以需要算术运算符。在Verilog语法中常用到了算术运算有+、-、*、/和%。值得注意的是,Verilog实现乘法和除法比较浪费逻辑资源,一般能进行移位的我们用移位替代。
Verilog中的关系运算符有:> 、< 、>= 、<= 、==、!=
关系运算符主要是用来做一些条件判断的,在进行关系运算符时,如果声明的关系是假的,则返回值0,如果声明的关系是真的,则返回值1;所有关系运算符都有着相同的优先级。
Verilog中的逻辑运算符有: ! 、&& 、 ||
逻辑运算符是连接多个关系表达式用的,可实现更加复杂的判断,一般不单独使用,都需要配合具体语句来实现完整的意思。
Verilog中的条件运算符有: ?:
条件运算符一般用来构建从两个输入中选择一个作为输出的条件选择结构,功能与always中的if - else语句差不多。
Verilog中的位运算符有:~、&、|、^
位运算符是一类基本的运算符,可以把他们当成与、或、非逻辑门看待。
Verilog中的移位运算符有:<< 、>>
移位运算符包括左移运算符和右移运算符,左移运算符相当于乘法,右移运算符相当于除法。如果a = 8‘b00000011,将其左移两位得a = 8'b00001100。
Verilog中的位拼接运算符有:{}
这是C语言中所不具备的运算符,假设有两个4bit的数a = 4'b0011 和 b = 4'b1100,则将其进行位拼接为{a,b} = 8'b00111100。
在Verilog语法中,运算符也是有优先级的,下面是verilog中的运算符优先级表格:
在经过上面是基本知识点的介绍之后,我们对Verilog语法也有了一定的了解。那么我们利用Verilog进行程序设计的话也是有一定的框架的,有了这个框架,可以极大地提高我们的代码可读性和可移植性,对别人学习你的代码也是非常友好的。但这样的框架结构并不是唯一的,下面是我常用的程序框架。
我个人是习惯用这样的框架来编写程序的,首先是输入输出定义,然后是需要用到的参数,后续需要修改参数的话也是很方便的,接下来就是状态机参数定义(如果需要用到状态机),然后是需要用到的中间信号定义。接下来就是程序的主体部分了,主体部分也是先写状态机,然后写满足状态机的条件(计数器以及其他条件),最后写输出。
作为一个程序设计者,必要的程序注释还是要有的,注释不仅仅是为了给别人看,而是让自己一眼明了该程序的功能,如果你长时间没有去接触这个程序,那么有可能这个程序所实现的功能你也会忘记,就算你自己会弄明白,但也要花费一定的时间,但如果我们对程序写一些中文或者英文注释,那么我们一眼就能看出这个程序是干什么的了。
在Verilog语言中,程序的注释可分为单行注释和多行注释,如果是对单行注释,那么只需要注释符号 // 后的全都是注释的内容;如果是多行注释,就像上面框架那样,那么注释符号 /* */内的是注释内容。
Verilog语言和C语言一样,都因编写需要定义一些关键字,这些关键字是识别语法的关键。所以我们在对模块或者信号进行命名时不要与所保留的关键字一样。下面是Verilog语法中所有的关键字。
看到这么多关键字,是不是人都傻了!但是别慌,虽然有这么多关键字,但是我们刚开始实际用到的并不多,等你全部都能用上的时候,你已经是这个领域的大佬级人物了。下面我就来盘点一些我们经常用到的关键词,其实没几个。
1、module(模块开始定义),2、endmodule(模块结束定义),3、input (输入端口定义),4、output(输出端口定义),5、inout(双向端口定义),6、parameter(参数定义),7、wire(wire型信号定义),8、reg(reg型信号定义),9、always (产生reg信号语句关键字),10、assign(产生wire信号语句关键字),11、begin....end (相当于括号),12、posedge/negedge(时序电路标志),13、case(Case语句开始标志),14,endcase(Case语句结尾标志),15、default(Case语句默认分支标志),16、if ....else(if/else语句),17、for(for语句标志)。
注意保留关键字全部都是小写哦!!!!!
这篇文章总结了一些Verilog语法中最基础的一些东西,也对Verilog程序设计框架做了简单的介绍,总体来说还是比较简单的。如果大家需要用到其他的关键字,还是得去看一看Verilog语法相关的书籍,书上讲的肯定要详细一点的,我这里只是简单总结一下。