⼀、SystemVerilog-数据类型
⼀、内建数据类型
1. 逻辑(logic)类型
  logic类型是对reg类型的改进,使得它除了作为⼀个变量以外,还可以被连续赋值、门单元和模块驱动。任何使⽤线⽹的地⽅都可以使⽤logic,但要求logic不能有多个结构性驱动,如在双向总线建模时,不能使⽤logic。
2. 双状态数据类型
  (1)最简单的双状态数据类型是bit,他是⽆符号的。另四种带符号的双状态数据类型是 byte,shortint,int 和 longint。
  (2)使⽤($isunknown)操作符,可以在表达式的任意位出现X或Z时,返回1。
⼆、定宽数组
1. 声明
  int  lo_hi[0 : 15] ;    // 16个整数[0] ....[15],等价于 int lo_hi[16] ;
  可以通过在变量名后⾯指定维度的⽅式来创建多维定宽数组
  int  array[0 : 7][0 : 3] ;  // 完整的声明
  int  array[8][4] ;    // 紧凑的声明
  如果代码试图从⼀个越界的地址中读取数据,那个SV将会返回数组元素的缺省值。对于⼀个元素为四状态类型的数组,例如logic,返回的是X,⽽对于双状态类型,例如int或bit,则返回0。这适⽤于所有的数组类型,包括定宽数组、动态数组、关联数组和队列,也同时适⽤于地址中含有X或Z的情况。线⽹在没有驱动的时候输出Z。
  SV仿真器在存放数组元素时,使⽤32⽐特的字边界,所以 byte,shortint 和 int 都是存放在⼀个字中,⽽ longint 则存放到两个字中。在⾮合并数组中,字的低位⽤来存放数据,⾼位则不⽤。
2. 常量数组
  int  ascend[4] = `{0, 1, 2, 3};    // 对4个元素进⾏初始化
  int descend[5];
  descend[0:2] = `{5,. 6, 7};     // 为前3个元素赋值
  ascend = `{4{8}};         // 四个值全是8
  descend = `{9, 8, default:1};    // {9, 8, 1, 1, 1}
3. 基本数组操作——for和foreach
  对多维数组使⽤foreach时,并不是像[i][j]这样把每个下标分别放在不同的括号⾥,⽽是⽤逗号隔开放在同⼀个⽅括号⾥,像[i, j],如foreach(md[i, j]) begin ... end
4.合并数组
  声明合并数组时,合并的位和数组⼤⼩作为数据类型的⼀部分必须放在变量名前⾯指定。数组的⼤⼩定义的格式必须是[msb : lsb],⽽不是[size] 。
  eg:bit[3 : 0] [7 : 0] bytes ;   // 4个字节组装成32⽐特
三、动态数组
  动态数组在声明时使⽤空的下标[ ],这意味着数组的宽度不在编译时给出,⽽在程序运⾏时再指定。数组在最开始时是空的。所以你必须⽤new[ ]操作符来分配空间,同时在⽅括号中传递数组宽度。可以把数组名传给new[ ]构造符,并把已有数组的值复制到新数组⾥。
eg:int dyn[], d2[];
  initial begin
    dyn = new[5];      // 分配5个元素
union是什么类型    foreach(dyn[j])    // 对元素进⾏初始化
      dyn[j] = j;   
    d2 = dyn;        // 复制⼀个动态数组
    dyn = new[20](dyn);    // 分配20个整数并进⾏复制
    dyn = new[100];    // 分配100个新的整数值,旧值不复存在
    dyn.delete();      // 删除所有元素
  end
  系统函数 $size 的返回值是数组的宽度。动态数组可以在声明直接进⾏初始化。当把⼀个定宽数组复制给⼀个动态数组时,SV会⾃动调⽤构造函数new[ ]来分配空间并复制数值。
四、队列
  队列的声明是使⽤带美元符号的下标:[$]。队列元素的编号从0到$。队列的常量中只有⼤括号⽽没有数组常量中开头的单引号。注意不要对队列使⽤构造函数new[ ]。
  队列在声明以后,只能通过索引或⽅法两种⽅式进⾏初始化。
  队列的⽅法有insert 、pop_front、push_back、delete等。
  如果把$放在⼀个范围表达式的右边,则代表最⼤值,如果$放在⼀个范围表达式的左边,则代表最⼩值。
