44B0啓動程序詳細說明文檔及ADS配置(轉自木瓜老C)

這是Samsung的S3C44B0(ARM7TDMI)芯片的經典bootloader,轉自木瓜老C的註解,很值得參考。

http://blog.chinaunix.net/u1/58640/showart_494549.html

 

; *******************************************************
; * NAME    : 44BINIT.S     *
; * Version : 10.JAn.2003    *
; * Description:     *
; * C start up codes    *
; * Configure memory, Initialize ISR ,stacks *
; * Initialize C-variables    *
; * Fill zeros into zero-initialized C-variables *
; * 思瑞訊電子增加註釋說明 2007-03-30
; *******************************************************

    GET ../inc/option.a
    GET ../inc/memcfg.a

;Interrupt Control      ;聲明符號常量定義寄存器的對應地址
INTPND     EQU 0x01e00004 
INTMOD     EQU 0x01e00008
INTMSK     EQU 0x01e0000c
I_ISPR     EQU 0x01e00020
I_CMST     EQU 0x01e0001c

;Watchdog timer
WTCON      EQU 0x01d30000

;Clock Controller
PLLCON     EQU 0x01d80000
CLKCON     EQU 0x01d80004
LOCKTIME   EQU 0x01d8000c

;Memory Controller
REFRESH    EQU 0x01c80024

;Pre-defined constants
USERMODE   EQU 0x10
FIQMODE    EQU 0x11
IRQMODE    EQU 0x12
SVCMODE    EQU 0x13
ABORTMODE  EQU 0x17
UNDEFMODE  EQU 0x1b
MODEMASK   EQU 0x1f
NOINT      EQU 0xc0

;check if tasm.exe is used.
    GBLL    THUMBCODE     ;定義全局邏輯變量THUMBCODE
    [ {CONFIG} = 16       ;相當於if (CONFIG==16)
THUMBCODE SETL {TRUE}     ;THUMBCODE=TRUE;
    CODE32                ;聲明爲32位指令集,即使用ARM指令進行編譯
    |                     ;else
THUMBCODE SETL {FALSE}    ;THUMBCODE=FALSE;
    ]     

    [ THUMBCODE           ;if THUMBCODE=TRUE
    CODE32                ;轉入32位編譯模式
    ]
;以下位宏定義,任何調用HandlerXXX HANDLER HandleXXX都將被下面的程序展開
;該宏定義的代碼用於將對應中斷服務程序ISR的入口地址裝載到PC中,可稱之爲“加載程序”
;本初始化程序定義了一個34個字空間的數據區(在文件最後),用於存放相應中斷服務程序的首地址。
;每個字空間都有一個標號,以HandleXXX命名。
;在向量中斷模式下使用“加載程序”來執行中斷服務程序。
;******************************************************************************
;**********向量(矢量)中斷和非向量(非矢量)中斷模式的概念與區別******************
;(一)www.chinasrx.com
;向量中斷模式是當CPU讀取位於0x18處的IRQ中斷指令的時候,系統自動讀取對應於該中斷源確定地址上的指令取代0x18處的指令,
;通過跳轉指令系統就直接跳轉到對應地址函數中,節省了中斷處理時間提高了中斷處理速度。
;例如 ADC 中斷的向量地址爲0xC0,則在0xC0處放如下代碼:ldr PC,=HandlerADC 當ADC中斷產生的時候系統會
;自動跳轉到HandlerADC函數中處理中斷。
;(二)www.chinasrx.com
;非向量中斷模式處理方式是一種傳統的中斷處理方法,當系統產生中斷的時候,系統將INTPND寄存器中對應標誌位置位,
;然後跳轉到位於0x18處的統一中斷函數中;
;該函數通過讀取INTPND寄存器中對應標誌位來判斷中斷源,並根據優先級關係再跳到對應中斷源的處理代碼中處理中斷。

    MACRO
$HandlerLabel HANDLER $HandleLabel

