SV_数据类型

数据类型

SV新特性:对比VERILOG

  • 2值逻辑:提高性能,减少内存使用;
  • 队列,动态数组,关联数组:减少内存使用,内建搜索和排序函数;
  • unions 和 packed;
  • class 和 structures
  • string
  • enumerated

赋值

  • 赋全值(全0,全1,全x,全z)时,可以忽略位宽
  • 注意verilog赋全1时,不能忽略位宽,也不能忽略进制。
// verilog
parameter SIZE=64;
logic [SIZE-1:0] data;
data=`b0;
data=`bz;
data=`bx;
data=64'hFFFFFFFFFFFFFFFF;


//sv
parameter SIZE=64;
logic [SIZE-1:0] data;
data=`0;
data=`z;
data=`x;
data=`1;

4值逻辑

  • 4值逻辑:0,1,x, z
  • integer,  logic,  reg,  net_type(例如wire,  tri)

logic

  • 支持连续赋值,门逻辑和模块;
  • 不支持多驱动,(例如:双向端口,inout,只能用wire不能用logic);
  • 可以替代VERILOG中的reg类型

2值逻辑

  • bit, byte, shortint, int, longint
  • 2值逻辑:0和1;z和x 会转换成0
  • 提升仿真性能和减少内存使用
  • 不适用于DUT,因为DUT识别z和x,但是2值逻辑将会转换为0
类型 描述 例子
bit unsigned bit b;  bit [31:0] b32;
byte 8 bits, signed byte b8; (-128~127)
shortint 16 bits, signed shortint s;
int 32 bits, signed int i;
longint 64 bits, signed longint l;

2值逻辑和4值逻辑

  • 仿真时,4值逻辑默认为x,2值逻辑默认为0
  • 2值逻辑变量不能代表一个未初始化的状态
  • 4值逻辑可以赋值给2值逻辑变量,x和z会转化成0
  • 使用$isunknown() check任何bit是x或z,如果表达式任何一个bit是z或x,返回1;if($isunknown(iport)==1);

有符号和无符号

  • 有符号: byte,  shortint,  int,  longint,  integer
  • 无符号:    bit,  logic,  reg,  net-type(例如wire,   tri)

数据类型转换

静态转换

  • 在转换的表达式前加上单引号即可
  • 不会対转换值做检查,如果转换失败,无从得知
  • 在编译的时候做检查
  • 有符号转换成无符号: unsigned'(signed_vec)

动态转换

  • 在仿真的时候做检查
  • $cast(tgt, src)

显示转换

  • 静态转换和动态转化都需要操作符号或者系统函数介入

隐式转换

  • 不需要进行转换的一些操作

定宽数组

  • 支持多维数组
  • 超过边界写将会被忽略,超过边界读将会返回x,2值逻辑也是返回x;
  • byte,int, shortint,都是存储在一个32位的空间中
  • longint存储在两个32位的空间中
  • 默认为unpacked数组

语法

type name [constant];  type  name  [0: constant];

int array[20];                     // 元素:0-19
int array[64:83];                  // 元素:64-83
logic [31:0] data [1024];        // 元素: 0-1023, 32位宽

int array1 [4]=`{3,2,4,1};   

