首页 > 其他分享 >SV 第二章 数据类型

SV 第二章 数据类型

时间:2023-07-31 18:22:37浏览次数:29  
标签:0d temp int 数据类型 SV write 数组 第二章 display

SystemVerilog验证

2 数据类型

相比较于Verilog,SystemVerilog引入了新的数据结构,具有如下优点:

  1. 双状态数据类型:更好的性能,更低的内存消耗
  2. 队列、动态和关联数组:减少内存的消耗,自带搜索和分类功能
  3. 类和结构:支持抽象数据结构
  4. 联合和合结构:允许对同意对数据有多种视图
  5. 字符串:支持内奸字符序列
  6. 枚举类型:方便代码编写,增加可读性

2.1 内建数据类型

逻辑(logic)类型

SystemVerilog改进了Verilog中的reg类型,使得可以杯连续赋值、门单元和模块驱动,但要求logic不能有多个结构性的驱动。

module logic_data_type(input logic rst_h);
    parameter CYCLE = 20;
    logic q,q_1,d,clk,rst_1;
    initial begin
        clk=0;								// 过程赋值
        forever # (CYCLE/2) clk = ~clk;
    end
    
    assign rst_1 = ~rst_h;					// 连续赋值
    not n1(q_1,q);							// q_1被门驱动
    my_dff d1(q,d,clk,rst_1);				// q被模块驱动
    

logic只能由一个驱动,可以用来查找网络中的漏洞,把所有的信号声明为logic,如果存在多个驱动,那么编译就会报错,希望由多个驱动的时候定义成线网类型,例如wire

双状态数据类型

integer i4;				// 四状态,32比特有符号整数
time t;					// 四状态,64比特无符号整数
real r;					// 双状态,双精度浮点数

// SystemVerilog独有
bit b;					// 双状态,单比特
bit [31:0] b32;			// 双状态,32比特无符号整数

byte b8;				// 双状态,8比特有符号整数
shortint s;				// 双状态,16比特有符号整数
int i;					// 双状态,32比特有符号整数
longint l;				// 双状态,64比特有符号整数

int unsigned ui;		// 双状态,32比特无符号整数

将双状态变量连接到被测设计时,尤其是被测设计的输出时,务必要小心,如果试图产生X、Z,这些值会被转换成双态值。可以使用($isunkonwn)操作符,在出现X或Z时返回1。

if($isunkown(iport) == 1)
    $display("@%0t: 4-state value detected on iport %b", $time, iport);

使用%0t和参数$time可以打印出当前的仿真时间,打印的格式在$timeformat()子程序中指定

2.2 定宽数组

在SystemVerilog中,定宽数组的定义和C语言类似,相比于Verilog,增加了紧凑的定义方式。例如:

int a_1[0:15];			// 16个整数[0]...[15]
int a_2[16];			// 16个整数[0]...[15]

int array2[0:7][0:3];	// 完整声明
int array3[8][4];		// 紧凑声明
array2[7][3] = 1;		// 给最后一个元素赋值

数据越界访问的时候,SystemVerilog会返回数组类型的缺省值。例如四状态类型logic类型返回X,双状态类型int和bit返回0.这适用于所有的数组类型,包括定宽数组、动态数组、关联数组和队列。

很多仿真器的使用32位的字边界,byte、shortint、int都是存放在一个字中,longint存放在两个字中。所以非合并数组在存放四状态变量时双状态变量多用一倍空间。

常量数组

和C语言一样,SystemVerilog支持在定义时为数组赋值,给数组一个缺省值。

int ascend[4] = '{0,1,2,3};			// 为四个元素进行初始化
int descend[5];

descend = '{4,3,2,1,0};				// 赋值五个元素
descend[0:2] = '{5,6,7};			// 赋值前三个元素
descend = '{4{8}};					// 四个值全部为8
descend = '{9,8,default:1};			// {9,8,1,1,1}

基本的数组操作-for和foreach

使用for遍历时,可以使用$size函数返回数组的宽度,再循环中声明局部变量,使用foreach循环,指定数组名并在后面的方括号中给出索引变量。例如:

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

