Verilog的语法要素:数据类型、变量和基本运算符号
2.1 变量的数据类型
-
net(default)
▲网络数据类型net表示结构实体(如门)之间的物理连接,它不能储存值,而且必须受到驱动器的驱动。如无驱动器连接,则呈现高阻Z态。
-
wire(default)
单门驱动或连续赋值语句驱动的网络型数据。
常用来表示以assign关键字指定的组合逻辑信号。
-
tri
多驱动器驱动的网络型数据。
(多驱动源下,若无定义逻辑强度,逻辑值会发生冲突产生不确定值X)
wire [n-1:0] name1, name2, ... , namei; wire [n:1] name1, name2, ... , namei; wire name;
-
-
register
▲寄存器是数据储存单元的抽象,通过赋值语句可以改变寄存器储存的值,作用与改变触发器储存的值相当。
常用来表示always块内的指定信号,代表触发器。always块中被赋值的每一个信号都必须定义成reg型。reg被赋值如同一组触发器存储单元的值被改变。
reg [n-1:0] name1, name2, ... , namei; reg [n:1] name1, name2, ... , namei; reg rega;
默认初始值为x。可以赋正负值,但当该reg是一个表达式中的操作数时,被作为无符号数处理。
reg型只表示被定义的信号将用在always块内,虽常为寄存器、触发器的输出,但并非总是如此。
-
memory
Verilog通过建立reg型变量的数组来对存储器进行建模,描述RAM/ROM型存储器和reg文件。Verilog中不存在多维数组,memory型数据通过扩展reg型数据的地址范围来生成。
reg [n-1:0] mem1[m-1:0]; reg [n-1:0] mem2[m:1]; reg[7:0] mem[255:0]; //定义了一个名为mem的存储器,该存储器拥有256个8位存储器,地址范围是从0到255 reg [n-1:0] rega;//rega是一个n位的寄存器 rega = 0;//rega可以由一个赋值语句赋值 reg mema[n-1:0];//mema是一个由n个1位寄存器单元构成的存储器 mema[0] = 0; mema[1] = 0; ... mema[n-1] = 0;//mema必须一个一个单元地赋值
存储器的地址索引必须为常数表达式。
2.2 常量的不同表达
2.2.1 数字integer
-
整数:b d h o
表达方式:<位宽=default><进制=d><数字>
Eg. 8‘b10100100,2'h0a3,3'o455,4’d2435
注意,当仅有位宽被忽略时,即'b, 'd, 'o'等形式,数据默认位宽为当前机器的字节宽度,常为32位。
-
X与Z值:x代表不定值,z代表高阻值(也可写作?)
可以用于定义当前进制数的1位(如h下可表达1位十六进制数)。
-
负数:位宽前加减号
-
下划线:分割数的表达,提高可读性,无意义
2.2.2 参数parameter
定义一个标识符代表一个常量,即标识符形式的常量。提高可读性。格式如下:
parameter para1=3'b010, para2=4'd1432,...,paran=2'h6a;
parameter ave_delay = (r+f)/2;
常用于定义延迟时间和变量宽度,以及改变在被引用模块或实例中已定义的参数。如:
module Decode(A,F);
parameter Width=1, Polarity=1;
...
endmodule
module Top;
wire[3:0] A4;
wire[4:0] A5;
wire[15:0] F16;
wire[31:0] F32;
Decode #(4,0) D1(A4,F16);//w=4,p=0
Decode #(5) D2(A5,F32);//w=5
endmodule
在其他模块中,可以使用defparam语句来改变下层模块的参数,但一般情况下不可综合,因此建议尽量在实例时使用#()的方式来更改引用模块参数。
2.3 基本运算符号
按操作数个数: 有单目、双目、三目运算符,分别可带一个、两个、三个操作数。
按功能:
-
算术运算符+、-、×、/、%
加、减、乘、除、求余
整数除法结果值略去小数部分,取模运算符号位采用模运算式中第一个操作数的符号位。
-
赋值运算符=、<=
同一个always块中,只能全使用阻塞赋值或全使用非阻塞赋值。
https://blog.csdn.net/Reborn_Lee/article/details/82222665
-
非阻塞赋值<=:当前语句的执行不会阻塞下一语句的执行。
在块语句结束时才完成赋值操作,块内的赋值语句同时赋值。
可以看作两个步骤的过程:
赋值时刻开始时,计算非阻塞赋值右操作数表达式。
赋值时刻结束时,更新非阻塞赋值左操作数。
reg a=1, b=2, c=3, d=4; always @(posedge clk) { a <= b; b <= c; c <= d; }
并行,电路实现往往与触发沿有关,常被综合成时序逻辑电路。
-
阻塞赋值=:完成当前语句后才能做下一句的操作
在该语句结束时就完成赋值操作,块内的阻塞赋值语句顺序执行。
顺序执行,一般不能设定有延迟,常被综合成组合逻辑电路。
-
-
关系运算符>、<、>=、<=
-
逻辑运算符&&、||、!
&&和 || 是双目运算符,优先级低于算术运算符
! 是单目运算符,优先级高于算术运算符
(a>b) && (x>y) 相当于 a>b && x>y (a==b) || (x==y) 相当于 a==b || x==y (!a) || (a>b) 相当于 !a || a>b
-
条件运算符?:
-
位运算符~、|、^、&、^~
取反、或、异或、与、同或
//除相应双目位运算外还可用作单目运算符缩减运算 reg [3:0] A = 0101; reg B; B = &A; //相当于B = 0 & 1 & 0 & 1 //即将A的所有位进行位运算
-
移位运算符<<、>>
a>>n;//将操作数a左移n位 a<<n;//将操作数a右移n位 //注意:移位符进行的是补零移位 reg [3:0] s, r; s = 4'b1111;//s = 1111 r = (s<<2);//r = 1100
-
拼接运算符{ }
把两个/多个信号的某些位拼接起来运算。
a = 1'b0; b = 8'b11101100; c = 1'b1; //用法1 r = {a, b[3:0], c, 3'b101}; //此时r = 0 1100 1 101 //用法2 r = {4{a}}; //此时r = 0000 //嵌套用法 r = {b[7:5], {3{c,a}}}; //此时r = 111 101010
2.4 块语句
-
顺序块
begin 语句1; 语句2; end begin:block_name assignments; 语句1; 语句2; end
-
块内语句顺序执行,上一条语句志行完毕后下一条语句才能执行
-
每条语句的延迟时间是相对于前一条语句的仿真时间而言的(也就是说,顺序块内一条语句的延迟时间是指从前一条语句仿真完毕到当前语句仿真完毕的间隔)
-
直到最后一条语句执行完,程序流程控制才跳出该语句块。
-
-
并行块
-
块内语句同时执行,程序流程控制一进入到该并行块,块内语句则开始同时并行地执行,
-
块内每条语句的延迟时间是相对于程序流程控制进入到块内的仿真时间的(也就是说,并行块内一条语句的延迟时间是指从程序流程控制进入到块内到该条语句执行完毕的间隔;这个延迟时间是用来给赋值语句提供执行时序的),
-
当按延迟时间的时序中排在最后的语句执行完毕或一个disable语句执行时,程序流程控制跳出该程序块。
fork 语句1; 语句2; join fork:块名 assignments; 语句1; 语句2; end
-
-
块用法
-
块嵌套
块可以嵌套使用,顺序块可以和并行块混合嵌套在一起使用。initial begin statements; fork statement; join #delay statement; end endmodule
-
块命名
块可以具有自己的名字,命名块中可以声明局部变量,可以通过层次名引用进行访问;命名块可以被禁用。Verilog通过关键字disable提供一种中止命名块执行的方法。disable可用于退出循环、处理错误以及控制某些代码段的执行与否。//命名块的禁用例子 module MrBlock; begin:MrBlock i = 1; if(i==10) begin $display("MrBlock is a good block."); disable MrBlock;//此处跳出MrBlock end i = i + 1; end $display("But now he isn't.");
-