$HandlerLabel
                                 ;由於ADS僅支持FD(滿遞減)型堆棧
    sub     sp,sp,#4             ;將堆棧退一個字用於保存下面用到的R0
    stmfd   sp!,{r0}             ;將R0壓入堆棧
    ldr     r0,=$HandleLabel     ;將HandleLabel的地址賦給R0
    ldr     r0,[r0]              ;將HandleLabel的地址指向的內容(實際的執行地址)賦給R0
    str     r0,[sp,#4]           ;將對應的中斷函數首地址入棧保護
    ldmfd   sp!,{r0,pc}          ;將中斷函數的首地址出棧,放入PC中,系統將跳轉到對應中斷處理函數   
    MEND
   
;ARM的系統軟件開發中主要包含RO,RW,ZI三個段組成。
;其中RO爲代碼段;RW爲已經初始化的全局變量;ZI是未初始化的全局變量
;(對於GNU來說,依次對.text .data .bss段)
;值得說明的是:
;Bootloader要將RW段複製到RAM中並將ZI段清零;
;編譯器要使用下列段來記錄各段的起始和結束地址。
; |Image$$RO$$Base|  ;   RO段起始地址
; |Image$$RO$$Limit| ;   RO段結束地址+1
; |Image$$RW$$Base|  ;   RW段起始地址
; |Image$$RW$$Limit| ;   RW段結束地址+1
; |Image$$ZI$$Base|  ;   ZI段起始地址
; |Image$$ZI$$Limit| ;   ZI段結束地址+1
;這些標號的值是通過編譯器的設定來確定的,如編譯軟件中對RO-base和RW-Base的設定

    IMPORT |Image$$RO$$Limit|    ; ROM代碼的結束地址(rom數據的起始地址)
    IMPORT |Image$$RW$$Base|     ; RAM中需初始化的首地址
    IMPORT |Image$$ZI$$Base|     ; 需初始化爲0的全局變量的首地址
    IMPORT |Image$$ZI$$Limit|    ; 結束地址

    IMPORT  Main         ;主程序的入口
;以下爲代碼段
    AREA    Init,CODE,READONLY
;說明:
;關鍵字ENTRY告訴編譯器保留這段代碼。
;從代碼看Init段就是要寫入0x00地址的原始中斷向量,
;因此把這個文件編譯生成的44binit.O和Init填入ADS-Linker-Layout頁對應項中。
;【這樣編譯器會把該段代碼編譯到0X0地址。】
;異常中斷向量表【每個表項佔4個字節】
;一旦系統運行時有中斷髮生,即使移植了操作系統,如linux。
;處理器已經把控制權交給了操作系統,一旦發生中斷,處理器還是會跳轉到從0x0開始執行
;中斷向量表中的對應中斷。
;具體中斷向量佈局參考S3C44B0X的數據手冊
;例如 ADC 的中斷向量爲 0x000000c0 下面對應表中第49項位置
;對應向量地址爲 0x0+4*(49-1)= 0x000000c0


ENTRY          ;ENTRY程序入口標號需要頂格式寫,否則出錯。
    b ResetHandler       ;復位異常
    b HandlerUndef       ;未定義異常
    b HandlerSWI         ;軟件中斷異常
    b HandlerPabort      ;指令預取異常
    b HandlerDabort      ;數據預取異常
    b .                    ;保留
    b HandlerIRQ      ;外部中斷 外設中斷都是在這裏擴展的
    b HandlerFIQ      ;快速中斷
;***IMPORTANT NOTE***
;If the H/W vectored interrutp mode is enabled, The above two instructions should
;be changed like below, to work-around with H/W bug of S3C44B0X interrupt controller.
; b HandlerIRQ  ->  subs pc,lr,#4
; b HandlerIRQ  ->  subs pc,lr,#4
;說明:原文註明當使用向量中斷模式時,需用subs pc,lr,#4來代替前面的語句
;      這是原來S3C44B0X硬件中的一個BUG,後期推出的S3C44B0X已經解決此BUG,但是爲了兼容
;      早期的版本,用subs pc,lr,#4替換後也可以正常工作,相當於現在的硬件中兩條語句都
;      可以兼容,後期的器件手冊中已經註明可以直接採用b HandlerIRQ的方式

;www.chinasrx.com

VECTOR_BRANCH
    ldr pc,=HandlerEINT0    ;mGA    H/W interrupt vector table
    ldr pc,=HandlerEINT1    ;
    ldr pc,=HandlerEINT2    ;
    ldr pc,=HandlerEINT3    ;
    ldr pc,=HandlerEINT4567 ;
    ldr pc,=HandlerTICK     ;mGA
    b .
    b .
    ldr pc,=HandlerZDMA0    ;mGB
    ldr pc,=HandlerZDMA1    ;
    ldr pc,=HandlerBDMA0    ;
    ldr pc,=HandlerBDMA1    ;
    ldr pc,=HandlerWDT     ;
    ldr pc,=HandlerUERR01   ;mGB
    b .
    b .
    ldr pc,=HandlerTIMER0   ;mGC
    ldr pc,=HandlerTIMER1   ;
    ldr pc,=HandlerTIMER2   ;
    ldr pc,=HandlerTIMER3   ;
    ldr pc,=HandlerTIMER4   ;
    ldr pc,=HandlerTIMER5   ;mGC
    b .
    b .
    ldr pc,=HandlerURXD0    ;mGD
    ldr pc,=HandlerURXD1    ;
    ldr pc,=HandlerIIC     ;
    ldr pc,=HandlerSIO     ;
    ldr pc,=HandlerUTXD0    ;
    ldr pc,=HandlerUTXD1    ;mGD
    b .
    b .
    ldr pc,=HandlerRTC     ;mGKA
    b .       ;
    b .       ;
    b .       ;
    b .       ;
    b .       ;mGKA
    b .
    b .
    ldr pc,=HandlerADC     ;mGKB
    b .       ;
    b .       ;
    b .       ;
    b .       ;
    b .       ;mGKB
    b .
    b .
;0xe0=EnterPWDN
    ldr pc,=EnterPWDN

    LTORG
;下面是具體的中斷處理函數跳轉的宏,通過上面的$HandlerLabel的宏定義
;展開後跳轉到對應的中斷處理函數(ISR)處理中斷(對於向量中斷)

HandlerFIQ    HANDLER HandleFIQ
HandlerIRQ    HANDLER HandleIRQ
HandlerUndef HANDLER HandleUndef
HandlerSWI    HANDLER HandleSWI
HandlerDabort HANDLER HandleDabort
HandlerPabort HANDLER HandlePabort

HandlerADC     HANDLER HandleADC
HandlerRTC     HANDLER HandleRTC
HandlerUTXD1 HANDLER HandleUTXD1
HandlerUTXD0 HANDLER HandleUTXD0
HandlerSIO     HANDLER HandleSIO
HandlerIIC      HANDLER HandleIIC
HandlerURXD1 HANDLER HandleURXD1
HandlerURXD0 HANDLER HandleURXD0
HandlerTIMER5 HANDLER HandleTIMER5
HandlerTIMER4 HANDLER HandleTIMER4
HandlerTIMER3 HANDLER HandleTIMER3
HandlerTIMER2 HANDLER HandleTIMER2
HandlerTIMER1 HANDLER HandleTIMER1
HandlerTIMER0 HANDLER HandleTIMER0
HandlerUERR01 HANDLER HandleUERR01
HandlerWDT     HANDLER HandleWDT
HandlerBDMA1  HANDLER HandleBDMA1
HandlerBDMA0  HANDLER HandleBDMA0
HandlerZDMA1  HANDLER HandleZDMA1
HandlerZDMA0  HANDLER HandleZDMA0
HandlerTICK     HANDLER HandleTICK
HandlerEINT4567 HANDLER HandleEINT4567
HandlerEINT3    HANDLER HandleEINT3
HandlerEINT2    HANDLER HandleEINT2
HandlerEINT1    HANDLER HandleEINT1
HandlerEINT0    HANDLER HandleEINT0


;One of the following two routines can be used for non-vectored interrupt.
;下面這段程序是用來處理非向量中斷,具體判斷I_ISPR中各位是否置1 置1表示目前此中斷等待響應(每次只能有一位置1),從最高優先級中斷位開始判斷,檢測到等待服務
;中斷就將pc置爲中斷服務函數首地址
IsrIRQ         ;using I_ISPR register.
    sub     sp,sp,#4           ;reserved for PC
    stmfd   sp!,{r8-r9}  

;IMPORTANT CAUTION
;if I_ISPC isn't used properly, I_ISPR can be 0 in this routine.

    ldr       r9,=I_ISPR
    ldr       r9,[r9]
    mov     r8,#0x0
0
    movs    r9,r9,lsr #1
    bcs     %F1
    add     r8,r8,#4
    b        %B0

1
    ldr       r9,=HandleADC
    add     r9,r9,r8
    ldr       r9,[r9]
    str      r9,[sp,#8]
    ldmfd   sp!,{r8-r9,pc}


;****************************************************
;* START         *www.chinasrx.com
;****************************************************
;板子上電和復位後,程序開始從位於0x0處執行b ResetHandler ,從而跳轉到這裏執行程序。
;板子上電覆位後,執行以下幾個步驟,這裏通過標號在註釋中加1,2,3....表示,標號表示執行順序
;1.禁止看門狗,屏蔽所有中斷
ResetHandler
    ldr     r0,=WTCON     ;watch dog disable
    ldr     r1,=0x0  
    str     r1,[r0]

    ldr     r0,=INTMSK
    ldr     r1,=0x07ffffff  ;all interrupt disable
    str     r1,[r0]
;2.根據工作頻率設置PLL
;這裏介紹一下計算公式
; Fpllo=(m*Fin)/(p*2^s)
; m=MDIV+8,p=PDIV+2,s=SDIV
; Fpllo必須大於20Mhz小於66Mhz
; Fpllo*2^s必須小於170Mhz
;如下面的PLLCON設定中的M_DIV P_DIV S_DIV是取自option.h中
;#elif  (MCLK==40000000)
;#define  PLL_M (0x48)
;#define  PLL_P (0x3)
;#define  PLL_S (0x2)
;所以m=MDIV+8=80,p=PDIV+2=5,s=SDIV=2
;硬件使用晶振爲10Mhz,即Fin=10Mhz
;Fpllo=80*10/5*2^2=40Mhz
    ;****************************************************
    ;* Set clock control registers   *
    ;****************************************************
    ldr r0,=LOCKTIME
    ldr r1,=800          ; count = t_lock * Fin (t_lock=200us, Fin=4MHz) = 800
    str r1,[r0]

    [ PLLONSTART
ldr r0,=PLLCON      ;temporary setting of PLL
ldr r1,=((M_DIV<<12)+(P_DIV<<4)+S_DIV) ;Fin=10MHz,Fout=40MHz
str r1,[r0]
    ]

    ldr     r0,=CLKCON  
    ldr     r1,=0x7ff8        ;All unit block CLK enable
    str     r1,[r0]
;3.設置存儲相關寄存器的程序
;主要設置SDRAM,flash ROM 存儲器連接和工作時序的程序,以及片選定義的程序
;SMRDATA map在下面的程序中定義
;SMRDATA中涉及的值請參考memcfg.s程序
;具體寄存器各位含義請參考S3C44B0X Specification

;www.chinasrx.com
    ;****************************************************
    ;* Set memory control registers   * 
    ;****************************************************
    ldr      r0,=SMRDATA
    ldmia   r0,{r1-r13}
    ldr      r0,=0x01c80000  ;BWSCON Address
    stmia   r0,{r1-r13}

    ;****************************************************
    ;* Initialize stacks    *
    ;****************************************************
    ldr     sp, =SVCStack ;Why?
    bl      InitStacks
;
;5.設置缺省中斷處理函數
    ;****************************************************
    ;* Setup IRQ handler    *
    ;****************************************************
    ldr     r0,=HandleIRQ  ;This routine is needed
    ldr     r1,=IsrIRQ   ;if there isn't 'subs pc,lr,#4' at 0x18, 0x1c
    str     r1,[r0]
;6.將數據段拷貝到RAM中,將ZI數據段清零,跳入C語言的main函數執行。
;到這裏Bootloader初步引導結束。拷貝|Image$$RO$$Limit|起始的大小爲(|Image$$ZI$$Base|-|Image$$RW$$Base|)
;的數據拷貝到|Image$$RW$$Base|對應的數據單元處。
    ;********************************************************
    ;* Copy and paste RW data/zero initialized data     *
    ;********************************************************
    LDR     r0, =|Image$$RO$$Limit| ; Get pointer to ROM data
    LDR     r1, =|Image$$RW$$Base| ; and RAM copy
    LDR     r3, =|Image$$ZI$$Base|
;Zero init base => top of initialised data
  
    CMP     r0, r1     ; Check that they are different
    BEQ     %F1

    CMP     r1, r3             ; Copy init data
    LDRCC   r2, [r0], #4    ;--> LDRCC r2, [r0] + ADD r0, r0, #4  
    STRCC   r2, [r1], #4    ;--> STRCC r2, [r1] + ADD r1, r1, #4
    BCC     %B0

    LDR      r1, =|Image$$ZI$$Limit| ; Top of zero init segment
    MOV     r2, #0

    CMP      r3, r1     ; Zero init
    STRCC   r2, [r3], #4
    BCC     %B2

    [ :LNOT:THUMBCODE
BL Main     ;Don't use main() because ......
;跳入main()函數
B .     
    ]

    [ THUMBCODE      ;for start-up code for Thumb mode
orr     lr,pc,#1
bx      lr
CODE16
bl      Main               ;Don't use main() because ......
b       .
CODE32
    ]
;4.初始化各模式下的堆棧指針
;****************************************************
;* The function for initializing stack     *
;****************************************************
InitStacks
;Don't use DRAM,such as stmfd,ldmfd......
;SVCstack is initialized before
;Under toolkit ver 2.50, 'msr cpsr,r1' can be used instead of 'msr cpsr_cxsf,r1'

    mrs     r0,cpsr
    bic     r0,r0,#MODEMASK
    orr     r1,r0,#UNDEFMODE|NOINT
    msr     cpsr_cxsf,r1    ;UndefMode
    ldr     sp,=UndefStack

    orr     r1,r0,#ABORTMODE|NOINT
    msr     cpsr_cxsf,r1        ;AbortMode
    ldr     sp,=AbortStack

    orr     r1,r0,#IRQMODE|NOINT
    msr     cpsr_cxsf,r1        ;IRQMode
    ldr     sp,=IRQStack

    orr     r1,r0,#FIQMODE|NOINT
    msr     cpsr_cxsf,r1        ;FIQMode
    ldr     sp,=FIQStack

    bic     r0,r0,#MODEMASK|NOINT
    orr     r1,r0,#SVCMODE
    msr     cpsr_cxsf,r1        ;SVCMode
    ldr     sp,=SVCStack

;USER mode is not initialized.
    mov     pc,lr       ;The LR register may be not valid for the mode changes.
;
;下面是PWDN模式下的相關寄存器的定義
;****************************************************
;* The function for entering power down mode   *
;****************************************************
;void EnterPWDN(int CLKCON);
EnterPWDN
    mov     r2,r0               ;r0=CLKCON
    ldr       r0,=REFRESH 
    ldr       r3,[r0]
    mov     r1, r3
    orr       r1, r1, #0x400000   ;self-refresh enable
    str       r1, [r0]

    nop     ;Wait until self-refresh is issued. May not be needed.
    nop     ;If the other bus master holds the bus, ...
    nop     ; mov r0, r0
    nop
    nop
    nop
    nop

;enter POWERDN mode
    ldr     r0,=CLKCON
    str     r2,[r0]

;wait until enter SL_IDLE,STOP mode and until wake-up
    mov     r0,#0xff
0   subs    r0,r0,#1
    bne     %B0

;exit from DRAM/SDRAM self refresh mode.
    ldr     r0,=REFRESH
    str     r3,[r0]
   
    mov     pc,lr

    LTORG
;
;
;這是上面提到的對存儲寄存器初始化的數據映射表(DATA Map)
SMRDATA DATA
;*****************************************************************
;* Memory configuration has to be optimized for best performance *
;* The following parameter is not optimized.                     *
;*****************************************************************

;*** memory access cycle parameter strategy ***
; 1) Even FP-DRAM, EDO setting has more late fetch point by half-clock
; 2) The memory settings,here, are made the safe parameters even at 66Mhz.
; 3) FP-DRAM Parameters:tRCD=3 for tRAC, tcas=2 for pad delay, tcp=2 for bus load.
; 4) DRAM refresh rate is for 40Mhz.

  
DCD 0x11110090 ;Bank0=OM[1:0], Bank1~Bank7=16bit, bank2=8bit;
DCD ((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC)) ;GCS0
DCD ((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC)) ;GCS1
DCD ((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC)) ;GCS2
DCD ((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC)) ;GCS3
DCD ((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC)) ;GCS4
DCD ((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC)) ;GCS5
DCD ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN)) ;GCS6
DCD ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN)) ;GCS7
DCD ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT) ;REFRESH RFEN=1, TREFMD=0, trp=3clk, trc=5clk, tchr=3clk,count=1019
DCD 0x16       ;SCLK power mode, BANKSIZE 32M/32M
DCD 0x20       ;MRSR6 CL=2clk
DCD 0x20       ;MRSR7

