lilinly225 发表于 2013-10-21 17:33

求助: 关于S3C2440启动代码的问题。

本帖最后由 lilinly225 于 2013-10-21 18:00 编辑

      目前正在Windows下学习ARM, 用的开发工具是MDK, 没有用Linux下的交叉编译链工具。现在我在学习启动代码相关的内容。
环境为:裸机,没有操作系统和bootloader。

在我看到的的一个代码中有一段关于入口的代码感觉很诡异,不知道怎么理解。;定义arm汇编程序段,段名叫init段,为只读段
        AREA    RESET,CODE,READONLY
;        ENTRY
        EXPORT        __ENTRY   ;导出__ENTRY标号
__ENTRY
ResetEntry
        ;1)The code, which converts to Big-endian, should be in little endian code.
        ;2)The following little endian code will be compiled in Big-Endian mode.
        ;The code byte order should be changed as the memory bus width.
        ;3)The pseudo instruction,DCD can not be used here because the linker generates error.
       
        ;判断模式改变是否定义过(ASSERT是伪指令,:DEF:lable判断lable是否定义过了)
        ASSERT        :DEF:ENDIAN_CHANGE
        [ ENDIAN_CHANGE                                                ;如果ENDIAN_CHANGE为真,则执行以下
          ASSERT:DEF:ENTRY_BUS_WIDTH    ;判断是否定义了总线宽度
          [ ENTRY_BUS_WIDTH=32            ;如果存储器是32位的总线宽度
                b        ChangeBigEndian               ;DCD 0xea000007
          ]

          [ ENTRY_BUS_WIDTH=16            ;如果存储器是16位的总线宽度
                andeq        r14,r7,r0,lsl #20         ;DCD 0x0007ea00
          ]

          [ ENTRY_BUS_WIDTH=8             ;如果是存储器是8位总线宽度
                streq        r0,   ;DCD 0x070000ea
          ]
        |                                 ;如果总线宽度没有定义的话,就直接跳转到复位中断
          b        ResetHandler                ;程序执行的地跳跳转指令;正常模式下第一条语句就是这条语句
    ]
        b        HandlerUndef                      ;handler for Undefined mode
        b        HandlerSWI                            ;handler for SWI interrupt
        b        HandlerPabort                      ;handler for PAbort
        b        HandlerDabort                      ;handler for DAbort
        b        .                                        ;reserved
        b        HandlerIRQ                            ;handler for IRQ interrupt
        b        HandlerFIQ                            ;handler for FIQ interrupt
;@0x20
        b        EnterPWDN          ; Must be @0x20.;进入powerdown模式按照ARM开发者指南的说法: ENTRY 伪指令表示程序代码的最开始地方(相当于C语言中的main函数,表示程序的入口); 但是这段代码将ENTRY给注释掉
以一个__ENTRY的标识符替代了,并且将这个符号给导出了。

   然后我搜索整个工程只在 mmu.c(MMU.c 文件为MMU功能的文件)发现了下面一句:extern char __ENTRY[];        //hzh很显然,这里只是声明了一个外部变量。
   后面这个变量名符号 __ENTRY 被用来建立MMU转换页表的时候用了一下。//MMU_SetMTT(int vaddrStart,int vaddrEnd,int paddrStart,int attr)
    //MMU_SetMTT(0x00000000,0x07f00000,0x00000000,RW_CNB);//bank0
                          //虚拟地址   虚拟地址结束           物理地址               映射区间属性
    MMU_SetMTT(0x00000000,0x03f00000,   (int)__ENTRY,RW_CB);//bank0, hzh然后就没有在任何地方用过了。