对于多维数组来说,例如:

byte two[4][6];						// 二维数组

foraeach(two[i]) begin				// 遍历第一个维度
    $write("%2d:", i);
    foreach(two[,j])
        $write("%3d", two[i][j]);	// 遍历第二个维度
    $display;
end

foreach循环遍历的时原始声明中的数组范围。例如:

f[5]等同于f[0:4],而foreach(f[i])等同于for(int i = 0; i <= 4; i++)

rev[6:2]中,foreach(rev[i])等同于for(int i = 6; i >= 2; i--)

基本的数组操作-复制和比较

对于数组的复制和比较可以通过运算符直接进行。

initial begin
    bit [31:0] 	src[5] = `{0,1,2,3,4},
    dst[5] = `{5,4,3,2,1};
    // 聚合比较
    if (src == dst)
        $dislpay("src == dst");
    else 
        $display("src != dst");
    
    // 复制
    dst = src;

同时使用位下标和数组下标

在SV中,数组下标和位下标可以同时使用

initial begin
    bit [31:0] src[5] = `{5{5}};
    $displayb (src[0],,			// ’b101 或 ‘d5
               src[0][0],,		// ‘b1
               src[0][2:1]);	// ’b10
end

合并数组

可以将多个数组合并成一个数组使用,与非合并数组不同,合并数组的存储空间是连续的。数组定义大小的格式必须必须是[msb:lsb]。

bit [3:0][7:0] bytes;		// 4个字节数组仔庄承32比特
bytes = 32'hCafe_Dada;
$display(bytes,,			// 显示所有的32比特
         bytes[3],,			// 最高字节“CA”
         bytes[3][7]);		// 最高位比特“1”

2.3 动态数组

如果程序运行前不知道数组的宽度,那么如果使得数组容量足够大,会导致资源浪费,可以使用动态数组来存储数据。动态数组只有一维,而且不能被合并。

int dyn[], d2[];					// 动态数组的声明

initial begin
    dyn = new[5];					// 给数组dyn分配五个元素
    foreach (dyn[j]) dyn[j] = j;	// 对元素进行初始化
    d2 = dyn;						// 复制一个动态数组
    d2[0] = 5;						// 修改动态数组的值
    $display(dyn[0], d2[0]);		// 显示数值(0和5)
    dyn = new[20](dyn);				// 不改变原值的方式进行拓展
    								// 首先为dyn申请了20个元素
    								// 然后将dyn之前的五个元素拷贝进去
    								// 释放之前五个元素占用的空间
    dyn = new[100];					// 为dyn分配100个元素,释放之前元素的空间
    dyn.delete();					// 删除dyn所有元素
end

可以使用动态列表来保存不定长但是定宽的列表,并且只要基本的数据类型相同,定宽数组和动态数组之间就可以相互赋值。

2.4 队列

SV中引入的新的数据类型,结合了链表和数组的优点。可以在一个队列中任何地方增加和删除元素,性能损失比动态数组小,队列的声明式使用美元符号的下标,队列的编号可以从0到$。

int j = 1,					
q2[$] = {3, 4},				// 队列的常量不需要使用'
q[$] = {0, 2, 5};			// {0, 2, 5}

initial begin
    q.insert(1, j);			// {0,1,2,5}		在2之前插入1
    q.insert(3, q2);		// {0,1,2,3,4,5}	在q中插入一个队列
    q.delete(1);			// {0,2,3,4,5}		删除第1个元素
    
    // 下面的操作执行速度很快
    q.push_front(6);		// {6,0,2,3,4,5}	在队列前插入6
    j = q.pop_back;			// {6,0,2,3,4}		取出队尾 j = 5
    q.push_back(8);			// {6,0,2,3,4,8}	在队尾插入8
    j = q.pop_front;		// {0,2,3,4,8}		取出队首 j = 6
    foreach (q[i])
        $display(q[i]);		// 打印整个队列
    q.delete();				// 删除整个队列
end

队列同样也可以使用字下标串联方式来对队列进行插值。

int j = 1,					
q2[$] = {3, 4},				// 队列的常量不需要使用'
q[$] = {0, 2, 5};			// {0, 2, 5}

initial begin
    q = {q[0], j, q[1:$]};	// {0,1,2,5}
    q = {q[0:2],q2,q[3:$]};	// {0,1,2,3,4,5}
    q = {q[0],q[2:$]};		// {0,2,3,4,5}
    
    // 下面的操作执行速度很快
    q = {6,q};				// {6,0,2,3,4,5}	在队列前插入6
    q = q[0:$-1];			// {6,0,2,3,4}		取出队尾 j = 5
    q = {q,8};				// {6,0,2,3,4,8}	在队尾插入8
    q = q[1:$];				// {0,2,3,4,8}		取出队首 j = 6
    q = {};					// 删除整个队列
end

2.5 关联数组

如果需要创建一个超大容量的数组,例如有个几个G字节寻址的处理器进行建模,这个处理器可能只访问了存放代码和数据的几百或几千个字节,这种时候对于几个G的存储空间是一种浪费。

SV中可以使用关联数组来保存稀疏矩阵的元素,在对一个风长达的地址空间进行寻址的时候,SV只为实际写入的元素分配了空间。

关联数组实现了一个所声明类型的元素的查找表,用作索引的数据类型作为查找表的查找键值,并强制了一种顺序。

关联数组采用在方括号中放置数据类型的方式来进行声明,例如[int]或[Packet]

例如在声明中:bit [63:0] assoc[bit[63:0]]

前面的bit [63:0] 表示为一个64位bit向量的关联数组,后面表示使用64位bit作为关联数组的索引。

使用起来更像是字典,例如 使用字符串作为索引,数据类型位int,这样就构建了一个字符串和数字的对照表,或者数据类型位int,索引依然是int,用来保存地址对应的数据。


`include "uvm_pkg.sv"

