初学verilog笔记

逻辑值

  • 0:逻辑低电平
  • 1:逻辑高电平
  • z:高阻态,无驱动
  • x:未知逻辑电平

关键字

1
2
3
4
5
6
7
8
9
10
module example(  //模块名  模块名

input wire sys_clk, //输入信号

output wire po_flag, //输出信号

inout wire sda, //输入输出信号 双向信号

);
endmodule //模块结束

变量类型

  • wire:线网型变量,相当于一条直接的连线
  • reg:具有对一时间点状态具有状态保存的功能,会被映射成一个真实的物理寄存器
1
2
3
wire  [0:0]  flag, //线网类型  连线   直接连接,电路中视为导线

reg [7:0] cnt, //寄存器类型 存储 电路中视为物理寄存器

参数

1
2
3
parameter CNT_MAX = 100;  //常量  宽度  在顶层文件中通过实例化可进行修改

localparam CNT_MAX = 100; //局部常量 宽度 只能在本模块中使用,不能被实例化修改
  • 模块实例化
1
2
3
4
5
example
#(
.CNT_MAX (8'd100) //实例化时参数可以修改
)

常量

  • 基数表示法

  • 格式:[换算为二进制后位宽的总长度][‘][数值进制符号][与进制符号对应的数值]

  • 8’d171 8位十进制数171

进制符号

  • b 二进制 d 十进制 h 十六进制 o 八进制

  • 总长度可有可无,verilog会根据数值自动计算位宽

  • 当总位宽小于数值实际位宽时,截断左侧多余位

  • 当总位宽大于数值实际位宽时,左侧补0

  • ‘d7和8’d7 表示相同数值 换算为二进制均为 00000111,前面五位补0

  • 2’d7表示二进制数11,前面两位截断 直接写参数,例如100,表示位宽为32的十进制数100

赋值方式

  • 阻塞赋值 = 适用于组合逻辑 按顺序执行
1
2
3
4
5
6
a=1;b=2;c=2;
begin
a = b;
c = a; //c的值为b
end
a,b,c=2;
  • 非阻塞赋值 <= 适用于时序逻辑 并行执行
1
2
3
4
5
6
a=1;b=2;c=3;
begin
a <= b;
c <= a;
end
a,b=2;c=1;
  • always语句

​ always @(*) 组合逻辑 当敏感信号变化时,立即执行

