zoukankan      html  css  js  c++  java
  • 【MIPS】--- 教你看懂MIPS架构的基本汇编程序(全是干货)

    使用龙芯Ls2k1000系列处理器,遇到内存的问题,真的是百般刁难。要梳理内存初始化流程,然后最麻烦的是龙芯的内存乃代码全是汇编源码,看起来着实有点头疼,被汇编按在地上摩擦了无数回后,也算是对汇编有个基本的认识。接下来用一篇文档教你如何快速入门看懂龙芯MIPS的汇编源码!

    按照国际惯例,先抛问题
    1. 汇编常用指令
    2. MIPS架构处理器的寄存器简析
    3. 汇编语法总结
    4. 基本的编程思想

    问题一:汇编常用指令

    这里我就不一一介绍了,龙芯的GS265_user_Guid中对大多数指令已有了简单的介绍,直接查阅即可。

       


    有人说,汇编早已淘汰,属于计算机历史上侏罗纪时代的古董产物;还有人说,汇编是让你深刻理解计算机处理机制的神兵利器。

    个人感觉,争执这种问题都是瞎扯。对于汇编这种语言,要求自己能看懂即可。简单概括,一次看懂,终身受益。不同处理器无非指令不一样,但是汇编处理的逻辑和方式都一样。因此,各位看官要好好理解本文哦。

    问题二:MIPS架构处理器的寄存器简析

    1. 通用寄存器

    MIPS32架构定义了32个通用寄存器,使用$0、$1……$31表示,都是32位。其中$0一般用做常量0,具体的用法可以参考下图。
    这其中你最常用的应该就是a0-a3, t0-t9, s0-s7,编程中的变量运算等等,都离不开这些寄存器。

     

    2. 特殊寄存器
    MIPS32架构中定义的特殊寄存器有三个:PC(Program Counter程序计数器)、HI(乘除结果高位寄存器)、LO(乘除结果低位寄存器)。进行乘法运算时,HI和LO保存乘法运算的结果,其中HI存储高32位,LO存储低32位;进行除法运算时,HI和LO保存除法运算的结果,其中HI存储余数,LO存储商。

    3. MIPS架构属于小端模式,具体什么是小端,参考之前的一篇文章

    问题三: 汇编语法总结---直接以LS2k代码为例进行实战讲解

    1. 标号1,2,3……,这些标号什么意思,如何理解?
    标号的意思基本可以理解为打个标签,方便汇编代码执行跳转指令。

    2. 标号用途详解

    汇编不同于C,没有那么智能,仅能顺序执行,但代码逻辑必定不能线性执行。我们以循环执行nop空与语句为例进行说明:

    C编程,如下:

     

    汇编编程,如下:

    含义解释如下:

        dli : 取双字常数装载到a3寄存器
        subu: 无符号减,等于于 a3=a3-1
        nop : 空操作,一般用于短延时
        Bgtz: 大于0,则跳转

    通过上述例子,应该能理解这些一大堆标号的意思,其中跳转是有时会看到1b,1f, 1b表示向上跳转至标号为1的代码处执行;1f表示向下跳转至标号为1的代码处执行,一般都是同一个函数内由于代码执行逻辑非线性,才会用这种简单的标号表示。如果类似于高级编程语言那种函数的话,一般会重新封装一个函数来做,这是你看到的标号,就不是简单的数字,有可能就是自己起的名字了。

    问题四: 汇编实战练习
    想实际理解汇编代码,最简单的方式,实战来个程序即可。接下来以我自己写的一个例子进行讲解。当内存控制器中的某个寄存器值为0x68,则执行拉低GPIO的操作。

    1. 问题背景,内存Training是GateLeveling过程中,需要进行8个Byte的PreambleCheck,这个preaam_check_init函数将会被循环执行8次,每次执行会改变的变量是dll_gate寄存器地址。实际测量得dll_gate2寄存器校验出错,因此在开始进行dll_gate2值校验之前,我要拉低一个GPIO作为触发信号,然后进行信号测量。

    2. dll_gate寄存器的地址大致如下:

      

    3.判断0x68寄存器的值,符合条件则跳转的代码如下:

     

    1)  t1含义解释:t1表示得是dll_gate得地址,也就是从0x38, 0x58, 0x78……等

    2)  红框内代码解释:

    line1:   将t1得知放进a0(别问为啥,因为没有为啥), 此时a0表示当前正在校验得dll_gate地址

    line2:   a0 = a0&0xff, 仅保留低2位。因为目标地址是0x78,放置高位垃圾值影响我得判断

    line3:   If a0==0x68, 跳转至inspur_gpio_test这个函数下执行

    4. inspur_gpio_test的程序如下,分为五步解释:

     

    Tips: 明确我们得目的是将GPIO27信号进行拉低拉高,产生跳变,先理解GPIO相关得寄存器如何配置:

     

     接下来进行代码分析(分成了五个小块):

    1)设置GPIO方向寄存器

    1     li t4, 0xbfe10500      //将0xbfe10500这个地址装载到t4寄存器
    2     lb t6, 0x3(t4)         //将0xbfe10500+3这个地址得单Byte值装载到t6
    3     and t6, t6, 0xf7       //t6 = t6&0xf7   (这步就是设置GPIO270为输出模式的操作)
    4     sb t6, 0x3(t4)         //将设置后的t6写入到寄存器中

    Tips:
        问题1: 0x3(t4)这种书写表示什么意思?
        答: 简单可以理解一个地址操作,就是t4地址再便宜0x3
        问题2. and t6, t6, 0xf7为何是清0操作?
       答:根据龙芯手册表述,GPIO方向控制寄存器位阈为[63:0],也就是8个Byte,从低到高,每个bit表示一个GPIO,因此GPIO27应该是0xbfe10500这个起始位置的第27个bit,基本表示如下:

    2)设置GPIO27输出低电平

    1     li t4, 0xbfe10510   //将GPIO电位设置寄存器的基地址放入t4
    2     lb t6, 0x3(t4)      //将0xbfe10510+3的地址的单byte数据放入t6寄存器
    3     and t6, t6, 0xf7    //将GPIO27的bit清0,使得GPIO27输出低
    4     sb t6, 0x3(t4)      //将t6的值保存至对应寄存器中

    3)延时,前面举过例子,这里不做详解

    1     dli a3,0xff         //delay
    2     1:
    3     subu a3, 0x1
    4     nop
    5     bgtz a3, 1b


    4)设置GPIO27输出为高(由于前面已将GPIO电位设置寄存器地址放进t4,且没有修改,这里可直接用)

    1     lb t6, 0x3(t4)     //参考问题三中以延时函数举例的说明
    2     ori t6, t6, 0x08
    3     sb t6, 0x3(t4)

    5)函数执行完毕,跳回到之前的位置继续向下执行

    1     PRINTSTR("
     start inspur GPIO end
    ")
    2     b Inspur                                    //跳转至Inpsur标签位置继续执行

    通过这样的例子,希望能更加清楚的让各位了解汇编代码的执行,不同架构处理器区别仅在于指令不一样。但是汇编的执行流程和逻辑均类似,可以对比学习

    如有其他问题,请直接回复留即可,我看到后会尽快和您交流。

    也欢迎您关注我的个人公众号,一起成长,一起交流。

    如有需要龙芯MIPS架构指令手册文档的,关注我的公众号后,回复"MIPS指令",自动获取。 

  • 相关阅读:
    自动化测试模型介绍
    接口测试
    adb 命令
    测试思路
    软件测试基础
    页面元素定位
    环境搭建
    自动化
    使用python操作mysql数据库
    mysql索引原理
  • 原文地址:https://www.cnblogs.com/szhb-5251/p/13091460.html
Copyright © 2011-2022 走看看