1、内建数据类型
verilog有两种基本的数据类型:变量和线网,他们各自都可以有四种取值:0 1 z x;
RTL代码使用 变量 来存放组合和时序值;变量可以是单bit或者是多bit的无符号数 reg [7:0] m,
32bit的有符号数 integer ,64bit的无符号数 time 或者是 浮点数 real.若干变量可以被一起放在定宽数组里,所有的存储都是静态的,意味着所有变量在tb的时候都是存活的。
1.1、 logic类型
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2025/03/20 17:24:56
// Design Name:
// Module Name: logic_data_type
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module logic_data_type
(
input logic rst_h
);
parameter CYCLE = 20 ;
logic q,q_l,d,clk,rst_l ;
initial
begin
clk = 1'b0 ;
forever #(CYCLE/2)
begin
clk = ~clk ;
end
end
assign rst_l = ~rst_h ;
not m1(q_l,q) ;
endmodule
1.2、 双状态数据类型
相比于四状态数据类型(0,1,x,z),SV 引入的双状态数据类型有利于提高仿真器的性能并减少内存。
双状态数据类型:可以用 unsigned 约束成无符号数
bit :无符号,width = 1 ;
byte :有符号整数, width = 8 ;
shortint :有符号整数, width = 16 ;
int :有符号整数,width = 32 ;
longint :有符号整数, width = 64 ;
real :双精度浮点
四状态数据类型:
integer : 有符号整数, width = 32 ;
time :无符号整数, width = 64 ;
对 四状态值 的检查
if( $isunknown( iport ) == 1 )
$display( " @%0t : four state value detected on iport %b ",$time,iport ) ;
2、定宽数组
相比于 veilog 支持的数据选择,SV提供更多的数据类型。
2.1、 定宽数组的声明和初始化
定宽数组的声明:
int one[0:15] ; //都表示 16个 int 的数组
int two[16] ;
多维数组的声明:
int one[0:7][0:3] ; //两种声明方式都可以
int two[8][4] ;
非合并数据的声明:表示三个temp_one 数组,每个数组有8个数
bit[7:0] temp_one[3] ;
常量数组:
int one[0:3] = '{ 0,1,2,3 } ;
int two[0:4] = '{ 4,5,default:1 } ;//two 为 { 4,5,1,1,1 }
2.2、 对数组的基本操作
在数组中使用 for 和 foreach 关键词。
initial
begin
bit[31:0] src[5] ;
bit[31:0] dst[5] ;
for( int i = 0 ; i < $size(src) ;i++ )
src[i] = i ;
foreach( dst[j] )
dst[j] = src[j]*2 ;
end
多维数组的初始化
int md[2][3] = '{ '{ 2,3,4 } , '{ 5,6,7 } } ;
initial
begin
$display(" Initial value: ") ;
foreach( md[i,j] )
$display(" md[%d][%d] = %0d ",i,j,md[i][j] ) ;
$display(" new value ") ;
md = '{ '{ 9,8,7 } ,'{ 3{32'd5} } } ;
foreach( md[i,j] )
$display(" md[%d][%d] = %0d ",i,j,md[i][j] ) ;
end
多维数组的打印
initial
begin
byte twoD[4][6] ;
foreach( twoD[i,j] )
twoD[i][j] = i*10 + j ;
foreach( twoD[i] )
begin
foreach( twoD[ ,j] )
begin
$write(" %3d " , twoD[i][j] ) ;
end
end
end
数组的复制和比较
initial
begin
bit[31:0] src[5] = '{ 0,1,2,3,4 } ;
bit[31:0] dst[5] = '{ 5,4,3,2,1 } ;
if( src == dst )
begin
$display(" src == dst ") ;
end
else
begin
$display(" src != dst ") ;
end
dst = src ;
src[0] = 5 ;
$display(" src %s dst ",(src == dst)?"==":"!=" ) ;
$display(" src[1:4] %s dst[1:4] ",(src[1:4] == dst[1:4] )?"==":"!=" ) ;
end
同时使用位下标和数组下标
verilog-1995 不支持 同时使用 数组下标和位下标,verilog-2001取消了这个限制。
initial
begin
bit[31:0] src[5] = '{ 5{5} } ;
$displayb( src[0] ,,
src[0][0] ,,
src[0][2:1]
);
end
合并数组 : 等待数组的变化的时候,必须使用合并数组
bit [3:0} [7:0] data ; //4 个 8bit的data的数组
3、动态数组
使用动态数组
int dyn[] , d2[] ; //动态数组声明
initial
begin
dyn = new[5] ; //给dyn分配 5 个空间
foreach( dyn[j] )
begin
dyn[j] = j ;
end
d2 = dyn ;
d2[5] = 0 ;
$display(dyn[0],d2[0]);
dyn = new[20](dyn) ; //为dyn分解 20 个空间 并复制 原来的数据
dyn = new[100] ;
dyn.delete() ; // 删除所有元素
end
使用动态数组保存元素数量不一定的list
bit [7:0] mask[] = '{
8'b0000_0000 , 8'b0000_0001 ,
8'b0000_0010 , 8'b0000_0011 ,
8'b0000_0100 , 8'b0000_0111 ,
8'b0000_1000 , 8'b0000_1111 ,
8'b0001_0000 , 8'b0001_1111
};
可以把一个 顶宽数据 复制到 动态数据,SV会为动态数组分配空间(new[ ])并复制数组。
4、队列
队列的操作:队列的常量不用 ' 。
module demo_2_9();
int j = 1 ,
q2[$] = { 3,4 } , //队列的声明
q[$] = { 0,2,5 } ;
initial
begin
q.insert(1,j) ; //插入元素
// q.insert(2,q2) ;
q.delete(1) ; //删除第一个元素
q.push_front( 6 ) ; //在q的前面插入 6
q.push_back( 8 ) ; //在q的后面插入 8
q.pop_back ; //删除最后一个元素并返回新的长度
q.pop_front ; //删除第一个元素并返回旧的的长度
foreach( q[i] )
begin
$display( q[i] ) ;
end
q.delete ; //删除q这个数组
end
endmodule
队列操作
int j = 1 ,
q2[$] = { 3,4 } ,
q[$] = { 0,2,5 } ;
int len_q = 0 ;
initial
begin
q = { q[0],j,q[1:$] } ;
q = { q[0:2],q2,q[3:$] } ;
q = { q[0],q[2:$] } ;
q = { 6,q } ;
len_q = q[$] ;//将q的长度复制给 j
q = q[0:$-1] ;//删除队列最后一个数
q = { q,8 } ;//在q之后插入 8
j = q[0] ;
q = q[1:$] ;
q = {} ;//删除队列
end