SystemVerilog学习笔记1——基本概念


前言:个人学习SV的在线笔记。学习SV的过程中借鉴一些大佬的笔记和路科验证学习资料,只做个人学习交流使用,感谢!

数据类型

logic和reg、wire的区分和联系:

  • -Verilog作为硬件描述语言,designer懂得所描述的变量应该被实现为寄存器还是线网类型,这有利于后端综合工具以及便于阅读和理解;
  • SV侧重于验证,不关心logic对应的逻辑被综合为寄存器还是线网,在验证环境中只作为单纯的变量进行赋值操作,这些变量只属于软件环境构建;
  • logic是为方便验证人员驱动和连接硬件模块、省去考虑该使用reg或wire的精力,节省时间又避免出错

SV为何有了四值逻辑还要引入二值逻辑?
SV在开始设计时就希望将硬件世界和软件世界分开,而软件的世界即验证环境,更多的是二值逻辑。

四值逻辑:integer、logic、reg、net-type(如wire、tri)
二值逻辑:shortint、int、longint、byte、bit

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

助记:二值逻辑:三种int+bit/byte;有符号:三种int+integer/byte。

四值转二值:Z、X变为0;每位四值逻辑须用连续2位存储。四值逻辑类型有四种值,所以需要2bit来表示。

组合/非组合型数组

组合型数组和非组合型数组变量名右边声明数组维度为非组合型(拷贝时操作数维度和大小须一致),左边为组合型数组(可直接赋值);

数组维度从高到低是先看数组名右侧(从左到右)再看左侧(从左到右)

  • 对于bit[3][7:0] b_pack;每一个元素都是8bit,一共有3个元素,3*8=24bit,因为是组合型,所以占用一个WORD空间。
  • 对于bit[7:0] b_unpack[3];因为是非组合型,每一个元素占用一个WORD空间,但是有效空间只有8bit。
    在这里插入图片描述
  • 对于logic[3][7:0] l_pack;因为是组合型,每个元素有8bit,一共有3个元素,每种值得用2bit来表示,所以8×3×2=48位,用2个WORD空间足以。
  • 对于logic[7:0] l_unpack[3];因为是非组合型,每个元素占用8bit,而四值逻辑得用2bit表示,所以一个元素8*2=16位,用一个WORD足以放下一个元素,所以需要3 * WORD=3WORD的空间。

定宽数组和动态数组

定宽数组的宽度在编译时就确定动态数组最大特点是可以在仿真运行时灵活调节数组的大小即存储量,在一开始声明时用‘[ ]’来声明,此时是空数组;其后用‘new[]’分配空间,在[ ]中传递数组的宽度;可在调用new[ ]时将数组名一并传递,将已有数组的值复制到新数组中。

关联数组

关联数组可用来保存稀疏矩阵的元素,对一个非常大的地址空间寻址时,该数组只为实际写入的元素分配空间,这种实现方法所需空间比定宽或动态数组所占用的空间要小得多

显示转换

  • 静态转换(需要在转换的表达式前加上单引号,该方式不会对转换值做检查,即转换失败也不知道);
  • 动态转换$cast(tgt,src))均需要操作符号或系统函数介入。

对于赋值,可用赋值符号“=”直接进行数组的复制;
对于比较,在不适用循环的情况下,可利用“==”或“!=”比较数组的内容,结果仅限于内容相同或不相同

初始化和赋值

//声明的同时,对4个元素初始化
int ascend[4] = '{0,1,2,3};		
//声明和赋值分开操作
int descend[5];
descend = '{4,3,2,1,0};
//4个值全部赋值为8
ascend = '{4{8}};
//部分元素使用默认赋值
descend = '{9,8,default:-1};		//{9,8,-1,-1,-1}

队列

队列结合链表和数组的优点,可在其任何地方添加或删除元素,通过索引实现对任一元素的访问,声明:[$],队列元素的标号从0到$;不需要new[ ]创建空间,初识空间为0;通过其方法push_back()和pop_front()的结合实现FIFO的用法

注意:队列赋值不像数组或结构体赋值需要使用单引号

结构体

结构体struct:数据的集合,其通常的使用方式是将若干相关的变量组合到一个struct结构定义中;伴随typedef可用来创建新类型实现类型共享),并利用新类型声明更多变量

枚举类型

枚举类型enum:常和typedef搭配使用,便于用户自定义枚举类型的共享使用,保证了一些非期望值的出现,降低设计风险

举例: INT=enum √ 枚举类型可直接赋值;
enum=T’(INT) —— 反过来须做类型转换为enum类型。

在enum/struct类型声明时添加typedef与否的差别

  • 若不添加typedef,例如enum{NO,YES} bool,那么bool为枚举类型"变量",而enum{NO,YES}匿名类型 (implicit type)来理解;
  • 若添加typedef,例如typedef enum{NO,YES} bool_t,那么bool_t为枚举类型,即通过typedef将匿名类型“显式" (explicitly)定义为bool_t,并且接下来可重复利用bool_t声明多个变量。

避坑指南:对于重复使用的enum/struct定义,默认添加typedef先定义类型,再利用该类型声明变量

字符串

字符串string(VHDL和Verilog所没有的):保存和处理所有与字符串相关的处理

字符串的格式化函数$sformatf(),即如何形成一个想要的字符串句子;使用$display打印输出。

过程块和方法

:定义的软件变量或例化的硬件所在的空间

  • 硬件世界:module/endmodule、interface/endinterface;
  • 软件世界:program/endprogram、class/endclass。

always:描述硬件行为,描述硬件时序电路和组合电路的正确打开方式,使用时需注意是描述时序电路还是组合电路,其@(event..)敏感列表是为了模拟硬件信号的触发行为,只可在module或interface中使用。

