範例下載,使用 ip210s,uart output "3210+dcba"。
;../source/test2.c:19: test1();
mov r0,#_test1
mov r1,#(_test1 >> 8)
mov r2,#(_test1 >> 16)
lcall __sdcc_banked_call
__sdcc_banked_call::
push _PSBANK ;save return bank
xch a,r0 ;save Acc in r0, do not assume any register bank
push acc ;push LSB address
mov a,r1
push acc ;push MSB address
; set new bank
mov a,r2 ;get new bank
mov _PSBANK,acc
cjne a,#0x07,call_bank6
setb _P1_7
setb _P3_4
setb _P3_5
sjmp call_end
call_bank6:
;..... 略 ......
call_bank0:
clr _P1_7
clr _P3_4
clr _P3_5
call_end:
xch a,r0 ;restore Acc
ret ;make the call
__sdcc_banked_ret::
pop _PSBANK ;restore bank
xch a,r0 ;save Acc in r0, do not assume any register bank
mov a,_PSBANK
cjne a,#0x07,ret_bank6
setb _P1_7
setb _P3_4
setb _P3_5
sjmp ret_end
ret_bank6:
;...... 略 .......
ret_bank0:
clr _P1_7
clr _P3_4
clr _P3_5
ret_end:
xch a,r0 ;restore Acc
ret ;return to caller
前言
最近在玩 IP210S 的晶片,該顆 8051 使用外掛的 flash(SST 39VF040),有 512KB 之大,總共有 19 條 address line。之前寫的 SDCC Bankswitching 太簡略了,所以又提筆補充了一下。
- ip210s 對於 512K flash 的 address line 是放在 P1.7(18),P3.4(17),P3.5(16)。所以只要對該三個 GPIO 做設定,就可以讓 ip210s 定址到 512KB。
- 每個 bank 的起始位址設定指令為 "-Wl-b BANK1=0x18000",BANK1 為 #pragma codeseg 的名稱,0x18000 為該 bank 的起始位址。以 IP210S 為例,512/64=8,所以必須切成 8 banks。"-Wl-b BANK0=0x8000","-Wl-b BANK1=0x18000","-Wl-b BANK2=0x28000","-Wl-b BANK3=0x38000","-Wl-b BANK4=0x48000","-Wl-b BANK5=0x58000","-Wl-b BANK6=0x68000","-Wl-b BANK7=0x78000"。
- #pragma codeseg 的使用只對在它宣告下面的程式碼有用,以上則無效,因為內定值是不同的,所以才需用 #pragma codeseg 來變更。
- 在寫程式時,通常伴隨著一些存放在 code 的變數,如 code char str[] = "hello test\n\r";,一般而言,它們存放的區域也是放在 common 區,如果也把它們放在 bank 裏,則需宣告 #pragma constseg,如此 SDCC 才會把 code 變數也放到 bank 裏。
- SDCC 編譯出來的 hex 檔,包含了 common 及所有的 bank 程式,經由 hex2bin 的轉換後,只有 bank0 包含 common 程式碼,其它 bank 都沒有,只能利用 ultraedit 自己剪貼搞定。
- 使用 SDCC Bankswitching 需要在 main.c 宣告一個變數 unsigned char PSBANK=0;,並要先初始化為 0,這個 PSBANK 主要是存放目前的 bank 值。
__sdcc_banked_call
- 一般函數呼叫都是用 lcall _test1,但是在呼叫 banked 函數時,則是會先呼叫 __sdcc_banked_call,並把 banked 函數位址放到 r0~r2 當參數傳遞。
- 當要呼叫位於 bank? 區段的函數時,會把讓函數的位址放到 r0~r2,由於在 bank? 區段的函數位址包含了最高的 16~18 條位址線,所以會把 r2 當做 bank 的選擇,實際上 r2 只是代表 address line 的 16~23 位址線而已。由此可知,SDCC 的 Bankswitching 可以達到 224,也就 16M bytes。
- 一開始需先把目前的 bank 值(PSBANK)推入堆疊,以便離開時還原 bank 值。
- 由於函數可能利用 acc 來傳遞參數,所以必須先把 acc 值保存,xch a,r0 就是把 acc 保存在 r0。
- 接著把呼叫函數的位址推入堆疊,以便等一下 ret 時跳到該函數位址。
- 接著就是判斷 r2 值來切換位址線,我只會最笨的方法,貽笑大方了。
- 然後還原 acc 值,並用 ret 返回呼叫函數。
__sdcc_banked_ret
- 一般函數結束時都是直接執行 ret 回到上一層,但是在 banked 函數結束時,則是會呼叫 __sdcc_banked_ret,並經由 __sdcc_banked_ret 返回上一層。
- 一開始需先把備份的 bank 值(PSBANK)從堆疊取出,以便等會還原 address line。
- 由於函數可能利用 acc 來傳遞返回值,所以必須先把 acc 值保存,xch a,r0 就是把 acc 保存在 r0。
- 接著就是判斷 PSBANK 值來切換位址線,我只會最笨的方法,貽笑大方了。
- 然後還原 acc 值,並用 ret 返回上一層函數。
張貼留言