原创 部分可重构计算平台设计构想

2007-3-10 23:46 1939 5 5 分类: FPGA/CPLD

概述与分析


现在很多年轻人喜欢用MP3播放器放音乐,这种播放器体积很小,里面只包含一个解码芯片;在它出现之前,我们通常是在PC上,用winamp等软件播放MP3。这种差别正好反映了两种计算模式的不同:前者的专用解码芯片是硬件模式(或者称ASIC模式),后者即软件模式。硬件模式专为特定的应用进行设计与优化,具有较之软件模式高得多的执行速度和更低的功耗,但是设计的周期长,功能不可能轻易改变,即缺少灵活性;软件模式在通用处理器上编程执行,执行速度比较慢,功耗大,但是软件开发过程相对硬件设计要简单得多,而且改变源程序就可以改变功能,因此更加灵活。


通过以上分析容易看出,硬件模式和软件模式有各自的优势,因此它们在各自不同的领域都发挥得很好。然而,正如爱因斯坦晚年研究统一场一样,人类总是希望找到单一的方法就解决目前的所有问题。于是自然而然地——研究者也在寻求一个途径以综合软硬件各自的优势——既能获得很高的计算性能,又能在很短的时间内设计实现并且易于改变功能。


可编程逻辑芯片(广义的概念,包括各种CPLD、FPGA和类似的器件),以及不断发展的IP核技术,在一定程度上适应了上述的需求。下面以FPGA为例,从性能和设计两方面分析。为了利于区分,如无说明,本文中硬件模式均特指ASIC芯片,软件模式指通用处理器,FPGA作为可编程逻辑芯片的特例来叙述。


ASIC包括前端设计和后端设计两个部分,因为现在硬件设计者经常利用FPGA验证ASIC设计的正确性,所以前端设计几乎可以和FPGA设计等价;后端设计特指芯片的物理布局布线。这样一来,因为少掉了物理优化,FPGA不可能达到像ASIC那样高的运行频率和那样低的功耗,除此之外ASIC的优势都被FPGA继承下来,也就是说FPGA的性能介于软硬件模式之间。

FPGA设计一般采用“自顶向下”的方法,即在系统设计的最初,把系统划分为若干模块;划分原则是使得每个模块有较独立的功能,模块之间的耦合尽可能小(通常表现为相互通信尽量简单)。划分之后,再分别实现每个模块,最后把模块像搭积木似的组装起来。某些模块可能已经有现成的,即所谓IP核心。可见系统设计的难点是模块的实现,那么IP核的思想有利于模块的重复使用,提高了设计的效率。再配合成熟的EDA工具作为设计流程的工具链,可以说FPGA的设计已经相当容易。即便如此,这个“组装”的过程,相对使用高级语言的软件编程,仍然是难于设计和缺乏灵活性的。如果把IP核心拿来和编程作对比,我们观察到IP的思想和软件的静态链接库很相似。按照这个思路分析,如果我们希望进一步简化系统的设计,最好把IP核心封装成软件可以调用的库的形式。库又分为静态库和动态库,动态库允许在程序执行时按需加载和卸载,这相当于FPGA在运行的时候,IP核心可以动态的载入和卸出,当然前提是并不破坏原有程序和数据,而目前的EDA工具不可能实现类似的功能。为了进一步提高硬件计算的灵活性,最好使用动态库。把IP核心封装成动态库,是可重构计算平台最为核心的思想。本文不严格区分IP核心和其封装库的概念。

系统设计难点

可重构计算平台集中了当今处理器设计思想的精华。在平台的设计当中要注意尽可能使用,或某种程度简化地使用业界成熟的技术与协议,这样一方面缩短我们的开发周期,另外还有利于和其他异构系统集成。为了保证我们设计的平台的执行速度,首先要知道,硬件计算的加速度从何处来。这主要包括以下几个方面:(请补充)

  1. 专用器件。例如乘累加操作是DSP中的常用操作,在一般的RISC处理器上实现需要用软件实现乘法,再进行相加。如果设计专用乘累加的IP核心,完全可以在一个周期内实现该操作。根据Amdahl定律,专用做能够提高运行速度。
  2. 处理器并行。
  3. 处理器资源重复。
