verilog语法刷题知识点总结
- 1.状态机
- 2.任务和函数的区别
- 3.case,casez和casex
- 4.随机数产生关键字
- 5.运算符优先级
- 6.特殊运算符
- (1)移位运算符
- (2)等式运算符
- (3)动态位宽截取运算符
- 7.testbench知识点
1.状态机
(1)三段式状态机的组成:三段式状态机,第一段用时序逻辑描述(现态);第二段用组合逻辑描述状态转移(次态);第三段用时序逻辑描述输出,第三段可以是多个always块。
(2)二段状态机中,不能为了减少代码长度,以便综合的面积,可以减少else情况,if else中少写else会产生锁存器。
2.任务和函数的区别
不同点 | 函数(function) | 任务(task) |
---|---|---|
时序逻辑 | 不能包含延时和时序控制逻辑,不能有非阻塞性赋值 | 可以包含延时和时序控制逻辑 |
输入 | 至少有一个输入 | 可以没有输入或可以有多个输入 |
输出 | 没有输出 | 可以没有输出或有多个输出 |
返回值 | 有一个返回值 | 没有返回值 |
调用关系 | 可以调用其他函数,不能调用任务 | 可以调用函数和任务 |
综合性 | 可综合 | 有的编译器可综合,有的编译器不可综合 |
3.case,casez和casex
(1)case:敏感事件表达式和各项之间的匹配是一种全等匹配,完全相同才匹配;
(2)casez:敏感事件表达式和各项之间的匹配不考虑高阻态z;
(3)casex:敏感事件表达式和各项之间的匹配不考虑高阻态z和随机状态x;
4.随机数产生关键字
(1)情况一:b>0,产生一个(-b+1)~(b-1)间的随机数;
parameter b = 60;
reg [23:0] rand;
rand = $random%b;
(2)情况二:b>0,产生一个0~(b-1)间的随机数;
parameter b = 60;
reg [23:0] rand;
rand = {$random}%b;
(2)情况二:max>0且min>0,产生一个min~max间的随机数;
parameter max = 60;
parameter min = 30;
reg [23:0] rand;
rand = min+{$random}%(max-min+1);
5.运算符优先级
6.特殊运算符
(1)移位运算符
移位运算符分为分为两种,逻辑移位运算符和算数移位运算符:
A逻辑移位运算符
特点:用0填补空位
“>>”:逻辑右移运算符;
“<<”:逻辑左移运算符;
B算术移位运算符
特点:只有算术右移运算符,用原最高位填补空位,通过算术右移可以实现有符号数的除法;
“>>>”:逻辑右移运算符;
(2)等式运算符
有四个运算符:
等于:== 和 ===
不等于:!= 和 !==
区别:
== 和 != 不考虑高阻态z和未知状态x;
=== 和 !== 要考虑高阻态z和未知状态x;
注意:(与casez和casex不同)
== 和 !=:只要表达式两边有一个存在高阻态z或未知状态x,判定结果为未知状态x;
casez和casex:只要表达式中存在高阻态z或高阻态z和未知状态x时,对应位判定为匹配。
以 == 和 === 为例:
(3)动态位宽截取运算符
语法:vect[base
±
\pm
±:width]
说明:base表示起始位,+表示升序截取,-表示降序截取,width表示截取位宽;
注意:base可变但是width必须为常量;
例子:将data_in,从第3位起,正序截取4位给data_out
代码
module function_test_top(
input [7:0] data_in,
output [3:0] data_out
);
assign data_out = data_in[3+:4];
endmodule
testbench
`timescale 1ns/1ns
module function_test_tb();
reg [7:0] data_in ;
wire [3:0] data_out ;
initial begin
data_in = 8'b0000_0000;
#20;
data_in = 8'b0110_1100;
#20;
data_in = 8'b1101_0110;
#20;
data_in = 8'b1001_1100;
end
function_test_top u_function_test_top(
.data_in (data_in),
.data_out (data_out)
);
endmodule
结果:
7.testbench知识点
(1)初始化时用阻塞赋值和非阻塞赋值的不同
A描述
当初始化采用阻塞赋值,值的变化和时钟跳变同时发生,当前时钟边沿时可以采到数据变化的;
当初始化采用非阻塞赋值,值的变化会在时钟跳变后发生,下一个时钟边沿才能采集到数据变化;
B例子:采集一拍数据变化
a代码
module function_test_top(
input sys_clk ,
input sys_rst_n ,
input data_in ,
output reg data_out
);
always@(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)
data_out <= 1'b0;
else
data_out <= data_in;
end
endmodule
b 情况一:testbench初始化阻塞赋值
testbench
`timescale 1ns/1ns
module function_test_tb();
reg sys_clk ;
reg sys_rst_n ;
reg data_in ;
wire data_out ;
parameter T = 20;
initial begin
sys_clk = 1'b1;
sys_rst_n = 1'b0;
data_in = 1'b0;
#(2*T);
sys_rst_n = 1'b1;
#(2*T);
data_in = 1'b1;
end
// initial begin
// sys_clk <= 1'b1;
// sys_rst_n <= 1'b0;
// data_in <= 1'b0;
// #(2*T);
// sys_rst_n <= 1'b1;
// #(2*T);
// data_in <= 1'b1;
// end
always#(T/2) sys_clk = !sys_clk;
function_test_top u_function_test_top(
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n),
.data_in (data_in ),
.data_out (data_out )
);
endmodule
结果:
c 情况一:testbench初始化非阻塞赋值
`timescale 1ns/1ns
module function_test_tb();
reg sys_clk ;
reg sys_rst_n ;
reg data_in ;
wire data_out ;
parameter T = 20;
// initial begin
// sys_clk = 1'b1;
// sys_rst_n = 1'b0;
// data_in = 1'b0;
// #(2*T);
// sys_rst_n = 1'b1;
// #(2*T);
// data_in = 1'b1;
// end
initial begin
sys_clk <= 1'b1;
sys_rst_n <= 1'b0;
data_in <= 1'b0;
#(2*T);
sys_rst_n <= 1'b1;
#(2*T);
data_in <= 1'b1;
end
always#(T/2) sys_clk = !sys_clk;
function_test_top u_function_test_top(
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n),
.data_in (data_in ),
.data_out (data_out )
);
endmodule
结果:
(2)begin end语句块和fork join语句块的不同
A begin end
描述:串行语句块
特点:
块内语句顺序执行,块内上一条语句执行完才能执行下一条语句;
最后一条语句执行完,程序跳出该语句块。
例子:
`timescale 1ns/1ns
module function_test_tb();
reg data_a ;
reg data_b ;
reg data_c ;
initial begin
data_a = 1'b0;
data_b = 1'b0;
data_c = 1'b0;
#(20) data_a = 1'b1;
#(10) data_b = 1'b1;
#(30) data_c = 1'b1;
end
endmodule
结果:数据变化发生在20ns,30ns和60ns
B fork join
描述:并行语句块
特点:
块内语句同时执行;
耗时最长的语句块执行完后,程序跳出该语句块。
例子
`timescale 1ns/1ns
module function_test_tb();
reg data_a ;
reg data_b ;
reg data_c ;
initial fork
data_a = 1'b0;
data_b = 1'b0;
data_c = 1'b0;
#(20) data_a = 1'b1;
#(10) data_b = 1'b1;
#(30) data_c = 1'b1;
join
endmodule
结果:数据变化发生在20ns,10ns和30ns
C 两种语句块可以嵌套使用
例子:
`timescale 1ns/1ns
module function_test_tb();
reg data_a ;
reg data_b ;
reg data_c ;
initial begin
data_a = 1'b0;
data_b = 1'b0;
data_c = 1'b0;
#(10) data_a = 1'b1;
#(20) data_b = 1'b1;
#(30) data_c = 1'b1;
fork
#(10) data_a = 1'b0;
#(20) data_b = 1'b0;
#(30) data_c = 1'b0;
join
end
endmodule
结果:数据上升沿发生于10ns,30ns,60ns;数据下降沿发生于70ns,80ns,90ns。