zoukankan      html  css  js  c++  java
  • 自己动手写CPU之第九阶段(7)——MIPS32中的LL、SC指令说明

    将陆续上传新书《自己动手写CPU》,今天是第46篇。



    在MIPS32指令集中有两条特殊的存储载入指令:链接载入指令LL、条件存储指令SC,本次将介绍这两条指令。在兴许将实现这两条指令。


    9.6 链接载入指令ll、条件存储指令sc说明

          在本章前面的部分,笔者花费非常多笔墨介绍了OpenMIPS中除llsc之外的载入、存储指令的实现过程,本节至9.9节将专门介绍链接载入指令ll、条件存储指令sc的实现过程。llsc指令是MIPS32指令集架构中比較特殊的载入存储指令。用来实现信号量机制。

          在多线程系统中,须要RMWRead-Modify-Write)操作序列保证对某个资源的独占性,RMW操作序列的含义是,读取内存某个地址的数据。读取的数据经过改动。然后再保存回内存原地址。这个过程不能有不论什么打搅,因此须要建立一个临界区域(Critical Region),临界区域中完毕的操作通常称为原子操作。原子操作不被打搅。操作系统建立临界区域的方式一般是信号量机制,例如以下。

    waitsemaphore;

    原子操作;

     signalsemaphore;

          semaphore是一个信号量。为1表示信号量使用中,为0表示信号量空暇。进行原子操作前,使用wait函数查询semaphore的值,假设为1,则等待,否则,将其置为1,開始运行原子操作,操作结束后,signal函数将semaphore置为0,这样其他线程就能够运行原子操作了。

          须要注意的是,wait函数的运行也是一个原子操作。是一种“先检測后设置”操作(test-and-set operation),这样的操作一般不希望被外部设备中断,也不希望被其他线程打断。非常多处理器都有专门的指令用来实现“先检測后设置”操作,比方:680x0 CPUx86 CPU等。这也是一种信号量机制。

          MIPS32架构採用特殊的方式实现信号量机制。对于原子操作,MIPS32架构并不保证它一定是原子性的,也就是同意检測和设置在没有原子性保证的情况下执行。但仅仅在它确实原子的执行了的时候才让“设置”生效。MIPS32架构採用链接载入指令ll、条件存储指令sc来实现这样的信号量机制。

          ll指令同一般的载入指令一样,从内存中载入一个字,可是,有一点不同。ll指令还会将处理器内部的一个链接状态位LLbit置为1,表明发生了一个链接载入操作。并将链接载入的地址保存到一个特殊寄存器LLAddr中(这个寄存器在多处理器中有作用,OpenMIPS是单处理器,所以在OpenMIPS实现过程中并没有实现LLAddr寄存器)。

          ll指令运行完成后,会进行一定的操作(如:改动载入得到的数据)。然后运行sc指令,这能够觉得是一个RMW序列。有例如以下两种情况干扰这个RMW序列。受到干扰后。处理器会设置链接状态位LLbit0

    •  在llsc指令之间产生异常。从而进入异常处理例程。或者发生线程切换,导致RMW序列受到干扰。
    •  多处理器的系统中,还有一个CPU改写了RMW序列要操作的内存空间。

          对于OpenMIPS而言,仅仅有第1种情况。

          运行sc指令时。会对从ll指令開始的RMW序列进行检查。推断是否受到干扰,实际就是推断LLbit是否为1,假设没有受到不论什么干扰,LLbit保持为1。那么操作是原子的,sc指令会对ll指令载入数据的地址进行写回操作,并设置一个通用寄存器的值为1,表示成功,反之不进行写回操作。并设置一个通用寄存器的值为0,表示失败。

          llsc指令的格式如图9-28所看到的。

    从图中可知,能够根据指令码对这2条指令进行区分。


    •  当指令中的指令码为6'b110000时。是ll指令,链接载入指令

          指令使用方法为:ll rt, offset(base)

          指令作用为:从内存中指定的载入地址处,读取一个字节。然后符号扩展至32位,保存到地址为rt的通用寄存器中。

    当中载入地址的计算方法例如以下。

          载入地址 = signed_extended(offset) + GPR[base]

          此外。还要设置链接状态位LLbit1

    •  当指令中的指令码为6'b111000时,是sc指令,条件存储指令

          指令使用方法为:sc rt, offset(base)

          指令作用为:假设RMW序列没有受到干扰,也就是LLbit1,那么将地址为rt的通用寄存器的值保存到内存中指定的存储地址处,同一时候设置地址为rt的通用寄存器的值为1,设置LLbit0。假设RMW序列受到了干扰,也就是LLbit0,那么不改动内存,同一时候设置地址为rt的通用寄存器的值为0。当中存储地址的计算方法例如以下。

          存储地址 = signed_extended(offset) + GPR[base]

          以下通过一个样例体会llsc指令的作用,这个样例实现了上面介绍的wait函数。只是此处是使用llsc指令实现的。


    wait:
    ori $1, $0, sem         // sem是信号量的地址,将这个地址赋给寄存器$1
    
    TryAgain:
    ll  $2, 0($1)           // 获取信号量的值,保存到寄存器$2
    bne $2, $0, WaitForSem  // 假设信号量被占用(其值为1),那么转移到地址WaitForSem
                            // 继续等待;假设信号量空暇(其值为0),那么运行以下的指令
    
    nop
    ori $2, $0, 1
    sc  $2, 0($1)           // 假设没有被干扰,那么设置信号量被占用(将1保存到信号
                            // 量中)。同一时候,设置寄存器$2为1,反之,不改动信号量。
                            // 设置寄存器$2为0
    
    beq $2, $0, TryAgain    // 假设寄存器$2为0。表示ll、sc指令没有成功,未获取到
                            // 信号量。回到TryAgain继续尝试
    nop
    
    jr  $31                  // 反之, 表示ll、sc指令成功,获取到信号量,能够进入
                             // “临界区域”了。调用wait函数时,会将返回地址放在
                             // 寄存器$31,所以此处jr $31指令就是回到调用过程。
                             // 进入临界区域


    下一次将改动OpenMIPS以实现LL、SC指令

  • 相关阅读:
    Java中List集合去除重复数据的方法
    ActiveMQ消息中间件Producer和Consumer
    JMS Activemq实战例子demo
    利用正则表达式判断输入内容是否全中文
    纯js的右下角弹窗
    java开源项目
    linux部署jdk-tomcat
    你的主机中的软件中止了一个已建立的连接。
    Centos编译安装 LAMP (apache-2.4.7 + mysql-5.5.35 + php 5.5.8)+ Redis
    在LAMP的生产环境内添加PHP的cURL扩展模块
  • 原文地址:https://www.cnblogs.com/llguanli/p/6879198.html
Copyright © 2011-2022 走看看