当前位置:   article > 正文

数字IC设计verilog编写——4流水线握手协议_握手协议verilog

握手协议verilog

1 流水线与握手协议

流水线在电路设计过程中,是必不可少的一种实现方式,其可以提高电路的性能,当我们需要设计高速电路的时候,就需要用到流水线;

流水线的设计,就是指对延时较大的组合逻辑插入寄存器,把较大的组合逻辑拆分成几个时钟周期来完成,以提高系统的最大时钟频率。但是这样做,会导致数据输出的延时,假若插入一个寄存器,则数据输出就到产生一个时钟周期的延时,假若插入N个寄存器,就会产生N个时钟周期的延时;

而握手协议能够确保数据的上游和下游能够正确的接收数据,握手协议的原则是:当Valid和Ready信号同时高有效时,数据在时钟上升沿传输:

在这里插入图片描述
2 流水线握手协议的电路设计

下面主要介绍使用Verilog设计一个简单的Valid-Ready握手协议电路的基本原理

本设计可以实现数据的流入和数据的流出,这样一个双端口握手协议通道传输。Valid和Ready信号的原理类似于FIFO的读写和空满信号,就好像FIFO外边包了一层。
在这里插入图片描述

在FIFO的端口信号上加上如上图所示反相器,也可达到握手的效果。

Valid-Ready信号产生有两种情况

1.Ready-Before-Valid

Ready-Before-Valid是Ready信号在Valid信号之前有效。

这样设计使得在数据来临之前,通道已准备好接收数据,可以保持通道的最大吞吐量,因为Ready先产生,这个通道保持刷新等待数据。通道作为接受数据端采用这样的设计。

2.Valid-before-Ready

Valid-before-Ready是Valid信号在Ready信号之前有效。通道作为数据输出端采用这样的设计。收到下游接收端的准备接收信号,才开始传输数据。

Valid-Ready协议Stalemate情况

Stalemate可以理解为“锁住”。假设我们不遵守上面两种接收端和输出端的设计规则。

输出端用Ready-Before-Valid而接受端使用Valid-before-Ready,就会出现输出端等待接受端给出的Ready来输出数据,但是接收端也在等待输出端给出Valid信号来接受数据。两者都在等待却没有一方先给,所以这个时候这个通道就是无效的,被“锁住”了。

握手协议的几种连接情况

在这里插入图片描述
3.握手流水线的Verilog设计(其中一级)

在这里插入图片描述
前面说过握手协议的接口可以在同步FIFO的基础上加以修改,修改电路如图:

assign  valid_o = ~fifo_empty;
assign  ready_o = ~fifo_full;
assign  wr_en = ready_o & valid_i;
assign  rd_en = ready_i & valid_o;
  • 1
  • 2
  • 3
  • 4

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

module Handshake_Protocol(
	input clk,
	input rst_n,

	input 			valid_i,  //from pre-stage
	input        data_i,  	//from pre-stage
	input 			ready_i,  //from post-stage

	output 		   ready_o,  //to pre-stage
	output 			valid_o,  //to post-stage
	output        data_o  	//to post-stage
);

	reg 		 valid_o_r;
	reg  		 ready_o_r;

	reg   		data_r;
	reg 	    dout;

   always @(posedge clk or negedge rst_n) begin
		if(!rst_n) begin
			valid_o_r <= 1'b0;
         data_r  <= 0;
      end
		else if(valid_i && ready_o) beign
        valid_o_r <= 1'b1;
         data_r  <= data_i;
      end
      else
			valid_o_r <= 1'b0;
	end

	always @(posedge clk or negedge rst_n)
		if(!rst_n) begin
			ready_o_r <= 1'b0;
         dout 	 <= 0;
		end
		else if(valid_o_r && ready_i) begin
        	ready_o_r <= 1'b1;
          	dout <= data_r;
		end
      else
      	  ready_o_r <= 1'b0;
   end

	assign ready_o = ready_o_r;
	assign valid_o = valid_o_r;
	assign data_o  = dout;

endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50

当vld_o为拉高时,表示这一级数据已经准备好,下一级数据可以将其读走;

当ready_o为拉高时,表示这几数据已经被读走,上一级数据可以写入新的数据;

此外,如果要实现高速的流水线作业,即这一级数据被读走时,上一级数据同时进来,这样每一级寄存器都会无缝的连接上(流水);

但是上述RTL存在优先级问题,即数据没有被读走之前,不能被写入;

always @(posedge clk or negedge rst_n) begin
	if(!rst_n) begin
		valid_o_r <= 1'b0;
         data_r  <= 0;
      end
	else if(valid_i && ready_o) beign    //数据可写进来,同时将valid_o置高,告诉下一级读取数据
        valid_o_r <= 1'b1;
         data_r  <= data_i;
      end
      else if(valid_o_r && ready_i)     //如果数据读走之后,因此将valid_o拉低;
		valid_o_r <= 1'b0;
end



always @(posedge clk or negedge rst_n)
	if(!rst_n) begin
		ready_o_r <= 1'b0;
         dout 	 <= 0;
	end
	else if(valid_o_r && ready_i) begin
        	ready_o_r <= 1'b1;
          	dout <= data_r;
	end
      else if (ready_o_r && valid_i)
      	  ready_o_r <= 1'b0;
   end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

当该级ready_o与valid_i同时为高时,将valid拉高,表明数据已经被写入了,下一级可以读出;

有问题的欢迎指正!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/206875
推荐阅读
相关标签
  

闽ICP备14008679号