Verilog手撕代码(8)握手机制

文章介绍了Verilog中实现数据交互的握手信号机制,包括上游master和下游slave的valid-ready同步方式,并提供了两个具体案例:数据串转并电路和数据累加输出模块的设计与测试bench仿真。案例展示了如何处理数据传输的完整性和效率问题。
摘要由CSDN通过智能技术生成

握手信号

握手信号,就是为了模块之间的数据交互正确才衍生出来的信号。其无非就是三种可能

  • 上游master提供的valid 信号随数据一起拉高,但下游slave过一段时间才准备好的valid先高为敬。

在这里插入图片描述

  • 下游slave一直准备好,但上游数据过段时间才有效的ready先高为敬。
    在这里插入图片描述
  • 上游master的valid信号和下游slave的ready同时为高。

在这里插入图片描述

对于master来说,master发出一个数据,如果数据有效,master就会把传送给slave的valid信号拉高,即告诉slave数据有效可以接收!如果slave准备好了,slave就把传送给master的ready信号拉高,告诉master我准备好了,如果你数据有效,我就可以接收!所以当master传输的数据有效,且slave也准备好时,数据就会在下一个周期被slave取走,master可以接着传下一个数据。

案例一

代码:

`timescale 1ns/1ns
module handshake(
	input 		clk,
	input 		rst_n,
	
	input 		valid_i,
	input [7:0] data_i,	
	output		ready_o,
	
	output [7:0]data_o,
	input 		ready_i,
	output 		valid_o
);

reg [7:0] data_o_r;
reg valid_o_r;

assign ready_o = ready_i; // 下游准备好时,此模块也准备好接收上游数据

always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		data_o_r <= 8'b0;
	else if(valid_i && ready_i) //如果下游准备好了,并且上游数据有效,那就把输入的数据乘以二输出
		data_o_r <= data_i * 2;	
end

always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		valid_o_r <= 1'b0;
	else if(ready_o)
		valid_o_r <= valid_i; //如果准备好了,就把上游的valid传递给下游。

end

assign data_o = data_o_r;
assign valid_o = valid_o_r;
endmodule

Testbench:

`timescale 1ns/1ns
module handshake_tb();
reg		clk;
reg		rst_n;

reg		valid_i;
reg[7:0] data_i;
wire		ready_o;
	
wire [7:0]data_o;
reg		ready_i;
wire	   valid_o;

	handshake inst(
		.clk(clk),
		.rst_n(rst_n),
		.valid_i(valid_i),
		.data_i(data_i),	
		.ready_o(ready_o),
		.data_o(data_o),
		.ready_i(ready_i),
		.valid_o(valid_o)
);

always #10 clk = ~clk;
initial begin
	clk = 0;
	rst_n = 0;
	data_i = 8'd0;
	valid_i = 1'b0;
	ready_i = 1'b1;
	#15
	rst_n = 1;
	#15
	rst_n    <= 1'b1;
   ready_i <= 1'b1;    //下游准备好了
   valid_i <= 1'b0;    //上游数据无效
   data_i  <= 8'b0000_1000;
   #20
   data_i  <= 8'b0111_1000;
   valid_i <= 1'b1;    //上游数据有效
   #20
   data_i  <= 8'b0100_0100;
   #20
   valid_i <= 1'b0;
   #20
   data_i  <= 8'b0010_0100;
   valid_i <= 1'b1;    //虽然上游数据有效,但下游没准备好
   ready_i <= 1'b0;
   #20
   ready_i <= 1'b1;    //上游数据有效,下游准备好了
   #20
   valid_i <= 1'b0;
   #500
   $stop();
	 
end

endmodule

用tb来模拟本模块的上游master和下游slave,用tb给本模块提供上游数据data_i和valid_i信号。分别模拟了上游断流,即valid_i中途拉低,以及下游反压,即ready_i中途为低的情况。

仿真结果:
在这里插入图片描述

案例二 :数据串转并电路

实现串并转换电路,输入端输入单bit数据,每当本模块接收到6个输入数据后,输出端输出拼接后的6bit数据。本模块输入端与上游的采用valid-ready双向握手机制,输出端与下游采用valid-only握手机制。数据拼接时先接收到的数据放到data_b的低位。

电路的接口如下图所示。valid_a用来指示数据输入data_a的有效性,valid_b用来指示数据输出data_b的有效性;ready_a用来指示本模块是否准备好接收上游数据,本模块中一直拉高;clk是时钟信号;rst_n是异步复位信号。

在这里插入图片描述
在这里插入图片描述

module s_to_p(
	input      		  clk,
	input      		  rst_n,
	input      		  valid_a,
	input      		  data_a,
			  
	output reg 		  ready_a,
	output reg 		  valid_b,
	output reg [5:0] data_b
);
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		ready_a = 1'b0;
	else
		ready_a = 1'b1;
