针对ready的反向打拍,如果单纯的将ready往后延一拍,有可能会造成数据丢失的情况。
例如:
假设valid和ready都是一个cycle周期的脉冲时,此时数据与valid一起传输。当经过了反向打拍后,ready晚于valid一拍,在source端看到的情况就是valid-ready没有握手成功。
所以在设计的时候与forward-path类似,在module中会有一个reg负责存储payload,另一个flag用来表示payload是否被缓存了。当ready信号assert或者是deassert的时候是需要考虑缓存一下payload数据的。
所以有以下的考虑,当valid有效的时候表示正在尝试发数据,ready为低的时候,下游无法接受数据那数据就需要缓存下来,当buffer的flag状态是full的时候不能更新数据。因为这个flag是如果有数据缓存则拉高,数据被下游接受则拉低。buffer_full是buffer的flag信号,第0位作为控制信号。
assign buffer_en = valid_src & ~buffer_full[0] & ~ready_dst;
always@(posedge aclk)
begin
if(buffer_en)
payload_reg <= payload_src;
end
更新buffer_full的状态需要根据buffer_en打一拍与payload_reg对齐。加上ready_dst的是为了不需要缓冲data的时候更新buffer_full的状态。
assign buffer_full_en = buffer_en | ready_dst ;
alwasy@(posedge aclk or negedge aresetn)
begin
if(~aresetn)
buffer_full <= {NUM_SEL_LINES+1{1'b0}};
else if(buffer_full_en)
buffer_full <= {NUM_SEL_LINES+1{buffer_en}};
end
所以ready_src的来源从控制信号buffer_full[0]来即可。
assign ready_src = ~buffer_full[0];
valid的传输直传加上buffer缓存的状态;
assign valid_dst = valid_src | buffer_full[0];
parameter NUM_SEL_LINES = (PAYLD_WIDTH + 7) / 8; 整数部分
parameter REM_SEL_LINE = (((PAYLD_WIDTH)-1)%8)+1; 小数部分
最后的mux选择输出的时候,为了防止buffer_full[0]驱动过多的MUX,所以做了分8个bit一组的操作,可能工艺先进了这个地方可以不用这个方式。
always@(buffer_full or payload_reg or payload_src)
begin : p_payload_mux
integer i;
integer j;
integer base;
base = 0;
for(i=1; i<NUM_SEL_LINES;i=i+1)
begin
for(j=base;j<base+8; j=j+1)
payload_dst[j]=(buffer_full[i])? payload_reg[j] : payload_src[j]);
base = 8*i;
end
for(j=base; j<base+REM_SEL_LINE; j=j+1)
payload_dst[j] = buffer_full[NUM_SEL_LINES] ? payload_reg[j] : payload_src[j];
end