本文章是CSDN博客上收集信息集合

1. event

event事件是静态的同步对象句柄(可以像参数一样在子程序中传递),它用来同步多个并发的进程,比如某个进程等待着事件,而另一个进程则触发这个事件。

几个特征:

  • 可以被赋值成null
  • 可以传给队列,函数和任务

可以被赋值给其它事件,这样两个事件变量(句柄)会指向同一个同步化对象,触发任意一个变量就触发这个事件, 如下所示

event eve;
event tmp;initial begintmp = eve;#10 -> tmp;
endinitial beginwait(eve.triggered());$display("@%0t : event eve receive trigger",$time);
end
------------------------------------
@10 : event eve receive trigger    //执行结果
-------------------------------------

事件的触发和阻塞等待

  • 触发: -> (or ->>) event_handle

  • 等待:@ or wait(event_handle.triggered)

两种等待条件的区别以及竞争条件的发生

首先分析竞争的产生。如下代码所示:

module tb;// Create an event variable that processes can use to trigger and waitevent event_a;// Thread1: Triggers the event using "->" operator at 20nsinitial begin#20 ->event_a;$display ("[%0t] Thread1: triggered event_a", $time);end// Thread2: Starts waiting for the event using "@" operator at 20nsinitial begin$display ("[%0t] Thread2: waiting for trigger ", $time);#20 @(event_a);$display ("[%0t] Thread2: received event_a trigger ", $time);end// Thread3: Starts waiting for the event using ".triggered" at 20nsinitial begin$display ("[%0t] Thread3: waiting for trigger ", $time);#20 wait(event_a.triggered);$display ("[%0t] Thread3: received event_a trigger", $time);end
endmodule

上面module的运行结果是:

[0] Thread2: waiting for trigger
[0] Thread3: waiting for trigger
[20] Thread1: triggered event_a
[20] Thread3: received event_a trigger

发现使用@的阻塞等待没有收到trigger。分析如下:事件的触发状态只会在当前时间步长保持,一但仿真开始向前运行,就会失去这个状态。也就是说,在仿真时间20的这个时间步长中(可以把它想象成1ns或1ps),事件是处于触发状态的,到21仿真时间后触发状态消失。在上面的代码中,两个阻塞等待@和.triggered都是和事件触发同时发生的,出现了竞争条件,结果是虽然触发和等待发生在同一个仿真时间,但是还有执行顺序,根据代码顺序,先执行事件的触发,由于@事件控制是边沿敏感的,等到执行@语句时,事件的触发的“上升沿”已经消失,所以@并没有被触发,而@和.triggered的不同就在于此,@是边沿敏感,后者是电平敏感,所以在整个20仿真时间步长中,wait语句都能被触发
触发和等待在同一时间开始的话就不要用@改用.triggered,当然如果触发进程在等待进程(的仿真时间)之前发生,那这两种等待都不会收到trigger。
其实将Thread2initial块移动到Thread1 initial块之前,也能让@阻塞等待被触发,这就是因为@的执行顺序在触发事件之前。

wait_order的使用

wait_order阻塞等待多个事件的触发,并且要求这多个事件按照用户决定顺序触发。wait_order可以和else一同使用,当多个事件按顺序触发时,执行wait_order后的语句,否则执行else后的语句。

module tb;// Declare three events that can be triggered separatelyevent a, b, c;// This block triggers each event one by oneinitial begin#10 -> a;#10 -> b;#10 -> c;end// This block waits until each event is triggered in the given orderinitial beginwait_order (a,b,c) $display ("Events were executed in the correct order");else $display ("Events were NOT executed in the correct order !");  end
endmodule
--------------------------------------------------------
Events were executed in the correct order //执行结果
--------------------------------------------------------------

事件的合并

之前提到一个事件可以赋值给其它的事件变量,这样两个事件变量实际指向同一个事件对象,触发任意一个变量就是触发了这个对象

module tb;// Create event variablesevent event_a, event_b;initial beginfork// Thread1: waits for event_a to be triggeredbeginwait(event_a.triggered);$display ("[%0t] Thread1: Wait for event_a is over", $time);end// Thread2: waits for event_b to be triggered    beginwait(event_b.triggered);$display ("[%0t] Thread2: Wait for event_b is over", $time);end// Thread3: triggers event_a at 20ns#20 ->event_a;// Thread4: triggers event_b at 30ns#30 ->event_b;// Thread5: Assigns event_b to event_a at 10nsbegin// Comment code below and try again to see Thread2 finish later#10 event_b = event_a;endjoinend
endmodule
--------------------------------------------------------------------
[20] Thread1: Wait for event_a is over
[20] Thread2: Wait for event_b is over
---------------------------------------------------------------------

