1. 程式人生 > >超詳細的CMD檔案講解(DSP28035)

超詳細的CMD檔案講解(DSP28035)

一、 CMD檔案基本概念及語法
CMD的專業名稱叫連結器配置檔案,是存放連結器的配置資訊的,我們簡稱為命令檔案。從其名稱可以看出,該檔案的作用是指明如何連結程式的。
那麼我們知道,在編寫TI DSP程式時,是可以將程式分為很多段,比如text、bss等,各段的作用均不相同。實際在片中執行時,所處的位置也不相同。比如text程式碼一般應該放在flash內,而bss的變數應該放在ram內。等等。但是對於不同的晶片,其各儲存器的起止地址都是不一樣的,而且,使用者希望將某一段,尤其是自定義段,放在什麼儲存器的什麼位置,這也是連結器不知道的。為了告訴連結器,即將使用的晶片其內部儲存空間的分配和程式各段的具體存放位置,這就需要編寫一個配置檔案,即CMD檔案了。
所以,CMD檔案裡面最重要的就是兩段,即由MEMORY和SECTIONS兩個偽指令指定的兩段配置。簡單的說,MEMORY就是用來建立目標儲存器的模型,而SECTIONS指令就是根據這個模型來安排各個段的位置。
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 表示儲存器可以進行初始話,什麼屬性程式碼也不寫,表示儲存區間具有上述的四種屬性,基本上我們都選擇這種寫法。下面為例子:
MEMORY
{
PAGE 0 :
BEGIN : origin = 0x000000, length = 0x000002
RAMM0 : origin = 0x000050, length = 0x0003B0
PAGE 1 :
RAMM1 : origin = 0x000480, length = 0x000380
RAML2 : origin = 0x008C00, length = 0x000400
}
SECTIONS 偽指令

SECTIONS 指令的語法如下:
SECTIONS
{
.text: {所有.text 輸入段名} load=載入地址 run =執行地址
.cinit: {所有.data 輸入段名} load=載入地址 run =執行地址
.bss: {所有.bss 輸入段名} load=載入地址 run =執行地址
.other: {所有.other 輸入段名} load=載入地址 run =執行地址
} 例如: .text : > RAML0L1, PAGE = 0
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 =執行地址”中的“ = ”可以用“>”,其它的簡化寫法就沒有了。大家不要亂用。
自定義段(C 語言)


#pragma DATA_SECTION(全域性變數名,"使用者自定義在資料空間的段名");
#pragma CODE_SECTION(函式名,"使用者自定義在程式空間的段名");

CODE_SECTION用來定義程式碼段
DATA_SECTION用來定義資料段
例如:在c檔案中定義了一個data段my_sect和一個code段ramfuncs,如下:

#pragma DATA_SECTION(bufferB, ”my_sect”)
char bufferB[512];
#pragma CODE_SECTION(dragon_update,"ramfuncs");
Uint16 dragon_update(UPDATE_SOURCE_TYPE *update_flag)
{
    。。。
}

然後再在cmd檔案中指定這兩個section的位置就可以了。
如果想在彙編中指定段,使用方法,在程式碼前用.sect “XXX”開始則標示接下來的一段程式碼都是在xxx的程式碼段中。
例子:

PieVectTableFile : > PIE_VECT,   PAGE = 1            // nonBIOS. cmd
#pragma DATA_SECTION(PieVectTable,"PieVectTableFile");   // globalVariableDefs.c
struct PIE_VECT_TABLE PieVectTable;                     // globalVariableDefs.c

注意:
不能再函式體內宣告#pragma;
必須在符號被定義和使用之前宣告#pragma

#pragma 可以阻止對未呼叫的函式的優化

這裡寫圖片描述
備註:
CMD 檔案中還可以寫上註釋,用“/”和“/”包圍起來,但不允許用“//” ,這一點和 C 語言不同。
可以直接在CMD檔案中寫編譯命令,如:
-l rts2800_ml.lib 連線系統檔案rts2800_ml.lib
-o filename.out 最終生成的二進位制檔案命名為filename.out
-m filename.map 生成對映檔案filename.map
二、DSP 28035的記憶體對映圖如下:
這裡寫圖片描述
這裡寫圖片描述
三、 燒寫FLASH的CMD檔案示例及註解(F28035.cmd)

