美文网首页
arm子程序

arm子程序

作者: 欧阳_z | 来源:发表于2020-08-10 23:39 被阅读0次

    (1)格式

    .global 来声明子程序全局可见;
    4 个参数可用R0~R3传参,从第 5 个参数开始用传递;

    返回值用R0传递;

    跳转到子程序时,会自动把返回地址存到LR寄存器,所以子程序结束时,需要手动跳转回LR保存的地方。

    (2)例子

    两个数相加

        .global my_add
    my_add:
        add r0, r0, r1
        bx lr // 表示返回; 也可以用 mov pc, lr
    

    打印一个字符到串口,(假设已经初始化过串口了,这里的寄存器地址和偏移量都是随便写的数字):

        .global write_char
    write_char:
        ldr r1, =(0x10000000 + 0x100) // r1=整个寄存器的起始地址+UART偏移量
        strb r0, [r1, #0x10] // r1加上某个偏移量,为UART写寄存器 把r0(第一个参数)写入该寄存器
    write_char_loop:
        ldr r0, [r1, #0x20] // 读取UART写完之后的标志
        and r0, r0, #0x30 // r0 = r0 与 某值
        cmp r0, #0x30 // 比较与的结果是不是 某值
        bne write_char_loop // 不是,表示串口还没写完,就用循环语句等一下
        bx lr // 是,表示写完成,就返回;
    

    不过这个子程序没有保存寄存器上下文,如果想让这个函数可以插入到代码的任意两行之间,需要把寄存器保存到栈中,这样返回之后,之前的寄存器还能用,增加如下两行:

        .global write_char
    write_char:
        stmfd   sp!, {r0-r1} // 入栈
        ldr r1, =(0x10000000 + 0x100)
        strb r0, [r1, #0x10]
    write_char_loop:
        ldr r0, [r1, #0x20]
        and r0, r0, #0x30
        cmp r0, #0x30
        bne write_char_loop 
        ldmfd   sp!, {r0-r1} // 出栈
        bx lr
    

    还有个小问题,每次使用都得先加一个mov指令,不能一行写完,所以增加如下宏,顺便把\r\n也加上:

    .macro PUT_CHAR c:
        stmfd   sp!, {r0-r1,lr} // 入栈
        ldr r0, =\c
        bl write_char
        mov r0,#0xD
        bl write_char
        mov r0,#0xA
        bl write_char
        ldmfd   sp!, {r0-r1,pc} // 出栈,返回
    .endm
    

    相关文章

      网友评论

          本文标题:arm子程序

          本文链接:https://www.haomeiwen.com/subject/lknsdktx.html