📅  最后修改于: 2020-11-22 17:16:53             🧑  作者: Mango
Verilog是一种硬件描述语言(HDL)。它是用于描述数字系统(如网络交换机或微处理器或存储器或触发器)的语言。这意味着,通过使用HDL,我们可以描述任何级别的任何数字硬件。 HDL中描述的设计独立于技术,非常易于设计和调试,并且通常比示意图更有用,尤其是对于大型电路。
Verilog支持许多抽象级别的设计。主要的三个是-
此级别通过并发算法(行为)描述系统。每种算法都是顺序的,这意味着它由一组指令组成,这些指令一个接一个地执行。功能,任务和块是主要元素。与设计的结构实现无关。
使用寄存器传输级别的设计使用操作和寄存器之间的数据传输来指定电路的特性。 RTL代码的现代定义是“任何可合成的代码都称为RTL代码”。
在逻辑级别内,系统的特征由逻辑链接及其时序属性描述。所有信号均为离散信号。它们只能具有确定的逻辑值(“ 0”,“ 1”,“ X”,“ Z”)。可用的操作是预定义的逻辑原语(基本门)。门级建模可能不是逻辑设计的正确想法。门级代码是使用诸如综合工具之类的工具生成的,其网表用于门级仿真和后端。
Verilog语言源文本文件是词汇标记流。令牌由一个或多个字符,每个单个字符恰好在一个令牌中。
Verilog HDL使用的基本词汇标记类似于C编程语言中的标记。 Verilog区分大小写。所有关键字均小写。
空格可以包含空格,制表符,换行符和换页符的字符。这些字符将被忽略,除非它们用于分隔标记。
空格字符是空格,制表符,回车符,换行符和换页符。
有两种形式代表评论
例如://这是单行语法
例如:/ *这是多行语法* /
您可以指定二进制,八进制,十进制或十六进制格式的数字。负数表示为2的恭维数。 Verilog允许使用整数,实数以及有符号和无符号数字。
语法由-
可以在
标识符是用于定义对象的名称,例如函数,模块或寄存器。标识符应以字母字符或下划线字符开头。例如A_Z,a_z,_
标识符是字母,数字,下划线和$字符。最长为1024个字符。
运算符是用于放置条件或操作变量的特殊字符。有一个,两个甚至三个字符用于对变量执行操作。
例如>,+,〜,&! =。
在Verilog中具有特殊含义的单词称为Verilog关键字。例如,分配,case,while,wire,reg和,or,nand和模块。它们不应用作标识符。 Verilog关键字还包括编译器指令以及系统任务和功能。
Verilog具有内置原语,例如逻辑门,传输门和开关。它们很少用于设计工作,但在后合成领域中用于ASIC / FPGA单元的建模。
门级建模具有两个属性-
驱动强度-输出门的强度由驱动强度定义。如果直接连接到源,则输出最强。如果通过导电晶体管进行连接,则强度会降低,至少在通过上拉/下拉电阻进行连接时,强度会降低。通常不指定驱动强度,在这种情况下,强度默认为Strong1和Strong0。
延迟-如果未指定延迟,则门不具有传播延迟;如果指定了两个延迟,则第一个代表上升延迟,第二个代表下降延迟;如果仅指定一个延迟,则上升和下降都相等。延迟在合成中可以忽略。
在Verilog中使用了一个输出和多个输入的基本逻辑门。 GATE使用一个关键字-和,nand或or或xor,xnor在Verilog中用于N个输入和1个输出。
Example:
Module gate()
Wire ot0;
Wire ot1;
Wire ot2;
Reg in0,in1,in2,in3;
Not U1(ot0,in0);
Xor U2(ot1,in1,in2,in3);
And U3(ot2, in2,in3,in0)
传输门原语包括缓冲区和反相器。它们具有单个输入和一个或多个输出。在下面显示的gate实例化语法中,GATE代表关键字buf或NOT gate。
示例:不,buf,bufif0,bufif1,notif0,notif1
否– n出逆变器
Buf – n输出缓冲区
Bufifo –三态缓冲器,低电平有效使能
Bufif1 –三态缓冲器,高电平有效使能
Notifo –三态逆变器,低电平有效使能
Notif1 –三态逆变器,高电平有效
Example:
Module gate()
Wire out0;
Wire out1;
Reg in0,in1;
Not U1(out0,in0);
Buf U2(out0,in0);
Verilog主要包含四个基本值。 Verilog中使用的所有Verilog数据类型都存储这些值-
0(逻辑零或错误条件)
1(逻辑1或真实条件)
x(未知逻辑值)
z(高阻抗状态)
x和z的使用在合成中非常有限。
导线用于表示电路中的物理导线,并且用于连接门或模块。导线的值只能读取,不能在函数或块中分配。导线无法存储值,但始终由连续的分配语句驱动,或通过将导线连接至门/模块的输出来驱动。其他特定类型的电线是-
Wand(有线与) -Wand的值取决于与其连接的所有设备驱动程序的逻辑与。
Wor(有线或) -Wor的值取决于与其连接的所有设备驱动程序的逻辑或。
Tri(三态) -此处连接到tri的所有驱动程序都必须是z,只有一个(确定tri的值)除外。
Example:
Wire [msb:lsb] wire_variable_list;
Wirec // simple wire
Wand d;
Assign d = a; // value of d is the logical AND of
Assign d = b; // a and b
Wire [9:0] A; // a cable (vector) of 10 wires.
Wand [msb:lsb] wand_variable_list;
Wor [msb:lsb] wor_variable_list;
Tri [msb:lsb] tri_variable_list;
reg(寄存器)是一个数据对象,它保存从一个过程分配到下一个过程分配的值,并且仅在不同的功能和过程块中使用。 reg是简单的Verilog变量类型寄存器,不能表示物理寄存器。在多位寄存器中,数据以无符号数字的形式存储,并且不使用符号扩展名。
示例-
reg c; //单个1位寄存器变量
reg [5:0] gem; // 6位向量;
reg [6:0] d,e; //两个7位变量
这些关键字用于声明任务或模块的输入,输出和双向端口。此处,输入和输出端口为线型,输出端口配置为线,reg,棒,wor或tri型。始终,默认为电线类型。
例
Module sample(a, c, b, d);
Input c; // An input where wire is used.
Output a, b; // Two outputs where wire is used.
Output [2:0] d; /* A three-bit output. One must declare type in a separate statement. */
reg [1:0] a; // The above ‘a’ port is for declaration in reg.
整数用于通用变量中。它们主要用于循环索引,常量和参数。它们是“ reg”类型的数据类型。它们将数据存储为带符号的数字,而显式声明的reg类型将它们存储为无符号的数据。如果在编译时未定义整数,则默认大小为32位。
如果整数保持常数,则合成器会将其调整为编译时所需的最小宽度。
例
Integer c; // single 32-bit integer
Assign a = 63; // 63 defaults to a 7-bit variable.
电源0定义连接到逻辑0(接地)的导线,电源1定义连接到逻辑1(电源)的导线。
例
supply0 logic_0_wires;
supply0 gnd1; // equivalent to a wire assigned as 0
supply1 logic_1_wires;
supply1 c, s;
时间是64位的数量,可以与$ time系统任务结合使用以保存模拟时间。不支持合成时间,因此仅用于仿真目的。
例
time time_variable_list;
time c;
c = $time; //c = current simulation time
参数定义了一个常数,可以在使用模块时设置该常数,该常数允许在实例化过程中自定义模块。
Example
Parameter add = 3’b010, sub = 2’b11;
Parameter n = 3;
Parameter [2:0] param2 = 3’b110;
reg [n-1:0] jam; /* A 3-bit register with length of n or above. */
always @(z)
y = {{(add - sub){z}};
if (z)
begin
state = param2[1];
else
state = param2[2];
end
这些运算符正在执行算术运算。 +和-用作一元(x)或二进制(z-y)运算符。
算术运算中包括的运算符为-
&加; (加法),-(减法),*(乘法),/(除法),%(模数)
示例–
parameter v = 5;
reg[3:0] b, d, h, i, count;
h = b + d;
i = d - v;
cnt = (cnt +1)%16; //Can count 0 thru 15.
这些运算符比较两个操作数,并以一位或1的位返回结果。
Wire和reg变量为正。因此(-3’d001)= = 3’d111和(-3b001)> 3b110。
关系运算中包括的运算符为-
例
if (z = = y) c = 1;
else c = 0; // Compare in 2’s compliment; d>b
reg [3:0] d,b;
if (d[3]= = b[3]) d[2:0] > b[2:0];
else b[3];
Equivalent Statement
e = (z == y);
在两个操作数之间进行逐位比较的按位运算符。
位操作中包括的运算符为-
例
module and2 (d, b, c);
input [1:0] d, b;
output [1:0] c;
assign c = d & b;
end module
逻辑运算符是按位运算符,仅用于单个位操作数。它们返回一个0或1的单个位值。它们可以处理整数或一组位,表达式,并将所有非零值都视为1。由于条件表达式使用逻辑运算符它们通常用于条件语句中。
逻辑运算中包含的运算符为-
例
wire[7:0] a, b, c; // a, b and c are multibit variables.
reg x;
if ((a == b) && (c)) x = 1; //x = 1 if a equals b, and c is nonzero.
else x = !a; // x =0 if a is anything but zero.
归约运算符是按位运算运算符的一元形式,并且对操作数向量的所有位进行运算。这些也返回一个单位值。
归约运算中包括的运算符为-
例
Module chk_zero (x, z);
Input [2:0] x;
Output z;
Assign z = & x; // Reduction AND
End module
移位运算符,用于将第一个操作数移位语法中第二个操作数指定的位数。空缺位置在两个方向(左移和右移)中都填充有零(没有使用符号扩展名)。
Shift操作中包含的运算符为-
例
Assign z = c << 3; /* z = c shifted left 3 bits;
空缺职位用0填充* /
串联运算符组合两个或多个操作数以形成较大的向量。
串联操作中包含的运算符为-{}(串联)
例
wire [1:0] a, h; wire [2:0] x; wire [3;0] y, Z;
assign x = {1’b0, a}; // x[2] = 0, x[1] = a[1], x[0] = a[0]
assign b = {a, h}; /* b[3] = a[1], b[2] = a[0], b[1] = h[1],
b[0] = h[0] */
assign {cout, b} = x + Z; // Concatenation of a result
复制运算符正在复制一个项目。
复制操作中使用的运算符是-{n {item}}(项的n倍复制)
例
Wire [1:0] a, f; wire [4:0] x;
Assign x = {2{1’f0}, a}; // Equivalent to x = {0,0,a }
Assign y = {2{a}, 3{f}}; //Equivalent to y = {a,a,f,f}
For synthesis, Synopsis did not like a zero replication.
For example:-
Parameter l = 5, k = 5;
Assign x = {(l-k){a}}
有条件的运算符合成一个多路复用器。它与C / C++中使用的类型相同,并根据条件评估两个表达式之一。
有条件操作中使用的运算符是-
(健康)状况) ? (如果条件为真则结果)-
(如果条件为假,则结果)
例
Assign x = (g) ? a : b;
Assign x = (inc = = 2) ? x+1 : x-1;
/* if (inc), x = x+1, else x = x-1 */
字面量是在Verilog表达式中使用的恒定值操作数。两种常用的Verilog字面量是-
字符串-字符串字面量操作数是一维字符数组,用双引号(“”)括起来。
数值-以二进制,八进制,十进制或十六进制数指定常数操作数。
例
n-表示位数的整数
F-四种可能的基本格式之一-
b代表二进制,o代表八进制,d代表十进制,h代表十六进制。
“time is” // string literal
267 // 32-bit decimal number
2’b01 // 2-bit binary
20’hB36F // 20-bit hexadecimal number
‘062 // 32-bit octal number
连线,regs和参数是在Verilog表达式中用作操作数的数据类型。
位选择和部分选择分别使用方括号“ []”从导线,reg或参数向量中选择一位和多位。位选择和部分选择也用作表达式中的操作数,其方式与使用它们的主要数据对象相同。
例
reg [7:0] x, y;
reg [3:0] z;
reg a;
a = x[7] & y[7]; // bit-selects
z = x[7:4] + y[3:0]; // part-selects
在函数调用,函数的返回值被直接用于表达,而不需要的第一将其分配给寄存器或导线。它只是将函数调用作为操作数类型之一。有必要确保您知道函数调用返回值的位宽。
Example
Assign x = y & z & chk_yz(z, y); // chk_yz is a function
. . ./* Definition of the function */
Function chk_yz; // function definition
Input z,y;
chk_yz = y^z;
End function
在Verilog中,模块是主要设计实体。这表示名称和端口列表(参数)。接下来的几行指定每个端口的输入/输出类型(输入,输出或输入输出)和宽度。默认端口宽度仅为1位。端口变量必须通过wire,wand等声明。 。 。,reg。默认端口变量是wire。通常,输入是有线的,因为它们的数据被锁存在模块外部。如果其信号存储在内部,则输出为reg类型。
例
module sub_add(add, in1, in2, out);
input add; // defaults to wire
input [7:0] in1, in2; wire in1, in2;
output [7:0] out; reg out;
... statements ...
End module
模块中的连续分配用于在导线上分配值,这是在Always块或初始块外部使用的常规分配。该分配是通过显式的assign语句完成的,或在其声明期间为电线分配值。连续分配在模拟时连续执行。 Assign语句的顺序不影响它。如果您对任何右侧输入信号进行了任何更改,它将更改左侧输出信号。
例
Wire [1:0] x = 2’y01; // assigned on declaration
Assign y = c | d; // using assign statement
Assign d = a & b;
/* the order of the assign statements does not matter. */
模块声明是用于创建实际对象的模板。模块是在其他模块内部实例化的,每个实例化都是从该模板创建单个对象。顶级模块是一个例外,它是自己的实例化。模块的端口必须与模板中定义的端口匹配。它指定-
按名称,使用点“ .template端口名称(连接到端口的电线名称)”。要么
按位置将端口放置在模板和实例的端口列表中的相同位置。
例
MODULE DEFINITION
Module and4 (x, y, z);
Input [3:0] x, y;
Output [3:0] z;
Assign z = x | y;
End module