上面结果可见,触发event_a后也触发了event_b,因为这两个句柄指向同一个事件对象。

2. fork

fork jion

fork...join内部的线程都会并行执行,直至处理完内部所有线程后才会结束块语句。fork join 例子:

module fork_join;initial begin$display("-----------------------------------------------------------------");fork//-------------------//Process-1//-------------------begin$display($time,"\tProcess-1 Started");#5;$display($time,"\tProcess-1 Finished");end//-------------------//Process-2//-------------------begin$display($time,"\tProcess-2 Started");#20;$display($time,"\tProcess-2 Finished");endjoin$display($time,"\tOutside Fork-Join");$display("-----------------------------------------------------------------");$finish;end
endmodule

Process-1和Process-2将会同时开始运行,Process-1在5ns完成,Process-2在20ns完成.运行结果如下:

fork join_any

fork...join_any语句块会阻塞statement-3的执行,直至fork..join_any语句块中的任意一个线程执行完(如上图中的proceess-2)后才能开始执行statement-3。

fork join any 例子:

module fork_join;initial begin$display("-----------------------------------------------------------------");fork//Process-1begin$display($time,"\tProcess-1 Started");#5;$display($time,"\tProcess-1 Finished");end//Process-2begin$display($time,"\tProcess-2 Started");#20;$display($time,"\tProcess-2 Finished");endjoin_any$display($time,"\tOutside Fork-Join");$display("-----------------------------------------------------------------");end
endmodule

Process-1和Process-2将会同时开始运行,Process-1在5ns完成,Process-2在20ns完成.在执行fork..join_any语句块的同时,语句块后的$display语句也在执行。运行结果如下:

fork join_none

fork...join_none语句块不会阻塞statement-3的执行,即在执行fork...join_none语句块的同时也在执行statement-3.

fork join none 例子:

module fork_join_none;initial begin$display("-----------------------------------------------------------------");fork//Process-1begin$display($time,"\tProcess-1 Started");#5;$display($time,"\tProcess-1 Finished");end//Process-2begin$display($time,"\tProcess-2 Startedt");#20;$display($time,"\tProcess-2 Finished");endjoin_none$display($time,"\tOutside Fork-Join_none");$display("-----------------------------------------------------------------");end
endmodule

在执行fork块语句的同时,语句块后面的$display语句也在执行,运行结果如下:

wait fork

直至处理完fork块中的线程,程序才会往下执行,也就是将程序阻塞在fork块这里,直到fork块执行完。例子如下:

module wait_fork;initial begin$display("-----------------------------------------------------------------");fork//Process-1begin$display($time,"\tProcess-1 Started");#5;$display($time,"\tProcess-1 Finished");end//Process-2begin$display($time,"\tProcess-2 Started");#20;$display($time,"\tProcess-2 Finished");endjoin_any$display("-----------------------------------------------------------------");
$finish; //ends the simulationend
endmodule

上面的例子在5ns执行完process-1后,fork块将不会阻塞,在执行fork块内的process-2的同时,开始执行块后的$display语句,当遇到$finish时会结束程序的执行,导致 process-2被迫中途停止执行。运行结果如下:

解决上述问题的办法就是在fork块语句后添加wait fork语句,它会等待fork语句块内的所有线程执行完毕后,才会继续往下执行。修改后的代码如下:

module wait_fork;initial begin$display("-----------------------------------------------------------------");fork//Process-1begin$display($time,"\tProcess-1 Started");#5;$display($time,"\tProcess-1 Finished");end//Process-2begin$display($time,"\tProcess-2 Started");#20;$display($time,"\tProcess-2 Finished");endjoin_anywait fork; //waiting for the completion of active fork threads$display("-----------------------------------------------------------------");$finish; //ends the simulationend
endmodule

运行结果如下:

disable fork

终止正在执行的fork语句块。看下面的例子:

module disable_fork;initial begin$display("-----------------------------------------------------------------");//fork-1fork//Process-1begin$display($time,"\tProcess-1 of fork-1 Started");#5;$display($time,"\tProcess-1 of fork-1 Finished");end//Process-2begin$display($time,"\tProcess-2 of fork-1 Started");#20;$display($time,"\tProcess-2 of fork-1 Finished");endjoin_any//fork-2fork//Process-1begin$display($time,"\tProcess-1 of fork-2 Started");#5;$display($time,"\tProcess-1 of fork-2 Finished");end//Process-2begin$display($time,"\tProcess-2 of fork-2 Started");#20;$display($time,"\tProcess-2 of fork-2 Finished");endjoin_none   disable fork;$display("-----------------------------------------------------------------");$display($time,"\tAfter disable-fork");$display("-----------------------------------------------------------------");end
endmodule