end

reg[2:0]cnt;
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		cnt <= 3'd0;
	else if(valid_a && ready_a)
		cnt <= (cnt == 3'd5)?3'd0:cnt + 1'b1;
	else
		cnt <= cnt;
end

reg [5:0] data_b_r;
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		data_b_r <= 6'd0;
	else if(valid_a && ready_a)
		data_b_r <= {data_a,data_b_r[5:1]};
end

always@(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		data_b <= 6'd0;
		valid_b <= 1'b0;
	end
	else if(cnt == 3'd5)begin
		data_b <= {data_a,data_b_r[5:1]};
		valid_b <= 1'b1;
	end
	else 
		valid_b <= 1'b0;
end
endmodule

Testbench:

`timescale 1ns/1ns
module s_to_p_tb();
	reg 		 clk;
	reg 		 rst_n;
	reg 		 valid_a;
	reg 		 data_a;
			  
	wire		 ready_a;
	wire		 valid_b;
	wire[5:0] data_b;

	s_to_p inst(
		.clk(clk),
		.rst_n(rst_n),
		.valid_a(valid_a),
		.data_a(data_a),

		.ready_a(ready_a),
		.valid_b(valid_b),
		.data_b(data_b)
	);
	always #10 clk = ~clk;
	
	initial begin
		clk= 0;
		rst_n = 0;
		valid_a = 0;
		data_a = 0;
		#15
		rst_n = 1;
		#15
		valid_a = 1;
		data_a = 1;
		#20
		data_a = 0;
		#20
		data_a = 1;
		#20
		data_a = 0;
		#20
		data_a = 0;
		#20
		data_a = 1;
		#20
		data_a = 1;
		#20
		valid_a = 0;
		#40
		valid_a = 1;
		#40
		data_a = 0;
		#40
		data_a = 1;
		#20
		data_a = 0;
		#200
		$stop;
	end
	endmodule

仿真结果:

在这里插入图片描述

案例三:数据累加输出

实现串行输入数据累加输出,输入端输入8bit数据,每当模块接收到4个输入数据后,输出端输出4个接收到数据的累加结果。输入端和输出端与上下游的交互采用valid-ready双向握手机制。要求上下游均能满速传输时,数据传输无气泡,不能由于本模块的设计原因产生额外的性能损失。

电路的接口如下图所示。valid_a用来指示数据输入data_in的有效性,valid_b用来指示数据输出data_out的有效性;ready_a用来指示本模块是否准备好接收上游数据,ready_b表示下游是否准备好接收本模块的输出数据;clk是时钟信号;rst_n是异步复位信号。

在这里插入图片描述
在这里插入图片描述
代码:

module valid_ready(
	input 			  clk,
	input 			  rst_n,
	input [7:0] 	  data_in,
	input 			  valid_a,
	input 			  ready_b,
		  
	output 			  ready_a,
	output reg		  valid_b,
	output reg [9:0] data_out
);

assign ready_a = !valid_b || ready_b;
reg [1:0]cnt;
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		cnt <= 2'd0;
	else if(valid_a && ready_a)
		cnt <= (cnt == 2'd3)?2'd0:cnt + 1'd1;
end

always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		valid_b <= 1'b0;
	else if(cnt == 2'd3 && valid_a && ready_a)
		valid_b <= 1'b1;
	else if(valid_b && ready_b)
		valid_b <= 1'b0;
end

always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		data_out <= 10'd0;
	else if(cnt == 2'd0 && valid_a && ready_a && ready_b)
		data_out <= data_in;
	else if(valid_a && ready_a)
		data_out <= data_in + data_out;
end
endmodule

Testbench:

`timescale 1ns/1ns
module valid_ready_tb();
	reg 			  clk;
	reg 			  rst_n;
	reg [7:0] 	  data_in;
	reg 			  valid_a;
	reg 			  ready_b;
		  
	wire 	      ready_a;
	wire 		   valid_b;
	wire  [9:0] data_out;

 valid_ready inst(
	.clk(clk),
	.rst_n(rst_n),
	.data_in(data_in),
	.valid_a(valid_a),
	.ready_b(ready_b),
	.ready_a(ready_a),
	.valid_b(valid_b),
	.data_out(data_out)
);
always #10 clk= ~clk;
initial begin
	clk = 0;
	rst_n = 0;
	ready_b = 0;
	#15
	rst_n = 1;
	#15
	valid_a = 1;
	data_in = 1;
	#20
	data_in = 2;
	#20
	data_in = 3;
	#20
	data_in = 4;
	#20
	data_in = 5;
	#40
	ready_b = 1;
	#200
	$stop;
	
end
endmodule

仿真结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值