栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

ARM base instruction -- ldm

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

ARM base instruction -- ldm

    LDM|STM {type} 基址寄存器{!}, 寄存器列表{^}

    ldm{cond} {!} < register list> {^}

    批量访问内存,内存中批量读取数据到寄存器。从< rn> 对应的内存块中取出数据,写入 < register list>这些寄存器。

    参数

        {cond}表示指定执行条件

    表示内存变化的模式:

        ia(increment after):事后递增方式
        ib(increment before):事先递增方式
        da(decrement after):事后递减方式
        db(decrement before):事先递减方式

    < rn>中保存着内存的地址,

    {!}加上了感叹号,指令执行后,rn的值会更新,等于下一个内存单元地址。

    < register list>表示寄存器列表,指令中寄存器列表和内存单元对应关系为:编号低得寄存器对应内存中得低地址单元,
        
                    编号高的寄存器对应内存中的高地址单元。

    {^}有两个含义:如果< register list>中有pc寄存器,它表示指令执行之后,spsr寄存器的值将自动复制到cpsr寄存器中–这常用于从中断处理函数中返回;

                   如果< register list>中没有pc寄存器,{^}表示操作的是用户模式下的寄存器,而不是当前特权模式的寄存器。
    
    例子示范

        stmia sp!, {r6, lr}            // 以sp为基地址,把后面寄存器的值依次存入sp的顺序地址
        ldmdb sp!, {r6, pc}            // 以sp为基地址,取sp的顺序地址的值放入到后面的寄存器


        //中断返回,"^"表示将spsr的值复制到cpsr
        //于是从irq模式返回被中断的工作模式
        //"!"使得指令执行后,sp=sp+14*4

    ! : 当数据传送完毕之后,将最后的地址写入基址寄存器,否则基址寄存器的内容不改变.
    ^ : 当指令为LDM且寄存器列表中包含R15,选用该后缀时表示除了正常的数据传送之外,还将SPSR复制到CPSR.
        同时,该后缀还表示传入或传出的是用户模式下的寄存器,而不是当前模式下的寄存器.


    ARM指令中多数据传输共有两种:

    LDM:(load  much)多数据加载,将地址上的值加载到寄存器上

    STM:(store much)多数据存储,将寄存器的值存到地址上

    主要用途:现场保护、数据复制、参数传送等,共有8种模式(前面4种用于数据块的传输,后面4种是堆栈操作)如下:

    (1)IA:(Increase After) 每次传送后地址加4,其中的寄存器从左到右执行,    // 例如:STMIA R0,{R1,LR} 先存R1,再存LR

    (2)IB:(Increase Before)每次传送前地址加4,同上

    (3)DA:(Decrease After)每次传送后地址减4,其中的寄存器从右到左执行,    // 例如:STMDA R0,{R1,LR} 先存LR,再存R1

    (4)DB:(Decrease Before)每次传送前地址减4,同上

    (5)FD:  满递减堆栈 (每次传送前地址减4)

    (6)FA:  满递增堆栈 (每次传送后地址减4)

    (7)ED:  空递减堆栈 (每次传送前地址加4)

    (8)EA:  空递增堆栈 (每次传送后地址加4)

    注意:其中在数据块的传输中是STMMDB和LDMIA对应,STMMIA和LDMDB对应

    而在堆栈操作是STMFD和LDMFD对应,STMFA和LDMFA对应

    

    格式:

    LDM{cond}  mode  Rn{!}, reglist{^}

    STM{cond}  mode  Rn{!}, reglist{^}

    其中

     Rn:基址寄存器,装有传送数据的起始地址,Rn不允许为R15;

     !:表示最后的地址写回到Rn中;

     reglist:可包含多于一个寄存器范围,用","隔开,如{R1,R2,R6-R9},寄存器由小到大顺序排列;

     ^:不允许在用户模式和系统模式下运行

    
    数据块的传输-实例:

        Ldr R1,=0x10000000          //传送数据的起始地址0x10000000     

        LDMIB R1!,{R0,R4-R6}      //从左到右加载,相当于 LDR R0,10000004  LDR R4,10000008... ...

        
    

        Ldr R1,=0x10000000          //传送数据的起始地址0x10000000      

        LDMIA R1!,{R0,R4-R6}         //从左到右加载,相当于 LDR R0,10000000  LDR R4,10000004... ...

        


        LDR R1,=0x10000000          //传送数据的起始地址0x10000000        

        LDR R4,=0x10

        LDR R5,=0x20

        LDR R6,=0x30

        STMIB R1,{R4-R6}          //从左到右加载,相当于STR [R4],0x10000004    STR [R5],0x10000008 .....

        

        

        Ldr R1,=0x10000000        //传送数据的起始地址0x10000000  

        LDR R4,=0x10

        LDR R5,=0x20

        LDR R6,=0x30    
        
        STMIA R1!,{R4-R6 }    
        
        


    中断实例(利用STMDB和LDMIA保护现场,然后通过LR寄存器返回)

        1.先设置栈sp,用于后面使用stmdb存储寄存器数据

        2.当产生异常时,便进入中断:

        sub lr, lr, #4                  

         //首先将lr-4,因为arm流水线,lr=当前pc+8,由于pc+4段没有执行,所以lr=(当前pc+8)-4;
        stmdb sp!, { r0-r12,lr }  

        //每次传送前-4,由于递减,所以从右往左存储寄存器

        //所以sp-4=lr,sp-8=r12,... sp-56=r0; 由于!,所以最后的地址写回到sp中,sp=sp-56;
        

        ldr lr, =int_return  //设置返回地址

        ldr pc, =EINT_Handle //进入中断服务函数,如果中途返回就会调用pc=lr,即可执行int_return;

        int_return:
        ldmia sp!, { r0-r12,pc }^  

        //每次传送后+4,所以从左往右加载数据到寄存器

        //所以r0=sp, r1=sp+4,...pc=sp+52;由于!,所以最后地址写回到sp中,sp=sp+56;

        //此时,sp=sp+56就等于最初栈顶值,pc=lr,然后返回到异常发生前的相应位置继续执行。

        //^  ^表示将spsr的值复制到cpsr,因为异常返回后需要恢复异常发生前的工作状态

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/766688.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号