第 1 章 Verilog 的基本知识第 2 章 Verilog 语法的基本概念2.1 Verilog 模块的基本概念2.2 Verilog 用于模块的测试第 3 章 模块与数据类型及其运算符3.1 模块结构3.2 数据类型3.2.1 常量3.2.2 变量第 4 章 运算符、赋值语句和结构说明语句第 5 章 流程控制语句第 6 章 结构语句、系统任务、函数语句和显示系统任务6.1 系统说明语句6.1.1 initial6.1.2 always6.2 task 和 function6.2.1 说明语句介绍6.2.2 task 说明语句6.2.3 function 说明语句6.2.4 函数的使用举例1 奇偶校验位2 左右移位寄存器6.2.5 自动递归函数6.2.6 常量函数6.2.7 带符号函数6.4 常用的系统任务6.4.1 $display 和 $write6.4.2 文件输出6.4.3 显式层次6.4.4 选通显示6.4.5 值变转储文件第 7 章 调试用系统任务和编译预处理语句7.1 $monitor7.2 $time 与 $realtime7.3 $finish 与 $stop7.4 $readmemb 与 $readmemh7.6 $random7.7 编译预处理第 12 章 状态机第 13 章 编写可综合的代码
电路结构在 5000 门以上:
软核:Verilog HDL 模型
固核:电路结构编码文件
硬核:电路结构版图掩膜
设计过程
编写 Verilog 模块
综合(synthesis)
1// 例 2.1:二选一(由 always 语句实现)
2module mux2(out, a, b, sl);
3 input a, b, sl;
4 output out;
5
6 reg out; // 用于 always 语句
7 always @(sl or a or b)
8 if (sl) out a;
9 else out b;
10endmodule
xxxxxxxxxx
111// 例 2.2:二选一(由逻辑表达式实现)
2module mux2(out, a, b, sl);
3 input a, b, sl;
4 output out;
5
6 wire nsl, sela, selb; // 内部连接线
7 assign nsl sl; // 求反
8 assign sela a nsl;
9 assign selb b sl;
10 assign out sela selb;
11endmodule
xxxxxxxxxx
101// 例 2.3:二选一(由逻辑门实现)
2module mux2(out, a, b, sl);
3 input a, b, sl;
4 output out;
5
6 not u1(nsl, sl);
7 and #1 u2(sela, a, nsl);
8 and #1 u3(sleb, b, sl);
9 or #1 u4(out, sela, selb);
10endmodule
xxxxxxxxxx
91// 例 2.4:三位加法器(由连续赋值语句)
2module adder(cout, sum, a, b, cin);
3 input[2:0] a, b; // 三比特输入
4 input cin; // 输入进位
5 output cout; // 输出进位
6 output[2:0] sum; // 三比特输出
7
8 assign {cout, sum} a b cin;
9endmodule
xxxxxxxxxx
71// 例 2.5;比较器(连续赋值语句)
2module compare2(equal, a, b);
3 output equal; // 是否相等
4 input[1:0] a, b;
5
6 assign equal (ab) 1 : 0;
7endmodule
xxxxxxxxxx
81// 例 2.6:三态门选择器
2module trist2(out, in, enable);
3 output out;
4 input in, enable;
5
6 bufif1 mybuf(out, in, enable);
7 // 定义名为 mybuf 的三态门驱动器元件
8endmodule
x1// 例 2.7:三态门选择器
2
3// 子模块 mytri
4module mytri(out, in, enable);
5 output out;
6 input in, enable;
7 assign out enable in : 'bz; // 高阻态
8endmodule
9
10// 上层模块
11module trist1(sout, sin, ena);
12 output sout;
13 input sin, ena;
14 mytri tri_inst(
15 .out(sout),
16 .in(sin),
17 .enable(ena)
18 ); // 实例化部件
19endmodule
xxxxxxxxxx
261// 例 2.8:对例 2.1 - 2.3 的测试文件
2`include "mux2.v"
3module t;
4 reg ain, bin, select;
5 reg clock; // 时钟信号
6 wire outw;
7
8 // 只能在 testbench 中使用 initial,用于初始化参数
9 initial begin
10 ain 0; bin 0;
11 select 0; clock 0;
12 end
13
14 always #50 clock clock; // 时钟信号周期为 100
15 always #10000 select select; // 选通信号周期为 10000
16
17 always @(posedge clock) begin
18 #1 ain {} 2;
19 #3 bin {} 2;
20 end
21
22 mux2 m(
23 .a(ain), .b(bin),
24 .out(outw), .sl(select)
25 );
26endmodule
模块的结构
模块的表示
程序模块
电路图符号
模块的组成
输入输出管脚分配
管脚间的逻辑关系
模块的端口
模块端口的定义
只标明端口:模块名(端口1, 端口2)
标明 I/O 口:模块名(input[n-1:0] 端口1, output 端口2)
模块端口的引用
按照顺序:模块名(信号1, 信号2)
表明端口:模块名(.端口1(信号1), .端口2(信号2))
模块内容
I/O 说明(也可以在定义端口时说明)
input[n-1:0] 端口1, 端口2;
output[n-1:0] 端口1, 端口2;
端口默认为 wire
型.
内部信号
reg[n-1:0] 变量1, 变量2;
wire[n-1:0] 变量1, 变量2;
功能定义
assign 语句:assign a = ~(b ^ c)
;
用实例元件:and #2 u1(q, a, b);
aways 语句:always @(posedge clk) begin ...; end
注意事项
连续赋值语句(即 assign)表示将变量用导线(与逻辑门)相连.
模块中所有过程块(如 initial 块、always 块)、连续赋值语句、实例引用语句,都是并行的.
只有连续赋值语句和实例引用语句,可以独立于过程块而存在于模块的功能定义部分.
数字
表示方法(前缀 0 可省略不写)
<位宽>'<进制><数字>
,如 8'b10101100
'<进制><数字>
,默认位宽一般为 32 位(与系统有关)
<数字>
,默认位宽、默认为十进制
数据类型
整型常量:二进制 b/B、十进制 d/D、十六进制 h/H、八进制 o/O
不定值:x
,如 4'b10x0
高阻值:z
或 ?
,如 4'dz
或 8'h32?
负数:写在表达式前,如 -8'd5
下划线:用在数字间,无实意,仅用于提高易读性.
缺省位宽
整数:10 = 32'd10
负数:-1 = -32'd1 = 32'hFFFFFFFF
不定值:'BX = 32'BX = 32'BXXX...X
字符串:"AB" = 16'h4142
参数:parameter 参数1 = 表达式1, 参数2 = 表达式2;
xxxxxxxxxx
271// 例 3.2
2// Test.v
3`include "Top.v"
4`include "Block.v"
5`include "Annotate.v"
6module Test;
7 wire W;
8 Top T();
9endmodule
10
11// Top.v
12module Top;
13 wire W;
14 Block B1();
15 Block B2();
16endmodule
17
18// Block.v
19module Block;
20 Parameter P 0;
21endmodule
22
23module Annotate;
24 defparam
25 Test.T.B1.P 2, // 注意这里是逗号
26 Test.T.B2.P 3;
27endmodule
在 Verilog 中,所有变量都是静态的.
网络数据类型:不能存储值,必须受到驱动器(如连续赋值语句)的驱动
wire 型
wire[n-1:0] a, b;
wire[n:1] a, b;
reg 型
reg[n-1:0] rega;
可赋正值,可赋负值
被定义的信号将用在 always
memory 型
reg[n-1:0] 存储器名[m-1:0];
reg[n-1:0] 存储器名[m:1];
表示存储器有 m 个 n 位存储器
读写操作:mema[3] = 0;
tri 型
case 等式运算符:===
和 !==
对不定值 x 和高阻值 z 也进行比较,完全一致才为 1.
位拼接运算符
{a, b[1:0], w, 3'b101}
{a, b[1], b[0], w, 1'b1, 1'b0, 1b'1}
{b, {2{a, b}}}
{b, a, b, a, b}
缩进运算符(单目运算符)
xxxxxxxxxx
51reg[2:0] A;
2reg B;
3B A;
4// 相当于
5B A[0] A[1] A[2];
赋值语句
非阻塞赋值方式
b <= a;
所赋的变量值不能立即后续语句使用.
块结束后才能完成这次赋值操作.
不要滥用,避免生成不必要的触发器.
阻塞赋值方式
b = a;
赋值语句执行完成之后,b 的值立即改变.
时序逻辑电路中建议不要这样写.
if 语句
条件语句必须在过程块语句中使用,即 initial 和 always 中
建议用 begin end 标明逻辑
xxxxxxxxxx
61if (test1) statement1;
2else if (test2) begin
3 if (test3) statement2;
4 else statement3;
5end
6else statement4;
case 语句
所有表达式值的位宽必须相等.
不能用 'bx
代替 n'bz
.
如果 if 或 case 没有为变量的所有可能都赋值,则会生成锁存器.
建议用 else 或 default 赋值,以避免自动生成锁存器.
xxxxxxxxxx
111// 例 5.1
2case (select[1:2])
3 2'b00: result 0;
4 2'b01: result flaga;
5 2'b0x,
6 2'b0z: result flaga 'bx : 0;
7 2'b10: result flagb;
8 2'bx0,
9 2'bz0: result flagb 'bx : 0;
10 default: result 'bx;
11endcase
forever 语句
常用于产生周期的波形,用于仿真测试信号.
必须写在 initial 块中.
xxxxxxxxxx
31forever begin
2 statements;
3end
repeat 语句
xxxxxxxxxx
171// 乘法器
2paramter size 8, longsize 16;
3reg[size:1] opa, opb;
4reg[longsize:1] result;
5
6begin: mult // 块语句名
7 reg[longsize:1] shift_opa, shift_opb;
8 shift_opa opa;
9 shift_opb opb;
10 result 0;
11 repeat(size) begin
12 if (shift_opb[1])
13 result result shift_opa;
14 shift_opa shift_opa << 1;
15 shift_opb shift_opb >> 1;
16 end
17end
while 语句
xxxxxxxxxx
151// 对八位二进制数华中值为 1 的位进行计数
2reg[7:0] rega;
3
4begin: count1s
5 rega 2'b1011_0110;
6
7 reg[7:0] tempreg;
8 count 0;
9 tempreg rega;
10 while (tempreg) begin
11 if (tempreg[0])
12 count count 1;
13 tempreg tempreg >> 1;
14 end
15end
for 语句
xxxxxxxxxx
61// 例 5.7:用 for 语句初始化
2begin: init_mem
3 reg[7:0] i;
4 for (i 0; i < memsize; i i 1)
5 memory[i] 0;
6end
xxxxxxxxxx
121// 例 5.8:用 for 语句实现乘法器
2paramter size 8, longsize 16;
3reg[size:1] opa, opb;
4reg[longsize:1] result;
5
6begin: mult // 块语句名
7 integer i;
8 result 0;
9 for (i 1; i < size; i i 1)
10 if (opb[i])
11 result result (opa << (i1));
12end
xxxxxxxxxx
81// 用 for 语句对八位二进制数华中值为 1 的位进行计数
2begin: count1s
3 reg[7:0] tempreg;
4 count 0;
5 for (tempreg rega; tempreg; tempreg tempreg >> 1)
6 if (tempreg[0])
7 count count 1;
8end
块语句
顺序块
xxxxxxxxxx
91// 例 4.5
2parameter d 50; // 声明 d 是一个参数
3reg[7:0] r; // 8 位寄存器变量
4begin
5 #d r 'h35;
6 #d r 'hE2; // 过了 d 个单位时间后,再经过 d 个单位时间
7 #d > end_wave;
8 // 表示触发事件 end_wave 使其翻转
9end
并行块
xxxxxxxxxx
61// 例 4.6
2fork
3 #100 r 'hE2;
4 #50 r 'h35; // 顺序是不重要的;
5 #150 > end_wave;
6join
块语句可以嵌套
块语句的命名
命名块中可以声明局部变量
命名块中声明的变量可以通过层次引用进行访问
命名块可以被禁用
xxxxxxxxxx
91// 例 5.12:命名块的层次引用
2module top;
3 initial begin: block1
4 integer i; // top.block1.i
5 end
6 initial fork: block2
7 reg i; // top.block2.i
8 join
9endmodule
xxxxxxxxxx
181// 例 5.13:命名块的禁用
2// 在标志寄存器中查找第一个非零位
3reg[15:0] flag;
4integer i; // 用于计数
5
6initial begin
7 flag 16'b 0010_0000_0000_0000;
8 i 0;
9 begin: block1
10 while (i < 16) begin
11 if (flag[i]) begin
12 ("TRUE bit at %d", i);
13 disable block1;
14 end
15 i i 1;
16 end
17 end
18end
5.7 生成块
5.7.1 循环生成语句
xxxxxxxxxx
141// 例 5.14:对两个 N 位总线变量进行按位异或
2module bitwise_xor(out, i0, i1);
3 paramter N 32;
4 output[N1 : 0] out;
5 input[N1 : 0] i0, i1;
6
7 genvar j; // 仿真时该变量在设计中不存在
8 generate
9 for (j 0; j < N; j j 1)
10 begin: xor_loop
11 xor g1 (out[j], i0[j], i1[j]);
12 end
13 endgenerate
14endmodule
xxxxxxxxxx
171// 例 5.14 的另一种编写形式
2module bitwise_xor(out, i0, i1);
3 paramter N 32;
4 output[N1 : 0] out;
5 input[N1 : 0] i0, i1;
6
7 reg[N1 : 0] out;
8
9 genvar j;
10 generate
11 for (j 0; j < N; j j 1)
12 begin: bit
13 always@(i0[j] or i1[j])
14 out[j] i0[j] i1[j];
15 end
16 endgenerate
17endmodule
xxxxxxxxxx
291// 例 5.15:用循环生成语句描述的脉动加法器
2module ripple_adder(co, sum, a0, a1, ci);
3 parameter N 4; // 默认总线位宽为 4
4 output[N1 : 0] sum;
5 output co;
6 input[N1 : 0] a0, a1;
7 input ci;
8
9 wire[N1 : 0] carry;
10 assign carry[0] ci;
11
12 genvar i;
13 generate
14 for (i 0; i < N; i i 1) begin: r_loop
15 wire t1, t2, t3;
16 xor g1(t1, a0[i], a1[i]);
17 xor g2(sum[i], t1, carry[i]);
18 and g3(t2, a0[i], a1[i]);
19 and g4(t3, t1, carry[i]);
20 or g5(carry[i1], t2, t3);
21 end
22 endgenerate
23
24 // 以 or 为例,上述生成块会生成以下层次实例名
25 // or: r_loop[0].g5, r_loop[1].g5, r_loop[2].g5, r_loop[3].g5
26 // 线网也会连接起来:r_loop[0].t1, r_loop[1].t2 等等;
27
28 assign co carry[N];
29endmodule
5.7.2 条件生成语句
xxxxxxxxxx
251// 例 5.16:使用条件生成语句实现参数化乘法器
2module multiplier(a0, a1, product);
3 // 可重新定义 (defparam) 的参数
4 parameter a0_width 8;
5 parameter a1_width 8;
6
7 // 本地参数
8 // 1. 不能用参数重新定义
9 // 2. 也不能在实例引用时通过传递参数语句,即 #(参数1, 参数2) 的方法修改
10 localparam product_width a0_width a1_width;
11
12 // 端口声明语句
13 input[a0_width1:0] a0;
14 input[a1_width1:0] a1;
15 output[product_width1:0] product;
16
17 // 根据位数选择不同类型的乘法器
18 generate
19 if (a0_width < 8 a1_width < 8)
20 cal_multiplier #(a0_width, a1_width) m0(product, a0, a1);
21 // # 用于给参数赋值
22 else
23 tree_multiplier #(a0_width, a1_width) m0(product, a0, a1);
24 endgenerate
25endmodule
5.7.3 case 生成语句
xxxxxxxxxx
211// 例 5.17:case 生成语句生成 N 位加法器
2module adder(co, sum, a0, a1, ci);
3 // 声明的参数可以重新定义
4 parameter N 4; // 默认的总线位宽为 4
5
6 // 端口声明
7 output[N1:0] sum;
8 output co;
9 input[N1:0] a0, a1;
10 input ci;
11
12 // 根据总线位宽,调用相应的加法器(实例引用)
13 // 参数 N 在调用(实例引用)时可重新定义
14 generate
15 case (N)
16 1: adder_1bit adder1(co, sum, a0, a1, ci);
17 2: adder_2bit adder2(co, sum, a0, a1, ci);
18 default: adder_cla #(N) adder3(co, sum, a0, a1, ci);
19 endcase
20 endgenerate
21endmodule
5.8 举例
5.8.1 四选一多路选择器
写法一:
xxxxxxxxxx
161// 例 5.18:四选一多路选择器——写法一
2module mux4_to_1(out, i0, i1, i2, i3, s1, s0);
3 input i0, i1, i2, i3;
4 input s1, s0
5 output reg out;
6
7 always @() begin
8 case ({s1, s0})
9 2'b00: out i0;
10 2'b01: out i1;
11 2'b10: out i2;
12 2'b11: out i3;
13 default: out 1'bx;
14 endcase
15 end
16endmodule
写法二:
xxxxxxxxxx
101// 例 5.18:四选一多路选择器——写法一
2module mux4_to_1(out, i, s);
3 input[3:0] i;
4 input[1:0] s;
5 output reg out;
6
7 // 试试能不能这样写,一是数组直接写 s,二是把 s 放在下标中
8 // 哈哈,测试过了,都是可以的
9 always @(s or i) out i[s];
10endmodule
上述代码的 testbench:
xxxxxxxxxx
161// testbench of mux4_to_1
2`timescale 1ns10ps
3module mux4_to_1_tb;
4 reg[3:0] i;
5 reg[1:0] s;
6 wire out;
7
8 mux4_to_1 mux4_to_1(.i(i), .s(s), .out(out));
9
10 always #10 i < i 1;
11 always #160 s < s 1;
12 initial begin
13 i < 0; s < 0;
14 #640 ;
15 end
16endmodule
5.8.2 四位计数器
xxxxxxxxxx
281// 例 5.19:四位二进制计数器
2module counter(Q, clock, clear);
3 output reg[3:0] Q;
4 input clock, clear;
5
6 always @(posedge clear or negedge clock) begin
7 if (clear) Q < 4'd0; // 为了生成包含触发器的时序逻辑,使用非阻塞赋值
8 else Q < Q 1; // 四位寄存器,无需模 16
9 end
10endmodule
11
12// testbench of counter
13`timescale 1ns10ps
14module counter_tb;
15 reg clock, clear;
16 wire[3:0] Q;
17
18 counter counter(.clock(clock), .clear(clear), .Q(Q));
19
20 always #10 clock < clock;
21 always #250 clear < clear;
22 initial begin
23 clock < 0;
24 clear < 1;
25 #1000 ;
26 end
27endmodule
28
一个模块可以有多个 initial 块,并且都是并行运行的.
如果没有时序控制,则会产生仿真死锁,如 always A <= B;
敏感事件列表,既可以用 or
也可以用 ,
,如 always @(A, B) ...
@*
或 @(*)
可以将所有输入变量都包括进敏感列表.
电平敏感时序控制,即等到条件为真时才运行,如
always wait(ena) #20 count <= count + 1;
函数与主模块共用一个仿真时间单位,而任务可自定义.
函数不能启动任务,而任务能启动其它任务和函数.
函数至少需要一个输入变量,而任务可以没有或有多个任何类型的变量.
函数返回一个值,而任务则不返回值.
xxxxxxxxxx
21switch_bytes(old_word, new_word); // 任务
2new_word switch_bytes(old_word); // 函数
xxxxxxxxxx
81// 任务的定义
2task<任务名>;
3 <端口及数据类型声明语句>
4 <语句>
5endtask
6
7// 任务的调用
8<任务名>(端口1, 端口2, ...)
xxxxxxxxxx
411// 例 6.9:描述交通信号灯行为的模块
2// 该模块只是一个行为模块,不能综合成电路网表
3`timescale 1ns10ps
4module traffic_lights;
5 reg clock, red, amber, green;
6 parameter on 1, off 0;
7 parameter red_tics 350, amber_tics 30, green_tics 200;
8
9 // 提问:可不可以写成 red = amber = green = off;
10 // 即赋值语句有没有返回值?那样连 begin end 都省了,直接一行代码.
11 // 试过了,只有非阻塞赋值都可以这样写
12 // 不!这样编译虽然能过,但是结果却有问题,都显示不定值了.
13 // initial red <= amber <= green <= off;
14
15 // 交通灯控制程序
16 always begin
17 red on; light(red, red_tics);
18 green on; light(green, green_tics);
19 amber on; light(amber, amber_tics);
20 end
21
22 // 定义交通灯开启时间的任务
23 task light;
24 output color;
25 input[31:0] tics;
26 begin
27 repeat(tics)
28 @(posedge clock); // 等待 tics 个时钟的上升沿
29 color off; // 之后关灯
30 end
31 endtask
32
33 // 产生时钟脉冲
34 initial begin
35 clock < 0;
36 red < off; amber < off; green < off;
37 #10000 ;
38 end
39 always #1 clock < clock;
40endmodule
41
xxxxxxxxxx
81// 函数的定义
2function <返回值的类型或范围> (函数名):
3 <端口说明语句>
4 <变量类型说明语句>
5 begin
6 <语句>
7 end
8endfunction
xxxxxxxxxx
81// 例子
2function [7:0] getbyte;
3 input [15:0] address;
4 begin
5 <说明语句>
6 getbyte result_expression
7 end
8endfunction
使用规则
函数的定义不能包含任何时间控制语句
函数不能启动任务
定义函数时至少要有一个输入参量
xxxxxxxxxx
251// 例 6.10:阶乘函数的定义与调用
2module tryfact;
3 // 函数的定义
4 function[31:0] factorial;
5 input[3:0] operand;
6 reg[3:0] index;
7 begin
8 factorial 1;
9 for (index 2; index < operand; index index 1)
10 factorial index factorial;
11 end
12 endfunction
13
14 // 函数的测试
15 reg[31:0] result;
16 reg[3:0] n;
17 initial begin
18 result 1;
19 for (n 2; n < 9; n n 1) begin
20 ("%d: %d, ", n, result);
21 result n factorial(n) (2n 1);
22 end
23 ("Final result = %d", result);
24 end
25endmodule
xxxxxxxxxx
251// 例 6.11:奇偶校验位的计算
2module parity;
3 reg[31:0] addr;
4 reg parity;
5
6 initial begin
7 addr < 32'h3456_789a;
8 #10 addr < 32'hc4c6_78ff;
9 #10 addr < 32'hff56_ff9a;
10 #10 addr < 32'h3faa_aaaa;
11 end
12
13 always @(addr) begin
14 parity calc_parity(addr); // 第一次启动,下一行是第二次
15 ("Parity calculated = %b", calc_parity(addr));
16 end
17
18 // 定义奇偶校验计算函数
19 function calc_parity;
20 input[31:0] address;
21 begin
22 calc_parity address; // 返回所有地址位的异或值
23 end
24 endfunction
25endmodule
注意上述代码中的 ^addresss
xxxxxxxxxx
61// 例 6.12:使用 C 风格进行变量声明的函数定义
2function calc_parity(input[31:0] address);
3 begin
4 calc_parity address;
5 end
6endfunction
xxxxxxxxxx
201// 例 6.13:定义一个包含移位函数的模块
2module shifter;
3 `define LEFT_SHIFT 1'b0
4 `define RIGHT_SHFIT 1'b1
5 reg[31:0] addr, left_addr, right_addr;
6 reg control;
7
8 always @(addr) begin
9 left_addr shift(addr, `LEFT_SHIFT);
10 right_addr shift(addr, `RIGHT_SHIFT);
11 end
12
13 function[31:0] shift;
14 input[31:0] address;
15 input control;
16 begin
17 shift (control `LEFT_SHIFT) (address << 1) : (address >> 1);
18 end
19 endfunction
20endmodule
Verilog 中的函数默认不能递归调用,如果同时调用同一块地址空间,那么计算结果将不确定.
xxxxxxxxxx
191// 例 6.14:自动递归函数
2module top;
3 function automatic integer factorial;
4 input[31:0] oper;
5 integer i;
6 begin
7 if (operand > 2)
8 factorial factorial(oper 1) oper; // 递归
9 else
10 factorial 1;
11 end
12 endfunction
13
14 integer result;
15 intial begin
16 result facotrial(4);
17 ("Factorial of 4 is %0d", result);
18 end
19endmodule
xxxxxxxxxx
121// 例 6.15:常量函数
2module ram(...);
3 parameter RAM_DEPTH 256;
4 input[clogb2(RAM_DEPTH) 1 : 0] addr_bus;
5 ...
6 function integer clogb2(input integer depth);
7 begin
8 for (clogb2 0; depth > 0; clogb2 clogb2 1)
9 depth depth >> 1;
10 end
11 endfunction
12endmodule
xxxxxxxxxx
81// 例 6.16:带符号函数
2module top;
3 ...
4 function signed[63:0] compute_signed(input[63:0] vector);
5 //
6 endfunction
7 ...
8endmodule
xxxxxxxxxx
91// 例 6.17
2module disp;
3 initial begin
4 ("\\\t%%\n\"\123");
5 \ \\ 表示反斜杠,\t 表示制表符, 表示百分号
6 \n 表示换行符 ,\" 表示双引号,\123 表示 S
7 \
8 end
9endmodule
xxxxxxxxxx
151// 例 6.18
2module disp;
3 reg[31:0] rval;
4 pulldown(pd);
5 initial begin
6 rval 101;
7 ("rval = %h (hex), %d (decimal)", rval, rval);
8 ("rval = %o (otal), %b (binary)", rval, rval);
9 ("rval has %c ascii character value", rval);
10 ("pd strength is %v", pd) // 输出 StX
11 ("current scope is %m"); // 输出 disp
12 ("%s is ascii value for 101", 101); // e
13 ("simulatoin time is %t", time); // 0
14 end
15endmodule
xxxxxxxxxx
91// 例 6.19
2module printval;
3 reg[11:0] r1;
4 initial begin
5 r1 10;
6 ("maximum size = %d = %h", r1, r1); // 10, 00a
7 ("minimum size = %0d = %0h", r1,r1); // 10, a
8 end
9endmodule
xxxxxxxxxx
161// 例 6.20:文件描述符
2integer handle1, handle2; // 整型数为 32 位
3integer desc1, desc2, desc3;
4
5initial begin
6 handle1 ("file1.out"); // 32'h0000_0002
7 handle2 ("file2.out"); // 32'h0000_0004
8
9 desc1 handle1 1; // 1 为标准输出 stdout
10 (desc1, "Display 1"); // 同时写入 file1.out 和 stdout
11
12 desc2 handle2 handle1;
13 (desc2, "Display 2"); // 写入 file1.out 和 file2.out
14
15 (handle1);
16end
写文件:$fdisplay, $fmonitor, $fwrite, $fstrobe
xxxxxxxxxx
91// 例 6.21:显示层次
2module M;
3 initial ("%m");
4endmodule
5
6module top;
7 M m1(); // 输出 top.m1
8 M m2(); // 输出 top.m2
9endmodule
xxxxxxxxxx
81// 例 6.22:选通显示
2always @(posedge clock) begin
3 a b; c d;
4end
5
6always @(posedge clock)
7 ("a = %b, c= %b", a, c);
8// posedge clock 发生时,始终在其它语句完成后才执行 $strobe
xxxxxxxxxx
131// 例 6.23:VCD 文件系统任务
2initial ("myfile.dmp"); // 仿真信息转储到 myfile.dmp
3initial ; // 设计中的全部信息都转储
4initial (1, top); // 转出模块示例 top 模块第一层的信号
5initial (2, top.m1); // 转储 top.m1 下两层的信号
6initial (0, top.m1); // 0 表示各个层的所有信号
7
8initial begin
9 ; // 启动转储过程
10 #100000 ; // 停止转储过程
11end
12
13initial ; // 转储所有 VCD 变量的现行值
xxxxxxxxxx
21( , , "rxd = %b, txd = %b", rxd, txd);
2// ', ,' 空参数显示为空格
xxxxxxxxxx
101`timescale 10ns1ns
2module test;
3 reg set;
4 initial begin
5 ( , ", ", , ", ", "set = ", set);
6 // 输出: 0, 0, set = x
7 #1.6 set 0; // 2, 1.6, set = 0
8 #1.6 set 1; // 3, 3.2, set = 1
9 end
10endmodule
xxxxxxxxxx
71 // 结束仿真 ;
2(0); // 结束且不输出任何信息
3(1); // 输出当当前仿真时刻和位置
4(2); // 输出当前仿真时刻、位置、所有 memory 和 CPU 时间统计
5
6 // 暂停仿真 (可在仿真器中点击继续仿真) ;
7(n);
xxxxxxxxxx
121// 例 7.3:初始化存储器
2module test;
3 reg[7:0] memory[0:7]; // 8 个 8 位的存储单元
4 integer i;
5
6 initial begin
7 ("init.dat", memory);
8 for (i 0; i < 8; i i 1) begin
9 ("Memory[%d] = %b", i, memory[i]);
10 end
11 end
12endmodule
xxxxxxxxxx
71// init.dat 文件
2@002
311111111 01010101
400000000 10101010
5
6@006
71111zzzz 00001111
xxxxxxxxxx
31reg[23:0] rand;
2rand ; // 生成 32 位的带符号随机数, 赋给 rand 时取低 24 位
3rand 60; // -b+1 ~ b-1
xxxxxxxxxx
91`define NUM 8 // 定义宏(无需分号)
2a `NUM; // 引用宏
3
4`define NUM 8; // 连着分号一起被替换
5a `NUM // 于是无需再写分号
6
7`define expr abcd // 建议不加分号,以防后续语法出错
8
9`define typ_nand nand #5 // 可以包含空格等
状态的编码:使用 Gray 码或独热码
输出的变量:使用新的变量,或者直接把部分状态作为输出
xxxxxxxxxx
341// 例 12.1:有限状态机,Gray编码
2module fsm(clk, rst, A, K2, K1, state);
3 input clk, rst, A;
4 output reg K2, K1;
5 output reg[1:0] state;
6 // Gray 码:
7 parameter Idle 2'b00,
8 Start 2'b01,
9 Stop 2'b10,
10 Clear 2'b11;
11 // 或者用独热码:
12 /*
13 parameter Idle = 4'b1000,
14 Start = 4'b0100,
15 Stop = 4'b0010,
16 Clear = 4'b0001;
17 */
18
19 always @(posedge clk) begin
20 if (rst) begin
21 state < Idle; K2 < 0; K1 < 1;
22 end
23 else case (state)
24 Idle: if (A) begin
25 state < Start; K1 < 0;
26 end
27 else begin
28 state < Idle; K2 < 0; K1 < 0;
29 end
30 ... // 其它的状态
31 default: state < 2'bxx;
32 endcase
33 end
34endmodule
xxxxxxxxxx
401// 例 12.4
2module fsm(Clock, Reset, A, K2, K1);
3 input Clock, Reset, A;
4 output reg K2, K1;
5 reg[1:0] state, nextState;
6
7 parameter Idel 2'b00;
8 parameter Start 2'b01;
9 parameter Stop 2'b10;
10 parameter Clear 2'b11;
11
12 // 时钟沿产生可能的状态变化
13 always @(posedge Clock)
14 if (Reset) state < Idle;
15 else state < nextState;
16
17 // 产生下一状态的组合逻辑
18 always @(state or A)
19 case (state)
20 Idle: nextState < A Start : Idle;
21 Start: nextState < A Start : Stop;
22 Stop: nextState < A Clear : Stop;
23 Clear: nextState < A Clear : Idle;
24 default: nextState < 2'bxx;
25 endcase
26
27 // 输出 K1
28 always @(state or Reset or A) begin
29 if (Reset) K1 < 0;
30 else if (state Clear A) K1 < 1;
31 else K1 < 0;
32 end
33
34 // 输出 K2
35 always @(state or Reset or A) begin
36 if (Reset) K2 < 0;
37 else if (state Stop A) K2 < 1;
38 else K2 < 0;
39 end
40endmodule
13.5.1 组合逻辑电路
xxxxxxxxxx
111// 例 13.1:n 位加法器
2module adder(a, b, cin, sum, cout);
3 parameter n 8;
4
5 input cin;
6 input[n1:0] a, b;
7 output cout;
8 output[n1:0] sum;
9
10 assign {cout, sum} a b cin;
11endmodule
xxxxxxxxxx
241// 例 13.2: 指令译码电路
2// 操作码的宏定义
3`define plus 3'd0
4`define minus 3'd1
5`define band 3'd2
6`define bor 3'd3
7`define unegate 3'd4
8
9module alu(a, b, opcode, out);
10 input[2:0] opcode;
11 input[7:0] a, b;
12 output reg[7:0] out;
13
14 always @(opcode or a or b) begin
15 case (opcode)
16 `plus: out a b;
17 `minus: out a b;
18 `band: out a b;
19 `bor: out a b;
20 `unegate: out a;
21 default: out 8'hx;
22 endcase
23 end
24endmodule
xxxxxxxxxx
211// 例 13.3: 排序
2module sort4(a, b, c, d, ra, rb, rc, rd);
3 parameter n 4;
4 input[n1:0] a, b, c, d;
5 output reg[n1:0] ra, rb, rc, rd;
6
7 always @(a or b or c or d) begin: local
8 // 如果定义局部变量,则必须有模块名
9 reg[n1:0] va, vb, vc, vd;
10 {va, vb, vc, vd} {a, b, c, d};
11 sort2(va, vc); sort2(vb, vd);
12 sort2(va, vb); sort2(vc, vd);
13 sort2(vb, vc);
14 {ra, rb, rc, rd} {va, vb, vc, vd};
15 end
16
17 task sort2;
18 input[n1:0] x, y;
19 if (x > y) {x, y} {y, x};
20 endtask
21endmodule
xxxxxxxxxx
71// 例 13.4:比较器
2module compare(equal, a, b);
3 parameter size 1;
4 input[size1:0] a, b;
5 output equal;
6 assign equal (ab) 1 : 0;
7endmodule
xxxxxxxxxx
61// 例 13.5:3-8 译码器
2module decoder(in, out);
3 input[2:0] in;
4 output[7:0] out;
5 assign out 1'b1 << in;
6endmodule
xxxxxxxxxx
501// 例 13.6: 8-3 编码器 1
2module encoder1(none_on, out, in);
3 input[7:0] in;
4 output reg[2:0] out;
5 output reg none_on;
6
7 always @(in) begin: local
8 integer i;
9 out 0;
10 none_on 1;
11 for (i 0; i < 8; i i 1) begin
12 if (in[i]) begin
13 out i;
14 none_on 0;
15 end
16 end
17 end
18endmodule
19
20// 8-3 编码器 2 (优先编码器, 利用 ?: 语句实现)
21module encoder2(none_on, out, in);
22 input[7:0] in;
23 output reg[2:0] out;
24 output reg none_on;
25
26 wire[3:0] outvec;
27 assign outvec in[7] 4'b0111 :
28 in[6] 4'b0110 :
29 in[5] 4'b0101 :
30 in[4] 4'b0100 :
31 in[3] 4'b0011 :
32 in[2] 4'b0010 :
33 in[1] 4'b0001 :
34 in[0] 4'b0000 : 4'b1000;
35 assign {none_on, out} outvec;
36endmodule
37
38// 8-3 编码器 3 (优先编码器, 利用 always 语句实现)
39module encoder3(none_on, out, in);
40 input[7:0] in;
41 output[2:0] out;
42 output none_on;
43
44 reg[3:0] outvec;
45 assign {none_on, out} outvec;
46 always @(in) begin
47 if (in[7]) outvec 4'b0110;
48 else if (in[6]) ......
49 end
50endmodule
xxxxxxxxxx
291// 例 13.7: 多路选择器
2module emux1(out, a, b, sel);
3 input a, b, sel;
4 output out;
5 assign out sel a : b;
6endmodule
7
8module emux2(out, a, b, sel);
9 input a, b, sel;
10 output reg out;
11
12 always @(a or b or sel) begin
13 case (sel)
14 1'b1: out a;
15 1'b0: out b;
16 default: out 'bx;
17 endcase
18 end
19endmodule
20
21module emux3(out, a, b, sel);
22 input a, b, sel;
23 output reg out;
24
25 always @(a or b or sel) begin
26 if (sel) out a;
27 else out b;
28 end
29endmodule
xxxxxxxxxx
71// 例 13.8: 奇偶校验位生成器
2module parity(even_numbits, odd_numbits, input_bus);
3 output even_numbits, odd_numbits;
4 input[7:0] input_bus;
5 assign odd_numbits input_bus;
6 assign even_numbits odd_numbits;
7endmodule
xxxxxxxxxx
131// 例 13.9: 三态输出驱动器 (三态门模型)
2module trist1(out, in, enable);
3 input in, enable;
4 output out;
5 assign out enable in : 'bz;
6endmodule
7
8module trist2(out, in, enable)
9 input in, enable;
10 output out;
11 // bufif1 是一个 Verilog 门级原语
12 bufif1 mybuf1(out, in, enable);
13endmodule
xxxxxxxxxx
81// 例 13.10: 三态双向驱动器
2module bidir(tri_inout, out, in, en, b);
3 input tri_inout;
4 output out;
5 input in, en, b;
6 assign tri_inout en in : 'bz;
7 assign out tri_inout b;
8endmodule
13.5.2 时序逻辑电路
xxxxxxxxxx
91// 例 13.11: 触发器
2module dff(q, data, clk);
3 input data, clk;
4 output reg q;
5
6 always @(posedge clk) begin
7 q < data;
8 end
9endmodule
xxxxxxxxxx
61// 例 13.12: 电平敏感型锁存器
2module latch1(q, data, clk);
3 input data, clk;
4 output q;
5 assign q clk data : q;
6endmodule
xxxxxxxxxx
61// 例 13.13: 带置位和复位端的电平敏感型锁存器
2module latch2(q, data, clk, set, reset);
3 input data, clk, set, reset;
4 output q;
5 assign q reset 0 : (set 1 (clk data : q));
6endmodule
xxxxxxxxxx
71// 例 13.14: 电平敏感型锁存器
2module latch(q, data, clk);
3 input data, clk;
4 output reg q;
5
6 always @(clk) q < data;
7endmodule
xxxxxxxxxx
131// 例 13.15: 移位寄存器
2module shifter(din, clk, clr, dout);
3 input din, clk, clr;
4 output reg[7:0] dout;
5
6 always @(posedge clk) begin
7 if (clk) dout < 8'b0;
8 else begin
9 dout < dout << 1;
10 dout[0] < din;
11 end
12 end
13endmodule
xxxxxxxxxx
321// 例 13.16: 8 位计数器
2module counter1(out, data, load, cin, clk);
3 input[7:0] data;
4 input load, cin, clk;
5 output reg[7:0] out;
6 output cout;
7
8 always @(posedge clk) begin
9 if (load) out < data;
10 else out < out cin;
11 end
12
13 assign cout (out) cin;
14 // &out 当且仅当 out 所有位都为 1 时才为 1
15endmodule
16
17module counter2(out, cout, data, load, cin, clk);
18 input[7:0] data;
19 input load, cin, clk;
20 output reg[7:0] out;
21 output reg cout;
22
23 reg[7:0] preout;
24 always @(posedge) begin
25 out < preout;
26 end
27
28 always @(out or data or load or cin) begin
29 {cout, preout} out cin;
30 if (load) preout data;
31 end
32endmodule