首页 > 代码库 > SATA主机协议的FPGA实现之物理层设计
SATA主机协议的FPGA实现之物理层设计
接上一篇文章,这里讲解SATA主机协议的物理层的实现过程。
下图是标准SATA协议文档中给出的物理层结构。可以看到它包含控制模块、时钟数据提取单元、同步字符源和同步字符检测模块以及模拟前端几个部分。其中,控制模块负责协调控制整个物理层的逻辑功能,并向上层协议提供控制信号、状态信息接口。时钟数据提取模块从串行数据流中提取时钟数据信息。同步字符源和同步字符检测两个模块负责串并/并串转换过程中的字节对齐。模拟前端包含高速差分数据发送接收器和OOB信号检测与生成电路。
上面这个图看上去比较复杂,但是如果仔细理解物理层协议,并对前一篇博客中提到的ALTGX收发器有一定认识之后,我们会发现其实这个收发器已经帮我们实现了时钟数据提取单元、同步字符源和同步字符检测模块以及模拟前端这几个部分,我们要做的就是如何配置这个收发器。另外,物理层还有一个重要的工作就是利用OOB(OUT OF BAND)信号实现设备的识别和上电初始化。因此,这里进一步划分物理层模块,得到下面这个物理层框图。整个物理层被划分为4个模块,OOB生成和检测、ALTGX收发器和物理层状态机。
首先说一下这个ALTGX收发器。关于这个收发器具体结构这些东西这里限于篇幅就不一一介绍,详细的介绍参考StatixIV器件手册,这里只是说明一下为什么会用上它。我们知道现在常见的FPGA的处理速度最高也只是在几百兆的水平,但是SATA1.0的串行数据流的传输速度已经达到了1.5Gbps,这样的速度不可能直接在FPGA里实现,而且SATA最终在传输线上传输的是差分信号,这里会有一个数字到模拟的过程,这也不是一般的FPGA能干的事。上面这两个问题其实并不只是实现SATA协议时会碰到,很多高速串行传输协议在使用FPGA实现时都会遇到,比如PCIe等。FPGA厂商为了满足对这种高速串行传输协议的支持,通常的做法都是在FPGA芯片中集成专用的硬件,这种专用硬件通常是一组满足高速数据传输速率要求的串行器/解串器(SERDES)以及模拟前端。这些集成的专用硬件通常是可以进行比较灵活的配置的,以使它们能满足对不同通信协议的支持。ALTERA公司的ALTGX收发器就属于这种,另外还有XILINX公司的RocketIO MGT等。ALTGX收发器可以通过QuartusII软件中的IP配置向导配置生成,这个配置过程参考“实现Altera器件中的SATA与SAS协议”一文。这篇文档中有详细的配置讲解,这里不再赘述。
接着说说这个OOB信号。带外信号,即OOB信号是物理层特有的一组信号,它通过在数据线上传输一组特定格式的信号实现。OOB信号有3个,分别是COMRESET、COMINIT和COMWAKE,其中COMRESET与COMINIT信号组成形式一样,只不过CONRESET由主机发出,而COMINIT由设备发出,它们的作用是在正常的通信链路没有建立之前主机进行SATA设备识别。关于这三种信号的组成形式请查阅SATA协议文档,这里主要说一下怎么实现这几个信号。上面关于ALTGX配置过程中我们应该注意到两个比较特殊的信号端口,一个是rx_signaldetect,一个是tx_forceelecidle,我们主要是通过控制这两个端口产生和读取OOB信号。查阅SATA文档之后我们知道OOB信号实际是由数据线上的突发信号和空闲周期组成的,突发信号周期比较好理解,在差分数据线上传输特定的原语(ALIGNp)即可,那空闲周期是什么意思呢?简单的理解就是不发送数据,那怎么就代表不发送数据呢?分析tx_forceelecidle这个端口的作用我们大概可以得到一些启示。这个端口的作用是将ALTGX中的发送器强制置为高阻,原来“高阻”才意味着没有数据发送,千万不要以为发送器发送“0”就是空闲周期了,“0”也代表一个数据!相反地,在接受端就比较好理解了,对于差分信号来说,在接受器端设置阈值电平检测电路就能区别差分数据线上“有或没有”信号,也就是区分突发周期和空闲周期,反映阈值检测结果的信号就是rx_signaldetect这个端口。这样就好理解OOB信号的具体实现了,当发送OOB信号时,通过置位或复位tx_forceelecidle端口来发送空闲周期和突发信号周期,接收设备端的OOB信号时,通过检测rx_signaldetect端口信号电平来确定当前设备发送的是空闲周期还是突发信号周期,当该端口被置位,说明接收到的是突发信号周期,否则是空闲周期。这里需要提醒一下的是这两个端口的信号都是高电平有效的,这意味着tx_forceelecidle为高电平时是空闲周期,而rx_signaldetect为低电平时为空闲周期。这一点一定要注意,这跟XILINX FPGA中的信号电平定义好像不太一样,我当时就在这里吃过亏。接下来的OOB生成和检测模块的实现就好办了,我们要做的工作就是实现能产生和检测一组符合OOB信号规定的高低电平电路就可以了。
最后说说这个物理层状态机。物理层状态机是整个物理层电路工作的大脑,它主要负责控制前面提到的三个模块,在上电时完成主机对SATA设备的识别和通信链路的建立。下面这个时序图就是上电时主机初始化的过程。首先是主机发送COMRESET信号,设备接收后响应COMINIT,主机接收之后发送COMWAKE,设备接收后再响应COMWAKE。四个OOB信号交互之后,主机就完成了SATA设备的识别。之后主机与设备之间通过ALIGNp原语进行速度协商并完成通信链路的建立,最后在通信链路建立之后以SYNCp保持。详细的描述参考文档中关于这部分的描述。
根据上面的时序图,我设计了以下的状态机,它的状态转移图如下图所示,供大家参考。
物理层状态机共有12个状态,状态转移图上图所示。主机上电后需要先对ALTGX收发器进行复位操作,使CDR能成功锁定到接收数据。当复位完成后,状态机能接收到power_rst_done信号,状态机进入发送COMRESET状态,使能OOB信号生成模块发送COMRESET信号。如果设备接收到COMRESET信号,设备会向主机发送COMINIT信号,主机接收到COMINIT信号后,状态机进入发送COMWAKE信号状态,使能发送模块发送COMWAKE信号,之后主机等待设备响应COMWAKE信号。主机在接到COMWAKE信号后会向设备发送一段时间D10.2数据,直到检测到设备发送的ALIGNp原语。这时主机存储ALIGNp原语,并以相同的速率返还给设备,完成速度协商。最后设备向主机发送SYNCp原语,主机在接收到该原语后进入Link_ready状态,表示通信链路已经建立。
最终整个物理层的实现情况如下图所示,这是用SignalTapII捕捉到的信号波形。第一个是OOB信号发送,即tx_forceelecidle端口控制信号,第二个是OOB信号接收,即rx_signaldetect端口信号,第三个是ALTGX接收转换后的16位并行数据,第四个是ALTGX发送的16位并行数据。
至此,物理层基本逻辑设计完成,下一篇文章将讲解链路层设计。