array1 [0:2]=`{5,6,7};

array1=`{{3}, `{3{8}}};

int md [2][3] = `{`{0,1,2}, `{3,4,5}};                 

存储空间:pack vs unpack

//  两个变量都可以表示24bit的数据容量
//  b_pack只会占据 1 个 WORD 的存储空间
//  b_unpack占据 3 个 WORD 的存储空间
//  如果变量前后都有容量定义,右边的维度高,即b_unpack的3的维度高

bit [3][7:0]  b_pack
bit [7:0]  b_unpack[3];

// logic是四值逻辑,即需要2bit
logic [3][7:0]   b_pack;       // 2 个WORD    2*8*3 
logic [7:0]   b_unpack[3];   //  3 个WORD    2*8=16, 1个WORD

    

数组复制和比较

  • 可以利用赋值符号  "="  直接进行数组的复制

  • 可以直接利用   "==" 或者  "!=" 来比较数组的内容,结果仅限于内容相同或者不相同

 动态数组

  •  定宽数组的宽度在编译时就确定了;

  • 动态数组可以在仿真运行时灵活调节数组大小,即存储量
// 动态数组在声明时,需要使用  []  声明,此时数组数组是空的,即0容量
// 使用new[]  来分配空间,在方括号中传递数组的宽度
// 也可以在调用 new[] 时将数组名传递,将已有的数组的值复制到新的数组中


initial begin: dynamic_array
  int dyn1[], dyn2[];
  
  dyn1 = new[5];         // 分配5个元素  
  dyn1 = '{1, 2, 3, 4};
  $display("dyn1 = %p", dyn1);
  // copp method option-1
  dyn2 = dyn1;           // 重新复制一份数据到dyn2,相当于深拷贝
  $display("dyn2 = %p", dyn2);
  $display("dyn2 size is %0d", dyn2.size());
  // copp method option-2
  dyn2 = new[dyn1.size()](dyn1);
  $display("dyn2 = %p", dyn2);
  $display("dyn2 size is %0d", dyn2.size());
  dyn2.delete();
  $display("dyn2 size is %0d", dyn2.size());
end

队列 

  •  可以在任何地方添加或删除元素,并且通过索引实现队任一元素的访问 
  • 使用美元符号声明:[$],元素标号从0到$
  • 不需要使用new[] 去创建空间,一开始其空间为0
  • 使用 push_back 和 pop_front 结合实现FIFO的用法,还有push_front 和 pop_back
initial begin: queue_use
  int que1[$], que2[$];
 
  que1 = {10, 30, 40};            // 不需要使用单引号赋值
  $display("que1 = %p", que1);
  que2 = que1;
  $display("que2 = %p", que1);

  que1.insert(1, 20);
  $display("que1 = %p", que1);

  que1.delete(3);                     // delete que1[3]==40
  void'(que1.pop_front());         // pop que[0]==10
  $display("que1 = %p", que1);
  
  foreach(que1[i])
       $display(que1[i]);

  que1.delete();
  $display("que1 = %p", que1);

end            

 关联数组

  • 用来保存稀疏矩阵的元素
initial begin: associate_array
  int id_score1[int], id_score2[int];     // key ID, value SCORE
  
  id_score1[101] = 111;
  id_score1[102] = 222;
  id_score1[103] = 333;

  // associate array copy
  id_score2 = id_score1;
  id_score2[101] = 101;
  id_score2[102] = 102;
  id_score2[103] = 103;

  foreach(id_score1[id]) begin
    $display("id_score1[%0d] = %0d", id, id_score1[id]);
  end
  foreach(id_score2[id]) begin
    $display("id_score2[%0d] = %0d", id, id_score2[id]);
  end

   if(id_score.first(idx)) begin
       do
           $display("id_score[%d]=%d", idx, id_score[idx]);
       while(id_score.next(idx));
   end

end    

结构体

  • 数据的集合
  • 使用struct语句创建
  • 结合typedef可以用来创建新的类型,并利用新类型来声明更多的变量
struct {
              bit [7:0] r,g,b;
          }   pixel;                         // 创建一个pixel结构体  
         
typedef struct {
              bit [7:0] r,g,b;
          }   pixel_s;
pixel_s     my_pixel;    // 声明变量
my_pixel = `{'h10, 'h10, 'h10};   // 赋值
 

枚举

  • 可读性和可维护性更好
  • 结合typedef使用
  • 枚举类型可以直接赋值给整型: int a = INIT;
  • 整型不能直接赋值给枚举类型,需要进行转换
typedef enum {INIT,DECODE,IDLE}  fsmstate_e;

fsmstate_e pstate, nstate;   //  声明自定义类型变量

case(pstate)
        IDLE: nstate = INIT
        INIT : nstate = DECODE;
        default:  nstate = IDLE;
endcase
$display("Next state is %s", nstate.name());

字符串(string)

  • SystemVerilog 包含一个string数据类型,它是一个可变尺寸、动态分配的字节数组。
  • SystemVerilog 还包含许多特殊的方法来对字符串进行操作。
    • string类型的变量可以从0到N-1(数组的最后一个元素)进行索引
    • 可以作用于一个特殊的空字符串:""
    • 从一个字符串读取一个元素会产生一个字节
    • string类型变量的索引从字符串的左侧开始排列,例如:对字符串"Hello World!",索引0对应"H",索引1对应"e",依此类推...
    • 如果在声明中没有指定初始值,变量会被初始化成空字符串("")
    • $sformatf()  函数: 格式化函数
    • $display()  函数: 打印函数
string s;
initial begin 
    s = "IEEE";
    $display (s.getc(0));      //显示第0个字符: I

    $display (s.tolower());     //显示小写字符: ieee

    s.putc(s.len() - 1,"-");       //putc是替换,len() - 1是字符串最后一位,即将最后一位替换成“ -”

    s = {s,"P1800"};                 //字符串拼接 ->IEE-P1800

    $display(s.substr(2,5));         // 显示第2-5位字符 ->E-P1
    //创建一个临时字符串并将其打印
    my_log ($sformatf("%s,%5d",s,42));
end
task my_log (string message); //打印信息 $display ("@%0t:%s",$time,message); endtask

for循环

// $size 默认获得最高的维度

initial begin
    bit        [31:0]  src[5],    dst[5];
    for(int i=0;i<$size(src); i++)
        src[i] = i;
end

foreach循环

//  自动创建变量j, 默认为最高维度
initial begin
    bit        [31:0]  src[5],    dst[5];
    foreach(dst[j])
        dst[j]  = j;
end    
原文地址:https://www.cnblogs.com/gareth-yu/p/14200691.html