花了几天看完了FSBL的代码,在这里做个总结,分析一下zynq的启动过程。
众所周知,xilinx zynq 7000系列的芯片中包括两个部分,PS和PL,也就是FPGA的逻辑编程的部分跟嵌入式ARM的部分,ARM部分是双核的A9处理器。关于FPGA的部分在这里就不说了。其实说的简单点,可以吧这个芯片看成一个带有FPGA外设的ARM处理器,下面详细分析一下启动流程。
所有的芯片都是从0地址启动的,所以首先找到0地址的代码,在..xxxx.sdk\standalone_bsp_0\ps7_cortexa9_0\libsrc\standalone_v5_1\src\asm_vectors.S中的开头也就是0地址的地方有这样得一段代码:
其中71行B _boot就是一条跳转命令,跳转到_boot的地方继续运行,在boot.s文件中_boot结束的地方有
这样的代码,跳转到_start的地方,在xil-crt0.s中我们找到了_start的地方
可以看见最终跳转到了main函数,从这里开始才真正的进入到了FSBL的代码中执行。打开FSBL的main函数,顺便一提我用的版本是2015.2的SDK。
我们从main函数开始一步一步的分析:
1. Status = ps7_init();这条语句是初始化cpu,也就是对寄存器进行设置,设置的依据就是从vivado生成的硬件的信息。
2. GetSiliconVersion();得到PS的版本,我得到的是3.1的版本
3. BootModeRegister = Xil_In32(BOOT_MODE_REG);得到boot模式,在这里我使用的是qspi的启动模式。
4.
所以会执行上面这段代码,进行初始化QSPI FALSH,在InitQspi()函数中由于我使用的QSPIFLASH是16M的所以LinearBootDeviceFlag就被赋值为1了。
下面一句QspiAccess函数赋值给MoveImage函数指针,找到QspiAccess函数:
这个函数的作用是从FLASH的SourceAddress地址开始复制一段长度为LengthBytes的数据到DDR内存中。所以MoveImage也就有了同样的功能。
5.
FlashReadBaseAddress是在InitQspi()函数中赋值的,就是qspi falsh的起始地址为0xFC000000,在zynq7000的数据手册UG585中可以看到。
6. HandoffAddress = LoadBootImage();这条语句是整个FSBL中最关键的,这个函数主要做两个事情,一个是分析烧录到qspi中的数据的头的部分,其次是根据分析的结果把数据拷贝到DDR中。在这里还要岔开一下,说明一下烧录到QSPI的数据是怎么生成的。
zynq 7000的启动方式有很多种,其中包括从QSPI FALSH,SDcard,NOR FLASH,NAND FALSH等地方启动,我这里选用QSPI FALSH启动方式为例进行说明,首先要生成.bin文件,然后把这个文件通过SDK烧录到QSPIflash中。那么怎么生成.bin文件呢,一般来说bin文件中包含fsbl代码,FPGA部分生成的代码,在后面就是用户的应用程序了。
通过SDK中的Create Boot Image工具生成,打开Create Boot Image,
可以看见其中MY_FSBL.elf就是对应的FSBL,top.bit就是FPGA生成的流文件,HELLO_WORLD.elf跟rsc_ucosii.elf这两个文件都是应用程序,一般来说一个应用程序就可以了,这里我多添加一个是为了更好地演示。这几个文件的顺序是不能变动的。添加完成之后点击Create Image生成.bin文件,在这之后通过sdk带的Programe Flash进行烧录。
这回先分析到这里,下次对LoadBootImage()进行详细分析。