SV学习小记(6)线程


一、线程的使用

在System Verilog语言参考手册里的"线程(thread)"和"进程(process)"是可以互换的。如果按照软件的思维理解硬件仿真, 仿真中的各个模块首先是独立运行的线程. 模块(线程)在仿真一开始的时候便并行执行, 除了每个线程会按照自己内部产生的事件来触发过程语句块之外, 也同时依靠相邻模块间的信号变化来完成模块之间的线程同步

什么是线程

  • 线程即独立运行的程序。

  • 线程需要被触发,可以结束也可以不结束。

  • 在module中的initial和always,都可以看做独立的线程,它们会在仿真0时刻开始,而选择结束或者不结束。

  • 硬件模型中由于都是always语句块,所以可以看成是多个独立运行的线程,而这些线程会一直占用仿真资源,因为它们并不会结束。

  • 软件测试平台中的验证环境都需要由initial语句块去创建,而在仿真过程中,验证环境中的对象可以动态的创建和销毁,因此软件测试端的资源占用是动态的。
    注:initial线程不一定会结束,若在initial语句块中生成clk信号,则该线程不会结束。

    在System Verilog中,除了集成自Verilog中的fork…join和begin…end之外,还新增了fork…join_any和fork…join_none。其中,begin…end语句块是按照顺序执行的,其余三种的执行顺序见下图:
    在这里插入图片描述

线程的概念

  • 线程的执行轨迹是树状结构的,任何线程都应该有父线程
  • 父线程可以开辟若干个子线程,父线程可以暂停或者终止子线程。
  • 在SV中,父线程执行结束后(注: 不是使用disable等终止线程, 而是线程按顺序执行结束), 并不会主动回收其子线程,如果disable父线程,则该线程与其子线程会被一同关闭。

二、线程的控制

等待所有衍生的线程

  • 在SV中,当程序中的initial块全部执行完毕,仿真器就退出了。
  • 如果我们希望等待fork块中的所有线程执行完毕再退出initial块,可以使用wait fork;语句来等待所有子线程结束。
    注:上述中提到,子线程不会随着父线程的结束而主动结束。那么这些在父线程结束后,没有结束的子线程,被称作僵尸线程。对于这种情况,建议使用fork-join_none、fork-join_any开辟的线程,一旦认为它没有必要了,一定要给他打上标签,方便后期主动disable

停止单个线程

parameter TIME_OUT = 1000;
task check_trans(Transaction tr);
	fork
		begin
			// 等待回应,或者达到某个最大时延
			fork: time_block
				begin
				wait (bus.cb.addr == tr.addr);
				$display("@%0t: Addr match %d", $time, tr.addr);
				end
				#TIME_OUT $display("@%0t: Error: timeout", $time);
			join_any
			disable time_block //  在disable之后,结束线程time_block
		end
	join_none	
endtask

停止多个线程

使用disable来停止多个线程

`timescale 1ns/1ns
module tb;
	task automatic child_t(int t, string name);
		forever #(t*1ns) $display("@%0t child thread [%s] say hello", $time, name);
	endtask : child_t
	task automatic parent_t(int t=3, string name="parent_thread");
		fork
			forever #(t*1ns) $display("@%0t parent thread [%s] say hello", $time, name);
			child_t(4,"child_thread_A");
			child_t(5,"child_thread_B");
			child_t(6,"child_thread_C");
		join_none
	endtask

	initial begin:parent_thread
		parent_t();		
	end

	initial begin
		#20ns;
		disable parent_thread;
		$display("@%0t disable parent_thread", $time);
		#20ns;
		$display("@%0t finish current test", $time);
	end
endmodule : tb

在tb中,disable父线程之后,连带其中的子线程也一同被终止了。运行结果如下图所示:
在这里插入图片描述
在如下代码中,如果父线程是自然执行结束的,子线程是不会结束的,直到手动终止。

`timescale 1ns/1ns
module tb2;
	task automatic child_t(int t, string name);
		forever #(t*1ns) $display("@%0t child thread [%s] say hello", $time, name);
	endtask
	task automatic parent_t(int t=3, string name="parent_thread", int loop=10);
		fork : child_threads
			child_t(4,"child_thread_A");
			child_t(5,"child_thread_B");
			child_t(6,"child_thread_C");
		join_none
		repeat(loop) #(t*1ns) $display("@%0t parent thread [%s] say hello", $time, name);
		$display("@%0t finish %s", $time, name);
	endtask

	initial begin:parent_thread
		parent_t();		
	end

	initial begin
		#50ns;
		// disable parent_thread;
		// $display("@%0t disable parent_thread", $time);
		$display("@%0t finish current test", $time);
		$finish;
	end	
endmodule : tb2

其运行结果如下图所示:
在这里插入图片描述

停止被多次调用的任务

  • 如果给一个任务或者线程指明标号,那么当这个线程被调用多次以后,如果通过disabe去禁止这个线程标号,所有衍生的同名线程都将被禁止
task wait_for_time_out(int id);
   if(id == 0)
   	fork
   		begin
   			#2;
   			$display("@%0t: disable wait_for_time_out", $time);
   			disable wait_for_time_out;
   		end
   	join_none
   fork: just_a_little
   	begin
   		$display("@%0t: %m: %0d entering thread", $time, id);
   		#TIME_OUT;
   		$display("@%0t: %m: %0d done", $time, id);
   	end
   join_none
endtask

initial begin
   wait_for_time_out(0);  // Spawn thread 0
   wait_for_time_out(1);  // Spawn thread 1
   wait_for_time_out(2);  // Spawn thread 2
   #(TIME_OUT*2) $display("@%0t: All done", $time);
end
  • 任务wait_for_time_out被调用三次,从而衍生了三个线程。
  • 线程0在#2延时之后禁止了该任务,而由于三个线程均是“同名”线程,因此这些线程都被禁止了,最终也都没有完成。

三、线程通信(明天更新)

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值