以上各个方面都必须在平台中有所体现,才能够保证可重构计算的速度优势。因此针对以上方面,设计中要考虑到:(序号与上面一一对应)

  1. 支持IP核心的封装。可以封装成各种共享库的形式,如何支持动态的加载和卸载库,这就要求主机能够高效且灵活的控制和使用FPGA资源。
  2. 包括所有并行体系结构的问题。重点是并行编程模型的构造,要求不对现有高级语言进行大的修改,但是还能够保证支持多个硬件任务可以并行执行;硬件资源有限,如果FPGA资源不足,软件是否可以替代硬件的功能,这个替代过程是否对程序员透明。
  3. 并行处理器之间的同步和通信。多处理机系统编程的复杂性,历来都不和处理机的数目成比例。
  4. FPGA资源调度引出的额外开销。
下面就针对以上难点提出一些设想。

编程模型

可重构计算平台的编程工具链包括:

  • IP核心设计工具,现有EDA工具已经可以实现IP设计;
  • IP封装工具,该工具用于软件和硬件之间接口,涉及平台的核心技术,需要我们自己实现;
  • 高级语言集成开发工具,由于平台对语言有一些新的要求,所以必须对现有工具进行扩充,但是自己开发的难度很大,因此可以参考SystemC的设计思想,不改变语言本身,而是利用特殊的宏来连接我们定制的库;
  • 调试工具,目前在高级语言的IDE调试底层的IP核是很困难的,因此要求IP设计时在EDA工具中进行完整的测试,保证其功能的正确,此外IP封装工具需要支持响应测试向量,并提供输出。
调用IP封装对程序员透明,即程序员并不知道硬件运行的细节,也不知道硬件任务的并行性如何,完全由平台调度。但是软硬件任务间及硬件任务相互间的同步与通信是显式的,可以由程序员控制,具体机制比较复杂在后面专门介绍。但为了减少同步的复杂度,IP封装内部应当避免使用全局变量,而完全使用局部变量;平台不提供共享变量的互斥机制,如果用到互斥机制,需要由主机利用软件实现。这也是本平台设计的思想,尽量减轻硬件实现的负担;FPGA内部包含两个处理器,其中一个作为主机处理器,与一般PC的CPU用法无异,运行OS和应用程序,另外一个作为硬件任务专用处理器,负责加载配置数据、调度等等。

IP调试

总线激励

调用接口


我们把IP核封装成函数的形式,利于调用;与此同时,从外部看来,封装成的函数与软件链接库函数并没有差别,因此程序员可以同等地对待它们。一个函数的基本组成部分有函数名、函数体、参数和返回值。函数名唯一性地指代了不同的IP核心,当然这其中可能要使用不同的命名空间,以区分不同的包。函数体是真正实现功能的部分,在这里应该就是指IP核心本身,当然还要包括一些封装所要用到的代码。函数参数是IP核心的输入值,可以接受形参,也可以接受实参。


我认为IP核心本身及其封装并不需要包括实参的互斥机制,这在大多数时间可以保证结果的正确性,而且节约了硬件资源和执行时间。但是前头提到过FPGA上同时运行多个处理器,因此共享变量并发地读写有可能使得执行结果出错,那么程序员在必要的时候应该显式声明临界区域。函数的返回值可以用来传递IP核的输出,但是这样做很不妥当。因为通用处理器的程序是串行执行的,主机调用一个IP核,实际上是调用封装它的函数,那么只有等到这个函数返回以后,主机程序才能继续运行下去。如此一来意味着执行IP核心的时候,主机的CPU就停滞了(虽然分时系统会把CPU资源分配给其他线程,但是很显然这种停滞的开销依然不能接受)。所以调用封装函数以后,我们让调度器同时做两件事,一个是启动IP核心,开始执行硬件任务,另一个就让函数立即返回值,这个是本平台的关键技术。主机收到返回值以后,可以调用其他IP或者执行软件任务,因为该函数不等硬件任务执行就返回,所以函数执行时间远远小于硬件执行时间,也就实现了多个硬件任务之间及软硬件任务之间的时间并行。函数返回的取值有可能包括 enum{ SUCCESS, FAILURE, WAITING} 当中的值,SUCCESS表示调度成功(只是调度,执行有可能失败);FAILURE表示所请求的IP核心永远也不可能被调度,这是个彻底失败的返回值,但是我们不能让整个应用崩溃,此时主机收到FAILURE应当利用软件计算来代替硬件任务;WAITING表示未来某个时间可以调度,当然如果调度器设计得好,那么能够返回具体要等待的时间,反之就不能给出精确的时间,但是至少也应该有一个量级,总而言之,主机可以据此判断是否等待FPGA资源或是直接用软件代替。


