SystemVerilog 语言部分(一)


一 数据类型

内建数据类型

verilog中,对于触发器,锁存器用reg类型,对于reg,会被综合成register,latch

       wire,做连接

sv中,logic可以被综合为reg或wire,logic如果在验证环境,只会作为单纯的变量进行赋值操作。

verilog & sv区别:

  verilog作为硬件描述语言,倾向于设计人员自身懂得所描述的电路中哪些变量应该实现为reg或是wire,但不利于后端综合工具

  sv侧重于验证语言,引入logic只会作为单纯的变量进行赋值操作,这些变量只属于软件环境构建

 

bit是二值逻辑:0 1

logic是四值逻辑:0 1 X Z

Q:为什么有了四值逻辑还要引入二值逻辑?

A:SV在开始做设计的时候,期望将硬件和软件分开,四值在硬件设计,二值在软件中

 

四值逻辑:integer(32),logic,reg,net-type

二值逻辑:byte(8bit),shortint,int(32),longint,bit

 

有符号类型: byte,shortint,int,longint,integer

无符号类型:bit, logic, reg, net-type(wire/tri)

note:用最高位来表征有无符号

在变量运算中,应该尽量避免两种不一致的变量操作

将有符号变量转换为无符号:unsigned'    属于静态转换

动态转换 $cast(tgt, src)  

对比:静态转换在编译的时候做检查,动态转换在仿真的时候做检查

静态转换和动态转换均需要操作符号或者系统函数介入,统称为显式转换

而不需要进行转换的一些操作称为隐式转换

note:不同数据类型进行操作时应注意变量的:逻辑数据类型、符号类型、矢量位宽

 

软件常用类型【定宽数组】

数组声明

int lo_hi[0:15];     //16 ints [0] .. [15]

int c_style[16];       //16 ints [0] .. [15]

多维数组声明和使用

int arr2 [0:7][0:3]; // 完整声明

int arr3 [8][4];  //紧凑声明

arr2[7][3] = 1;  //设置最后一个元素

初始化和赋值

int  ascend[4] = `{0, 1, 2, 3}; //对四个元素初始化

int  descend[5];

descend[0:2] = `{5, 6, 7}   //片段赋值操作

ascend = `{4{8}}   //四个值全部为8

descend = `{9, 8, default:-1 }      //{9,8,-1,-1,-1}

存储空间考量

从实际硬件容量的角度出发,哪种方式存储方式更小?

bit [3][7:0] b_pack;      //合并型

bit [7:0] b_unpack[3];    //非合并

 

 b_unpack 实际占用3个WORD存储空间,但是b_pack则只会占据一个WORD存储空间

note:当左边也有维度,右边也有维度声明时,先考虑右边维度

  对于unpack的数组,初始化和赋值“ ` ”要存在

Q:当b_pack和b_unpack用logic存储时,实际占用的大小为:

A:b_pack有24bit,用logic 4值表示时,每个需要2bit,i.e. 48bit =2WORD

    b_unpack为3 *8,8位连续位,即3*16,其中16bit可以被一个WORD存储,则需要3WORD

note:对于unpack的数组做初始化要有“ ` ”

for和foreach循环

initial begin

bit [31:0] src[5], dst[5];

for (int i=0; i< $size(src); i++)      //$size(src,default =1)

  src[i] = i;

foreach (dst[j]) begin

  dst[j] = src[j]*2

end

复制和比较    “==” / “!=”

 

软件常用类型【动态数组】

定宽数组类型的宽度在编译时就确定了,但是如果在程序运行时再确定数据的宽度需要使用【动态数组】

动态数组用的是非合并的存储方式,合并数组和非合并数组之间不能直接赋值

特点:可以在仿真运行时灵活调解数组的大小即存储量

 动态数组一开始声明时,需要利用“[ ]”来声明,而此时数组是空的,即0容量,其后使用new[ ]来分配空间,方括号中传递数组的宽度

此外,也可以在调用new[ ]时将数组名一并传递,将已有数组的值复制到新数组中

 

 d2和dyn是两个地址空间,integer默认值是X

