学习大神写的bootload笔记

看了网上大神写的bootload,弄个小笔记

1、内联汇编编程
带有C/C++表达式的内联汇编格式为:
  asm volatile(“InSTructiON List” : Output : Input : Clobber/Modify);
  Instruction list是汇编指令序列:
   当Instruction list中有多条指令时,可以将多条指令放在一对引号中,用;或\n将它们分开,如过一条指令放一对引号中,可以每条指令一行。
2. __volatile__是GCC 关键字volatile 的宏定义
#define volatile volatile
 __volatile__或volatile 是可选的,假如用了它,则是向GCC 声明不答应对该内联汇编优化,否则当 使用了优化选项(-O)进行编译时,GCC 将会根据自己的判定决定是否将这个内联汇编表达式中的指令优化掉。
3. Output 用来指定内联汇编语句的输出
4.Input
Input 域的内容用来指定当前内联汇编语句的输进Input中,格式为形如“constraint”(variable)的列表(逗号分隔)
5.Clobber/Modify
 有时候,你想通知GCC当前内联汇编语句可能会对某些寄存器或内存进行修改,希看GCC在编译时能够将这一点考虑进往。那么你就可以在Clobber/Modify域声明这些寄存器或内存。这种情况一般发生在一个寄存器出现在"Instruction List",但却不是由Input/Output操纵表达式所指定的,也不是在一些Input/Output操纵表达式使用"r"约束时由GCC 为其选择的,同时此寄存器被"Instruction List"中的指令修改,而这个寄存器只是供当前内联汇编临时使用的情况。如果内存有改动就加”memory”
例如:

void CP15_SetTranslationTableBase(int Base)
{
	asm volatile (
		"mcr p15,0,%0,c2,c0,0\n"  
		: : "r"(Base):"memory"
	);
}

2、S3C2416.lds — 连接脚本,主要在连接过程中指定代码的重定位

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start) 
SECTIONS
{
	. = 0x00000000;   --- 编译起始地址
	. = ALIGN(4);
	.text	:   --- 代码区
	{
	  _scode = .;    --代码区的首地址
	  ./System/s3c2416.o (.text* .rodata*)
	  ./System/LowLevelInit.o (.text* .rodata*)
	  ./System/NandBoot.o (.text* .rodata*)
	  ./System/Coprocessor.o (.text* .rodata*)
	  ./System/Download.o (.text* .rodata*)
	  *(.text*)
	}
	. = ALIGN(4);
	.rodata : { *(.rodata*) }

	. = ALIGN(4);   --- 4个字节对齐
	.data :   --- 数据区
	{ 
	  _sdata = .;
	  *(.data*)
	  _edata = .;
	}
	_ecode = .;  

	. = ALIGN(4);
	.bss :    
	{
	  _sbss = .;
	  *(.bss*)
	  *(COMMON*)
	  _ebss = .;
	}

	. = ALIGN(4);
	.heap (NOLOAD):
	{
	  PROVIDE(end = .);
	  *(.heap*)
	}

	. = ALIGN(4);
	.stack (NOLOAD):
	{
	  *(.stack*)
	}

	. = ALIGN(4);
	.mem_uninit (NOLOAD):
	{
	  *(.mem_uninit)
	}

	/* cache off, write buffer off */
	. = ALIGN(0x100000);
	.mem_ncnb (NOLOAD):
	{
	  _smem_ncnb = .;
	  *(.mem_ncnb)
	  _emed_ncnb = .;
	}
	/* cache off, write buffer on */
	. = ALIGN(0x100000);
	.mem_ncb (NOLOAD):
	{
	  _smem_ncb = .;
	  *(.mem_ncb)
	  _emem_ncb = .;
	}	
	/* cache on, write through */
	. = ALIGN(0x100000);
	.mem_cnb (NOLOAD):
	{
	  _smem_cnb = .;
	  *(.mem_cnb)
	  _emem_cnb = .;
	}
}

3、LowLevelInit.S – 实现重要的函数

	.text
	.arm
	.align	2
/************************ 时钟初始化 *****************************/
// Clock Base Address
#define	CLOCK_BASE	0x4C000000
#define	LOCKCON0_OFS	0x00
#define	LOCKCON1_OFS	0x04
#define	MPLLCON_OFS	0x10
#define	EPLLCON_OFS	0x18
#define	CLKSRC_OFS	0x20
#define	CLKDIV0_OFS	0x24
#define	CLKDIV1_OFS	0x28
#define	CLKDIV2_OFS	0x2C	

	.globl	Clock_Init		