当然我们还要考虑到,IP核的输出肯定是要返回的,这个可以从函数的输入实参返回。前面提到主机不等IP核执行结束就继续运行其他程序了,那么IP核执行结束的消息如何通知主机呢?其实这里又是给程序员留了一个灵活的接口,因为有些应用不需要返回值,例如MP3,处理完的数据就直接交给D/A转换器输出,而不需要主机的干涉。但是有些应用又需要通知主机,对于这种情况,调用IP的时候需要传递一个回调函数的指针,此时IP任务结束后调度器会给主机发中断。函数有一个可重入的概念,即这个函数在没有返回的时候就可以再次被调用,而不破坏原先的结果。最典型的例子是递归调用。这个问题对于软件编程并不难解决,只要让每次调用对应不同的内存堆即可。但是硬件任务允许并行执行,而其内部是一个硬件核心,因此不可能递归调用主机程序。也就是说多次调用同一个函数,每次都应该在FPGA上为其分配资源,让该函数并行执行。


硬件实现模型

IP核心的实现方法不属于本文讨论的范畴。但是平台对IP核心的实现有一定的约束。一般商品化的IP核被综合到寄存器级的网表。应用到FPGA之前,还需要根据用户约束,继续综合到门级,然后再进行布局布线。这个过程应该在EDA工具上静态完成,交给调度器的是已经完成的可以直接被FPGA使用的配置数据。设计者完全从头用FPGA设计工具生成的器件,其中可能包括一些特殊的资源,如硬件乘法器、内存块、高速IO等等。这些资源在FPGA上并非均匀地分布,所以在加载这一类IP核心的时候,只能锁定在某些有限的区域。如果IP核心需要更多的RAM空间,FPGA内部的RAM可能无法满足要求,一个容易的方案是采用FPGA外部扩展SRAM或者DRAM。DRAM容量大,但是需要复杂的控制器,那么可以把这个控制器固定在FPGA内部,供所有IP核使用;或者在FPGA外部提供一条总线,把DRAM控制器和FPGA都挂在总线上,这同时也有利于扩展多FPGA。这个方案在总线技术一节讨论。

同步与通信协议

主机和硬件任务之间可能要传输数据,这部分的协议参考前面硬件任务调用一节。硬件任务之间可能要传输数据,根据通信关系,一个硬件任务被分为无通信、和其他一个通信、和其他多个通信,三种情况。如果是一对一的通信,可以使用双端口内存缓冲区法。传输数据比较多的时候,性能有优势,缺点是需要专用内存,控制复杂。但是有一个特殊的用法,FPGA内部有Block RAM(块内存),块内存经常被IP核用作存储器。所谓硬件任务的卸载,实质上和硬盘上数据删除很相似,即数据其实没有真的被擦除,只是标记该区域无用。被标记为无用的FPGA资源就可以重新另一个IP核使用,但是这个资源区域包含的块内存的内容并不一定被初始化(可以控制),这样一来,后一个任务就可以共享前一个任务的块内存,实际上相当于之前的任务把数据传递给后一个任务。或者主机把内存读出,作为前一个任务的输出结果,返回给软件程序。如果多个IP核心按照流水线方式工作,可以使用直接连接法,简单而且效率高,但是不推荐这样使用,因为这样几个强耦合的IP核组成一个大的任务更加合适。设计硬件任务有一个原则,要让任务之间的通信尽可能得小,也就是强耦合的任务应该合并,否则通信会有开销,主机调度多个任务也会产生额外开销。还有就是总线方式,也是推荐的通信方式。其优势有:设计一个管理层,用来协调数据传输,并可以提供一个通用的总线接口,简化IP核通信接口的设计。协议在总线技术一节介绍。

总线技术


FPGA内部各模块间通信应该采用片上总线技术,业界有完备且经过实践验证的协议。使用片上总线的优点有:因为协议规定了数据通路和控制信号,能够容易解决硬件任务互通信,容易解决总线争用。总线上各设备是对等的,任何一个硬件任务都可以成为总线的主控设备,也就是解决了硬件任务发消息的问题。发送数据可以是单播,也可以是多播。成熟的协议有ABUS和xx,前者适合ARM处理器(CPU核心),后者适合PowerPC。


