《DSP處理器原理與應(yīng)用》課件第4章_第1頁
《DSP處理器原理與應(yīng)用》課件第4章_第2頁
《DSP處理器原理與應(yīng)用》課件第4章_第3頁
《DSP處理器原理與應(yīng)用》課件第4章_第4頁
《DSP處理器原理與應(yīng)用》課件第4章_第5頁
已閱讀5頁,還剩212頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

第4章DSP軟件開發(fā)

4.1程序定位方式的比較

4.2公共目標(biāo)文件格式

4.3DSP匯編程序簡介

4.4DSPC語言程序基礎(chǔ)

4.5TIDSP軟件開發(fā)平臺

4.6本章小結(jié)習(xí)題與思考題在第3章中,簡單介紹了DSP軟件開發(fā)的一般流程以及TI公司的eXpressDSP,從中我們可以看到,DSP軟件的開發(fā)與普通軟件的開發(fā)有很大的不同。本章重點(diǎn)講述TI公司DSP的軟件開發(fā)基礎(chǔ)、軟件開發(fā)方法以及軟件的架構(gòu)。

一般來說程序是由代碼和數(shù)據(jù)組成的。要運(yùn)行的程序其代碼和數(shù)據(jù)必須存放在CPU能夠?qū)ぶ返拇鎯臻g里,而代碼和數(shù)據(jù)是以代碼塊和數(shù)據(jù)塊的形式存放的。代碼塊和數(shù)據(jù)塊是程序的最小單元,一個(gè)代碼塊或數(shù)據(jù)塊在存儲空間中連續(xù)、順序存放,不同的代碼塊或數(shù)據(jù)塊,可以存放于不同的存儲空間中。

如何確定這些代碼塊或數(shù)據(jù)塊在存儲空間的地址,就是我們通常說的程序的定位。程序的定位有以下三種。4.1程序定位方式的比較

1.編譯時(shí)定位

編程時(shí)由ORG語句確定代碼塊和數(shù)據(jù)塊的絕對地址,編譯器以此地址為首地址,連續(xù)、順序地存放該代碼塊或數(shù)據(jù)塊,也就是說我們在編程的時(shí)候已經(jīng)知道程序存放的大概位置。

MCU系統(tǒng)常采用這種方式。這種定位方式屬于絕對定位,其優(yōu)點(diǎn)是簡單、容易上手;缺點(diǎn)是程序員必須熟悉硬件資源,模塊化編程差且不支持工程化管理。

2.鏈接時(shí)定位

編程時(shí)以“SECTIONS”偽指令區(qū)分不同的代碼塊或數(shù)據(jù)塊。編譯器每遇到一個(gè)“SECTIONS”偽指令,從0地址重新開始一個(gè)代碼塊或數(shù)據(jù)塊。鏈接器將同名的“SECTIONS”合并,并按.cmd文件中的“SECTIONS”命令進(jìn)行實(shí)際的定位。程序員在編寫程序的時(shí)候并不知道程序最終的具體地址。具體的“SECTIONS”偽指令將在本章的后面部分加以介紹。

DSP系統(tǒng)常采用這種方式。這種定位方式屬于相對定位,其缺點(diǎn)是復(fù)雜靈活、上手較難;優(yōu)點(diǎn)是程序員不必熟悉硬件資源,模塊化編程強(qiáng)且支持工程化管理。

3.加載時(shí)定位

編程、編譯和鏈接時(shí)均未對程序進(jìn)行絕對定位。程序運(yùn)行前,由操作系統(tǒng)對程序進(jìn)行重新定位,并加載到存儲空間中。例如,在Windows操作系統(tǒng)下運(yùn)行一個(gè)應(yīng)用軟件,運(yùn)行前我們并不知道應(yīng)用軟件將會被加載到內(nèi)存的什么位置。

PC機(jī)系統(tǒng)常采用這種方式。這種定位方式也屬于相對定位,其缺點(diǎn)是必須要有操作系統(tǒng)支持;優(yōu)點(diǎn)是模塊化編程強(qiáng)且支持工程化管理。

由上我們可以看出,DSP軟件的定位方式介于MCU與GPP之間。下面我們來介紹“SECTIONS”偽指令的具體情況以及相關(guān)的知識。

4.2.1段(sections)

匯編器和鏈接器建立的目標(biāo)文件,是一個(gè)可以在TMS320C55X器件上執(zhí)行的文件。這些目標(biāo)文件的格式稱為公共目標(biāo)文件格式,即COFF(CommonObjectFileFormat)。由于COFF在編寫匯編語言程序時(shí)采用代碼和數(shù)據(jù)塊的形式,會使模塊化編程和管理變得更加方便。這些代碼和數(shù)據(jù)段稱為“段”。因?yàn)楫?dāng)編寫一個(gè)匯編語言程序時(shí),它可按照代碼段和數(shù)據(jù)段來考慮問題。匯編器和鏈接器都有一些命令建立并管理各種各樣的段。4.2公共目標(biāo)文件格式段(sections)是COFF文件中最重要的概念。每個(gè)目標(biāo)文件都被分成若干個(gè)段。一個(gè)段就是最終在存儲器映像中占據(jù)連續(xù)空間的一個(gè)數(shù)據(jù)或代碼塊。在編制匯編語言源程序時(shí),程序按段組織,每行匯編語句都從屬一個(gè)段,且由段匯編偽指令標(biāo)明該段的屬性。目標(biāo)文件中的每一個(gè)段是相互獨(dú)立的。在編程時(shí),段沒有絕對定位,每個(gè)段都認(rèn)為是從“0”地址開始的一塊連續(xù)的存儲空間,所以軟件開發(fā)人員只需要將不同的代碼塊和數(shù)據(jù)塊放到不同的段中,而無需關(guān)心這些段究竟定位于系統(tǒng)何處。采用段的優(yōu)點(diǎn)是便于程序的模塊化編程,便于工程化管理,可將軟件開發(fā)人員和硬件開發(fā)人員基本上分離開。一般地,COFF目標(biāo)文件都包含3個(gè)缺省的段:

.text段:通常包含可執(zhí)行代碼;

.data段:通常包含已初始化數(shù)據(jù);

.bss段:通常為未初始化變量保留存儲空間。

另外,匯編器與鏈接器允許程序員建立和鏈接自定義的段,這些段的用法與上述3個(gè)缺省段的用法相類似。所有的段可以分為兩大類,即已初始化段和未初始化段。4.2.2匯編器對段的處理

匯編器對段的處理是通過段偽指令區(qū)分出各個(gè)段,且將段名相同的語句匯編在一起。每個(gè)程序都可以由幾個(gè)段結(jié)合在一起形成。

匯編器有5個(gè)偽指令支持該功能,分別是:

.bss(未初始化段)

.usect(未初始化段)

.text(已初始化段)

.data(已初始化段)

.sect(已初始化段)

如果匯編語言程序中一個(gè)段偽指令都沒有用,那么匯編器把程序中的內(nèi)容都匯編到.text段。

1.未初始化段

未初始化段(UninitializedSections)由?.bss和?.usect偽指令建立。未初始化段就是TMS320C55X在目標(biāo)存儲器中的保留空間,以供程序運(yùn)行過程中的變量作為臨時(shí)存儲空間使用。在目標(biāo)文件中,這些段中沒有確切的內(nèi)容,通常將他們定位到RAM區(qū)。未初始化段分為默認(rèn)的和命名的兩種,分別由?.bss和?.usect產(chǎn)生,其句法如下:

.bss???符號,字?jǐn)?shù)

符號.usect“段名”,字?jǐn)?shù)

其中:符號——對應(yīng)于保留的存儲空間第一個(gè)字的變量名稱,這個(gè)符號可讓其它段引用,也可以用?.global命令定義為全局符號;

字?jǐn)?shù)——表示在?.bss段或標(biāo)有名字的段中保留多少個(gè)存儲單元;

段名——程序員為自定義未初始化段起的名字。

每調(diào)用?.bss偽指令一次,匯編器在相應(yīng)的段保留更多的空間;每調(diào)用?.usect偽指令一次,匯編器在指定的命名段保留更多的空間。

2.已初始化段

已初始化段(InitializedSections)由?.text、.data和?.sect偽指令建立,包含可執(zhí)行代碼或初始化數(shù)據(jù)。這些段中的內(nèi)容都在目標(biāo)文件中,當(dāng)加載程序時(shí)再放到TMS320C55X的存儲器中。每個(gè)初始化段都是可以重新定位的,并且可以引用其他段中所定義的符號。鏈接器在鏈接時(shí)自動處理段間的相互吸引。三種偽指令的句法如下:

.text [段起點(diǎn)]

.data [段起點(diǎn)]

.sect “段名”[,段起點(diǎn)]

其中,段起點(diǎn)是任選項(xiàng)。如果選用,它就是為段程序計(jì)數(shù)器(SPC)定義的一個(gè)起始值,SPC值只能定義一次,而且必須在第一次遇到這個(gè)段時(shí)定義。如果省略,則SPC從0開始。

當(dāng)匯編器遇到?.text、.data或?.sect命令時(shí),將停止對當(dāng)前段的匯編(相當(dāng)于一條結(jié)束當(dāng)前段匯編的命令),然后將緊接著的程序代碼或數(shù)據(jù),匯編到指定的段中,直到再遇到另一條?.text、.data或?.sect命令為止。