在执行完fork-1的process-1后开始执行后面的fork-2,由于fork-2为fork...join_none语句,不会发生阻塞,所以会继续执行下面的disable fork语句,在执行此语句后,中断所有的fork块,包括 fork-1的process-2和fork-2的process-1以及process-1的执行都被终止。运行结果如下:

3. TASK

1.任务定义 
任务定义的形式如下: 
task task_id; 
    [declaration] 
    procedural_statement 
endtask 
其中,关键词 task 和 endtask 将它们之间的内容标志成一个任务定义,task 标志着一个
任务定义结构的开始;task_id 是任务名;可选项 declaration 是端口声明语句和变量声明语
句,任务接收输入值和返回输出值就是通过此处声明的端口进行的;procedural_statement
是一段用来完成这个任务操作的过程语句,如果过程语句多于一条,应将其放在语句块内;
endtask 为任务定义结构体结束标志。下面给出一个任务定义的实例。

:定义一个任务。 
task task_demo;                //任务定义结构开头,命名为 task_demo 
    input  [7:0] x,y;           //输入端口说明 
    output [7:0] tmp;           //输出端口说明 
 
    if(x>y)                  //给出任务定义的描述语句 
      tmp = x; 
  else 
    tmp = y;

endtask 
上述代码定义了一个名为“task_demo”的任务,求取两个数的最大值。在定义任务时,
有下列六点需要注意: 
(1)在第一行“task”语句中不能列出端口名称; 
(2)任务的输入、输出端口和双向端口数量不受限制,甚至可以没有输入、输出以及
双向端口。 
(3)在任务定义的描述语句中,可以使用出现不可综合操作符合语句(使用最为频繁
的就是延迟控制语句) ,但这样会造成该任务不可综合。 
(4)在任务中可以调用其他的任务或函数,也可以调用自身。 
(5)在任务定义结构内不能出现 initial和 always过程块。 
(6)在任务定义中可以出现“disable 中止语句” ,将中断正在执行的任务,但其是不
可综合的。当任务被中断后,程序流程将返回到调用任务的地方继续向下执行。

2.任务调用 
虽然任务中不能出现 initial 语句和 always 语句语句, 但任务调用语句可以在 initial 语句
和 always 语句中使用,其语法形式如下: 
task_id[(端口1,  端口 2, ........,  端口 N)]; 
其中 task_id是要调用的任务名,端口 1、端口 2,…是参数列表。参数列表给出传入任
务的数据(进入任务的输入端)和接收返回结果的变量(从任务的输出端接收返回结果) 。
任务调用语句中,参数列表的顺序必须与任务定义中的端口声明顺序相同。任务调用语句是
过程性语句,所以任务调用中接收返回数据的变量必须是寄存器类型。下面给出一个任务调
用实例。

例:通过 Verilog HDL 的任务调用实现一个 4 比特全加器。

module EXAMPLE (A, B, CIN, S, COUT); 
 
input [3:0] A, B; 
input CIN; 
output [3:0] S; 
output COUT; 
 
reg [3:0] S; 
reg COUT; 
reg [1:0] S0, S1, S2, S3; 
 
task ADD; 
 
input A, B, CIN; 
output [1:0] C; 
 
reg [1:0] C; 
reg S, COUT; 
 
begin

S = A ^ B ^ CIN; 
COUT = (A&B) | (A&CIN) | (B&CIN); 
C = {COUT, S}; 
end 
endtask 
 
always @(A or B or CIN) begin 
ADD (A[0], B[0], CIN, S0); 
ADD (A[1], B[1], S0[1], S1); 
ADD (A[2], B[2], S1[1], S2); 
ADD (A[3], B[3], S2[1], S3); 
S = {S3[0], S2[0], S1[0], S0[0]}; 
COUT = S3[1]; 
end 
endmodule

在调用任务时,需要注意以下几点: 
(1)任务调用语句只能出现在过程块内; 
(2)任务调用语句和一条普通的行为描述语句的处理方法一致; 
(3)当被调用输入、输出或双向端口时,任务调用语句必须包含端口名列表,且信号
端口顺序和类型必须和任务定义结构中的顺序和类型一致。需要说明的是,任务的输出端口
必须和寄存器类型的数据变量对应。 
(4)可综合任务只能实现组合逻辑,也就是说调用可综合任务的时间为“0” 。而在面
向仿真的任务中可以带有时序控制,如时延,因此面向仿真的任务的调用时间不为“0”

