下面是关于Verilog的好多好多细节. May it be helpful!
- Verilog是大小写相关的,关键词全部为小写
- 空白符(
\b \t 换行符
)仅用于分割标识符,在编译阶段被忽略 - 单行注释
//
多行注释/* */
(多行注释不允许嵌套) - 操作符包含单目、双目和三目
<size>'<base_format><number>
数字声明如果不指出基数,则为10- x表示不确定,z表示高阻
- 在位宽前加入
-
号表示负数 - 下划线只是提高可读性,在编译阶段会被忽略掉
- 问号表示高阻,不care。
4'b10??
相当于4'b10zz
- 字符串不能多行。将字符串当作单字节的ASCII字符列表
- 标识符由字母,数字,下划线和$,第一个字符必须是字母或下划线
- 0, 1, x, z
- 线网
wire
和寄存器reg
- 线网的默认值是z, 但trireg除外,为x(与reg类型相同)
- net不是一个关键词,包含
wire
,wand
,wor
,tri
,triand
,trireg
等 - 寄存器不需要驱动源,也不需要时钟信号,在仿真的任何阶段可直接赋值
- 寄存器也可signed
- 驱动由强到弱supply, strong, pull, large, weak, medium, small, highz
- 向量[#high:#low]与[#low:#high]以及[<starting_bit>+:width]从起始位开始,位宽为width
- integer, real, time. 注意只能仿真,而integer,real是一种通用寄存器数据类型
- integer是有符号数. reg是补码保存,取出来无符号,而integer一直有符号
- time最小64位 $time可得当前时间
- 注意数组的声明(在后边),与向量不同
- 存储器是reg的数组
- parameter与localparameter #(.N(_))重载
- 字符串保存在reg变量里面,如果位数不够则左面去掉
- $表示系统指令
- %d, %b, %B, %m(显示层次名), %v(显示强度), %e(科学计数), %T(时间)
- $monitor $display $stop(暂停结束仿真)
- `include和`define
include header.v
- module, 模块名,端口声明,可选参数声明,endmodule
- 模块内部五部分,变量声明、数据流语句、底层模块实例、行为语句块和任务函数
- input, output, inout
- reg, wire可以连input, 输出端口只能wire连接,input必须永远wire
- 允许不同位宽(模块调用),允许未连接(空开就行)
- 顺序连接,或者端口名连接(.b(B))
- 整个设计层次,每个标识符具有唯一的位置
- $display %m
- 与/或门类(多输入,单输出)和缓冲器/非门类(单输入,多输出)
- 注意and, or, nand, nor, xor, xnor的逻辑符号以及运算结果
- 注意x,z的情况
- bufif1, bufif0, notif1, notif0
- 注意如果很多个一维tmp变量,可以用数组完成
- 门原语不能写到过程块里
- 支持内部原语实例数组和用户自定义模块
- 允许通过门延迟来说明逻辑电路的延迟
- 默认无延迟
- 上升延迟(0,x,z->1),下降延迟(1,x,z->0),关断延迟(0,1,x->z)
and #(rise_val, fall_val, turnoff_val) b1 (out, in, ctrl)
- 如果用户指定了一个,那么所有的延迟都按这个,如果两个,则为上升和下降,关断为二者小者,如果三个,则依次是上升,下降,关断
- 用户还可以对于每种类型的延迟指定最小值,最大值,典型值
- 具体的控制方法与仿真器和操作系统有关
and #(2:3:4, 3:4:5, 4:5:6) a3(out, i1, i2)
- 上例子,若最小延迟,则上升、下降和关断分别为2,3,4,若经典则都取第三个值
verilog test.v +maxdelays(+mindelays/+typdelays)
continuous_assign ::= assign [drive_strength][delay3] list_of_net_assignments;
list_of_net_assignments ::= net_assignment (, net_assignment)
net_assignment ::= net_lvalue = expression
- 驱动强度可选,默认是strong1和strong0,延迟值也可选
- 连续赋值语句左值必须是一个标量或者向量线网,或者其的拼接,不能使向量or向量寄存器
- 总处于激活转台,一变则重新计算
- 操作数可以wire,reg或者 函数调用
- 操作符
^, &, |, {, }, +
assign {c_out, sum[3:0]} = a[3:0] + b[3:0] + c_in;
- 线网的隐式赋值只能一次
wire a = b & c;
wire i1, i2; assign out = i1 & i2;
虽然out未声明,但是合法为wire类型
- 三种:普通赋值延迟,隐式赋值延迟和线网声明延迟
assign #10 out = in1 & in2;
如果in1和in2发生变化,等10个单位,取新值计算(如果再次变化,则取当前值),为普通也称为惯性延迟(同样适用于门延迟)- 允许在线网声明的时候指定一个延迟,则对其任何赋值都会被推迟指定时间
- 隐式延迟
assign #10 out = in1 & in2;
不必声明out, out为wire
wire #10 out; assign out = in1 & in2;
<=>wire out; assign #10 out = in1 & in2;
- 算数运算符
+, -, *, /, **(求幂), %(取第一操作数符号),
- 如果操作数里面有一位是x,则运算的结果全部位均为x
- 负数是用二进制补码表示,故建议使用整数和实数计算,避免使用
<sss><base><nnn>
表示负数,因为会转换成正数(补码) - 逻辑运算符
&&, ||, !
- 逻辑运算符计算结果为一位,0为假,1为真,x表示不确定
- 不是0就是1, 是0才是0, x和z都是x
A = 2'bx1; B=1; A && B; //结果为x
)- 关系操作符
>, <, >=, <=
结果真则1,假则0,某位未知或高阻为x - 等价操作符
==, !=, ===, !==
- 'a==b' a等于b,若a,b中有x,z则x,
a!=b
同理 - 'a===b' a全等于b,结果为0或1,
a!==b
同理 - 按位操作符
~, &, |, ^, ^~ or ~^
分别是取反,与,或,异或,同或 - 位宽不等左扩展,确定不了就是x(注意是每一位的操作)
- 注意按位操作和逻辑操作完全不一样
- 缩减操作
&, ~&, |, ~|, ^, ~^ or ^~
分别是缩减与,缩减与非,缩减或,缩减或非,缩减异或,缩减同或 - 缩减运算只有一个操作数
X = 4'b1010; &X; // 1 & 0 & 0 & 0 Ans = 1'b0
- 移位操作符
>>, <<. <<<, >>>
分别为右移,左移,算术左移,算术右移 - 注意产生的空余位补零,不是循环左右移
- 算术移动,补第一位
- 拼接操作
A = 1'b1; D = 3'b101; Y = {A, D, 3'b001}; // 7'b1101001
- 重复操作
A = 1'b1; B = 1'b0; Y = {2{A}, 2{B}}; //4'b1100
- 条件操作
condition ? true_expr : false_expr;
- 注意,condition当逻辑类型,规则相同,如果条件表达式不确定为x,则对后两个表达式均计算,逐位比较,不同为x
- 条件操作允许嵌套
- 操作符优先级: 单目运算(+ - ! ~) > 算术运算(*/% > +-) > 移位 > 关系 > 等价(== > ===) > 缩减(& > ^ > |) > 逻辑 > 条件