1、修改原先的代码
原Makefile文件:
all:
arm-linux-gcc -c -o led.o led.c
arm-linux-gcc -c -o uart.o uart.c
arm-linux-gcc -c -o init.o init.c
arm-linux-gcc -c -o main.o main.c
arm-linux-gcc -c -o start.o start.S
#arm-linux-ld -Ttext 0 -Tdata 0x30000000 start.o led.o uart.o init.o main.o -o sdram.elf
arm-linux-ld -T sdram.lds start.o led.o uart.o init.o main.o -o sdram.elf
arm-linux-objcopy -O binary -S sdram.elf sdram.bin
arm-linux-objdump -D sdram.elf > sdram.dis
clean:
rm *.bin *.o *.elf *.dis
对于使用Thumb指令集的参数:
arm-linux-gcc -mthumb -c -o led.o led.c//只需要在arm-linux-gcc加上 mthumb命令即可
改进Makefile文件:
all: led.o uart.o init.o main.o start.o //all依赖led.o uart.o init.o main.o start.o
#arm-linux-ld -Ttext 0 -Tdata 0x30000000 start.o led.o uart.o init.o main.o -o sdram.elf
arm-linux-ld -T sdram.lds start.o led.o uart.o init.o main.o -o sdram.elf
arm-linux-objcopy -O binary -S sdram.elf sdram.bin
arm-linux-objdump -D sdram.elf > sdram.dis
clean:
rm *.bin *.o *.elf *.dis
%.o : %.c
arm-linux-gcc -mthumb -c -o $@ $< //对于所有的.c文件使用规则就可以使用thumb指令集编译 $@表示目标 $<表示第一个依赖
%.o : %.S
arm-linux-gcc -c -o $@ $<
原start.S:
.text
.global _start
_start:
/* 关闭看门狗 */
ldr r0, =0x53000000
ldr r1, =0
str r1, [r0]
/* 设置MPLL, FCLK : HCLK : PCLK = 400m : 100m : 50m */
/* LOCKTIME(0x4C000000) = 0xFFFFFFFF */
ldr r0, =0x4C000000
ldr r1, =0xFFFFFFFF
str r1, [r0]
/* CLKDIVN(0x4C000014) = 0X5, tFCLK:tHCLK:tPCLK = 1:4:8 */
ldr r0, =0x4C000014
ldr r1, =0x5
str r1, [r0]
/* 设置CPU工作于异步模式 */
mrc p15,0,r0,c1,c0,0
orr r0,r0,#0xc0000000 //R1_nF:OR:R1_iA
mcr p15,0,r0,c1,c0,0
/* 设置MPLLCON(0x4C000004) = (92<<12)|(1<<4)|(1<<0)
* m = MDIV+8 = 92+8=100
* p = PDIV+2 = 1+2 = 3
* s = SDIV = 1
* FCLK = 2*m*Fin/(p*2^s) = 2*100*12/(3*2^1)=400M
*/
ldr r0, =0x4C000004
ldr r1, =(92<<12)|(1<<4)|(1<<0)
str r1, [r0]
/* 一旦设置PLL, 就会锁定lock time直到PLL输出稳定
* 然后CPU工作于新的频率FCLK
*/
/* 设置内存: sp 栈 */
/* 分辨是nor/nand启动
* 写0到0地址, 再读出来
* 如果得到0, 表示0地址上的内容被修改了, 它对应ram, 这就是nand启动
* 否则就是nor启动
*/
mov r1, #0
ldr r0, [r1] /* 读出原来的值备份 */
str r1, [r1] /* 0->[0] */
ldr r2, [r1] /* r2=[0] */
cmp r1, r2 /* r1==r2? 如果相等表示是NAND启动 */
ldr sp, =0x40000000+4096 /* 先假设是nor启动 */
moveq sp, #4096 /* nand启动 */
streq r0, [r1] /* 恢复原来的值 */
bl sdram_init
//bl sdram_init2 /* 用到有初始值的数组, 不是位置无关码 */
/* 重定位text, rodata, data段整个程序 */
bl copy2sdram
/* 清除BSS段 */
bl clean_bss
//bl main /* 使用BL命令相对跳转, 程序仍然在NOR/sram执行 */
ldr pc, =main /* 绝对跳转, 跳到SDRAM */
halt:
b halt
使用thumb指令集的Start.S文件
.text
.global _start
.code 32 //表示后续的指令使用ARM指令集
_start:
/* 关闭看门狗 */
ldr r0, =0x53000000
ldr r1, =0
str r1, [r0]
/* 设置MPLL, FCLK : HCLK : PCLK = 400m : 100m : 50m */
/* LOCKTIME(0x4C000000) = 0xFFFFFFFF */
ldr r0, =0x4C000000
ldr r1, =0xFFFFFFFF
str r1, [r0]
/* CLKDIVN(0x4C000014) = 0X5, tFCLK:tHCLK:tPCLK = 1:4:8 */
ldr r0, =0x4C000014
ldr r1, =0x5
str r1, [r0]
/* 设置CPU工作于异步模式 */
mrc p15,0,r0,c1,c0,0
orr r0,r0,#0xc0000000 //R1_nF:OR:R1_iA
mcr p15,0,r0,c1,c0,0
/* 设置MPLLCON(0x4C000004) = (92<<12)|(1<<4)|(1<<0)
* m = MDIV+8 = 92+8=100
* p = PDIV+2 = 1+2 = 3
* s = SDIV = 1
* FCLK = 2*m*Fin/(p*2^s) = 2*100*12/(3*2^1)=400M
*/
ldr r0, =0x4C000004
ldr r1, =(92<<12)|(1<<4)|(1<<0)
str r1, [r0]
/* 一旦设置PLL, 就会锁定lock time直到PLL输出稳定
* 然后CPU工作于新的频率FCLK
*/
/* 设置内存: sp 栈 */
/* 分辨是nor/nand启动
* 写0到0地址, 再读出来
* 如果得到0, 表示0地址上的内容被修改了, 它对应ram, 这就是nand启动
* 否则就是nor启动
*/
mov r1, #0
ldr r0, [r1] /* 读出原来的值备份 */
str r1, [r1] /* 0->[0] */
ldr r2, [r1] /* r2=[0] */
cmp r1, r2 /* r1==r2? 如果相等表示是NAND启动 */
ldr sp, =0x40000000+4096 /* 先假设是nor启动 */
moveq sp, #4096 /* nand启动 */
streq r0, [r1] /* 恢复原来的值 */
/* 怎么从ARM State切换到Thumb State? */
adr r0, thumb_func //定义此标号的地址
add r0, r0, #1 /* 为什么加1? bit0=1时, bx就会切换CPU State到thumb state */
bx r0
.code 16 //下面都使用thumb指令集
thumb_func: //需要得到这个标号的地址
/*下面就是使用thumb指令来执行程序*/
bl sdram_init
//bl sdram_init2 /* 用到有初始值的数组, 不是位置无关码 */
/* 重定位text, rodata, data段整个程序 */
bl copy2sdram
/* 清除BSS段 */
bl clean_bss
//bl main /* 使用BL命令相对跳转, 程序仍然在NOR/sram执行 */
ldr r0, =main /* 绝对跳转, 跳到SDRAM ,先把main的地址赋值给R0 */
mov pc, r0 /*让后再移动到PC*/
halt:
b halt
注意:thunb指令不能直接
ldr pc, =main
2、编译后的使用了memcpy出错的解决方法
上传代码编译测试
出现错误,如下
init.o(.text+0x6c):In function ‘sdram_init2’;
undefined reference to ‘memcpy’
发现是init,o里sdram_init2使用的了memcpy函数
查看init.c
#include "s3c2440_soc.h"
void sdram_init(void)
{
BWSCON = 0x22000000;
BANKCON6 = 0x18001;
BANKCON7 = 0x18001;
REFRESH = 0x8404f5;
BANKSIZE = 0xb1;
MRSRB6 = 0x20;
MRSRB7 = 0x20;
}
/*下面函数使用了memcpy函数,显然是编译器的操作,使用了memcpy把数组里的值从代码段拷贝到了arr局部变量里
是否可以禁用掉memcpy*/
void sdram_init2(void)
{
unsigned int arr[] = {
0x22000000, //BWSCON
0x00000700, //BANKCON0
0x00000700, //BANKCON1
0x00000700, //BANKCON2
0x00000700, //BANKCON3
0x00000700, //BANKCON4
0x00000700, //BANKCON5
0x18001, //BANKCON6
0x18001, //BANKCON7
0x8404f5, //REFRESH,HCLK=12MHz:0x008e07a3,HCLK=100MHz:0x008e04f4
0xb1, //BANKSIZE
0x20, //MRSRB6
0x20, //MRSRB7
};
volatile unsigned int * p = (volatile unsigned int *)0x48000000;
int i;
for (i = 0; i < 13; i++)
{
*p = arr[i];
p++;
}
}
内部使用memcpy将数据段的数据复制到栈上,因此我们将其修改为静态变量,这些数据就会放在数据段中,最终重定位时会把数据类拷贝到对应的arr地址里面去。
还有一种解决办法是我们自己实现memcpy函数。
void sdram_init2(void)
{
const static unsigned int arr[] = { //加上const 和static
0x22000000, //BWSCON
0x00000700, //BANKCON0
0x00000700, //BANKCON1
0x00000700, //BANKCON2
0x00000700, //BANKCON3
0x00000700, //BANKCON4
0x00000700, //BANKCON5
0x18001, //BANKCON6
0x18001, //BANKCON7
0x8404f5, //REFRESH,HCLK=12MHz:0x008e07a3,HCLK=100MHz:0x008e04f4
0xb1, //BANKSIZE
0x20, //MRSRB6
0x20, //MRSRB7
};
volatile unsigned int * p = (volatile unsigned int *)0x48000000;
int i;
for (i = 0; i < 13; i++)
{
*p = arr[i];
p++;
}
}
查看文件大小可以看出原先的bin文件有2K左右,用thumb编译的文件1.4K.
查看反汇编代码:
sdram.elf: file format elf32-littlearm
Disassembly of section .text:
/*前面这些ARM指令还是占用4个字节*/
30000000 <_start>:
30000000: e3a00453 mov r0, #1392508928 ; 0x53000000
30000004: e3a01000 mov r1, #0 ; 0x0
30000008: e5801000 str r1, [r0]
3000000c: e3a00313 mov r0, #1275068416 ; 0x4c000000
30000010: e3e01000 mvn r1, #0 ; 0x0
30000014: e5801000 str r1, [r0]
30000018: e59f005c ldr r0, [pc, #92] ; 3000007c <.text+0x7c>
3000001c: e3a01005 mov r1, #5 ; 0x5
30000020: e5801000 str r1, [r0]
30000024: ee110f10 mrc 15, 0, r0, cr1, cr0, {0}
30000028: e3800103 orr r0, r0, #-1073741824 ; 0xc0000000
3000002c: ee010f10 mcr 15, 0, r0, cr1, cr0, {0}
30000030: e59f0048 ldr r0, [pc, #72] ; 30000080 <.text+0x80>
30000034: e59f1048 ldr r1, [pc, #72] ; 30000084 <.text+0x84>
30000038: e5801000 str r1, [r0]
3000003c: e3a01000 mov r1, #0 ; 0x0
30000040: e5910000 ldr r0, [r1]
30000044: e5811000 str r1, [r1]
30000048: e5912000 ldr r2, [r1]
3000004c: e1510002 cmp r1, r2
30000050: e59fd030 ldr sp, [pc, #48] ; 30000088 <.text+0x88>
30000054: 03a0da01 moveq sp, #4096 ; 0x1000
30000058: 05810000 streq r0, [r1]
3000005c: e28f0004 add r0, pc, #4 ; 0x4
30000060: e2800001 add r0, r0, #1 ; 0x1
30000064: e12fff10 bx r0
30000068 <thumb_func>:
30000068: f94ef000 bl 30000308 <sdram_init>
3000006c: f9fef000 bl 3000046c <copy2sdram>
30000070: fa24f000 bl 300004bc <clean_bss>
/**下面的thumb指令占据2个字节**/
30000074: 4805 ldr r0, [pc, #20] (3000008c <.text+0x8c>)
30000076: 4687 mov pc, r0
30000078 <halt>:
30000078: e7fe b 30000078 <halt>
3000007a: 0000 lsl r0, r0, #0
3000007c: 0014 lsl r4, r2, #0
3000007e: 4c00 ldr r4, [pc, #0] (30000080 <.text+0x80>)
30000080: 0004 lsl r4, r0, #0
30000082: 4c00 ldr r4, [pc, #0] (30000084 <.text+0x84>)
30000084: c011 stmia r0!,{r0, r4}
30000086: 0005 lsl r5, r0, #0
30000088: 1000 asr r0, r0, #0
3000008a: 4000 and r0, r0
3000008c: 04fd lsl r5, r7, #19
3000008e: 3000 add r0, #0
如果你的flash很小的话可以考虑使用Thumb指令集
烧写进去看是否可以运行
测试结果没有任何问题
Thumb指令集后面没有任何作用,只是简单作为介绍