MMU£ºÄÚ´æ¹ÜÀíµ¥Ôª¡£¹¦ÄÜ£º
£¨1£©ÐéÄâµØÖ·---->ÎïÀíµØÖ·µÄÓ³É䣬ʹµÃ¸÷¸ö½ø³ÌÓµÓп´ÆðÀ´Ò»ÑùµÄµØÖ·¿Õ¼ä¡£
£¨2£©¼ì²éÄÚ´æ·ÃÎÊȨÏÞ£¨Ó²¼þ×Ô¼ºÊµÏÖ£©¡£±£»¤¸÷¸ö½ø³ÌËùÓõÄÄÚ´æ²»±»ÆäËü½ø³ÌÆÆ»µ¡£
ÔÚ32λµÄCPUÖУ¬ÐéÄâÄÚ´æµØÖ·Îª0~0xFFFF_FFFF.
Cache:½éÓÚÖ÷´æºÍCPUÖ®¼äµÄ¸ßËÙ»º³å´æ´¢Æ÷¡£
´úÂëÏê½â£º£¨²Î¿¼Î¤¶«É½´ó¸ç´úÂ룩
£¨1£©head.S
@*************************************************************************
@ File£ºhead.S
@ ¹¦ÄÜ£ºÉèÖÃSDRAM£¬½«µÚ¶þ²¿·Ö´úÂë¸´ÖÆµ½SDRAM£¬ÉèÖÃÒ³±í£¬Æô¶¯MMU£¬
@ È»ºóÌøµ½SDRAM¼ÌÐøÖ´ÐÐ
@*************************************************************************
.text
.global _start
_start:
ldr sp, =4096 @ ÉèÖÃÕ»Ö¸Õ룬ÒÔ϶¼ÊÇCº¯Êý£¬µ÷ÓÃǰÐèÒªÉèºÃÕ»
bl disable_watch_dog @ ¹Ø±ÕWATCHDOG£¬·ñÔòCPU»á²»¶ÏÖØÆô
bl memsetup @ ÉèÖô洢¿ØÖÆÆ÷ÒÔʹÓÃSDRAM
bl copy_2th_to_sdram @ ½«µÚ¶þ²¿·Ö´úÂë¸´ÖÆµ½SDRAM
bl create_page_table @ ÉèÖÃÒ³±í
bl mmu_init @ Æô¶¯MMU
ldr sp, =0xB4000000 @ ÖØÉèÕ»Ö¸Õ룬ָÏòSDRAM¶¥¶Ë(ʹÓÃÐéÄâµØÖ·)
ldr pc, =0xB0004000 @ Ìøµ½SDRAMÖмÌÐøÖ´Ðеڶþ²¿·Ö´úÂë
halt_loop:
b halt_loop
(2)init.c
/*
* init.c: ½øÐÐһЩ³õʼ»¯£¬ÔÚSteppingstoneÖÐÔËÐÐ
* ËüºÍhead.SͬÊôµÚÒ»²¿·Ö³ÌÐò£¬´ËʱMMU먦Æô£¬Ê¹ÓÃÎïÀíµØÖ·
*/
/* WATCHDOG¼Ä´æÆ÷ */
#define WTCON (*(volatile unsigned long *)0x53000000)
/* ´æ´¢¿ØÖÆÆ÷µÄ¼Ä´æÆ÷ÆðʼµØÖ· */
#define MEM_CTL_BASE 0x48000000
/*
* ¹Ø±ÕWATCHDOG£¬·ñÔòCPU»á²»¶ÏÖØÆô
*/
void disable_watch_dog(void)
{
WTCON = 0; // ¹Ø±ÕWATCHDOGºÜ¼òµ¥£¬ÍùÕâ¸ö¼Ä´æÆ÷д0¼´¿É
}
/*
* ÉèÖô洢¿ØÖÆÆ÷ÒÔʹÓÃSDRAM
*/
void memsetup(void)
{
/* SDRAM 13¸ö¼Ä´æÆ÷µÄÖµ */
unsigned long 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;
volatile unsigned long *p = (volatile unsigned long *)MEM_CTL_BASE;
for(; i < 13; i++)
p[i] = mem_cfg_val[i];
}
/*
* ½«µÚ¶þ²¿·Ö´úÂë¸´ÖÆµ½SDRAM
*/
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)
{
/*
* ÓÃÓÚ¶ÎÃèÊö·ûµÄһЩºê¶¨Òå
*/
#define MMU_FULL_ACCESS (3 << 10) /* ·ÃÎÊȨÏÞ */
#define MMU_DOMAIN (0 << 5) /* ÊôÓÚÄĸöÓò */
#define MMU_SPECIAL (1 << 4) /* ±ØÐëÊÇ1 */
#define MMU_CACHEABLE (1 << 3) /* cacheable */
#define MMU_BUFFERABLE (1 << 2) /* bufferable */
#define MMU_SECTION (2) /* ±íʾÕâÊǶÎÃèÊö·û */
#define MMU_SECDESC (MMU_FULL_ACCESS | MMU_DOMAIN | MMU_SPECIAL | \
MMU_SECTION)
#define MMU_SECDESC_WB (MMU_FULL_ACCESS | MMU_DOMAIN | MMU_SPECIAL | \
MMU_CACHEABLE | MMU_BUFFERABLE | MMU_SECTION)
#define MMU_SECTION_SIZE 0x00100000
unsigned long virtuladdr, physicaladdr;
unsigned long *mmu_tlb_base = (unsigned long *)0x30000000;
/*
* SteppingstoneµÄÆðʼÎïÀíµØÖ·Îª0£¬µÚÒ»²¿·Ö³ÌÐòµÄÆðʼÔËÐеØÖ·Ò²ÊÇ0£¬
* ΪÁËÔÚ¿ªÆôMMUºóÈÔÄÜÔËÐеÚÒ»²¿·ÖµÄ³ÌÐò£¬
* ½«0¡«1MµÄÐéÄâµØÖ·Ó³É䵽ͬÑùµÄÎïÀíµØÖ·
*/
virtuladdr = 0;
physicaladdr = 0;
*(mmu_tlb_base + (virtuladdr >> 20)) = (physicaladdr & 0xFFF00000) | \
MMU_SECDESC_WB;
/*
* 0x56000000ÊÇGPIO¼Ä´æÆ÷µÄÆðʼÎïÀíµØÖ·£¬
* GPBCONºÍGPBDATÕâÁ½¸ö¼Ä´æÆ÷µÄÎïÀíµØÖ·0x56000010¡¢0x56000014£¬
* ΪÁËÔÚµÚ¶þ²¿·Ö³ÌÐòÖÐÄÜÒÔµØÖ·0xA0000010¡¢0xA0000014À´²Ù×÷GPBCON¡¢GPBDAT£¬
* °Ñ´Ó0xA0000000¿ªÊ¼µÄ1MÐéÄâµØÖ·¿Õ¼äÓ³Éäµ½´Ó0x56000000¿ªÊ¼µÄ1MÎïÀíµØÖ·¿Õ¼ä
*/
virtuladdr = 0xA0000000;
physicaladdr = 0x56000000;
*(mmu_tlb_base + (virtuladdr >> 20)) = (physicaladdr & 0xFFF00000) | \
MMU_SECDESC;
/*
* SDRAMµÄÎïÀíµØÖ··¶Î§ÊÇ0x30000000¡«0x33FFFFFF£¬
* ½«ÐéÄâµØÖ·0xB0000000¡«0xB3FFFFFFÓ³Éäµ½ÎïÀíµØÖ·0x30000000¡«0x33FFFFFFÉÏ£¬
* ×ܹ²64M£¬Éæ¼°64¸ö¶ÎÃèÊö·û
*/
virtuladdr = 0xB0000000;
physicaladdr = 0x30000000;
while (virtuladdr < 0xB4000000)
{
*(mmu_tlb_base + (virtuladdr >> 20)) = (physicaladdr & 0xFFF00000) | \
MMU_SECDESC_WB;
virtuladdr += 0x100000;
physicaladdr += 0x100000;
}
}
/*
* Æô¶¯MMU
*/
void mmu_init(void)
{
unsigned long ttb = 0x30000000;
__asm__(
"mov r0, #0\n"
"mcr p15, 0, r0, c7, c7, 0\n" /* ʹÎÞЧICachesºÍDCaches */
"mcr p15, 0, r0, c7, c10, 4\n" /* drain write buffer on v4 */
"mcr p15, 0, r0, c8, c7, 0\n" /* ʹÎÞЧָÁî¡¢Êý¾ÝTLB */
"mov r4, %0\n" /* r4 = Ò³±í»ùÖ· */
"mcr p15, 0, r4, c2, c0, 0\n" /* ÉèÖÃÒ³±í»ùÖ·¼Ä´æÆ÷ */
"mvn r0, #0\n"
"mcr p15, 0, r0, c3, c0, 0\n" /* Óò·ÃÎÊ¿ØÖƼĴæÆ÷ÉèΪ0xFFFFFFFF£¬
* ²»½øÐÐȨÏÞ¼ì²é
*/
/*
* ¶ÔÓÚ¿ØÖƼĴæÆ÷£¬ÏȶÁ³öÆäÖµ£¬ÔÚÕâ»ù´¡ÉÏÐ޸ĸÐÐËȤµÄ룬
* È»ºóÔÙдÈë
*/
"mrc p15, 0, r0, c1, c0, 0\n" /* ¶Á³ö¿ØÖƼĴæÆ÷µÄÖµ */
/* ¿ØÖƼĴæÆ÷µÄµÍ16λº¬ÒåΪ£º.RVI ..RS B... .CAM
* R : ±íʾ»»³öCacheÖеÄÌõĿʱʹÓõÄËã·¨£¬
* 0 = Random replacement£»1 = Round robin replacement
* V : ±íʾÒì³£ÏòÁ¿±íËùÔÚµÄλÖã¬
* 0 = Low addresses = 0x00000000£»1 = High addresses = 0xFFFF0000
* I : 0 = ¹Ø±ÕICaches£»1 = ¿ªÆôICaches
* R¡¢S : ÓÃÀ´ÓëÒ³±íÖеÄÃèÊö·ûÒ»ÆðÈ·¶¨ÄÚ´æµÄ·ÃÎÊȨÏÞ
* B : 0 = CPUΪС×Ö½ÚÐò£»1 = CPUΪ´ó×Ö½ÚÐò
* C : 0 = ¹Ø±ÕDCaches£»1 = ¿ªÆôDCaches
* A : 0 = Êý¾Ý·ÃÎÊʱ²»½øÐеØÖ·¶ÔÆë¼ì²é£»1 = Êý¾Ý·ÃÎÊʱ½øÐеØÖ·¶ÔÆë¼ì²é
* M : 0 = ¹Ø±ÕMMU£»1 = ¿ªÆôMMU
*/
/*
* ÏÈÇå³ý²»ÐèÒªµÄ룬ÍùÏÂÈôÐèÒªÔòÖØÐÂÉèÖÃËüÃÇ
*/
/* .RVI ..RS B... .CAM */
"bic r0, r0, #0x3000\n" /* ..11 .... .... .... Çå³ýV¡¢Iλ */
"bic r0, r0, #0x0300\n" /* .... ..11 .... .... Çå³ýR¡¢Sλ */
"bic r0, r0, #0x0087\n" /* .... .... 1... .111 Çå³ýB/C/A/M */
/*
* ÉèÖÃÐèÒªµÄλ
*/
"orr r0, r0, #0x0002\n" /* .... .... .... ..1. ¿ªÆô¶ÔÆë¼ì²é */
"orr r0, r0, #0x0004\n" /* .... .... .... .1.. ¿ªÆôDCaches */
"orr r0, r0, #0x1000\n" /* ...1 .... .... .... ¿ªÆôICaches */
"orr r0, r0, #0x0001\n" /* .... .... .... ...1 ʹÄÜMMU */
"mcr p15, 0, r0, c1, c0, 0\n" /* ½«Ð޸ĵÄֵдÈë¿ØÖÆ¼Ä´æÆ÷ */
: /* ÎÞÊä³ö */
: "r" (ttb) );
}
(3)leds.c
/*
* leds.c: Ñ»·µãÁÁ4¸öLED
* ÊôÓÚµÚ¶þ²¿·Ö³ÌÐò£¬´ËʱMMUÒÑ¿ªÆô£¬Ê¹ÓÃÐéÄâµØÖ·
*/
#define GPFCON (*(volatile unsigned long *)0xA0000010) // ÎïÀíµØÖ·0x56000050
#define GPFDAT (*(volatile unsigned long *)0xA0000014) // ÎïÀíµØÖ·0x56000054
#define GPF0_out (1<<(0*2))
#define GPF1_out (1<<(1*2))
#define GPF2_out (1<<(2*2))
#define GPF3_out (1<<(3*2))
/*
* waitº¯Êý¼ÓÉÏ¡°static inline¡±ÊÇÓÐÔÒòµÄ£¬
* ÕâÑù¿ÉÒÔʹµÃ±àÒëleds.cʱ£¬waitǶÈëmainÖУ¬±àÒë½á¹ûÖÐÖ»ÓÐmainÒ»¸öº¯Êý¡£
* ÓÚÊÇÔÚÁ¬½Óʱ£¬mainº¯ÊýµÄµØÖ·¾ÍÊÇÓÉÁ¬½ÓÎļþÖ¸¶¨µÄÔËÐÐÊ±×°ÔØµØÖ·¡£
* ¶øÁ¬½ÓÎļþmmu.ldsÖУ¬Ö¸¶¨ÁËleds.oµÄÔËÐÐÊ±×°ÔØµØÖ·Îª0xB4004000£¬
* ÕâÑù£¬head.SÖеġ°ldr pc, =0xB4004000¡±¾ÍÊÇÌøÈ¥Ö´ÐÐmainº¯Êý¡£
*/
static inline void wait(unsigned long dly)
{
for(; dly > 0; dly--);
}
int main(void)
{
unsigned long i = 0;
// ½«LED1-4¶ÔÓ¦µÄGPB5/6/7/8ËĸöÒý½ÅÉèΪÊä³ö
GPFCON = GPF0_out|GPF1_out|GPF2_out|GPF3_out;
while(1){
for(i=0;i<4;i++){
GPFDAT = ~(1< wait(30000);
}
}
return 0;
}
(4)mmu.lds
SECTIONS {
firtst 0x00000000 : { head.o init.o }
second 0xB0004000 : AT(2048) { leds.o }
}
(5)Makefile objs := head.o init.o leds.o
mmu.bin : $(objs)
arm-linux-ld -Tmmu.lds -o mmu_elf $^
arm-linux-objcopy -O binary -S mmu_elf $@
arm-linux-objdump -D -m arm mmu_elf > mmu.dis
%.o:%.c
arm-linux-gcc -Wall -O2 -c -o $@ $<
%.o:%.S
arm-linux-gcc -Wall -O2 -c -o $@ $<
clean:
rm -f mmu.bin mmu_elf mmu.dis *.o