joe 发表于 2022-10-28 00:52:02

ARM926EJ-S的起动汇编代码注释

;--------------sys_boot0_start.s汇编文件--------------------------------------------------------------------------------------------------------
        PRESERVE8 ;保持堆栈8字节对齐
    AREA INIT, CODE, READONLY ;代码段,处于INIT节中
       
    IMPORTVector_Table       
    IMPORT__main
               
;--------------------------------------------
; Mode bits and interrupt flag (I&F) defines
;--------------------------------------------
USR_MODE    EQU   0x10
FIQ_MODE    EQU   0x11
IRQ_MODE    EQU   0x12
SVC_MODE    EQU   0x13
ABT_MODE    EQU   0x17
UDF_MODE    EQU   0x1B
SYS_MODE    EQU   0x1F ;上面七种模式是ARM核定义的
I_BIT       EQU   0x80 ;当前程序状态寄存器CPSR中 bit7是I(IRQ使能) bit6是F(FIQ使能) bit5是T(ARM指令或THUMB指令) bit4-bit0定义上面所说的七种模式
F_BIT       EQU   0x40


SRAM_ADDR    EQU (0x0)       
SRAM_SIZE    EQU (0x8000)


RAM_Limit               EQU             (SRAM_ADDR+SRAM_SIZE)
USR_Stack                                EQU                                RAM_Limit
IRQ_Stack                       EQU                   (USR_Stack-1024*1)             
SVC_Stack                       EQU                   (IRQ_Stack-1024*1)         
;USR_Stack用户堆栈在32M处,IRQ_Stack和SVC_Stack堆栈指针分别都低1K地址如果是一个正常的程序,应将USR_Stack设置为最低地址好些,这与页保护和FD模式有关。

    ENTRY
    EXPORTReset_Go
       
