在valid-ready握手协议传输的数据结构中,如果前向的数据流出现了时序违例,没办法收下来,具体说可能是setup出现违例的情况,通常在前端设计的过程中可以通过前向打拍valid的方式来解决forward 路径上的时序问题。
又因为valid需要与payload数据对齐,所以不仅需要打拍valid信号也需要打拍payload。因为这里仅仅是将数据打一拍,不考虑存储大量数据的问题所以我们不考虑使用fifo的结构来缓存数据。初步想法是使用两个reg根据控制信号的使能来存储数据和valid,因为不对反向的ready进行打拍,那么ready的传输就是直穿的情况。
那控制reg的使能信号应该如何产生,产生的依据是什么呢?
从正向的角度分析,什么时候允许数据存到reg中不会导致整个data数据通路出错呢?
第一种情况是:reg是空的没有存上一级的数据,那这时把数据存进去不会对数据通路造成任何的影响,就算下级没有准备好当前的reg不往后传即可。
第二种情况是:reg是有数据的里面存了上一级的数据,但是这一拍时data path是流动的下级正在取这一级的payload,那这时也可以把数据存进去。
所以问题的关键是如何找到一个flag来表示当前reg中数据的状态,它是有效的还是无效的。那其实这个flag就是valid信号的含义。关键点就是找到这个valid的control什么时候可以把valid_src信号传递给valid_dst。flag为高时表示尝试新载入了一个数据或者上一次的数据没有被下一级接收。表示现在的数据是有效的,只有数据无效了才能再重新更新payload。
那何时更新下一级valid呢,可以用相同的思想来判断这个问题,上一次的valid有没有被下一级接收或者这个时候是否可以将新的valid更新进去,可以通过接收端的ready来判断,接收端如果ready为1,那么下一个cycle后valid一定是可以更新进去的。所以valid_dst_en = ready_dst;又因为内部存在一个reg可以先更新一个数据所以valid_src有效的时候,也可以更新valid。所以valid_dst_en = valid_src | ready_dst;
assign valid_dst_en = valid_src | ready_dst;
always@(posedge aclk or negedge aresetn) begin
if(~aresetn)
i_valid_dst <= 1'b0;
else if(valid_dst_en)
i_valid_dst <= valid_src;
end
那payload的更新就存在也是存在2个情况:载入新数据当前数据无效和当前是满的但是下级正在拿现在这个数据就是握手的时候。
所以有
assign payload_en = ((valid_src & ~i_valid_dst)|(valid_src & i_valid_dst & ready_dst));
always@(posedge aclk )
if (payload_en)
payload_dst <= payload_src;
end
对于valid和ready信号的传递,当前打拍是否ready一是来自下级的ready判断二是当前的reg是空的,valid_dst从i_valid_dst打拍获得。使用了不带reset复位的dff节省功耗。
所以有
assign valid_dst = i_valid_dst;
assign ready_src = ready_dst | ~i_valid_dst;
至此根据valid_src和ready_dst得到的正向打拍逻辑。