ALIGN

;下面是對RAM區域數據映射表的(DATA Map)的定義
AREA RamData, DATA, READWRITE
;從地址(_ISR_STARTADDRESS-0x500)處保留指定字節數的空間
^ (_ISR_STARTADDRESS-0x500)
   
UserStack # 256 ;c1(c7)ffa00  ;以地址(_ISR_STARTADDRESS-0x500)起始保留連續256個字節 
SVCStack   # 256 ;c1(c7)ffb00  ;緊接着保留256個字節
UndefStack # 256 ;c1(c7)ffc00
AbortStack # 256 ;c1(c7)ffd00
IRQStack    # 256 ;c1(c7)ffe00
FIQStack    # 0 ;c1(c7)fff00

;從地址_ISR_STARTADDRESS處保留指定字節數的空間
  ^ _ISR_STARTADDRESS   ;該值在OPTION.h中定義
HandleReset # 4      ;保留4個連續字節
HandleUndef # 4
HandleSWI   # 4
HandlePabort # 4
HandleDabort # 4
HandleReserved # 4
HandleIRQ     # 4
HandleFIQ     # 4

;Don't use the label 'IntVectorTable',
;because armasm.exe cann't recognize this label correctly.
;the value is different with an address you think it may be.
;IntVectorTable
HandleADC    # 4
HandleRTC    # 4
HandleUTXD1 # 4
HandleUTXD0 # 4
HandleSIO     # 4
HandleIIC      # 4
HandleURXD1 # 4
HandleURXD0 # 4
HandleTIMER5 # 4
HandleTIMER4 # 4
HandleTIMER3 # 4
HandleTIMER2 # 4
HandleTIMER1 # 4
HandleTIMER0 # 4
HandleUERR01 # 4
HandleWDT     # 4
HandleBDMA1 # 4
HandleBDMA0 # 4
HandleZDMA1 # 4
HandleZDMA0 # 4
HandleTICK    # 4
HandleEINT4567 # 4
HandleEINT3  # 4
HandleEINT2  # 4
HandleEINT1  # 4
HandleEINT0  # 4   ;0xc1(c7)fff84

  END

