Verilog
数字表示
基本格式:< 位宽 >’< 数制的符号 >< 数值 >
h十六进制
d十进制
o八进制
b二进制
向量
可直接进行加减等运算,方括号位于向量名前方。eg: reg [7:0] data
数组
方括号位于数组名的后面。括号内的第一个数字为第一个元素的序号,第二 个数字为最后一个元素的序号,中间用冒号隔开。
eg: wire array [15:0];
参数
可以通过 parameter 关键字声明参数以增强模块可拓展性和可读性。
在模块实例化时,可以使用 #() 将所需的实例参数覆盖模块的默认参数。
局部参数可以用 localparam 关键字声明,它不能够进行参数重载。
eg:
1 | module adder #( |
在我们例化这个模块时,可以进行如下操作:
1 | // 覆盖宽度,修改为 6 |
局部参数 localparam 和参数类似,但是不能在例化时被覆盖。
运算
按位运算
按位取反 ~
按位与 &
按位或 |
按位异或 ^
逻辑运算
• 逻辑取反!
• 逻辑与 &&
• 逻辑或 ||
缩减运算
• 缩减与 &:对一个多位操作数进行缩减与操作,计算所有位之间的与操作结果,例如:&(4’b1011) 的结果为 0
• 缩减或 |:对一个多位操作数进行缩减或操作,计算所有位之间的或操作结果。例如:|(4’b1011) 的结果为 1
• 缩减异或 ^:对一个多位操作数进行缩减异或操作,计算所有位之间的异或操作结果。例如: ^(4’b1011) 的结果为 1
缩减或非、缩减异或、缩减同或是类似的。
移位运算
• 逻辑右移>>:1 个操作数向右移位,产生的空位用 0 填充
• 逻辑左移<<:1 个操作数向左移位,产生的空位用 0 填充
• 算术右移>>>:1 个操作数向右移位。如果是无符号数,则产生的空位用 0 填充;有符号数则用其符号 位填充
• 算术左移<<<:1 个操作数向左移位,产生的空位用 0 填充
其他运算
• 拼接 {,}:2 个操作数分别作为高低位进行拼接,例如:{2’b10,2’b11} 的结果是 4’b1011
• 重复 {n{m}}:将操作数 m 重复 n 次,拼接成一个多位的数。例如:a=2’b01,则 {2{a}} 的结果 是 4’b0101
• 条件? ::根据? 前的表达式是否为真,选择执行后面位于: 左右两个语句。例如:assign c = (a > b) ? a : b,如果 a 大于 b,则将 a 的值赋给 c,否则将 b 的值赋给 c
组合逻辑
always
不推荐使用 always 块来表示组合逻辑。不正确的使用会生成大量锁存器。
下面的例子是一个 32-5 优先编码器,如果 tlb_hit_array 全为 0,那么 tlb_hit_index 也为 0。 always 块中被赋值的变量只能是 reg 类型,但是该编码器并不会综合出寄存器或者锁存器,这是因为 Verilog 中的寄存器 (reg) 和硬件上的寄存器不能完全等价。 如果去掉 tlb_hit_index = 5’d0; 一句,则会综合出锁存器。
1 | reg [4 :0] tlb_hit_index; |
模块声明和例化
模块被包含在关键字 module、endmodule 之内。
1 | module adder ( // 模块名称声明 |
Generate 块
这里只介绍 generate for 块。
generate for 的主要功能就是对模块或组件以及 always 块、assign 语句进行复制。 使用 generate for 的时候, 必须要注意以下几点要求
• 在使用 generate for 的时候必须先声明一个 genvar 变量,用作 for 的循环变量。genvar 是 generate 语句中的一种变量类型,用于在 generate for 语句中声明一个正整数的索引变量。
• for 里面的内嵌语句, 必须写在 begin-end 里
• 尽量对 begin-end 顺序块进行命名
generate for 的语法示例如下:
1 | genvar i; |
测试代码
时延语句
仿真中还经常使用时延来构造合适的仿真激励。它是不可综合的,仅能够在仿真中使用。时延分两类,一是 语句内部时延,二是语句间时延,其示例如下所示:
1 | // 语句内部时延 |
两种方式都表达在五个时间单位后,将 A 的值赋为 1。
initial 语句
一般用来生成复位信号和激励。只在仿真开始时执行一次。
1 | // 测试代码中 |
会生成一个 100MHz 的时钟,一个 50ns 有效的复位信号。
系统任务
系统任务可以被用来执行一些系统设计所需的输入、输出、时序检查、仿真控制操作。所有的系统任务名称 前都带有符号 $ 使之与用户定义的任务和函数相区分。
常见的系统任务:
• $display:用于显示指定的字符串,然后自动换行(用法类似 C 语言中的 printf 函数)
• $time:可以提取当前的仿真时间
• $stop:暂停仿真
• $finish:终止仿真
• $random:生成随机数
• $readmemh:读入一个 16 进制数的文件以初始化 reg
测试设计
测试最基本的结构包括信号声明、激励和模块例化。 测试模块声明时,一般不需要声明端口。因为激励信号一般都在测试模块内部,没有外部信号。 声明的变量应该能全部对应被测试模块的端口。当然,变量不一定要与被测试模块端口名字一样。但是被测试模块输入端对应的变量应该声明为 reg 型,输出端对应的变量应该声明为 wire 型。 仿真过程中可以使用 $display 显示当前仿真进度或者测试结果。 在测试完成或者发现错误时可以使用 $finish; 或者 $stop; 来停止仿真。