五一來了,三天小假期終于可以讓大家歇一歇了(估計好多人都已經在規劃著五一出行計劃了或者已經在旅途中了),校園里一下子冷清了不少。記得去年12月份曾經寫過一篇“寫在圣誕節之簡單破解飛思卡爾HCS12系列Flash空間限制“的文章,當時還頗受歡迎來,至今仍保持著我博客的點擊記錄,哈哈,所以今天再續寫一篇"五一特別篇"(嘿嘿,最近看海賊王看的,也出個特別篇,哈哈,豐富下俺博客的藝術形式),希望不要石沉大海的好。
勞動節嘛,自然勞動最光榮,呵呵,所以我還是變回技術宅,鉆進實驗室搗鼓下技術吧,順便寫寫心得體會、工程經驗之類的給大家分享分享(所以勞動人民是最美麗滴啊,呼呼)。這里首先得說聲抱歉了,好像月初有網友要求寫篇有關kinetis的DMA功能的介紹,也答應了盡量本月份就寫出來,不過主要是更新從零入手系列很麻煩,每寫一篇的時候我都需要仔細斟酌,保證質量(畢竟不能砸了招牌嘛,嘿嘿),而且本月也的確有些忙,所以這個月底就不更新了,下個月會更新出來,敬請期待哦,哈哈。
本篇介紹介紹IAR的icf配置文件,其實這算是一篇知識深入擴展,初手在用IAR簡單開發一款片子的時候很少有人去關心該配置文件的,因為該配置文件一般在用IAR新建工程選型目標芯片的時候系統自動添加了(當然kinetis的官方例程里給出的配套的配置文件需要另行自己添加了),會覺得這是IDE系統的事。但是如果你是要做深入研究或者說真正掌握了解一款片子,而不是霧里看花知其然而不知其所以然,那么配置文件則是你的必修內容,怎么樣,好奇了吧,呵呵,下面深入了解一番吧,進入正題:
1.首先說說什么是icf文件(即ILINK鏈接器的配置文件)的作用,其實在IAR5.x之前,IAR是采用的叫XLINK的鏈接器(它相應的配置文件為xcl文件),5.x之后才采用了新版ILINK鏈接器,所以咱們開發Kinetis的IAR6.x自然也采用的是ILINK鏈接器,配置文件為icf文件,咳咳,如果有人問什么是鏈接器,先谷歌一下補補,我這里就引用IAR官方手冊里的一句話簡要說明一下什么是鏈接器及其相應配置文件的作用吧:
”EWARM 5.xx 中的鏈接器稱為ILINK。ILINK 可以從 ELF/DWARF 格式的目標文件中提取代碼和數據, 并生成可執行的輸出鏡像。對于 ELF/DWARF 格式而言,基本的鏈接單元是section,section 的類型有code和data,屬性可以是readonly (ro),readwrite (rw)和zeroinit (zi)。ILINK 根據 ILINK Configuration File(*.icf)來分配和定位這些sections。“
2.簡單的概括icf的文件,其主要包括以下幾個內容,即:
(1)可編址的存儲空間(memory);
(2)不同的存儲地址區域(region);
(3)不同的地址塊(block);
(4)section的初始化與否;
(5)section在存儲空間的放置。
上面幾點內容,如果你對照實際icf文件都會找得到,建議大家嘗試下,會讓你受益匪淺的。
3.對于icf文件使用的常用命令,在網上早已有人貼出來了,隨意即可搜到,這里省去麻煩,我也貼出來自己學的時候記下來的命令用法,建議通讀一遍:
(1)define [ exported ] symbol name = expr;
作用:指定某個符號的值。
參數:
exported 導出該symbol,使其對可執行鏡像可用
name 符號名
expr 符號值
舉例:
define symbol RAM_START_ADDRESS = 0x40000000; /* 定義 RAM 起始地址 */
define symbol RAM_END_ADDRESS = 0x4000FFFF; /* 定義 RAM 結束地址 */
-------------------------------------------------------------------
(2)define memory name with size = expr [, unit-size];
作用:
定義一個可編址的存儲地址空間(memory)。
參數:
name memory的名稱
expr 地址空間的大小
unit-size expr的單位,可以是位(unitbitsize),缺省是字節(unitbytesize)
舉例:
define memory MEM with size = 4G;
-----------------------------------------------------------------
(3)define region name = region-expr;
作用:
定義一個存儲地址區域(region)。一個區域可由一個或多個范圍組成,每個范圍內地址必須連續,但幾個范圍之間不必是連續的。
參數:
name region的名稱
region-expr memory:[from expr { to expr | size expr}],可以定義起止范圍,也可以定義起始地址和region的大小
舉例:
define region ROM = MEM:[from 0x0 size 0x10000];
/* 定義 ROM region,位于地址空間MEM 中,起始地址為0x0,大小為0x10000 字節 */
define region ROM = MEM:[from 0x0 to 0xFFFF];
/* 定義 ROM region,位于地址空間MEM 中,起始地址為0x0,結束地址為0xFFFF */
---------------------------------------------------------------------------------------------
(4)
define block name [ with param, param... ]
{
extended-selectors
};
作用: 定義一個地址塊(block);它可以是個只保留指定大小的地址空間的空塊,比如棧、堆;也可以包含一系列的sections,由extended-selectors 選擇。
參數:
name block 的名稱
param 可以是: size = expr (塊的大小)
maximum size = expr (塊大小的上限)
alignment = expr (最小對齊字節數)
fixed order (按照固定順序放置sections)
extended-selector [ first | last ] { section-selector | block name | overlay name }
first 最先存放
last 最后存放
section-selector [ section-attribute ][ section sectionname ][object filename ]
section-attribute [ readonly [ code | data ] | readwrite [ code | data ] | zeroinit ]
sectionname section的名稱
filename 目標文件的名稱
name block或overlay的名稱
注:這里可以按照section的屬性,名稱及其所在目標文件這三個過濾條件中,任意選取一個條件或多個條件進行組合,來圈定所要求的sections。
舉例:
define block HEAP with size = 0x1000, alignment = 4 { };
/* 定義 HEAP block,大小為0x1000,4 字節對齊,沒有內容 */
define block MYBLOCK1 = { section mysection1, section mysection2, readwrite };
/* 定義 MYBLOCK1 block,含有mysection1,mysection2,以及所有readwrite 屬性的sections */
define block MYBLOCK2 = { readwrite object myfile2.o };
/* 定義 MYBLOCK2 block,含有目標文件myfile2.o 中所有readwrite 屬性的sections */
define block MYBLOCK3 = { readonly code object myfile3.o };
/* 定義 MYBLOCK3 block,含有目標文件myfile3.o 中所有readonly 屬性的code sections */
(5)
initialize { by copy | manually } [ with param, param... ]
{
section-selectors
};
作用: 初始化sections
參數:
by copy 在程序啟動時自動執行初始化
manually 在程序啟動時不自動執行初始化
param 可以是: packing = { none | compress1 | compress2 | auto } copy routine = functionname
packing表示是否壓縮數據,缺省是auto
functionname表示是否使用自己的拷貝函數來取代缺省的拷貝函數
section-selector 同上
舉例:
initialize by copy { readwrite }; /* 在啟動時初始化所有屬性為 readwrite 的sections */
--------------------------------------------------------------
(6)
do not initialize
{
section-selectors
};
作用: 規定在程序啟動時不需要初始化的sections;一般用于__no_init 聲明的變量段(.noinit)
參數:
section-selector 同上
舉例:
do not initialize { .noinit }; /* 在啟動時不要初始化.noinit section */
(7)
place at { address memory [:expr] | start of region_expr | end of region_expr }
{
extended-selectors
};
作用: 把section 或 block 放置在某個具體的起始地址處,或者一個 region 的開始或結束處
參數:
memory memory 的名稱
expr 地址值,該地址必須在 memory 所定義的范圍內
region_expr region 的名稱
extended-selector 同上
舉例:
place at end of ROM { section .checksum }; /* 把.checksum 放在 ROM region 的最后 */
place at address MEM:0x0 { section .intvec }; /* 把.intvec 放在地址 0x0 */
place at address MEM:0x1000 { section .text object myfile.o }; /* the .text section of myfile.o */
place at address MEM:0x1000 { readonly object myfile.o }; /* all read-only sections of myfile.o */
place at address MEM:0x1000 { readonly data object myfile.o }; /* all read-only data sections of myfile.o */
(8)
place in region-expr
{
extended-selectors
};
作用: 把section 或 block (按任意順序)放置在某個region 中
參數:
region-expr region 的名稱
extended-selector 同上
舉例:
place in ROM { readonly }; /* all readonly sections */
place in RAM { readwrite }; /* all readwrite sections */
place in RAM { block HEAP, block CSTACK, block IRQ_STACK }; /* heap and stacks */
place in ROM { section .text object myfile.o }; /* the .text section of myfile.o */
place in ROM { readonly object myfile.o }; /* all read-only sections of myfile.o */
place in ROM { readonly data object myfile.o }; /* all read-only data sections myfile.o */
下面為系統預定義(即你是找不到其定義的,所以不要浪費時間去找了,呵呵)的section和block描述,上圖:

