一、Verilog_HDL模型
所谓不同的抽象类别,实际上是指同一个物理电路,可以在不同层次上用Verilog语言来描述。如果只从行为功能的角度来描述某一电路模块,就称作行为模块。如果从电路结构的角度来描述该电路模块,就称作结构模块。根据抽象的级别将Verilog的模块分为5种不同的等级:
(1)系统级(system-level):用语言提供的高级结构能够实现待设定模块的外部性能的模型;
(2)算法级(algorithm-level):用语言提供的高级结构能够实现算法运行的模型;
(3)RTL级(register transfer level):描述数据在寄存器之间的流动和如何处理、控制这些数据流动的模型;
(4)门级(gate-level):描述逻辑门以及逻辑门之间连接的模型,与逻辑电路有明确的关系;
(5)开关级(switch-level):描述器件中三极管和存储节点以及他们之间连接的模型,与具体的物理电路有对应关系;
系统级、算法级和RTL级属于行为级描述,只有RTL级才与逻辑电路有明确的对应关系;门级属于结构级描述。
二、模块结构
verilog的基本设计单元是模块(block),一个模块是由两部分组成,一部分描述接口,另一部分描述逻辑功能,即定义输入如何影响输出。
verilog结构位于module和demodule声明语句之间,每个verilog程序包括端口定义、I/O口说明、内部信号声明与功能定义。
2.1 模块的端口定义:module 模块名(端口1,端口2,......)
2.2 模块引用的端口连接
(1)严格按照端口顺序进行连接,不用表明原模块定义时规定的端口名称;
模块名(连接端口1信号名,连接端口2信号名,连接端口3信号名,...)
(2)用端口名与被引用模块的端口相对应,而不必严格按照端口顺序对应;
模块名(.端口1名(信号1名),.端口2名(信号2名),...)
我建议在FPGA开发设计中使用第(2)种端口连接方式。
2.3 模块功能定义
(1)assign语句(连续赋值语句):wire变量,不能是reg变量
(2)实例元件引用:键入元件的名字和相连的引脚,例如:and #2 u1(q, a, b);
(3)always块,例如:always @(posedge clk or negedge rst)
assign语句是用来描述组合逻辑,always语句既可以用来描述组合逻辑,也可以描述时序逻辑。
在verilog模块中的所有过程块(如:initial块、always块)、连续赋值语句、实例引用都是并行的,他们表示的是一种通过变量名互相连接的关系。在同一个verilog模块文件中,assign语句、实例元件、always块都是同时执行的,并发的,这三者出现的先后次序无关。两个或多个always模块同时执行,而每个模块内部的语句是顺序执行。只有连续赋值语句assign和实例引用语句可以独立于过程块而存在于模块功能定义部分。
三、verilog数据类型
数据类型用来表示数字电路硬件中的数据储存和传送元素,Verilog HDL中一共有19种数据类型。
4个基本数据类型:reg型, wire型, integer型, parameter型;
其他类型为:large型, medium型, scalared型, time型, small型, tri型, trio型, tril型, triand型, trior型, trireg型, vectored型, wand型, wor型。
3.1 常量
3.1.1 数字
在Verilog HDL中,整数常量共有4种进制表示形式:二进制(b或B)、十进制(d或D)、十六进制(h或H)和八进制(o或O).
数字表达方式有3种:
(1)<位宽><进制><数字>,比较全面的描述方式;
(2)<进制><数字>,数字的位宽采用默认位宽(由具体的机器系统决定);
(3)<数字>,采用默认进制(十进制)。
在表达式中,位宽指定了数字的精确位数。
(4)x和z值。x代表不定值,z代表高阻值,一个x可用来定义十六进制数的4位二进制的状态,八进制数的3位,二进制数的1位;z的表达与x类似,另外,z有另外一种表示形式,可以写作 “?”,尤其在case语句中可以提高程序的可读性。
例如:8‘h4x //位宽为8的十六进制数,其低4位为不定值
(5)负数:可以定义为负数,在数字表达式最前面(位宽之前)加一个减号。
3.1.2 参数型(parameter)
在Verilog HDL中,用parameter定义一个标识符代表常量,称为符号常量,其说明格式如下:
parameter 参数名1 = 表达式,参数名2 = 表达式,...
其中,赋值语句的右边必须是常数表达式,即该表达式只能包含常数或之前定义的参数。
3.2 变量
3.2.1 wire型
wire型数据用来表示以assign关键字指定的组合逻辑信号,在Verilog HDL程序模块中,输入输出信号类型默认自动定义为wire型,wire型信号可以作为任意方程式的输入,或assign语句和实例元件的输出。
wire[n-1, 0] a1, a2,...,ai,//共有i条总线,每条总线内部有n条线路。
3.2.2 reg型
reg型数据常用来表示always模块内的指定信号,常代表触发器,在always模块内被赋值的信号必须定义为reg型,reg型数据的默认初始值为不定值x。reg型数据可以是整数,也可以是负数,但当一个reg型数据是一个表达式的操作数时,它的值被当作是无符号数,即正值。
3.2.3 memory型
memory型数据是通过扩展reg型数据的地址范围来生成的,其格式如下:
reg[7:0] mema[255:0] //定义一个名为mema的存储器,该存储器有256个8位存储器,该存储器地址范围为:0-255。
对存储器进行地址索引的表达式必须是常数表达式。
memory型和reg型数据类似,但有不同之处,如一个由n个1位寄存器构成的存储器组是不同于一个n位寄存器的。例如:
reg[n-1 : 0]rega; //一个n位寄存器
reg mema[n-1 : 0]; //n个1位寄存器构成的存储器组
另外,一个n位寄存器可以在一条赋值语句中进行赋值,而一个完整的存储器组则不可以。如果想对memory型数据进行读写操作,必须指定存储器数组地址,例如:
mema[3] = 0; //给mema中的第3个寄存单元赋值
四、运算符及其表达式
Verilog HDL语言中的运算符按功能可以分为以下几类:
(1)算术运算符(+, -, *, /, %),又称为二进制运算符;
(2)赋值运算符(=, <=);
(3)关系运算符(>, <, >=, <=);
(4)逻辑运算符(&&, ||, !);
(5)条件运算符(? : );
(6)位运算符(~, |, ^, &, ^~);
(7)移位运算符(<<, >>);
(8)拼接运算符({ });
(9)其他
这些运算符按其所带的操作数的个数可以分为3种:
(1)单目运算符(unaary operater): 可以带一个操作数,操作数放在运算符的右边; 例如:clock = ~clock;
(2)双目运算符(binaryoperater): 可以带两个操作数,操作数放在运算符的两边; 例如: c = a|b;
(3)三目运算符(ternary operater): 可以带三个操作数,这三个操作数用三目运算符分隔开; 例如:r = s?t:u;
4.1 算术运算符
共有以下几种:
(1)+ (加法或正值运算符)
(2) - (减法或负值)
(3)* (乘)
(4)/ (除)
(5)% (模或求余运算)
在进行整数除法运算时,结果要略去小数部分,只取整数部分;而进行取模运算时,结果的符号位采用模运算式中第一个操作数的符号位,如下例:
模运算表达式 结果 说明
10%3 1 余数为1
11%3 2 余数为2
12%3 0 余数为0,即无余数
-10%3 -1 结果取第一个操作数的符号位,所以余数为-1
11%3 2 结果取第一个操作数的符号位,所以余数为2
在进行算术运算操作时,如果某一个操作数有不确定的值x,则整个结果也为不定值x。
4.2 位运算符
在硬件电路中,信号有4种状态值,即1,0,x,z。在电路中信号进行与、或、非时,反映在Verilog HDL语言中则是响应的操作数的位运算,Verilog HDL中一共有5种位运算符:
(1)~ //取反
(2)& //按位与
(3)| //按位或
(4)^ //按位异或
(5)^~ //按位同或(异或非)
除取反运算符之外,其他几个位运算符均是双目运算符。
不同长度的数据进行位运算时,系统会自动按照右对齐方式,位数少的操作数高位自动补零。
4.3 逻辑运算符
在Verilog HDL中,一共有3种逻辑运算符:
(1)&& 逻辑与
(2)|| 逻辑或
(3)! 逻辑非
“&&”和“||”是双目运算符,“!”是单目运算符。
逻辑运算符中的“&&”和“||”的优先级低于算数运算符,“!”优先级高于算术运算符。
4.4 关系运算符
在Verilog HDL中,一共有4种关系运算符:
(1)a
(2)a>b
(3)a<=b
(4)a>=b
所有的关系运算符具有相同的优先级,关系运算符的优先级低于算数优先级。
4.5 等式运算符
在Verilog HDL中,一共有4种等式运算符:
(1)==(等于)
(2)!=(不等于)
(3)===(等于)
(4)!==(不等于)
这四个运算符均是双目运算符,具有相同的优先级,(1)和(2)又称为逻辑等式运算符,(3)和(4)又称为case等式运算符,常用于case表达式的判别。
由于操作数的某些位可能是不定值x或高阻值z,(1)和(2)运算符运算的结果也可能是不定值x,(3)和(4)运算符则不同,它对操作数进行比较时对某些位的不定值x或高阻值z也进行比较,两个操作数必须完全一致,其结果才为1,否则为0。
等式运算符真值表如下:
=== | 0 | 1 | x | z | == | 0 | 1 | x | z |
0 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | x | x |
1 | 0 | 1 | 0 | 0 | 1 | 0 | 1 | x | x |
x | 0 | 0 | 1 | 0 | x | x | x | x | x |
zx | 0 | 0 | 0 | 1 | z | x | x | x | x |
4.6 移位运算符
在Verilog HDL中,一共有2种移位运算符:<<(左移位),>>(右移位)
这两种移位运算都是用0来填补移出的空位。
4'b1001 <<1 = 5'b10010; 4'b1001 <<2 = 6'b100100;
1<<6 = 32'b1000000; 4'b1001>>4 = 4'b0000;
4.7 位拼接运算符
位拼接运算符{ }可以把两个或多个信号的某些位拼接起来,在位拼接表达式中不允许存在没有指定位数的信号,因为在计算机中计算拼接信号位宽大小时必须知道其中每一个信号的位宽。
位拼接还可以用重复法或嵌套法来表示,例如:
{4{a}} 等价于 {a, a, a, a}
{b,3{a, b}} 等价于 {b, a, b, a, b, a, b}
4.8 缩减运算符
缩减运算时对单个操作数进行与或非递推运算,最后的运算结果是1位的二进制数。运算过程如下:第一步先将操作数的第1位与第2位进行与或非运算,第二步将运算结果与第3位进行与或非运算,以此类推,直至最后一位。
例如: reg[3:0] a; reg b; b = &a; 相当于 b = ((a[0]&a[1] )&a[2])&a[3];