Bootloader的工作流程如图5所示。
NiosII C程序在运行之前需要做一些初始化工作。如果程序直接从Flash中运行,则Crt0.S是最先执行的代码;如果程序不是直接从Flash中运行,则Crt0.S是执行完Bootloader后最开始执行的代码。
运行完Bootloader后仍然要执行CrtO.s,但此时Crt0.s的流程和程序在Flash中直接运行的情况有一些区别:它没有初始化指令Cache,也不会企图去装载别的段,这些步骤已经在Boot—loader中完成。程序映像已经包含这些段,在搬移程序映像的同时也装载了相应的段(.rodata段,.rwdata段和.exceptions段)。程序映像中不包含.bss段和栈,所以仍然需要清.bss段,以及设置栈指针sp和全局指针gp。Bootloader没有读写存储器数据,因此没有初始化数据Cache,所以Crt0.S仍然要初始化数据Cache。如图6所示,当Bootloader读取到L时,L=0表示前面所有的程序记录已经处理完毕,这是最后的程序记录,所以就直接跳到地址A的地方执行。显然A必须是程序的入口地址。如果L=Oxffffffff(即一1),那么就忽略A并停机,这样,即使是一个只有FPGA配置数据而没有程序的EPCS也是安全的。当一个EPCS只有配置数据而没有程序时,sof2Flash会在配置数据的末尾增加4个字节的Oxff,使Bootloader不会有误动作。Bootloader的工作流程与Flash中相同,如图5所示。
4 软件编程
Altera公司提供给客户两种类型的函数:SimpleFlash Access(简单的Flash访问),以及Fine—GrainedFlash Access(细粒度Flash访问)。本文使用Fine—Grained Flash Access函数,虽然比Simple Flash Access复杂一些,但可以避免通常的跨块擦除问题。因为Flash是按照块(Block)组织起来的,通常一次擦除一整个块。如果写Flash的地址与Flash块的组织结构不吻合,比如跨越了Flash块的边缘,那么可能会擦除掉其余的数据。在使用Flash的读写函数时,头文件中要包含“sys/alt_Flash.h”和“sys/alt_Flash_dev.h”,这两个头文件提供了访问Flash器件的驱动接口。
使用之前要打开Flash。打开Flash,就像C程序打开硬盘中的数据文件一样。这里使用alt_Flash_open_dev()打开Flash,它返回一个句柄。例如:
其中,fd是alt_Flash_open_dev()返回的句柄;offset是相对Flash基地址的偏移量,是读操作中要读出数据第一个字节的地址;length是本次操作的数据长度,单位是字节。当返回值为时,表示读操作成功。
其中,fd是a1t_Flash_open_dev()返回的句柄;offset是相对Flash基地址的偏移量,是写操作中要写入的数据第一个字节的地址;length是本次操作的数据长度,单位是字节。当返回值为O时,表示写操作成功。
使用完后别忘记关闭该Flash,就像读写完硬盘中的数据文件后要关闭一样。其原型如下:
void alt_Flash_close_dev(alt_Flash_fd*fd);
其中,fd是alt_Flash_open_dev()返回的句柄。
编者注:Flash器件读写程序略。
结 语
目前,在FPGA的开发过程中,每次进行程序的调试和更新时都需要将产品与计算机直连,进行在线操作,这样就限制了程序调试和更新的空间范围。而基于FPGA的在应用编程技术就是为了打破这种限制而设计的。在应用编程技术对硬件要求极低,只要满足FPGA是Cy—clone系列,具有Flash器件,具有上下位机的通信能力,无需增加太多的硬件资源,都可以实现在应用编程。如果产品具有网络功能或无线功能,那么在恶劣的工业现场和野外可以免除到现场反复拆卸、调试的麻烦。对于保密产品,该项技术可以保护知识产权,通过网络更新产品的软硬件,增加了更新过程中被破解的难度。