valid_ready protocol

 http://www.socvista.com/bbs/viewthread.php?tid=2110&extra=&page=1

【PIPE】流水线设计中的基本模块

大概分成以下几节:  

1,概述及协议 

2,valid forward-valid超前 
3, bubble collapse - 消除气爆  
4, input/output skid - 不知中文怎么说 
5, pipe halt - 流水停顿 

6,idle present - 显示空闲

 

protocol

两个模块需要协同工作,少不了的就是你给我一些数据,我告诉你我收到了。或者你问我要一些数据,我过一会给你。
“你给我,我告诉你我收到了”,在通信,称之为握手。在数字设计中也一样。

握手有很多种,pipe里用到的这种握手协议,被我称为valid_ready。描述如下

valid_ready协议:
1, 当sender端有数据要发送时,将valid置1,并保证数据有效,可以不用检测ready。
2, 当receiver模块允许接受数据,将ready置1,可以不用检测valid是否有效。
3, 在任一个cycle,如果valid=1 && ready=1, 则接受端将会在紧接着的下一个clock posedge将数据采入,并通过ready信号来表示自己是否可以接受新的数据。
4, 在任一个cycle,如果valid=1 && ready=1,如果发送端仍有数据需要发送,则会在下一个clock posedge将新数据放入data bus,来表示自己有新的数据需要发送。如果没有新的数据需要发送,则将valid置0,表示没有数据需要发送。如果前一次的数据没有被接受端接受,即 ready=0,发送端需要保持valid=1,否则,数据将被丢弃,并没有被接收端收到。






如上图所示,c1周期,发送端有数据想要发送,将valid置1,并将D0稳定;可是c1周期接收端不肯接受数据(可能因为他正在忙于其他事务的处理), 数据没有被接受,发送端只能继续将valid置1,并保持D0不变。c2周期,接受端不再繁忙,可以接受数据了,于是他将ready置1,表明这个周期他 可以接受新数据。于是D0便在c2结束的那个上升沿被接收端取走。尽管接受端还想接受数据(c3周期,ready仍为1),但是发送端没有新数据需要发 送,于是接收端继续保持ready=1,表明自己仍可以接受数据。
紧接着,发送端在c4周期又有数据需要发送,于是就置vliad=1,而此时接收端正在等着呢,于是这个数据D1在c4周期,就传送完成。这次发送方发送 完D1,紧接着还有D2需要发送,可是接收端不干了,他不能、不想、不愿意接受新的数据,于是D2和表明D2有效的valid只能一直保持在那里,等啊 等,等啊等。。直到c7,接收端可以接受了。于是D2终于传过去了。

呼呼,,,3笔数据就这么传完了。。。 

 

 

 

basic pipe

basic pipe所 谓的pipe,他的目的就是实现pipeline,即流水,有了valid_ready,我们就能很容易的将操作进行流水作业。通过插入pipe,可以将 原来需要较多层的逻辑分拆开来,每一级pipe做一点。如下图,这是插入了一级pipe的。其中valid和data是同样的逻辑,所以就合并画在一起 了。 


下图,这是插入了2级pipe的。
 

每一级你可以对data进行一些处理,再传给下一级。

对于每一级pipe,其基本的逻辑是这样的。o: output, i:input

vo <= (ri) ? vi : vo;
do <= (ri) ? di : do;
ro = ri;

这个就是最基本的pipe的逻辑。

下面是基本pipe的电路图。

 

 

valid forward

细 心的读者会注意到,当sender想要发送数据的时候,会将vi置1,这样,当receiver能够接受数据时,需要多等一个cycle,即数据先要寄存 在pipe中,然后下一个cycle,接受端才能看到数据有效。如果要传输一笔数据需要2个cycle,当数据连续传送时,这没有问题,但是如果数据都是 零碎的片断,那么效率就变得比较低下。也就是说,当pipe里面为空,但是receiver端不可以接受数据时,数据还是得停留再sender端,而这个 空的pipe,我们称之为bubble。

如何解决这个问题? 
当我们发现如果pipe级没有有效数据,即vo=0,那么我们让vi直接送到receiver端,而不再寄存一级。这样做的好处是效率提高了,坏处就是 timing变差了。而且相比于没有插入pipe,timing更糟糕了。因为多了一些mux。其实,最糟糕的是,这种做法毫无用处,除非和下面要讲的 bubble collpase配合使用。因为如果没有bubble collapse,它根本就没让pipe工作,因为reset之后,pipe始终为空,于是每一次,数据都绕过了pipe,直接送到了serder端。而 且,这比没有插入pipe的timing来的更糟糕。这和我们最初要引出pipe,来实现流水以提高timing性能,这个目的相矛盾。
下面我们要讲提及了很多次的bubble collapse了,看看他神奇在什么地方。其实道理很简单,如果receiver端不ready,而pipe为空,我们就将数据先进入pipe级的寄存 器,缓存于pipe级。在sender看来,这个数据已经被pipe级取走,可以放新的数据了。下次,receiver端ready了,直接和pipe要 数据即可。这样,bubble就消失了。
如图所示:



逻辑代码如下:
ro = ri || !vo;             // ready
vo <0= (ro)? vi : vo;       // valid
do <= (ro && vi)? di : do;  // data

仔细、仔细、再仔细体会一下以上代码

 

 

input/output skid

