对于分发模块设计,关键参考信号是EOP及快满信号AF1、AF2,参考EOP可以实现每次处理一个包,参考AF1、AF2信号可以决定相应的包该往哪个 FIFO中写入。分发算法为:FIFO1未满(AF1=0),数据包将写入FIFO1;如果FIFO1将满且FIFO2未满(AF1=1,且 AF2=0),则下一数据包将写入FIFO2;如果FIFO1、FIFO2都将满(AF1=1且AF2=1),则进入丢包状态。UseFifo1状态下数据包将写入FIFO1,UseFifo2状态下数据包将写入FIFO2,丢包状态下数据包被丢弃,提供丢包计数
使能 DropCountEnable。
状态机的进一步优化
1. 利用一位有效编码方式
如前所述,状态机的工作频率跟状态机中各个状态对应的不同转移条件的入线数目有关。如果到一个状态的转移条件相同但入线数非常多,其逻辑实现很可能并不复杂。在一位有效编码方式下,对于某个状态,如果其他所有状态经相同的转移条件到该状态,那么其逻辑实现可以很好地化简。
例4:一位有效编码方式下状态位s_State[n:0]中,
s_State[1] | s_State[2] | ... | s_State[n]=1与 s_State[0]=1等价,那么
next_State[0]=(s_State[0]&S) | (s_State[1]&T) | (s_State[2]&T) | ... | (s_State[n]) 可以化简为:
next_State[0]=(s_State[0]&S) | ((~s_State[0])&T),右端输入信号数目大大减少。
2. 利用寄存器的使能信号
多数FPGA或CPLD寄存器提供使能端,如果所有的状态机转移必须至少满足某个条件,那么这个条件可以通过使能信号连接实现,从而可以降低寄存器输入端的逻辑复杂度。如上例中不同状态间转移必须以EOP为1作为前提,因而可以将该信号作为使能信号来设计。
3. 结合所选FPGA或CPLD内部逻辑单元结构编写代码
以Xilinx FPGA为例,一个单元内2个4输入查找表及相关配置逻辑可以实现5个信号输入的最复杂的逻辑,或8~9个信号的简单逻辑(例如全与或者全或),延时为一级查找表及配置逻辑延时;如果将相邻单元的4个4输入查找表输出连接到一个4输入查找表,那么可以实现最复杂的6输入逻辑,此时需要两级查找表延时及相关配置逻辑延时。更复杂的逻辑需要更多的级连来实现。针对高速状态机的情况,可以尽量将状态寄存器输入端的逻辑来源控制在7个信号以内,从而自主控制查找表的级连级数,提高设计的工作频率。
4. 通过修改状态机
如果一个状态机达不到工作频率要求,则必须根据延时最大路径修改设计,通常的办法有:改变状态设置,添加新状态或删除某些状态,简化转移条件及单个状态连接的转移数目;修改转移条件设置,包括改变转移条件的组合,以及将复杂的逻辑改为分级经寄存器输出由寄存器信号再形成的逻辑,后者将会改变信号时序,因而可能需要改变状态设置。
5. 使用并行逻辑
很多情况下要参考的关键信号可能非常多,如果参考这些关键信号直接设计状态机所得到的结果可能很复杂,个别状态的出线或入线将会非常多,因而将降低工作频率。可以考虑通过设计并行逻辑来提供状态机的关键信号以及所需的中间结果,状态机负责维护并行逻辑以及产生数据处理的流程。并行逻辑应分级设计,级间为寄存器,从而减少寄存器到寄存器的延时。
该设计用于使用单一数据总线将FIFO1~4中的数据发送到4个数据通路上去,该设计中并行逻辑产生每次操作时的通路及 FIFO选择结果,状态机负责控制每次操作的流程:在“Idle”状态下,如果FIFO1~4中有数据包供读取,则进入“Schedule”状态;获得调度结果后“Schedule”经过一个“Wait”状态,然后进入“ReadData”状态读取数据,同时开始计数,计数到达所指定数值或者读到数据包尾时进入空闲状态“Idle”,依次循环下去。
流水线设计
流水线(Pipelining)设计是将一个时钟周期内执行的逻辑操作分成几步较小的操作,并在较高速时钟下完成。如果它的Tpd为T,则该电路最高时钟频率为1/T,而假设每部分的Tpd为T/3,则其时钟频率可提高到原来的3倍,因而单位时间内的数据流量可以达到原来的三倍。代价是输出信号相对于输入滞后3个周期,时序有所改变(输出信号的总延时一样,但数据吞吐量提高了),同时增加了寄存器资源,而FPGA具有丰富的寄存器资源。
本文所强调的通过减少寄存器间的逻辑延时来提高状态机的工作频率,与流水线设计的出发点一样,不同的是流水线所强调的是数据处理时的数据通路优化,而本文所强调的是状态机中控制逻辑的优化。