流水线中的握手信号笔记

1.《握手信号的打拍(一)》

解释了,为什么在流水线中,握手信号不能简单得加一级寄存器

业界关于流水线级握手信号的标准答案是 skid buffer,此外还有人提到了 Register slice

2.《握手信号的打拍(二)》

为什么简单加一级寄存器会握手失败 ?

从图1可以看出,加入 Handshake Pipe Module 之后,在 Sender 端有一组握手信号,在 Receiver 也有一组握手信号。也就是说,我们必须同时满足 Sender 端和 Receiver 端的握手,才能保证握手成功。

但是简单加一级寄存器只是满足一边的,图2是对 valid+data 打一拍,可以看出只能满足 Sender 端的握手时序。

流水线中的握手信号笔记_第1张图片

如图,对 valid + data 打一拍,只满足了 Sender 端的握手时序

握手信号 valid 打拍的改进

观察图2,我们可以看到,Receiver 端不能满足握手时序的原因是 Sender 端认为数据已经被接收,从而拉低 valid,导致 valid_pipe 也被拉低。那么我们解决的办法应该是在 pipe 模块中保持住 valid 直到 receiver 端也握手成功,如图3所示。

流水线中的握手信号笔记_第2张图片

图3 - handshake valid pipe example1

为了提高效率,我们可以在 IDLE 状态(即没有保持数据)时让 pipe 模块输出 ready_o 高电平,直到 Sender 端握手成功。接着保持住 valid 和 data,直到 Receiver 端也握手成功。如图4所示。

流水线中的握手信号笔记_第3张图片

图4 - handshake valid pipe example2

图5是 Sender 端连续发送数据,但是 Receiver 端 ready 不连续的例子。可以看到 Sender 端有三次握手,Receiver 端也有三次握手。

流水线中的握手信号笔记_第4张图片

图5 - handshake valid pipe example3

图6是 Sender 端连续发送数据,Receiver 端 ready 也连续的例子。

流水线中的握手信号笔记_第5张图片

图6 - handshake valid pipe example4

后面有对 ready 信号打拍的内容,不明白为什么要打拍,我觉得现在这样就挺好,skip

3. 芯片设计-握手与反压(valid&ready)

从工厂流水线说起

流水线中的握手信号笔记_第6张图片

本来一众打工人在流水线上"快快乐乐"地搬砖,突然receiver处理不过来了,拉低了data_o_ready。为避免数据丢失,得立刻启动应急方案。

应急方案1 (receiver 直接告知 sender 不接受新数据,同时使用 FIFO 接收流水线中的数据) (缺点:成本高)

receiver立刻通知sender,拉低data_i_ready(assign data_i_ready = data_o_ready),不允许再进新数据了。

流水线中的握手信号笔记_第7张图片

(注:本章所有图示均用红色表示该pipe处于工作状态,无色表示该pipe处于空闲状态)

此时虽然没有新输入了,但是流水线中的搬砖人没有得到通知,还在继续工作。意味着流水线还会输出3个数据,但是receiver已经拒绝接收数据了。没办法,这时我们得放个fifo在流水线末尾,fifo深度等于流水线级数。

流水线中的握手信号笔记_第8张图片

虽然这个方案解决了问题,但增加了fifo,提升了工厂成本。老板不允许,想想其他方案吧。

应急方案2 (reciver 暂停整个 sender 和所有流水级)     (缺点:流水级中没有被塞满的部分也会空转,每次流水线复位都会有气泡在悬停)

在这个方案中,receiver不仅通知sender暂停,还会通知整个pipe暂停。此时不会有数据输出,也不需要加fifo了。

流水线中的握手信号笔记_第9张图片

但从上图我们可以看到,PIPE2是空闲的,这意味着虽然此时receiver拒绝接收,但其实没必要立刻停掉流水线的,完全可以再跑一拍流水的。可能打工人觉得没啥,等一下就好,但工厂老板可不是这样想的。

首先,出现pipe空闲的情况,都是在流水初始阶段,这时候后级流水需要等若干拍才能拿到数据来干活。而我们往往会在完成一次任务后复位流水,而每次复位都会存在PIPE空闲的情况。

我们假设一次任务处理16个数据,流水线为3级,处理完后需要复位流水线。

(注:在ISP中,一般是一帧为一次任务,在vblank期间复位流水线。这里为描述方便简化处理)

理想情况下,需要16+3拍才能完成任务,这里的3拍我们称之为气泡。这意味着对于receiver来说,他需要等待。老板不希望有气泡时间,希望的是他的receiver能够满负荷工作,即一旦receiver准备好了(data_o_ready为高),就能立刻接收到数据。

所以,方案还得改善……

应急方案3

我们得想办法挤掉气泡,别data_o_ready一拉低,大家就摸鱼,可以干的得继续干。

如方案2所提到的,气泡仅出现在流水线初始阶段,且持续拍数=流水级数。也就是说,在前几拍的时候,不用管data_o_ready什么状态,大家努力干活就是。

因此,我们添加一个计数器,当data_i_ready & data_i_valid有效时,计数器+1。当计数器小于流水级数时,流水线保持工作;当计数器≥流水级数时,流水线工作与否取决于data_o_ready.

流水线中的握手信号笔记_第10张图片

本方案虽然把气泡挤掉了,但是控制会麻烦许多,因此:

  • 如果你的应用不在意这点气泡,比如一帧4K图像仅有几十拍的气泡,那用方案2也没啥问题。
  • 如果你的应用不会出现起始阶段,receiver不ready的情况,那也没必要用本方案

老板对本方案表示很满意,但我们可以继续想想有没有其他方案。

 目前看到应急方案4

应急方案4

逐级反压,只要我的后级空闲或ready, 我就传数据给他。

流水线中的握手信号笔记_第11张图片

以下是代码。注意:以下代码要配合下面的图,才比较好看懂

流水线中的握手信号笔记_第12张图片

用代码表示:

module pipe_ctrl #(
	parameter DW = 8 )( input clk, input rst_n, output data_i_ready, input data_i_valid, input [DW-1:0] data_i, input data_o_ready, output data_o_valid, output [DW-1:0] data_o ); // ------------------- // signals def // ------------------- reg valid_l1; wire ready_l1; reg [DW-1:0] data_l1; reg valid_l2; wire ready_l2; reg [DW-1:0] data_l2; reg valid_l3; wire ready_l3; reg [DW-1:0] data_l3; // ------------------- // pipe logic // ------------------- // l0 assign data_i_ready = ~valid_l1 || ready_l1; // l1 always @ (posedge clk or negedge rst_n) begin if(!rst_n) valid_l1 <= 0; else if(data_i_ready) valid_l1 <= data_i_valid; end assign ready_l1 = ~valid_l2 || ready_l2; always @ (posedge clk) begin if(data_i_ready && data_i_valid) data_l1 <= data_i + 1; end // l2 always @ (posedge clk or negedge rst_n) begin if(!rst_n) valid_l2 <= 0; else if(ready_l1) valid_l2 <= valid_l1; end assign ready_l2 = ~valid_l3 || ready_l3; always @ (posedge clk) begin if(ready_l1 && valid_l1) data_l2 <= data_l1 * 2; end // l3 always @ (posedge clk or negedge rst_n) begin if

你可能感兴趣的:(笔记)