前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SystemVerilog教程之数据类型1

SystemVerilog教程之数据类型1

作者头像
猫叔Rex
发布2020-06-30 14:23:31
2.1K0
发布2020-06-30 14:23:31
举报
文章被收录于专栏:科学计算科学计算

内建数据类型

逻辑类型

  我们知道,Verilog中,有两种基本的数据类型:regwireregalwaysinitialtaskfunciton中被赋值,wire使用assign赋值。

  在systemVerilog中,引入了新的逻辑(logic)类型来代替reg类型和部分wire类型的功能,因此在sv中,编译器可自动判断logicreg还是wire。之所以说取代了部分wire类型的功能,是因为logicwire还是有点区别的:wire类型可以被多重驱动,比如inout类型;但logic类型不能被多重驱动,因此inout类型不能被定义为logic

  所以,总结logic的用法,

  • 单驱动时logic可完全替代reg和wire
  • 多驱动时,如inout类型端口,使用wire

双状态数据类型

  systemVerilog主要是做仿真用的,当然,现在越来越多的人开发FPGA也都是用systemVerilog。为了提高仿真器的性能并减少内存的使用量,它引入了双状态数据类型。什么是双状态数据类型?就是它的值只能是0或者1这两个状态,而Verilog中,wirereg都是四状态数据类型,除了0和1之外,还可能是z或者x,上面讲到的logic就是四双态数据类型。

代码语言:javascript
复制
bit b;               //双状态,单比特
bit [7:0] b8;        //双状态,8位无符号数
int i;               //双状态,32位有符号数
int unsigned ui;     //双状态,32位无符号数
byte b8;             //双状态,8位有符号数
shortint s;          //双状态,16位有符号数
longint l;           //双状态,64位有符号数
integer i4;          //四状态,32位有符号数
time t;              //四状态,64位无符号数
real r;              //双状态,双精度浮点数

  可以看到,systemVerilog中,既有双状态数据类型,也有四状态数据类型,这就很容易带来一个问题。当某个模块的输出是logic型,而在例化时,输出到了一个双状态类型上。如果都是正常的0或者1,那没什么问题;如果输出为x或者z,那这些值就被转换成了0或者1,关于这一点的内容,我们后续面会专门讲到。

定宽数组

数组声明

  SystemVerilog中的数组跟C是很像的,下面两种定义方式的效果是一样的。

代码语言:javascript
复制
int arr[0:15];         //包含16个int类型的数组
int c_arr[16];       

多维数组的定义方式:

代码语言:javascript
复制
int arr1[0:7][0:3];    //完整的声明
int arr2[8][4];        //紧凑的声明
arr2[7][3] = 10;       //设置最后一个元素为10

  在C中,是不对数组越界进行检查的,当从一个越界的地址上读数时,也可以得到结果,这个结果是内存中的某个数据;但SystemVerilog中有数组越界的检查,当代码中试图从一个越界的地址中读取数据时,会返回数组元素类型的缺省值。对于四状态类型的数组,比如logic,会返回X,对于双状态类型的数组,比如intbit,会返回0

  这适用于所有的数组类型,包括定宽数组、动态数组、关联数组和队列,也同时适用于地址中含有XZ的情况。wire在没有驱动时输出Z.

数组的初始化

  在声明一个数组时,可以直接对其初始化,也可以先声明数组,再进行赋值,跟C的用法基本一致,但赋值的语法有所区别。

代码语言:javascript
复制
int arr1[3] = '{1,2,3};
int arr2[4];
arr2 = '{0,1,2,3};
arr2[0:2] = '{4,5,6};
arr2 = '{4{7}};              //四个值都是7
arr2 = '{8,9,default:10};    //{8,9,10,10}
int arr3[2][3] = '{'{0,1,2},'{3,4,5}};  //多维数组初始化

数组遍历

  数组遍历最常用的语法就是for,SystemVerilog提供了forforeach关键字来进行数组的遍历,其中for的用法跟C中基本一致,foreach的用法倒是跟Python中的for itm in的用法很像,下面程序中$size表示数组中元素个数。

代码语言:javascript
复制
initial begin
    byte src[5], dst[5];
    for(int i=0; i<$size(src); i++)
        src[i] = i;

    foreach (dst[j])
        dst[j] = src[j] * 2;
end

  我们前面讲了多维数组的初始化,下面来看下多维数组的遍历,在语法上还是有区别的,这也是SystemVerilog蛋疼的地方,现在编程语言虽然很多,但一些常规的语法都是一样的,在使用SystemVerilog中要多注意一下。

代码语言:javascript
复制
int md[2][3] = '{'{0,1,2},'{3,4,5}};
initial begin
    foreach(md[i,j])                                      //注意,不是md[i][j]
        $display("md[%0d][%0d] = %0d", i, j, md[i][j])   // 这里使用md[i][j]
end

  在遍历时,如果不需要所有维度,可以在foreach循环中忽略掉。

代码语言:javascript
复制
initial begin
    byte md[2][3] = '{`{0,1,2},'{3,4,5}};
    foreach(md[i]) begin
        foreach(md[,j])
            $display("%0d", md[i][j]);
    end
end

数组的拷贝和比较

  复制和比较是数组中很常用的操作,在C中,比较数组是否相同需要用到strcmp()函数,数组的拷贝需要用到memcpy()函数,但SystemVerilog中将该操作简化,这一操作跟Python很类型。

代码语言:javascript
复制
initial begin
    byte src[4] = '{0,1,2,3,4},
         dst[4] = '{4,3,2,1,0};
    if (src == dst)
        $display("src == dst");
    else
        $display("src != dst");
    dst = src;                   //数组拷贝操作
end

合并数组和非合并数组

  SystemVerilog仿真器在存放数组时一般都是使用32比特的字边界,所以byteshortintint都是存放在一个字中,而longint存放在两个字中,这样就是采用非合并数组的方式。

代码语言:javascript
复制
bit [7:0] b_unpack[3];    // 非合并数组定义
bit [2:0][7:0] b_pack;    // 合并数组定义

  在合并数组的声明中,合并的位和数组大小作为数据类型的一部分必须在变量名前面指定,而且数组大小定义的格式必须是[msb:lsb],而不是[size]。

内存中的存放方式如下:

非合并时数组的存放:

合并数组的存放:

  讲到这里,我们就再补充一点,对于logicinteger等四状态类型,仿真器通常使用两个或两个以上连续的字来存放,这会比双状态变量多占用一倍的空间。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-04-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 傅里叶的猫 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 内建数据类型
    • 逻辑类型
      • 双状态数据类型
      • 定宽数组
        • 数组声明
          • 数组的初始化
            • 数组遍历
              • 数组的拷贝和比较
                • 合并数组和非合并数组
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档