ARM笔记: MMU单元控制器

发布者:快乐心跳最新更新时间:2017-11-17 来源: eefocus关键字:ARM笔记  MMU  单元控制器 手机看文章 扫描二维码
随时随地手机看文章

.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




#define WTCON    (*(volatile unsigned long *)0x53000000)


#define MEM_CTL_BASE    0X48000000



void disable_watch_dog(void)
{
    WTCON=0;    //关闭WATCHDOG,WATCHDOG寄存器设为0
}


void memsetup(void)
{
   
    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];
    }
}


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)       
#define MMU_BUFFERABLE    (1<<2)       
#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;

   
    virtuladdr=0;
    physicaladdr=0;
    *(mmu_tlb_base+(virtuladdr>>20))=(physicaladdr&0xfff00000)|MMU_SECDESC_WB;

   
    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)
{
    unsigned long ttb=0x30000000;
__asm__(
    "mov    r0,#0\n"
    "mcr    p15,0,r0,c7,c7,0\n"    //使无效ICches和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"   
   
    //对控制寄存器,先读出其值,在这基础上修改位,然后在写入
    "mrc    p15,0,r0,c1,c0,0\n"    //读出控制就能器的值
   
   

    //先清除不需要的位,往下若需要则重新设置
   
    "bic    r0,r0,#0x3000\n"    //.RVI ..RS B... .CAM
    "bic    r0,r0,#0x0300\n"    //..11 ..... .... ....清除V.I位
    "bic    r0,r0,#0x0087\n"    //.... .... 1... .111清除B/C/A/M

    //设置需要的位
    "orr    r0,r0,#0x0002\n"    //开启对其检查
    "orr    r0,r0,#0x0004\n"    //开启DCaches
    "orr    r0,r0,#0x1000\n"    //开启ICaches
    "orr    r0,r0,#0x0001\n"    //使能MMU

    "mcr    p15,0,r0,c1,c0,0\n"    //将修改的值写入控制寄存器
    :    //无输出
    :"r"(ttb) );
}



#define GPFCON    (*(volatile unsigned long *)0xa0000050)
#define GPFDAT    (*(volatile unsigned long *)0xa0000054)

#define GPF4_OUT    (1<<(2*4))
#define GPF5_OUT    (1<<(2*5))
#define GPF6_OUT    (1<<(2*6))


static inline void wait(volatile unsigned long dly)
{
    for(;dly>0;dly--);
}
int main(void)
{
    unsigned long i=0;
    GPFCON=GPF4_OUT|GPF5_OUT|GPF6_OUT;
   
    while(1)
    {
        wait(30000);
        GPFDAT=(~(i<<4));
        if(++i==8)
            i=0;
    }
    return 0;
}
mmu.lds:
SECTIONS{
    firtst 0x00000000 : { head.o init.o}
    second 0xb0004000 : AT(2048) { leds.o }
}
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

关键字:ARM笔记  MMU  单元控制器 引用地址:ARM笔记: MMU单元控制器

上一篇:ARM笔记: NAND Flash程序
下一篇:ARM筆記:定时器中断的应用

推荐阅读最新更新时间:2024-03-16 15:45

