DSP的CMD文件 & RUN_START

DSP的存儲器的地址範圍,CMD是主要是根據那個來編的。
CMD 它是用來分配rom和ram空間用的,告訴連接程序怎樣計算地址和分配空間.
因此不一樣的芯片就有不一樣大小的rom和ram.放用戶程序的地方也不盡相同.因此要根據芯片進行修改.分兩部分.MEMORY和SECTIONS.
MEMORY
{ PAGE 0 ..........
PAGE 1.........
}
SECTIONS
{SECTIONS
{
.vectors .................
.reset .................
................
}
MEMORY是用來指定芯片的rom和ram的大小和劃分出幾個區間.
PAGE 0 對應romAGE 1對應ram
PAGE 裏包含的區間名字與其後面的參數反映了該區間的起始地址和長度.
SECTIONS:(在程序裏添加下面的段名如.vectors.用來指定該段名如下,
另外一個段名以上的程序(屬於PAGE0)或數據(屬於PAGE1)放到「>」符號後的空間名字所在的地方。

SECTIONS
{
.vectors : { } > VECS PAGE 0
.reset : { } > VECS PAGE 0
............
............
..........
}
eg:
MEMORY
{
PAGE 0: VECS: origin = 00000h, length = 00040h
LOW: origin = 00040h, length = 03FC0h
SARAM: origin = 04000h, length = 00800h
B0: origin = 0FF00h, length = 00100h
PAGE 1: B0: origin = 00200h, length = 00100h
B1: origin = 00300h, length = 00100h
B2: origin = 00060h, length = 00020h
SARAM: origin = 08000h, length = 00800h
}
SECTIONS
{
.text : { } > LOW PAGE 0
.cinit : { } > LOW PAGE 0
.switch : { } > LOW PAGE 0
.const : { } > SARAM PAGE 1
.data : { } > SARAM PAGE 1
.bss : { } > SARAM PAGE 1
.stack : { } > SARAM PAGE 1
.sysmem : { } > SARAM PAGE 1
}

由三部分組成:
輸入/輸出定義:這一部分,能夠經過ccs的「Build Option........」菜單設置
          。obj 連接的目標文件
          。lib 連接的庫文件
          。map 生成的交叉索引文件
          。out 生成的可執行代碼
MEMORY命令:描述系統實際的硬件資源
SECTION命令:描述「段」如何定位
例子
.cmd文件
-c
-o hello.out
-m hello.map
-stack 100
-l rts2xx.lib
MEMORY
{
    PAGE 0: VECT:origin=0x8000,length 0x040
    PAGE 0: PROG:origin=0x8040,length 0x6000
    PAGE 1: DATA:origin=0x8000,length 0x400
}
SECTIONS
{
.vextors >VECT PAGE 0
.text >PROG PAGE 0
.bss >DATA PAGE 1
.const >DATA PAGE 1
}
存儲模型:c程序的代碼和數據如何定位
系統定義
.cinit 存放程序中的變量初值和常量
.const 存放程序中的字符常量、浮點常量和用const聲明的常量
.switch 存放程序中switch語句的跳轉地址表
.text 存放程序代碼
.bss 爲程序中的全局和靜態變量保留存儲空間
.far 爲程序中用far聲明的全局和靜態變量保留空間
.stack 爲程序系統堆棧保留存儲空間,用於保存返回地址、函數間的參數傳遞、存儲局部變量和保存中間結果
.sysmem 用於程序中的malloc 、calloc 、和realoc 函數動態分配存儲空間

CMD的專業名稱叫連接器配置文件,是存放連接器的配置信息的,咱們簡稱爲命令文件,其中比較關鍵的就是MEMORY和SECTIONS兩個僞指令的使用,經常使人困惑,系統出現的問題也常常與它們的不當使用有關。CCS是DSP軟件對DOS系統繼承的開發環境,CCS的命令文件通過DOS命令文件長時間的引伸發展,已經變得很是簡潔(不知道TI文檔有沒有詳細CMD配置說明)。我學CMD是從DOS裏的東西開始的,因此也從DOS環境下的CMD提及:

1命令文件的組成
命令文件的開頭部分是要連接的各個子目標文件的名字,這樣連接器就能夠根據子目標文件名,將相應的目標文件連接成一個文件;接下來就是連接器的操做指令,這些指令用來配置連接器,接下來就是MEMORY和SECTIONS兩個僞指令的相關語句,必須大寫。MEMORY,用來配置目標存儲器,SECTIONS用來指定段的存放位置。結合下面的典型DOS環境的命令文件link.cmd來作一下說明:
file.obj //子目標文件名1
file2.obj //子目標文件名2
file3.obj //子目標文件名3
- o prog.out //鏈接器操做指令,用來指定輸出文件
- m prog.m //用來指定MAP文件
MEMORY
{ 略 }
SECTIONS
{ 略 }
otherlink.cmd
本命令文件link.cmd要調用的otherlink.cmd等其餘命令文件,則文件的名字要放到本命令文件最後一行,由於放開頭的話,連接器是不會從被調用的其餘命令文件中返回到本命令文件。

2 MEMORY僞指令
MEMORY用來創建目標存儲器的模型,SECTIONS指令就能夠根據這個模型來安排各個段的位置,MEMORY指令能夠定義目標系統的各類類型的存儲器及容量。MEMORY的語法以下:
MEMORY
{
PAGE 0 : name1[(attr)] : origin = constant,length = constant
          name1n[(attr)] : origin = constant,length = constant
PAGE 1 : name2[(attr)] : origin = constant,length = constant
          name2n[(attr)] : origin = constant,length = constant
PAGE n : namen[(attr)] : origin = constant,length = constant
          namenn[(attr)] : origin = constant,length = constant
}
PAGE關鍵詞對獨立的存儲空間進行標記,頁號n的最大值爲255,實際應用中通常分爲兩頁,PAGE0程序存儲器和PAGE1數據存儲器。
name存儲區間的名字,不超過8個字符,不一樣的PAGE上能夠出現相同的名字(最好不用,免的搞混),一個PAGE內不準有相同的name。
attr的屬性標識,爲R表示可讀;W可寫X表示區間能夠裝入可執行代碼;I表示存儲器能夠進行初始話,什麼屬性代碼也不寫,表示存儲區間具備上述的四種屬性,基本上咱們都選擇這種寫法。
origin:略。
length:略。
下面是常常用的2407的簡單寫法你們參考,程序從0x060開始,要避開加密位,不從0x0044開始更可靠一點,此例中的同名的頁能夠只寫第一個,其後省略,但寫上至少安全一點:
MEMORY
{
PAGE 0: VECS: origin = 0x0000, length 0x40
PAGE 0: PROG: origin = 0x0060, length 0x6000
PAGE 1: B0 : origin = 0x200, length 0x100
PAGE 1: B1 : origin = 0x300, length 0x100
PAGE 1: DATA: origin = 0x0860, length 0x0780
}

3 SECTIONS僞指令
SECTIONS指令的語法以下:
SECTIONS
{
.text: {全部.text輸入段名} load=加載地址 run =運行地址
.data: {全部.data輸入段名} load=加載地址 run =運行地址
.bss: {全部.bss輸入段名} load=加載地址 run =運行地址
.other: {全部.other輸入段名} load=加載地址 run =運行地址
}
SECTIONS必須用大寫字母,其後的大括號裏是輸出段的說明性語句,每個輸出段的說明都是從段名開始,段名以後是如何對輸入段進行組織和給段分配存儲器的參數說明:
.text段的屬性語句爲例,「{全部.text輸入段名}」這段內容用來講明鏈接器輸出段的.text段由哪些子目標文件的段組成,舉例以下
SECTIONS
{
.text:{ file1.obj(.text) file2(.text) file3(.text,cinit)}
}
指明輸出段.text要連接file1.obj的.text和 file2的.text 還有file3的.text和.cinit。在CCS的SECTIONS裏一般只寫一箇中間沒有內容的「{ }」就表示全部的目標文件的相應段
接下來講明「load=加載地址 run =運行地址」連接器爲每一個輸出段都在目標存儲器裏分配兩個地址:一個是加載地址,一個是運行地址。一般狀況下兩個地址是相同的,能夠認爲輸出段只有一個地址,這時就能夠不加「run =運行地址」這條語句了;但有時須要將兩個地址分開,好比將程序加載到FLASH,而後放到RAM中高速運行,這就用到了運行地址和加載地址的分別配置了,以下例所示:
.const :{略} load = PROG run = 0x0800
常量加載在程序存儲區,配置爲在RAM裏調用。
「load=加載地址」的幾種寫法須要說明一下,首先「load」關鍵字能夠省略,「=」能夠寫成「>, 「加載地址」能夠是:地址值、存儲區間的名字、PAGE關鍵詞等,因此你們見到「.text:{ } > 0x0080」這樣的語句可千萬不要奇怪。「run =運行地址」中的「 = 」能夠用「>」,其它的簡化寫法就沒有了。你們不要亂用。

4 CCS中的案例
在CCS中的命令文件好像簡化了很多,少了不少東西,語句也精簡了好多,首先不用指定輸入連接器的目標文件,CCS會自動默認處理,其次連接器的配置命令也和DOS的環境不一樣,須要瞭解的請找TI文檔吧!下面是劉和平書中的例子,你們來看看是否是能夠很精確的理解了呢!
-stack 40



MEMORY
{
PAGE 0 : VECS : origin = 0h , length = 40h
       PVECS : origin = 40h , length = 70h
       PROG : origin = 0b0h , length = 7F50h
PAGE 1 : MMRS : origin = 0h , length = 05Fh
     B2 : origin = 0060h , length = 020h
     B0 : origin = 0200h , length = 100h
     B1 : origin = 0300h , length = 100h
SARAM : origin = 0800h , length = 0800h
EXT : origin = 8000h , length = 8000h
}



SECTIONS
{
    .reset : { } > VECS PAGE 0
    .vectors : { } > VECS PAGE 0
    .pvecs : { } > PVECS PAGE 0
    .text : { } > PROG PAGE 0
    .cinit : { } > PROG PAGE 0
    .bss : { } > SARAM PAGE 1
    .const : { } > SARAM PAGE 1
    .stack : { } > B1 PAGE 1
}



第二章 CMD文件的編寫



1. COFF格式

1> 通用目標文件格式(Common Object File Format)是一種流行的二進制可執行文件格式,二進制可執行文件包括庫文件(lib),目標文件(obj)最終可執行文件(out)。,現今PC機上的Windows95和NT4.0之後的操做系統的二進制文件格式(PE)就是在COFF格式基礎上的進一步擴充。

2> COFF格式:詳細的COFF文件格式包括段頭,可執行代碼和初始化數據,可重定位信息,行號入口,符號表,字符串表等,這些屬於編寫操做系統和編譯器人員關心範疇。而對於C只須要了解定義段和給段分配空間就能夠了。

3> 採用COFF更有利於模塊化編程,程序員能夠自由決定願意把哪些代碼歸屬到哪些段,而後加以不一樣的處理。

2. Section目標文件中最小單位稱爲塊。一個塊就是最終在存儲器映象中佔據連續空間的一段代碼或數據。

1> COFF目標文件包含三個默認的塊:

.text可執行代碼

.data已初始化數據

.bss爲未初始化數據保留的空間

2> 彙編器對塊的處理

未初始化塊

                        .bss 變量存放空間

                        .usect 用戶自定義的未初始化段

初始化塊

                        .text 彙編指令代碼

                        .data 常數數據(好比對變量的初始化數據)

                        .sect 用戶自定義的已初始化段 程序員

                       .asect 通.sect,多了絕對地址定位功能,通常不用

          3>C語言的段

未初始化塊(data)

                        .bss 存放全局和靜態變量

                        .ebss 長調用的.bss(超過了64K地址限制)

                        .stack 存放C語言的棧

                        .sysmem 存放C語言的堆

                        .esysmem 長調用的.sysmem(超過了64K地址限制)

初始化塊

                        .text 可執行代碼和常數(program)

                        .switch switch語句產生的常數表格(program/低64K數據空間)

                                           .pinit Tables for global constructors (C++)(program)

                        .cinit 用來存放對全局和靜態變量的初始化常數值(program)

                        .const 全局和靜態的const變量初始化值和字符串常數,(data)

                        .econst 長.const(可定位到任何地方)(data)

3> 自定義段(C語言)

#pragma DATA_SECTION(函數名或全局變量名,"用戶自定義在數據空間的段名");

#pragma CODE_SECTION(函數名或全局變量名,"用戶自定義在程序空間的段名");

不能在函數體內聲明。

必須在定義和使用前聲明

#pragma能夠阻止對未調用的函數的優化

3. 鏈接命令文件(CMD)

1> MEMORY指定存儲空間

MEMORY
{
PAGE 0:
   name 0 [attr] : origin = constant, length = constant

PAGE n:
      name n [attr] : origin = constant, length = constant

}

PAGE n:標示存儲空間,n SECTIONS分配段

    SECTIONS

{

name : [property,property,……]

}

name:輸出段的名稱

property:輸出段的屬性:

    load=allocation(強制地址或存儲空間名稱)同>allocation:定義輸出段將會被裝載到哪裏。

    run= allocation(強制地址或存儲空間名稱)同>allocation:定義輸出段將會在哪裏運行。

注:CMD文件中只出現一個關鍵字load或run時,表示二者的地址時表示二者的地址時重合的。

    PAGE = n,段位於那個存儲頁面空間。

例:ramfuncs : LOAD = FLASHD,

                          RUN = RAML0,

                          LOAD_START(_RamfuncsLoadStart),

                          LOAD_END(_RamfuncsLoadEnd),

                          RUN_START(_RamfuncsRunStart),

                          PAGE = 0

  

3> 直接寫編譯命令

-l rts2800_ml.lib 鏈接系統文件rts2800_ml.lib

-o filename.out 最終生成的二進制文件命名爲filename.out

-m filename.map 生成映射文件filename.map

-stack 0x200 堆棧爲512字

    4. .const段:

       由關鍵字const限定的全局變量(const限定的局部變量不產生)初始化值,和出如今表達式(作指針使用,而用來初始化字符串數組變量不產生)中的字符串常數,另外數組和結構體是局部變量時,其初始值會產生.const段,而全局時不產生。 編程

 

 

 

 

 

[關於LOAD_START, LOAD_END, RUN_START]

首先, Flash28_API 和 ramfuncs 是兩個段名,{...}大括號中表示這個段的內容,若是爲空則表示所有內容。

其次,LOAD和RUN是段的兩個屬性,分別規定段將裝載在存儲器內何處以及在存儲器內何處運行。

再次,LOAD_START, LOAD_END, RUN_START 這幾個並不是是參數,而是可以生成指全局符號的指令,生成的全局符號決定了裝載地址、運行地址、段長度(這裏是:Flash28_API_LoadStart, Flash28_API_LoadEnd 和Flash28_API_RunStart)

最後,要了解以上的工做只是在cmd中定義了段的屬性,意思是說,Flash28_API 這個段將裝載入FLASH,而須要在RAM中運行。所以要把FLASH中的地址複製到RAM區中去,那麼你須要再作一步工做:在main中的初始化代碼段中,調用支持庫裏面的函數memcpy()將上面定義的段從FLASH中的地址複製到RAM區。
數組

memcpy(&Flash28_API_RunStart, &Flash28_API_LoadStart, 安全

        &Flash28_API_LoadEnd-&Flash28_API_LoadStart)
這樣纔算完整。


補充:爲何須要將一些段從FLASH中複製到RAM中運行

1,初始化中斷向量。因爲上電時,外設擴展中斷(PIE)的中斷向量必須位於非易失性存儲器(如Flash)中,所以初始化時必需要把中斷向量從FLASH中拷貝到PIEVECT RAM中,完成中斷向量表的初始化。


2,初始化Flash控制寄存器。Flash控制寄存器FOPT、FPWR、:FSTDBY-WAIT、FACTIVEWAIT、FBANKWAIT、FOTPWAIT的初始化代碼不能從Flash存儲器當中運行.不然就會有不可預料的結果出現。因此,Flash控制寄存器的初始化函數在運行時必須從Flash(它的裝載地址)拷貝到RAM(它的運行地址)。同時要注意的是,Flash控制寄存器由Code Security Module(CSM)保護。若是CSM被保護起來了,那麼必須從被保護的RAM(例如:L0或者L1 SARAM)運行Flash控制寄存器的初始化代碼,不然Flash控制寄存器的初始化代碼沒法訪問Flash控制寄存器。


3,性能最優化。因爲分立式嵌入式系統要求全部的初始化數據最初都是位於非易失性存儲器中(如FLASH),訪問片上RAM中的常數與常數表必須花費多個時鐘去訪問FLASH,爲提升效率,必須爲想訪問的RAM中的常數創建獨立的裝載和運行地址。在運行時把這些常數從片上Flash中拷貝到RAM中。
模塊化

相關文章
相關標籤/搜索