//###########################################################################
// 檔案:  F28035.cmd
// 說明:  F28035連線命令檔案
//###########################################################################
/* 
定義F28035記憶體塊的起始地址及長度
PAGE 0 為程式碼段
PAGE 1 為資料段
注意:
F2803x的記憶體塊對於PAGE 0和PAGE 1是共用的。
同一個記憶體塊不能同時定義為PAGE 0和PAGE 1。會造成程式的混亂。
L0記憶體塊是被映象的:可以在高地址記憶體或都低地址記憶體被訪問。
在這裡只使用低地址記憶體。當需要一片很大的的記憶體塊時,SARAM記憶體塊
或者FLASH段可以連線在一起。
*/
MEMORY
{
PAGE 0:    /* 程式記憶體塊 */
   RAML0       : origin = 0x008000, length = 0x000800     /* 片上 RAM block L0 */
   RAML1       : origin = 0x008800, length = 0x000400     /* 片上 RAM block L1 */
   OTP         : origin = 0x3D7800, length = 0x000400     /* 片上 OTP */
   FLASHH      : origin = 0x3E8000, length = 0x002000     /* 片上 FLASH */
   FLASHG      : origin = 0x3EA000, length = 0x002000     /* 片上 FLASH */
   FLASHF      : origin = 0x3EC000, length = 0x002000     /* 片上 FLASH */
   FLASHE      : origin = 0x3EE000, length = 0x002000     /* 片上 FLASH */
   FLASHD      : origin = 0x3F0000, length = 0x002000     /* 片上 FLASH */
   FLASHC      : origin = 0x3F2000, length = 0x002000     /* 片上 FLASH */
   FLASHA      : origin = 0x3F6000, length = 0x001F80     /* 片上 FLASH */
   CSM_RSVD    : origin = 0x3F7F80, length = 0x000076     
   /* FLASHA的一部分.  Program with all 0x0000 when CSM is in use. */
   BEGIN       : origin = 0x3F7FF6, length = 0x000002
   /* FLASHA的一部分.  使用了啟動引導FLASH模式 */
   CSM_PWL_P0  : origin = 0x3F7FF8, length = 0x000008     
   /* FLASHA的一部分.  CSM password locations in FLASHA */
/*
說明
CSM_RSVD是Code Security Module_reserved的意思,
是指當使用程式碼 安全模組時,origin = 0x3F7F80, length = 0x000076
這個記憶體塊是受保留的reserved。不能放程式程式碼或者資料塊。且必須初始化為0x0000.
CSM_PWL是password locations的意思,即存放密碼的地方
BEGIN是程式啟動的開始地址。
*/
   IQTABLES    : origin = 0x3FE000, length = 0x000B50     /* 在引導ROM中的IQ數學表  */
   IQTABLES2   : origin = 0x3FEB50, length = 0x00008C     /* 在引導ROM中的IQ數學表  */
   IQTABLES3   : origin = 0x3FEBDC, length = 0x0000AA     /* 在引導ROM中的IQ數學表  */

   ROM         : origin = 0x3FF27C, length = 0x000D44     /* 啟動引導 ROM */
   RESET       : origin = 0x3FFFC0, length = 0x000002     
   /* 啟動引導 ROM的一部分 復位地址BROM向量  */
   VECTORS     : origin = 0x3FFFC2, length = 0x00003E
   /* 啟動引導 ROM的一部分  BROM向量*/

PAGE 1 :   /* 資料記憶體塊 */
   BOOT_RSVD   : origin = 0x000000, length = 0x000050 
       /* M0的一部分, 預留給啟動引導 ROM時的棧空間 */
   RAMM0       : origin = 0x000050, length = 0x0003B0     /* 片上 RAM  M0 */
   RAMM1       : origin = 0x000400, length = 0x000400     /* 片上 RAM M1 */
   RAML2       : origin = 0x008C00, length = 0x000400     /* 片上 RAM L2 */
   RAML3       : origin = 0x009000, length = 0x001000     /* 片上 RAM L3 */
   FLASHB      : origin = 0x3F4000, length = 0x002000     /* 片上 FLASH */
}
/* 
將各個段分配到記憶體塊.
注意:  codestart段在 DSP28_CodeStartBranch.asm中被定義,用於引導FLASH時,重定向程式碼。
ramfuncs段內的函式會從FLASH被轉移到RAM中執行。
*/
SECTIONS
{
   .cinit    : > FLASHA   PAGE = 0  /* 初始化的全域性變數和static變量表*/
   .pinit    : > FLASHA   PAGE = 0  /* 全域性物件的建構函式表  C++範疇*/
   .text     : > FLASHA   PAGE = 0  /* 可執行程式碼和常數段 */
   codestart : > BEGIN    PAGE = 0  /* 程式碼啟動段 */
   ramfuncs  : LOAD = FLASHD, /* 將定義到段ramfuncs上的程式碼,載入到FLASHD */
       RUN = RAML0,  /* 定義到ramfuncs上的程式碼,複製到RAML0上執行 */
       LOAD_START(_RamfuncsLoadStart), /* 所要載入程式在Flash裡的初始地址 */
       LOAD_END(_RamfuncsLoadEnd), /* 所要載入程式在Flash裡的結束地址 */
       RUN_START(_RamfuncsRunStart),     /* 程式執行的起始地址 */
       PAGE = 0
   csmpasswds: > CSM_PWL_P0  PAGE = 0    /* 密碼段 */
   csm_rsvd  : > CSM_RSVD    PAGE = 0/* 使用程式碼安全模組時,需要預留的段  */

   /* 未初始化資料段: */
   .stack    : > RAMM0       PAGE = 1    /* 棧空間*/
   .ebss     : > RAML2 | RAML3  PAGE = 1
   /* 長呼叫的全域性或static變數,初始化和未初始化變數*/
   .esysmem  : > RAML2 | RAML3  PAGE = 1

   /* 已初始化的段 */
   .econst   : > FLASHA      PAGE = 0   
   /* 字串常量和far const定義的全域性和靜態變數(static const)*/
   .switch   : > FLASHA      PAGE = 0
   /* 存放switch語句產生的常數表格*/
   /* 分配 IQ 數學表區域  : */
   IQmath    : > FLASHA      PAGE = 0            /* Math Code */
   IQmathTables   : > IQTABLES,   PAGE = 0, TYPE = NOLOAD  /* 不載入*/
/*
.reset是由編譯器使用的。它包含了C程式碼的開始地址_c_int00。
使用啟動引導ROM的這部分和CPU向量表是不需要的。預設的型別被設定為dsect
*/
   .reset    : > RESET,      PAGE = 0, TYPE = DSECT 
   /* DSECT 說明這一塊地址並不會真的載入資料,只是連結一下symbol。*/
   vectors   : > VECTORS     PAGE = 0, TYPE = DSECT
}
/*說明
編譯器生成的包含程式碼和資料的多個部分,稱為段。這個段被分為兩個不同的組:初始化了的和沒被初始化的。
初始化的部分是由所有的程式碼,常量和初始化表組成的。下面列出了由編譯器產生的初始化段。
                            初始化段
段名      內容                                           限制
.cinit  初始化的全域性變數和static變量表                     程式碼
.const  初始化的全域性const變數和static const變數和字串常量 不超過64K長度
.econst 長呼叫的常量                                      資料中的任何地方
.pinit  全域性物件的建構函式表                               程式碼
.switch switch語句產生的表                                程式碼或者資料
.text   可執行程式碼和常數                                  程式碼
沒初始化的段是由未初始化的變數,堆疊和malloc產生的記憶體。下表列出了由編譯器產生的沒初始化段。
                            沒初始化段
段名          內容                      限制
.bss        全域性變數和static變數         不超過64K長度
.ebss       長呼叫的全域性變數和static變數   資料中的任何地方
.stack      棧空間                      不超過64K長度
.sysmem     malloc函式產生的記憶體         不超過64K長度
.esysmem    far_malloc函式產生的記憶體      資料中的任何地方

已初始化的段:.text,.cinit,.const,.econst,.pinit和.switch..
.text:所有可以執行的程式碼和常量
.cinit:全域性變數和static變數的C初始化記錄,
包含未用const宣告的外部(extern)或靜態(static)資料表
.const:包含字串常量和const定義的全域性和static變數
.econst:包含字串常量和初始化的全域性變數和static變數(由far const)
的初始化和說明,與.const不同的是.const分配範圍被限制在低64K 
16位資料區,而.econst的分配範圍是4M 22位資料區
.pinit:全域性構造器(C++)程式列表,注意是全域性的構造器。
.switch:包含大switch段宣告的列表。Jump tables for large switch statements。
非初始化的段:.bss,.ebss,.stack,.sysmem,和esysmem.
.bss: 為全域性變數和區域性變數保留的空間,在程式上電時.cinit空間中的資料複製出來並存儲在.bss空間中。
.ebss:為使用大暫存器模式時的全域性變數和靜態變數預留的空間,在程式上電時,
cinit空間中的資料複製出來並存儲在.ebss中,與.ebss不同的是.bss分配範圍被限制在低64K 16位資料區,
而.ebss的分配範圍是4M 22位資料區
.stack:為系統堆疊保留的空間,用於和函式傳遞變數或為區域性變數分配空間。
.sysmem:為動態儲存分配保留的空間。如果有巨集函式,此空間被巨集函式佔用,如果沒有的話,此空間保留為0
.esysmem:為動態儲存分配保留的空間。如果有far函式,此空間被相應的佔用,如果沒有的化,此空間保留為0.
ramfuncs: LOAD = FLASHD,表示ramfuncs段的裝載在PAGA0的FLASHD中。
RUN = RAML0,表示ramfuncs段的執行地址在PAGE0的RAML0中
LOAD_START(_RamfuncsLoadStart),
令編譯器建立了一個變數RamfuncsLoadStart,該變數指向段
ramfuncs的裝載地址的首地址。 
LOAD_END(_RamfuncsLoadEnd),
令編譯器建立了一個變數RamfuncsLoadEnd,該變數指向段ramfuncs的裝載地址的末地址。
RUN_START(_RamfuncsRunStart),
令編譯器建立了一個變數RamfuncsRunStart,該變數指向段ramfuncs的執行地址的首地址。
解釋一下什麼叫長呼叫,指的是程式指令的尋指範圍。
上面說了絕對呼叫的尋指範圍是16位資料區,長呼叫的尋指範圍是22位資料區 。
*/