pipe 能有效的改善data的timing(当然,顺带也改善了valid的timing),使得data在其传输路径上被寄存N拍,,如果有复杂的组合逻辑, 则可以将组合逻辑拆成一系列的组合逻辑,并在每个之间插入pipe,尽管每一笔数据的延时增加了,但是带宽并没有变小。可是,如果ready信号的产生, 传播逻辑比较复杂,我们也同样在某些地方将ready打上一拍,以改善他的timing。可是仅仅对ready打一拍,协议就会被破坏了,使得valid 和ready对应不上。

现在我们仅仅简单的将ready打了一拍给sender端,那么sender端看到就是延时一拍以后的ready,即ro<=ri。如果vi=1&&ro=1,从sender的角度看来,就是data被取走了,可以放一个新的数据了。




让我们用最简单的basic pipe来举例说明。假设sender有3笔数据需要发送,而receiver收到一笔后既不能再接受,需要进行一些处理,等几个cycle之后才能再接受新的数据。

其时序如图所示:



我们来简单分析一下:
最初,sender没有数据要发送,vi=0;receiver空闲,可以接受数据,ri=1。但是由于在c3时刻,ri=0,ro=1;receiver不可以接收新的数据,而sender没有及时发现,他还是将数
据D2押送给了pipe,但是pipe里面囤积的D1并没有被收走,于是pipe处于一个两难的境地,要么将D1丢弃,要么将D2丢弃,无论如何,总是会丢失一笔数据。

D1占据着Pipe里唯一可以容身的小屋(data register),D2来了,也想进来。D1看了看D2,说:“小样,你是新、新、新、新、新来的吧……,我这里只有一间屋,住不下咱俩,要不这间给 你,我自己在离sender近一点的地方再造一间新屋,但是得先说好,船来了(ri=1),我先走。”D2想了想,没办法,一山不容二虎,除非一公和一 母,谁让咱俩没性别,要不然…………说不定,还能生个小娃,这是后话。

于是,我们又造了一间新的小屋,起名叫skid buffer。当ri从1变0时,即ri=0,ro=1,表示receiver端忽然不能接受新数据了,但是sender要晚点才能知道,这时 候,skid给D1住,D2住老屋。当ri从0变1时,即ri=1,ro=0,表示receiver有可以接受新数据了,这是得先把skid里得数据放 走。此时skid里住着D1呢,D2这时看到得还是ro=0,所以他继续呆在老屋里不动。除了这两种情况,其他情况都无所谓,随便我们怎么处理skid都 可以,如果想要逻辑简单,那么就像我上面所说得那样处理。但是会出现的这个问题:D2在以后的cycle中,尽管不需要再住进skid了,但是还是会给个 分身给skid,而自己会直接从老屋乘船走了。这样会造成skid里不停的让无用的D2们进进出出(无效翻转);为了降低skid再无用的时候不要住无用 的D2们的分身,可以加一点控制逻辑,使得D2们在不需要的时候不要浪费skid的资源。(逻辑为 ri ^ ro==0时,disable skid)

下面这个图稍微复杂了点,是一个basic pipe+skid。控制逻辑最少,但增加了额外的skid使用。






skid和pipe这两部分的位置是可以互换的。如果你能成功的做到,你对以上内容的掌握应该已经炉火纯清了。

 

 

pipe halt

在输入增加一个信号,用于将pipe停止。
即流水线停顿。来自upstream的valid会立即被忽略,送给上一级的ready立刻被取消。同样送给downstream的valid立刻会被取消,而ready也不予理睬。pipe内部所有数据流全部立即停止。

但是如果pipe内部有skid,为了保证数据的正确,skid级的valid立即取消,但是送给upstream的ready需要在下一个cycle再 停顿。恢复的时候也一样,valid立即恢复,而送给upstream的ready需要在下一个cycle才可以恢复。(有关skid的停顿逻辑需要你冥 想3分钟,我刚开始几次,每次思考这个问题,都不能一下子想明白,总要绕几圈才豁然。) 

 

 

idle present

Idle 信号表明Pipe中没有有效数据,即每一级pipe的valid无效。
其逻辑为

idle = ~(p1_valid |p2_valid|...)

其中,pn_valid 为第n级Pipe的vo

 


以下为:valid forward的实现

 

代码
 1
 2module pipeline (iclk, irst_n, datain, datain_val, datain_rdy,
 3                  dataout, dataout_val, dataout_rdy);
 4parameter DW = 8;
 5input                   iclk;
 6input                   irst_n;
 7input[DW-1:0]           datain;
 8input                   datain_val;
 9output                  datain_rdy;
10input                   dataout_rdy;
11output reg [DW-1:0]     dataout;
12output reg              dataout_val;
13    
14assign datain_rdy = dataout_rdy || !dataout_val;
15 
16 always@(posedge iclk or negedge irst_n)
17 begin
18     if(!irst_n)
19     begin
20         dataout_val <= 1'b0;
21         dataout <= 0;
22     end
23     else
24     begin
25         dataout_val <= (datain_rdy)? datain_val: dataout_val;
26         dataout <= (datain_rdy && datain_val)? datain : dataout;
27         
28     end
29 end
30            
31endmodule
32            
33

 

posted on 2009-12-02 10:20  Homography Matrix  阅读(3674)  评论(0编辑  收藏  举报

导航