當(dāng)匯編器遇到?.bss或?.usect命令時(shí),并不結(jié)束當(dāng)前段的匯編,只是暫時(shí)從當(dāng)前段脫離出來,并開始對新的段進(jìn)行匯編。.bss和?.usect命令可以出現(xiàn)在一個(gè)已初始化段的任何位置上,而不會對它的內(nèi)容發(fā)生影響。段的構(gòu)成要經(jīng)過一個(gè)反復(fù)過程。例如,當(dāng)匯編器第一次遇到?.data命令時(shí),這個(gè)?.data段是空的,接著將緊跟其后的語句匯編到?.data段,直到匯編器遇到一條?.text或?.sect命令。如果匯編器再遇到一條?.data命令,他就將緊跟這條命令的語句匯編后加到已經(jīng)存在的?.data段中。這樣就建立了單一的?.data段,段內(nèi)數(shù)據(jù)都是連續(xù)地安排到存儲器中的。

3.自定義段

自定義段與缺省的?.text、.data和?.bss段一樣使用,但與缺省段分開匯編,也可將初始化的數(shù)據(jù)匯編到與?.data段不同的存儲器中,或者將未初始化的變量匯編到與?.bss段不同的存儲器中。產(chǎn)生命名段的偽指令為:

符號 .usect “段名”,字?jǐn)?shù)

.sect “段名”[,段起點(diǎn)]

4.子段

子段(Subsections)是大段中的小段。鏈接器可以像處理段一樣處理子段。采用子段可以使存儲器圖更加緊密。子段的命名句法為:

基段名:子段名

子段也有兩種,用?.sect命令建立的是已初始化段,用?.usect命令建立的是未初始化段。

5.段程序計(jì)數(shù)器(SPC)

匯編器為每個(gè)段安排一個(gè)獨(dú)立的程序計(jì)數(shù)器,即段程序計(jì)數(shù)器(SPC)。SPC表示一個(gè)程序代碼段或數(shù)據(jù)段內(nèi)的當(dāng)前地址。開始時(shí),匯編器將每個(gè)SPC置0,當(dāng)匯編器將程序代碼或數(shù)據(jù)加到一個(gè)段內(nèi)時(shí),相應(yīng)的SPC增加。如果匯編器再次遇到相同段名的段,繼續(xù)匯編至相應(yīng)的段,且相應(yīng)的SPC在先前的基礎(chǔ)上繼續(xù)增加。4.2.3鏈接器對段的處理

鏈接器在處理段的時(shí)候,有如下兩個(gè)主要任務(wù):

(1)將由匯編器產(chǎn)生的COFF格式的OBJ文件作為輸入塊;當(dāng)有多個(gè)文件進(jìn)行鏈接時(shí),將相應(yīng)的段結(jié)合在一起,產(chǎn)生一個(gè)可執(zhí)行的COFF輸出模塊。

(2)將輸出段分配到存儲器的指定地址,定義到實(shí)際的存儲空間中。有兩條鏈接命令支持上述任務(wù):

MEMORY命令——定義目標(biāo)系統(tǒng)的存儲器配置圖,包括對存儲器各部分命名,以及規(guī)定它們的起始地址和長度;

SECTIONS命令——告訴鏈接器如何將輸入段組合成輸出段,以及將輸出段放在存儲器中的什么位置。子段可用來更精細(xì)地編排段??捎面溄悠鞯腟ECTIONS命令指定子段。若沒有明顯的子段,則子段將和具有相同基段名稱的其他段結(jié)合在一起。鏈接器通過?.cmd文件來獲取上述的這些信息。

并不是總需要使用這些鏈接器命令的。若不使用它們,則鏈接器將使用目標(biāo)處理器默認(rèn)的分配方法。如果使用鏈接器命令,就必須在鏈接器命令文件中進(jìn)行說明。

鏈接器還將檢查各輸出段是否重疊、是否超界,避免了人工檢查邊界帶來的隱患。

圖4-1表示了鏈接器對段的處理。在圖4-1中,file1.obj和file22.obj已經(jīng)被匯編,作為鏈接器的輸入,都包含有缺省的?.text、.data、.bss段??蓤?zhí)行的輸出模式表示已合并的段。鏈接器先將兩個(gè)文件的?.text合并成一個(gè),再合并?.data和?.bss段,將自定義的段放在最后。圖4-1中的存儲器圖說明了如何將段放入存儲器,在缺省的情況下,鏈接器從地址080h開始依次放入。

圖4-1鏈接器對段的處理4.2.4重新定位

1.鏈接時(shí)重新定位

匯編器處理每個(gè)段都從地址0開始,而所有需要重新定位的符號(標(biāo)號)在段內(nèi)都是相對于地址0的。事實(shí)上,所有段都不可能從存儲器中地址0單元開始,因此鏈接器必須通過以下方法對各個(gè)段進(jìn)行重新定位:

(1)將各個(gè)段定位到存儲器圖中,每個(gè)段都從一個(gè)恰當(dāng)?shù)牡刂烽_始;

(2)將符號的數(shù)值調(diào)整到相對于新的段地址的數(shù)值;

(3)調(diào)整對重新定位后符號的引用。

匯編器在需要引用重新定位的符號處都留了一個(gè)重定位入口。鏈接器在對符號重定位時(shí),利用這些入口修正對符號的引用值。

2.運(yùn)行時(shí)重新定位

有時(shí),希望將代碼裝入存儲器的一個(gè)地方,而運(yùn)行在另一個(gè)地方。例如,一些關(guān)鍵的執(zhí)行代碼必須裝在系統(tǒng)的ROM中,但希望在較快的RAM中運(yùn)行。鏈接器提供一個(gè)處理該問題的簡單方法,利用SECTIONS偽指令選項(xiàng)可讓鏈接器定位兩次。第一次使用裝入關(guān)鍵字設(shè)置裝入地址,再用運(yùn)行關(guān)鍵字設(shè)置它的運(yùn)行地址。裝入地址確定段的原始數(shù)據(jù)或代碼裝入的地方,而任何對段的引用(例如其中的標(biāo)號)則參考它的運(yùn)行地址。在應(yīng)用中必須將該段從裝入地址復(fù)制到運(yùn)行地址,這并不能簡單地自動運(yùn)行,因?yàn)橹付ǖ倪\(yùn)行地址是分開的。若僅為段提供了一個(gè)定位(裝入或運(yùn)行),則該段將只定位一次,并且裝入和運(yùn)行地址相同;若提供兩個(gè)地址,則段將被自動地定位,就好像是兩個(gè)同樣大小的不同段一樣。

未初始化的段不能裝入,所以它僅有的有意義的地址為運(yùn)行地址。鏈接器只定位未初始化段一次。若為它指定運(yùn)行和裝入地址,則鏈接器將發(fā)出警告并忽略裝入地址。4.2.5程序裝入

鏈接器產(chǎn)生可執(zhí)行的COFF目標(biāo)文件??蓤?zhí)行的目標(biāo)模塊與鏈接器輸入的目標(biāo)文件具有相同的COFF格式,但在可執(zhí)行的目標(biāo)文件中,對段進(jìn)行結(jié)合并在目標(biāo)存儲器中進(jìn)行重新定位。為了運(yùn)行程序,在可執(zhí)行模塊中的數(shù)據(jù)必須傳輸或裝入目標(biāo)系統(tǒng)存儲器。有幾種方法可以用來裝入程序,取決于執(zhí)行環(huán)境。下面說明兩種常用的情況。

(1)硬件仿真器和CCS集成開發(fā)環(huán)境,具有內(nèi)部的裝入器,調(diào)用裝入器的LOAD命令即可裝入可執(zhí)行程序。

(2)將代碼固化在片外存儲器中,采用Hex轉(zhuǎn)換工具(Hexconversionutility),例如Hex500將可執(zhí)行的COFF目標(biāo)模塊(.out文件)轉(zhuǎn)換成幾種其他目標(biāo)格式文件,然后將轉(zhuǎn)換后的文件用編程器將代碼寫入EPROM/Flash。4.2.6.cmd文件

.cmd文件是用來分配ROM和RAM的,告訴鏈接程序怎樣計(jì)算地址和分配空間。它包括三個(gè)部分:

1.輸入/輸出定義

●?obj文件:鏈接器要鏈接的目標(biāo)文件;

●?lib文件:鏈接器要鏈接的庫文件;

●?map文件:鏈接器生成的交叉索引文件,?.map文件中能看到各“段”實(shí)際定位的情況,所以強(qiáng)烈建議鏈接產(chǎn)生此文件,便于對系統(tǒng)整個(gè)存儲空間的實(shí)際使用情況有清晰的理解;●?out文件:鏈接器生成的可執(zhí)行代碼;

●鏈接器選項(xiàng):這一部分現(xiàn)在基本上在CCS集成調(diào)試環(huán)境中的編譯選項(xiàng)中設(shè)置,所以在?.cmd文件中不再需要。

2.?MEMORY命令

該命令用來描述系統(tǒng)實(shí)際的硬件資源。

3.?SECTIONS命令

該命令用來描述“段”如何定位。

.cmd文件是存儲空間的分配文件,也就是要指明目標(biāo)板上實(shí)際的物理存儲空間是如何分配給DSP系統(tǒng)使用的,也就是程序要放在哪里,數(shù)據(jù)要放在哪里,堆棧放在哪里,中間向量表要放在哪里。