删除方法:也可以dyn = new[0]    /  dyn = `{ }

 

【队列】

  • 结合了链表和数组的优点,可以在它的任何地方添加或删除元素,并且通过索引实现对任一元素的访问
  • 队列的声明是 [$]   队列元素的标号从0到$
  • 队列不需要new[ ]去创建空间(new[]只对动态数组使用),只需要使用队列的方法为其增减元素,一开始空间为0
  • 队列的一个简单使用是通过自带的push_back( )和pop_front( )结合来实现FIFO的用法

 note:数组中用size( ),mailbox中用num( )

 【关联数组】

 关联数组中index不是连续的,为此尽可能不要用for循环

 

 如果找不到第一个索引,说明第一个为空

【结构体】struct

note:verilog中没有数据结构,sv中可以使用struct语句创建结构

只是一个数据的结合,通常是将若干相关变量组合到一个结构体中

用来创建一个新的类型 typedef,为此pixel_s是类型

第一行的pixel在这里是变量名 

 typedef在这里也可以替换为define,区别在于typedef创建的是类型,define是变量名

 

 note:数据是非合并型,采用`{ }方式,如果结构体用合并型,只需struct packed {bit [7:0] r, g, b} pixel

【枚举类型】

 

 INIT,DECODE,IDLE默认是0,1,2

note:枚举类型可以赋值给整型,INT = enum, 但是整型不能直接赋值给enum

【字符串】

 

字符串默认" " ,与null不同,null有且只用到句柄(对象)中,字符串中没有null

note:verilog中没有str,sv中str没有"\0"

      数组的大小用.size(), str用 .len() - 1

 

二 过程块和方法

硬件过程块 initial和always

module/endmodule,interface/endinterface 可以被视为硬件世界

program/endprogram,class/endclass可以被视为软件世界

  • always是为了描述硬件的行为
  • always中的@(event)敏感列表是为了模拟硬件信号的触发行为
  • always过程块是用来描述硬件时序电路和组合电路的正确打开方式,因此只可以在module或者interface中使用

note:不可以在always中初始化变量,可以在always中复位,而初始化变量是在软件操作过程中,即可以在initial中

  •   initial只执行一次
  •   initial和always无法被延迟执行,在仿真一开始他们就会并行执行
  •   initial本身不可综合,对于描述电路没有任何帮助,不应该存在于硬件设计代码中
  •   initial是为了测试而生的
  •   initial可以在module,interface和program中使用

note:sv中的class不允许出现initial和always

软件方法  函数func

  • 可以在参数列表中指定输入参数(input),输出参数(output),输入输出参数(inout),或引用参数(ref)
  • 可以设置返回值或不设置返回值(void)
  • 默认数据类型是logic,eg input[7: 0]  addr
  • 可以传参数也可以传数组(作为形参)
  • 可以有返回值也可以没有返回值(void function())
  • 在使用ref时,为了保护数据对象只能被读取,不能被写入,可以通过const来限定ref的声明
  • 声明参数时,默认方向是input

软件方法  任务task

  • task无法通过return添加返回值
  • task可以置入耗时语句,包括@event, wait event, #delay
  • function不可以调用task,task可以调用function

变量生命周期

分为automatic(动态,局部变量)和static(静态,全局变量)

  • func/task中的临时变量,在方法调用结束后,自动释放
  • 如果数据变量被声明为automatic,进入该进程/方法后,automatic变量会被创建,离开该线程/方法后会被销毁
  • 对于automatic方法,其内部所有变量内部默认也是automatic
  • 对于static方法,其内部所有变量内部默认也是static

note:没有显式注明动态还是静态变量的情况下,默认是static

  • module,program,interface,task和func之外的变量拥有静态的生命周期,即存在与整个仿真阶段
  • class中默认是automatic
  • 在module, interface和program内部声明,且在task,process或者func外部声明的变量也是static

 

三 设计的例化和连接

 例化:

 

 

硬件和软件的连接有且只能通过interface,硬件和硬件的连接可以通过端口,也可以通过interface

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM