張開(kāi)生 汪 慧 孟愛(ài)權(quán)
(西安電子工程研究所 西安 710100)
對(duì)于嵌入式芯片而言,Boot就是自啟動(dòng),在DSP的調(diào)試階段,可執(zhí)行的代碼文件(.out)存放在安裝了TI開(kāi)發(fā)環(huán)境CCS所在的計(jì)算機(jī)上,在線連接仿真器調(diào)試時(shí),由仿真器將可執(zhí)行代碼load到DSP的內(nèi)存中運(yùn)行并調(diào)試。但軟件成熟后,需要將用戶的可執(zhí)行代碼存放在片外Flash或者別的設(shè)備(GMAC/PCIE/SRIO加載方式)中,系統(tǒng)上電后將可執(zhí)行代碼自動(dòng)加載到內(nèi)存中,實(shí)現(xiàn)可執(zhí)行代碼的上電自動(dòng)運(yùn)行,這一過(guò)程就是通常所說(shuō)的自啟動(dòng)或者Boot[1]。
片外的Flash分為NAND Flash和NOR Flash兩種,其中在DSP和FPGA加載過(guò)程中常用的是NOR Flash,因?yàn)镹OR Flash和普通的內(nèi)存訪問(wèn)方式類似,可以支持隨機(jī)訪問(wèn),這使它既具有支持XIP(eXecute In Place,即芯片內(nèi)執(zhí)行)的特性,又具備像普通RAM一樣執(zhí)行程序的能力,因此NOR Flash是自啟動(dòng)代碼的絕佳載體。
本文將對(duì)DSP的加載過(guò)程和方式進(jìn)行簡(jiǎn)要介紹,重點(diǎn)闡述多核器件的啟動(dòng)流程、啟動(dòng)方式選擇、啟動(dòng)文件格式生成和文件內(nèi)容,提出基于網(wǎng)絡(luò)FTP的動(dòng)態(tài)加載方式,詳細(xì)闡述了多片網(wǎng)絡(luò)動(dòng)態(tài)加載的實(shí)現(xiàn)步驟。
對(duì)于TI的C66xx系列DSP而言,無(wú)論是單核加載還是多核加載,均是DSP上電/系統(tǒng)復(fù)位后所有核的PC指針指向RBL代碼,RBL是在芯片出廠的時(shí)候就已固化到芯片內(nèi)部NOR Flash中的一段程序,程序起始地址為0x20B0_0000。無(wú)論對(duì)于單核DSP還是多核DSP而言,在上電/系統(tǒng)復(fù)位后所有核同時(shí)從地址0x20B0_0000運(yùn)行片內(nèi)的RBL(Rom Bootloader)程序[2],但從核(多核DSP中定義Core0為主核,其余為從核)的RBL在判斷核ID號(hào)不為0后進(jìn)入等待狀態(tài),等待Core0發(fā)送啟動(dòng)地址BOOT_MAGIC_ADDRESS和核間IPC中斷,從核收到核間中斷后將PC指針指向啟動(dòng)地址并開(kāi)始執(zhí)行程序[3]。
而主核的RBL通過(guò)讀取寄存器DEVSTAT寄存器的值判斷啟動(dòng)模式,根據(jù)啟動(dòng)方式進(jìn)行接口初始化和CPU時(shí)鐘PLL的配置,同時(shí)根據(jù)啟動(dòng)方式?jīng)Q定是否進(jìn)行數(shù)據(jù)搬移,如果需要進(jìn)行數(shù)據(jù)搬移,如SPI加載,就需要將SPI Flash中的可執(zhí)行程序加載到DSP的相應(yīng)內(nèi)存中,如果不需要搬移,就直接跳轉(zhuǎn)到外接NOR Flash的起始地址(如EMIF16加載時(shí)外接的NOR Flash地址0X7000_0000)執(zhí)行[4]。
RBL程序執(zhí)行的流程如圖1所示,Core0執(zhí)行的RBL負(fù)責(zé)將用戶程序加載到合適的存儲(chǔ)位置(例如:L2、片內(nèi)共享存儲(chǔ)、DDR、EMIF RAM空間),然后Core0執(zhí)行用戶程序。
圖1 DSP自啟動(dòng)流程
在某些啟動(dòng)方式的加載過(guò)程中,加載啟動(dòng)之前需要預(yù)留L2最后0XD23F字節(jié)空間(0X0087_2DC1 ~0X0087_FFFF約53KB)[1],這段保留空間作為RBL程序執(zhí)行時(shí)的堆棧、配置、參數(shù)存儲(chǔ)空間,在用戶程序加載起來(lái)之后(CPU開(kāi)始執(zhí)行_c_int00)就可以使用,如果用戶需要使用這段預(yù)留的空間,必需將一些未初始化的變量在.cmd內(nèi)存配置文件中進(jìn)行定義。
用戶程序啟動(dòng)后的主程序入口地址固定指向_c_int00函數(shù),而_c_int00是C/C++程序初始化代碼的入口地址,其主要功能是完成建立C程序的運(yùn)行環(huán)境,為進(jìn)入main()函數(shù)進(jìn)行系統(tǒng)初始化,因此它是芯片運(yùn)行支持庫(kù)中的一個(gè)重要函數(shù)。DSP上電時(shí),由RBL負(fù)責(zé)引導(dǎo)至_c_int00,_c_int00主要完成以下工作:
1)定義系統(tǒng)棧.stack,并初始化棧指針,配置相關(guān)寄存器;
2)初始化全局變量(.cinit),從.cinit段將初始化數(shù)據(jù)拷貝到.bss段中相應(yīng)的變量;
3)若使用C++,還會(huì)完成全局對(duì)象構(gòu)造(.pinit);
4)調(diào)用main函數(shù)運(yùn)行C程序;
5)當(dāng)main函數(shù)return時(shí),調(diào)用exit函數(shù);
當(dāng)_c_int00函數(shù)執(zhí)行完畢之后,即完成了為C語(yǔ)言的準(zhǔn)備工作,系統(tǒng)就轉(zhuǎn)到C語(yǔ)言的main()函數(shù)。
另外如果程序在鏈接文件.cmd中采用-c選項(xiàng),則編譯鏈接后的可執(zhí)行程序會(huì)將全局變量的初始化放在_c_int00()函數(shù)中進(jìn)行,在此函數(shù)中會(huì)調(diào)用_auto_init(CINIT)函數(shù),將.cinit段的內(nèi)容拷入.bss中相應(yīng)的變量中,此過(guò)程是在系統(tǒng)上電后進(jìn)入main()函數(shù)之前執(zhí)行的;如果程序在鏈接時(shí)采用-cr選項(xiàng),則編譯后的可執(zhí)行程序中全局變量需要使用loader進(jìn)行初始化,這種方法一般用于在JTAG調(diào)試時(shí),CCS即為loader。
DSP芯片在上電復(fù)位過(guò)程中通過(guò)采樣鎖存13個(gè)引腳BOOTMODE[12:0]/GPIO[13:1]的狀態(tài)值到芯片內(nèi)部DEVSTAT寄存器[5],采樣鎖存時(shí)序如圖2所示,RBL程序獲取啟動(dòng)模式后,執(zhí)行相應(yīng)的加載流程,用戶程序加載完成后這些GPIO配置引腳就可以作為普通輸入輸出引腳使用。
圖2 啟動(dòng)模式采樣鎖存時(shí)序
在RESETFULL信號(hào)拉高前后12個(gè)時(shí)鐘周期內(nèi),GPIO配置管腳的值會(huì)被DSP采樣鎖存,鎖存的值存儲(chǔ)在芯片內(nèi)部地址為0x02620020的DEVSTAT寄存器中,在片內(nèi)RBL啟動(dòng)加載流程時(shí),RBL通過(guò)讀取DEVSTAT寄存器的值決定執(zhí)行相應(yīng)的加載程序,例如選擇啟動(dòng)方式為EMIF啟動(dòng)時(shí),需在芯片復(fù)位上升沿期間將GPIO[15:0]管腳值設(shè)置為0X1821,選擇I2C啟動(dòng)時(shí)管腳值為0X160D,設(shè)置的管腳值可以在DEVSTAT寄存器中查看,在調(diào)試過(guò)程中,可以在CCS中點(diǎn)擊“System Reset”后,通過(guò)修改DEVSTAT寄存值,選擇不同的啟動(dòng)方式/強(qiáng)制軟件引導(dǎo)加載,而不用每次通過(guò)硬件修改/上電復(fù)位等選擇啟動(dòng)方式。
DSP的啟動(dòng)方式可以分為以下三種方式[6]。
1)No Boot啟動(dòng)方式,相關(guān)的外設(shè)設(shè)備為EMIF,用戶代碼存放在EMIF Flash,RBL檢測(cè)到啟動(dòng)方式為No Boot后,RBL執(zhí)行直接跳轉(zhuǎn)到EMIF Flash空間首地址,然后由Core0直接讀取并執(zhí)行用戶程序;
2)Host Boot啟動(dòng)方式,相關(guān)的設(shè)備有PCIE/GMAC/SRIO,用戶程序由另外的設(shè)備通過(guò)上述接口搬移到相應(yīng)的存儲(chǔ)位置,搬移完成后由Core0跳轉(zhuǎn)并執(zhí)行用戶程序;
3)Slave Boot啟動(dòng)方式,相關(guān)的設(shè)備有EMIF/SPI/I2C/UART,用戶的可執(zhí)行程序以boot table格式存放在芯片的片外Flash中(從首地址開(kāi)始存放),加載過(guò)程中由RBL初始化Flash接口,RBL程序通過(guò)啟動(dòng)接口將用戶程序搬移到指定地址,然后Core0跳轉(zhuǎn)到用戶程序的_c_int00函數(shù)處,由Core0向從核發(fā)送IPC中斷,啟動(dòng)從核。
用TI的編程工具CCS(Code Composer Studio)編譯連接生成后綴為.out可執(zhí)行文件,此目標(biāo)文件格式被稱作通用目標(biāo)文件格式(Common Object File Format,COFF)。COFF文件是按照模塊化思想對(duì)程序進(jìn)行管理的,它的最小單位稱為段(Section)。段是占據(jù)一個(gè)連續(xù)空間的代碼塊或者數(shù)據(jù)塊,與其他段一起映射到存儲(chǔ)器內(nèi)。但各個(gè)段是分開(kāi)的,各有功能特色。對(duì)于C語(yǔ)言文件,編譯器生成的代碼段分配在.text段中,全局變量和靜態(tài)變量分配在.bss段中,而局部變量或寄存器變量分配到.stack段,還有其他段和自定義段,可以查詢TI的有關(guān)文檔。
連接器生成的可執(zhí)行COFF文件(后綴為.out),含有一些定位符號(hào)和文件頭等信息,這些信息能夠被仿真器識(shí)別,仿真器可以從COFF文件中提取有用的程序,并把提取的程序加載到DSP的L2 SRAM。但是,如果我們采用FLASH、PCI或SRIO等加載時(shí),COFF文件中的一些信息不能被識(shí)別,而且由于含有的無(wú)效信息較多,COFF文件比較大,因此,我們應(yīng)該對(duì)COFF文件進(jìn)行提取和精簡(jiǎn)處理。這就需要用到TI提供的十六進(jìn)制轉(zhuǎn)換工具(Hex6x.exe),該轉(zhuǎn)換工具可以把COFF文件轉(zhuǎn)換成需要的格式。
為了使RBL從Flash加載時(shí)知道搬移的目的地址和數(shù)據(jù)大小,需要將用戶的.out文件轉(zhuǎn)換成RBL能夠識(shí)別使用的Boot Table格式(后綴.dat);用戶程序固化燒寫的過(guò)程就是將用戶的.out文件通過(guò)工具鏈轉(zhuǎn)換成Boot Table格式的.dat文件,然后將.dat文件固化到Flash中。轉(zhuǎn)化工具鏈中主要用到的有:
首先利用Hex轉(zhuǎn)換工具h(yuǎn)ex6x.exe將.out文件和.rmd轉(zhuǎn)換為.btbl文件;其次利用mergebtbl工具將多個(gè).out文件生成的對(duì)應(yīng)的.btbl文件合成成一個(gè).btbl文件;最后利用bconvert64x.exe和b2ccs.exe兩個(gè)工具,將文件.btbl轉(zhuǎn)換為最終燒寫到Flash中的.dat文件。TI提供的轉(zhuǎn)換工具的可執(zhí)行程序和源碼位于軟件安裝包“X: imcsdk_2_01_02_05 oolsoot_loaderiblsrcutil”路徑下,使用者可以根據(jù)實(shí)際需要對(duì)轉(zhuǎn)換工具進(jìn)行修改,例如官方b2i2c.exe支持的最大文件長(zhǎng)度為0X20000個(gè)字節(jié),如果最終生成的.dat文件超出該長(zhǎng)度,需要用戶修改宏定義的文件上限大小,否則會(huì)出現(xiàn)文件燒寫長(zhǎng)度不夠的情況,導(dǎo)致程序加載失敗。
最終生成的.dat文件的Boot Table由3個(gè)部分組成:首先是包含32bit的程序入口地址(_c_int00的地址);其次是Boot Table的核心部分,也是占據(jù)文件大小最大的部分,該部分由若干個(gè)文件段組成,每個(gè)文件段第一個(gè)32bit是段字節(jié)數(shù)(需要搬移的字節(jié)長(zhǎng)度4n),第二個(gè)是段文件搬移的目的地址,緊接著是n個(gè)需要搬移的數(shù)據(jù),Boot Table文件格式如圖3所示[7-8]。
圖3 Boot Table文件格式
RBL在搬運(yùn)Boot Table格式的用戶程序時(shí),按照格式不斷地讀取和搬移段數(shù)據(jù),當(dāng)讀取到搬移段字節(jié)數(shù)為0(接收標(biāo)識(shí))時(shí),則PC指針跳轉(zhuǎn)到Boot Table最開(kāi)始指定的32位頭地址(_c_int00函數(shù)地址),Core0開(kāi)始執(zhí)行用戶程序。
在本項(xiàng)目中,由于系統(tǒng)中需要使用16片TI 6678,如果采用傳統(tǒng)的仿真器進(jìn)行程序固化,那么在調(diào)試和程序燒寫過(guò)程中需要重復(fù)且頻繁地?zé)龑懹脩舫绦?dat文件到片外Flash,為減輕程序更新操作的復(fù)雜減少更新時(shí)間,本文提出一種基于PowerPC的FTP服務(wù)器的動(dòng)態(tài)加載方法,該方法的系統(tǒng)硬件架構(gòu)如圖4所示,本系統(tǒng)由4塊DSP板卡組成,每塊板卡中搭載4個(gè)DSP芯片,每個(gè)DSP芯片的網(wǎng)絡(luò)接口與板上的網(wǎng)絡(luò)交換芯片相連,4個(gè)DSP板卡的16個(gè)6678芯片與中心控制板的網(wǎng)絡(luò)通過(guò)交換芯片進(jìn)行互聯(lián),基于交換芯片的網(wǎng)絡(luò)互聯(lián)機(jī)制為網(wǎng)絡(luò)加載提供物理通路。
圖4 多片網(wǎng)絡(luò)加載硬件架構(gòu)
具體加載過(guò)程為:在每個(gè)DSP外掛的Flash中固化統(tǒng)一的一個(gè)小的用戶程序,該程序在上電后由Flash自動(dòng)加載到共享存儲(chǔ)區(qū)的前128KB空間(0x0C000000-0X0C020000該空間在正常用戶程序中作為數(shù)據(jù)接收緩存用,在動(dòng)態(tài)加載階段作為加載程序執(zhí)行的運(yùn)行空間),由Core0實(shí)現(xiàn)每個(gè)芯片的時(shí)鐘、DDR、網(wǎng)絡(luò)初始化,其余7個(gè)核處于Idle狀態(tài),程序中根據(jù)槽位號(hào)和DSP節(jié)點(diǎn)號(hào)為每個(gè)DSP芯片設(shè)置一個(gè)固定的網(wǎng)絡(luò)IP地址(例如:192.168.0.1---192.168.0.16),網(wǎng)絡(luò)地址設(shè)定完畢后啟動(dòng)TCP客戶端線程,等待運(yùn)行于中心控制板的TCP服務(wù)器啟動(dòng);16個(gè) DSP中實(shí)際需要運(yùn)行的用戶程序首先利用工具鏈將.out文件轉(zhuǎn)換成對(duì)應(yīng)的.dat文件存放到PowerPC的FTP服務(wù)器上,每個(gè)芯片的用戶程序以文件名區(qū)分,例如dsp1.dat,dsp2.dat……dsp16.dat,中心控制板在上電啟動(dòng)后,從FTP服務(wù)器中按照文件名依次讀取DSP的用戶程序,同時(shí)根據(jù)確定的IP地址利用TCP協(xié)議將DSP程序從FTP服務(wù)器中傳輸?shù)紻SP芯片,DSP接收到文件后,判斷接收最后字節(jié)是否是Boot Table文件結(jié)束標(biāo)識(shí)(32位全0),如果數(shù)據(jù)流中沒(méi)有結(jié)束標(biāo)識(shí)則繼續(xù)接收,如果出現(xiàn)結(jié)束標(biāo)識(shí),則認(rèn)為程序文件傳輸完畢,Core0將接收到的數(shù)據(jù)文件按照Boot Table文件格式,首先獲取32位頭地址(用戶程序_c_int00函數(shù)地址),然后根據(jù)Boot Table文件格式將用戶程序搬移到指定地址,Core0搬移完成后,將_c_int00地址寫入到從核L2的最后4字節(jié)(0x1X87FFFC,X為核號(hào)),依次向從核發(fā)送IPC中斷啟動(dòng)從核,然后Core0跳轉(zhuǎn)到_c_int00地址執(zhí)行,至此,整個(gè)DSP芯片的用戶程序?qū)崿F(xiàn)了從中心控制板的FTP服務(wù)器到DSP芯片內(nèi)執(zhí)行的過(guò)程。針對(duì)加載過(guò)程中的地址空間劃分,在RBL階段由片內(nèi)固化程序占用L2空間最后54字節(jié),在動(dòng)態(tài)加載程序執(zhí)行時(shí),僅占用所有存儲(chǔ)空間中共享存儲(chǔ)區(qū)前128KB空間,該128KB空間用于程序的代碼段、常量段、向量端、堆棧段等程序執(zhí)行段,在程序加載完成后,共享區(qū)占用的128KB存儲(chǔ)空間在跳轉(zhuǎn)到用戶程序時(shí)被全部交給用戶程序使用,即整個(gè)程序加載完成后用戶程序可以使用DSP芯片的所有存儲(chǔ)空間。
本文詳細(xì)介紹了TI C66XX系列多核啟動(dòng)的流程和加載方式,分析了加載文件格式,提出將用戶程序上傳到FTP服務(wù)器實(shí)現(xiàn)用戶程序在線動(dòng)態(tài)加載,該方式同傳統(tǒng)的仿真器單個(gè)燒寫的方式相比,顯著提高了程序更新的效率,同時(shí)由于在每個(gè)DSP的Flash固化的程序全部一致,因此系統(tǒng)內(nèi)的4塊DSP板卡無(wú)需固定槽位,每個(gè)DSP上電后的屬性和地位由槽位號(hào)和節(jié)點(diǎn)號(hào)確定,提高硬件板卡的通用性,這種加載方式對(duì)于提高開(kāi)發(fā)效率,縮短產(chǎn)品研發(fā)周期,具有非常重要的工程實(shí)踐意義。