另一个重要问题是FPGA如何和主机通信,一个主机能够带几个FPGA。当然理想的情况是越多越好,目前一些商业化产品,八个或者十六个FPGA的硬件计算平台都有(不是可重构平台)。从可重构技术的角度来看,因为其实运行的硬件任务能够被替换出来,所以并非同时加载全部IP核,需要的FPGA数量应该较小些。但是作为可扩充的系统,至少要有带4~8颗FPGA的能力。这个数量目前还不能确定,因为要作一些实验,考虑主机CPU的负载能力,主机也要运行很多软件任务,太多的FPGA会使主机过载。


因为CPU的IO有限,所以多个FPGA不可能同时连接到CPU上。那么它们之间应该有一个总线协议。最容易想到的是PCI或者更新的PCI-e,使用总线通信的好处和前面类似,就不再赘述,但是我们还要考虑到,采用成熟的片外总线,非常有利于产品的商品化,还有利于用户和原有的系统集成。PCI-e出现的晚,先进一些,传输率高,占用IO少(数据线少),实现也应该复杂一些,具体没有调研。


这样一来,主机CPU和每个FPGA都应该一个PCI控制器。PC的控制器放在主板的芯片组里,但是FPGA的控制器放在哪里,也是值得思考的问题。按照常规的思路,因为FPGA的资源非常多,把控制器放在FPGA内部是没有问题的,但是这样做并不妥。原因有:一个固定的、占用很多资源的控制器,必然使得剩余的FPGA资源分布更加不平衡;控制器是系统必备的,放在FPGA内部有潜在的危险,在用户配置FPGA的时候把控制器破坏,使整个系统崩溃。相反的,如果在FPGA外部加一个专用的控制器(相当于PC的北桥),除了避免以上问题,还能获得额外的利益:专用控制器相当于MAC层,也就是说改变专用控制器的功能,就可以适应更多的接口,除了PCI以外,还可以让FPGA卡通过USB或者FireWire等和主机连接。


调度器

从前面的分析可以看出来,整个设计尽量采用业界成熟的协议和标准,大多数的部分容易实现,我们需要花最多功夫设计的就是调度器。调度器是主机和FPGA软硬件之间的接口。这里再把前面提到的功能总结到一起:

  • 接受主机的调用。
  • 熟悉FPGA结构,能够分析资源约束。
  • 根据目前资源的使用情况,把IP核放到最合适的地方(次优)。
  • IP核加载到FPGA的时间很长,甚至可能比运行时间长,因此要减小开销。
  • 调度器使用CPU资源,当CPU空闲且FPGA资源足够的时候,预加载IP核。原理和cache类似,都是为了减小命中所需资源时的开销。但是设计cache的依据是局部性原理,而硬件任务的粒度大得多,局部性原理不再适用,这方面的机制仍需要研究。

平台设计步骤

本文只是平台设计的一个设想,但是我们目前不具备硬件条件,现有的主板只有一块FPGA,内含两个CPU核心。但是也可以变通的,把其中一个CPU作为主机,实现平台的原型。实现步骤:

  1. Selector,查找空闲区域。要求能够理解IP核对资源的约束,列出FPGA上允许该IP核的区域。重点是设计一个高效的数据结构,以便尽快的找到空闲空间。
  2. Scheduler,调度器,根据IP核占用资源、运行时间等参数,为硬件任务选择合适的空间。其目标是使得未来产生的任务的阻塞尽可能少。
  3. Loader,加载FPGA配置文件。按照指定坐标,把配置数据写入FPGA。
  4. BRAM Controller,块内存控制器,供主机初始化和读写FPGA上块内存。
  5. Macro,片上总线宏,给IP核的总线接口。
  6. PCI Controller,PCI总线控制器。
  7. Interrupt Controller,IP核产生中断,该控制器产生相应的中断向量,主机响应后协调。
例子,简单wav音频处理器,主机读取*.wav文件,交给均衡、滤波等模块处理,再送到AC97设备输出。 bmp或jpeg图片显示,主机读取文件,交给解码单元,再由调色板映射之后,利用标准VGA输出。
PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
5
关闭 站长推荐上一条 /3 下一条