1 引言
IEEE1394是在计算机与外设直接进行高速数据传输的串行总线,因其具有传输速度高、支持即插即用、支持多达63个设备级联、以及设备间传输无需主机干预等特点,以至从其一出现就备受青睐。因IEEE 1394协议中的物理层可以在链路层不激活的情况下,作为中间节点而存在于1394网络中,物理层具有单独存在的意义,因此应用中就有纯物理层芯片、纯链路层芯片以及物理层和链路层合一的芯片三种类别。
由FPGA实现应用协议是目前最普遍的芯片设计方法。在用VHDL语言两个小FPGA芯片上分别设计出IEEE1394链路层和双端口的物理层后,把这两部分代码合并到一个更大容量的FPGA上,并改进为三端口,看似非常简单,但因FPGA电路的逻辑综合,引脚到寄存器之间的延时等方面发生了变化,代码移植发生了问题。
由于物理层部分的移植过程中有增加端口,出现的问题较多,而链路层基本没有变化,这里主要分析物理层的设计部分。
通过对改进电路设计.分析代码上的差别,从而阐述FPGA设计代码规范化的重要性和一些技巧的应用。
2 IEEE1394物理层介绍
2.1 IEEE1394总线协议框图
1394物理层的每个端口有两对差分信号TPA和TPB组成,其中TPA包含TPA+和TPA-两条信号线,TPB包含TPB+和TPB-两条信号线,物理层通过判断每个端口在自己发送的信号与对方发送的信号产生的线状态来判别总线的工作状态,当进人接收或发送状态时,就进行数据处理,并与链路层进行数据交换。
1394链路层和物理层使用统一的系统时钟,以保证数据的同步。链路层对物理层的总线申请和寄存器操作是单向的,由LREQ来控制。而数据则是双向的,由控制信号决定数据的传输。链路层要实现发送数据的打包操作和接收到的数据的校验判别及解包操作。
1394事务层则由具体的设备程序处理,其与链路层之间交换的是已通过校验的有效数据包。
2.2 IEEE1394物理层的工作流程
1394物理层的每个设备没有固定的节点号,是在使用时通过配置产生的节点号,设备间再通过这个节点号来识别数据的源与目标。其配置流程如下:
总线复位由设备上电、设备插拔、状态超时、软件控制等产生,它通过发送一个超过166us的BUS_RESET信号,保证所有的节点都能进入复位状态。
树标识是从叶子节点开始,按端口号由低到高的原则,通过子握手和父握手信号协商,把整个网络各端口的父子关系确定下来,也就是确定了整个网络的TOP结构(树结构)。
自标识也是从叶子节点开始的,通过逐一向总线发送自标识包,来表明自己的身份,节点号从0开始,已经完成自标识的进人正常仲裁状态,没有完成自标识的,每收到一个自标识包,其节点号增l,这样当最后一个节点(即根节点)完成自标识包发送后,网络上的每个节点都有一个唯一标识自己的节点号,这时自标识过程完成,所有节点都进入正常仲裁状态。
正常仲裁则通过判断总线状态和链路层的总线请求,进行总线权的仲裁,包括优先权仲裁、公平仲裁等,只有通过仲裁获得总线权的节点才可以向网络发送数据。
2.3 IEEE1394物理层的数据收发
在自标识完成后,获得1394总线权的节点进入数据发送状态,而没有获得总线权的节点进入接收与转发状态。数据的发送比较简单,直接向所有已连接的端口输出信号即可,而接收则不同,一方面要从接收端口接收数据,另一方面要向其它端口转发接收的数据,而这个转发的数据,需要经过内部时钟同步才能转发出去。这样就会有转发延时的问题,考虑到总线上可挂接63个节点,因此,这个延时还不能太大,否则将影响整个1394总线权的仲裁,而导致系统崩溃。
3 移植前后的主要差异
3.1 芯片型号变化
由两片EP1C6T144C8合为一片EP1C12Q240C8,总的I/O引脚减少,单一芯片的逻辑单元数加大,电路综合变得复杂,综合效果没有芯片分开时好,另外合到一个芯片后,原本来自1394信号电缆的干扰基本只与物理层相关,现在更渗透到了链路层,反之,来自应用层的干扰原本主要影响链路层,现在却影响到了物理层。
3.2 端口数增加
1394端口由2端口增加到3端口,信号数增加了12根,I/O资源变少,状态判别逻辑变复杂,与信号直接相关的逻辑单元平均距离变长,也就是说信号延时变长。
3.3 链路层与物理层程序合一
程序合并后,调试难度增加,一是编译时间加长,分成两个单独芯片进行电路综合的总时间,要比合到一起后的时间短1/3;二是不能采取与标准LLC层、PHY层芯片分别调试的方式来简化设计调试过程,因而导致问题更难定位。
4 移植过程中问题的解决
4.1 接收FIFO的处理
在移植前,是一个2端口的方案,移植后变成了3端口,按照原设计,先利用接收端口号(PORT)选择相应的STRB和DATA输人,再利用这个信号异或产生时钟信号,接一个FIFO(见图2),但运行中问题出现了,不是所有时间所有端口都能正常接收。
图2 接收FIFO
实际上,扩充到3端口后,各引脚不是排列在FPGA的同一ROW或COLUMN,在电路综合中,不同端口到FIFO的输入路径长度和方式都不一致,同时因为内部时钟频率并不比接收时钟频率高,不能在FIFO前对接收信号进行同步处理,只能使用组合逻辑,使得组合逻辑产生的毛刺影响了数据的有效性。
通过使用冗余的办法,把原来的共用FIFO改为每个端口一个接收FIFO(见图3),这样在每个端口能以最短路径和很少的组合逻辑接到FIFO,而3个FIFO的输出再由接收端口号来控制,此时FIFO的输出是通过内部时钟同步,这样就解决了问题。
图3 使用冗余后每端口接收FIFO
使用双时钟异步FIFO时,要注意Empty和Full输出的时钟对应问题,在本设计中,接收FIFO的接收时钟是由信号XOR产生的,是临时的,当接收数据停止时,时钟不存在了,对应的Empty和Full失去了赖以动作的时钟源,会一直保持下去,此时只有通过异步清除的办法才能清除这些信号。因为这个问题的存在,会出现数据已经读完了,但Empty信号仍保持为低的情况,如果依赖Empty做判断,就会出现死循环。
4.2 帧结束的判别
1394在接收数据帧的结束时,根据对方是否有连续数据帧发送,将分别收到DATA_PREFIX(10)或DATA_END(01)两种情况,其再生的时钟信号都为1,且最短的帧结束信号保持时间为4个时钟周期。这两个信号也会出现在数据中,但不会保持超过1个时钟周期。这样就可以利用DATA_PREFIX或DATA_END信号的保持时间来判断帧结束。移植前是通过判断FIFO空来处理的,因FIFO空与信号再生的时钟相关,在帧结束时,信号再生的时钟停止,需要用计数器进行辅助处理。因此移植后进行了改进。
在进行计数器设计时,一般采用同步清除的方式,这样不至于因信号上一个小毛刺而导致计数器被清0,但在这个帧结束的判别中,却不可以采用同步清除方式,因为接收的信号时钟频率虽和内部的时钟频率相同,但相位和占空比有差异,在用内部时钟对接收到的信号进行计数时,会发生连续的数据信号被错误判断而计数器未被清除,导致提早判定为帧结束。
-- RecvClk由Strb与Data异或产生
-- DATA_PREFLX和DATA_END异或产生的RecvClk皆为1
process(Pclk,RecvClk)
begin
-- 出现RecvClk为低,表示数据有变化,帧结束判别计数器清零
if RecvClk= 0 then
RecvEndCheekCount<=0;
elsif Pclk'event and Pclk='1' then
-- 开始接收后,进行接收状态计算器
if RecvStartFlag='1' then
-- 收到RX_DATA_PREFIX或RX_DATA_END且保持3个周期,则帧接收结束
if RecvEndCheekCount/=3 then
RecvEndCheckCout<=RecvEndCheckCount+1;
end if;
else
RecvEndCheckCount<=0;
end if;
end if;
end process;
4.3 计数器处理
1394总线配置过程中有相当多的时间判别,如总线复位时间、复位等待时间、状态超时等,都要使用计数器来解决。计数器有相应的计数条件和清零条件,而这些条件是与状态机、接收到的端口状态等相关的。
对于计数器的清零,有异步清零和同步清零,异步清零要求清零控制信号绝对的干净,因为一个小的毛刺,都会导致计数器归零,除了非常特别的情况,一般不用异步清除的计数器。
计数器的判别有用大于(小于)和等于(不等于)两种方式,从理论分析来讲,用前者应该比较保险,计数过头了也同样能判别成功。而实际上,因为大于(小于)的判别所消耗的逻辑单元要多,处理起来变得复杂,在计数值比较大时,反而容易出现问题,测试中发现,采样等于(不等于)的比较方法要优于大于(小于)的比较方法。为了得到比较好的判断结果,可以利用一些技巧,比如判断连续的两个值,这样误判的几率就小很多。
signal TimerCount:integer range 0 to 1 5;
signal TimeOutFlag:std_logic;
process(Sclk)
begin
if(Sclk'event and Sclk='1')then
if(CountEnable='1') then
-- 当等于14或15时,置超时标志,电路综合时bit0未用到
if(TimerCount=14 or TimerCount=15)then
TimeOutFlag<='1';
else
TimerCount<=TimerCount+1;
end if;
else
TimeOutFlag<= 0;
TimerCount<=0;
end if;
end if;
end process;
4.4 逻辑锁的应用
链路层(LEe)程序和物理层(PHY)程序,除了接口外,基本是独立的,但在FPGA内部,由于资源有限,而且使用同一全局时钟信号,在线路综合时就出现了逻辑单元交叉的现象,这样两层之间的信号影响就加大。另外,各端口间的电路干扰也是存在的
为了减少这个相互之间的干扰,使用QUARTUS软件所带的逻辑锁(Logic-Lock)功能进行处理。所谓逻辑锁,就是在进行综合布线之前,先把FPGA的内部逻辑单元进行预分配,把各模块限制在一定范围内,当QUARTUS软件进行综合布线处理的时候,它会首先在预分配的逻辑单元内进行相应模块的布线处理。
实践证明,使用逻辑锁能有效地减少模块间的相互影响,没使用逻辑锁前,链路层的中断屏蔽寄存器被打开,应用层开始处理中断数据,有时会出现接收的数据错误,甚至导致1394总线复位的现象,而使用逻辑锁以后,这个问题就不存在了。不过逻辑锁的应用要注意一定的规则,一是要判断要加锁的模块大致逻辑单元数,逻辑锁分配的单元数要有一定的余量,以保证模块在综合布线是不致线路太复杂;二是模块尽量与其相应的I/O口靠近,减少布线的长度;三是有使用RAM或FIFO的模块,一定要包含对应的RAM单元。
5 总结
FPGA的芯片代码设计不同于CPU、DSP之类的代码设计,CPU、DSP类的代码设计,只要芯片引脚性能相同,程序移植过去就能正常工作,而FPGA的设计则不同,进行代码移植后,其内部电路综合结果将因芯片的逻辑单元布局、使用的编译器版本等很多相关因素而发生较大的变化,因此,FPGA代码的移植相对要难得多。只有按照一定的规则进行代码优化,而不是依赖于芯片本身的特性来拼凑实现所需功能,才能编制一个可移植的FPGA代码。
时序同步是FPGA设计的关键,能用时序逻辑实现的,尽量采用时序逻辑,能同步处理的就不用异步处理。时序逻辑能有效地消除因组合电路门延迟产生的毛刺对逻辑的影响,当然这里有个前提条件是两级时序电路之间的组合电路门延迟不能太大,因为延迟太大时,在时钟沿到来时,组合逻辑的输出仍是不稳定的,时序锁存后会出错,因而时序电路两级中问的组合电路是影响速度的关键,例如用相等判别要比判别大于(小于)速度快。
在必要的时候,用空间换时间的冗余设计是很有效的,如果通过冗余,能大大降低逻辑的复杂程度,就能提高信号处理速度和增强电路的稳定性。如前面的单FIFO改成三FIFO设计,就是利用了这个思路,把组合逻辑部分简化了,解决了干扰问题。多时钟系统中,使用FIFO来解决同步问题是最好的办法之一,尤其是两个时钟频率相差不大的情况,用FIFO来同步可能是唯一的办法。不过,使用异步FIFO,输入和输出之间会有8个时钟(输入时钟)的延迟,对应与之相关的电路,要考虑这个延迟,否则,控制信号和数据信号不协调,同样会工作不正常。
在FPGA设计中,除了芯片差异和程序设计不同影响最终结果外,编译系统的差异,也会影响最终结果。这个是与基于指令集的CPU、DSP等完全不同的。不同的编译系统,在进行电路综合是采用不同的算法进行优化处理,同样一个功能,编译结果可能完全不同,如使用逻辑门的数量、信号的路径等都有差别,因为不同综合结果电路中延迟的差异,会导致性能和功能上的差异。因此,在电路设计中要尽量使用系统元件库和电路模块化的处理,另外,要合理利用一些编译系统的功能,对电路进行一下优化、抑制处理,尤其是象逻辑锁这样的工具,它能使得一个内部模块象一个独立的芯片一样包含在电路中,对电路的综合效果非常有好处。
文章评论(0条评论)
登录后参与讨论