實(shí)際物理空間的分配一般與MP/MC、OVLY、DROM的設(shè)定或設(shè)置有關(guān),同時(shí)也與選用的DSP有關(guān)。比如同是54或55系列的,但是不同的DSP型號(比如5402、5410、5416、5502、5509等)內(nèi)部的SARAM和DARAM的大小是不同的,反過來這也確定你能使用的外部擴(kuò)展空間的地址范圍。

MEMORY指令分配哪些是程序區(qū)的地址范圍,哪里是中斷向量的入口,哪些是數(shù)據(jù)空間的地址范圍。

SECTIONS指令具體分配?.text段放在哪里,.data和?.bss放在哪里。自己指定的?.usect和?.sect段對應(yīng)在什么地方,等等。

這樣鏈接器就知道把各段不一定連續(xù)的代碼匯成?.out文件,才能load到DSP上去運(yùn)行。所以在用CCS自帶的tutorial例子時(shí)必須修改相應(yīng)的?.cmd文件,使之與目標(biāo)板上的物理空間能夠?qū)?yīng),這樣實(shí)際代碼才能load到DSP系統(tǒng)的存儲空間中,程序才能運(yùn)行起來。下面是任務(wù)2的?.cmd文件清單:

/*========hello.cmd========*/

MEMORY{

DATA(RWI):origin=0x6000,len=0x4000

PROG:origin=0x200,len=0x5e00

VECT:origin=0xd000,len=0x100

}

/*注:DATA后面的括號中為可選項(xiàng),規(guī)定存儲器的屬性:R,可對存儲器進(jìn)行讀操作;W,可對存儲器執(zhí)行寫操作;X命名的存儲器可能含有可執(zhí)行的代碼;I,可以對存儲器進(jìn)行初始化。origm:起始地址,可寫成org或o;length:長度,可寫成len或l。*/

SECTIONS

{

.vectors:{}>VECT

.trcinit:{}>PROG

.gblinit:{}>PROG

frt:{}>PROG

.text:{}>PROG

.cinit:{}>PROG

.pinit:{}>PROG

.sysinit:{}>PROG

.bss:{}>DATA

.far:{}>DATA

.const:{}>DATA

.switch:{}>DATA

.sysmem:{}>DATA

.cio:{}>DATA

.MEM$obj:{}>DATA

.sysheap:{}>DATA

.sysstack:{}>DATA

.stack:{}>DATA

}該?.cmd文件中的MEMORY部分定義了程序存儲空間、數(shù)據(jù)存儲空間、中斷向量的入口地址,其中程序存儲空間是從地址0x200開始,大小為0x5e00。SECTIONS部分中說明將?.text段存放在程序空間中,將?.bss段放在數(shù)據(jù)空間中等。

4.3.1尋址模式及指令系統(tǒng)

TMS320C55X的助記符指令是由操作碼和操作數(shù)兩部分組成的。在匯編前,操作碼和操作數(shù)都是用助記符表示的,例如:

LD#0FFH,A

該條指令的執(zhí)行結(jié)果是將立即數(shù)0FFH傳送至累加器A。

TMS320C55X和C54X類似,都提供7種基本的數(shù)據(jù)尋址方式:4.3DSP匯編程序簡介

(1)立即數(shù)尋址:指令中嵌有一個(gè)固定的立即數(shù)。

(2)絕對地址尋址:指令中有一個(gè)固定的地址,指令按照此地址進(jìn)行數(shù)據(jù)尋址。

(3)累加器尋址:將累加器內(nèi)的當(dāng)前值作為地址去訪問程序存儲器中的該單元。

(4)直接尋址:指令中的7bit是一個(gè)數(shù)據(jù)頁內(nèi)的偏移地址,而所在的數(shù)據(jù)頁由數(shù)據(jù)頁指針DP或SP決定。該偏移加上DP和SP的值決定了在數(shù)據(jù)存儲器中的實(shí)際地址。

(5)間接尋址:按照輔助寄存器中的地址訪問存儲器。

(6)存儲器映射寄存器尋址:修改存儲器映射寄存器中的值,而不影響當(dāng)前DP或SP的值,以存儲器映射寄存器中的修改值去尋址。

(7)堆棧尋址:把數(shù)據(jù)壓入和彈出系統(tǒng)堆棧,按照后進(jìn)先出原則進(jìn)行。

TMS320C54X和C55X可以使用兩套指令系統(tǒng):助記符方式和代數(shù)表達(dá)式方式。其可分成四種基本類型:

●算術(shù)指令;

●邏輯指令;

●程序控制指令;

●裝入和存儲指令。

在附錄里介紹了C54X的指令概要。4.3.2C55X匯編語言指令系統(tǒng)的特點(diǎn)

由于C55X指令集對C54X的兼容性,限于本書篇幅,這里就不再將C55X指令一一列出,僅在本小節(jié)后列出C54X的部分指令。C55X和C54X指令集最大的區(qū)別在于C55X結(jié)構(gòu)中比C54X增加的并行硬件,如雙MAC、雙ALU以及相應(yīng)增加的總線等。反映在指令集里,就是增加了并行指令,即在一個(gè)機(jī)器周期里可以并行完成的指令。

1.并行特性

C55X并行指令的種類有:

(1)單個(gè)指令里的內(nèi)在并行。有些指令可以并行地完成兩個(gè)操作,在助記符里用兩個(gè)冒號(∶∶)將兩個(gè)操作分開來表示。例如:

MPYAR3,CDP,AR0

∶∶MPYAR4,*CDP,AC1

該條指令表示用輔助寄存器AR3尋址得到的值,和用CDP尋址得到的值相乘,結(jié)果存入AR0。同時(shí),用輔助寄存器AR4尋址得到的值,和用CDP尋址得到的值相乘,結(jié)果存入AC1。

(2)用戶定義兩個(gè)指令并行。由用戶或C編譯器決定的并行,用‖將兩個(gè)指令分開來表示。例如:

MPYMAR1-,CDP,AC1

‖XORAR2,T1

第一個(gè)指令在D單元里運(yùn)行;第二個(gè)指令在A單元的ALU里運(yùn)行。

(3)隱含的并行和用戶定義的并行組合在一起。例如:

MPYMT3=*AR3+,AC1,AC2

‖MOV#5,ARl

第一個(gè)指令里已經(jīng)包含了并行性;第二個(gè)并行指令是由用戶定義的。

2.并行的規(guī)則

如果以下的所有規(guī)則都得到遵守的話,就只允許兩個(gè)指令并行。

(1)規(guī)則1:如果增加的指令長度不超過6byte,兩個(gè)指令可以并行。

(2)規(guī)則2:兩個(gè)指令可以并行需滿足:

①如果兩個(gè)指令中的一個(gè)具有并行使能位。這種由硬件支持的并行,稱為并行使能機(jī)制。

②如果兩個(gè)指令都像規(guī)則8所指定的,在間接尋址模式下訪問一個(gè)存儲器。硬件支持的這種類型的并行性,稱為軟件雙機(jī)制。

(3)規(guī)則3:如果存儲器總線、跨單元總線以及常數(shù)總線相互不妨礙,兩個(gè)指令可以并行。

(4)規(guī)則4:對A單元、D單元以及P單元之間的并行性沒有限制。

(5)規(guī)則5:處理器允許以下子單元之間的任何并行性:

①?P單元裝入通道;

②?P單元存儲通道;

③?P單元控制操作。

(6)規(guī)則6:處理器允許以下子單元之間的任何并行性:

①?D單元裝入通道;

②?D單元存儲通道;

③?D單元交換操作;

④?D單元的ALU、移位器、DMAC操作,被看成是一個(gè)操作;

⑤?D單元移位和存儲通道。

(7)規(guī)則7:除X、Y、C以及SP地址產(chǎn)生單元的操作,處理器允許以下子單元之間的任何并行性:

①?A單元裝入通道;

②?A單元存儲通道;

③?A單元交換操作;

④?A單元的ALU操作。

(8)規(guī)則8:數(shù)據(jù)地址產(chǎn)生單元(DAGEN)包含4個(gè)操作:

①?DAGENX和DAGENY是最常用的操作,允許產(chǎn)生以下的尋址模式:

●單個(gè)數(shù)據(jù)存儲器尋址Smem,db1(Lmem)

●間接雙數(shù)據(jù)存儲器尋址(Xmem,Ymem)

●系數(shù)數(shù)據(jù)存儲器尋址(Cmem)

●寄存器位尋址(Baddr)

②?DAGENX和DAGENY也在指令mar()里作指針修改;

③?DAGENC是一個(gè)專門的操作,用于系數(shù)數(shù)據(jù)存儲器尋址;

④?DAGENSP是一個(gè)專門的操作,用于數(shù)據(jù)及系統(tǒng)的堆棧尋址。

(9)規(guī)則9:如果在一個(gè)指令里使用了以下尋址修改,則該指令不能與其他指令并行:

①?*ARn(k16);

②?*+ARn(k16);

③?*CDP(k16);

④?*+CDP(k16);

