Chinaunix首页 | 论坛 | 博客
  • 博客访问: 42504
  • 博文数量: 19
  • 博客积分: 1416
  • 博客等级: 上尉
  • 技术积分: 210
  • 用 户 组: 普通用户
  • 注册时间: 2008-11-19 11:33
文章分类
文章存档

2010年(10)

2009年(9)

我的朋友

分类: 嵌入式

2009-12-29 15:22:11

1.Remap

对重映射控制寄存器(地址0xffffff00)写0x1——保存或取消重映射

 

重映射原因:

由于板子启动是从地址0x00开始,并且中断向量表从0x00开始。但是当调试程序时,程序放在SRAM中,其地址在at91rm9200中是从0x200000开始的。当程序中需要进入中断的时候,要访问中断向量表。Arm架构将中断向量表放置在0x00处。实际上物理地址中0x00处并没有,中断向量表定义在物理地址中SRAM开始处。所以需要重映射,将0x00对应的地址指向了0x200000的空间。

重映射实际上是以0x00对应的地址指向了0x200000的空间,也就是重映射以后,0x00x200000指向同一片空间。

而这些功能对于有中断的情况时是必须的。

但是如果用不到中断的话,就不需要重映射,只需要在开始的时候,也就是pc0x0的时候,将其值修改为程序的存储空间,也就是0x200000,这样就可以了

 

判断重映射标准:

修改0x0对应的地址中的值,如果可以修改则已经重映射,如果修改不了,就没有重映射。

中断向量的定义:



AREA RESET, CODE, READONLY
                ARM
                EXPORT Vectors
