(四)内存控制器与代码重定位

S3C2440访问SROM或寄存器
举例:
ldr r0,#100
ldr r1,[r0]

上面2条指令要求CPU将地址为100的数据内容取出,放入R1寄存器
而CPU会将地址100传给内存控制器,要求它去确定位置。

S3C2440对外引出27条地址线,8条片选线(对应8个BANK,每个BANK最大128MB)

S3C2440的内存控制器得到CPU传入的地址后,做了什么:
(1)根据地址范围,判断是哪一个BANKx。再使能对应的nGCSx片选信号。
(2)确定是哪个BANKx后,再由27条地址线决定偏移地址(128M范围),此时,对应BANKx上的数据就通过DATA总线送到了CPU上。

S3C2440访问SDRAM

MINI2440的BANK6接的是2片32MB的外部SDRAM,总共64MB,具体查看原理图。
在这里插入图片描述
(1)CPU发出的片选信号nSCS0(它与nGCS6是同一引脚的两个功能)有效,它选中SDRAM
(2)SDRAM中4个L-Bank(Logical Bank),需要两条地址线做片选;原理图中标明了ADDR24、ADDR25
(3)CPU使能行地址信号(nSRAS),同时输出行地址,进行行寻址;
(4)CPU使能列地址信号(nSCAS),同时输出列地址,进行列寻址;

根据SDRAM芯片的列地址线数目设置CPU相关寄存器后,

CPU就会从32为的地址自动分出L-Bank选择信号、行地址信号、列地址信号,先后发送出来。

(5)找到存储单元后,被选中的芯片就要进行数据输出。而两块16位宽的SDRAM并联组成32位宽的空间。

相关寄存器

BANK0~5只需要设置BWCON(总线位宽控制)和BANKCONx(控制);
BANK6、BANK7外接SDRAM时,还要额外设置REFRESH(刷新控制)、BANKSIZE(大小控制)、MRSRB6(BANK6控制模式)、MRSRB7

将程序拷贝到SDRAM(重定位)
  • 在start.S中,使用汇编指令,配置SDRAM相关寄存器
  • 配置C程序运行环境,调用C函数,将存储区start到end直接的内容全部拷贝到SDRAM中
  • 使用绝对跳转指令,将pc指针指向SDRAM中的main函数,开始执行
/* main.c */
void copy2sdram(void)
{
	/* 要从lds文件中获得 __code_start, __bss_start
	 * 然后从0地址把数据复制到__code_start
	 */

	extern int __code_start, __bss_start;

	volatile unsigned int *dest = (volatile unsigned int *)&__code_start;
	volatile unsigned int *end = (volatile unsigned int *)&__bss_start;
	volatile unsigned int *src = (volatile unsigned int *)0;

	while (dest < end)
	{
		*dest++ = *src++;
	}
}


void clean_bss(void)
{
	/* 要从lds文件中获得 __bss_start, _end
	 */
	extern int _end, __bss_start;

	volatile unsigned int *start = (volatile unsigned int *)&__bss_start;
	volatile unsigned int *end = (volatile unsigned int *)&_end;


	while (start <= end)
	{
		*start++ = 0;
	}
}
//
//
//
/* 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段整个程序 */
	mov r0, #0
	ldr r1, =_start 	    /* 第1条指令运行时的地址 */
	ldr r2, =__bss_start    /* bss段的起始地址 */
	sub r2, r2, r1

	bl copy2sdram  /* src, dest, len */

	/* 清除BSS段 */
	ldr r0, =__bss_start
	ldr r1, =_end

	bl clean_bss  /* start, end */

	//bl main  /* 使用BL命令相对跳转, 程序仍然在NOR/sram执行 */
	ldr pc, =main  /* 绝对跳转, 跳到SDRAM */

halt:
	b halt

在上面的汇编文件中,调用C函数copy2sdram之前,将3个参数_start、__bss_start、(_start-__bss_start)分别给了R0、R1、R2,运行C程序时,参数就从寄存器中取出。

变量_start、__bss_start、_end均来自链接脚本文件.lds中的定义

如果C程序中想使用链接脚本中的变量值该怎么办?

链接脚本

链接脚本应该怎么写

SECTIONS
{
	. = 0x30000000;
	//当前运行地址为0x30000000
	__code_start = .;
	//定义一个符号变量,值为当前地址
	. = ALIGN(4);
	//4字节对齐
	.text      :
	{
	  *(.text)
	}

	. = ALIGN(4);
	.rodata : { *(.rodata) }

	. = ALIGN(4);
	.data : { *(.data) }

	. = ALIGN(4);
	__bss_start = .;
	.bss : { *(.bss) *(.COMMON) }
	_end = .;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值