⑤?*absl6(#k16);

⑥?*(#k23);

⑦?*port(#k16)。

(10)規(guī)則10:如果兩個(gè)并行的指令的目的資源沖突,則高地址的指令(第二個(gè)指令)更新目的資源。

4.4.1DSP軟件的設(shè)計(jì)方式

通常DSP芯片軟件設(shè)計(jì)有以下三種方式。4.4DSPC語言程序基礎(chǔ)

1.完全用C語言開發(fā)

TI公司提供了用于C語言開發(fā)的CCS平臺。該平臺包括了優(yōu)化ANSIC編譯器,從而可以在C源程序級進(jìn)行開發(fā)調(diào)試方式。這種方式大大提高了軟件的開發(fā)速度和可讀性,方便了軟件的修改和移植。但是,在某些情況下,C代碼的效率還是無法與手工編寫的匯編代碼的效率相比,如FFT編程。這是因?yàn)榧词棺罴训腃編譯器,也無法在所有的情況下都能夠最合理地利用DSP芯片所提供的各種資源。此外,用C語言實(shí)現(xiàn)DSP芯片的某些硬件控制也不如匯編程序方便,有些甚至無法用C語言實(shí)現(xiàn)。

2.完全用匯編語言開發(fā)

TI公司提供了用于匯編語言開發(fā)的針對TMS320C55X的匯編語言,用戶可以用它進(jìn)行軟件開發(fā)。此種方式可以更為合理地充分利用DSP芯片提供的硬件資源,其代碼效率高,程序執(zhí)行速度快,但是用DSP芯片的匯編語言編寫程序是比較繁雜的。一般來說,不同公司的芯片匯編語言是不同的,即使是同一公司的芯片,由于芯片類型的不同(如定點(diǎn)和浮點(diǎn)),芯片的升級換代,其匯編語言也不同。因此,用匯編語言開發(fā)基于某種DSP芯片的產(chǎn)品周期較長,并且軟件的修改和升級較困難,這些都是因?yàn)閰R編語言的可讀性和可移植性較差所致。

3.用C語言和匯編語言混合編程開發(fā)

為了充分利用DSP芯片的資源,更好地發(fā)揮C語言和匯編語言進(jìn)行軟件開發(fā)的各自的優(yōu)點(diǎn),可以將兩者有機(jī)結(jié)合起來,兼顧兩者的優(yōu)點(diǎn),避免其弊端。因此,在很多情況下,采用混合編程方法能更好地達(dá)到設(shè)計(jì)要求,完成設(shè)計(jì)功能。但是,采用C語言和匯編語言混合編程必須遵循一些有關(guān)的規(guī)則,否則會遇到一些意想不到的問題,給開發(fā)設(shè)計(jì)帶來許多麻煩。

因此,在DSP軟件的開發(fā)中我們應(yīng)該以C語言為主,并且在需要的情況下適當(dāng)采用匯編語言的混合編程的開發(fā)方法。4.4.2C語言軟件開發(fā)過程

在第3章中,我們了解了軟件開發(fā)過程涉及編譯器(compiler),匯編器(assembler),連接器(linker),歸檔器(archiver),建庫器(library-buildutility),運(yùn)行支持庫(runtimesupportlibrary),HEX轉(zhuǎn)換器(hexconversionutility),交叉引用列表器(crossreferencelister),絕對列表器(absolutelister)等。其大都設(shè)置既可通過命令,也可通過CCS的project\buildoptions設(shè)置。

圖4-2顯示了從.c文件到最終.hex文件簡化的軟件build流程。

圖4-2軟件build流程如前所述,在這過程中,目標(biāo)文件地址是浮動的,能被重定位,鏈接器用?.cmd文件對鏈接目標(biāo),進(jìn)行重定位,列出目標(biāo)文件、庫文件和鏈接器選項(xiàng),用MEMORY命令描述目標(biāo)系統(tǒng)存儲空間配置,用SECTIONS命令描述“段”如何定位。Hex轉(zhuǎn)換程序也使用.cmd文件,配置轉(zhuǎn)換選項(xiàng)。4.4.3C語言運(yùn)行環(huán)境

1.存儲模型

雖然,C語言是一種相對高效的高級語言,并且TI提供的C編譯器還結(jié)合硬件特點(diǎn)支持三級優(yōu)化功能,但生成的匯編代碼效率仍可能會不盡人意。因此,用戶對C編譯器究竟是如何進(jìn)行存儲分配的,應(yīng)有一定的了解。

C55X將存儲器處理為程序存儲器和數(shù)據(jù)存儲器兩個(gè)線性塊。程序存儲器包含可執(zhí)行代碼;數(shù)據(jù)存儲器主要包含外部變量、靜態(tài)變量和系統(tǒng)堆棧。編譯器的任務(wù)是產(chǎn)生可重定位的代碼,允許鏈接器將代碼和數(shù)據(jù)定位進(jìn)合適的存儲空間。

使用者可以使用系統(tǒng)定義的段也可以自己定義所需要的段。

1)系統(tǒng)定義

●?.cinit:存放C程序中的變量初值和常量;

●?.const:存放C程序中的字符常量、浮點(diǎn)常量和用const聲明的常量;

●?.switch:存放C程序中switch語句的跳針表;

●?.text:存放C程序的代碼;

●?.bss:為C程序中的全局和靜態(tài)變量保留存儲空間;

●?.far:為C程序中用far聲明的全局和靜態(tài)變量保留空間;

●?.stack:為C程序系統(tǒng)堆棧保留存儲空間,用于保存返回地址、函數(shù)間的參數(shù)傳遞、存儲局部變量和保存中間結(jié)果;

●?.sysmem:用于C程序中malloc、calloc和realloc函數(shù)動態(tài)分配存儲空間。

2)用戶定義

●?#pragmaCODE_SECTION(symbol,"sectionname");

●?#pragmaDATA_SECTION(symbol,"sectionname")。

其中.stack不同于DSP匯編指令定義的堆棧。DSP匯編程序中要將堆棧指針SP指向一塊RAM,用于保存中斷、調(diào)用時(shí)的返回地址,存放PUSH指令的壓棧內(nèi)容。

.stack定義的系統(tǒng)堆棧實(shí)現(xiàn)的功能是保護(hù)函數(shù)的返回地址,分配局部變量,在調(diào)用函數(shù)時(shí)用于傳遞參數(shù),保護(hù)臨時(shí)結(jié)果。

.stack定義的段大小(堆棧大小)可用鏈接器選項(xiàng)STACKSIZE設(shè)定,鏈接器還產(chǎn)生一個(gè)全局符號__STACK_SIZE,并賦給它等于堆棧長度的值,以字為單位,缺省值為1K。

2.寄存器使用規(guī)則

在C環(huán)境中,定義了嚴(yán)格的寄存器規(guī)則。寄存器規(guī)則明確了編譯器如何使用寄存器以及在函數(shù)調(diào)用過程中如何保護(hù)寄存器。調(diào)用函數(shù)時(shí),被調(diào)用函數(shù)負(fù)責(zé)保護(hù)某些寄存器,這些寄存器不必由調(diào)用者來保護(hù)。如果調(diào)用者需要使用沒有保護(hù)的寄存器,則調(diào)用者在調(diào)用函數(shù)前必須予以保護(hù)。下面具體說明寄存器規(guī)則:

(1)輔助寄存器AR1、AR6、AR7由被調(diào)用函數(shù)保護(hù),即可以在函數(shù)執(zhí)行過程中修改,但在函數(shù)返回時(shí)必須恢復(fù)。AR0、AR2、AR3、AR4、AR5可以自由使用,即在函數(shù)執(zhí)行過程中可以修改,而且不必恢復(fù)。

(2)堆棧指針SP在函數(shù)調(diào)用時(shí)必須予以保護(hù),但其是自動保護(hù)的,即在返回時(shí),壓入椎棧的內(nèi)容都將被全部彈出。

(3)?ARP在函數(shù)進(jìn)入和返回時(shí),必須為0,即當(dāng)前輔助寄存器為AR0。函數(shù)執(zhí)行時(shí)可以是其他值。

(4)在缺省的情況下,編譯器總是認(rèn)為OVM為0。因此,若在匯編程序中將OVM置為1,則在返回C環(huán)境時(shí),必須將其恢復(fù)為0。

(5)其他狀態(tài)位和寄存器在子程序中可以任意使用,不必恢復(fù)。

3.函數(shù)調(diào)用規(guī)則

C編譯器規(guī)定了一組嚴(yán)格的函數(shù)調(diào)用規(guī)則。除了特殊的運(yùn)行支持函數(shù)外,任何調(diào)用C函數(shù)或被C函數(shù)所調(diào)用的函數(shù)都必須遵循這些規(guī)則,否則就會破壞C環(huán)境,造成不可預(yù)測的結(jié)果。

1)參數(shù)傳遞

函數(shù)間的參數(shù)傳遞通過寄存器和系統(tǒng)堆棧進(jìn)行。函數(shù)調(diào)用前,將參數(shù)以逆序壓入運(yùn)行堆棧,即最右邊的參數(shù)最先入棧,然后自右向左將參數(shù)依次入棧。但是,對于TMS320C54X,在函數(shù)調(diào)用時(shí),第一個(gè)參數(shù)放入累加器A中進(jìn)行傳遞。若參數(shù)是長整型和浮點(diǎn)數(shù)時(shí),則低位字先壓棧,高位字后壓棧。若參數(shù)中有結(jié)構(gòu)形式,則調(diào)用函數(shù)給結(jié)構(gòu)分配空間,其地址通過累加器A傳遞給被調(diào)用函數(shù)。

2)結(jié)果返回

函數(shù)調(diào)用結(jié)束后,將返回值置于累加器A中。整數(shù)和指針在累加器A的低16位中返回;浮點(diǎn)數(shù)和長整型數(shù)在累加器A的32位中返回。

3)函數(shù)調(diào)用時(shí)需注意的一些問題

