|
关于重定位的理论知识推荐大家观看韦东山的视频《6410裸板视频》中的第5章(位置无关码、重定位)。
下载地址:http://pan.baidu.com/share/link? ... 0%E8%A3%B8%E6%9D%BF
在S5PV210上的实验方法:烧写程序到SD的第1块,从SD启动,程序的链接地址为0xD0024000,在程序中将程序拷贝到0xD0024000地址处,然后跳转到main函数去执行。
运行效果如下:
before relocate
after relocate
t = 0
t = 1
t = 2
t = 3
t = 4
t = 5
8ððàÿÿÿÿÿÿÿø
在重定位之前,用自己实现的puts函数打印字符串“before relocate”,重定位后,循环打印t的值。
注意这里在重定位前不能使用printf("before relocate")这样的操作,因为字符串"before relocate"是放在数据段中的,而程序中访问数据段的内容使用的是链接地址(0xD0024000之后),而这时程序还位于0xD0020010。具体怎么处理见代码。
start.S
[cpp] view plaincopy
01..global br_str /* 声明全局标号 */
02..global ar_str
03..global _start
04._start:
05. bl clock_init /* 时钟初始化 */
06. bl uart_init /* 串口初始化 */
07.
08. adr r0, br_str /* 取得br_str的当前地址(重定位之前) */
09. /* 调用C函数before_relocate,接收一个参数 */
10. bl before_relocate
11.
12. /* 重定位 */
13. adr r0, _start /* 相对寻址:取得_start的当前地址0xD0020010 */
14. ldr r1, =_start /* 绝对寻址:取得_start的链接地址0xD0024000 */
15. ldr r2, =bss_start /* bss段的起始地址 */
16. cmp r0, r1 /* 如果取得_start的当前地址和链接地址相等,则说明程序已经位于它的链接地址 */
17. beq clean_bss
18.
19.copy_loop:
20. ldr r3, [r0], #4 // 源
21. str r3, [r1], #4 // 目的
22. cmp r1, r2
23. bne copy_loop
24.
25.
26. /* 清bss段 */
27.clean_bss:
28. ldr r0, =bss_start
29. ldr r1, =bss_end
30. cmp r0, r1
31. beq relocate_done
32. /* 为什么这里要比较呢?
33. ** 因为如果相等,则bss段没有数据,而这时如果进行下面的清bss段操作
34. ** 首先执行“str r2, [r0], #4”后,r0加4,再执行“cmp r0, r1”就不相等了,这样一直循环。
35. */
36.
37. mov r2, #0
38.1:
39. str r2, [r0], #4
40. cmp r0, r1
41. bne 1b /* b是back的意思,代表向后跳转;如果向前跳转则使用f意思是forward */
42.
43. /* 跳转 */
44.relocate_done:
45. ldr pc, =main
46.
47.halt:
48. b halt
49.
50./* 定义一个字符串:.asciz会自动添加一个'\0',而ascii不会 */
51.br_str:
52. .asciz "\nbefore relocate\n"
types.h
[cpp] view plaincopy
01.#ifndef TYPES_H_
02.#define TYPES_H_
03.
04.typedef volatile char s8;
05.typedef volatile short s16;
06.typedef volatile int s32;
07.
08.typedef volatile unsigned char u8;
09.typedef volatile unsigned short u16;
10.typedef volatile unsigned int u32;
11.
12.#endif
clock.c
[cpp] view plaincopy
01.#include <stdarg.h>
02.#include "types.h"
03.
04.#define GPA0CON *((volatile unsigned int *)0xE0200000)
05.#define ULCON0 *((volatile unsigned int *)0xE2900000)
06.#define UCON0 *((volatile unsigned int *)0xE2900004)
07.#define UFCON0 *((volatile unsigned int *)0xE2900008)
08.#define UTRSTAT0 *((volatile unsigned int *)0xE2900010)
09.#define UTXH0 *((volatile unsigned int *)0xE2900020)
10.#define URXH0 *((volatile unsigned int *)0xE2900024)
11.#define UBRDIV0 *((volatile unsigned int *)0xE2900028)
12.#define UDIVSLOT0 *((volatile unsigned int *)0xE290002C)
13.
14./*
15.** UART0初始化
16.*/
17.void uart_init()
18.{
19. /*
20. ** 配置GPA0_0为UART_0_RXD
21. ** 配置GPA0_1为UART_0_TXD
22. */
23. GPA0CON &= ~0xFF;
24. GPA0CON |= 0x22;
25.
26. /* 8-bits/One stop bit/No parity/Normal mode operation */
27. ULCON0 = 0x3 | (0 << 2) | (0 << 3) | (0 << 6);
28.
29. /* Interrupt request or polling mode/Normal transmit/Normal operation/PCLK/*/
30. UCON0 = 1 | (1 << 2) | (0 << 10);
31.
32. /* 静止FIFO */
33. UFCON0 = 0;
34.
35. /*
36. ** 波特率计算:115200bps
37. ** PCLK = 66MHz
38. ** DIV_VAL = (66000000/(115200 x 16))-1 = 35.8 - 1 = 34.8
39. ** UBRDIV0 = 34(DIV_VAL的整数部分)
40. ** (num of 1's in UDIVSLOTn)/16 = 0.8
41. ** (num of 1's in UDIVSLOTn) = 12
42. ** UDIVSLOT0 = 0xDDDD (查表)
43. */
44. UBRDIV0 = 34;
45. UDIVSLOT0 = 0xDDDD;
46.}
47.
48./* 输出一字节的数据到终端 */
49.void uart_send_byte(u8 byte)
50.{
51. while (!(UTRSTAT0 & (1 << 2))); /* 等待发送缓冲区为空 */
52. UTXH0 = byte; /* 发送一字节数据 */
53.}
54.
55./* 从终端接收一字节数据 */
56.u8 uart_recv_byte()
57.{
58. while (!(UTRSTAT0 & 1)); /* 等待接收缓冲区有数据可读 */
59. return URXH0; /* 接收一字节数据 */
60.}
61.
62./* 打印字符c到终端 */
63.void putchar(u8 c)
64.{
65. uart_send_byte(c);
66. if (c == '\n')
67. uart_send_byte('\r');
68.}
69.
70./* 打印字符串s到终端 */
71.void puts(s8 *s)
72.{
73. s8 *p = s;
74. while (*p)
75. putchar(*p++);
76.}
77.
78./* 打印整数v到终端 */
79.void put_int(u32 v)
80.{
81. int i;
82. u8 a[10];
83. u8 cnt = 0;
84.
85. if (v == 0)
86. {
87. putchar('0');
88. return;
89. }
90.
91. while (v)
92. {
93. a[cnt++] = v % 10;
94. v /= 10;
95. }
96.
97. for (i = cnt - 1; i >= 0; i--)
98. putchar(a + 0x30);
99. /*
100. ** 整数0-9的ASCII分别为0x30-0x39
101. */
102.}
103.
104./* 将一字节十六进制数按十六进制显示打印到终端 */
105.void put_hex(u8 v, u8 small)
106.{
107. /* 注意:必须用volatile修饰,否则会出错 */
108. u8 h, l; /* 高4位和第4位(这里按二进制算) */
109. char *hex1 = "0123456789abcdef"; /* 这里放在数据段中 */
110. char *hex2 = "0123456789ABCDEF";
111.
112. h = v >> 4;
113. l = v & 0x0F;
114.
115. if (small) /* 小写 */
116. {
117. putchar(hex1[h]); /* 高4位 */
118. putchar(hex1[l]); /* 低4位 */
119. }
120. else /* 大写 */
121. {
122. putchar(hex2[h]); /* 高4位 */
123. putchar(hex2[l]); /* 低4位 */
124. }
125.}
126.
127./* 将int型整数按16进制打印到终端 */
128.void put_int_hex(u32 v, u8 small)
129.{
130. if (v >> 24)
131. {
132. put_hex(v >> 24, small);
133. put_hex((v >> 16) & 0xFF, small);
134. put_hex((v >> 8) & 0xFF, small);
135. put_hex(v & 0xFF, small);
136. }
137. else if ((v >> 16) & 0xFF)
138. {
139. put_hex((v >> 16) & 0xFF, small);
140. put_hex((v >> 8) & 0xFF, small);
141. put_hex(v & 0xFF, small);
142. }
143. else if ((v >> 8) & 0xFF)
144. {
145. put_hex((v >> 8) & 0xFF, small);
146. put_hex(v & 0xFF, small);
147. }
148. else
149. put_hex(v & 0xFF, small);
150.}
151.
152./* 格式化输出到终端 */
153.int printf(const char *fmt, ...)
154.{
155. va_list ap;
156. s8 c;
157. s8 *s;
158. u32 d;
159. u8 small;
160.
161. va_start(ap, fmt);
162. while (*fmt)
163. {
164. small = 0;
165. c = *fmt++;
166. if (c == '%')
167. {
168. switch (*fmt++)
169. {
170. case 'c': /* char */
171. c = (char) va_arg(ap, int);
172. putchar(c);
173. break;
174. case 's': /* string */
175. s = va_arg(ap, char *);
176. puts(s);
177. break;
178. case 'd': /* int */
179. case 'u':
180. d = va_arg(ap, int);
181. put_int(d);
182. break;
183. case 'x':
184. small = 1; // small
185. case 'X':
186. d = va_arg(ap, int);
187. put_int_hex(d, small);
188. break;
189. }
190. }
191. else
192. putchar(c);
193. }
194. va_end(ap);
195.}
[cpp] view plaincopy
01.#define APLLCON0 *((volatile unsigned int *)0xE0100100)
02.#define MPLLCON *((volatile unsigned int *)0xE0100108)
03.#define EPLLCON0 *((volatile unsigned int *)0xE0100110)
04.#define VPLLCON *((volatile unsigned int *)0xE0100120)
05.#define CLK_SRC0 *((volatile unsigned int *)0xE0100200)
06.#define CLK_DIV0 *((volatile unsigned int *)0xE0100300)
07.#define CLK_DIV1 *((volatile unsigned int *)0xE0100304)
08.#define CLK_DIV2 *((volatile unsigned int *)0xE0100308)
09.#define CLK_DIV3 *((volatile unsigned int *)0xE010030C)
10.
11.void clock_init()
12.{
13. /* 1、设置PLL_LOCK寄存器(这里使用默认值) */
14. /* 2、设置PLL_CON寄存器(使用芯片手册推荐的值) */
15. APLLCON0 = (1 << 0) | (3 << 8) | (125 << 16) | (1 << 31); /* FOUTAPLL = 1000MHz */
16. MPLLCON = (1 << 0) | (12 << 8) | (667 << 16) | (1 << 31); /* FOUTMPLL = 667MHz */
17. EPLLCON0 = (1 << 0) | (12 << 8) | (667 << 16) | (1 << 31); /* FOUTEPLL = 96MHz */
18. VPLLCON = (3 << 0) | (6 << 8) | (108 << 16) | (1 << 31); /* FOUTVPLL = 54MHz */
19.
20. /* 3、选择PLL为时钟输出 */
21. /* MOUT_MSYS = SCLKAPLL = 1000MHz
22. ** MOUT_DSYS = SCLKMPLL = 667MHz
23. ** MOUT_PSYS = SCLKMPLL = 667MHz
24. */
25. CLK_SRC0 = (1 << 0) | (1 << 4) | (1 << 8) | (1 << 12);
26.
27. /* 4、设置系统时钟分频值 */
28. /* freq(ARMCLK) = MOUT_MSYS / (APLL_RATIO + 1) = 1000MHz / (0 + 1) = 1000MHz
29. ** freq(HCLK_MSYS) = ARMCLK / (HCLK_MSYS_RATIO + 1) = 1000MHz / (4 + 1) = 200MHz
30. ** freq(PCLK_MSYS) = HCLK_MSYS / (PCLK_MSYS_RATIO + 1) = 200MHz / (1 + 1) = 100MHz
31. ** freq(HCLK_DSYS) = MOUT_DSYS / (HCLK_DSYS_RATIO + 1) = 667 / (3 + 1) = 166MHz
32. ** freq(PCLK_DSYS) = HCLK_DSYS / (PCLK_DSYS_RATIO + 1) = 166 / (1 + 1) = 83MHz
33. ** freq(HCLK_PSYS) = MOUT_PSYS / (HCLK_PSYS_RATIO + 1) = 667 / (4 + 1) = 133MHz
34. ** freq(PCLK_PSYS) = HCLK_PSYS / (PCLK_PSYS_RATIO + 1) = 133 / (1 + 1) = 66MHz
35. */
36. CLK_DIV0 = (0 << 0) | (4 << 8) | (1 << 12) | (3 << 16) | (1 << 20) | (4 << 24) | (1 << 28);
37.}
uart.c
[cpp] view plaincopy
01.#include <stdarg.h>
02.#include "types.h"
03.
04.#define GPA0CON *((volatile unsigned int *)0xE0200000)
05.#define ULCON0 *((volatile unsigned int *)0xE2900000)
06.#define UCON0 *((volatile unsigned int *)0xE2900004)
07.#define UFCON0 *((volatile unsigned int *)0xE2900008)
08.#define UTRSTAT0 *((volatile unsigned int *)0xE2900010)
09.#define UTXH0 *((volatile unsigned int *)0xE2900020)
10.#define URXH0 *((volatile unsigned int *)0xE2900024)
11.#define UBRDIV0 *((volatile unsigned int *)0xE2900028)
12.#define UDIVSLOT0 *((volatile unsigned int *)0xE290002C)
13.
14./*
15.** UART0初始化
16.*/
17.void uart_init()
18.{
19. /*
20. ** 配置GPA0_0为UART_0_RXD
21. ** 配置GPA0_1为UART_0_TXD
22. */
23. GPA0CON &= ~0xFF;
24. GPA0CON |= 0x22;
25.
26. /* 8-bits/One stop bit/No parity/Normal mode operation */
27. ULCON0 = 0x3 | (0 << 2) | (0 << 3) | (0 << 6);
28.
29. /* Interrupt request or polling mode/Normal transmit/Normal operation/PCLK/*/
30. UCON0 = 1 | (1 << 2) | (0 << 10);
31.
32. /* 静止FIFO */
33. UFCON0 = 0;
34.
35. /*
36. ** 波特率计算:115200bps
37. ** PCLK = 66MHz
38. ** DIV_VAL = (66000000/(115200 x 16))-1 = 35.8 - 1 = 34.8
39. ** UBRDIV0 = 34(DIV_VAL的整数部分)
40. ** (num of 1's in UDIVSLOTn)/16 = 0.8
41. ** (num of 1's in UDIVSLOTn) = 12
42. ** UDIVSLOT0 = 0xDDDD (查表)
43. */
44. UBRDIV0 = 34;
45. UDIVSLOT0 = 0xDDDD;
46.}
47.
48./* 输出一字节的数据到终端 */
49.void uart_send_byte(u8 byte)
50.{
51. while (!(UTRSTAT0 & (1 << 2))); /* 等待发送缓冲区为空 */
52. UTXH0 = byte; /* 发送一字节数据 */
53.}
54.
55./* 从终端接收一字节数据 */
56.u8 uart_recv_byte()
57.{
58. while (!(UTRSTAT0 & 1)); /* 等待接收缓冲区有数据可读 */
59. return URXH0; /* 接收一字节数据 */
60.}
61.
62./* 打印字符c到终端 */
63.void putchar(u8 c)
64.{
65. uart_send_byte(c);
66. if (c == '\n')
67. uart_send_byte('\r');
68.}
69.
70./* 打印字符串s到终端 */
71.void puts(s8 *s)
72.{
73. s8 *p = s;
74. while (*p)
75. putchar(*p++);
76.}
77.
78./* 打印整数v到终端 */
79.void put_int(u32 v)
80.{
81. int i;
82. u8 a[10];
83. u8 cnt = 0;
84.
85. if (v == 0)
86. {
87. putchar('0');
88. return;
89. }
90.
91. while (v)
92. {
93. a[cnt++] = v % 10;
94. v /= 10;
95. }
96.
97. for (i = cnt - 1; i >= 0; i--)
98. putchar(a + 0x30);
99. /*
100. ** 整数0-9的ASCII分别为0x30-0x39
101. */
102.}
103.
104./* 将一字节十六进制数按十六进制显示打印到终端 */
105.void put_hex(u8 v, u8 small)
106.{
107. /* 注意:必须用volatile修饰,否则会出错 */
108. u8 h, l; /* 高4位和第4位(这里按二进制算) */
109. char *hex1 = "0123456789abcdef"; /* 这里放在数据段中 */
110. char *hex2 = "0123456789ABCDEF";
111.
112. h = v >> 4;
113. l = v & 0x0F;
114.
115. if (small) /* 小写 */
116. {
117. putchar(hex1[h]); /* 高4位 */
118. putchar(hex1[l]); /* 低4位 */
119. }
120. else /* 大写 */
121. {
122. putchar(hex2[h]); /* 高4位 */
123. putchar(hex2[l]); /* 低4位 */
124. }
125.}
126.
127./* 将int型整数按16进制打印到终端 */
128.void put_int_hex(u32 v, u8 small)
129.{
130. if (v >> 24)
131. {
132. put_hex(v >> 24, small);
133. put_hex((v >> 16) & 0xFF, small);
134. put_hex((v >> 8) & 0xFF, small);
135. put_hex(v & 0xFF, small);
136. }
137. else if ((v >> 16) & 0xFF)
138. {
139. put_hex((v >> 16) & 0xFF, small);
140. put_hex((v >> 8) & 0xFF, small);
141. put_hex(v & 0xFF, small);
142. }
143. else if ((v >> 8) & 0xFF)
144. {
145. put_hex((v >> 8) & 0xFF, small);
146. put_hex(v & 0xFF, small);
147. }
148. else
149. put_hex(v & 0xFF, small);
150.}
151.
152./* 格式化输出到终端 */
153.int printf(const char *fmt, ...)
154.{
155. va_list ap;
156. s8 c;
157. s8 *s;
158. u32 d;
159. u8 small;
160.
161. va_start(ap, fmt);
162. while (*fmt)
163. {
164. small = 0;
165. c = *fmt++;
166. if (c == '%')
167. {
168. switch (*fmt++)
169. {
170. case 'c': /* char */
171. c = (char) va_arg(ap, int);
172. putchar(c);
173. break;
174. case 's': /* string */
175. s = va_arg(ap, char *);
176. puts(s);
177. break;
178. case 'd': /* int */
179. case 'u':
180. d = va_arg(ap, int);
181. put_int(d);
182. break;
183. case 'x':
184. small = 1; // small
185. case 'X':
186. d = va_arg(ap, int);
187. put_int_hex(d, small);
188. break;
189. }
190. }
191. else
192. putchar(c);
193. }
194. va_end(ap);
195.}
main.c
[cpp] view plaincopy
01.#include "uart.h"
02.#include "types.h"
03.
04.void delay(u32 t)
05.{
06. u32 t2 = 0xFFFF;
07. while (t--)
08. for (; t2; t2--);
09.}
10.
11.void before_relocate(u32 addr)
12.{
13. char *p = (char *)addr;
14. puts(p);
15.}
16.
17.int main()
18.{
19. u32 t = 0;
20. printf("\nafter relocate\n\n");
21. while (1)
22. {
23. printf("t = %d\n", t++);
24. delay(1000000);
25. }
26. return 0;
27.}
link.lds(链接脚本)
[cpp] view plaincopy
01.SECTIONS
02.{
03. . = 0xD0024000;
04.
05. .text : {
06. start.o
07. * (.text)
08. }
09.
10. .data : {
11. * (.data)
12. }
13.
14. bss_start = .;
15. .bss : {
16. * (.bss)
17. }
18.
19. bss_end = .;
20.}
Makefile
uart.bin: start.o clock.o uart.o main.o
arm-linux-ld -Tlink.lds -o uart.elf $^
arm-linux-objcopy -O binary uart.elf $@
arm-linux-objdump -D uart.elf > uart.dis
%.o : %.c
arm-linux-gcc -c $< -o $@
%.o : %.S
arm-linux-gcc -c $< -o $@
clean:
rm *.o *.elf *.bin *.dis
烧写过程见《TQ210裸机编程(5)——系统时钟配置》
转载请注明来源:http://blog.csdn.net/zjhsucceed_329/
|
|