相關推薦

詳細CMD檔案講解DSP28035

一、 CMD檔案基本概念及語法 CMD的專業名稱叫連結器配置檔案,是存放連結器的配置資訊的,我們簡稱為命令檔案。從其名稱可以看出,該檔案的作用是指明如何連結程式的。 那麼我們知道,在編寫TI DSP程式時,是可以將程式分為很多段,比如text、bss等,各段

【cocos2dx 3.2】Flappy Bird開發詳細講解主角小鳥的建立

本文可以隨意轉載,轉載請註明出處,謝謝! 像之前我們說的,GameLayer是管家,其他的東西(小鳥,管道,草地等)各自封裝成類。現在我們就把主角小鳥封裝成一個類。 在這裡我們先思考下,我們有三種不同顏色的小鳥,在預載入LoadingScene裡我們給它們初始化了各自的動

Leetcode 72:編輯距離詳細的解法!!!

給定兩個單詞 word1 和 word2,計算出將 word1 轉換成 word2 所使用的最少運算元 。 你可以對一個單詞進行如下三種操作: 插入一個字元 刪除一個字元 替換一個字元 示例 1: 輸入: word1 = "horse", wor

Leetcode 44:萬用字元匹配詳細的解法!!!

給定一個字串 (s) 和一個字元模式 (p) ,實現一個支援 '?' 和 '*' 的萬用字元匹配。 '?' 可以匹配任何單個字元。 '*' 可以匹配任意字串(包括空字串)。 兩個字串完全匹配才算匹配成功。 說明: s 可能為空,且只包含從 a-z 的小寫字母。