調(diào)用函數(shù)與被調(diào)用函數(shù)必須對各自的寄存器進(jìn)行保護(hù),從被調(diào)用函數(shù)返回前,被調(diào)用函數(shù)必須歸還所有已占用的堆棧空間。

4.?C語言和匯編語言的混合編程

C語言和匯編語言的混合編程有以下幾種方法。

獨(dú)立編寫匯編程序和C程序,分開編譯或匯編,形成各自的目標(biāo)代碼模塊,再用鏈接器將C模塊和匯編模塊鏈接起來。這種方法靈活性較大,但用戶必須自己維護(hù)各匯編模塊的入口和出口代碼,自己計(jì)算傳遞的參數(shù)在堆棧中的偏移量,工作量較大,但能做到對程序的絕對控制。

在C程序中直接內(nèi)嵌匯編語句。用此種方法可以在C程序中實(shí)現(xiàn)C語言無法實(shí)現(xiàn)的一些硬件控制功能,如修改中斷控制寄存器,中斷標(biāo)志寄存器等。將C程序編譯生成相應(yīng)的匯編程序,手工修改和優(yōu)化C編譯器生成的匯編代碼。采用此種方法時(shí),可以控制C編譯器,使之產(chǎn)生具有交叉列表的C程序和與之對應(yīng)的匯編程序,而程序員可以對其中的匯編語句進(jìn)行修改。優(yōu)化之后,對匯編程序進(jìn)行匯編,產(chǎn)生目標(biāo)文件。根據(jù)編者經(jīng)驗(yàn),只要程序員對C和匯編均很熟悉,這種混合匯編方法的效率可以做的很高。但是,由交叉列表產(chǎn)生的C程序?qū)?yīng)的匯編程序往往讀起來頗為費(fèi)勁,因此對一般程序員不提倡使用這種方法。下面就前面三種方法逐一介紹。

1)獨(dú)立的C模塊和匯編模塊接口

獨(dú)立的C模塊和匯編模塊接口是一種常用的C和匯編語言接口方法。采用此種方法在編寫C程序和匯編程序時(shí),必須遵循有關(guān)的調(diào)用規(guī)則和寄存器規(guī)則。如果遵循了這些規(guī)則,那么C和匯編語言之間的接口是非常方便的。C程序可以直接引用匯編程序中定義的變量和子程序,匯編程序也可以引用C程序中定義的變量和子程序。在編寫?yīng)毩⒌膮R編程序時(shí),必須注意以下幾點(diǎn):

(1)不論是用C語言編寫的函數(shù)還是用匯編語言編寫的函數(shù),都必須遵循寄存器使用規(guī)則。

(2)必須保護(hù)函數(shù)要用到的幾個(gè)特定寄存器。

(3)中斷程序必須保護(hù)所有用到的寄存器。

(4)從匯編程序調(diào)用C函數(shù)時(shí),第一個(gè)參數(shù)(最左邊)必須放入累加器A中,剩下的參數(shù)按自右向左的順序壓入堆棧。

(5)調(diào)用C函數(shù)時(shí),注意C函數(shù)只保護(hù)了幾個(gè)特定的寄存器,而其他是可以自由使用的。

(6)長整型和浮點(diǎn)數(shù)在存儲器中存放的順序是低位字在高地址,高位字在低地址。

(7)如果函數(shù)有返回值,返回值存放在累加器A中。

(8)匯編語言模塊不能改變由C模塊產(chǎn)生的?.cinit段,如果改變其內(nèi)容將會引起不可預(yù)測的后果。

(9)編譯器在所有標(biāo)識符(函數(shù)名、變量名等)前加下劃線“_”。

(10)任何在匯編程序中定義的對象或函數(shù),如果需要在C程序中訪問或調(diào)用,則必須用匯編指令?.global定義。

(11)編輯模式CPL指示采用何種指針尋址,如果CPL=1,則采用堆棧指針SP尋址;如果CPL=0,則選擇頁指針DP進(jìn)行尋址。下面給出具體例子。

C程序:

Externintasmfunc(); /*聲明外部的匯編子程序*/

/*注意函數(shù)名前不要加下劃線*/

intgvar; /*定義全局變量*/

main()

{

intI=3;

I=asmfunc(i); /*進(jìn)行函數(shù)調(diào)用*/

}匯編程序:

_asmfunc: ;函數(shù)名前一定要有下劃線

ADD*(-gvar),A ;I的值在累加器A中

STLA,*(-gvar) ;返回結(jié)果在累加器A中

RETD ;子程序返回

2)從C程序中訪問匯編程序變量

從C程序中訪問匯編程序中定義的變量或常數(shù)時(shí),根據(jù)變量和常數(shù)定義的位置和方法的不同,可分為三種情況。

(1)訪問在?.bbs段中定義的變量,方法如下:

①采用?.bss命令定義變量;

②用?.global將變量說明為外部變量;

③在匯編語言名前加下劃線“_”;

④在C程序中將變量說明為外部變量,然后就可以象訪問普通變量一樣訪問它。

(2)訪問未在.bbs段定義的變量,如當(dāng)C程序訪問在匯編程序中定義的常數(shù)表時(shí),則方法更復(fù)雜一些。此時(shí),定義一個(gè)指向該變量的指針,然后在C程序中間訪問它。在匯編程序中定義此常數(shù)表時(shí),最好定義一個(gè)單獨(dú)的段。然后,定義一個(gè)指向該表起始地址的全局標(biāo)號,可以在鏈接時(shí)將它分配至任意可用的存儲器空間。如果要在C程序中訪問它,則必須在C程序中以extern方式予以聲明,并且變量名前不必加下劃線“_”。這樣就可以像訪問其他普通變量一樣進(jìn)行訪問。

(3)對于那些在匯編中以.set和.global定義的全局常數(shù),也可以在C程序中訪問,不過要用到一些特殊的方法。一般說來,在C程序中和匯編程序中定義的變量,其符號表包含的是變量的地址。而對于匯編程序中定義的常數(shù),符號表包含的是常數(shù)值。編譯器并不能區(qū)分哪些符號表包含的是變量的地址,哪些是變量的值。因此,如果要在C程序中訪問匯編程序中的常數(shù),則不能直接用常數(shù)的符號名,而應(yīng)在常數(shù)符號名前加一個(gè)地址操作符&,以示與變量的區(qū)別,這樣才能得到常數(shù)值。

3)?C程序中直接嵌入?yún)R編語句

在C程序中直接嵌入?yún)R編語句是一種直接的C和匯編的接口方法。此種方法可以在C程序中實(shí)現(xiàn)C語言無法實(shí)現(xiàn)的一些硬件控制功能,如修改中斷控制寄存器、中斷標(biāo)志寄存器等。

嵌入?yún)R編語句的方法比較簡單,只需在匯編語句的兩邊加上雙引號和括號,并且在括號前加上asm標(biāo)識符即可。即:

asm("匯編語句");注意:括號中引號內(nèi)的匯編語句和語法通常的匯編編程的語法一樣。不要破壞C環(huán)境,因?yàn)镃編譯器并不檢查和分析嵌入的匯編語句。插入跳轉(zhuǎn)語句和標(biāo)號會產(chǎn)生不可預(yù)測的結(jié)果。不要讓匯編語句改變C程序中變量的值,不要在匯編語句中加入?yún)R編器選項(xiàng)而改變匯編環(huán)境。

修改編譯器的輸出可以控制C編譯器,從而產(chǎn)生具有交叉列表的匯編程序。而程序員可以對其中的匯編語句進(jìn)行修改,之后再對匯編程序進(jìn)行匯編,產(chǎn)生最終的目標(biāo)文件。注意,修改匯編語句時(shí)切勿破壞C環(huán)境。采用這種方法一方面可以在C程序中實(shí)現(xiàn)用C語言難以實(shí)現(xiàn)的一些硬件控制功能。另一方面,也可以用這種方法在C程序中的關(guān)鍵部分用匯編語句代替C語句以優(yōu)化程序。采用這種方法的一個(gè)缺點(diǎn)是它比較容易破壞C環(huán)境,因?yàn)镃編譯器在編譯嵌入了匯編語句的C程序時(shí)并不檢查或分析所嵌入的匯編語句。

4)何時(shí)使用混合編程技術(shù)

(1)當(dāng)程序中需要操作與硬件密切相關(guān)的設(shè)備,而用C語言較難實(shí)現(xiàn)時(shí)。比如:在中斷程序設(shè)計(jì)時(shí)需要設(shè)置中斷向量表,向量表中空間有限用C語言語句有困難,且需向量表要在內(nèi)存中精確定位,這時(shí)可將設(shè)置中斷向量表的部分用匯編語言代替。

(2)當(dāng)需要繞開C編譯器的規(guī)定,進(jìn)行特殊操作時(shí)。比如:C語言規(guī)定,程序不能訪問程序代碼區(qū),而系統(tǒng)功能需要進(jìn)行類似訪問時(shí)可采用限制較小的匯編語言程序設(shè)計(jì)。

(3)當(dāng)需要提高模塊的效率(包括空間上和時(shí)間上兩方面的),而C語言程序無法達(dá)到要求時(shí)。

5)使用混合編程時(shí)的注意事項(xiàng)

(1)在匯編程序中使用其他C語言模塊中定義的變量或函數(shù)名稱時(shí),需要在引用的名稱前加下劃線。如:C中定義的變量為x,在匯編中引用時(shí)要用_x。

(2)匯編語言寫的子程序需要符合C語言的調(diào)用規(guī)則,尤其是在默認(rèn)的輔助寄存器使用上和棧的使用上要求兼容。