SV中关键字用法学习笔记相关推荐

  1. Python中索引的学习笔记

    1 前言 今天在学习FaceBoxes- 看到一个比较奇怪的代码,"order = scores.argsort()[::-1][:args.top_k]",不太懂这个" ...

  2. 机器人学中的状态估计——学习笔记

    机器人学中的状态估计--学习笔记 离散时间的批量估计问题 1.最大后验概率法(Maximum A Posteriori, MAP) 2.贝叶斯推断(Bayesian inference) 离散时间的迭 ...

  3. 机器人学中的状态估计学习笔记(二)第三章线性高斯系统的状态估计

    机器人学中的状态估计学习笔记(二)第三章线性高斯系统的状态估计 3.1 离散时间的批量估计问题 3.1.1 问题定义 3.1.2 最大后验估计 3.1.3 贝叶斯推断 3.1.4 存在性.唯一性与能观 ...

  4. JavaSE中Map框架学习笔记

    前言:最近几天都在生病,退烧之后身体虚弱.头疼.在床上躺了几天,什么事情都干不了.接下来这段时间,要好好加快进度才好. 前面用了三篇文章的篇幅学习了Collection框架的相关内容,而Map框架相对 ...

  5. Java中expecial,RxJava 学习笔记 (一)

    作者: 一字马胡 转载标志 [2017-12-13] 更新日志 日期 更新内容 备注 2017-12-13 RxJava学习笔记系列 系列笔记 (一) 2017-12-15 增加系列笔记(二) 201 ...

  6. 我的Android进阶之旅------gt;Android中编解码学习笔记

    编解码学习笔记(一):基本概念 媒体业务是网络的主要业务之间.尤其移动互联网业务的兴起,在运营商和应用开发商中,媒体业务份量极重,其中媒体的编解码服务涉及需求分析.应用开发.释放license收费等等 ...

  7. zynq中interrupts的学习笔记(一)

    本学习笔记参考UG585-Zynq-7000-TRM.pdf ch.7:Interrupts.文中有说的不够严谨或者是有错误的地方,欢迎指正! zynq中的interrupts有很多种,大体上分为三类 ...

  8. Oracle中job_type,【学习笔记】Oracle DBMS_SCHEDULER详细介绍与使用案例

    天萃荷净 分享一篇关于Oracle DBMS_SCHEDULER详细介绍与使用案例 1.通过DBMS_SCHEDULER.CREATE_JOB直接创建job SQL> create table ...

  9. SiKi学院 Unity中常用api学习笔记(001-014)

    Api 应用程序编程接口 前言 笔记是看siki学院中<Unity中常用api>的学习笔记 课程地址:  http://www.sikiedu.com/my/course/59 强烈推荐大 ...

最新文章

  1. 去除ios input部分默认样式
  2. 转 PHP 使用 Redis
  3. 417 Pacific Atlantic Water Flow 太平洋大西洋水流
  4. php对图像的各种处理函数代码小结
  5. Android攻城狮ListView
  6. Python 空值与非空值
  7. python定义test方法_向python/django失败的测试方法的详细信息中添加自定义/调试消息的任何方法unittest.TestCase?...
  8. Linux系统文件属性,什么是Linux系统的文件属性?
  9. 【SQL】字符型函数
  10. Calvin: Fast Distributed Transactions for Partitioned Database Systems研读
  11. SQL Server维护工作详解
  12. SQL Server 2008 R2
  13. jquery日历插件 途牛_jQuery日历插件FullCalendar中文版
  14. 今日头条java后端四面_今日头条笔试第二批后端开发第一题java实现
  15. uni-app+微信小程序+云开发 爬取必应首页每日图片
  16. 工作量单位-人月、人日、人时 详解
  17. matlab把图像白色部分变透明,怎么将PPT中的白底图片,白色部分变透明
  18. bigworld源码分析(3)——dbMgr分析
  19. presto日期转换及计算
  20. Xcode8使用出现bundleid: com.xxx.xxx, enable_level: 0, persist_level: 0, propagate_with_acti

热门文章

  1. javascript写字技巧_如何优雅地书写JavaScript
  2. 计算机与音乐整合的教学设计,音乐与戏剧的结合教学设计及教案分析
  3. 关于产品如何讲之好产品
  4. ELK系统分析nginx日志
  5. 2023 剪映小白从入门到精通手机视频剪辑课程全套视频
  6. 2018年总结及2019前三个月规划
  7. python下载手机app视频教程_Python实例教学app
  8. Python数据分析:根据大众点评数据挑选店铺地址
  9. 打造沉浸空间,vivo i音乐10.0版本回归音乐本质
  10. 【Python入门】Turtle海龟库:利用海龟画笔绘制位于正中心的正方形