1
2
3
4
5
always(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt <= 8'd0; //复位信号有效时,cnt被赋值为0
else if(cnt == CNT_MAX)
cnt <= cnt + 8'd1; //没有增加到最大值,cnt+1
  • assign语句 组合逻辑 连续赋值

​ 位拼接运算符 {} 将多个信号拼接成一个信号

​ 位选择运算符 [] 选择信号的某几位

1
2
3
4
5
6
7
8
9
10
11
module top_module(

output zero

);

assign zero = 1'b0;
assign po_flag = (cnt == CNT_MAX) ? 1'b1 : 1'b0;
//满足第一个条件时,po_flag=1,否则po_flag = 0 三目运算符

endmodule

测试文件

  • 测试文件其功能主要为了验证设计文件逻辑的正确性
  • 将设计文件模块名称和端口信息例化(调用)到测试文件中
1
2
3
4
5
6
7
8
9
10
11
12
`timescale 1ns/1ps  //1ns表示单位,1ps表示精度
module and_gate_tb;//无端口信号

reg a;
reg b;
reg s;
//实例化
and_gate and_gate_inst(
.a(a),
.b(b),
.s(s)
);
  • 如何给输入信号激励,需要用 initial 语句进行赋值,语法规定,在initial语句中,被赋值变量的数据类型为 reg 类型
1
2
3
4
5
6
7
8
9
10
initial begin
a = 0; b = 0;
#20 //延迟20ns
a = 0; b = 1;
#20 //延迟20ns
a = 1; b = 0;
#20 //延迟20ns
a = 1; b = 1;
#20; //延迟20ns 结尾要写分号
end

算术运算符

  • +:加法
  • -:减法
  • *:乘法
  • /:除法 乘除一般不使用
  • %:求模(取余) 一般用在测试文件中

归约运算符、按位运算符

  • &:

    一元运算符作用:表示归约与,&m是将m中所有比特相与,最后结果为1bit

    eg: &4’b1111 = 1&1&1&1 = 1’b1

    ​ &4’b1101 = 1&1&0&1 =1’b0

    二元运算符:表示按位与

  • &,|,^,^,~|等同理

逻辑运算符

  • &&:逻辑与
  • || :逻辑或

关系运算符

  • <,>,<=,>=
  • 一般在条件判断上用到

移位运算符

  • 二元运算符
  • 左移符号是**<<,右移符号是**>>,将运算符左边的操作数左移或者右移指定的位数,用0来填补空闲位
1
2
b <=  a<<1;  //即让a的每一位都往左移动一位,结果赋值给b
b <= a>>2; //即让a的每一位都往右移动两位,结果赋值给b
  • 一个二进制数不管原数值是多少,只要一直移位,最后都会变成0
  • 移位运算在使用的时候可以代替乘法和除法,左移一位可以看成是乘以2,右移一位可以看成是除以2,但是要注意宽的拓展

位拼接运算符

  • 由一对花括号和逗号组成 {,,,},拼接不同的数据之间,用“,”隔开
  • eg:将8bit的a,3bit的b,5bit的c 按顺序拼接成一个16位的d 表示为:d={a,b,c}

条件运算符

  • 即三目运算符

优先级:归约运算符>算术运算符>移位运算符>关系运算符>按位运算符>条件运算符

()可以增加优先级

if-else分支语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
if(<条件表达式1>)
语句或语句块1;
else if(<条件表达式2>)
语句或语句块2;
......
else //最常用的一种



//第二种,嵌套类型的语句
if (<条件表达式1>)
if(<条件表达式2>)
语句或语句块1;
else
语句或语句块2;
else
语句或语句块3;//不推荐


case分支语句

  • 多路控制更加直观
  • 通常用于对微指令译码器、有限状态机的描述
  • 有case、casex,casez三种形式
1
2
3
4
5
6
7
8
9
case(<控制表达式>)
<分支语句1> : 语句块1;
<分支语句2> : 语句块2;
<分支语句3> : 语句块3;
······
<分支语句n> : 语句块n;
default : 语句块n+1;
endcase

  • 控制表达式代表着对程序流向进行控制的控制信号,各个分支表达式则是控制表达式的某些具体状态取值
  • 各个分支语句取值必须互不相同,否则会出现矛盾现象

系统函数

  • Verilog语言中预先定义了一些任务和函数,用于完成一些特殊的功能,这些函数大多只能在testbench仿真中使用
1
2
3
4
5
`timescale 1ns/1ns  //时间尺度预编译指令  时间单位/时间精度
#10 //表示延时10个单位的时间,即10ns

`timescale 1ns/10ps //精度0.01,#10.11表示延时10110ps
`timescale 100ps/1ns //错误,因为时间单位不能比时间精度小
  • 时间单位和时间精度由值1、10和100以及单位s、ms、us、ns、ps、fs组成
  • 时间单位:定义仿真所有与时间相关量的单位
  • 仿真中使用**“#数字”**表示延时相应时间单位的时间
  • 时间精度:决定事件相关量的精度以及仿真显示的最小刻度
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
`timescale 1ns/1ns

module tb_test();
reg [3:0] a;
reg [3:0] b;
reg [3:0] c;

initial begin //只在仿真文件中使用,不能被综合
$display("hello");
$display("world");
a = 4'd5;
b = 4'd6;
c = a + b;
#100;
$display("%b+%b=%d",a,b,c);
end
endmodule

$stop //暂停仿真
$finish //结束仿真
$time //时间函数 返回64位当前仿真时间
$ramdom //用于产生随机函数,返回随机数

简单组合逻辑-译码器

译码器定义

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
module decoder(
input wire in_1,
input wire in_2,
input wire in_3

output reg [7:0] out //always对应reg,assign对应wire
);
always@(*)
if({in_1,in_2,in_3} == 3'b000)
out = 8'b0000_0001;
else if({in_1,in_2,in_3} == 3'b001)
out = 8'b0000_0010;
else if({in_1,in_2,in_3} == 3'b010)
out = 8'b0000_0100;
else if({in_1,in_2,in_3} == 3'b011)
out = 8'b0000_1000;
else if({in_1,in_2,in_3} == 3'b100)
out = 8'b0001_0000;
else if({in_1,in_2,in_3} == 3'b101)
out = 8'b0010_0000;
else if({in_1,in_2,in_3} == 3'b110)
out = 8'b0100_0010;
else if({in_1,in_2,in_3} == 3'b111)
out = 8'b1000_0010;
else
out = 8'b000_0001;
endmodule

仿真文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
`timescale 1ns/1ns //时间

module tb_decoder();

reg in_1;
reg in_2;
reg in_3;

wire [7:0]; //输出信号引出

initial //输入信号初始化
begin
in_1 <= 1'b0;
in_2 <= 1'b0;
in_3 <= 1'b0;

always #10 in_1 <= ($random) % 2;
always #10 in_2 <= ($random) % 2;
always #10 in_3 <= ($random) % 2;
//#:延迟,10:10个时间单位, 随机数求余