Vectors LDR PC,Reset_Addr
                LDR PC,Undef_Addr
                LDR PC,SWI_Addr
                LDR PC,PAbt_Addr
                LDR PC,DAbt_Addr
                NOP ; Reserved Vector                     
                ldr pc, [pc,#-0xf20]
                LDR PC,FIQ_Addr

Reset_Addr DCD Reset_Handler
Undef_Addr DCD Undef_Handler
SWI_Addr DCD SWI_Handler
PAbt_Addr DCD PAbt_Handler
DAbt_Addr DCD DAbt_Handler
                DCD 0 ; Reserved Address
FIQ_Addr DCD FIQ_Handler

Undef_Handler B Undef_Handler
SWI_Handler B SWI_Handler
PAbt_Handler B PAbt_Handler
DAbt_Handler B DAbt_Handler
FIQ_Handler B FIQ_Handler

2.关于ldr     pc, [pc,#-0xf20]

AIC采用硬件中断向量化。硬件中断向量化将到达中断处理入口所需的指令减少到只有一条,即位于地址0x00000018ldr     pc, [pc,#-0xf20]

USTCPIO的中断都属于IRQ中断。ARM核的中断只有resetundefinedprefetch abortdata abortSWIIRQFIQ7种。其中IRQ的向量位于第7位。从地址0算起,地址为(7-1*4=24=0x18

执行此条指令时,由ARM的流水线结构可知,现时的PC0x00000018+2*4=0x20

#define AT91C_AIC_IVR   ((AT91_REG *)           0xFFFFF100) // (AIC) IRQ Vector Register

因此,执行后PC被赋予了地址0x20-0xF20=0x FFFFF100的内容,即IRQ向量寄存器AIC_IVR的内容。程序跳转到相应的中断例程中。

执行上述指令后,PC被赋予了保存于AIC_IVR的中断处理例程的入口地址。于是程序开始执行当前中断的处理例程。

 

 

 

3.如果SRAM中程序大于16k,启动就出错

SRAM(片内)只有16k,程序需要放在SDRAM中(片外)。

SDRAM需要初始化,重映射,这样就需要preload

Preload的代码在0x200000处,而目标程序放在0x20000000

改变pc的值,指向0x20000000.

 

 

启动代码

一上电就运行的程序,完成各种初始化工作并引导进入c程序。

Cpu在上电之后,紧接着就从地址0开始取得第一条指令的代码来执行

所以说地址0的地方必须在上电的时候就存在可执行的正确代码,也就是地址0的地方应该是ROM区,至少在上电之后一小段时间内是ROM区。

有如下一些部分的初始化:

一、定义入口点



AREA RESET, CODE, READONLY
        ARM
EXPORT Vectors

二、设置中断向量

Remap之前是地址为0的地方



Vectors LDR PC,Reset_Addr
                LDR PC,Undef_Addr
                LDR PC,SWI_Addr
                LDR PC,PAbt_Addr
                LDR PC,DAbt_Addr
                NOP ; Reserved Vector                     
                ldr pc, [pc,#-0xf20]
                LDR PC,FIQ_Addr
Reset_Addr DCD Reset_Handler
Undef_Addr DCD Undef_Handler
SWI_Addr DCD SWI_Handler
PAbt_Addr DCD PAbt_Handler
DAbt_Addr DCD DAbt_Handler
                DCD 0 ; Reserved Address
FIQ_Addr DCD FIQ_Handler

Undef_Handler B Undef_Handler
SWI_Handler B SWI_Handler
PAbt_Handler B PAbt_Handler
DAbt_Handler B DAbt_Handler
FIQ_Handler B FIQ_Handler

三、初始化堆栈指针寄存器



EXPORT Reset_Handler
Reset_Handler
                LDR R0, =Stack_Top

; Enter Undefined Instruction Mode and set its Stack Pointer
                MSR CPSR_c, #Mode_UND:OR:I_Bit:OR:F_Bit
                MOV SP, R0
                SUB R0, R0, #UND_Stack_Size

; Enter Abort Mode and set its Stack Pointer
                MSR CPSR_c, #Mode_ABT:OR:I_Bit:OR:F_Bit
                MOV SP, R0
                SUB R0, R0, #ABT_Stack_Size

; Enter FIQ Mode and set its Stack Pointer
                MSR CPSR_c, #Mode_FIQ:OR:I_Bit:OR:F_Bit
                MOV SP, R0
                SUB R0, R0, #FIQ_Stack_Size

; Enter IRQ Mode and set its Stack Pointer
                MSR CPSR_c, #Mode_IRQ:OR:I_Bit:OR:F_Bit
                MOV SP, R0
                SUB R0, R0, #IRQ_Stack_Size

; Enter Supervisor Mode and set its Stack Pointer
                MSR CPSR_c, #Mode_SVC:OR:I_Bit:OR:F_Bit
                MOV SP, R0
                SUB R0, R0, #SVC_Stack_Size

; Enter User Mode and set its Stack Pointer
                MSR CPSR_c, #Mode_USR
                IF :DEF:__MICROLIB

                EXPORT __initial_sp

                ELSE

                MOV SP, R0
                SUB SL, SP, #USR_Stack_Size

                ENDIF

四、初始化存储器系统(调用一段c程序)



IMPORT AT91F_LowLevelInit

    ldr r0, = AT91F_LowLevelInit
    mov lr, pc
    bx r0

五、初始化c环境(c程序用到的存储区)



IMPORT |Image$$RO$$Limit|
IMPORT |Image$$RW$$Base|
    IMPORT |Image$$ZI$$Base|
IMPORT |Image$$ZI$$Limit|
LDR R0,=|Image$$RO$$Limit| ;RO段结束地址加1 ,表示RO区末地址后面的地址,即RW数据源的起始地址,应该是RW数据的加载地址
         ;RW数据总数为:|Image$$ZI$$Base||Image$$RW$$Base|
                                             ;即RW数据源的值放在区间
LDR R1,=|Image$$RW$$Base| ;RW区在RAM里的执行区起始地址,也就是编译器选项RW_Base指定的地址,应该是RW运行地址
LDR R3,=|Image$$ZI$$Base|;RW型数据初值挎贝(R0为当前要挎贝数据地址)
CMP R0,R1
BEQ LOOP1 ;如果当前挎贝源地址和目标地址(RW型数据空间起始点)相等,结束。
LOOP0                                         
        CMP R1,R3 ;比较当前挎贝目标地址和ZI型数据空间起始点
        LDRCC R2,[R0],#4 ;如果不等时,取出当前挎贝源地址所对应空间的值,同时源地址加4(指向下一空间)
        STRCC R2,[R1],#4    ;将取出的值放到当前挎贝目标地址所对应空间,同时目标地址加4(指向下一空间)
        BCC LOOP0                    ;继续挎贝
                                            ;否则,进入ZI型数据空间置零操作。
  
LOOP1
        LDR R1,=|Image$$ZI$$Limit|
        MOV R2,#0
LOOP2
        CMP R3,R1 ;比较当前目标地址是不是和ZI型数据空间结束点后一空间地址相同
        STRCC R2,[R3],#4 ;如果不相同,当前目标地址所对应的空间置零,目标地址加4(指向下一空间) ;
        BCC LOOP2 ;继续置零
         ;否则,结束初始化。

先把ROM|Image$$RO$$Limt|开始的RW初始数据拷贝到RAM里面|Image$$RW$$Base|开始的地址,当RAM这边的目标地址到达|Image$$ZI$$Base|后就表示RW区的结束和ZI区的开始,接下去就对这片ZI区进行清零操作,直到遇到结束地址|Image$$ZI$$Limit|。只有这样,程序执行才能可靠运行。 

六、进入c程序



IMPORT main
                LDR R0, =main
                BX R0

附件里的源代码是把程序映射到0x20000000开始的sdrm中
 
阅读(1270) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~