SystemVerilog线程控制与通信
01
线程控制
1.概述
线程,即独立运行的程序;
线程需要被触发执行,可以结束或者不结束;
- 在module中的initial和always,都可以看作独立的线程,他们在仿真0时刻开始,而选择结束或者不结束;
- 在硬件模块中都是always语句块,所以可以看成是独立运行的线程,而且会一直占用仿真资源,因为他们不会结束;
验证环境需要initial语句块,在仿真过程中,验证环境中的对象可以创建和销毁,故验证环境的资源是动态的;
- 验证环境中的initial语句块有两种方式:begin……end或者fork……join;
Begin……end中语句顺序执行,而fork……join中语句并发执行;
与fork……join类似的并行语句有fork……join_any、fork……join_none;
- 线程的执行轨迹是呈树状结构,即任何线程都应该有父线程;
- 父线程可以开辟若干子线程,父线程可以暂停或者终止子线程;
- 当子线程终止时,父线程可以继续执行;
- 当父线程终止时,其子线程都终止执行;
2.并行线程
fork……join需要所有并行线程都结束才会继续执行;
fork……join_any其中任意一个线程结束就继续执行;
fork……join_none不等待子线程,直接继续执行;
- 注意:
Fork……join_any和fork……join_none继续执行后,其一些未完成的子线程仍将继续在后台执行;
如果要等待或者停止这些子线程,可使用wait fork 或者disable fork;
task do_test;
fork
……
join_any
fork
……
join_none
wait fork;//等待所有子线程结束
endtask
task get_first(output ubt adr);
fork
……
join_any
disable fork;
endtask
3.时序控制
- SV可以通过延迟控制或者事件(event)等待来完成时序控制;
延迟控制即通过#来完成;
#100 clk2=clk1;
事件(event)控制即通过@来完成;
@a clk1=clk2; //等待事件
@(posedge clk)a=b;//边沿触发
Wait语句可以与事件或者表达式结合使用;
Real AOR[];
Initial wait(AOR,size()>0) //wait语句完成电平触发
02
线程同步
1.概述
测试平台所有线程都需要同步并进行交换数据;
一个线程等待另一个线程;
2.事件event
- 通过event声明一个event变量,并且触发;
- event变量可以由一端去触发,再由另一端完成阻塞式的等待,即可以用来控制多个线程之间的同步;
- 通过->来触发事件;
- 其他等待该事件的线程可以通过@操作符或者wait()来检查事件触发状态来完成等待事件;
event done,blast; //声明两个独立的事件
event done_too=done; //事件done赋值给done_too
task trigger(event ev);
->ev; //触发ev事件
endtask
……
fork
@done_too; //等待done_too
#1 trigger(done); //触发done事件
join
fork
->blast; //触发blast事件
wait(blast.triggered); //电平触发等待
join
- wait_order() 可使得线程保持等待,直到在参数列表中的事件event按照顺序从左往右依次完成;
wait_order(a,b,c);
3.旗语(semaphore)
旗语是一个互斥体,使用旗语可以实现对同一资源的访问控制;
在创建旗语时,会为其分配固定的钥匙数量;
使用旗语的进程必须先获得钥匙,才可访问资源;
旗语的钥匙数量可以有多个,等待旗语的进程也可以有多个;
旗语的等待队列是先进先出(FIFO),即先排队等待旗语的将优先得到钥匙;
旗语操作
创建旗语
semaphore sm;//创建一个旗语
sm=new(1); //分配一个钥匙
创建一个固定钥匙数量的旗语:new
从旗语获取一个或多个钥匙(阻塞型):get
返回一个或多个钥匙:put
获取一个或多个钥匙而不被阻塞:try_get
task send;
sem.get(1) ///获取钥匙
……
sem.put(1); //处理完成时把钥匙返回
endtask
03
线程通信
1.信箱
用于收发信息,SV中信箱可以存放任何数据类型,也可以从信箱中读取这些数据,
创建信箱:new()
将信息写入信箱:put()
写入信箱但不会阻塞:try_put()
获取信息:get() 获取信息并取出数据:
peek()获取信息不会取出数据
从信箱获取数据但不会阻塞:try_get()/try_peek()
获取信箱信息数目:num()
2.信箱和队列区别
- 信箱必须通过new()例化,队列只需要声明
- 信箱的存取方法put()和get()是阻塞方法,不一定会立即返回;队列的存取方法push_back和pop_front()是非阻塞方法,会立即返回;
- 传递形式参数时,如果是input方向,则信箱类型传递的是句柄,队列类型完成的是队列内容的拷贝;
3.总结
- event:最小信息量的触发,即单一的通知单元,用来做事件的触发,也可多个事件组合起来作线程之间的同步;
- semaphore:共享资源安全,用于多线程间需要对某一公共资源做访问;
- mailbpx:SV类似FIFO,在线程之间做数据通信或者内部数据缓存;
END
- MySQL误操作数据恢复的简单实践(r11笔记第67天)
- Oracle 12c中JOB运行失败的简单处理(r11笔记第66天)
- MySQL中的半同步复制(r11笔记第65天)
- Linux系统LVM逻辑卷创建过程以及自动化脚本
- 一个闪回区报警的数据恢复(r11笔记第62天)
- 利用腾讯云COS云对象存储定时远程备份网站
- 分享一个自写的Python远程命令和文件(夹)传输类
- Oracle数据误操作全面恢复实战(r11笔记第78天)
- 远程协助解决异常宕库的问题(r11笔记第75天)
- Nginx-helper纯代码版,文章评论发布自动清理Fastcgi缓存
- MySQL和Oracle行值表达式对比(r11笔记第74天)
- 闪回数据库不是“万金油”(r11笔记第73天)
- 修改Apache的超时设置,解决长连接请求超时问题
- Oracle 12cR2初体验(r11笔记第91天)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- MySQL 8.0新特性 — 事务性数据字典与原子DDL
- Python基础之面向对象-继承
- [源码分析]ArrayList和LinkedList如何实现的?我看你还有机会!
- 使用Python实现平台自动打卡
- QT学习第4天:qt点击鼠标画一条直线(附源代码和程序)
- 跨站请求伪造——CSRF
- 13-6 编辑多个文件和保存
- 汇编基础
- php 使用AMQP扩展调用RabbitMq
- 聊聊RedisTokenVisitor
- R语言几行代码拼接pdf文件
- 一次 Redis 分布式锁事故,整个项目组被扣绩效了。。。
- 小程序访问https显示网络错误,微信打开https空白、浏览器访问正常 解决方案
- Python GUI项目实战(七)学生信息的修改、删除和保存
- Python | 使用argparse解析命令行参数