Reset_Go

    ;--------------------------------
    ; Initial Stack Pointer register
    ;--------------------------------
    ;INIT_STACK
   MSR    CPSR_c, #IRQ_MODE :OR: I_BIT :OR: F_BIT; :OR:是ARMCC汇编中的按位或,如果是:LOR:则是逻辑或
                                                                                                       ;MSR指令是通用寄存器R到状态寄存器S,MRS指令是状态寄存器S到通用寄存器R,所以MSR或MRS这二个指令数据流向都是从右到左
                                                                                                       ;语法格式:
                                                                                                       ;MRS{<cond>}<Rd>,CPSR或SPSR,将PSR状态寄存器的值赋绘一个通用寄存器,也就是读状态寄存器,数据是从右到左
                                                                                                       ;MSR{<cond>}PSR_<fields>,#immed_8r或Rn 将立即数或通用寄存器值赋给状态寄存器,也就是写状态寄存器,数据也是从右到左
                                                                                                       ;状态寄存器不管是读还是写,数据都是从右到左,MRS是读状态寄存器,MSR是写状态寄存器
                                                                                                       ;<fields>设置状态寄存器中需要操作的位,状态寄存器的32位可以分为4个9位的域
                                                                                                       ;        f:指示bits,又名条件标志位域
                                                                                                       ;        s:指示bits,又名状态标志位域
                                                                                                       ;        x:指示bits,又名扩展位域
                                                                                                       ;        c:指示bits,又名控制位域
                                                                                                       ;状态寄存器32位分成了三部分,高位31~28 四bit叫条件标志位,因为ARM指令中的条件cond可以有14种可能;27位是Q标志位
                                                                                                       ;(与DSP指令相关,DSP指令溢出),低8bit中,bit7=I(irq中断使能)bit6=F(fiq中断使能)bit5=T(thumb状态还是ARM状态)
                                                                                                       ;bit4~bit0(m4~m0表示哪种模式),其实还有些bit位,只是不同的版本就有不同的bit位相关
                                                                                                       ;所以<fields>是c的话,则表示写状态寄存器时与状态寄存器的低8bit有关了即IFTM4M3M2M1M0
                                                                                                       
   LDR    SP, =IRQ_Stack ;因为上面通过MSR写状态寄存器将模式变成了IRQ模式,所以此时的SP是IRQ下的SP(IRQ与USER模式,R0~R12以及PC都相同,但R13(SP),R14(LR)不同)

   MSR    CPSR_c, #SYS_MODE :OR: I_BIT :OR: F_BIT        ;system模式,这种模式与USER模式使用相同的寄存器,并且system也没有spsr寄存器
   LDR    SP, =USR_Stack ;所以设置为system模式,此句中设置的SP也是USER模式下的SP

   MSR    CPSR_c, #SVC_MODE :OR: I_BIT :OR: F_BIT        ;SVC模式
   LDR    SP, =SVC_Stack

    ;------------------------------------------------------
    ; Set the normal exception vector of CP15 control bit
    ;------------------------------------------------------
        ;MRC和MCR指令在汇编语法格式上是相同的,都是MCR/MRC{<cond>} <coproc>,<opcode_1>,<Rd>,<CRn>,<CRm>{,<opcode_2>}
        ;                                                                                cond表示条件;coproc表示协处理器,opcode_1表示操作码1(协处理器CP15,不管是MCR还是MRC此值都是0b000)
      ;                                                                                Rd表示ARM中寄存器,CRn表示协处理器中寄存器,CRm辅助协处理器寄存器,如果不需要则必须写为c0,opcode_2 备用,如果不需要则写为0       
        MRC p15, 0, r0 , c1, c0   ; r0 := cp15 register 1 协处理器寄存器到ARM处理器寄存器的数据传送 协处理器为cp15,第一操作码是0(针对CP15,不管是MCR还是MRC都必须为0),目标是ARM寄存器R0,源是c1,
                                                                ; 源操作寄存器是协处理寄存器c1,备用协处理器寄存器CRm不需要,所以必须写为c0,没有第二操作码opcod_2
                                                                ;C1各位:
                                                                ;31       16 1514131211109876543210
                                                                ;SBZP/UNP   L4RR   V   I   Z   FRSBLDPWCAM
                                                                ;M:1使能MMU或PU 0禁止MMU或PU
                                                                ;A:1使能地址对齐检查功能 0禁止地址对齐检查功能
                                                                ;C:当数据CACHE和指令CACHE分开时,本控制位禁止/使能数据CACHE;当数据CACHE和指令CACHE统一时,本位控制禁止/使能整个CACHE
                                                                ;W:禁止/使能写入缓冲
                                                                ;P:用于兼容26位地址的ARM处理器,本位控制PROG32控制信号
                                                                ;D:也是兼容26位地址的ARM处理器,控制DATA32控制信号
                                                                ;L:针对ARMV3版本,控制中止模型,其它ARM版本不用
                                                                ;B:1表示存储系统是大端模式(权重的位即高位字节放在低地址)小端模式(权重的位即高位字节放在高地址)
                                                                ;S:在基于MMU的存储系统中,本位用作系统保护
                                                                ;R:在基于MMU的存储系统中,本位用作ROM保护
                                                                ;F:由厂商自定义
                                                                ;Z:禁止/使能跳转预测功能
                                                                ;I:当数据CACHE和指令CACHE是分开的时,本位禁止/使能指令CACHE,如果系统中使用统一的指令CACHE和数据CACHE或不含CACHE,读时返回0,写时忽略这位
                                                                ;V:是否选择高端异常中断向量表
                                                                ;RR:CACHE中的淘汰算法选择,0 随机 1 预测性的淘汰算法,如round-robin
                                                                ;L4:提供兼容以前的版本,主要是LDM/LDR/POP
                                                                ;UNP/SBZP:保留位                                                                
        bic r0, r0, #0x2000         ; Clear bit13 in r1 =0低端异常向量表地址 1高端异常向量表地址将R0与#0x2000的反码即0xffffdffff进行按位逻辑与操作,再将结果传给R0
        MCR p15, 0, r0 , c1, c0   ; cp15 register 1 := r0


        ldr r0, = Vector_Table
        mrc p15, 0, r2, c1, c0, 0;c1传给ARM寄存器r2
        ands r2, r2, #(1 << 13)    ;前面已设置V位为0,此句之后r2=0 Z标志为1
        ldreq r1, =0x00000000      ;Z置位情况下,指令中条件码EQ则为true,ldr指令表示内存数据传到ARM寄存器,伪代码:if(低异常向量设置)r1=0x00000000; else r1=0xffff0000;
        ldrne r1, =0xFFFF0000           ;
       
        ldmia r0!, {r2-r8, r10}           ;批量 内存到寄存器列表传输 每次传输之后地址增加 内存地址起始是r0值,注意:先从r0所指的内存地址中取值给r2,然后再依次给r3...r8,最后给r10
                                                           ;因为r0指向的是异常向量地址表,所以r2-r8,r10这8个寄存器对应的就是向量地址表中前8个项的值也就是8个异常向量对应的跳转指令口
                                                           ;每次传输之后都要修改r0的值即r+=4,总共要做8次+4动作
        stmia r1!, {r2-r8, r10}           ;批量 寄存器值保存到内存地址中 每次传输之后地址增加r1初值是异常向量表地址,注意:先保存的是寄存器r10,最后保存的是r2
                                                           ;也就是说ldmia 加载时寄存器列表是从左到右,而stmia 保存时寄存器列表是从右到左
        ldmia r0!, {r2-r8, r10}           ;经过上面ldmia和stmia这二句之后,r0和r1值都添加了8*4=32,本句和下句stmia指令其实是将8个异常向量跳转指令之后的8个地址的值又加到这8个寄存器中
                                                           ;也就是异常向量的跳转指令入口之后就是各自真正的入口函数地址值,这8个入口函数地址分别对应到各自的执行函数,有必要时,有的函数是由用户自己编写       
        stmia r1!, {r2-r8, r10}           ;


    ;-----------------------------
    ;   enter the C code
    ;-----------------------------
    B   __main                                   ;注意:此时还是SVC模式,跳转到了C库的__main函数中,正常情况下,C库最终会跳到我们的main函数

    END

页: [1]
查看完整版本: ARM926EJ-S的起动汇编代码注释