SDCC Bankswitching (code banking) part 2

Posted by: 邱小新 at 下午3:08 in ,
範例下載,使用 ip210s,uart output "3210+dcba"。

前言

最近在玩 IP210S 的晶片,該顆 8051 使用外掛的 flash(SST 39VF040),有 512KB 之大,總共有 19 條 address line。之前寫的 SDCC Bankswitching 太簡略了,所以又提筆補充了一下。

  1. ip210s 對於 512K flash 的 address line 是放在 P1.7(18),P3.4(17),P3.5(16)。所以只要對該三個 GPIO 做設定,就可以讓 ip210s 定址到 512KB。
  2. 每個 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"。
  3. #pragma codeseg 的使用只對在它宣告下面的程式碼有用,以上則無效,因為內定值是不同的,所以才需用 #pragma codeseg 來變更。
  4. 在寫程式時,通常伴隨著一些存放在 code 的變數,如 code char str[] = "hello test\n\r";,一般而言,它們存放的區域也是放在 common 區,如果也把它們放在 bank 裏,則需宣告 #pragma constseg,如此 SDCC 才會把 code 變數也放到 bank 裏。
  5. SDCC 編譯出來的 hex 檔,包含了 common 及所有的 bank 程式,經由 hex2bin 的轉換後,只有 bank0 包含 common 程式碼,其它 bank 都沒有,只能利用 ultraedit 自己剪貼搞定。
  6. 使用 SDCC Bankswitching 需要在 main.c 宣告一個變數 unsigned char PSBANK=0;,並要先初始化為 0,這個 PSBANK 主要是存放目前的 bank 值。

__sdcc_banked_call

  1. 一般函數呼叫都是用 lcall _test1,但是在呼叫 banked 函數時,則是會先呼叫 __sdcc_banked_call,並把 banked 函數位址放到 r0~r2 當參數傳遞。
  2. 當要呼叫位於 bank? 區段的函數時,會把讓函數的位址放到 r0~r2,由於在 bank? 區段的函數位址包含了最高的 16~18 條位址線,所以會把 r2 當做 bank 的選擇,實際上 r2 只是代表 address line 的 16~23 位址線而已。由此可知,SDCC 的 Bankswitching 可以達到 224,也就 16M bytes。
  3. 一開始需先把目前的 bank 值(PSBANK)推入堆疊,以便離開時還原 bank 值。
  4. 由於函數可能利用 acc 來傳遞參數,所以必須先把 acc 值保存,xch a,r0 就是把 acc 保存在 r0。
  5. 接著把呼叫函數的位址推入堆疊,以便等一下 ret 時跳到該函數位址。
  6. 接著就是判斷 r2 值來切換位址線,我只會最笨的方法,貽笑大方了。
  7. 然後還原 acc 值,並用 ret 返回呼叫函數。
;../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

  1. 一般函數結束時都是直接執行 ret 回到上一層,但是在 banked 函數結束時,則是會呼叫 __sdcc_banked_ret,並經由 __sdcc_banked_ret 返回上一層。
  2. 一開始需先把備份的 bank 值(PSBANK)從堆疊取出,以便等會還原 address line。
  3. 由於函數可能利用 acc 來傳遞返回值,所以必須先把 acc 值保存,xch a,r0 就是把 acc 保存在 r0。
  4. 接著就是判斷 PSBANK 值來切換位址線,我只會最笨的方法,貽笑大方了。
  5. 然後還原 acc 值,並用 ret 返回上一層函數。
__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

0 意見

張貼留言