不枉初心,砥砺前行

皮皮祥的博客

欢迎留言,评论

导航

verilog中的fork...join用法

这句话通常使用在验证之中,也就是常说的system
verilog(SV),写在testbench,不可综合。如果在功能代码中这样写进程,或者显示的写延时语句是没有用的,只能用于功能查看,无法综合这些指定的内容。但是功能代码中常常使用阻塞与非阻塞进行流水线设计,以及多个模块的并行。像testbench中还通常会有任务task,函数func,打印,以及其他特殊约束或者规则等。

总之,verilog中fork…join在testbench延时很有用。

initial

begin

........

end

之间的语句都是顺序执行,特别中间有延迟时间时,就是顺序累加的结果。

initial

fork

.....

join

之间的语句都是并行执行的,特别是延迟时间也是并行的,不是相互累加的结果。

更详细点说,

块语句是指将两条或者两条以上的语句组合在一起,使其在格式上更像一条语句。块语句分为两种:

1)用begin_end语句,通常用来标识顺序执行的语句,用它标识的块称作顺序块

2)用fork_join语句,通常用来标识并行执行的语句,用它标识的块称作并行块

A)顺序块

begin

    语句1;

    语句2;

   ....

    语句n;

end

begin:块名

    块内声明语句

    语句1;

    语句2;

   ....

    语句n;

end

特点:

1)块内的语句是按照顺序执行的,即只有上面一条语句执行完后下面的语句才能执行;

2)每条语句的延迟时间都是相对于前一条语句的仿真时间而言的;

3)直到最后一条语句执行完,程序流程控制才跳出该语句块。

在begin-end语句块中,begin-end和fork-join块可以相互嵌套,也可以自我嵌套。如果begin-end中包含有局部声明,则他必须被命名(必须有一个标志)。如果要禁止一个begin-end块,那么被禁止的begin-end必须有名字。

B)并行块

fork

    语句1;

    语句2;

   ....

    语句n;

join

fork:块名

    块内声明语句

    语句1;

    语句2;

   ....

    语句n;

join

特点:

1)块内语句是同时执行的,即程序流程控制进入该块时刻,块内语句则开始同时并行执行;

2)块内每条语句的延迟时间都是相对于程序流程进入到块内的时刻。

3)延迟时间是用来给赋值语句提供执行时序的;

4)当按时间排序在最后的语句执行完成后,或者一个disable语句执行时,程序流程控制跳出该模块。

块名:

1)可以在块内定义局部变量,即只在块内使用的变量;

2)可以允许被其他的语句调用,也可以通过层次名进行调用;

3)在Verilog中,所有的变量都是静态的,即所有的变量都只有一个唯一的存储地址,因此进入或者跳出块并不影响储存在变量内的值。

4)命令块可以被禁用,关键词为disable,可以用disable跳出循环,处理错误条件以及根据控制信号来控制某些代码是否执行。

顺序块和并行块的性质对比

在这里插入图片描述

parameter  d=50;

reg   [7:0] r;

begin

    #d   r='h35;

    #d   r='hE2;

    #d   r='h00;

    #d   r='hF7;

    #d   ->end_wave;                   //->表示触发事件end_wave使其翻转

end

(如果d=0,则这个顺序块的执行不需要时间。若d=50,则块语句完成的时间为250,因为每个语句都要等待50个时间单位)

fork

    #250  ->end_wave; 

    #200   r='hF7;

    #150   r='h00;

    #100   r='hE2;

    #50     r='h35;

join

(在并行块中,所有语句都是在程序流程进入并行块时同时开始的,因此这个语句结束的时间为250)


以上就是本人fork … join的主要内容了。
这里再添加一个小模块作为示例,主要介绍时钟控制沿的作用,始终永远是最快的,最好什么东西都要以时钟作为基准
这是网上某人写的一个简易的算数模块:

module arithmetic(IN,S,A,B,LDA,LDB,FZ,ALU,CLK,rst_n);//建立变量
input CLK,rst_n;//输入变量
input [2:0] S; //输入变量(3位)
input LDA,LDB; //输入变量
input [7:0] IN; //输入变量(8位)
output [7:0] A,B,ALU;//输出变量(8位)
output FZ;//输出变量
reg [7:0] A,B,ALU;//变量类型
reg FZ; //变量类型

