在FPGA设计中,我们通常采用的都是“自顶向下”的设计方法,即现有顶层设计,再有细节设计。比如先有整个项目的功能框图、数据流程图等,然后再细分功能到一级模块,每个一级模块再细分到二级、三级甚至更低级别的模块。除了每个模块的设计,如何把模块连接起来?也是一个很有趣且重要的话题,这就是我们通常说的内部模块接口。这里先介绍几种常见的内部模块接口。

AXI接口

目前xilinx或者intel提供的IP core中的接口越来越多的都支持AXI接口,这种接口是业界非常通用的接口,使用的频率也非常的高,关于这个接口的说明,网上有很多资料,本文不在这里介绍该接口相关的信息。

采用这种接口有什么好处呢?显然IP的移植性非常好,只要是使用AXI接口的设计,都可以直接调用这样的IP,不需要做任何接口上的修改,也不会出现对接口理解上的差异,确实很方便。尤其是你的模块需要和外部模块对接的时候,这里的外部可能是外部的客户、外部的合作伙伴等,标准的接口也能减少对接的沟通成本。

AXI接口笔者觉得也有一些缺点,接口相对比较复杂。如果我们的FPGA设计只是公司或者部门内使用,不需要对外,甚至都不需要重用的时候,那有没有一些更加简单的接口呢?这里重点介绍2种内部模块间通用接口,最后再说明这样接口的好处。

req-ack接口

先看时序图,这种接口通常是请求方有数据要发送之前,先发送一个req请求信号,同时保持数据不变,一直等待响应方的应答。当响应方处理完数据后,给一个ack应答信号,表示一次数据传送完成。

FPGA Interface Design

这种接口的应用场景是什么呢?它一般应用在低速、无缓存数据传输场景。当2个模块之间的接口传输数据的性能较低,且有相互依赖,就可以采用这类接口。从时序图可以看出,在req阶段,整个data是不会变化,直到有ack后,再发送下一个数据。数据的传输依赖请求和响应双方的配合,彼此牵制。另外,发送发等当前数据处理完成后,才会有一下次数据发送,所以这类场景无需数据缓存,比较节省资源,但是性能较低。

流式接口

先看时序图,该接口共有5个信号, data_vld(数据有效信号)、 data(数据本身)、 data_sop(表示数据开始)、 data_eop(表示数据结束)、 data_index(和data相关的其他信号,位宽和格式可以用户自定义,往往在data_sop = 1或者data_eop = 1的时候有效,或者在整个data_vld = 1期间保持不变)、 data_afull(数据反压信号,通知对端不要再发送data)。

FPGA Interface Design

这种接口信号,非常的像fifo的写接口信号,通过这种接口在发送数据的过程中,只要对端不反压就可以不停的发送。这种接口实现简单,模块之间高度解耦,性能较好。

也有人会想,用这样的私有接口,为什么不用标准axi_stream接口呢?确实这2种接口已经非常非常的相似了,唯一的不同就是反压的处理,私有接口是不反压的时候数据就可以无限制的发送,即发数据依赖data_afull = 0。但是axi_stream接口的vld和ready之间是没有相关关系的,协议规定不能相互依赖,这点这内部处理起来就稍稍麻烦点点。

另外即使afull = 1以后,一般都还可以继续发送2-3拍数据,时序处理起来也非常的简单。而axi_stream中的vld和ready之间是严格的时序关系,必须同时为1,数据才能正常发送,时序处理起来相对麻烦。

总结

当有对外的接口时,应该还是要采用业界标准的接口,但是模块内部的设计,还是要遵循设计简单、实用可靠、无依赖,性能高的基本原则。