(3)在匯編語言模塊中,需要編程者自己消除流水線沖突。

(4)在使用內(nèi)嵌匯編技術(shù)時(shí),需要考慮以下內(nèi)容:

①要非常小心地處理,以免破壞C語言操作環(huán)境。編譯器在遇到內(nèi)嵌匯編語句時(shí),不會對其中的匯編語句進(jìn)行分析處理。

②避免從內(nèi)嵌匯編語句跳轉(zhuǎn)到C語言模塊中,那將極容易造成寄存器使用上的混亂,從而產(chǎn)生難以預(yù)料的結(jié)果。

③不要在內(nèi)嵌匯編語句中改變C語言模塊中變量的值,但可以安全地讀取它們的值。

④在匯編程序中不要使用內(nèi)嵌匯編。

5.中斷服務(wù)程序

在編寫中斷服務(wù)程序時(shí)要注意以下問題。

(1)匯編語言編寫的中斷服務(wù)程序必須對所有用到寄存器進(jìn)行保護(hù),以免破壞C運(yùn)行環(huán)境。

(2)?C編寫的中斷服務(wù)程序應(yīng)用interrupt關(guān)鍵字聲明。(本書將在第5章中介紹DSP中斷的內(nèi)容)

6.系統(tǒng)初始化

在運(yùn)行C程序前,必須建立C運(yùn)行環(huán)境,此任務(wù)由C引導(dǎo)程序_c_int00完成。

_c_int00包含在庫函數(shù)中,build時(shí)自動將其鏈接到可執(zhí)行程序中,程序的入口地址必須設(shè)為_c_int00起始地址。在前面的任務(wù)之中,程序load以后,我們發(fā)現(xiàn)程序的指針指向_c_int00位置。

_c_int00的源程序存放在由rts.src分離出來的boot.asm中,用戶可根據(jù)需要修改,如:●設(shè)置堆棧指針。

●初始化全局變量:將.cinit段中數(shù)據(jù)拷貝到?.bss段中。

●調(diào)用C程序的主函數(shù)main()。

對于TI公司不同系列的DSP,其C編譯器對C運(yùn)行環(huán)境的處理略有不同,具體參考各自的C編譯器用戶指南。

4.5.1傳統(tǒng)軟件開發(fā)方法

在大多數(shù)的情況下,我們采用傳統(tǒng)的軟件開發(fā)方法。傳統(tǒng)的軟件開發(fā)方法按照以下的方法進(jìn)行:

(1)用匯編語言或C語言混合編程,從零開始。4.5TIDSP軟件開發(fā)平臺

(2)編寫硬件資源頭文件。

①?DSP片內(nèi)寄存器資源頭文件。

●描述片內(nèi)寄存器地址;

●描述片內(nèi)寄存器控制/狀態(tài)位域。

②板上資源頭文件。

●描述片外外設(shè)寄存器地址;

●描述片外外設(shè)寄存器控制/狀態(tài)位域。

(3)編寫應(yīng)用專用的外設(shè)驅(qū)動程序。

①片內(nèi)/片外外設(shè)初始化程序;

②片內(nèi)/片外外設(shè)操作程序。

(4)編寫應(yīng)用專用的算法。

(5)編寫主控程序順序、循環(huán)執(zhí)行。

傳統(tǒng)的軟件開發(fā)方法的程序結(jié)構(gòu)如圖4-3所示,主函數(shù)為一死循環(huán),循環(huán)內(nèi)順序執(zhí)行各程序模塊,如任務(wù)1。

圖4-3傳統(tǒng)軟件開發(fā)方法程序結(jié)構(gòu)圖當(dāng)然如果程序用到中斷(TMS320VC5509的中斷本書將在下章講述),程序的結(jié)構(gòu)就如圖4-4所示。

如圖4-4所示,程序在初始化之后就進(jìn)入一個(gè)內(nèi)容為空的死循環(huán)之中,等待中斷的到來,具體的任務(wù)在中斷子程序中執(zhí)行。用這種結(jié)構(gòu)開發(fā)的實(shí)時(shí)軟件,我們很難跟蹤它要發(fā)生的事件。

在這里要注意的是這兩種結(jié)構(gòu)與普通的C語言程序之間的區(qū)別,普通的C語言程序結(jié)構(gòu)如圖4-5所示,程序順序地執(zhí)行各個(gè)部分,直到結(jié)束,如第3章的任務(wù)2,因此任務(wù)2的程序并不能真正用于實(shí)際的DSP系統(tǒng),只是可以用來教學(xué)而已。圖4-4采用中斷的傳統(tǒng)軟件開發(fā)方法程序結(jié)構(gòu)圖

圖4-5普通的C語言程序結(jié)構(gòu)圖4.5.2TI倡導(dǎo)的DSP軟件架構(gòu)

1.?TI提供的基礎(chǔ)軟件

用傳統(tǒng)的方法,我們編寫程序要從零開始。實(shí)際上TMS320系列DSP的軟件開發(fā)無需從零開始,TI已經(jīng)為我們提供了一系列基礎(chǔ)軟件,這些基礎(chǔ)軟件包括:

●?CSL庫:ChipSupportLibrary芯片支持庫,已為我們定義了DSP片內(nèi)外設(shè)的資源,以及對片內(nèi)外設(shè)的基本操作。

●?DDK:DriverDevelopmentKit設(shè)備驅(qū)動程序開發(fā)包,設(shè)計(jì)標(biāo)準(zhǔn)的設(shè)備驅(qū)動程序模型,方便開發(fā)新的設(shè)備驅(qū)動程序?!?DSPLIB/IMGLIB:SignalProcessingLibrary信號處理庫,提供通用的、已充分優(yōu)化的數(shù)學(xué)運(yùn)算、矩陣運(yùn)算、FFT、濾波、卷積、相關(guān)等信號處理函數(shù),及壓縮、分析、濾波和格式轉(zhuǎn)換等圖像/視頻處理函數(shù)。

●?DSP/BIOS:嵌入式實(shí)時(shí)、多任務(wù)操作系統(tǒng),用于對實(shí)時(shí)、多任務(wù)進(jìn)行管理和調(diào)度,以及為實(shí)時(shí)分析提供相關(guān)的信息。

●?ReferenceFrameworks:程序參考架構(gòu),是一個(gè)C程序初始框架,通過其可以迅速創(chuàng)建特定的應(yīng)用程序?!?XDAIS:DSPAlgorithmStandard,DSP算法標(biāo)準(zhǔn),XDAIS規(guī)定一系列算法編程規(guī)則,只要遵循這些規(guī)則開發(fā)的算法,不同公司提供的算法也可以相互調(diào)用。

2.?TI倡導(dǎo)的DSP軟件架構(gòu)

TI倡導(dǎo)的DSP軟件架構(gòu)如圖4-6所示,以DSP/BIOS實(shí)時(shí)多任務(wù)操作系統(tǒng)為核心,由CSL實(shí)現(xiàn)片上外設(shè)的配置和控制,通過DDK提供一組標(biāo)準(zhǔn)的設(shè)備驅(qū)動程序模型(Driver),實(shí)現(xiàn)標(biāo)準(zhǔn)的外設(shè)數(shù)據(jù)流操作,外設(shè)數(shù)據(jù)流則由信號處理算法進(jìn)行處理。信號處理算法由兩部分組成,一部分是TI免費(fèi)提供的基礎(chǔ)的信號處理庫(SignalProcessingLibrary),另一部分為專用的算法,可由用戶自己編寫,或從TI眾多的第三方購買。為了使這些算法通用,TI專門定義了一套算法標(biāo)準(zhǔn)(TMS320DSPAlgorithmStandard),以此標(biāo)準(zhǔn)編寫的算法程序,可以實(shí)現(xiàn)相互調(diào)用。在此基礎(chǔ)上TI還專門針對不同的應(yīng)用系統(tǒng),設(shè)計(jì)了一套軟件參考架構(gòu)(ReferenceFramework),作為框架程序,方便用戶在此基礎(chǔ)上快速創(chuàng)建自己的應(yīng)用程序(UserApplication)。

圖4-6TI倡導(dǎo)的DSP軟件架構(gòu)

TI提供的基礎(chǔ)軟件架構(gòu),為創(chuàng)建設(shè)備驅(qū)動程序和應(yīng)用程序提供了基本的代碼,幫助用戶加速產(chǎn)品原型開發(fā),縮短開發(fā)周期,加快產(chǎn)品上市的速度。

那么采用了這種架構(gòu)后的軟件結(jié)構(gòu)發(fā)生了根本性的改變。這種方法為硬件中斷和用戶應(yīng)用軟件之間提供了一個(gè)層面。調(diào)度程序按照用戶定義的設(shè)置對不同的實(shí)時(shí)發(fā)生的硬件事件程序進(jìn)行優(yōu)化調(diào)用。這種方式提高了系統(tǒng)的實(shí)時(shí)性,也為日益復(fù)雜的片內(nèi)資源和外設(shè)管理提供了方便。圖4-7所示為采用了實(shí)時(shí)多任務(wù)操作系統(tǒng)的軟件結(jié)構(gòu)。

圖4-7采用實(shí)時(shí)多任務(wù)操作系統(tǒng)的軟件結(jié)構(gòu)

3.?DSP/BIOS

