吳 潔,李尚柏
(四川大學 原子核科學技術研究所 輻射物理及技術教育部重點實驗室,四川 成都 610064)
通常DSP程序是被加載到DSP的內部存儲器中執(zhí)行的。調試過程中,用CCS集成環(huán)境將編譯好的代碼通過JTAG接口下載到DSP的內部存儲器執(zhí)行;調試完成后,將程序代碼燒錄到DSP的外部存儲器,在 DSP上電時,自動將程序代碼裝載到內部存儲器執(zhí)行[1]。但是,DSP的內部存儲器有限的。如果程序代碼及其使用的數(shù)據(jù)區(qū)大于DSP的內部存儲器,就會限制DSP程序的開發(fā)。解決這種困局的一個有效的方法是使用Overlay程序設計技術。
早期計算機的內存是非常小的,又要完成較為復雜的任務,開發(fā)人員提出了Overlay的程序設計思想。隨著大規(guī)模集成電路技術的發(fā)展,擁有更多的計算機內存已不是奢望,Overlay技術似乎已逐漸被遺忘。然而,對嵌入式系統(tǒng)和DSP而言,內部存儲器仍然是稀缺資源,Overlay技術仍然具有用武之地[2]。本文將討論DSP Overlay程序的設計技術和實現(xiàn)步驟,并通過一個具體的實例在C6000系列DSP上來實現(xiàn)Overlay程序設計技術。
在DSP上,對目標系統(tǒng)存儲器的配置以及對段(代碼段、數(shù)據(jù)段等)的配置是實現(xiàn)Overlay的關鍵技術之一。鏈接命令文件是一個以.cmd為后綴的文本文件,其主要用途就是定義目標存儲器的模型,以及指定模塊要加載的位置。它包含:要鏈接的目標文件名、鏈接器選項、MEMORY指令(定義目標系統(tǒng)的存儲器的配置)、SECTIONS指令 (定義段在目標系統(tǒng)中的配置)。表1給出了鏈接命令文件中主要的保留字。
表1 命令鏈接文件主要保留字Tab.1 The main reserved words of command link file
UNION:產生一個聯(lián)合段,其中的輸出段具有相同的運行地址。當程序代碼很大,不能加載到目標系統(tǒng)的內部存儲器中執(zhí)行時,希望互相獨立的段運行在相同的地址[3]。
本文討論的DSP Overlay程序設計主要是解決內存資源不足的問題,方法是用若干模塊構建一個聯(lián)合段,使聯(lián)合段中各成員模塊共享一塊運行內存,需要執(zhí)行哪個模塊就把它從裝載內存復制到運行內存來執(zhí)行。由此可見,聯(lián)合段中的成員模塊具有互斥性,也就是說,在同一時間只能運行一個聯(lián)合段中的模塊。因此,本DSP Overlay源程序的設計就是把要完成的任務合理的劃分成多個功能模塊[4]。
在本DSP Overlay程序設計實例中,設計了4個功能模塊和兩個公用模塊。每個功能模塊的源代碼分別存儲為獨立的源文件task1.c(計算出兩個整數(shù)的和,再乘以比例系數(shù)ratio)、task2.c(調用公共函數(shù) IntSub,并返回 IntSub 的結果)、task3.c(計算兩個整數(shù)的積)、task4.c(計算兩個整數(shù)的平方和)。公用模塊vectors.asm包含中斷矢量的映射,main.c包含硬件設備的初始化、中斷服務程序和公用函數(shù)。鏈接命令文件overly.cmd是每個DSP程序不可或缺的。命令鏈接文件是Overlay設計的關鍵,下面將重點討論其使用和Overlay程序的設計思想。
1)鏈接命令文件overlay.cmd,如程序1所示:程序1鏈接命令文件
/*目標系統(tǒng)存儲器配置*/
MEMORY
{
RAM :origin=0x00000000,len=0x010000/*數(shù)據(jù)存儲器*/
OVLMEM :origin=0x00010000,len=0x010000/*Overlay模塊運行存儲器*/
ROM :origin=0x00020000,len=0x020000/*程序存儲器*/
SDRAM :origin=0x80000000,len=0x1000000/*擴展存儲器*/
}
/*段配置*/
SECTIONS
{
.vectors>ROM /*中斷映射段配置*/
.text >ROM /*公共代碼段配置*/
.bss >RAM /*未初始化數(shù)據(jù)段配置*/
.cinit>RAM /*已初始化數(shù)據(jù)段配置*/
.const>RAM /*常數(shù)段配置*/
.far >RAM /*遠指針段配置*/
.stack >RAM /*堆棧段配置*/
.cio >RAM /*流式I/O函數(shù)緩沖區(qū)配置*/
.sysmem>RAM/*系統(tǒng)堆內存段配置*/
/*聯(lián)合段配置*/
UNION
{
.task12:{debug ask1.obj (.text), debug ask2.obj(.text)}
load >> SDRAM, table (BINIT),table(_task12_ctbl)
.task34:{debug ask3.obj (.text), debug ask4.obj(.text)}
load>>SDRAM, table(_task34_ctbl)
}run=OVLMEM
.ovly:{}>RAM/*聯(lián)合段拷貝表段配置*/
.binit:{}>RAM/*引導時的聯(lián)合段拷貝表配置*/
}
在上述程序1MEMORY命令中,定義了目標系統(tǒng)的存儲器配置,設置了數(shù)據(jù)存儲器 (RAM)、聯(lián)合段模塊運行存儲器(OVLMEM)、程序存儲器(ROM)、擴展存儲器(SDRAM)的起始地址和長度。在SECTIONS命令中,首先定義了輸出段的配置,將可執(zhí)行代碼段 (.text和.vectors)配置到程序存儲器(ROM), 將 其 它 的 數(shù) 據(jù) 段 (.bss、.cinit、.const、.far、.cio 和 .sysmem)配置到數(shù)據(jù)存儲器(RAM);其次還配置了聯(lián)合段,在聯(lián)合段中使用的table(arg)算符使得鏈接器生成了一個拷貝表(此拷貝表必須具有唯一的名字),同時用arg生成一個變量名,應用程序可以用這個變量名訪問拷貝表。如果指定table(BINIT)(arg為BINIT),則鏈接器產生一個引導時的拷貝表,也即產生一個默認的拷貝表段,供系統(tǒng)初始加載時使用[5]。
圖1 實例的內存配置和段配置Fig.1 The instance of memory configuration and section configuration
本程序設計中,鏈接器根據(jù)鏈接命令文件(程序1)產生的目標系統(tǒng)內存配置和段配置如圖1所示。圖中左側部分是MEMORY所定義的系統(tǒng)存儲器配置,右側部分是根據(jù)SECTIONS的描述產生的模塊定位信息。鏈接器把所有的數(shù)據(jù)段定位到RAM存儲器。實際使用數(shù)據(jù)空間的段依次為系統(tǒng)堆棧段.stack(長度為 0x7d0)、已初始化數(shù)據(jù)段.cinit(長度為 0x264)、遠指針段.far(長度為 0x250)、常數(shù)段.const(長度為 0x20)、未初始化段.bss(長度為 0x14)、拷貝表段.ovly(長度為0x20)、引導加載拷貝表段.binit(長度為0x10)。鏈接器把代碼段.text定位在ROM存儲器,占用存儲空間0x20a0字節(jié)。聯(lián)合段的.task12和.task34分別定位在SDRAM存儲器的0x8000000和0x80000100處,分別占用存儲空間0x100和0x0e0字節(jié)。當程序運行時,根據(jù)需要把聯(lián)合段的成員拷貝到OVLMEM存儲空間來執(zhí)行。
對本DSP Overlay程序設計實例的工程項目編譯鏈接后,打開映射文件(*.map)可以看到鏈接器產生的詳細信息,下面給出內存配置信息、段定位信息和拷貝表信息:
①內存配置信息(MEMORY CONFIGURATION)
name origin length used attr fill
RAM 00000000 00010000 00000d00 RWIX
OVLMEM 00010000 00010000 00000100 RWIX
ROM 00020000 00040000 00001fa0 RWIX
SDRAM 80000000 01000000 000001e0 RWIX
由于本實例比較簡單,所以內存的使用也較少。對于復雜的任務,或內存資源較少的目標系統(tǒng),ROM空間可能不足以加載所有代碼。
②段定位信息(SECTION ALLOCATION MAP)
output attributes/
section page origin length input sections
-------- ----- ---------- ----------
.task12 0 80000000 00000100 RUN ADDR=00010000
80000000 000000c0 task1.obj(.text)
800000c0 00000040 task2.obj (.text)
.task34 0 80000100 000000e0 RUN ADDR=00010000
80000100 00000080 task3.obj (.text)
80000180 00000060 task4.obj (.text)
.ovly 0 00000cd0 00000030
聯(lián)合段.task12和.task34的運行地址均為0x00010000,但各自的加載地址不同,.task12的加載地址為0x80000000,.task34的加載地址為0x80000100??截惐矶?ovly起始地址為0x00000cd0,長度為 0x30,包含 _task12_ctbl、_task34_ctbl和BINIT3個表項。
③拷貝表信息(LINKER GENERATED COPY TABLES)
_task12_ctbl@ 00000cd0 records:1, size/record:12,table size:16
.task12:copy 256 bytes from load addr=80000000 to run addr=00010000
_task34_ctbl@ 00000ce0 records:1, size/record:12,table size:16
.task34:copy 224 bytes from load addr=80000100 to run addr=00010000
BINT@00000cf0 records:1,size/record:12,table size:16
.task12:copy 256 bytes from load addr=80000000 to run addr=00010000
拷貝表信息有3條記錄,第一條記錄說明拷貝表段task12_ctbl的存儲地址為 0x0cd0,有 1個記錄,每個記錄的大小為12字節(jié),拷貝表的大小為16字節(jié)。.task12段的加載地址為0x80000000,運行地址為0x00010000,拷貝的長度為256字節(jié)。加載.task12模塊時從0x8000000拷貝256個字節(jié)到0x00010000;同理,第二條記錄列出了拷貝表段task34_ctbl的具體信息;第三記錄是引導時加載的拷貝表信息,由于在鏈接命令文件中指定.task12段為引導時的加載段,所以第三條記錄與第一條相同。
2)公共模塊程序設計
公共模塊包含了硬件設備的初始化、中斷服務程序、公用函數(shù)和運行主函數(shù)。從圖2可以看出,主函數(shù)主要完成兩項任務,初始化和Overlay模塊的加載執(zhí)行。初始化工作主要包括芯片支持庫初始化,系統(tǒng)時鐘初始化。在初始化系統(tǒng)時鐘之前要求關閉所有中斷。對外部總線進行初始化才能使目標板上擴展的SDRAM存儲器正常工作。本實例使用定時器調度Overlay模塊的執(zhí)行,所以還需進行定時器初始化和中斷初始化。從圖2也可以看出,在定時器事件的驅動下,兩個Overlay模塊交替加載和執(zhí)行。當?shù)谝粋€定時器事件發(fā)生時,ovlyFlag=0,將.task34段拷貝到運行內存,然后依次執(zhí)行task3()、task4()和 IntSub()函數(shù)。 task3()和 task4()是聯(lián)合段.task34中的函數(shù),必須先將.task34段拷貝到內存中才能調用這兩個函數(shù)。IntSub()是公共模塊中的函數(shù),它常駐內存,隨時都可以執(zhí)行。當?shù)诙€定時器事件發(fā)生時,ovlyFlag=1,將.task12段拷貝到運行內存,然后依次執(zhí)行 task1()、task2()和IntAdd()函數(shù)。這三個函數(shù)是聯(lián)合段.task12中的函數(shù),必須先將.task12段拷貝到內存中才能調用。
3)功能模塊設計
本應用實例設計了4個功能模塊。模塊1設計了該模塊的局部函數(shù) int IntAdd(int,int)(實現(xiàn)兩個整數(shù)的加法)和功能函數(shù) int task1(int, int)(加載后由主函數(shù)調用)。 task1 調用局部函數(shù)IntAdd,并將所得到的結果與全局變量ratio相乘。模塊2設計了一個功能函數(shù)task2(int,int),加載后由主函數(shù)調用。task2調用全局函數(shù)IntSub(int,int),實現(xiàn)兩個整數(shù)的減法。模塊3和模塊4分別設計了一個功能函數(shù)task3(int,int)和 task4(int, int),task3 實現(xiàn)了兩個整數(shù)的乘積,task4 實現(xiàn)了兩個整數(shù)的平方和。
多個Overlay模塊共享同一塊運行內存,因而必須根據(jù)需要動態(tài)地加載Overlay模塊。要實現(xiàn)這個目的,必須知道鏈接器所產生的拷貝表結構??截惐淼慕Y構信息定義在運行支持庫的頭文件cpy_tbl.h中。對于每個需要動態(tài)加載的模塊,鏈接器都會為其產生一個COPY_RECORD結構對象(包含裝載地址、運行地址和需要拷貝的代碼長度)。鏈接器將所有COPY_RECORD結構對象組織成一個COPY_TABLE結構對象。根據(jù)COPY_TABLE的內容,將代碼從裝載地址拷貝到運行地址[6]。裝載的task34模塊的程序代碼如程序2所示。
圖2 main函數(shù)的執(zhí)行流程Fig.2 The execution process of main funtion
程序2 Overlay段task34的裝載和執(zhí)行
copy_in(&task34_ctbl); //拷貝.task34 段代碼
CACHE_invAllL1p(); //更新 cache
asm(“nop 5”); //消除流水線的影響
val1=task3(taskIn1,taskIn1); //調用 task3,執(zhí)行 a*b
val2=task4(taskIn1,taskIn1); //調 用 task4, 執(zhí) 行a*a+b*b
val3=IntSub(val1,val2);//調用全局函數(shù),執(zhí)行 2a-3b
值得注意的是,當所使用的DSP具有cache(高速緩存)時,在調用完copy_in函數(shù)之后,執(zhí)行剛剛加載的代碼之前,應該刷新程序cache的內容。
多個Overlay模塊共享一塊運行內存,代碼是動態(tài)加載的,程序的跟蹤調試有所不同。
在實際的運行中,為了調試方便,暫時將Overlay模塊的加載地址定位在SDRAM,待調試完成后,再將其定位到目標系統(tǒng)的程序存儲器。調試時,在下載.task12段和.task34段時可能會出現(xiàn)錯誤提示,可以暫時忽略此錯誤。當下載完成后,在外總線初始化函數(shù)EMIFInit()之后設置斷點,然后運行程序到所設置的斷點處,此時外部總線已被初始化,重新下載*.out文件,就能避免這個錯誤。
在跟蹤調試時,如果想跟蹤調試某一Overlay模塊,可以暫時不把該模塊放在聯(lián)合段中,待調試完成后,再把它添加到聯(lián)合段中。為此,除了要修改鏈接命令文件外,還要修改Overlay模塊的加載代碼。例如要調試.task34模塊,可以修改鏈接器命令文件中部分代碼如下:
SECTIONS
……
/*.task34:{debug ask3.obj(.text), debug ask4.obj(.text) }
load>>SDRAM, table(_task34_ctbl)*/
……
}
由于在聯(lián)合段中刪除了.task34段,鏈接器將把目標文件task3.obj和task4.obj的.text段鏈接到統(tǒng)一的.text輸出段中,并把它定位到ROM存儲器。經上述修改,函數(shù)task3(int,int)和task4(int,int)將成為公共代碼的一部分,編譯、鏈接、下載后,即可在源代碼級跟蹤調試它們。此方法是將要調試的模塊作為公共模塊的一部分,任何時候都可在源代碼級跟蹤調試。
文中通過討論DSP覆蓋(Overlay)程序設計技術的開發(fā)方法,有效解決了由于DSP的內部存儲器有限,當程序代碼及其使用的數(shù)據(jù)區(qū)大于DSP的內部存儲器時,則會限制DSP程序的開發(fā)這一困局,并在TMS320C6713B上通過調試和運行,成功應用于基于DSP的繼電保護測試儀中,取得了滿意的結果。
[1]馬喜強,劉維亞,鄭喜鳳.基于多通信方式實現(xiàn)DSP程序在線編程[J].電子器件,2013,36(1):112-115.MA Xi-qiang,LIU Wei-ya,ZHENG Xi-feng.On-line programming of DSP based on multiple communications[J].Chinese Journal of Electron Devices,2013,36(1):112-115.
[2]李聲飛,代華山.基于串口通信的DSP程序動態(tài)加載技術[J].電訊技術,2011(6):121-124.LI Sheng-fei,DAI Hua-shan.Dynamic locading technology for DSP program based on serial communication[J].Telecommunication Engineering,2011(6):121-124.
[3]孫濱,周楊,郭曉東.動態(tài)鏈接庫技術及其應用[M].電腦編程技巧與維護,2009.SUN Bin,ZHOU Yang,GUO Xiao-dong.Dynamic link library technology and application[M].Computer Programming Skills and Maintenance,2009.
[4]王楠.基于Overlay期刊的網(wǎng)絡開放學術資源建設與服務研究[D].蘭州:蘭州大學,2010.
[5]夏爽.DSP的二級加載及Bootloader研究 [J].電腦編程技巧與維護,2009(10):8-11,16.XIA Shuang.The secondrey loading based on DSP and bootloader research[M].Computer Programming Skills and Maintenance,2009(10):8-11,16.
[6]楊音穎.基于Overlay網(wǎng)絡的應用層組播系統(tǒng)的研究與實現(xiàn)[J].計算機應用,2005,24(9):61-64.YANG Yin-ying.Application level multicast system based on overlay network[J].Computer Applications,2005,24(9):61-64.