[ARM笔记]设备IO端口和IO内存的访问
设备通常会提供一组寄存器来用于控制设备、读写设备和获取设备状态,即控制寄存器、数据寄存器和状态寄存器。这些寄存器可能位于IO空间,也可能位于内存空间。当位于IO空间时,通常被称为IO端口,位于内存空间时,对应的内存空间成为IO内存。 1. Linux IO端口和IO内存访问接口 1.1 IO端口 在Linux设备驱动中,应使用Linux内核提供的函数来访问定位于IO空间的端口,这些函数包括如下几种: (1)读写字节端口(8位宽) unsigned inb(unsigned port); void outb(unsigned char byte , unsigned port); (2)读写字端口(16位宽) unsigned
[单片机]
uboot-2011.12移植到S3C2440(三序)——MMU Cache/TLB/etc on/off functions
R1_I EQU (1 12) ;//Cache分开时,1 使能指令Cache,0 禁止使能Cache R1_C EQU (1 2) ;//禁止/使能数据Cache或整个Cache,1使能 不含Cache返回0,不能禁止Cache返回1 R1_A EQU (1 1) ;//是否支持内存访问时地址对齐检查系统,1使能 R1_M EQU (1) ;//禁止/使能MMU 1使能 R1_iA EQU (1 31) R1_nF EQU (1 30) ;void MMU_EnableICache(void) EXPORT MMU_EnableICache MMU_EnableICache mr
[单片机]
ARM笔记: GPIO口LED程序
leds.bin:crt0.S leds.c arm-linux-gcc -g -c -o crt0.o crt0.S arm-linux-gcc -g -c -o leds.o leds.c arm-linux-ld -Ttext 0x00000000 -g crt0.o leds.o -o leds_elf arm-linux-objcopy -O binary -S leds_elf leds.bin arm-linux-objdump -D -m arm leds_elf leds.dis clean: rm -f leds.dis leds.bin leds_elf *.o .text .gl
[单片机]
armMMU详解(虚拟地址)
一、MMU的产生 许多年以前,当人们还在使用DOS或是更古老的操作系统的时候,计算机的内存还非常小,一般都是以K为单位进行计算,相应的,当时的程序规模也不大,所以内存容量虽然小,但还是可以容纳当时的程序。但随着图形界面的兴起还用用户需求的不断增大,应用程序的规模也随之膨胀起来,终于一个难题出现在程序员的面前,那就是应用程序太大以至于内存容纳不下该程序,通常解决的办法是把程序分割成许多称为覆盖块(overlay)的片段。覆盖块0首先运行,结束时他将调用另一个覆盖块。虽然覆盖块的交换是由OS完成的,但是必须先由程序员把程序先进行分割,这是一个费时费力的工作,而且相当枯燥。人们必须找到更好的办法从根本上解决这个问题。不久人们找到了一个办
[单片机]
<font color='red'>arm</font>的<font color='red'>MMU</font>详解(虚拟地址)
ARM7学习笔记之开始
今天看到百度博客 http://hi.baidu.com/ch314156/blog/category/lpc2000 arm7 ��� ѧϰ�ʼ�/index/1 里关于学习ARM的记录,我觉得这种电子笔记的方法挺好的,再加上本人最近正在学习ARM,电子笔记方便自己查询。 我是用KEIL4 for ARM写的,直接用配套开发板用JLINK仿真测试,在开始的工程中需加入cofig.c文件。 具体配置图如下:
[单片机]
<font color='red'>ARM</font>7学习<font color='red'>笔记</font>之开始
ARM 汇编学习笔记
1.LDR和MOV的不同 ARM是RISC结构,数据从内存到CPU之间的移动只能通过L/S指令来完成,也就是ldr/str指令。 比如想把数据从内存中某处读取到寄存器中,只能使用ldr 比如: ldr r0, 0x12345678 就是把0x12345678这个地址中的值存放到r0中。 而mov不能干这个活,mov只能在寄存器之间移动数据,或者把立即数移动到寄存器中,这个和x86这种CISC架构的芯片区别最大的地方。 x86中没有ldr这种指令,因为x86的mov指令可以将数据从内存中移动到寄存器中。 2.汇编的位操作技巧 ldr r0,=rGPBCON;//设置GPB5~GPB8输出端口 ldr r1,=0x55
[单片机]
ARM裸机开发笔记4ARM寻址方式
所谓寻址方式就是处理器根据指令中给出的地址信息来寻找物理地址的方式。 立即(数)寻址 操作数本身就在指令中给出,只要取出指令也就取到了操作数。这个操作数被称为立即数,对应的寻址方式为立即寻址 ADD R0,R0,#1 ;R0 -R0+1 ADD R0,R0,#ox3f ;R0 -R0+0x3f 以上指令中,第二个源操作数即为立即数。立即数以#开头 寄存器寻址 利用寄存器中的数值作为操作数,这种寻址方式是各类微处理器经常采用的一种方式,也是一种执行效率较高的寻址方式。 ADD R0,R1,R2 :R0 -R1+R2 该指令将寄存器R1和R2的内容相加放到R0中。
[单片机]
MMU的理解
MMU,全称Memory Manage Unit, 中文名 存储器管理单元。 许多年以前,当人们还在使用DOS或是更古老的操作系统的时候,计算机的内存还非常小,一般都是以K为单位进行计算,相应的,当时的程序规模也不大,所以 内存容量虽然小,但还是可以容纳当时的程序。但随着图形界面的兴起还用用户需求的不断增大,应用程序的规模也随之膨胀起来,终于一个难题出现在程序员的面 前,那就是应用程序太大以至于内存容纳不下该程序,通常解决的办法是把程序分割成许多称为覆盖块(overlay)的片段。覆盖块0首先运行,结束时他将调用另一个覆盖块。虽然覆盖块的交换是由OS完成的,但是必须先由程序员把程序先进行分割,这是一个费时费力的工作,而且相当枯燥
[单片机]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved