我是
靠谱客的博主
温婉缘分,最近开发中收集的这篇文章主要介绍
MMU 裸机程序,觉得挺不错的,现在分享给大家,希望可以做个参考。
概述
来自:http://blog.sina.com.cn/s/blog_49d9a0820100e37l.html
一级页表
head.S//
@*************************************************************************
@ File:head.S
@ 功能:设置SDRAM,将第二部分代码复制到SDRAM,设置页表,启动MMU,
@
然后跳到SDRAM继续执行
@*************************************************************************
.text
.global _start
_start:
ldr sp,=4096 @ 设置栈指针,以下都是C函数,调用前需要设好栈
bldisable_watch_dog @ 关闭WATCHDOG,否则CPU会不断重启
blmemsetup @ 设置存储控制器以使用SDRAM
blcopy_2th_to_sdram @ 将第二部分代码复制到SDRAM
blcreate_page_table @ 设置页表
blmmu_init @ 启动MMU
ldr sp,=0xB4000000 @ 重设栈指针,指向SDRAM顶端(使用虚拟地址)
ldr pc,=0xB0004000 @ 跳到SDRAM中继续执行第二部分代码
halt_loop:
b halt_loop
//init.c//
#defineWTCON (*(volatile unsigned long *)0x53000000)
#defineMEM_CTL_BASE 0x48000000
void disable_watch_dog(void)
{
WTCON = 0;// 关闭WATCHDOG很简单,往这个寄存器写0即可
}
void memsetup(void)
{
unsignedlong const mem_cfg_val[]={0x22011110, //BWSCON
0x00000700, //BANKCON0
0x00000700, //BANKCON1
0x00000700, //BANKCON2
0x00000700, //BANKCON3
0x00000700, //BANKCON4
0x00000700, //BANKCON5
0x00018005, //BANKCON6
0x00018005, //BANKCON7
0x008C07A3, //REFRESH
0x000000B1, //BANKSIZE
0x00000030, //MRSRB6
0x00000030, //MRSRB7
};
int i = 0;
volatileunsigned long *p = (volatile unsigned long *)MEM_CTL_BASE;
for(; i< 13; i++)
p[i] = mem_cfg_val[i];
}
void copy_2th_to_sdram(void)
{
unsigned int*pdwSrc = (unsigned int *)2048;
unsigned int*pdwDest = (unsigned int *)0x30004000;
while(pdwSrc < (unsigned int *)4096)
{
*pdwDest = *pdwSrc;
pdwDest++;
pdwSrc++;
}
}
void create_page_table(void)
{
#defineMMU_FULL_ACCESS (3 <<10)
#defineMMU_DOMAIN (0 <<5)
#defineMMU_SPECIAL (1 <<4)
#defineMMU_CACHEABLE (1 <<3)
#defineMMU_BUFFERABLE (1 <<2)
#defineMMU_SECTION (2)
#defineMMU_SECDESC (MMU_FULL_ACCESS | MMU_DOMAIN | MMU_SPECIAL |
MMU_SECTION)
#defineMMU_SECDESC_WB (MMU_FULL_ACCESS | MMU_DOMAIN | MMU_SPECIAL |
MMU_CACHEABLE | MMU_BUFFERABLE | MMU_SECTION)
#defineMMU_SECTION_SIZE 0x00100000
unsignedlong virtuladdr, physicaladdr;
unsignedlong *mmu_tlb_base = (unsigned long *)0x30000000;
virtuladdr =0;
physicaladdr= 0;
*(mmu_tlb_base + (virtuladdr >> 20))= (physicaladdr & 0xFFF00000) |
MMU_SECDESC_WB;
//从SDRAM的开始存放页表,将虚拟地址0对应的物理地址0的页表创建好,当我们以后对这个虚拟地址操作的时候,MMU可以为我们在这个页表也找到相应的物理地址。
virtuladdr =0xA0000000;
physicaladdr= 0x56000000;
*(mmu_tlb_base + (virtuladdr >> 20))= (physicaladdr & 0xFFF00000) |
MMU_SECDESC;
virtuladdr =0xB0000000;
physicaladdr= 0x30000000;
while(virtuladdr < 0xB4000000)
{创建好了页表以后
*(mmu_tlb_base + (virtuladdr >> 20))= (physicaladdr & 0xFFF00000) |
MMU_SECDESC_WB;
virtuladdr += 0x100000;
physicaladdr += 0x100000;
}
}
void mmu_init(void)
{
unsignedlong ttb = 0x30000000;
__asm__(
"mov r0,#0n"
"mcr p15, 0,r0, c7, c7,0n"
"mcr p15, 0,r0, c7, c10, 4n"
"mcr p15, 0,r0, c8, c7,0n"
"mov r4,%0n"
"mcr p15, 0,r4, c2, c0,0n"
"mvn r0,#0n"
"mcr p15, 0,r0, c3, c0,0n"
"mrc p15, 0,r0, c1, c0,0n"
"bic r0, r0,#0x3000n"
"bic r0, r0,#0x0300n"
"bic r0, r0,#0x0087n"
"orr r0, r0,#0x0002n"
"orr r0, r0,#0x0004n"
"orr r0, r0,#0x1000n"
"orr r0, r0,#0x0001n"
"mcr p15, 0,r0, c1, c0,0n"
:
: "r" (ttb));
}
/mmu.lds/
SECTIONS
{
first0x00000000 : {head.o init.o} #first
second0xB0004000 : AT(2048) {leds.o}#指定这个段在编译出来的映像文件中的地址-加载地址。如果不使用这个选项,并且不指定0xB0004000,则加载地址等于运行地址,否则指定了 0xB0004000是不相同的。通过这个选项。可以控制各段分别保存输出文件中不同的位置。这里指定leds.o保存在映像文件的2048这个起始地址,而0xB0000000这个是段重定位地址,也称为运行地址,它是个虚拟地址。
}
///Makefile/
objs := head.o init.o leds.o
mmu.bin : $(objs)
arm-softfloat-linux-gnu-ld -Tmmu.lds -o mmu_elf $^
arm-softfloat-linux-gnu-objcopy -O binary -S mmu_elf $@
arm-softfloat-linux-gnu-objdump -D -m arm mmu_elf >mmu.dis
%.o:%.c
arm-softfloat-linux-gnu-gcc -Wall -O2 -c -o $@$<
%.o:%.S
arm-softfloat-linux-gnu-gcc -Wall -O2 -c -o $@$<
clean:
rm -fmmu.bin mmu_elf mmu.dis*.o
leds.c///
#defineGPFCON (*(volatile unsigned long*)0xA0000050) // 物理地址0x56000050
#defineGPFDAT (*(volatile unsigned long*)0xA0000054) // 物理地址0x56000054
#defineGPF4_out (1<<(4*2))
#defineGPF5_out (1<<(5*2))
#defineGPF6_out (1<<(6*2))
#defineGPF7_out (1<<(7*2))
static inline void wait(unsigned long dly)
{
for(; dly> 0; dly--);
}
int main(void)
{
unsignedlong i = 0;
//将LED1-4对应的GPF4/5/6/7四个引脚设为输出
GPBCON =GPF4_out|GPF5_out|GPF6_out|GPF7_out;
while(1){
wait(300000);
GPBDAT =(~(i<<4)); // 根据i的值,点亮LED1-4
if(++i == 16)
i = 0;
}
return0;
}
最后
以上就是温婉缘分为你收集整理的MMU 裸机程序的全部内容,希望文章能够帮你解决MMU 裸机程序所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复