4.1并行flash配置控制器
Nios II应用常常把Nios II 程序和FPGA配置数据都存放在flash中。这就需要一个配置控制器来驱动flash输出配置数据完成FPGA的配置。配置控制器可以用一片CPLD来实现。Flash除了可以存贮FPGA配置数据和Nios II程序外还可以存贮其它数据(比如只读文件系统)。Flash中的配置数据区还可以分为两个区,一个用于用户逻辑,另一个用于出厂逻辑。当用户逻辑配置失败后,就会自动使用出厂逻辑,保证任何时候都有一个配置可以工作。另外,配置控制器还可以接收来自Nios II 的重配置请求,并驱动FPGA重新配置,完成FPGA的现场升级。Stratix开发板的配置控制安排偏移量为0的地方存放Nios II程序,而FPGA用户配置逻辑从偏移量0x600000开始,出厂配置则从偏移量0x700000开始。
Stratix开发板的并行flash配置控制器其实是一个地址序列生成器,地址生成器的输入时钟是板上时钟的4分频(比如,板上的晶振时钟是50MHz,则地址生成器的时钟就是12.5MHz)。上电的时候,由上电复位芯片提供的复位信号复位,地址生成器初始化为用户逻辑的配置数据的偏移量(比如Stratix板是0x600000),然后开始计数并驱动地址由低往高增长,使flash送出对应地址的配置数据。配置控制器监测FPGA的config_done信号,一旦发现FPGA配置完成就停止计数,并置flash的地址和其它控制线为高阻,以免影响Nios II对flash的操作。FPGA配置完成后,内部逻辑开始生效,复位Nios II,Nios II开始从reset地址执行程序。
4.2 直接在Flash中运行程序
嵌入式应用有时希望程序能够直接在flash中运行,以节约RAM空间,降低成本。为了使程序直接在flash中运行,可以在SOPC builder中设置reset地址在flash中,连接程序的时候可以指定程序的.TEXT段和.RODATA段存放在flash中,而让.RWDATA和堆栈放在RAM中(这2个段都是可读写的,不能放在flash中)。同时还可以在SOPC builder中指定exception地址到flash中,也可以节约一点RAM空间。由于最后的flash映象文件.flash文件(.flash文件其实是.srec格式的文件)中没有bss段,所以程序的开始必须在RAM中建立bss段并清0,同时也把.RWDATA段从flash中拷贝到RAM中(.RWDATA段在程序运行的时候必须在RAM中),并设置好栈,建立好C程序的工作环境然后调用C用户入口函数。这些工作都是由Crt0.s来完成的。下面是Crt0.s在flash中运行的工作流程:
4.3 在RAM中运行程序
程序在flash运行通常比在RAM中慢,所以有时也希望程序能够在RAM中运行。Nios II的reset地址仍然指向flash中(reset地址不能指向RAM,RAM在上电复位时还没有被初始化),在连接程序的时候可以把每个段都指定到RAM中,在SOPC builder中也可以把exception部分指定到RAM中。这样连接生成的可执行文件.elf文件就是适合在RAM中运行的程序。但在实际应用中这个程序最终存放在flash中,所以需要有一段bootloader代码,用于把flash中的程序映象拷贝到RAM中运行。工具elf2flash能够根据情况自动给你的程序在生成.flash文件时添加“程序记录”和bootloader。elf2flash判断其后随参数reset地址(就是Nios II的reset地址)和程序的入口地址是不是一样,如果一样就不添加“程序记录”和bootloader,如果不一样就添加。这个bootloader根据各个“程序记录”把程序映象拷贝到到RAM中并从RAM中执行。和EPCS一样,每个“程序记录”由两个32位的数据组成,一个是程序的长度,一个目的执行地址(即程序的运行地址)。Stratix 开发板上flash中的存贮分布如下:
0x700000~0x7FFFFF |
出厂逻辑Safe Logic |
0x600000~0x6FFFFF |
用户逻辑User Logic |
剩余空间 |
|
4字节的最后一个 “程序记录”的目的地址域A |
|
0x00000000,4字节的最后一个 “程序记录”长度域L |
|
Ln个字节的第n个程序段映象 |
|
4字节的第n个程序段的目的地址An |
|
4字节的第n个程序段的长度Ln |
|
… |
|
L2个字节的第2个程序段映象 |
|
4字节的第2个程序段的目的地址A2 |
|
4字节的第2个程序段的长度L2 |
|
Length+8~length+L+7 |
L1字节的第1个程序段映象 |
Length+4~length+7 |
4字节的第1个程序段的目的地址A1 |
Length~length+3 |
4字节的第1个程序段的长度L1 |
0~length-1 |
Bootloader |
Bootloader的工作流程如下:
运行完bootloader后仍然要执行Crt0.s,但此时Crt0.s的流程和程序在flash中直接运行的情况有一些区别:它没有初始化指令cache,也不会企图去装载别的段,这些步骤已经在bootloader中完成。程序映象已经包含这些段,在搬移程序映象的同时也装载了相应的段(.RODATA段,.RWDATA段和.EXCEPTIONS段),程序映象中不包含.bss段和栈,所以仍然需要清.bss段以及设置栈指针和全局指针。Bootloader没有存取存贮器数据,因此没有初始化数据cache,所以Crt0.s仍然要初始化数据cache。