SV学习笔记(13)

学习目标:

SV绿皮书第七章:线程以及线程间的通信

学习内容:

1.模块(线程)在仿真一开始便并行执行,除了每个线程会按照自身内部产生的事件来触发过程语句块之外,也同时依靠相邻模块间的信号变化来完成模块之间的线程同步。

2.线程即独立运行的程序,线程需要被触发,可以结束或者不结束

3.硬件模型中由于都是always语句块,所以可以看成是多个独立运行的线程,而这些线程会一直占用仿真资源;
软件测试平台中的验证环境都需要由initial语句由去创建,而在仿真过程中,验证环境中的对象是可以创建或者销毁的,因此资源占用是动态的。

4.线程的执行轨迹是呈树状结构的,即任何的线程都应该有父线程
父类线程可以开辟若干个子线程,父线程可以暂停或者终止子线程
当子线程终止时,父线程可以继续执行
当父线程终止时,其所开辟的所有子线程都应当会终止

5.fork…join

initial  begin
	$display("@%0t:start  fork  ...  join  example",$time);
	#10  $display("@%0t:sequential  after  #10",$time);
	fork
		$display("@%0t:parallel  start",$time);
		#50  $display("@%0t:parallel  after #50",$time);
		#10  $display("@%0t:parallel  after #10",$time);
		begin
			#30  $display("@%0t:sequential  after #30",$time);
			#10  $display("@%0t:sequential  after #10",$time);
		end
	join
	$display("@%0t:after join",$time);
	#80  $display("@%0t:finish  after #80",$time);
end

//结果
@0:start  fork  ... join  example
@10:sequential  after  #10
@10:parallel  start
@20:sequential  after #30
@40:sequential  after #10
@50:parallel  after #50
@60:after join
@140:finish  after  #80

6.fork join_any

initial  begin
	$display("@%0t:start  fork  ...  join_any  example",$time);
	#10  $display("@%0t:sequential  after  #10",$time);
	fork
		$display("@%0t:parallel  start",$time);				//注意:这也是一条子线程
		#50  $display("@%0t:parallel  after #50",$time);
		#10  $display("@%0t:parallel  after #10",$time);
		begin
			#30  $display("@%0t:sequential  after #30",$time);
			#10  $display("@%0t:sequential  after #10",$time);
		end
	join_any
	$display("@%0t:after join_any",$time);
	#80  $display("@%0t:finish  after #80",$time);
end

//结果
@0:start  fork  ... join_any  example
@10:sequential  after  #10
@10:parallel  start
@10:after join_any
@20:parallel  after #10
@40:sequential  after #30
@50:sequential  after #10
@60:parallel  after #50
@90:finish  after  #80

7.fork join_none

initial  begin
	$display("@%0t:start  fork  ...  join_none  example",$time);
	#10  $display("@%0t:sequential  after  #10",$time);
	fork
		$display("@%0t:parallel  start",$time);				//注意:这也是一条子线程
		#50  $display("@%0t:parallel  after #50",$time);
		#10  $display("@%0t:parallel  after #10",$time);
		begin
			#30  $display("@%0t:sequential  after #30",$time);
			#10  $display("@%0t:sequential  after #10",$time);
		end
	join_none
	$display("@%0t:after join_none",$time);
	#80  $display("@%0t:finish  after #80",$time);
end

//结果
@0:start  fork  ... join_none  example
@10:sequential  after  #10
@10:after join_none					//直接退出join_none,先执行这一条
@10:parallel  start
@20:parallel  after #10
@40:sequential  after #30
@50:sequential  after #10
@60:parallel  after #50
@90:finish  after  #80

8.如果希望等待fork块中的所有线程执行完毕再退出结束initial块,我们可以使用wait join语句来等待所有子线程结束

9.可以使用disable来指定需要停止的线程。
如果你给某一个任务或者线程指明标号,那么当这个线程被调用多次以后,如果通过disbale去禁止这个线程标号,所有衍生的同名线程都将被禁止。

//disable  fork可以停止从当前线程中衍生出来的所有子线程
initial  begin
	check_trans(tr0);		//线程0
	//创建一个线程来限制disable  fork的作用范围
	fork		//线程1(父)
		begin
			check_tran(tr1);	//线程2
			fork		//线程3
				check_tran(tr2);		//线程4
			join
			//停止线程1-4,单独保留线程0
			#(TIME_OUT/2)  disable  fork;
		end
	join
end

10.所有这些数据交换和同步称之为线程间的通信(event、semaphore旗语、mailbox信箱)

11.event不需要new
线程可以通过->操作符来触发事件

12.电平敏感wait(a.triggered())来代替边沿敏感的阻塞语句@a,只要event被触发过,就可以防止引起阻塞

class car;
	event e_start;
	task  launch();
		->e_start;
		$dispaly("car  is  launched");
	endtask
	task  move();
		wait(e_start.triggered);
		$display("car  is moving");
	endtask
	task  drive();
		fork
			this.launch();
			this.move();
		join
	endtask
endclass

13.event没有方法可以清除event.triggered的状态
如果要多次触发event A,可以使用@A来多次等待A

14.semaphore可以实现对同一资源的访问控制

15.semaphore的三个基本操作:
new()方法可以创建一个带单个或者多个钥匙的semaphore----new里面指定多少钥匙,默认一把,可以初始化为0
使用get()可以获取一个或者多个钥匙
put()可以返回一个或者多个钥匙

16.如果获取一个semaphore而不希望被阻塞,可以使用try_get()函数,返回1表示钥匙足够,返回0表示钥匙不够

17.semaphore的操作

program  automatic  test(bus_ifc.TB  bus);
	semaphore  sem;		//创建一个semaphore
	initial  begin
		sem=new(1);		//分配一把钥匙
		fork
			sequencer();		//产生两个总线事务线程
			sequencer();
		join
	end
	task sequencer;
		repeat(2)
		@bus.cb;
		sendTrans();		//执行总线事务
	endtask
	task  sendTrans;
		sem.get(1);		//获取总线钥匙
		@bus.cb;		//把信号驱动在总线上
		bus.cb.addr<=t.addr;
		...
		sem.put(1);		//处理完成时把钥匙返回,不返回会发生死锁
	endtask
endprogram

18.对于线程间共享资源的使用方式,应该遵循互斥访问原则,否则将“线程不安全”

19.mailbox是一种对象,因此也需要使用new()来例化,例化时有一个可选的参数size来限定其存储的最大数量
信箱为满时,put()会阻塞---------使用非阻塞加try_put()、try_get()、try_peek()
peek()可以获取对信箱里数据的拷贝而不移除它

20.信箱的容量可以固定也可以不固定
信箱可以通过参数化指定其存储的数据类型
多个对象可以同时使用信箱存储或者获取数据

21.限定mailbox中元素的类型,mailbox #(type=T)

event最小信息量的触发
semaphore共享资源的安全卫士
mailbox精小的SV原生FIFO

问题:

学习时间:

4/14
早:9-11
中:15-17
晚:20-22

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值