module tb();

    import uvm_pkg::*;
	`include "uvm_macros.svh"

	initial begin
	    bit [63:0] assoc[bit[63:0]], idx = 1;

        // 对关联数据进行初始化
        repeat (64) begin
            assoc[idx] = idx;
            idx = idx << 1;
        end

        // 使用foreach遍历
        foreach (assoc[i])
            $display("assoc[%h] = %h", i, assoc[i]);

        // 使用 do while 遍历
        if (assoc.first(idx))  begin
            do
                $display("assoc[%h] = %h",idx,assoc[idx]);
                while (assoc.next(idx));
        end

        assoc.first(idx);
        assoc.delete(idx);
        $display("The arry now has %0d elements", assoc.num);
	end

endmodule

assoc.first(idx) 获取了关联数组的首项索引,然后把索引值给idx

assoc.next(idx) 获取了比idx大的最小索引,然后把索引值给idx

通过first next 和 do while 配合可以很好完成对于关联数组的遍历

num():数据长度

delete():删除指定索引或所有元素

exists():检查是否存在该索引,有返回1否则返回0

first():将指定的索引变量赋值为数组第一个索引的值

last():将指定的索引变量赋值为数组最后一个索引的值

next():索引变量被赋值为下一个条目的索引

prev():索引变量被赋值为上一个条目的索引

2.6 链表

虽然SV中提供了链表的数据结构,但是应当避免使用它,应当使用更简单高效的队列。

2.7 对数组的多种操作

  1. 缩减操作:以求和操作为例,对数组的所有元素求和,如果是单比特的数组,使用求和后也只有单比特。也可以使用with表达式,更改求和得到的位宽。在学习该部分的内容时,发现实际编译得到的结果和书本中不符合。具体如下。

    
        bit on[10];         // one bit
        int total;          // 32 bit
    
    	initial begin
            
            foreach (on[i])
                on[i] = i;
    
            $display("on.sum = %0d", on.sum);
            $display("on.sum = %0d", on.sum + 32'd0);
    
            total = on.sum;
            $display("on.sum = %0d", total);
    
            if (on.sum >= 32'd5)
                $display("sum has 5 or more");
    
            $display("int sum = %0d", on.sum with (int'(item)));
    
    
    

    以下是得到的结果:

    on.sum = 1
    on.sum = 1
    on.sum = 1
    int sum = 5
    

    所以,在求和时,如果想改变求和得到的位宽,最好使用with表达式来完成。由于后面在学习约束的时候会展开说with,这里就不展开说了。

    类似的缩减操作有 product (求积)、 and (与)、or(或)、xor(异或)

    在SV中没有提供专门从一个数组里随机选取一个元素的方法,对于定宽数组、队列、动态数组和关联数组可以使用$urandom_range($size(arry)-1),对于队列和动态数组还可以使用$urangom_range(array.size()-1)

  2. 数组的定位方法:

    数组的定位方法有很多:

    min():返回最小值

    max():返回最大值

    unique():返回在数组中具有唯一值的队列

    find():通过限定条件返回符合条件的数值队列

    find_index():通过限定条件返回符合条件的数值队列的索引

    find_first():返回满足条件的第一个数值

    find_first_index():返回满足条件的第一个索引

    find_last():返回满足条件的最后一个值
    find_last_index():返回满足条件的最后一个索引

    
        int array[7] = '{1,3,3,9,9,10,21};
        int temp[$];
    
       	initial begin
            
            $write("The min is : ");
            temp = array.min();
            foreach(temp[i])
                $write("%0d ", temp[i]);
            $display();
    
            $write("The max is : ");
            temp = array.max();
            foreach(temp[i])
                $write("%0d ", temp[i]);
            $display();
    
            $write("The unique is : ");
            temp = array.unique();
            foreach(temp[i])
                $write("%0d ", temp[i]);
            $display();
    
            $write("Find item more 3 : ");
            temp = array.find() with (item > 3);
            foreach(temp[i])
                $write("%0d ", temp[i]);
            $display();
    
            $write("Find index that item more 3 : ");
            temp = array.find_index() with (item > 3);
            foreach(temp[i])
                $write("%0d ", temp[i]);
            $display();
    
            $write("Find the first item that equal to 9 : ");
            temp = array.find_first() with (item == 9);
            foreach(temp[i])
                $write("%0d ", temp[i]);
            $display();
    
            $write("Find the first index of item that equal to 9 : ");
            temp = array.find_first_index() with (item == 9);
            foreach(temp[i])
                $write("%0d ", temp[i]);
            $display();
    
            $write("Find the last item that equal to 9 : ");
            temp = array.find_last() with (item == 9);
            foreach(temp[i])
                $write("%0d ", temp[i]);
            $display();
    
            $write("Find the last index of item that equal to 9 : ");
            temp = array.find_last_index() with (item == 9);
            foreach(temp[i])
                $write("%0d ", temp[i]);
            $display();
    
    
    	end
    
    
    

    得到的结果如下:

          (Specify +UVM_NO_RELNOTES to turn off this notice)
    
    The min is : 1  
    The max is : 21  
    The unique is : 1 3 9 10 21  
    Find item more 3 : 9 9 10 21  
    Find index that item more 3 : 3 4 5 6  
    Find the first item that equal to 9 : 9  
    Find the first index of item that equal to 9 : 3  
    Find the last item that equal to 9 : 9  
    Find the last index of item that equal to 9 : 4  
               V C S   S i m u l a t i o n   R e p o r t 
    Time: 0 ps
    CPU Time:      0.200 seconds;       Data structure size:   0.2Mb
    Thu Jul 27 16:31:27 2023
    
    
  3. 数组的排序:SV中有几个可以改变数组中元素顺序的方法,可以对元素进行正排序、逆排序,或是打乱他们的顺序

    包含以下方法:

    reverse():反向,倒置

    sort():正排序,从小到大

    resort():逆排序,从大到小

    shuffle():打乱

    由于reverse和shuffle的作用域都是作用域整个数组的,所以不能使用with来限定区域

    
        struct packed {byte red, green, blue;} c[];
    
       	initial begin
    
            c = new[5];
            foreach (c[i])
                c[i] = $urandom;
    
            $display("Array item is : ");
            foreach (c[i]) begin
                $write("%0d,", c[i].red);
                $write("%0d,", c[i].green);
                $write("%0d\n", c[i].blue);
            end
    
            // sort the red firstly
            c.sort with (item.red);
    
            $display("Array item is : ");
            foreach (c[i]) begin
                $write("%0d,", c[i].red);
                $write("%0d,", c[i].green);
                $write("%0d\n", c[i].blue);
            end
    
            // sort the green and blue
            c.sort(x) with ({x.green, x.blue});
    
            $display("Array item is : ");
            foreach (c[i]) begin
                $write("%0d,", c[i].red);
                $write("%0d,", c[i].green);
                $write("%0d\n", c[i].blue);
            end
    
    	end
    
    
    

    得到的输出为:

          (Specify +UVM_NO_RELNOTES to turn off this notice)
    
    Array item is : 
    -30,53,54
    -34,-95,60
    127,-25,125
    -86,51,-30
    121,68,11
    Array item is : 
    -86,51,-30
    -34,-95,60
    -30,53,54
    121,68,11
    127,-25,125
    Array item is : 
    -86,51,-30
    -30,53,54
    121,68,11
    -34,-95,60
    127,-25,125
               V C S   S i m u l a t i o n   R e p o r t 
    Time: 0 ps
    CPU Time:      0.200 seconds;       Data structure size:   0.2Mb
    Thu Jul 27 16:52:48 2023
    
    

    由于对于约束的部分不太熟悉,这里保留一个疑问:关于先对green排序之后对于blue拍寻的结果,和我理解的不一样。

  4. 使用数组定位的方法来建立计分板:

    先定义一个包结构,然后建立一个由包结构队列组成的记分板

    module tb();
    
        typedef struct packed
        {
            bit [7:0]   addr;
            bit [7:0]   pr;
            bit [15:0]  data;
        } Packet;
        
        Packet scb[$];
    
        initial begin
    
            Packet temp;
            temp = 
            '{
                8'd200,
                8'd100,
                0
            };
            scb.push_back(temp);
    
            $display("scb is : %p", scb);
            $display("scb[0] addr is : %0d", scb[0].addr);
            check_addr(8'd100);
            check_addr(8'd200);
            check_addr(8'd200);
    
    	end
    
    
        function void check_addr(bit [7:0] addr);
    
            int intq[$];
    
            intq = scb.find_index() with (item.addr == addr);
    
            case (intq.size())
            0:  $display("Addr %0d not found in scoreboard", addr);
            1:  scb.delete(intq[0]);
            default:
                $display("ERROR: Multiple hits for addr %h", addr);
            endcase
    
        endfunction: check_addr
    
    
    endmodule
    

    代码的运行效果如下:

          (Specify +UVM_NO_RELNOTES to turn off this notice)
    
    scb is : '{'{addr:'hc8, pr:'h64, data:'h0}} 
    scb[0] addr is : 200
    Addr 100 not found in scoreboard
    Addr 200 not found in scoreboard
               V C S   S i m u l a t i o n   R e p o r t 
    Time: 0 ps
    CPU Time:      0.200 seconds;       Data structure size:   0.2Mb
    Thu Jul 27 18:33:40 2023
    

2.8 选择存储类型

灵活性

如果需要数组的索引时连续的非负整数,那就是用定宽数组或动态数组。

编译前就已经知道数据有多大的数组,直接用定宽数组就可以了,否则就用动态数组。

当你编写需要处理数组的子程序的时候,最好使用动态数组,这样可以只需要类型匹配就可以了,可以处理不同长度的数组。

如果数组的索引不规则时候,例如由于随机数产生的稀疏分布的索引,就应该使用关联数组了。

如果在仿真的过程中元素的数目变化很大的数目,例如计分板,那么队列是一个很好的选择。

存储器的用量

双状态类型可以减少仿真时的存储器用量,为了避免浪费,应当尽量选择32比特的整数倍作为数据位宽,因为仿真器通常会把小于32位宽的数据存放到32比特的字里。使用合并数组可以减少空间浪费。

对于具有大量数据的数组,数据的类型对于存储器的用量影响不大。如果

队列需要用到额外的指针,所以存取效率要比顶宽或动态数组稍微差一点。如果你把长度经常变化的数据集使用动态数组存放,那么在进行new[]来分配和复制内存的时候,这个代价很高。

速度

队列的读写速度和定宽数组、动态数组速度相当,但是如果队列长度过长,在进行插入曹茹的时候,可能会变得很慢。

关联数组常用的方法是使用哈希表和树形结构,所以关联数组的存取速度是最慢的。

排序

因为SV可以对任何一种一维数组进行排序,所以应该按照元素增加的繁琐程度来选择数组的类型,例如如果一次性全部加入的话就是用定宽数组或动态数组,如果元素是逐个加入到话,就是用队列。如果数组的值不连续并且彼此互异,那么可以使用关联数组,并把元素值本身作为索引。

选择最优的数据结构

  1. 网络数据包:特点是长度固定,顺序存取,针对长度固定和可变的数据包,可分别使用定宽或动态数组。
  2. 保存期望值的计分板:特点是仿真前长度位置,按值存取,长度经常变化,一般可以使用队列,方便在仿真期间连续增加和删除元素。如果计分板有数百个元素,并且需要在元素之间进行增删操作,则使用关联数组可能在速度上更快一些。
  3. 有序结构:如果数据按照可预见的顺序输出,那么可以使用队列,如果输出顺序不确定,则使用关联数组。
  4. 对超过百万个条目的特大容量存储器进行建模:如果你不需要用到所有的存储空间,可以使用关联数组来实现稀疏存储,在没有办法减少数据的使用量的情况下,请确保使用的是双状态的32比特合并数据。
  5. 文件中的命名名或操作码:特点是要把字符串转换成固定值,可以使用关联数组。

2.9 定义新的类型

使用typedef来定义新的类型,和C类似:

typedef bit [31:0] unit;
typedef int unsigned unit;

typedef struct{
    int addr,
    int pr,
    int data
} SCB;

2.10 创建用户自定义结构

即结构体,和C语言中的结构体基本一致。可以利用结构体,将不同的类型封装在一起,成为一种新的类型,如果在声明时,加入packed关键字,说明结构体是压缩的,存储空间之间没有间隙,属于合并结构。如果操作经常是针对结构体内部成员的,那么就应该优先使用非合并结构,尤其是不同元素之间长度不一的时候,对子元素的访问会比较消耗资源,如果经常对结构体的整体进行复制,那么应该使用合并结构,来减少存储空间的占用。以下是例子:

module tb();

    typedef union packed
    {
        shortint            si;
        shortint unsigned   usi;
    } my_union;
    typedef struct packed
    {
        bit [7:0] id;
        bit [7:0] addr;
        my_union un;
    }my_packet;

    initial begin
        
        my_packet pkt;

        pkt = 
        '{
            8'd100,
            8'd200,
            -16'd5
        };

        $display("The struct is : %p", pkt);
        $display("The si of union is : %0d", pkt.un.si);
        $display("The si of union is : %0d", pkt.un.usi);

	end
endmodule

以下是仿真输出结果:


      (Specify +UVM_NO_RELNOTES to turn off this notice)

The struct is : '{id:'h64, addr:'hc8, un:'{}}
The si of union is : -5
The si of union is : 65531
           V C S   S i m u l a t i o n   R e p o r t 
Time: 0 ps
CPU Time:      0.220 seconds;       Data structure size:   0.2Mb
Fri Jul 28 01:20:12 2023

结构体的部分很好理解,对于联合体的部分,是不同种类型的数据占用同一片存储区域,占用空间由最大位宽的数据种类决定。-5在有符号的情况下得到的是-5,在无符号的情况下得到的是65531,他们在二进制存储的时候是一致的。

2.11 类型转换

静态转换

在对静态的数据进行转换的时候,只需要在需要的类型后面加上',例如:

int i;
real r;

i = int'(10.0-0.1);
r = real'(42);

动态转换

使用 $cast(a,b) $cast被当成函数的时候,会把右边的值赋给左边的量,如果赋值成功返回1,如果不成功则返回0.这样做转换的好处是,会进行越界检查。如果把$cast当作任务来使用,则会打印出错误信息。

流操作符

流操作符用于把后面的数据打包成一个比特流,>>表示从左到右打包,<<表示从右到左打包。例子如下:

module tb();

    function void pack_array_int(const ref bit [7:0] array[4], output int a);
        a = {<<byte{array}};
    endfunction

    initial begin
        
        bit [7:0] array[4] = '{8'h11, 8'h22, 8'h33, 8'h44};
        int pack_result;

        pack_array_int (array, pack_result);

        $display("The result is : 0x%h", pack_result);

    end

endmodule

以下是仿真结果:

     (Specify +UVM_NO_RELNOTES to turn off this notice)

The result is : 0x44332211
           V C S   S i m u l a t i o n   R e p o r t 
Time: 0 ps
CPU Time:      0.200 seconds;       Data structure size:   0.2Mb
Fri Jul 28 01:40:14 2023

使用流操作符,实现了逆序之后,并打包成一个int输出。

类似的基础操作还有很多,如下:

initial begin
    
    int h;
    bit[7:0]b,g[4],[4]='8 ha,8"hb,8'hc,8'hd);
    bit[7:0] q,r,s,t;
    
    h={>>{j}};				// 0a0b0c0d- 把数组打包成整型
    h={<<{j}};				// b030d050 位倒序
    h={<<byte{j}};			// 0d0c0b0a 字节倒序
    g={<<byte {j}};			// 0d,0c,Ob,0a 拆分成数组
    b={<<{8'b0011_0101}};	// 1010 1100位倒序
    b={<<4{8 b0011_01011}};	//01010011半字节倒序
    {>>{q,r,s,t}}=j;		// 把分散到四个字节变量里
     h=(>>{t,s,r,g}};		// 把字节集中到 h 里
end

2.12 枚举类型

由于宏的作用域很大,多数情况下是对调试着可见的。对于具有一些特定名称的集合,例如装药集中的状态名,就可以使用枚举类型来实现。下面是一个例子:

module tb();

    typedef enum {INIT, DECODE, IDLE} fsmstate_e;
    fsmstate_e pstate,nstate;

    initial begin
    
        case (pstate)
            IDLE: nstate = INIT;
            INIT: nstate = DECODE;
            default: nstate = IDLE;
        endcase

        $display("The next state is %s", nstate.name());
        $display("The value of state is %0d %0d %0d", INIT, DECODE, IDLE);
        
    end

endmodule

以下是仿真结果:

      (Specify +UVM_NO_RELNOTES to turn off this notice)

The next state is DECODE
The value of state is 0 1 2
           V C S   S i m u l a t i o n   R e p o r t 
Time: 0 ps
CPU Time:      0.220 seconds;       Data structure size:   0.2Mb
Fri Jul 28 01:55:34 2023

可以观察到,枚举类型和C语言的枚举类型类似,默认从左到右从0开始赋值,默认数值为0。在这种情况下,如果将DECODE=2,那么INIT依然为0,此时IDLE会从DECODE之后开始加,所以IDLE值为3。

枚举类型有如下子函数:

first():返回第一个枚举常量

last():返回最后一个枚举常量

next():返回下一个枚举常量

next(N):返回后面第N个枚举常量

prev():返回前一个枚举常量

prev(N):返回前面第N个枚举常量

2.13 常量

常量可以用宏来定义,但是宏的作用域太广了,可以使用常量来定义。

initial begin
    const byte colon = ":";
    ...
end

除了使用常量,之前还会使用typedef parameter来替换掉宏

2.14 字符串

string类型可以保存长度可变的字符串,单个字符使用byte类型保存,也就是双状态有符号8位。字符串结尾不代标识符null,所有尝试使用\0的操作都会被忽略。

关于使用字符串有一些内建子函数:

getc(N):获得第N个字符

touper():返回一个所有字符大写的字符串

tolower():返回一个都是小写的字符串

putc(M,C):把字符C写在M位上

len():获取字符串长度

substr(start,end):闭区间 左右都取从 从字符串中提取字符串

2.15 表达式的位宽

要多注意由尾款带来数据计算不准确的问题。

标签:0d,temp,int,数据类型,SV,write,数组,第二章,display
From: https://www.cnblogs.com/MinxJ/p/17594154.html

相关文章

  • Eclipse使用SVN
    Eclipse使用SVN[转]1.下载所需软件   1.1SVN服务端(svn-1.4.3-setup.exe)       http://subversion.tigris.org/project_packages.html   1.2把SVN设置成window服务(SVNService.exe)       我没有下载地址,如有需要,留下你的email   1.......
  • redis常见的5中数据类型以及相关命令
    redisredis简介redis是采用ASNIC语言编写的采用的是C/S架构是非关系型数据库以键值对的形式存储在内存中redis在windows中的启动命令redis-serverredis.windows.confredis-cli切换到客户端一、redis的数据类型1.String(字符串)最基本的数据结构,可以......
  • C#-SharpSvn使用记录
    工作需要使用C#代码从SVN库中下载文件,网上查找后,实现功能,现简单记录。1.首先打开解决方案-工具-库程序包管理器-程序包管理器控制台,输入指令:NuGet\Install-Package SharpSvn.1.7-x86 -Version 1.7006.2206;此时引用中出现SharpSvn.dll;2.在app.config的configuration-startup......
  • PHP8的数据类型-PHP8知识详解
    在PHP8中,变量不需要事先声明,赋值即声明。不同的数据类型其实就是所储存数据的不同种类。在PHP8.0、8.1中都有所增加。以下是PHP8的15种数据类型:1、字符串(String):用于存储文本数据,可以使用单引号或双引号来定义字符串。2、整数(Integer):用于存储整数值,可以是正数、负数或零。3、浮点数(F......
  • PyTorch的数据类型
    python和pytorch中的类型对比:我们可以发现pytorch中每中类型后面都有一个Tensor。但是很遗憾PyTorch没有String类型。我们在做NLP的时候会遇到String类型处理的问题,我们会将string转化问数值:one-hot[0,1,0,0,....]Embeddingword2vecglove1Datatype我们需要注......
  • 爬虫数据保存到csv中
    importjsonimportos.pathimporttimefromjsonpathimport*#importjsonpathasjsonpathimportpandasaspdimportrequests#url="http://www.whggzy.com/front/search/category"defget_resp(url,name,i):headers={&quo......
  • 解决QT QGraphicsView提升到QChartView报错的问题
    使用QT提供的QChartView来绘制图表,提升QGraphicsView控件继承QChartView后,然后将QGraphicsView提升到我们自己写的类,怎么才能确保提升后编译不报错呢。[问题描述]使用QGraphicsView显示图表的时候,我们需要将它提升为QChartView.但提升后再此运行一般会发生编译报错,错误发生在......
  • Nodejs 第二章(安装)
    安装nodejs访问官网ennodejs.org/encnwww.nodejs.com.cn/LTS长期支持版Current尝鲜版选择自己的操作系统windowsMacLinuxwindows需要区分64位和32位Mac需要区分64位还是ARM芯片Linux同上。其中msi和pkg可以直接安装较为简单MacPkgwindowsmsi也可以自行下载压缩包......
  • 第二章 网络攻击原理与常用方法
    网络攻击概述网络攻击概念网络攻击是指损害网络系统安全属性的危害行为。常见的危害行为由四个基本类型:信息泄露攻击;完整性破坏攻击;拒绝服务攻击;非法使用攻击。网络攻击模型攻击树模型攻击树模型起源于故障树分析方法。故障树分析方法主要用于系统风险分析和系统可靠......
  • Java学习-2.简介、关键字、标识符、变量、数据类型、运算符
    一、Java简介Java最早是由SUN公司(已被Oracle收购)的詹姆斯·高斯林(高司令,人称Java之父)在上个世纪90年代初开发的一种编程语言,最初被命名为Oak,目标是针对小型家电设备的嵌入式应用,结果市场没啥反响。谁料到互联网的崛起,让Oak重新焕发了生机,于是SUN公司改造了Oak,在1995年以Java的名......