Clock_Init:    //对时钟进行设置
	LDR	R0, =CLOCK_BASE
	LDR	R1, =3600 
// MPLL锁定时间大于300us,以外部晶振12M计
	STR	R1, [R0, #LOCKCON0_OFS]
	LDR	R1, =3600 
// EPLL锁定时间大于300us
	STR	R1, [R0, #LOCKCON1_OFS]
				
	LDR	R1, =(0x1<<0)+(1<<2)+(1<<3)+(0x1<<4)+(0x0<<9)
	STR	R1, [R0, #CLKDIV0_OFS]
				
	LDR	R1, =(0x0<<4)+(0x3<<6)+(0x0<<8)+(0x0<<12)+ \
							(0x0<<16)+(0x0<<24)
	STR	R1, [R0, #CLKDIV1_OFS]
	
	LDR	R1, =(0x0<<0)+(0x3<<6)
	STR	R1, [R0, #CLKDIV2_OFS]
				
// 设置EPLL输出96M,
	LDR	R1, =(2<<0)+(1<<8)+(32<<16)+(0x0<<24)+(0x0<<25)
	STR	R1, [R0, #EPLLCON_OFS]			
				
// 外部晶振12M,设置MPLL输出为533M
	LDR	R1, =(1<<0)+(3<<5)+(267<<14)+(0x0<<24)+(0x0<<25)
	STR	R1, [R0, #MPLLCON_OFS] 

	LDR	R1, =(1<<4)+(1<<6) 
	STR	R1, [R0, #CLKSRC_OFS]
		
	BX	LR

/********************* 内存初始化 ********************************/	
// DRAM controller base address
#define	DRAM_BASE	0x48000000
#define	BANKCFG_OFS	0x00
#define	BANKCON1_OFS	0x04
#define	BANKCON2_OFS	0x08
#define	BANKCON3_OFS	0x0C
#define	REFRESH_OFS	0x10
#define	TIMEOUT_OFS	0x14

	.globl	ERAM_Init
ERAM_Init: //初始化内存
	LDR	R0, =DRAM_BASE
	LDR	R1, =(2<<17)+(2<<14)+(2<<11)+(2<<8)+(1<<6)+(1<<4)+(1<<1)+(1<<0)
	STR	R1, [R0, #BANKCFG_OFS]
// DQS delay 3,Write buffer,Auto pre-charge,bank address 在高位 				
	LDR	R1, =(3<<28)+(1<<26)+(1<<8)+(0<<7)+ \
			(1<<6)+(0<<5)+(1<<4)
	STR	R1, [R0, #BANKCON1_OFS]		
				
	LDR	R1, =(5<<20)+(13<<16)+(3<<4)+(1<<2)+(1<<0)
	STR	R1, [R0, #BANKCON2_OFS]	

// issue a PALL(pre-charge all) command
	LDR	R1, [R0, #BANKCON1_OFS]
	BIC	R1, R1, #0x03
	ORR	R1, R1, #0x01
	STR	R1, [R0, #BANKCON1_OFS]

// issue an EMRS(extern mode register) command to EMR(2)
	LDR	R1, [R0, #BANKCON3_OFS]
	LDR	R2, =0xFFFF0000
	BIC	R1, R1, R2
	ORR	R1, R1, #(2<<30)
	STR	R1, [R0, #BANKCON3_OFS]

	LDR	R1, [R0, #BANKCON1_OFS]
	ORR	R1, R1, #0x03				
	STR	R1, [R0, #BANKCON1_OFS]

// issue an EMRS(extern mode register) command to EMR(3)
	LDR	R1, [R0, #BANKCON3_OFS]
	LDR	R2, =0xFFFF0000
	BIC	R1, R1, R2
	ORR	R1, R1, #(3<<30)
	STR	R1, [R0, #BANKCON3_OFS]

	LDR	R1, [R0, #BANKCON1_OFS]
	ORR	R1, R1, #0x03				
	STR	R1, [R0, #BANKCON1_OFS]
				
// issue an EMRS to enable DLL and RDQS, nDQS, ODT disable
	LDR	R1, =0xFFFF0000
	LDR	R2, [R0, #BANKCON3_OFS]
	BIC	R2, R2, R1
	LDR	R1, =(0x1<<30)+(0<<27)+(1<<26)+ \
			 (0<<23)+(0<<16)				
	ORR	R1, R1, R2
	STR	R1, [R0, #BANKCON3_OFS]
	LDR	R1, [R0, #BANKCON1_OFS]
	ORR	R1, R1, #0x03				
	STR	R1, [R0, #BANKCON1_OFS]

// issue a mode register set command for DLL reset 
	LDR	R1, =0x0000FFFF
	LDR	R2, [R0, #BANKCON3_OFS]
	BIC	R2, R2, R1
	LDR	R1, =(1<<8)+(0<<7)+(3<<4)						
	ORR	R1, R1, R2
	STR	R1, [R0, #BANKCON3_OFS]
	LDR	R1, [R0, #BANKCON1_OFS]
	BIC	R1, R1, #0x03
	ORR	R1, R1, #0x02				
	STR	R1, [R0, #BANKCON1_OFS]
				
// Issue a PALL(pre-charge all) command	
	LDR	R1, [R0, #BANKCON1_OFS]
	BIC	R1, R1, #0x03
	ORR	R1, R1, #0x01
	STR	R1, [R0, #BANKCON1_OFS]
				
// Issue 2 or more auto-refresh commands
	LDR	R1, =0x20
	STR	R1, [R0, #REFRESH_OFS]
				
// Issue a MRS command with LOW to A8 to initialize device operation
	LDR	R1, =0x0000FFFF
	LDR	R2, [R0, #BANKCON3_OFS]
	BIC	R2, R2, R1
	LDR	R1, =(0<<8)+(0<<7)+(3<<4)					
	ORR	R1, R1, R2
	STR	R1, [R0, #BANKCON3_OFS]
	LDR	R1, [R0, #BANKCON1_OFS]
	BIC	R1, R1, #0x03
	ORR	R1, R1, #0x02				
	STR	R1, [R0, #BANKCON1_OFS]
				
// Wait 200 clock, execute OCD Calibration
	LDR	R1, =200
0:	SUBS	R1, R1, #1
	BNE	0b
				
// Issue a EMRS1 command to over OCD Mode Calibration
	LDR	R1, =0xFFFF0000
	LDR	R2, [R0, #BANKCON3_OFS]
	BIC	R2, R2, R1
	LDR	R1, =(0x1<<30)+(0<<27)+(1<<26)+ \
			(0<<23)+(0<<19)+(0<<22)+(0<<18)+ \
			(0x0<<17)+(0<<16)				
	ORR	R1, R1, R2
	STR	R1, [R0, #BANKCON3_OFS]
	LDR	R1, [R0, #BANKCON1_OFS]
	ORR	R1, R1, #0x03				
	STR	R1, [R0, #BANKCON1_OFS]

// Refresh period is 7.8us, HCLK=133M, REFCYC=1037
	LDR	R1, =1037
	STR	R1, [R0, #REFRESH_OFS]

// issue a Normal mode
	LDR	R1, [R0, #BANKCON1_OFS]
	BIC	R1, R1, #0x03
	STR	R1, [R0, #BANKCON1_OFS]
				
	BX	LR
				
/*******************  复制代码函数*******************************/
// SD/MMC Device Boot Block Assignment
#define	eFuseBlockSize	1
#define	SdReservedBlockSize	1
#define	BL1BlockSize	16
#define	SdBL1BlockStart	SdReservedBlockSize + \
					eFuseBlockSize + BL1BlockSize
#define	globalBlockSizeHide	0x40003FFC
#define	CopyMovitoMem	0x40004008

// Nand controller base address
#define	NFCONF	0x4E000000

// Port c base address
#define	GPCCON	0x56000020

// 引出代码搬移函数,以供启动代码调用
	.globl	CopyCodeToRAM
// 引入Nand启动的初始化函数及Nand读函数
	.extern	NandBoot_Init
	.extern	NandBoot_ReadSkipBad
	.extern	NandBoot_ReadWithoutCheck

	.extern	CP15_EnableICache
	.extern	_scode
	.extern	_ecode
									
CopyCodeToRAM:
	STMFD	SP!, {LR} // 将LR入栈,保存返回地址

	BL	CP15_EnableICache // 开启ICache,加快执行代码
		
	LDR	R0, =GPCCON
	MOV	R1, #0
	STR	R1, [R0] // 设置GPC为输入引脚
		
// 判断NFCONF的最高位为1,说明启动设备为Nand		
	LDR	R0, =NFCONF
	LDR	R1, [R0]
	AND	R1, R1, #0x80000000
	CMP	R1, #0x80000000
	BNE	IROM_Boot	//IROM启动

Nand_Boot:		
	BL	NandBoot_Init // Nand初始化
	MOV	R0, #0
	LDR	R1, =_scode
	LDR	R2, =_ecode
	SUB	R2, R1

	BL	NandBoot_ReadSkipBad // 调用Nand读函数,检查坏块
// 如果用仿真器下载代码进NAND,Nand boot启动应禁止对NAND检验,应采用下面的函数加载
//	BL	NandBoot_ReadWithoutCheck // 不检验读取数据,不检查坏块
		
	MOVS	R0, R0 // 返回值确定函数成功还是失败
Nand_Boot_Loop:	
	BNE	Nand_Boot_Loop // 返回非0说明拷贝失败
	B	AfterCopy
		
IROM_Boot:
	LDR	R0, =GPCCON
	LDR	R1, [R0, #4] // GPC data
	AND	R1, R1, #(7<<5) // GPC5 ~ GPC7
	MOV	R0, #(0<<5) // IROM MMC boot
	CMP	R0, R1
	BEQ	IROM_MMC_Boot //如果是SD卡启动
	MOV	R0, #(5<<5)
	CMP	R0, R1
	BEQ	Nand_Boot // NANDFLASH启动
IROM_Unknow_Boot:
	B	IROM_Unknow_Boot
		
IROM_MMC_Boot:
	LDR	R3, =0 
// 到链接执行域内存代码处
	LDR	R2, =_scode
				
// 计算代码的大小,以block计,不足512字节的算1个block
// 代码的大小包括Code RO-data RW-data(代码需保存需初始化的RW的初始值)
// 代码保存在ROM中,应从加载域得到ROM的大小,而不是执行域,编译器可能压缩
// 代码段保存在加载域的ROM中
	LDR	R0, =_ecode
	SUB	R0, R2
	LDR	R1, =0x1ff
	TST	R0, R1 // TST按位与运算,是否不足一个block(512Bytes)
	BEQ	0f // 代码恰好block对齐,不用加多一个block
	ADD	R0, R0, #512
0:
	LSR	R1, R0, #9 // 逻辑右移,得到代码的block大小(注:9位就是相当于512B)

// 计算代码在SD/MMC卡中的block起启地址
	LDR	R4, =SdBL1BlockStart	
	LDR	R0, =globalBlockSizeHide   //SD卡的总块数
	LDR	R0, [R0] // SD/MMC的总block块
	SUB	R0, R4 // 减去保留块及BL1大小
	CMP	R1, #16 // 代码不足8k,直接BL1处拷贝
	BLS	ParameterOK // 代码少于16个block跳转	
	SUB	R0, R1 // 再减去代码的大小,代码的block位置

// 用IROM Movi拷贝函数,仅适用于IROM启动,卡访问时钟25M	
ParameterOK:
	LDR	R4, =CopyMovitoMem
	LDR	R4, [R4]
	MOV	LR, PC // 准备函数的返回地址
	BX	R4
	MOVS	R0, R0 // 返回值确定函数成功还是失败
MMC_SD_Boot_Loop:			
	BEQ	MMC_SD_Boot_Loop // 返回0说明拷贝失败
				
AfterCopy:	
	LDMFD	SP!, {PC} // 函数返回			


				

4、s3c2416.S —运行时第一个载入的文件



// Clock setting(External Crystal 12M):
// MPLLCLK = 533M, EPLLCLK = 96M
// ARMCLK = 533M, HCLK = 133M
// DDRCLK = 266M, SSMCCLK = 66M, PCLK = 66M
// HSMMC0, HSMMC1 = 24M

// Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs
#define	Mode_USR	0x10
#define	Mode_FIQ	0x11
#define	Mode_IRQ	0x12
#define	Mode_SVC	0x13
#define	Mode_ABT	0x17
#define	Mode_UND	0x1B
#define	Mode_SYS	0x1F
// when I bit is set, IRQ is disabled
#define	I_Bit	0x80 
// when F bit is set, FIQ is disabled
#define	F_Bit	0x40            

// Stack Configuration
#define	UND_Stack_Size	0x00000020
#define	SVC_Stack_Size	0x00000020
#define	ABT_Stack_Size	0x00000020
#define	FIQ_Stack_Size	0x00000020
#define	IRQ_Stack_Size	0x00040000
#define	USR_Stack_Size	0x00200000
#define	ISR_Stack_Size	(UND_Stack_Size + SVC_Stack_Size + \
					ABT_Stack_Size + FIQ_Stack_Size + \
					IRQ_Stack_Size)
	.section .stack, "aw", %nobits
	.align	3
	.globl	__StackTop
	.globl	__StackLimit
__StackLimit:
	.space	(USR_Stack_Size+ISR_Stack_Size)
__StackTop:

// Heap Configuration
#define	Heap_Size	0x00400000
	.section .heap, "aw", %nobits
	.align	3
	.globl	__HeapBase
	.globl	__HeapLimit
__HeapBase:
	.space	Heap_Size
__HeapLimit:

// Watchdog Timer Base Address
#define	WT_BASE	0x53000000  

// Interrupt Register Base Address
#define	INT_BASE	0x4A000000
#define	INTMSK1_OFS	0x08
#define	INTSUBMSK_OFS	0x1C
#define	INTMSK2_OFS	0x48

//---------------------- CODE -------------------------------------------
	.text
	.arm
	.align	2
	.globl	_start
_start:
	B	Reset_Handler        
	LDR	PC, Undef_Addr
	LDR	PC, SWI_Addr
	LDR	PC, PAbt_Addr
	LDR	PC, DAbt_Addr
	LDR	PC, Notuse_Addr
	LDR	PC, IRQ_Addr
	LDR	PC, FIQ_Addr
	.word	0x55aa55aa // 0x20位置用来判断代码的运行区域		
	.extern	Undef_Handler
	.extern	SWI_Handler
	.extern	PAbt_Handler
	.extern	DAbt_Handler
	.extern	IRQ_Handler
	.extern	FIQ_Handler				
Reset_Addr: 
	.word	Reset_Handler
Undef_Addr: 
	.word	Undef_Handler
SWI_Addr: 
	.word	SWI_Handler
PAbt_Addr: 
	.word	PAbt_Handler
DAbt_Addr: 
	.word	DAbt_Handler
Notuse_Addr: 
	.word	0           // Reserved Address 
IRQ_Addr: 
	.word	IRQ_SaveContext
FIQ_Addr: 
	.word	FIQ_Handler
IRQ_SaveContext:
// 保存中断上下文,支持中断嵌套				
	SUB	LR, LR, #4 // 计算返回地址
	STMFD SP!, {R0-R12, LR} // 所有寄存器压栈保存
	MRS 	R0, SPSR // 保存中断前的CPSR(即现在的SPSR)
	STMFD	SP!, {R0}

	MSR	CPSR_cxsf, #(Mode_SYS | I_Bit) // 切换到系统模式	
	STMFD	SP!, {LR} // 压栈系统模式LR
				
	LDR 	R0, =IRQ_Handler // 系统模式下进行IRQ代码处理
	MOV	LR, PC // 准备函数的返回地址
	BX	R0 // 调用中断处理函数
			
	LDMFD	SP!, {LR} // 出栈系统模式LR
	MSR	CPSR_cxsf, #(Mode_IRQ | I_Bit) // 切换到IRQ模式					
	LDMFD	SP!, {R0} // 返回中断前的CPSR				
	MSR	SPSR_cxsf, R0
	LDMFD  SP!, {R0-R12, PC}^ // ^表同时从spsr恢复给cpsr
			
	.globl  Reset_Handler
Reset_Handler:
/***********************************************************************/
// 看门狗关闭
	LDR	R0, =WT_BASE 
	LDR	R1, =0
	STR	R1, [R0]		

/***********************************************************************/
// 关闭所有外设中断
	LDR	R0, =INT_BASE
	LDR	R1, =0xFFFFFFFF
	STR	R1, [R0, #INTMSK1_OFS]
	STR	R1, [R0, #INTMSK2_OFS]
	STR	R1, [R0, #INTSUBMSK_OFS]

/***********************************************************************/
// 判断代码是否已加载进RAM
	LDR	R0, =_scode
	ADD	R0, R0, #0x20
	LDR	R0, [R0]
	LDR	R1, =0x55aa55aa
	CMP	R0, R1
	BEQ	SkipLoadCode

/***********************************************************************/
// 系统时钟设置	
	.extern	Clock_Init
	BL	Clock_Init
				
/************************************************************************/
// 外部内存控制设置
	.extern	ERAM_Init
	BL	ERAM_Init ;// 外部RAM初始化
	LDR	SP, =__StackTop

/************************************************************************/
// 拷贝用户代码到RAM
	.extern	CopyCodeToRAM
	BL	CopyCodeToRAM
		
/***********************************************************************/
// 检查是否进入串口下载模式,开机时按住空格键进入串口下载模式
	.extern	DownloadCheck
	BL	DownloadCheck

/************************************************************************/	
SkipLoadCode:
// MMU初始化	
	LDR	SP, =__StackTop
	.extern	MMU_Init 
	BL	MMU_Init	

/*************************************************************************/
// 堆栈初始化
	LDR	R0, =__StackTop

//  Enter Undefined Instruction Mode and set its Stack Pointer
	MSR	CPSR_c, #(Mode_UND | I_Bit | F_Bit)
	MOV	SP, R0
	SUB	R0, R0, #UND_Stack_Size

//  Enter Abort Mode and set its Stack Pointer
	MSR	CPSR_c, #(Mode_ABT | I_Bit | F_Bit)
	MOV	SP, R0
	SUB	R0, R0, #ABT_Stack_Size

//  Enter FIQ Mode and set its Stack Pointer
	MSR	CPSR_c, #(Mode_FIQ | I_Bit | F_Bit)
	MOV	SP, R0
	SUB	R0, R0, #FIQ_Stack_Size

//  Enter IRQ Mode and set its Stack Pointer
	MSR	CPSR_c, #(Mode_IRQ | I_Bit | F_Bit)
	MOV	SP, R0
	SUB	R0, R0, #IRQ_Stack_Size

//  Enter Supervisor Mode and set its Stack Pointer
	MSR	CPSR_c, #(Mode_SVC | I_Bit | F_Bit)
	MOV	SP, R0
	SUB	R0, R0, #SVC_Stack_Size

//  Enter System Mode and set its Stack Pointer
	MSR	CPSR_c, #Mode_SYS
	MOV	SP, R0
	SUB	SL, SP, #USR_Stack_Size

/*************************************************************************/
Clear_bss:
	LDR	R0, =_sbss
	LDR	R1, =_ebss
	MOV	R2, #0
Clear_bss_loop:
	CMP	R0, R1
	BGE	Clear_bss_done
	STR	R2, [R0], #4
	B	Clear_bss_loop
Clear_bss_done:
				
/*************************************************************************/
// 绝对地址跳转到c入口
	.extern  main
	LDR	R0, =main
	BX	R0

5接下来看makefile中的配置文件Config.mk


TEXT_BASE=0x30000000   #--连接重定位地址
export TEXT_BASE

CROSS_COMPILE   = arm-linux-    #编译器的宏定义
export CROSS_COMPILE

DEBUG = n

AS              = $(CROSS_COMPILE)as
LD              = $(CROSS_COMPILE)ld
CC              = $(CROSS_COMPILE)gcc
CPP             = $(CC) -E
AR              = $(CROSS_COMPILE)ar
NM              = $(CROSS_COMPILE)nm
STRIP           = $(CROSS_COMPILE)strip
OBJCOPY         = $(CROSS_COMPILE)objcopy
OBJDUMP         = $(CROSS_COMPILE)objdump
export	AS LD CC CPP AR NM STRIP OBJCOPY OBJDUMP

AFLAGS :=

ARFLAGS := cr

PROJECT := Bootloader   #生成的文件名

SUBDIRS := $(TOPDIR)/System $(TOPDIR)/Driver \    #编译的目标文件
		$(TOPDIR)/Common $(TOPDIR)/Apps \
	
CFLAGS := -Wall -Wstrict-prototypes \
		-march=armv5t -mfloat-abi=soft -mabi=aapcs-linux -marm \
		-ffunction-sections -fdata-sections \
		-I $(TOPDIR)/System  -I $(TOPDIR)/Driver \
		-I $(TOPDIR)/Common  -I $(TOPDIR)/Apps \

ifeq ($(DEBUG), y)
CFLAGS += -g
else
CFLAGS += -Os
endif

OBJCFLAGS := 

PLATFORM_LIBS :=  -L $(TOPDIR)/newlib -lm -lc
PLATFORM_LIBS += -L $(shell dirname `$(CC) $(CFLAGS) -print-libgcc-file-name`) -lgcc

LDSCRIPT = $(TOPDIR)/System/s3c2416.lds
LDFLAGS := --gc-sections --no-enum-size-warning -Bstatic -T $(LDSCRIPT) -Ttext $(TEXT_BASE)

export PROJECT SUBDIRS LDFLAGS AFLAGS CFLAGS ARFLAGS OBJCFLAGS PLATFORM_LIBS
#下面就是编译的方法
%.o: %.S
	@echo "assembling $<..."
	@$(CC) $(AFLAGS) -c -o $@ $<
%.o: %.s
	@echo "assembling $<..."
	@$(CC) $(AFLAGS) -c -o $@ $<
%.o: %.c
	@echo "compiling $<..."
	@$(CC) $(CFLAGS) -c  -o $@ $<
%.o: %.C
	@echo "compiling $<..."
	@$(CC) $(CFLAGS) -c -o $@ $<

6顶层的makefile文件



TOPDIR		:= $(shell pwd)   #得到当前的文件目录
export TOPDIR

include config.mk    #包含上面的配置文件

FOLDERS	:= $(notdir $(SUBDIRS))   #将文件名去掉路径:
#例如:  ./APPS  经过上面的处理之后就剩下apps
LIBS_TEMP	:= $(addsuffix .a, $(addprefix /lib, $(FOLDERS)))  #前面街上/lib ,后缀加上.a 例如、libApps.a

LIBS	:= $(join $(SUBDIRS), $(LIBS_TEMP)) #就是字符串拼接例如:./libApps.a

ALL = $(PROJECT).bin $(PROJECT).dis $(PROJECT).srec   #这个就是咋们的目标文件

.PHONY: all clean depend $(SUBDIRS)  

all: $(ALL)
$(PROJECT).hex: $(PROJECT).elf
	@echo "creating hex file $@ from $<..."
	@$(OBJCOPY) ${OBJCFLAGS} -O ihex $< $@

$(PROJECT).srec: $(PROJECT).elf
	@echo "creating srec file $@ from $<..."
	@$(OBJCOPY) ${OBJCFLAGS} -O srec $< $@

$(PROJECT).bin: $(PROJECT).elf
	@echo "creating bin file $@ from $<..."
	@$(OBJCOPY) ${OBJCFLAGS} -S -O binary $< $@	

$(PROJECT).dis: $(PROJECT).elf
	@echo "creating dis file $@ from $<..."
	@$(OBJDUMP) -d $< > $@

$(PROJECT).elf: depend $(SUBDIRS) $(LDSCRIPT)
	@echo "Linking..."   #生成的全部.a文件全部进行连接
	@$(LD) $(LDFLAGS) --start-group $(LIBS) $(PLATFORM_LIBS) --end-group -Map $(PROJECT).map -o $(PROJECT).elf

depend:
	@echo "Build target $(PROJECT)"
	@for dir in $(SUBDIRS); do $(MAKE) --no-print-directory -C $$dir _depend; done

//对各个文件夹中的文件以此进行编译,并返回到上面all
$(SUBDIRS):
	@$(MAKE) -C $@ all

clean:  //对文件进行删除的伪指令
	rm -f $(PROJECT).elf $(PROJECT).map $(PROJECT).srec $(PROJECT).bin $(PROJECT).dis
	@for dir in $(SUBDIRS); do $(MAKE) -C $$dir clean; done

工程的文件结构如下
在这里插入图片描述
在这里对Systm里面makefile进行解析,其他文件的套路都是一样的

include $(TOPDIR)/config.mk

SOBJS	:= s3c2416.o LowLevelInit.o 
COBJS	:= Coprocessor.o NandBoot.o Exception.o Download.o Retarget.o

SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)   
OBJS	:= $(SOBJS) $(COBJS)
CURDIR	:= $(shell pwd)
FOLDER	:= $(notdir $(CURDIR))
LIB	:= lib$(FOLDER).a

.PHONY: all clean
all: .depend $(LIB)

$(LIB): $(OBJS)  #目标就是连接成libxxx.a文件
	@$(AR) $(ARFLAGS) $@ $(OBJS)  

clean:
	rm -f .depend *.o $(LIB)


#########################################################################

# defines $(obj).depend target
include $(TOPDIR)/rules.mk

sinclude .depend

#########################################################################
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值