由于在暑假匆忙接收的嵌入式項(xiàng)目中需要使用特別大的數(shù)組,非分頁RAM的內(nèi)存不夠用了,沒辦法,硬著頭皮嘗試使用分頁RAM,但是完全沒有單片機(jī)的基礎(chǔ),導(dǎo)致極其的困難。之前寫程序都是按照純軟件的思維,主要考慮架構(gòu),不會(huì)考慮到每個(gè)變量具體存在哪個(gè)物理地址這么底層的問題,結(jié)果被飛思卡爾這分頁地址、prm文件什么的搞得一頭霧水,而網(wǎng)上的資料又少,講的又大同小異的籠統(tǒng),最后寫出來的程序因?yàn)檫@分頁地址的原因存在各種問題(還以為把變量放到分頁RAM了,結(jié)果現(xiàn)在稍微懂了點(diǎn)回去看,發(fā)現(xiàn)其實(shí)很多根本還是分配在非分頁區(qū)。暈倒~。但是居然還能相對(duì)正常運(yùn)行也是很神奇)。這些天各種找相關(guān)的資料,結(jié)果發(fā)現(xiàn)在CodeWarrior的官方文檔資料里其實(shí)把我想知道的都講的很清楚了(還是官方文檔給力,以后學(xué)什么東西直接找官方文檔,不去到處找網(wǎng)上一堆零零散散的資源來學(xué)了)。本著學(xué)習(xí)的態(tài)度,將逐步把官方文檔翻譯一遍,供大家一起交流學(xué)習(xí)進(jìn)步。
翻譯的資料是公開的,我想應(yīng)該不會(huì)有什么版權(quán)問題,如涉及版權(quán)問題,請(qǐng)聯(lián)系我刪除文章,原文檔在這里(https://www.nxp.com/pages/codewarrior-development-studio-for-hcs12x-microcontrollers-classic-ide-v5.2:CW-HCS12X?&tab=Documentation_Tab&linkline=Users-Guides),另感謝NXP提供的學(xué)習(xí)資料。
另外,本人有另一篇詳解怎么定義及訪問直接尋址區(qū)的博文
譯者注:譯者博客(),轉(zhuǎn)載請(qǐng)保留這條。此為官方文檔TN238,僅供學(xué)習(xí)交流使用,請(qǐng)勿用于商業(yè)用途。
這個(gè)文檔描述了程序員要怎么樣幫助HCS12X編譯器來產(chǎn)生在數(shù)據(jù)訪問上更加優(yōu)化的代碼。我們將討論以下主題:
分配在直接尋址區(qū)的變量
分配在擴(kuò)展尋址區(qū)的變量
分配在banked尋址區(qū)的變量 — 使用邏輯尋址
分配在banked尋址區(qū)的變量 — 使用全局尋址
Banked常量分配
邏輯地址 vs. 全局地址
對(duì)于以上舉例的每個(gè)變量類型,我們都會(huì)描述:
怎么定義一個(gè)變量
怎么聲明一個(gè)變量
生成來分為這變量的代碼
怎么定義一個(gè)指向這樣一個(gè)變量的指針
生成來訪問指針和其指向的變量的代碼
PRM文件中的位置
注意1: 這篇技術(shù)文檔中描述的信息適用于SMALL(-Ms)以及BANKED(-Mb)地址模型。而不適用于LARGE(-Ml)地址模型。 注意2 : 對(duì)于少于32Kb代碼的應(yīng)用,我們通常推薦使用SMALL地址模型,或者使用BANKED地址模型。我們不推薦使用LARGE地址模型。分配在直接尋址區(qū)的變量
為了使編譯器將某個(gè)變量分配到直接尋址頁,你必須定義(以及聲明)它到個(gè)特別的segment中,這segment帶有屬性__SHORT_SEG。
定義&訪問直接尋址區(qū)的數(shù)據(jù)
1 像這樣進(jìn)行變量定義:
#pragma DATA_SEG __SHORT_SEG MyShortData unsigned char rub_short_var; #pragma DATA_SEG DEFAULT2 像這樣進(jìn)行變量聲明:
#pragma DATA_SEG __SHORT_SEG MyShortData extern unsigned char rub_short_var; #pragma DATA_SEG DEFAULT3 對(duì)這變量的訪問會(huì)生成如下代碼:
37: rub_short_var = 2; 00E08002 C602 [1] LDAB #2 00E08004 5B08 [2] STAB $084 沒有用于訪問直接尋址頁變量的特殊指針類型。一個(gè)指向這樣一個(gè)變量的指針將像這樣定義:
unsigned char* ptr_on_short_var;5 初始化和訪問被指向的對(duì)象會(huì)產(chǎn)生如下代碼:
46: ptr_on_short_var = &rub_short_var; 00E0801F 180320102102 MOVW #8208,$2102 47: (*ptr_on_short_var)++; 00E08025 62FBA0D9 INC [$A0D9,PC] /* [ptr_on_short_var,PCR] */6 對(duì)于定義在__SHORT_SEG section的變量,PRM文件中的SEGMENT和PLACEMENT是這樣子的:
SEGMENTS DIRECT_PAGE = READ_WRITE 0x2010 TO 0x20FF; /* 這里省略了其他segment定義 */ END PLACEMENT MyShortData INTO DIRECT_PAGE; /* 這里省略了其他placement定義 */ END 注意: 包含通過直接尋址模式訪問的變量的section,應(yīng)該被分配在用邏輯地址定義的segment中配置直接尋址區(qū)
在HCS12X上,直接尋址頁可以移動(dòng),并且不是硬編碼到0x00..0xFF(HCS12上是硬編碼到這的)。編譯器需要進(jìn)行特別的設(shè)置來支持這一特性。
如果DIRECT寄存器包含任何東西但是默認(rèn)值是0(譯者注:意思是存在DIRECT寄存器?),編譯器和匯編器就要啟用-CpDirect選項(xiàng),其后跟著可直接訪問區(qū)的起始地址。比如:如果DIRECT初始化為0x20,那么直接訪問窗口就是從0x2000到0x20FF,編譯器和匯編器選項(xiàng)就是-CpDirect0x2000。編譯器和匯編器都要加上這個(gè)選項(xiàng)。
DIRECT寄存器必須由用戶代碼來初始化。默認(rèn)的啟動(dòng)代碼不初始化DIRECT。
在prm文件中,section MyShortData要被分配到這個(gè)區(qū)域(在上例中是從0x2000到0x20FF)。
小心,不正確地分配直接訪問section(也就是說MyShortData沒有被正確地分配)不會(huì)產(chǎn)生鏈接器診斷消息。
對(duì)于HCS12,鏈接器會(huì)報(bào)告一個(gè)fixup溢出。但是對(duì)于HCS12X卻無法做到這一點(diǎn),因?yàn)橹苯釉L問頁可以被映射。
為了使編譯器將某個(gè)變量分配到擴(kuò)展地址空間,你只需要用普通的方式定義(并聲明)它。
1 像這樣進(jìn)行變量定義:
2 像這樣進(jìn)行變量聲明:
extern unsigned char rub_var;3 對(duì)這變量的訪問會(huì)生成如下代碼:
39: rub_var =7; 00E08002 C607 [1] LDAB #7 00E08004 7B2001 [3] STAB $20014 指向這個(gè)變量的指針可以像這樣定義:
unsigned char * ptr_on_var;5 初始化和訪問被指向的對(duì)象會(huì)產(chǎn)生如下代碼:
57: ptr_on_var = &rub_var; 00E0805F 18032100210C MOVW #8448,$210C 58: (*ptr_on_var)++; 00E08065 62FBA0A3 INC [$A0A3,PC] /* [ptr_on_var,PCR] */6 這種方式定義的變量被分配在預(yù)定義section DEFAULT_RAM中。在PRM文件中,這個(gè)section的SEGMENT和PLACEMENT定義是這樣子的:
SEGMENTS RAM = READ_WRITE 0x2100 TO 0x3FFF; /* 這里省略了其他segment定義 */ END PLACEMENT DEFAULT_RAM INTO RAM; /* 這里省略了其他placement定義 */ END 注意: 包含使用擴(kuò)展尋址模式定義的變量的Section應(yīng)該被分配在使用邏輯地址定義的segment中。分配在Banked尋址區(qū)的變量
分配在banked RAM中的變量可以使用以下來訪問:
邏輯地址(使用RPAGE) 或
全局地址
使用邏輯地址為了告訴編譯器你想要使用一個(gè)變量的邏輯地址來訪問它,你得使用如下語法:
1 像這樣進(jìn)行變量定義:
2 像這樣進(jìn)行變量聲明:
#pragma DATA_SEG __RPAGE_SEG PAGED_RAM extern unsigned char rub_far_var; #pragma DATA_SEG DEFAULT3 對(duì)這變量的訪問會(huì)生成如下代碼:
38: rub_far_var = 5; 00E08002 C6FB [1] LDAB #251 /* #PAGE(rub_far_var) */ 00E08004 5B16 [2] STAB $16 /* RPAGE */ 00E08006 C605 [1] LDAB #5 00E08008 7B1000 [3] STAB $10004 指向這個(gè)變量的指針可以像這樣定義:
unsigned char * __rptr ptr_on_far_var;5 初始化和訪問被指向的對(duì)象會(huì)產(chǎn)生如下代碼:
50: ptr_on_far_var = &rub_far_var; 00E08029 180310002105 MOVW #4096,$2105 00E0802F 180BFB2104 MOVB #251,$2104 51: (*ptr_on_far_var)++; 00E08034 FE2105 LDX $2105 /* ptr_on_far_var:1 */ 00E08037 F62104 LDAB $2104 /* ptr_on_far_var */ 00E0803A 7B0016 STAB $0016 /* RPAGE */ 00E0803D 6200 INC 0,X6 對(duì)于定義在RPAGE section中的變量,對(duì)應(yīng)PRM文件中的SEGMENT和PLACEMENT是這樣子的:
SEGMENTS RAM_FB = READ_WRITE 0xFB1000 TO 0xFB1FFF; RAM_FC = READ_WRITE 0xFC1000 TO 0xFC1FFF; RAM_FD = READ_WRITE 0xFD1000 TO 0xFD1FFF; /* 這里省略了其他segment定義 */ END PLACEMENT PAGED_RAM INTO RAM_FB, RAM_FC, RAM_FD; /* 這里省略了其他placement定義 */ END 注意: 包含通過邏輯尋址模式訪問的變量的section,應(yīng)該被分配在用邏輯地址定義的segment中 注意: 分配在RPAGE segment中的變量也可以通過使用far指針來訪問, unsigned char * __far ptr_on_far_var; 在這種情況下,將會(huì)使用全局尋址模式來訪問指向的對(duì)象使用全局地址
使用全局地址的主要原因是因?yàn)橐粋€(gè)對(duì)象可能沒法裝進(jìn)單頁的邏輯地址中去。通過使用全局地址訪問對(duì)象,就繞開了這個(gè)制約,對(duì)象就可以大到所有可用的內(nèi)存大小或可訪問的64KB。
全局地址指針可以用于任何對(duì)象,對(duì)象不受到任何特殊限制。
為了告訴編譯器你想要訪問一個(gè)使用全局地址的變量,你要使用以下語法:
1 像這樣進(jìn)行變量定義:
2 像這樣進(jìn)行變量聲明:
#pragma DATA_SEG __GPAGE_SEG PAGED_RAM extern unsigned char rub_far_var; #pragma DATA_SEG DEFAULT3 對(duì)這變量的訪問會(huì)生成如下代碼:
35: rub_far_var = 7; 00E0802B C607 [1] LDAB #7 00E0802D 860F [1] LDAA #15 /* #GLOBAL_PAGE(rub_far_var)*/ 00E0802F 5A10 [2] STAA $10 /* GPAGE*/ 00E08031 187BE00F [4] GSTAB $E00F4 指向這個(gè)變量的指針可以像這樣定義:
unsigned char *__far ptr_on_far_var;5 初始化和訪問被指向的對(duì)象會(huì)產(chǎn)生如下代碼:
37: ptr_on_far_var = &rub_far_var; 00E08035 1803B0002101 MOVW #45056,$2101 00E0803B 180B0F2100 MOVB #15,$2100 38: (*ptr_on_far_var)++; 00E08040 FE2101 LDX $2101 /* ptr_on_far_var:1 */ 00E08043 F62100 LDAB $2100 /* ptr_on_far_var */ 00E08046 5B10 STAB $10 /* GPAGE */ 00E08048 18A600 GLDAA 0,X 00E0804B 42 INCA 00E0804C 186A00 GSTAA 0,X6 對(duì)于定義在 GPAGE section中的變量,對(duì)應(yīng)PRM文件中的SEGMENT和PLACEMENT是這樣子的:
SEGMENTS RAM_BANKED = NO_INIT 0xF9000'G TO 0xFCFFF'G; /* 這里省略了其他segment定義 */ END PLACEMENT PAGED_RAM INTO RAM RAM_BANKED; /* 這里省略了其他placement定義 */ END 注意: 包含通過全局尋址模式訪問的變量的section可以被分配在使用邏輯或全局地址定義的segment中。所以PRM文件也可以看起來像這樣:SEGMENTS RAM_FB = READ_WRITE 0xFB1000 TO 0xFB1FFF; RAM_FC = READ_WRITE 0xFC1000 TO 0xFC1FFF; RAM_FD = READ_WRITE 0xFD1000 TO 0xFD1FFF; /* 這里省略了其他segments定義 */ END PLACEMENT PAGED_RAM INTO RAM_FB, RAM_FC, RAM_FD; /* 這里省略了其他placement定義 */ END 分頁常量分配
常量可以被分配在banked EEPROM或者在banked FLASH中,并且可以通過以下來訪問:
EEPROM(使用EPAGE)中的邏輯地址 或
FLASH(使用PPAGE)中的邏輯地址 或
全局地址
在EEPROM中使用邏輯地址為了告知編譯器你想要使用一個(gè)常量在EEPROM中的邏輯地址訪問它,你得使用如下語法:
1 像這樣進(jìn)行常量定義:
2 像這樣進(jìn)行常量聲明:
#pragma CONST_SEG __EPAGE_SEG PAGED_CONST extern const unsigned char cub_far_const=1; #pragma CONST_SEG DEFAULT3 指向這個(gè)變量的指針可以像這樣定義:
const unsigned char *__eptr ptr_on_far_const; 注意: 分配在一個(gè)EPAGE segment的常量還可以使用far指針來訪問。 const unsigned char *__far ptr_on_far_const; 這種情況下,會(huì)使用全局尋址模式來訪問指向的對(duì)象在FLASH中使用邏輯地址
編譯器只支持那些分配在非分頁區(qū)的代碼在FLASH中使用邏輯地址來尋址。因?yàn)橥ǔ2粫?huì)這樣做,我們推薦為所有在FLASH中的數(shù)據(jù)對(duì)象使用全局地址。
為了實(shí)現(xiàn)使用邏輯地址,要使用segment qualifier __PPAGE_SEG 和pointer
qualifier __pptr。
1 像這樣進(jìn)行常量定義:
#pragma CONST_SEG __GPAGE_SEG PAGED_CONST const unsigned char cub_far_const=1; #pragma CONST_SEG DEFAULT2 像這樣進(jìn)行常量聲明:
#pragma CONST_SEG __GPAGE_SEG PAGED_CONST extern const unsigned char cub_far_const= 1; #pragma CONST_SEG DEFAULT3 指向這個(gè)變量的指針可以像這樣定義:
const unsigned char *__far ptr_on_far_const; 邏輯地址 vs 全局地址對(duì)于那些大小不大于4K(Banked RAM窗口的大小)的變量,使用邏輯地址比使用全局地址更有效率。
事件 邏輯地址 全局地址數(shù)據(jù)訪問(代碼大小) xy=3; 9字節(jié) 10字節(jié)
數(shù)據(jù)訪問(執(zhí)行速度) xy=3; 7周期 8周期
指針訪問(代碼大小) *xx=4; 11字節(jié) 12字節(jié)
指針訪問(執(zhí)行速度) *xx=4; 11周期 15周期
指針內(nèi)容遞增(代碼大小) (*xx)++; 11字節(jié) 15字節(jié)
指針內(nèi)容遞增(執(zhí)行速度) (*xx)++; 12周期 16周期
如果一個(gè)變量的大小大于4K,連接器將不得不把它分配地橫跨bank的邊界。這種情況下,我們推薦使用全局尋址來訪問這個(gè)變量
我們推薦使用全局尋址模式來訪問分配在FLASH中的常量或字符串常量
我們推薦為所有那些在運(yùn)行時(shí)使用邏輯地址的對(duì)象使用邏輯尋址。包括:棧,代碼,直接尋址的變量,擴(kuò)展尋址區(qū)的變量,I/O寄存器。
為了定義個(gè)分頁的變量,一定要使用DATA_SEG pragma。不要試圖使用 __far關(guān)鍵字來干這件事。far關(guān)鍵字指定了編譯器應(yīng)該怎么訪問一個(gè)變量,但它不會(huì)影響變量被分配的方式。
評(píng)論