------------------------------------------------------------------------------------------------------------------------------------
 
------------------------------------------------------------------------------------------------------------------------------------
44B0的初始化程序就是初始化各個關鍵的寄存器,建立中斷向量,然後轉移到主函數去執行程序。
不過44B0不支持地址映射,所以程序不COPY到RAM種執行。44B0初始化對我們廣大
初學者來說,比較難理解的是中斷的處理和一些少見的操作符號,44b0的中斷子程序地址存放在初始化程序最後就是
HandleADC       #      4
HandleRTC       #      4
HandleUTXD1     #      4
HandleUTXD0     #      4
HandleSIO       #      4
HandleIIC       #      4
HandleURXD1     #      4
HandleURXD0     #      4
這一段,它的其實地址是ISR_STARTADDRESS,個人寫中斷程序的時候,子程序地址被編譯器連放在相應的位置。初始化完成後,程序轉通過BL      Main 轉到用戶定義的主程序上執行。以下是我個人的一些理解:
  GBLL   THUMBCODE
  [ {CONFIG} = 16     
THUMBCODE SETL      {TRUE}
  CODE32
  |  
THUMBCODE SETL      {FALSE}
  ]

  [ THUMBCODE
  CODE32   ;for start-up code for Thumb mode
  ]
×××××××××××××××××××××××
其中[=IF ,|=ELSE ,]= ENDIF, CODE32 表明以下操作都在ARM狀態。這些都是僞操作
這段我理解爲設定THUMCODE的值,然後確定,用戶的程序是在ARM狀態還是THUM狀態。不過不管THUMCODE是何值,下面代碼都是ARM狀態這段沒有什麼很複雜的,就是這三個[,|,]操作符讓我迷惑了半天,翻了半天書才找到解釋


  MACRO 宏 僞操作