CCS是一個(gè)完整的DSP集成開發(fā)環(huán)境,所有的TIDSP都可以使用該軟件進(jìn)行開發(fā)。在CCS中,不僅集成了常規(guī)的開發(fā)工具,如源程序編輯器、代碼生成工具(編譯、鏈接器)以及調(diào)試環(huán)境外,還提供了DSP/BIOS開發(fā)工具。

DSP/BIOS是CCS提供的一套工具,它是一個(gè)簡易的嵌入式操作系統(tǒng),主要是為需要實(shí)時(shí)調(diào)度、同步,實(shí)時(shí)主機(jī)—目標(biāo)系統(tǒng)通信和實(shí)時(shí)監(jiān)測的應(yīng)用而設(shè)計(jì)的。DSP/BIOS集成在CCS中,不需要額外的費(fèi)用,但不提供源碼,它是TI公司倡導(dǎo)的eXpressDSP技術(shù)的重要組成部分。

1)

DSP/BlOS功能

(1)搶先型實(shí)時(shí)、多任務(wù)操作系統(tǒng)內(nèi)核。

●基于優(yōu)先級的、搶先型實(shí)時(shí)調(diào)度程序;

●支持多線程管理與調(diào)度;

●支持4種線程類型:HWI、SWI、TSK、IDL;

●支持3種作業(yè)間的通信方式:Mailboxes、Semaphores、Queues;

●支持周期函數(shù),方便實(shí)現(xiàn)固定時(shí)間間隔的數(shù)據(jù)采集,簡化多速率系統(tǒng)的設(shè)計(jì);

●提供存儲器管理,實(shí)現(xiàn)動態(tài)存儲器分配。

(2)實(shí)時(shí)分析模塊。

●分析信息實(shí)時(shí)獲取、傳輸和顯示,為早期的系統(tǒng)級排錯(cuò)提供幫助;

●?DSP/BIOS模塊中內(nèi)含分析信息的實(shí)時(shí)獲取功能;

●分析信息的實(shí)時(shí)傳輸由RTDX(Real-TimeDataExchange)技術(shù)實(shí)現(xiàn);

●完成目標(biāo)DSP與主機(jī)之間的實(shí)時(shí)通信,C6000RTDX的帶寬為20Kbyte;

●?RTDX是在idle作業(yè)期間完成的,所以對程序執(zhí)行速度的影響最??;

●主機(jī)可以顯示:事件記錄、線程執(zhí)行順序、執(zhí)行次數(shù)的最大值或平均值和總的CPU負(fù)載等信息。

2)

DSP/BIOS的使用

(1)為了方便使用,TI提供一個(gè)可視化的配置工具界面,如圖4-8所示,用于配置實(shí)際系統(tǒng)中所需的DSP/BIOS模塊。

圖4-8DSP/BIOS配置工具界面

(2)

DSP/BIOS是可裁剪的,只有被應(yīng)用程序使用的模塊才會被鏈接到應(yīng)用程序中。

(3)

DSP/BIOS開銷?。?/p>

●代碼大?。?KWords;

●?CPU占用:1MIPS。

(4)?DSP,BIOS采用標(biāo)準(zhǔn)的API,所以不同系列DSP之間的移植容易。

(5)?DSP/BIOS集成在CCS中,無需使用許可費(fèi)。

3)基于DSP/BIOS的程序開發(fā)流程

基于DSP/BIOS的程序開發(fā)是交互式的可反復(fù)的開發(fā)模式,開發(fā)者可以方便地修改線程的優(yōu)先級和類型,首先生成基本框架,添加算法之前給程序加上一個(gè)仿真的運(yùn)算負(fù)荷進(jìn)行測試,看是否滿足時(shí)序要求,然后再添加具體的算法實(shí)現(xiàn)代碼。使用DSP/BIOS開發(fā)軟件需要注意兩點(diǎn):

(1)所有與硬件相關(guān)的操作都需要借助DSP/BIOS本身提供的函數(shù)完成,開發(fā)者要避免直接控制硬件資源,如定時(shí)器、DMA控制器、串口、中斷等;

(2)基于DSP/BIOS的程序運(yùn)行與傳統(tǒng)的程序有所不同,傳統(tǒng)編寫的DSP程序完全控制DSP,程序依次執(zhí)行,而基于DSP/BIOS的程序,由DSP/BIOS程序控制DSP,用戶程序不是順序執(zhí)行,而是在DSP/BIOS的調(diào)度下按任務(wù)、中斷的優(yōu)先級等待執(zhí)行?;贒SP/BIOS的程序開發(fā)流程如下:

(1)利用配置工具設(shè)置環(huán)境參數(shù)并靜態(tài)建立應(yīng)用程序要用到的對象。要注意的是,在配置工具下創(chuàng)建對象為靜態(tài)創(chuàng)建,對象是不可以刪除的,利用xxx_create可以動態(tài)創(chuàng)建對象,并可以用xxx_delete刪除動態(tài)創(chuàng)建的對象(xxx表示模塊名字,如TSK)。

(2)保存配置文件。保存配置文件時(shí),配置工具自動生成匹配當(dāng)前配置的匯編源文件和頭文件以及一個(gè)鏈接命令文件。

(3)為應(yīng)用程序編寫一個(gè)框架,可以使用C、C++、匯編語言或這些語言的混合語言來編程。在CCS環(huán)境下編譯并鏈接程序,添加program.cdb和programcfg.cmd到項(xiàng)目工程文件中,其他的文件自動鏈接進(jìn)應(yīng)用程序。如果用戶想使用自己的鏈接命令文件,則需要在自己的命令文件的第一行包含語句“-lprogramcfg.cmd”。

(4)使用仿真器(或者使用硬件平臺原型)和DSP/BIOS分析工具來測試應(yīng)用程序。

(5)重復(fù)上述步驟直至程序運(yùn)行正確。

(6)在實(shí)際產(chǎn)品開發(fā)過程中,當(dāng)正式產(chǎn)品硬件開發(fā)好后,修改配置文件來支持產(chǎn)品硬件并測試。

4.?CSL(ChipSupportLibrary芯片支持庫)

(1)為什么要設(shè)計(jì)CSL?

DSP片上外設(shè)種類及其應(yīng)用日趨復(fù)雜。

②提供一組標(biāo)準(zhǔn)的方法用于訪問和控制片上外設(shè)。

③免除用戶編寫配置和控制片上外設(shè)所必需的定義和代碼。

(2)什么是CSL?

①用于配置、控制和管理DSP片上外設(shè)。

②已為C6000和C5000系列DSP設(shè)計(jì)了各自的CSL庫。

CSL庫函數(shù)大多數(shù)是用C語言編寫的,并已對代碼的大小和速度進(jìn)行了優(yōu)化。

CSL庫是可裁剪的,即只有被使用的CSL模塊才會包含進(jìn)應(yīng)用程序中。

CSL庫是可擴(kuò)展的:每個(gè)片上外設(shè)的API相互獨(dú)立,增加新的API,對其他片上外設(shè)沒有影響。

(3)

CSL的特點(diǎn)。

①提供了片上外設(shè)編程的標(biāo)準(zhǔn)協(xié)議,其定義了一組標(biāo)準(zhǔn)的API,包括函數(shù)、數(shù)據(jù)類

型、宏。

②定義一組宏,用于訪問和建立寄存器及其域值。

③基本的資源管理:對多資源的片上外設(shè)進(jìn)行管理。

④已集成到DSP/BIOS中:是通過圖形用戶接口GUI對CSL進(jìn)行配置。

⑤使片上外設(shè)容易使用:縮短開發(fā)時(shí)間,增加可移植性。

5.?DDK(DriverDevelopmentKit設(shè)備驅(qū)動程序開發(fā)包)

(1)

TI提供DDK的目的。DDK提供標(biāo)準(zhǔn)的設(shè)備驅(qū)動程序模型,使用戶無需從零開始編寫設(shè)備驅(qū)動程序。

(2)設(shè)備驅(qū)動程序模型(IOM)。

①將設(shè)備驅(qū)動程序分為兩個(gè)部分。

●與設(shè)備相關(guān)的:“迷你”驅(qū)動程序(mini-driver);

●與設(shè)備無關(guān)的:“類”驅(qū)動程序(class-driver)。②“類”驅(qū)動程序。

●設(shè)備驅(qū)動程序的上層抽象,使其與特定設(shè)備無關(guān),為應(yīng)用程序提供通用的接口;

3大類“類”驅(qū)動程序:SIO、PIP和GIO;

SIO:流I/O接口,由SIO和DIO組成,DIO負(fù)責(zé)緩沖器管理、信號同步以及底層“迷你”驅(qū)動程序接口;

PIP:管道接口,由PIP和PIO組成,PIO負(fù)責(zé)緩沖器管理、信號同步以及底層“迷你”驅(qū)動程序接口;

GIO:通用I/O,允許進(jìn)行塊讀塊寫,可以用其新的用戶驅(qū)動程序。

③“迷你”驅(qū)動程序:設(shè)備驅(qū)動程序的底層抽象,與特定設(shè)備有關(guān),對硬件設(shè)備進(jìn)行實(shí)際操作,DDK規(guī)定一組標(biāo)準(zhǔn)的API,函數(shù)體由用戶根據(jù)實(shí)際硬件設(shè)備編寫。

(3)

DDK在CSL基礎(chǔ)上對外設(shè)I/O進(jìn)行更高層次的抽象。

(4)

Tl免費(fèi)提供DDK的源代碼及相關(guān)文檔(可從TI網(wǎng)站上免費(fèi)下載)。