五、关联数组
  关联数组采⽤在⽅括号中放置数据类型的形式来声明。例如 [int] 或 [packet] 。
  关联数组的声明、初始化和遍历过程:
  initial begin
    bit [63:0] assoc[bit [63:0]] , idx = 1;   // 声明
    repeat (64) begin          // 初始化
      assoc[idx] = idx;
      idx << 1;
    foreach (assoc[i])           // 使⽤foreach进⾏遍历
      $display("assoc[%h] = %h", i, assoc[i]);
    if (assoc.first(idx)) begin        // 使⽤函数进⾏遍历
      do
        $display(assoc[%h] = %h", idx, assoc[idx]);
      while ((idx));
    end
    // 到并删除第⼀个元素
    assoc.first(idx); 
    assoc.delete(idx);
  end
六、数组的⽅法
1. 数组的缩减⽅法
  最常⽤的缩减⽅法是sum,它对数组中的元素进⾏求和。这⾥必须对SV处理操作位宽的规则⼗分⼩⼼。缺省情况下,如果你把⼀个单⽐特数组中的元素相加,其和也是单⽐特的。但如果你使⽤32⽐特的表达式,把结果保存在32⽐特的变量⾥,与⼀个32⽐特的变量进⾏⽐较,或者使⽤适当的with表达式,
SV都会在数组求和过程中使⽤32⽐特位宽。
  SV没有提供专门从数组中随机选取⼀个元素的⽅法,所以对于定宽数组、队列、动态数组和关联数组来说,可以使⽤
$urandom_range($size(array) - 1),⽽对于队列和动态数组还可以使⽤$urandom_range(array.size() - 1)。
2. 数组的定位⽅法
  常⽤的数组定位⽅法有min、max、unique和find,unique⽅法返回的是在数组中具有唯⼀值的队列,即排除掉重复的数值。以上min、max、unique和find⽅法的返回值是⼀个队列。
  当把数组缩减⽅法与条件语句with结合使⽤时,你会发现惊⼈的结果。例如sum⽅法,其结果是条件表达式为真的次数。
3.数组的排序
  常⽤的排序⽅法有reverse(逆向排序),sort(从⼩到⼤排序),rsort(从⼤到⼩排序),shuffle(随机排序)。其中,reverse和shuffle⽅法不能带with条件语句。
七、使⽤typedef创建新的类型
  在Verilog中,可以使⽤宏(macro)为⼀个操作数定义位宽和类型,然后通过(` 变量名)的⽅式引⽤。这种情况下并没有创建新的类型,只是在进⾏⽂本替换。SV中可以使⽤typedef创建新的类型。
eg:parameter  OPSIZE = 8;
  typedef reg[OPSIZE - 1 : 0] opreg_t;   // 新的数据类型
  opreg_t  op_a, op_b;
⼋、创建⽤户⾃定义结构
1. 使⽤struct创建新类型
  把若⼲个变量组合到⼀个结构,struct  {bit  [7 : 0]  red, green, blue;}  pixel;  // 创建⼀个新的结构
  上⾯只是创建了⼀个新的结构,要想使⽤它,必须创建⼀个新的类型, typedef  struct  {bit  [7 : 0]  red, green, blue;}  pixel_s;  //创建⼀个类型
2. 对结构进⾏初始化
  typedef  struct {int a; byte b; shortint c; int d;}  my_struct_s;
  my_struct_s  st = `{32'haaaa_aaaa, 8'hbb, 16'hcccc, 32'hdddd_dddd};
3. 创建可容纳不同类型的联合
  typedef union {int i; real f;}  num_u;
4. 合并结构
  typedef struct packed {bit  [7 : 0]  red, green, blue;}  pixel_p_s;
  pixel结构使⽤了三个数值,所以占⽤了三个长字的存储空间,即使它只需要三个字节,使⽤packed可以将三个变量合并在尽可能⼩的空间⾥。
九、类型转换
1. 静态转换
  静态转换操作不对转换值进⾏检查。转换时指定⽬标类型,并在需要转换的表达式前加上单引号即可。
  eg:int  i;
    real  r;
    i = int `(10.0-0.2);
    r = real `(42);
2. 动态转换
  动态转换函数$cast允许你对越界的数值进⾏检查。当$cast被调⽤时,⽬的在于把其右边的值赋给左边的量。如果赋值成功,$cast()返回1.
3. 流操作符
  流操作符<<;和>>⽤在赋值表达式的右边,后⾯带表达式、结构或数组,⽤于把其后的数据打包成⼀
个⽐特流。流操作符>>把数据从左⾄右变成流,⽽<<;则把数据从右⾄左变成流。不能将⽐特流直接赋给⾮合并数组,⽽应该在赋值表达式的左边使⽤流操作符把⽐特流拆分到⾮合并数组中。
  数组下标失配是在数组间进⾏流操作时常见的错误。数组声明中的下标[256]等同于[0:255],⽽⾮[255:0],使⽤流操作把使⽤[high:low]形式数组的值赋给带[size]下标形式的数组,会造成元素倒序。同样,如果把声明形式为bit [7:0] src[255:0]的⾮合并数组使⽤流操作赋值给声