$HandlerLabel HANDLER(宏的名稱) $HandleLabel(宏的參數)

$HandlerLabel
  sub     sp,sp,#4         ;decrement sp(to store jump address)
  stmfd   sp!,{r0}         ;PUSH the work register to stack(lr does't push because it return to original address)
  ldr     r0,=$HandleLabel;load the address of HandleXXX to r0
  ldr     r0,[r0]         ;load the contents(service routine start address) of HandleXXX
  str     r0,[sp,#4]         ;store the contents(ISR) of HandleXXX to stack
  ldmfd   sp!,{r0,pc}         ;POP the work register and pc(jump to ISR)
  MEND
*******************************
這 段當初我覺得比較難理解,不過通過看各種程序,對這段有了一個基本的理解。這個宏的作用是把各個中斷程序的地址裝入當前的PC,44B0有兩種裝斷模式 一種是沒有中斷向量表,一種是使用中斷向量表的使用中斷向量表只能是IRQ方式,當使用中斷向量表的時候,中斷髮生時由44B0的中斷控制器自動跳轉到相 應的位置。比如在中斷向量表的模式下,一個外部中斷0發生程序自動跳轉到 地址0X20處,0X20地址單元的指令時ldr pc,=HandlerEINT0因而程序PC跳到HandlerEINT0處,執行這個宏操作,把外部中斷的函數的地址賦給PC。 44B0裏面定義了一個#define pISR_EINT0      (*(unsigned *)(_ISR_STARTADDRESS+0x84)) ,_ISR_STARTADDRES是中斷程序地址的起始地址,_ISR_STARTADDRESS+0X84是HandleEINT0的地址
例如一個外部中斷函數名void EXINT(),程序裏執行 pISR_EINT0=(unsigned)EXIT,就把自己的函數地址賦給了標號爲HandleEINT0處的內存單元
IMPORT      |Image$$RO$$Limit| ; End of ROM code (=start of ROM data)
IMPORT      |Image$$RW$$Base|   ; Base of RAM to initialise
IMPORT      |Image$$ZI$$Base|   ; Base and limit of area
IMPORT      |Image$$ZI$$Limit| ; to zero initialise
××××××××××××××××××××××××××××××××××
這段我個人的理解爲這些是連接器生成的於輸出段相關的符號,是在沒有使用SCATTER文件的情況可以調用。
這段指出了在ROM和RAM種的數據的地址,這些地址應該是連接器生成的,不過爲什麼能調用
連接器生產的符號,我不大明白其中的原因,還希望各位說說自己的理解
IsrIRQ      ;using I_ISPR register.
  sub     sp,sp,#4     ;reserved for PC
  stmfd   sp!,{r8-r9}  

     ;IMPORTANT CAUTION
     ;if I_ISPC isn't used properly, I_ISPR can be 0 in this routine.

  ldr         r9,=I_ISPR
  ldr         r9,[r9]
  mov         r8,#0x0
0
  movs   r9,r9,lsr #1
  bcs    %F1
  add    r8,r8,#4
  b      %B0

1
  ldr         r9,=HandleADC
  add         r9,r9,r8
  ldr         r9,[r9]
  str         r9,[sp,#8]
  ldmfd       sp!,{r8-r9,pc}
×××××××××××××××××××××××
這段是沒有使用裝斷向量模式下如何裝載中斷子程序,因爲44B0有30箇中斷源,所以需要程序處理以確定調用那個中斷程序
0,1是局部標號,%B是向後搜索局部標號, %F是向前搜索局部標號 。都是僞操作
I_ISPR寄存器各位表明發生了應該調用那個中斷子程序。只能1位置位,其它位爲0,比如說串口1發送中斷髮生,這時I_ISPR的
值爲0X04,
    ldr    r9,=I_ISPR
    ldr    r9,[r9] 兩條指令後,r9的內容爲0X4 ,
    movs   r9,r9,lsr #1 r9內容右移一位
    bcs    %F1 判斷是否把置位是否轉移到C位,
    add    r8,r8,#4 如果沒有的R8加4
如 果r9內容爲0x04 需要右移3次 ,之後r8的內容爲8 然後HandleADC的地址 加上r8的值 就是串口1發送中斷的地址,這個地址的內容是中斷子程序的地址再說明幾個僞操作:^=MAP.     #=field別的方面我覺得比較容易理解了,就不多講了。

------------------------------------------------------------------------------------------------------------------------------------
 
------------------------------------------------------------------------------------------------------------------------------------

ARM彙編程序分析過程中,比較難理解的是他的僞操作、宏指令和僞指令。本文是結合44B0X引導程序中出現僞操作、宏指令和僞指令進行總結,便於進一步分析44B0X的引導。

 
*****************************************************
一、GET option.s
 
// GET和INCLUDE功能相同
功能:引進一個被編譯過的文件。
格式:GET    filename
其中:fiename    彙編時引入的文件名,可以有路徑名。
    GET符號在彙編時對宏定義,EQU符號以及存儲映射時是很有用的,在引入文件彙編完以後,彙編將從GET符號後開始。在被引入的文件中可能有GET符號再引入其他的文件。GET符號不能用來引入目標文件。
 
*****************************************************
二、INTPND EQU 0x01e00004
 
//EQU可以用“*”代替 ,在閱讀源程序時注意。
功能:對一個數字常量賦予一個符號名。
格式:name    EQU   expression
其中:name   符號名。Expression    寄存器相關或者程序相關的固定值。
    使用EQU定義常量,與C語言中用#define定義一個常量相同。
例:num   EQU   2    ;   數字2賦予符號num
 
*****************************************************
三、GBLL    THUMBCODE
        [ {CONFIG} = 16
            THUMBCODE SETL {TRUE}
            CODE32
        |  
            THUMBCODE SETL {FALSE}
        ]
        [ THUMBCODE
            CODE32   ;for start-up code for Thumb mode
        ]
 
//其中[=IF ,|=ELSE ,]= ENDIF, CODE32 表明以下操作都在ARM狀態。這些都是僞操作這段理解爲設定THUMCODE的值,然後確定,用戶的程序是在ARM狀態還是THUM狀態。
*****************************************************
四、MACRO

        $HandlerLabel HANDLER $HandleLabel
        $HandlerLabel
        sub sp,sp,#4 ;decrement sp(to store jump address)
        stmfd sp!,{r0} ;PUSH the work register to stack
        ldr r0,=$HandleLabel;load the address of HandleXXX to r0
        ldr r0,[r0] ;load the contents(service routine start address) of HandleXXX
        str r0,[sp,#4] ;store the contents(ISR) of HandleXXX to stack
        ldmfd sp!,{r0,pc} ;POP the work register and pc(jump to ISR)
        MEND
 
//MACRO……MEND
功能:標誌以下宏的定義。
格式:MACRO
     Macro_prototype
     MEND
宏表達式的格式如下:
{$label}   macroname    {$ parameter{,parameter2}…}
其中:
$ label   參數,在宏使用時,被給定的符號替代。
Macroname   宏的名稱,並不一定以一條指令或者符號名開始。
$parameter    在宏使用時,被替代的參數,格式爲:$parameter=“default value”
   在 宏體中,參數如:$parameter和變量一樣使用,在被宏引用時,被賦於新值,參數必須用“$”符號加於區別。$label在宏定義內部符號時很有 用,可以看作宏的參數。使用“|”符號作爲使用一個參數缺省值的變量,如果使用的是一個空格符串,將省去該變量。在使用內部標誌的宏定義中,將內部標誌定 義爲帶後綴的標誌,將會很有用。如果在擴展中空間不夠,可以作爲參數和後繼文字之間或者參數之間使用圓點隔開,但在文本和後繼參數之間不能使用圓點。宏可 以定義局部變量的範圍。宏還可以嵌套使用。
例:
MACRO
$label    xmac    $p1,$p2
          LCLS   err
$labell,loopl
          BGE    $pl
$labell,loop2
          BL     $p1
          BEG      $p1
          BEG      $labell,loop2
MEND 
 
*****************************************************
五、$和$$
 
//$臨時變量替換,若程序中需要用字符$則用$$來表示,通常情況下,包含在兩個||之間的$並不表示進行變量替換,但是如果|線是在雙引號內,則將進行變量替換。用“.”來分割出變量名的用法,
 GBLS STR1
 GBLS STR2
STR1 SETS "AAA"
STR2 SETS "BBB$$STR1.CCC"  //彙編後STR2的值爲bbAAACCC
 
*****************************************************
六、 IMPORT  Main    ; The main entry of mon program
 
//該僞操作告訴編譯器當前的符號不是在本文件中定義的,在本源文件中可能引用該符號,而不論該源文件是否使用該符號,該符號都將被加入到本源文件中。
格式:
IMPORT symbol {[WEAK]}
    symbol 引用的符號的名稱,他是區分大小寫的,[WEAK]指定這個選項後,如果symbol所在的源文件中沒有被定義,編譯器也不會報錯。他和EXTERN作用 相同,不同之處在於,如果本源文件沒有實際引用該符號,該符號將不會被加入到本源文件的符號表中。

*****************************************************
七、AREA    Init,CODE,READONLY
       ENTRY
 
//功能:指示彙編器彙編一段新的代碼或新的數據區。
格式:
name  給出的特定段名。以數字開頭,必須加豎線,否則,將報錯,例如:|1_Data-Area|。某些名字已保留,如:|C$$code|已經被C編譯器用作代碼,或者用作與C庫相連的代碼段。
Attr    段名屬性,下列屬性是有效的:
ALIGN=expression
缺省狀態下,AOF段將按4個字節對準,expression可以是2~31之間的整數,該段將按2(上標爲expression)字節對準。例如,espression等於
10,該段將按1KB對準。
 
CODE        特定機器指令,缺省爲READONLY。
COMDEF      通用段定義。該AOF段可能包括代碼和數據,但必須與其他段名相區別。
COMMON      通用數據段,無須再註釋定義任何代碼和數據,通常由鏈接器初始化爲零。
DATA        包含數據,但是不包含指令,缺省爲READWRITE
INTERWORK   表明代碼段可以適用ARM/Thumb interworking功能。
NOINIT      表明數據段可以初始化爲零,只包含指示符。
PIC         表明定位獨立段,可以不修改情況下,在任意地址執行。
READONLY    表明該段可讀可寫。
 
   彙編時,必須至少有一個AREA指示符。使用AREA符號可以將源程序區分,但是必須不重名。通常需要獨立的AOF段做爲代碼或者數據 段,較大程序可以分爲多個代碼段。AOF段可以定義局部標籤的範圍,可以使用ROUT符號。如果沒有任何的AREA指示符定義,彙編器將會產生名 爲|$$$$$$$|的AOF段和一條診斷信息,將限制由於缺少指示符而產生的錯誤信息,但是並不一定會成功彙編。
 
*****************************************************
八、LTORG
 
//LTORG是在此指令出現的地方放一個文本池(literal pool). 在ARM彙編中常用到
    ldr   r0, =instruction     將地址instruction載入r0
    此時編譯器將ldr儘可能的轉變成mov或mvn指令。 如果轉變不成, 將產生一個ldr指令,通過pc相對地址從一塊保存常數的內存區讀出instruction的值。此內存區既是文本池。一般的, 文本池放在END指令之後的地方。但是, 如果偏移地址大於4k空間, ldr指令會出錯(因爲ldr的相對偏移地址爲12-bit的值). 此時使用LTORG放到會出錯的ldr指令附近,以解決此問題。 編譯器會收集沒有分配的ldr的值放到此文本池中
。所以必須在LDR指令前後4KB的範圍內用LTORG顯式地在代碼段中添加一個文字池。
 
*****************************************************
九、LDR r0,=WTCON ;watch dog disable 
      LDR r1,=0x0
 
功能:將一個32位常量或地址讀取至寄存器。
格式:
LDR{condition} register,=[expression|Label-expression]
其中:
condition             可選的條件代碼。
register              讀取的寄存器。
expression            數字常量:
    如果該數字常量在MOV或MVN指令的範圍中,彙編器會產生合適的指令;
    如果該數字量不在MOV或MVN指令的範圍中,彙編器把該常量於程序後,用程序相關的LDR僞指令讀取,PC與該常量的偏移量不得超過4KB。
Label-expression      程序相關的或外部的表達式。彙編器將其存放在程序後的常量庫(稱爲文字池(literal pool))中,用程序相關的LDR僞指令讀取,PC與與該常量的偏移量不得超過4KB。
LDR僞指令的使用有兩個目的:
     對於不能被MOV和MVN指令所讀取的立即數,將其變成常量,進行讀取。
     將一個程序相關的或外部的表達式讀取進寄存器中。
例:
LDR  R1, =0xfff
LDR  R2, =place
 
*****************************************************
十、DCD 0x11110090
      ;Bank0=OM[1:0], Bank1~Bank7=16bit, bank2=8bit;
 
//DCD或“&”
功能: 分配一個或多個字,從4個字節邊界開始。
格式:
{label}DCD  expression{,expression}…
其中:
expression    可以是:
一個數學表達式;
一個程序相關的表達式。
    如果在Thumb代碼中,使用DCD符號定義帶標誌的數據時則必須使用DATA符號。
    按4個字節對準時,DCD符號會在第一個字節之前插入3個字節的空字符,如果無須對準的話,可以使用DCDU符號。
例:
datal   DCD    1,5,20
data2   DCD    mem06
data3    DCD  glb+4
 
*****************************************************
十一、ALIGN
 
//功能:從1個字邊界開始。
格式:
ALIGN  {expression  {,offset-expression} }
其中:
    expression    2(上標爲0)到2(上標爲31)之間的任意數冪,當前按2(上標爲n)字節對準,如果該參數沒有指定,ALIGN將按字對準。
    Offset-expression  定義expression指定的對準方式的字節偏移量。
    使用ALIGN符號,保證程序正確對準。對於Thumb地址,使用ALIGN符號保證其按字對準,例如:ADR  Thuub僞指令只能讀取字對準的地址。
    在代碼段出現數據定義符時,使用ALIGE符號。當在代碼段使用數據定義符(DCB,DCW,DCWU,DCDU和%),程序計數器PC並不一定按字對準。
    彙編器會在下一條指令時插入3個字節,保證:
    ARM狀態下按字對準;
    Thumb狀態下按半字對準。
    在Thumb狀態下,可以使用ALIGN2對Thumb代碼按半字對準。
    使用ALIGN狀態下,還可以充分利用一些ARM處理器的Cache,例如,ARM940T有一個每行4字的Cache,使用ALIGN16按16字節對準,從而最大限度使用Cache。
 
*****************************************************
十二、^ _ISR_STARTADDRESS
 
//MAP與"^"
    MAP用於定義一個結構化的內存表(StorageMAP)的首地址。此時,內存表的位置計數器{VAR}(彙編器的內置變量)設置成該地址值。MAP可以用”^”代替。
語法:MAP  expr {,base-register}
    其中,expr爲數字表達式或者是程序中已經定義過的標號。Base-register爲一個寄存器。當指令中沒有Base-register 時,expr爲結構化內存表的首地址。此時,內存表的位置計數器{VAR}設置成該地址值。當指令中包含這一項時,結構化內存表的首地址爲expr和 Base-register寄存器內容的和。
使用說明:MAP僞操作和FIELD僞操作配合使用來定義結構化的內存表結構。
舉例:MAP僞操作
MAP  fun  ;fun就是內存表的首地址
MAP   0x100,R9  ;內存表的首地址爲 R9+0x100
 
*****************************************************
十三、HandleReset # 4 
         HandleUndef # 4 
         HandleSWI # 4
 
//FIELD和"#"
FIELD 用於定義一個結構化的內存表中的數據域。FIELD 可用“#”代替。
語法:{label} FIELD expr
其中:{label}爲可選的。當指令中包含這一項時,label的值爲當前內存表的位置計數器{VAR}的值。彙編編譯器處理了這條FIELD僞操作後。
內存表計數器的值將加上expr.expr表示本數據域在內存中所佔的字節數。
使用說明:MAP僞操作和FIELD僞操作配合使用來定義結構化的內存表結構。MAP僞操作定義內存表的首地址。FIELD僞操作定義內存表的數據域的字節長度,並可以爲每一格數據域指定一個標號,其他指令可以引用該標號。
MAP僞操作中的Base-registe寄存器值隊以其後所有FIELD僞操作定義的數據域是默認使用的,直到遇到新的包含Base- registe項的MAP僞操作需要特別注意的是,MAP僞操作和FIELD僞操作僅僅是定義數據結構,他們並不實際分配內存單元。由MAP僞操作和 FIELD僞操作配合定義的內存表有3種:基於絕對地址的內存表,基於相對地址的內存表和基於PC的內存表。
舉例:基於絕對地址的內存表
    用僞操作序列定義一個內存表,其首地址爲固定的地址8192(0X2000),該內存表中包括5個數據域。   
    Consta長度爲4個字節;constb長爲4個字節,x長爲8字節;y長爲8字節;string長爲16字節。這種內存表成爲基於絕對地址的內存表。
MAP  8192 ; //內存表的首地址8192(0x2000)
Consta FIELD 4 ; //consta 長爲4字節,相對位置爲0
Constb FIELD 4; //constb長爲4字節,相對位置爲4
X   FIELD  8; // X長爲8字節,相對位置爲8
Y    FIELD 8; // y長爲8字節,相對位置爲16
String FIELD 16 ;// String爲16字節,相對位置爲24
在指令中,可以這樣引用內存表中的數據域;
LDR R0,consta; //將consta地址處對應內存加載到R0上面的指令僅僅可以訪問LDR指令前後4KB地址範圍的數據域。
舉例:相對絕對地址的內存表
    下面的僞操作序列定義一個內存表,其首地址爲0與R9寄存器值得和,該內存表中包含5個數據域。這種表稱爲相對地址的內存表。
MAP 0,R9;//內存表的首地址寄存器R9的值
Consta FIELD 4 ; //consta 長爲4字節,相對位置爲0
Constb FIELD 4; //constb長爲4字節,相對位置爲4
X   FIELD  8; // X長爲8字節,相對位置爲8
Y    FIELD 8; // y長爲8字節,相對位置爲16
String FIELD 16;// String爲16字節,相對位置爲24
可以通過下面的指令訪問地址範圍超過4KB的數據;
ADR  R9, Field ;  //僞指令
LDR  R5,Constb;//相當於LDR R5,[R9,#4]
    在這裏,內存表中的數據都是相對於R9寄存器的內容,而不是相對於一個固定的地址。通過在LDR中指定不同的基址寄存器的值,定義的內存表結構可以在程序中有多個實例。可多次使用LDR指令,用以實現不同的程序實例。
舉例:基於PC的內存表
Data   SPACE 100 ; //分配100字節的內存單元,並初始化爲0
MAP Data;//內存表的首地址爲Datastruc內存單元
Consta FIELD 4 ; //consta 長爲4字節,相對位置爲0
Constb FIELD 4; //constb長爲4字節,相對位置爲4
X   FIELD  8; // X長爲8字節,相對位置爲8
Y    FIELD 8; // y長爲8字節,相對位置爲16
String FIELD 16;// String爲16字節,相對位置爲24
可以通過下面的指令訪問範圍不超過4kb的數據;
LDR R5,constb ;相當於 LDR R5,[PC,offset]
 
*****************************************************
十四、RN

在局部標號中:
%表示引用操作
F指示編譯器只向前搜索。
B指示編譯器只向後搜索。
A指示編譯器搜索宏的所有嵌套層。
T指示編譯器搜索宏的當前層次。
若F、B沒有指定則先向前搜索,再向後搜索。
若A、T都沒有指定則先從當前層到最高層,比當前層低的不再搜索。

------------------------------------------------------------------------------------------------------------------------------------
 
------------------------------------------------------------------------------------------------------------------------------------


ADS 中的配置:
以一般的 S3C44B0X 的板子爲例:
1、 RO: 0x0, RW: 0xC000000 (Debug 模式下是:RO: 0xC000000, RW: ---)
2、 ARM LINKER:
    Layout 中指明整個 IMAGE 的入口,這一般和你的程序有關。
    Place at beginning of image
    1) Object/Symbol: 放程序的初始化的彙編文件,比如 44binit.o 或 boot.o. 你的工程不是有一個 .S 文件嗎,比如 44binit.s 或 boot.s 或你自己到的一個文件名,你只要把後綴名改成 .o , 填進去就可以了
    2) 還是剛纔那個 .s 文件, 你找一下,是不是有以下的代碼 IMPORT Main ; The main entry of mon program AREA Init,CODE,READONLY ;這就是入口的 AREA, 這裏的名字叫 Init,也可以是你自己取的名字,把這個名字填到 Section中。
    3) ENTRY b ResetHandler ;for debug ;這是debug時ADS停下來的第一條語句。還有,就是確認一個你的程序是否正確固化到Flash中,你可以把工程編譯成 .bin 格式的映像。然後通過編程器或 ads 讀取 Flash 的內容,與 .bin 文件比較.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章