自己动手写CPU之第九阶段(1)——加载存储指令说明1

时间:2021-10-10 09:08:22

将陆续上传新书《自己动手写CPU》,今天是第37篇,我尽量每周四篇

开展晒书评送书活动,在亚马逊、京东、当当三大图书网站上,发表《自己动手写CPU》书评的前十名读者,均可获赠《步步惊芯——软核处理器内部设计分析》一书,大家踊跃参与吧!活动时间:2014-9-11至2014-10-20


      本章将实现MIPS32指令集架构中定义的加载存储指令,分两步:首先实现除ll、sc指令外的一般加载存储指令,其次实现比较特殊的加载存储指令ll、sc。

      读者可以将本章内容分为五个部分理解阅读:(1)9.1至9.3节介绍了一般加载存储指令的实现;(2)为了验证加载存储指令是否实现正确,在9.4节修改了我们之前一直用来做测试的SOPC,为其添加了数据RAM;(3)9.5节给出了针对一般加载存储指令的测试程序,通过ModelSim仿真验证指令是否实现正确;(4)9.6至9.9节介绍了特殊加载存储指令ll、sc的实现;(3)9.10至9.12节探讨了由于加载指令引起的load相关问题,给出了OpenMIPS的解决方法,最后验证了解决效果。

9.1 加载存储指令说明

      MIPS32指令集架构中定义的加载存储指令共有14条,如下。

  •  8条加载指令:lb、lbu、lh、lhu、ll、lw、lwl、lwr
  •  6条存储指令:sb、sc、sh、sw、swl、swr

      对ll、sc指令的说明将放在9.6节,本节介绍其余的12条指令,在本书中也称为一般加载存储指令。其中,由于lwl、lwr、swl、swl这4条指令的作用不太容易理解,所以在9.1.4、9.1.5节专题介绍。

9.1.1 加载指令lb、lbu、lh、lhu、lw说明

      加载指令lb、lbu、lh、lhu、lw的格式如图9-1所示。

自己动手写CPU之第九阶段(1)——加载存储指令说明1

      从图9-1可知,这5条加载指令可以根据指令中26-31bit的指令码加以区分,另外,加载指令的0-15bit是offset、21-15bit是base,加载地址的计算方法如下,先将16位的offset符号扩展至32位,然后与地址为base的通用寄存器的值相加,即可得到加载地址。

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

      下面分别介绍各个加载指令的作用。

  •  当指令中的指令码为6'b100000时,是lb指令,字节加载指令

      指令用法为:lb rt, offset(base)

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

  •  当指令中的指令码为6'b100100时,是lbu指令,无符号字节加载指令

      指令用法为:lbu rt, offset(base)

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

  •  当指令中的指令码为6'b100001时,是lh指令,半字加载指令

      指令用法为:lh rt, offset(base)

      指令作用为:从内存中指定的加载地址处,读取一个半字,然后符号扩展至32位,保存到地址为rt的通用寄存器中。该指令有地址对齐要求,要求加载地址的最低位为0。

  •  当指令中的指令码为6'b100101时,是lhu指令,无符号半字加载指令

      指令用法为:lhu rt, offset(base)

      指令作用为:从内存中指定的加载地址处,读取一个半字,然后无符号扩展至32位,保存到地址为rt的通用寄存器中。该指令有地址对齐要求,要求加载地址的最低位为0。

  •  当指令中的指令码为6'b100011时,是lw指令,字加载指令

      指令用法为:lw rt, offset(base)

      指令作用为:从内存中指定的加载地址处,读取一个字,保存到地址为rt的通用寄存器中。该指令有地址对齐要求,要求加载地址的最低两位为00。

9.1.2 存储指令sb、sh、sw说明

      存储指令sb、sh、sw的格式如图9-2所示。

自己动手写CPU之第九阶段(1)——加载存储指令说明1

      从图9-2可知,这3条存储指令可以根据指令中26-31bit的指令码加以区分,另外,存储指令的0-15bit是offset、21-15bit是base,存储地址的计算方法如下,先将16位的offset符号扩展至32位,然后与地址为base的通用寄存器的值相加,即可得到存储地址。

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

      下面分别介绍各个存储指令的作用。

  •  当指令中的指令码为6'b101000时,是sb指令,字节存储指令

      指令用法为:sb rt, offset(base)

      指令作用为:将地址为rt的通用寄存器的最低字节存储到内存中的指定地址。

  •  当指令中的指令码为6'b101001时,是sh指令,半字存储指令

      指令用法为:sh rt, offset(base)

      指令作用为:将地址为rt的通用寄存器的最低两个字节存储到内存中的指定地址。该指令有地址对齐要求,要求计算出来的存储地址的最低位为0。

  •  当指令中的指令码为6'b101011时,是sw指令,字存储指令

      指令用法为:sw rt, offset(base)

      指令作用为:将地址为rt的通用寄存器的值存储到内存中的指定地址。该指令有地址对齐要求,要求计算出来的存储地址的最低两位为00。

9.1.3 加载存储指令用法示例

      OpenMIPS处理器是按照字节寻址,并且是大端模式,在这种模式下,数据的高位保存在存储器的低地址中,而数据的低位保存在存储器的高地址中。比如:使用指令sb在0x50处存储0x81,存储器中实际存储效果如图9-3所示。

自己动手写CPU之第九阶段(1)——加载存储指令说明1

      使用指令sh在0x54处存储0x8281,存储器中实际存储效果如图9-4所示。

自己动手写CPU之第九阶段(1)——加载存储指令说明1

      使用指令sw在0x58处存储0x84838281,存储器中实际存储效果如图9-5所示。

自己动手写CPU之第九阶段(1)——加载存储指令说明1

      此时使用加载指令会有如下效果。

      (1)使用指令lbu从0x58处加载一个字节,读出的字节就是0x84,经无符号扩展至32位是0x00000084。

      (2)使用指令lb从0x58处加载一个字节,读出的字节就是0x84,经符号扩展至32位是0xffffff84。

      (3)使用指令lhu从0x58处加载一个半字,读出的半字就是0x8483,经无符号扩展至32位是0x00008483。

      (4)使用指令lh从0x58处加载一个半字,读出的半字就是0x8483,经符号扩展至32位是0xffff8483。

      (5)使用指令lh从0x59处加载一个半字,不满足地址对齐要求,会出现异常。

      (6)使用指令lhu从0x5a处加载一个半字,读出的半字就是0x8281,经无符号扩展至32位是0x00008281。

      (7)使用指令lh从0x5a处加载一个半字,读出的半字就是0x8281,经符号扩展至32位是0xffff8281。

      (8)使用指令lw从0x58处加载一个字,读出的字就是0x84838281。



还有四条加载存储指令lwl、lwr、swl、swl,由于这4条指令的作用不太容易理解,将在下一次专题介绍。