支援向量機演算法的實現和應用Python3詳細的原始碼實現+圖介紹

支援向量機演算法的實現和應用,因為自己推到過SVM,建議自己推到一遍, 這裡不對SVM原理做詳細的說明。 原理公式推到推薦看:https://blog.csdn.net/jcjx0315/article/details/61929439 #!/usr/bin/env python # enc

Leetcode 951:翻轉等價二叉樹詳細的解法!!!

我們可以為二叉樹 T 定義一個翻轉操作,如下所示:選擇任意節點,然後交換它的左子樹和右子樹。 只要經過一定次數的翻轉操作後,能使 X 等於 Y,我們就稱二叉樹 X 翻轉等價於二叉樹 Y。 編寫一個判斷兩個二叉樹是否是翻轉等價的函式。這些樹由根節點 root1 和 root2 給出

Leetcode 950:按遞增順序顯示卡牌詳細的解法!!!

牌組中的每張卡牌都對應有一個唯一的整數。你可以按你想要的順序對這套卡片進行排序。 最初,這些卡牌在牌組裡是正面朝下的(即,未顯示狀態)。 現在,重複執行以下步驟,直到顯示所有卡牌為止: 從牌組頂部抽一張牌,顯示它,然後將其從牌組中移出。 如果牌組中仍有牌,則將下

Leetcode 949:給定數字能組成的最大時間詳細的解法!!!

給定一個由 4 位數字組成的陣列,返回可以設定的符合 24 小時制的最大時間。 最小的 24 小時制時間是 00:00,而最大的是 23:59。從 00:00 (午夜)開始算起,過得越久,時間越大。 以長度為 5 的字串返回答案。如果不能確定有效時間,則返回空字串。 示例 1