而MMU初始化是在 C语言代码的main函数中开始的,也就是说汇编代码的起始点运行的时候,MMU不可能运行,我的理解就是这个设置虚拟地址映射的
过程不可能与汇编代码的起始位置有关。int main(void)
{       
    rGPBDAT = 0x1e0;                   //关LED
    rGPBCON=0x00015400;           //设置GPB5~8为输出
    rGPBUP   =0x3ff;                   //禁止上拉
        LCD_Init();
        Brush_Background(0xffff);
        Paint_Bmp(0,0,240,320,gImage_fhand);
    MMU_Init();
    KeyScan_Test()        ;这里还有一个信息是:
            上面那个汇编代码段定义是第一个代码段定义 ,这个代码段前面有两个数据段。

我想问的的是:
            是不是汇编文件的第一个代码段默认的地址就是为0x00000000,是否是链接到代码段的0x00000000???
否则为什么不需要ENTRY 宏汇编 伪指令。
      
    在ARM DUI 0204IC Real View 4.0版汇编器指南的7-69页中,明确的表示一个程序至少需要一个 ENTRY 入口的。
但是上面的代码没有也可以运行。


下面为整个汇编代码到 __ENTEY 之间的汇编代码。;=========================================
; NAME: 2440INIT.S
; DESC: C start up codes
;       Configure memory, ISR ,stacks
;        Initialize C-variables
; HISTORY:
; 2002.02.25:kwtark: ver 0.0
; 2002.03.20:purnnamu: Add some functions for testing STOP,Sleep mode
; 2003.03.14:DonGo: Modified for 2440.
;=========================================
        GET option.inc
        GET memcfg.inc
        GET 2440addr.inc

BIT_SELFREFRESH EQU        (1<<22)


;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    ;

;定义GPB口的,寻址地址
GPBCON      EQU   0x56000010
GPBDAT          EQU   0x56000014

;各个异常模式的堆栈
UserStack        EQU        (_STACK_BASEADDRESS-0x3800)        ;0x33ff4800 ~   
SVCStack        EQU        (_STACK_BASEADDRESS-0x2800)        ;0x33ff5800 ~
UndefStack        EQU        (_STACK_BASEADDRESS-0x2400)        ;0x33ff5c00 ~
AbortStack        EQU        (_STACK_BASEADDRESS-0x2000)        ;0x33ff6000 ~
IRQStack        EQU        (_STACK_BASEADDRESS-0x1000)        ;0x33ff7000 ~
FIQStack        EQU        (_STACK_BASEADDRESS-0x0)        ;0x33ff8000 ~堆栈的顶部



;------------------------------------------------------------------------------
UND_Stack_SizeEQU   0x00000400   ;
SVC_Stack_SizeEQU   0x00000400
ABT_Stack_SizeEQU   0x00000400
FIQ_Stack_SizeEQU   0x00000400
IRQ_Stack_SizeEQU   0x00000400
USR_Stack_SizeEQU   0x00004000

;堆栈的总大小为        0x5400 个字节 = 21504 字节
Stack_Size      EQU   (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + \
                         FIQ_Stack_Size + IRQ_Stack_Size + USR_Stack_Size)

                AREA    STACK, NOINIT, READWRITE, ALIGN=3

Stack_Mem       SPACE   Stack_Size               
Stack_Top       EQU   Stack_Mem + Stack_Size
Heap_Size       EQU   0x00000000

                AREA    HEAP, NOINIT, READWRITE, ALIGN=3
Heap_Mem      SPACE   Heap_Size

;-------------------------------------------------------------------------------
;这一段是统一arm的工作状态和对应的软件编译方式(16位编译环境使用tasm.exe编译)。
;arm处理器的工作状态分为两种:32位,arm执行字对齐的arm指令集;16位,arm执行半字
;对齐的Thumb指令集。不同的工作状态,编译方式也不一样。所以下面的程序就是判断
;arm的工作方式来确定它的编译方式。
;Check if tasm.exe(armasm -16 ...@ADS 1.0) is used.
        GBLL    THUMBCODE ;定义THUMBCODE 这个变量GBLL 声明一个全局逻辑变量并初始化为{FALSE}
        [ {CONFIG} = 16   ;"["表示"if","|"表示"else","]"表示"endif",对于CONFIG是在ADS编译中定义的内部变量。
THUMBCODE SETL{TRUE}
          CODE32
                |
THUMBCODE SETL{FALSE}
    ]                  ;如果ARM是在16位的工作状态的话,就使全局变量THUMBCODE设置为ture。

                MACRO          ;这个是宏定义的关键字
        MOV_PC_LR          ;作用是子程序返回
                [ THUMBCODE    ;当目标程序是Thumb时,就要使用BX跳转返回,并转换模式。
          bx lr         
                |
;          mov        pc,lr      ;目标程序是ARM指令集,直接把lr赋给pc就可以了。
                bx lr
                ]
        MEND               ;宏定义的结束标志。

                MACRO
        MOVEQ_PC_LR      ;这个是带“相等”条件的子程序返回。和上面说的类似。
                [ THUMBCODE
      bxeq lr
                |
          moveq pc,lr
                ]
        MEND

;//////////////////////////////////////////////////////////////////////////

                MACRO          ;这个地方定义一个宏处理器,HANDLER 为宏标识符
$HandlerLabel HANDLER $HandleLabel
$HandlerLabel
        sub        sp,sp,#4                   
        stmfd        sp!,{r0}             
        ldr   r0,=$HandleLabel    ;load the address of HandleXXX to r0
        ldr   r0,                    ;load the contents(service routine start address) of HandleXXX
        str   r0,      ;store the contents(ISR) of HandleXXX to stack
        ldmfd   sp!,{r0,pc}       ;POP the work register and pc(jump to ISR)
        MEND


;编译器使用下列段来记录各段的起始地址和结束地址
;|Image$RO$Base|(ADS用这种写法), |Image$ER_ROM1$RO$Base|(MDK用这种写法); RO 段起始地址
;|Image$RO$Limit|(ADS用这种写法),|Image$ER_ROM1$RO$Limit| (MDK用这种写法);RO 段结束地址加1
;|Image$RW$Base| (ADS用这种写法),|Image$RW_RAM1$RW$Base|(MDK用这种写法);RW 段起始地址
;|Image$RW$Limit| (ADS用这种写法),|Image$RW_RAM1$ZI$Limit|(MDK用这种写法);RW 段结束地址加1
;|Image$ZI$Base|(ADS用这种写法),|Image$RW_RAM1$ZI$Base| (MDK用这种写法); ZI 段起始地址
;|Image$ZI$Limit| (ADS用这种写法),|Image$RW_RAM1$ZI$Limit|(MDK用这种写法); ZI 段结束地址加1

        IMPORT|Image$ER_ROM1$RO$Base|       ; Base of ROM code
        IMPORT|Image$ER_ROM1$RO$Limit|; End of ROM code (=start of ROM data)
        IMPORT|Image$RW_RAM1$RW$Base|   ; Base of RAM to initialise
        IMPORT|Image$RW_RAM1$ZI$Base|   ; Base and limit of area
        IMPORT|Image$RW_RAM1$ZI$Limit|; to zero initialise

;引入外部变量mmu的快速总线模式和同步总线模式两个变量
        IMPORT        MMU_SetAsyncBusMode
        IMPORT        MMU_SetFastBusMode        ;hzh

;引入外部标号我们所熟知的main函数
        IMPORT__main    ; The main entry of mon program
        PRESERVE8
       
;定义arm汇编程序段,段名叫init段,为只读段
        AREA    RESET,CODE,READONLY
;        ENTRY
        EXPORT        __ENTRY   ;导出__ENTRY标号
__ENTRY
ResetEntry
        ;1)The code, which converts to Big-endian, should be in little endian code.
        ;2)The following little endian code will be compiled in Big-Endian mode.
        ;The code byte order should be changed as the memory bus width.
        ;3)The pseudo instruction,DCD can not be used here because the linker generates error.
       
        ;判断模式改变是否定义过(ASSERT是伪指令,:DEF:lable判断lable是否定义过了)
        ASSERT        :DEF:ENDIAN_CHANGE
        [ ENDIAN_CHANGE                                                ;如果ENDIAN_CHANGE为真,则执行以下
          ASSERT:DEF:ENTRY_BUS_WIDTH    ;判断是否定义了总线宽度
          [ ENTRY_BUS_WIDTH=32            ;如果存储器是32位的总线宽度
                b        ChangeBigEndian               ;DCD 0xea000007
          ]

          [ ENTRY_BUS_WIDTH=16            ;如果存储器是16位的总线宽度
                andeq        r14,r7,r0,lsl #20         ;DCD 0x0007ea00
          ]

          [ ENTRY_BUS_WIDTH=8             ;如果是存储器是8位总线宽度
                streq        r0,   ;DCD 0x070000ea
          ]
        |                                 ;如果总线宽度没有定义的话,就直接跳转到复位中断
          b        ResetHandler                ;程序执行的地跳跳转指令;正常模式下第一条语句就是这条语句
    ]
        b        HandlerUndef                      ;handler for Undefined mode
        b        HandlerSWI                            ;handler for SWI interrupt
        b        HandlerPabort                      ;handler for PAbort
        b        HandlerDabort                      ;handler for DAbort
        b        .                                        ;reserved
        b        HandlerIRQ                            ;handler for IRQ interrupt
        b        HandlerFIQ                            ;handler for FIQ interrupt
;@0x20
        b        EnterPWDN          ; Must be @0x20.;进入powerdown模式
求各位大神解释一下。
    另外各位大神,有没有关于MMU和堆栈初始化的相关比较系统的资料,关于裸机设置MMU和堆栈设置的系统的解释的资料, 我搜到的资料都是
一些比较零散的资料,理解起来很难。

crifan 发表于 2013-10-21 23:53

本帖最后由 crifan 于 2013-10-21 23:54 编辑

你问题太多了。
其中很多问题,下面的教程,应该可以帮你解答了:
Uboot中start.S源码的指令级的详尽解析

看完后,还有疑问,再问,我再抽空看看能否帮你解答。

lilinly225 发表于 2013-12-08 18:57

回复 2# crifan

谢谢先。


   
页: [1]
查看完整版本: 求助: 关于S3C2440启动代码的问题。