6.?SignalProcessingLibrary(信號處理庫)

C5000系列DSP基本的信號處理庫:

(1)?DSPLIB提供數(shù)學(xué)運(yùn)算、矩陣運(yùn)算、FFT、濾波、卷積等常用的信號處理函數(shù)。

●?TMS320C54XDSPLIB專門為C54X系列DSP進(jìn)行優(yōu)化;

●?TMS320C55XDSPLIB專門為C55X系列DSP進(jìn)行優(yōu)化。

(2)?IMGLIB提供壓縮、分析、濾波和格式轉(zhuǎn)換等常用的圖像/視頻處理函數(shù)。

●?TMS320C55XIMGLIB專門為C55X系列DSP進(jìn)行優(yōu)化。

TI免費(fèi)提供信號處理函數(shù)庫的源代碼、庫及相關(guān)文檔,可從TI網(wǎng)站上免費(fèi)下載。

7.?DSPAlgorithmStandard(DSP算法標(biāo)準(zhǔn),XDAIS)

(1)制定XDAIS的目的。

①?DSP軟件系統(tǒng)日趨復(fù)雜,算法由專業(yè)公司、專業(yè)人員開發(fā)。

②算法提供者和算法使用者分離。

③為了使二者協(xié)調(diào)工作,必須定義一組通用的編程規(guī)則和指導(dǎo)方針,以及一組編程接口。

④即使算法使用者和提供者相同,但只要符合XDAIS算法標(biāo)準(zhǔn),這些算法就可以用到不同的項(xiàng)目中,使算法具有良好的繼承性。

(2)開發(fā)符合標(biāo)準(zhǔn)的算法。TI提供一組工具用來開發(fā)符合標(biāo)準(zhǔn)的算法。

①?ComponentWizardControl:超級向?qū)?,幫助你快速、精確地將你的算法封裝為符合XDAIS標(biāo)準(zhǔn)的算法。

②?QuaiTI:測試工具,用于快速、有效地測試算法是否符合XDAIS標(biāo)準(zhǔn)。

③?DOSA:自動優(yōu)化工具,當(dāng)算法用于靜態(tài)環(huán)境時(shí),刪除算法中不必要的部分。

8.?ReferenceFrameWork(軟件參考架構(gòu))

(1)?TI提供軟件參考架構(gòu)的目的。

①?DSP系統(tǒng)日趨復(fù)雜。

●包含多個(gè)算法,如同時(shí)包含音頻算法和視頻算法;

●同一個(gè)算法可能需要多道運(yùn)行,如對多個(gè)視頻流進(jìn)行處理;

●不同算法或通道所需的數(shù)據(jù)或幀率可能不同,如音頻幀和視頻幀幀率不同;

●某些DSP硬件系統(tǒng)的存儲容量有限,如C54X系統(tǒng);

●軟件對象可能需要動態(tài)地創(chuàng)建和刪除,導(dǎo)致存儲器需要進(jìn)行動態(tài)管理;

●硬件系統(tǒng)可能為由DSP和通用處理器構(gòu)成的雙處理器系統(tǒng)。

TI精選一些通用的模塊,構(gòu)成軟件參考架構(gòu)。

③讓使用者將精力集中于系統(tǒng)的特定應(yīng)用方面。

(2)?TI根據(jù)系統(tǒng)的復(fù)雜程度已提供3個(gè)軟件參考架構(gòu)。

①?RF1:小型系統(tǒng),主要用于由C54X和C55X實(shí)現(xiàn)的低端系統(tǒng);

②?RF3:中型系統(tǒng),主要用于由C54X和C55X實(shí)現(xiàn)的高端系統(tǒng)和C6X實(shí)現(xiàn)的低端

系統(tǒng);

③?RF5:大型系統(tǒng),主要用于由C6X實(shí)現(xiàn)的高端系統(tǒng)。

一、任務(wù)目的

(1)學(xué)習(xí)用標(biāo)準(zhǔn)C語言編制程序;了解常用的C語言程序設(shè)計(jì)方法和組成部分。

(2)學(xué)習(xí)編制鏈接命令文件,并用來控制代碼的鏈接。

(3)學(xué)會建立和改變map文件,以及利用它觀察DSP內(nèi)存使用情況的方法。

(4)熟悉使用軟件仿真方式調(diào)試程序。任務(wù)3編寫一個(gè)以C語言為基礎(chǔ)的DSP程序

二、所需設(shè)備

PC兼容機(jī)一臺,操作系統(tǒng)為Windows2000(或Windows98、WindowsXP,以下默認(rèn)為Windows2000),安裝CCS(CodeComposerStudio)2.21軟件。三、相關(guān)原理

1.標(biāo)準(zhǔn)C語言程序

CCS支持使用標(biāo)準(zhǔn)C語言開發(fā)DSP應(yīng)用程序。當(dāng)使用標(biāo)準(zhǔn)C語言編制程序時(shí),其源程序文件名的后綴應(yīng)為?.c(如volume.c)。

CCS在編譯標(biāo)準(zhǔn)C語言程序時(shí),首先將其編譯成相應(yīng)匯編語言程序,再進(jìn)一步編譯成目標(biāo)DSP的可執(zhí)行代碼,最后生成的是COFF格式的可下載到DSP中運(yùn)行的文件,其文件名后綴為?.out。由于使用C語言編制程序,其中調(diào)用的標(biāo)準(zhǔn)C的庫函數(shù)由專門的庫提供,在編譯鏈接時(shí)編譯系統(tǒng)還負(fù)責(zé)構(gòu)建C運(yùn)行環(huán)境,所以用戶工程中需要注明使用C的支持庫。

另外,由于TMS320VC5509DSP的存儲器區(qū)域較大,程序中如果要使用大于64K的數(shù)據(jù)空間,需要設(shè)置C工程使用大模式、連接大模式庫。

2.命令文件的作用

命令文件(文件名后綴為?.cmd)為鏈接程序提供程序和數(shù)據(jù)在具體DSP硬件中的位置分配信息。通過編制命令文件,我們可以將某些特定的數(shù)據(jù)或程序按照我們的意圖放置在DSP所管理的內(nèi)存中。?命令文件也為鏈接程序提供了DSP外擴(kuò)存儲器的描述。在程序中使用cmd文件描述硬件存儲區(qū),可以只說明使用部分,但只要是說明的,必須和硬件匹配,也就是說只要說明的存儲區(qū)必須是存在的和可用的。

3.內(nèi)存映射(map)文件的作用

一般地,我們設(shè)計(jì)、開發(fā)的DSP程序在調(diào)試好后,要固化到系統(tǒng)的ROM中。為了更精確地使用ROM空間,我們就需要知道程序的大小和位置,通過建立目標(biāo)程序的map文件可以了解DSP代碼的確切信息。當(dāng)需要更改程序和數(shù)據(jù)的大小和位置時(shí),就要適當(dāng)修改cmd文件和源程序,再重新生成map文件來觀察結(jié)果。另外,通過觀察map文件,可以掌握DSP存儲器的使用和利用情況,以便進(jìn)行存儲器方面的優(yōu)化工作。

4.程序設(shè)計(jì)要求

程序框圖如圖4-9所示。

圖4-9任務(wù)3程序框圖

四、任務(wù)步驟

(1)準(zhǔn)備。

設(shè)置CCS為軟件仿真模式。

(2)建立新的工程文件。

①雙擊桌面上圖標(biāo),啟動CCS2.21。

②按照圖4-10所示的操作順序進(jìn)行設(shè)置,建立CProgram.pjt。

圖4-10建立CProgram.pjt

(3)設(shè)置工程文件。

按照圖4-11所示的操作步驟設(shè)置工程文件。

(4)編輯輸入源程序。

①?C語言程序。

a.首先新建源程序,如圖4-12所示。圖4-11設(shè)置工程文件

圖4-12新建源程序

b.輸入源程序:

main()

{

intx,y,z;

x=1;y=2;

while(1)

{

z=x+y;

}

}

c.保存源程序?yàn)镃Program.c,如圖4-13所示。

圖4-13保存源程序?yàn)镃Program.pjt②?.cmd文件。

a.如同C語言程序的第a操作,建立空的源程序。

b.輸入鏈接命令文件內(nèi)容:

-lrts55x.lib

MEMORY

{

DARAM:o=0x100,l=0x7f00

DARAM2:o=0x8000,l=0x8000

}

SECTIONS

{

.text:{}>DARAM

.bss:{}>DARAM

.stack:{}>DARAM

.cinit:{}>DARAM

}

注意:第1行中減號后面和第5、6行中等號前邊字母是小寫的“L”。

c.如同C語言程序的第c步操作,將文件在項(xiàng)目文件夾下保存為CProgram.cmd。

在鏈接命令文件中,將可用內(nèi)存分為兩塊:DARAM和DARAM2,而在其后指定程序只占用DARAM塊,DARAM2留作其他用途(此程序未使用)。另外,第1句指定編譯器使用庫rts55x.lib,這是一個(gè)大模式庫。

③將上述編譯的源程序加入工程CProgram.pjt。

(5)編譯源文件、下載可執(zhí)行程序。

①單擊菜單“Project”、“RebuildAll”。

②執(zhí)行File→LoadProgram,在隨后打開的對話框中選擇剛剛建立的項(xiàng)目文件夾下的\debug\CProgram.out文件。完成后,系統(tǒng)自動打開一個(gè)反匯編窗口“Disassembly”,并在其中指示程序的入口地址

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論