07-verilog & sytem verilog
一.数据类型
二值逻辑变量
bit
- 不赋值的时候,变量初始默认为0
- x或z的值会转变为0
- bit vector--bit矢量
bit [msb,lsb] variable_name = [initial_value]
- 位宽:最高位为MSB,最低位为LSB
- 不加任何描述,默认为unsigned,无符号数;表示有符号数需要加signed进行描述
- 二值逻辑方便编译器的优化,效率更高,性能更好;但是不支持X和Z状态,不适用于RTL设计
建立自己的仿真目录
- sim -- 仿真目录,放Makefile文件
- RTL -- 放RTL代码
- TB -- 放testbench
- 使用tb文件进行仿真
module tb_test;
//定义变量
bit [3:0] a;
bit [4:0] b;
initial begin
a = 4'b0;
b = -10;
$display("a = %b",a);
$display("b = %b",b); // 10110 就是-10的补码
end
endmodule
- begin end之间就是代码块
- $display()就类似于print()函数
- 使用Makefile进行测试
Makefile文件
PLATFORM = LINUX64
FLIST := ../tb/tb_test.v
run:
vcs -sverilog $(FLIST) -debug_all -P ${NOVAS_HOME}/share/PLI/VCS/LINUX64/novas.tab ${NOVAS_HOME}/share/PLI/VCS/LINUX64/pli.a -R -kdb -lca
wave:
verdi -simflow -elab simv.daidir/kdb.elab++ -ssf sim.fsdb
clean:
rm csrc novas_dump.log sim.fsdb simv simv.daidir ucli.key verdi_config_file novas.conf novas.rc verdiLog -rf
通过make run进行仿真
byte\shortint\int\longint
- byte 8bit
- shortint 16bit
- int 32bit
- longint 64bit
byte/shortint/int/longint variable_name = initial_value;
- 默认都是有符号数,十进制数
- 在前端设计中,这些数据类型是很少用到的
shortint temp = 256;
int sample,ref_data = -9876;
longint a,b;
longint unsigned testdata;
real & shortreal
- real 等于C语言中的double,64bit
- shortreal等于C语言中的float,32bit
- 有符号数
- 在验证覆盖率的时候会用到
real/shortreal variable_name = initial_value
real alpha = 100.0,coverage_result;
coverage_result = $get_coverage();
if(coverage_result = 100.0)...
四值逻辑变量
- 四值逻辑:0,1,x,z
- 如果不声明数值,变量的初始值为x;在进行设计的时候要避免x态传递
reg & logic
- 四值逻辑在verilog中使用reg
reg [MSB:LSB] variable_name = initial_value;
- 在SV中使用logic变量
logic [MSB.LSB] variable_name = initial_value;
- reg和logic如果不用signed修饰,默认都是无符号数
- logic继承了reg所有的特性,但是logic可以进行连续赋值,并且只有一个驱动;如果定义了一个reg变量,是不能用assign对其进行赋值的,但是logic变量可以用assign进行赋值
- SV中:logic相当于reg和只有一个驱动的wire
module tb_test;
wire [3:0] b;
assign b = din_c;
assign b = din_d; //多个变量和b连接,多驱动,前提是cd具有推拉结构,OC,OD门
wire [3:0] e;
assign e = din_c; //单驱动
endmodule
integer & time
- integer,32bit有符号数
- time,64bit无符号数
integer a = -100,b;
time current_time;
b = -a;
current_time = $time;// $time内置函数,返回仿真时间
if(current_time>100ms).....
枚举类型
将所有的情况列举出来,在状态机中使用的比较多,比如FSM有限状态机
- 默认的数据类型是int
- 初始化值是0
- 可以使用枚举变量.name,显示枚举字符
enum [data_type] {named constants} enum_var1,enum_var2....;
module tb_test;
enum bit[2:0] {IDLE=3'b001,TEST=3'b010,START=3'b100} st; //声明枚举类
initial begin
st = START;
$display("st=%3b,name=%s",st,st.name); //st = 100,name=START
$finish;
end
endmodule
- 使用typedef定义枚举类,方便例化
typedef enum [data_type] {named constants} enumtype;
typedef enum bit[2:0] {IDLE=3'b001,TEST=3'b010,START=3'b100} state; //定义枚举类
state st; //例化一个枚举
initial begin
st = START;
$display("st=%3b,name=%s",st,st.name); //st = 100,name=START
$finish;
end
- 不使用枚举类型还可以使用parameter
parameter variable_name = initial_value;
固定数组
type(数据类型 bit reg logic..) [位宽] array_name [size] = initial value;
- 超过边界的写操作将被忽略
- 超过边界的读操作:2值逻辑返回0,四值逻辑返回x
- 支持多维数组
- size--就是数组长度,index从0开始
integer number[5]; //定义一个长度为5的数组,不给初值
int b[2] = {3,7};
int c[2][3] = {{3,7,1},{5,1,9}}; //定义二维数组
byte d[7]][2] = {default:-1} ; 将所有元素的值都设置默认-1
bit [31:0] a[2][3] = c; //数组可以通过赋值的方式进行复制
for(int i = 0;i<$dimensions(a);)
$display($size(a,i+1);) // 2,3,32
- $dimensions(数组)--返回数组的维数
- $size(数组,数组维数)--返回给定数组维数数组元素的个数
module tb_test;
logic [3:0] arr[3]; //定义长度为3的一维数组,每个元素为三位二进制数
logic [3:0] arr2[3][3]; //定义二维数组
initial begin
arr[0] = 4'd2;
end
endmodule
二.操作符
语法规则
- verilog和system verilog一样,都是大小写敏感的
- 注释 // /**/
- 数制格式
<size>'<base><number>
- base-b表示2进制 ,d表示10进制,h表示16进制数
- size是将数值转化为二进制数的时候的二进制位宽
32'h_beef_cafe
操作符
- 一般在写除法的时候,是需要设计特定的算法进行计算的,硬件当中实现除法比较麻烦
- 自增和自减用在for循环中使用的比较多
- 逻辑运算&& || !
- 逻辑等于,不等于 == !==
- 逻辑与或非,在运算的时候需要参与运算的位数应该都是一位的
左移和右移运算
module tb_test
logic [3:0] a;
initial begin
a = 4'b0011;
d = $signed(4'b0011); //转化为有符号数
b = a << 2;
c = d >>> 2;
$display("b = %4b",b); //左移低位补零,1100
$display("c = %4b",c); //右移,逻辑运算右移>>,高位补0,算术右移>>>,高位补符号位 c = 1111
end
endmodule
- 按位与或
module tb_test.v
logic [3:0] a;
logic [3:0] b;
initial begin
a = 4'b0011;
b = 4'b0011 & 4b'1100;
$display("b = %4b",b);
$finish;
end
endmodule
- 缩减运算符,单目运算符,第一位与下一位进行运算,最后输出一位
- 三目运算符
module tb_test.v
logic [3:0] a;
logic [3:0] b;
logic sel;
logic [3:0] mux;
initial begin
mux = sel ? a : b;
$finish;
end
endmodule
- {a,b} -- 将ab两个数连接在一起,
a = 4b'1100;
b = 4b'0011;
c = {a,b}; // 1100_0011
-
逻辑比较运算符
-
== != 遇到x和z,就会返回x
-
=== !=== 会将0 1 x z都进行匹配
-
通配比较符
匹配等==?和不匹配等!=?,按位比较,把x和z值当作匹配值,仅仅把右侧操作数中的z和x当作屏蔽信号
可以理解为,右边能够匹配上左边就返回真,xz可以取任意值0或1
a=4'b1111;
b=4'b11xz
a==?b//数字相等,只要x和z能通配到1就可以是匹配等,返回逻辑值为1'b1,真
A = 010z;
B = 0101;
A ==? B; //右边匹配不上左边 x
B ==? A; // z=1的时候,右边===左边 1
赋值语句
- -= += *= /= %=
- 在assign中使用复合赋值运算,会形成组合逻辑环comb loop
三.控制语句
自增和自减运算符
经常用在for循环中
for(int i = 0 ; i < 3; i++)begin
.....
end
i = 1;
j = i++; // j = 1
j = ++1; // j = 2
j = i--; // j = 1
j = --i; // j = 0
在阻塞赋值总使用自增自减运算符,会造成竞争与冒险
module tb_test;
integer i,j;
initial begin
i = 0;
j = 0
while(i++<5) begin //先判断再加一,当i=5时,判断不满足,还要再加1,最后i = 6
end
while(++j<5) begin // 先加1,再判断,j=5
end
end
endmodule
自定义类型
使用typedef为一个数据类型创建符号
typedef logic [31:0] vec;
vec a; // 创建32位a变量
vec b; // 创建32位b变量
在一些变量定义比较长的时候进行使用
数据类型转换
type'(value或variable)
logic signed [31:0] a;
logic [31:0] b;
logic [63:0] c;
assign c = a*b; //error,有符号数*无符号数出错,需要进行数据类型转换
assgin c = unsigned(a)*b;
bit [7:0] playload[]; //不给数组长度就是定义了一个动态数组
int temp = $random; // 生成一个随机数
playload = new [(temp%3)+2]; //实例化数组并指定长度
playload = new [(uint'(temp)%3)+2];
playload = new [(unsigned'(temp)%3)+2];
顺序控制
1.for循环
sv中循环遍历可以在for语句中定义,verilog中只能定义在外部
for循环中声明的i和外部声明的i是不相同的,互不影响
for(int i;i<3;i++) begin
end
- while
while() begin
end
- continue/break/return
- return 结束函数和task;用于循环,停止循环
- continue 用于循环语句,结束本次循环,执行下次循环
- break 用于循环语句,跳出循环
- do ... while
- while循环的时候,不一定会执行
- do..while至少会执行一次
do begin
...
end while(条件)
5.case
先计算表达式值,将case中的值与表达式的值进行匹配,匹配成功执行语句
- 匹配是从上到下匹配的
case(expr)
value1: xxxxxx
value2: xxxxxx
...
default xxxx
endcase
6.casez或casex
- casez 不关心z
- 忽略对应位上的z
sel = 4'b1100;
casez(sel)
4b'1101:data = 4'b01;
4b'zz00:data = 4'b00; //casez会匹配zz00 casez就不关心value中的z位置对应的值
default data = 4'b0011;
endcase
- casex忽略对应位置出现的x和z
- @ & wait
- @ 等待时间发生才执行后面的程序,可以是信号变量,上升沿,下降沿,事件变量
always@(posedge Clk) begin
...
end
- wait(expr) begin...end 是不可综合的
- 延迟信息 #5 5个时间单位,单位体现在timescale = 1np/100ps