今天来看看systemverilog的变量类型。systemverilog的变量类型有2值和4值两种类型。4值是z(高阻态,我们常说是三态门中的高阻态是干什么用的呢?是用来实现让电线实现断开的,实际上就是通过门来控制一条线中接个很大的电阻来让这个线就想中间断了一样,这样这根线就不会影响其它电路了),x,0,1。 2值就是0和1。
(一)4值变量有4种,wire,reg,logic,integer。
首先咱们来看一看4值变量中最常见的wire和reg,关于他们俩有一个很常见的问题,就是为什么过程赋值(就是always块)中用reg,并且要用非阻塞赋值(<=,后面都写nonblocking赋值了,方便一点)。而连续赋值(就是assign语句,blocking赋值)中就要用阻塞赋值(=)。
实际上这也是承接了昨天的话题,因为要真正了解这件事情要追究到昨天所说的软件实现仿真所划分的active区和NBA区上。
首先assign语句对wire赋值,就相当于在模块里实现电线的连线,这是个一步到位的事情,所以我们用blocking,这样的话软件在执行的时候就是直接在active区里一步到位的。
而reg,实际上是一个flipflop,这玩意的值是能变的,对一个能变的东西,我们想,如果我们还是让他只在active区里一步到位,那么会有一个很大的问题,就是如果同时有俩always语句对它下命令,一个让它把值直接给另外一个数据a,一个让它取反后把值给另外一个数据b,那它在执行的时候会怎么办呢,谁的指令先来,它就先执行哪个。这样的话对与a和b的值我们就不能确定了。为了解决这个问题,我们引入了NBA区。看过上一篇的就明白是怎么回事了,我们先让这个数在active区分别把原本值和取反的值都找个地方记录下来,然后在NBA分别将记录好的两个值赋值给a和b,这样就不会出错了。
下面直接上代码:
(1)nonblocking的例子:
module nonblocking(y1,y2,clk,rst);
output y1,y2;
input clk,rst;
reg y1,y2;
always@(posedge clk or posedge rst)
if(rst) y1 = 0;
else y1 <= y2;
always@(posedge clk or posedge rst)
if(rst) y2 = 1;
else y2 <= y1;
endmodule
testbench
`timescale 1ns/1ps
module nonblocking_tb();
wire y1,y2;
reg clk,rst;
parameter PERIOD = 10;
nonblocking nonblocking_1(
.y1(y1),
.y2(y2),
.clk(clk),
.rst(rst)
);
initial begin
clk = 0;
#1;
forever
#(PERIOD/2) clk = ~clk;
end
initial
begin
rst = 1;
#1 rst = 0;
#100;
$finish;
end
endmodule
结果
![8beec2569d5d229fd8f196955371a79d.png](https://img-blog.csdnimg.cn/img_convert/8beec2569d5d229fd8f196955371a79d.png)
这样的结果是没什么问题。
(2)如果我们在always语句中强行要用blocking赋值呢?
module nonblocking(y1,y2,clk,rst);
output y1,y2;
input clk,rst;
reg y1,y2;
always@(posedge clk or posedge rst)
if(rst) y1 = 0;
else y1 = y2;
always@(posedge clk or posedge rst)
if(rst) y2 = 1;
else y2 = y1;
endmodule
testbench
`timescale 1ns/1ps
module nonblocking_tb();
wire y1,y2;
reg clk,rst;
parameter PERIOD = 10;
nonblocking nonblocking_1(
.y1(y1),
.y2(y2),
.clk(clk),
.rst(rst)
);
initial begin
clk = 0;
#1;
forever
#(PERIOD/2) clk = ~clk;
end
initial
begin
rst = 1;
#1 rst = 0;
#100;
$finish;
end
endmodule
结果
![21338165d7ab717d77066a0f9a7c7f76.png](https://img-blog.csdnimg.cn/img_convert/21338165d7ab717d77066a0f9a7c7f76.png)
喏,出问题了吧,这是很好理解的。
在这里补充一个资料:
![cea7c5616af59828e33d4c98d79e082c.png](https://img-blog.csdnimg.cn/img_convert/cea7c5616af59828e33d4c98d79e082c.png)
![0cfbb501885b365d9fa66c37d45055d3.png](https://img-blog.csdnimg.cn/img_convert/0cfbb501885b365d9fa66c37d45055d3.png)
(3)接下来是logic和integer
logic简单来说就是一个又能放在always中当reg,又能放在assign中当wire用的变量,是纯软件的,不可综合。并且它还有一个好处是用它来写module的时候,可以省点笔墨,不用像verilog中那样,在module后面的端口声明中说一遍方向,然后在模块里面再说一遍变量的类型是wire还是reg。例子以后写了再补。
integer就是一个在C的int基础上,添加了z和x两个状态的32位数字。
(二)2值函数
2值函数就灰常直观易懂了。没啥可说的,直接把代码放这看一眼就好。
module data_types(
);
//2值
bit data_1bit;
byte data_8bit;
shortint data_16bit;
int data_32bit;
longint data_64bit;
shortreal shortreal_32bit;
real real_32bit;
bit unsigned data_1bit_unsigned;
byte unsigned data_8bit_unsigned;
shortint unsigned data_16bit_unsigned;
int unsigned data_32bit_unsigned;
longint unsigned data_64bit_unsigned;
initial begin
//2值
$display("2type data");
data_1bit = {8{4'b1111}};
data_8bit = {8{4'b1111}};
data_16bit = {8{4'b1111}};
data_32bit = {8{4'b1111}};
data_64bit = {8{4'b1111}};
shortreal_32bit= {8{4'b1111}};//浮点数
real_32bit= {8{4'b1111}};//双精度浮点数
//显示位数
$display("width");
$display("data_1bit = %b",data_1bit);
$display("data_8bit = %b",data_8bit);
$display("data_16bit = %b",data_16bit);
$display("data_32bit = %b",data_32bit);
$display("data_64bit = %b",data_64bit);
$display("shortreal_32bit = %b",shortreal_32bit);
$display("real_32bit = %b",real_32bit);
//显示表达的数字
$display("show figure");
$display("data_1bit = %d",data_1bit);
$display("data_8bit = %d",data_8bit);
$display("data_8bit = %0d",data_8bit);//%前面的0表示不要显示数字前面的空格
$display("data_16bit = %0d",data_16bit);
$display("data_32bit = %0d",data_32bit);
$display("data_64bit = %0d",data_64bit);
$display("shortreal_32bit = %d",shortreal_32bit);
$display("real_32bit = %d",real_32bit);
$display("shortreal_32bit = %f",shortreal_32bit);
$display("real_32bit = %f",real_32bit);
data_1bit_unsigned ={8{4'b1111}};
data_8bit_unsigned ={8{4'b1111}};
data_16bit_unsigned ={8{4'b1111}};
data_32bit_unsigned ={8{4'b1111}};
data_64bit_unsigned ={8{4'b1111}};
$display("data_1bit = %0d",data_1bit_unsigned);
$display("data_8bit = %0d",data_8bit_unsigned );
$display("data_16bit = %0d",data_16bit_unsigned);
$display("data_32bit = %0d",data_32bit_unsigned);
$display("data_64bit = %0d",data_64bit_unsigned);
//2 值函数如果赋zx这样的值,zx会赋为0
data_8bit = {8{4'bzx01}};
$display("data_8bit = %b",data_8bit);
$display("data_8bit = %d",data_8bit);
#1 $finish;
end
endmodule
结果
![fc0f29b585dc147d82c502484ada8ac3.png](https://img-blog.csdnimg.cn/img_convert/fc0f29b585dc147d82c502484ada8ac3.png)