注意,always由时钟或其他非时钟信号驱动,不同的always语句块之间是并行执行的,不可在always中初始化变量(这是软件概念,一般在initial或定义变量时进行初始化),但可以做复位

initial:非常符合软件的执行方式,即只执行一次;和always一样无法被延迟执行,仿真一开始都会同步执行,不同的initial和always之间的执行顺序是没有顺序的;initial不应存在于硬件设计代码中,其本身不可综合,对于描述电路没有任何帮助;它为测试而生,可实现测试按照时间顺序,即软件方式来完成

  • 所有测试语句都可被放置在initial中,为了便于统一管理测试顺序,将有关测试语句都放置在同一initial过程块中
  • initial过程块可在module、interface和program中使用;
  • begin…end将其作用域“包”住。

函数function

函数function:同C语言的函数非常类似。可以在参数列表中指定input、output、inout、ref类型的参数,也可返回数值或是void不返回数值。

  • 默认数据类型为logic
  • 数组可以作为形参传递
  • function可返回或不返回结果(声明时采用void function());
  • 只有数据变量可以在形参列表中声明为ref类型,线网类型不能被声明为ref类型;
  • 在使用ref时可以采用const方式保护数据对象只被读取不被写入
  • 在声明参数时可给入默认值,同时在调用时若省略该参数的传递,则默认值会被传递给function。

任务task

  • 无法通过return返回结果,只能通过output、inout或ref参数返回;
  • task内可以置入耗时语句(@event、wait event、#delay等),而function不能;
  • 内置耗时语句时使用task,用于耗时的信号采样或者驱动的场景;而非耗时方法定义时使用function,运用于纯粹的数字或者逻辑运算
  • 如果要调用function,function和task都可以调用;如果调用task,建议使用task调用,因为task有可能耗时。

变量生命周期

  • 可以将数据的生命周期分为动态(automatic)和静态(static)
  • 局部变量生命周期同其所在域共存亡,属于动态生命周期;
  • 全局变量伴随着程序开始到结束,如module中变量默认为全局变量,由于在模拟硬件信号,故它们是静态生命周期;
  • 如果数据变量被声明为automatic,在进入该进程/方法后,automatic变量会被创建,离开后被销毁static变量在仿真开始时即被创建,在进程/方法执行过程中不被销毁,可被多个进程/方法所共享;
  • module、program、interface、task、function之外声明的变量拥有static生命周期,存在于整个仿真阶段;
  • module、interface和program内部声明,且在task、process或function外部声明的变量也是static变量,且作用域在该块内;
  • module、program、interface中定义的task、function默认都是static类型;
  • 过程块中(task、function、process)定义的变量均跟随它的作用域,即过程块的类型,如果过程块为static,则它们也默认为static,反之亦然;这些变量也可由用户显式声明为automatic或static;
  • 对于static变量,用户在声明变量时应同时对其做初始化,初始化只会伴随其生命周期发生一次,并不会随着方法调用被多次初始化。

设计例化和连接

模块:module为硬件域,在定义时需标注方向、位宽和端口名

模块例化:在上层例化底层模块,或TB例化DUT时均需要完成模块例化;例化时需注意模块名、参数例化传递、例化名和端口名例化对应
在这里插入图片描述
模块连接

  • 在testbench中的连接指的对象是有硬件模块参与作为信号驱动方(driver)或负载方(load)
  • 在TB中常见的连接有两个硬件模块之间的连接,如实例A与实例B的连接,可由logic类型完成连接。如果是硬件模块与TB发送数据激励的连接,则要考虑数据激励端如何正确产生数据并发送至DUT一侧,同时数据激励端也要对DUT反馈的信号做出正确响应。

验证结构

测试平台:整个验证系统的总称,包括验证结构的各组件、组件之间连接关系、测试平台的配置和控制,更系统的讲还包括编译仿真的流程、结果分析报告和覆盖率检查等。狭义上主要关注验证平台的结构和组件部分,可产生设计所需要的各种输入,在此基础上进行设计功能的检查。

  • 各个组件之间互相独立
  • 验证组件与设计之间需要连接
  • 验证组件之间需要进行通信
  • 验证环境需要时钟和复位信号的驱动。
    在这里插入图片描述
  • 9
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
SystemVerilog是一种硬件描述语言(HDL),用于设计和验证数字电路。SystemVerilog具有丰富的特性,适用于各种设计和验证任务。以下是SystemVerilog入门笔记的一些重点内容。 首先,了解SystemVerilog的基本语法是很重要的。SystemVerilog继承了Verilog的语法,同时加入了一些额外的特性,如数据类型、类和接口等。熟悉这些语法规则对于编写有效的代码至关重要。 其次,了解模块和端口的概念。SystemVerilog中的模块是最基本的构建单元,而端口则是模块与外部环境之间的接口。了解如何定义和使用模块和端口是编写可重用代码的关键。 另外,掌握数据类型和运算符是必不可少的。SystemVerilog支持多种数据类型,如整数、浮点数、逻辑值等,同时也提供了丰富的运算符,如加法、减法、逻辑运算符等。这些知识对于设计和验证数字电路非常重要。 此外,了解时序控制和并发控制是必要的。SystemVerilog提供了多种时序控制和并发控制的语法和特性,如always块、initial块和fork/join语句等。掌握这些知识对于设计复杂的数字电路至关重要。 最后,了解Verilog验证中的一些基本概念也是很重要的。例如,了解如何使用assert语句进行断言检查、如何使用coverage语句进行覆盖率分析等。 总之,SystemVerilog入门需要掌握其基本语法、模块和端口、数据类型和运算符、时序控制和并发控制,以及一些基本的验证概念。这些知识是成为一名合格的SystemVerilog工程师所必备的基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值