1、框架
(1)关看门狗//对2440来说,看门狗一上电是打开的,不关掉过3秒会复位整个开发板
(2)设置时钟//2440一上电时运行频率是12M,所以要让它能运行更快点
(3)初始化SDRAM (重定位时用到)
(4)重定位(bootloader比较小时,在nor flash上运行就可以了。如果bootloader比较大,要把它重定位到SDRAM)
执行main(其它复杂功能的代码用C函数实现)
2、程序
#define S3C2440_MPLL_200MHZ ((0x5c<<12)|(0x01<<4)|(0x02))
#define MEM_CTL_BASE 0x48000000
//.text表示一个代码段
.text
//.global表示标号_start是全局标号
.global _start_start:
/* 1. 关看门狗 */对2440来说,看门狗一上电是打开的,不关掉过3秒会复位整个开发板
//0x53000000是看门狗定时控制寄存器的地址,ldr是 伪汇编指令,把0x53000000这个地址值赋给r0寄存器。
ldr r0, =0x53000000
//把立即数0赋给r1寄存器
mov r1, #0
//把数据r1保存到地址为r0的内存单元
str r1, [r0]/* 2. 设置时钟 */2440一上电时系统运行频率是12M,所以要让它能运行更快点
//0x4c000014是时钟分频控制寄存器的地址
mov r1, #0x03; // FCLK:HCLK:PCLK=1:2:4, HDIVN=1,PDIVN=1
str r1, [r0]
/* 如果HDIVN非0,CPU的总线模式应该从“fast bus mode”变为“asynchronous bus mode” */
mrc p15, 0, r1, c1, c0, 0/* 读出控制寄存器 */
orr r1, r1, #0xc0000000/* 设置为“asynchronous bus mode” */
mcr p15, 0, r1, c1, c0, 0/* 写入控制寄存器 */
/* MPLLCON = S3C2440_MPLL_200MHZ */
//0x4c000004是MPLL配置寄存器的地址
对应的反汇编33f80024:e59f0084 ldrr0, [pc, #132]; 33f800b0 <sdram_config+0x38>
如果对于ldr伪汇编指令,0x4c000004这个数比较复杂,不能用mov指令表示,会吧这个数存在地址(pc + 132)处,也就是33f800b0处,然后从(pc + 132)的存储器地址处取出数据,加载到寄存器r0中。
ldr r0, =0x4c000004
str r1, [r0]
/* 3. 初始化SDRAM */
//吧设置的SDRAM控制器的值赋给SDRAM的控制器里面去,MEM_CTL_BASE是控制器的基址
//MEM_CTL_BASE是控制器的基址,也就是 r0是控制器的基址
ldr r0, =MEM_CTL_BASE
//adr读取相对地址值,也就是r1是 sdram_config的当前地址
adr r1, sdram_config /* sdram_config的当前地址 */
//由于用作SDRAM控制器的寄存器有13个,且每个地址的值占4个字节,也就是r3是最后一个寄存器的地址的内容的尾部字节地址。
add r3, r0, #(13*4)
//这里1是局部标签,用于跳转
1:
//将地址为r1的内存单元数据读到r2中,然后r1+4
ldr r2, [r1], #4
//将r2的数据保存到地址为r0的内存单元中,然后r0+4
str r2, [r0], #4
//比较r0和r3的地址值
cmp r0, r3
/*
1: ;A
cmp r0, #0
beq 1f ; r0==0那么向前跳转到B处执行
bne 1b ; 否则向后跳转到A处执行
1: ;B
*/
bne 1b/* 4. 重定位 : 把bootloader本身的代码从flash复制到它的链接地址去 */
用C语言写代码要先设置栈,让栈指针指向一块空的内存,让其指向SDRAM的最高内存,栈是往下增长的
ldr sp, =0x34000000//先调用nand flash的初始化函数,因为无论是nor flash启动还是nand flash启动,都会从nand flash读取内核到SDRAM,
bl nand_init
传给C函数的参数r0 ,r1,r2
r0对应C函数的第一个参数src,是0地址(从nand flash的0地址或nor flash的0地址复制到SDRAM的链接地址)
mov r0, #0
r1对应dest,也就是链接地址,第一条指令_start的地址
ldr r1, =_start
r2对应len,也就是要拷贝的程序的长度,看链接脚本,_bss_start是bss端的起始地址,二进制文件的大小应为bss端的起始地址减去代码段的起始地址(链接地址)的值
ldr r2, =__bss_start
相当于r2=r2-r1
sub r2, r2, r1把代码从nand flash 拷贝到SDRAM
bl copy_code_to_sdram
//把bss段占用的内存清零
bl clear_bss/* 5. 执行main */ 其他代码使用C函数(初始化nand flash,从nand flash把内核读到内存)
bl main是相对跳转,若从nand flash的0地址开始执行,跳转的时候不能调到SDRAM里面去,因为是根据当前指令地址PC,PC值实际的值是A+8(跳转指令处的地址是A),以当前指令bl的bit[23:0]找到main函数的偏差值,然后跳转到(PC值+偏差值)的地址。
连接寄存器r14(LR),用于保存返回地址,用于main函数执行完后返回
ldr lr, =halt
该指令是从内存中的某个位置(main)读出数据并赋给
PC,同样依
赖当前PC的值,但是偏移量是那个位置(main)的连接地址(运行时的地址),所以
可以用它实现从Flash到RAM的程序跳转。
把main函数的地址赋给PC ,跳转到main函数执行
ldr pc, =main
//进入死循环,防止程序跑飞
halt:b halt
//sdram_config标号下是SDRAM的所有寄存器的值
sdram_config:
.long 0x22011110//BWSCON
.long 0x00000700//BANKCON0
.long 0x00000700//BANKCON1
.long 0x00000700//BANKCON2
.long 0x00000700//BANKCON3
.long 0x00000700//BANKCON4
.long 0x00000700//BANKCON5
.long 0x00018005//BANKCON6
.long 0x00018005//BANKCON7
.long 0x008C04F4// REFRESH
.long 0x000000B1//BANKSIZE
.long 0x00000030//MRSRB6
.long 0x00000030//MRSRB7