对于添加SKP对,读指针如何才能知道要添加多少呢?因此读指针需要写指针去引导。在设计中,采用了断点保存和握手来解决。在SKP窗口出现和添加阀值标志有效时候,写指针在此时计算FIFO中的有效数据个数,根据FIFO中有效数据的个数与8的差距来决定wrptr_nxt所指向的下一个指针点,这就是写指针跳跃。并且在写时钟域把当前的写指针和下一个所指向的指针点保存起来。在弹性缓冲设计中,读指针永远落后于写指针。
图 10 写指针保存断点
3.2.2 握手
写指针在出现SKP窗口和SKP添加阀值触发的时候,发生了跳跃,并保存了断点,但这只是在写时钟域。由于读指针晚于写指针,因此采用握手来通知读时钟域何时添加SKP。如下图,当SKP窗口出现,并且添加阀值触发时,弹性缓冲保存了断点,并向读时钟域发起了请求(req),请求一直持续到读指针读到了断点的起始地址(start_rptr),此时,读指针读到了断点的起始地址,并向写时钟发送收到(ack)。当写时钟域收到读时钟域的ack信号,撤销req。读时钟域一旦读到了截止地址(end_ptr)自动撤销ack信号。在整个读时钟域的ack过程中,SKP对被添加。
图11 握手
3.2.3 输出控制
弹性缓冲FIFO读写控制的过程中,写先于读,首先根绝延迟要写到规定的要求,此时写有效读无效(定义为W1R0)。当达到规定的阀值之后,读写同时有效(W1R1)。等到写结束, 即一个包接收完毕,但是读不一定结束(W0R1),直至读到空,即所有数据已经同步到本地了(W0R0)表示此次任务结束。这种流程控制为了保持这个数据的完整性。
图 12 读写流程控制
USB协议中明确规定SKP对为2个连续的SKP symbol。根据8b10b原则,2个连续的SKP对的游程是相反的,并且SKP对的添加要符合8b10b3的规则。
中要求,在弹性缓冲下溢的时候,要添加一个EDB字符,并且显性的用下溢标志。如下图,在rx-g与rx-h之间,由于读快于写,导致了下溢。因此需要添加一个EDB字符,并使能一个时钟的下溢,并且置状态。
图 13 弹性缓冲下溢
PIPE3.0中要求,在弹性缓冲上溢的时候,丢掉一个数据,并且置状态。如下图rx-f、rx-g与rx-h,由于溢出,rx-g被丢弃,并且置状态。
图 14 弹性缓冲上溢
5.总结
本文通过分析弹性缓冲的作用与机制,采用异步时钟FIFO来设计弹性缓冲。并且根据USB3.0协议要求,提出了断点保存、指针跳跃与握手、指针屏蔽等方法来设计弹性缓冲。本设计充分考虑了PIPE 3.0标准的要求与实际需要,并且应用于工程中,实现了弹性缓冲补偿时钟的目的。