always @ (posedge CLK or negedge rst_n)//当CLK处在上升沿时执行下列程序 
begin
	if (!rst_n)
		begin 
			A<=0;
			B<=0;
			ALU<=0;
		end
	else
		begin
				if(LDA==1'b1) A<=IN;//LDA为1时IN给A赋值
				else if(LDB==1'b1) B<=IN; //LDB为1时IN给B赋值
		
				case (S)
				3'b000:ALU<=A+B;//+
				3'b001:ALU<=A-B;//-
				3'b010:ALU<=A-1;//-1
				3'b011:ALU<=A&B;//与
				3'b100:ALU<=A|B;//或
				3'b101:ALU<=A<<1;//左移
				3'b110:ALU<=A>>1;//右移
				3'b111:ALU<=A+1;//+1
				endcase
		
				if(ALU==8'b00000000)
					FZ<=1'b1;//进位
				else
				FZ<=1'b0;//零位
			
		end
end
endmodule

对应的tb:

`timescale 1 ps/ 1 ps
module arithmetic_vlg_tst();
reg CLK,rst_n;
reg [7:0] IN;
reg LDA;
reg LDB;
reg [2:0] S;                                            
wire [7:0]  A;
wire [7:0]  ALU;
wire [7:0]  B;
wire FZ;                      
arithmetic i1 (   
	.A(A),
	.ALU(ALU),
	.B(B),
	.CLK(CLK),
	.FZ(FZ),
	.IN(IN),
	.LDA(LDA),
	.LDB(LDB),
	.S(S),
	.rst_n(rst_n)
);
initial
	begin
		rst_n=1;
		#20 rst_n=0;
		#20 rst_n=1;
	end
initial                                                
begin                                                  
CLK=00000000;

	forever
	#20 CLK=~CLK; 
end
initial
begin
	LDA=00000000;
	forever
	#35 LDA=~LDA;
end
initial
begin
	LDB=00000001;
	forever
	#35 LDB=~LDB;
end

initial             
begin                                                  
    IN=00000001;
	 forever
	 #20 IN=IN+00000001;
end
initial
begin
	S=000;
	forever
	begin
	repeat(7)
	begin
		#20 S=S+001;
	end
	end
end 
endmodule

当然了,tb也可以这样:

`timescale 1 ps/ 1 ps
module arithmetic_vlg_tst();
reg CLK,rst_n;
reg [7:0] IN;
reg LDA;
reg LDB;
reg [2:0] S;                                            
wire [7:0]  A;
wire [7:0]  ALU;
wire [7:0]  B;
wire FZ;                      
arithmetic i1 (   
	.A(A),
	.ALU(ALU),
	.B(B),
	.CLK(CLK),
	.FZ(FZ),
	.IN(IN),
	.LDA(LDA),
	.LDB(LDB),
	.S(S),
	.rst_n(rst_n)
);
initial
	begin
		rst_n=1;
		#20 rst_n=0;
		#20 rst_n=1;
	end
initial                                                
begin                                                  
CLK=00000000;

	forever
	#20 CLK=~CLK; 
end
initial
begin
	LDA=00000000;
	forever
	#35 LDA=~LDA;
end
initial
begin
	LDB=00000001;
	forever
	#35 LDB=~LDB;
end

initial             
begin                                                  
    IN=00000001;
	 forever
	 #20 IN=IN+00000001;
end
initial
begin
	S=000;
	forever
	begin
	repeat(7)
	begin
	    @(posedge CLK)
		S=S+001;
	end
	end
end 
endmodule

你可以试着用modelsim进行对应的仿真,看下输出波形。

更多参考;

https://www.cnblogs.com/SYoong/archive/2016/09/08/5852128.html
https://www.cnblogs.com/god_like_donkey/archive/2011/08/11/2135128.html
http://blog.sina.com.cn/s/blog_6c7b6f030101cpgt.html
https://blog.csdn.net/lbt_dvshare/article/details/81236313
https://segmentfault.com/a/1190000012014804

posted on 2022-08-18 10:57  皮皮祥  阅读(903)  评论(0编辑  收藏  举报