Leetcode 30:與所有單詞相關聯的字串詳細的解法!!!

給定一個字串 s 和一些長度相同的單詞 **words。**在 s 中找出可以恰好串聯 words 中所有單詞的子串的起始位置。 注意子串要與 words 中的單詞完全匹配,中間不能有其他字元,但不需要考慮 words 中單詞串聯的順序。 示例 1: 輸入: s = "b

Leetcode 89:格雷編碼詳細的解法!!!

格雷編碼是一個二進位制數字系統,在該系統中,兩個連續的數值僅有一個位數的差異。 給定一個代表編碼總位數的非負整數 n,列印其格雷編碼序列。格雷編碼序列必須以 0 開頭。 示例 1: 輸入: 2 輸出: [0,1,3,2] 解釋: 00 - 0 01 - 1 11 - 3 10

Leetcode 60:第k個排列詳細的解法!!!

給出集合 [1,2,3,…,n],其所有元素共有 n! 種排列。 按大小順序列出所有排列情況,並一一標記,當 n = 3 時, 所有排列如下: "123" "132" "213" "231" "312" "321" 給定 n 和 k

Leetcode 69:Sqrt(x)詳細的解法!!!

實現 int sqrt(int x) 函式。 計算並返回 x 的平方根,其中 x 是非負整數。 由於返回型別是整數,結果只保留整數的部分,小數部分將被捨去。 示例 1: 輸入: 4 輸出: 2 示例 2: 輸入: 8 輸出: 2 說明: 8 的平方根是 2.82

Leetcode 42:接雨水詳細的解法!!!

給定 n 個非負整數表示每個寬度為 1 的柱子的高度圖,計算按此排列的柱子,下雨之後能接多少雨水。 上面是由陣列 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度圖,在這種情況下,可以接 6 個單位的雨水(藍色部分表示雨水)。 感謝 Marcos 貢

Leetcode 50:Pow(x, n)詳細的解法!!!

實現 pow(x, n) ,即計算 x 的 n 次冪函式。 示例 1: 輸入: 2.00000, 10 輸出: 1024.00000 示例 2: 輸入: 2.10000, 3 輸出: 9.26100 示例 3: 輸入: 2.00000, -2 輸出: 0.25

人體姿態估計Alphapose配置安裝教程GPU,詳細,親測有效!

首先簡單介紹一下Alposepose 該模型提出的論文:《RMPE: Regional Multi-Person Pose Estimation》ICCV 2017,是由上海交通大學提出的,目前在多人自討估計的效果最好。 文章的寫作背景是單人姿態估計的方法不能用在多人

白話Hadoop入門-WordCount詳細講解2

     前一篇部落格講述瞭如何進行Hadoop壞境的搭建,以及第一個傳輸檔案程式的編寫,通過第一個檔案可能大概對Hadoop有一個瞭解了,但是Hadoop的精髓在於mapreduce,下面我們就來看看如何編寫Hadoop的第一個“hello world”程式--也就是Wor

Leetcode 68:文字左右對齊詳細的解法!!!

給定一個單詞陣列和一個長度 maxWidth,重新排版單詞,使其成為每行恰好有 maxWidth 個字元,且左右兩端對齊的文字。 你應該使用“貪心演算法”來放置給定的單詞;也就是說,儘可能多地往每行中放置單詞。必要時可用空格 ' ' 填充,使得每行恰好有 maxWidth 個字元。

Leetcode 52:N皇后 II詳細的解法!!!

n 皇后問題研究的是如何將 n 個皇后放置在 n×n 的棋盤上,並且使皇后彼此之間不能相互攻擊。 上圖為 8 皇后問題的一種解法。 給定一個整數 n,返回 n 皇后不同的解決方案的數量。 示例: 輸入: 4 輸出: 2 解釋: 4 皇后問題存在如下兩個

Leetcode 947:移除最多的同行或同列石頭詳細的解法!!!

在二維平面上,我們將石頭放置在一些整數座標點上。每個座標點上最多隻能有一塊石頭。 現在,move 操作將會移除與網格上的某一塊石頭共享一列或一行的一塊石頭。 我們最多能執行多少次 move 操作? 示例 1: 輸入:stones = [[0,0],[0,1],[1,0],[1,2

Leetcode 946:驗證棧序列詳細的解法!!!

給定 pushed 和 popped 兩個序列,只有當它們可能是在最初空棧上進行的推入 push 和彈出 pop 操作序列的結果時,返回 true;否則,返回 false 。 示例 1: 輸入:pushed = [1,2,3,4,5], popped = [4,5,3,2,1]