4.相關命令知曉了,也就是大好基礎了,下面就俺就根據上面個的指令獨家解析下飛思卡爾提供的Kinetis例程包里自帶的icf配置文件,以512KB_Pflash.icf為例介紹一下(當初自己上傳的開發框架代碼里沒有作相關注釋,這里就算是補充了吧,哈哈):
(1)首先找到該文件,打開(咳咳,雖然這步算是廢話,不過為了嚴謹,還是不能少的,呵呵),采用從上到下的順序解讀;
(2)

先定義了一些可讀性的符號,包括異常向量表的起始地址,ROM、RAM 的起止地址和堆、棧的大小等(該地址分配我們可以在Kinetis的datasheet里找到),以前綴__ICFEDIT_開頭的符號是由圖形化編輯工具 ICF Editor自動定義的,可能會有些人不懂,其實上面部分代碼是體現在IAR的Options->Linker選項里的(自己去探索一下即可發現)。
(3)

這部分仍然是定義一些符號,由Kinetis的內存映射可以知道,其實其內部是由兩部分RAM塊組成的,所以第一步出現RAM_start這一步出現了RAM2_start,另外也定義了中斷向量表在ROM中的地址和在RAM中的地址。code_start定義為0x00000410是緊鄰前面向量表的,也就是說向量表占用了0x00000410大小的空間。
(4)

到了這一步就設計到具體操作內容了,32位地址總線選址4G空間,然后定義了kinetis(512k型號的哈)的ROM區的地址范圍和RAM區(含RAM1和RAM2)的地址范圍。接著下面定義了堆和棧的屬性,8字節對齊方式,大小為前面定義的大小即分別為0x1000和0x200。
(5)

對屬性為readwrite的sections,.data和.textrw的sections不自動初始化,對.noinit屬性的sections(即用__no_init修飾的全局和靜態變量),定義重定位代碼區為.textrw_init,定義重定位RAM區為.textrw。
(6)

對所有的sections 和 blocks 在地址空間中所處的位置進行了配置。首先將只讀的異常向量表.intvec放置在_intvec_start地址處(前面已定義),然后將余下的只讀sections以任意順序存放在ROM_region中,將可讀寫的sections和棧、堆這些blocks以任意順序存放在RAM_region中。
呼呼,今晚工作量有點大,沒想到一寫就寫了這么多,哈哈,終于又找到”文思泉涌“的趕腳了。自己該收收工了,規劃下這個五一該怎么玩了,大好時光不能浪費了,大家五一快樂,呵呵。未完待續~
|