将陆续上传新书《自己动手写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的解决方法,最后验证了解决效果。
MIPS32指令集架构中定义的加载存储指令共有14条,如下。
对ll、sc指令的说明将放在9.6节,本节介绍其余的12条指令,在本书中也称为一般加载存储指令。其中,由于lwl、lwr、swl、swl这4条指令的作用不太容易理解,所以在9.1.4、9.1.5节专题介绍。
从图9-1可知,这5条加载指令可以根据指令中26-31bit的指令码加以区分,另外,加载指令的0-15bit是offset、21-15bit是base,加载地址的计算方法如下,先将16位的offset符号扩展至32位,然后与地址为base的通用寄存器的值相加,即可得到加载地址。
加载地址 = signed_extended(offset) + GPR[base]
下面分别介绍各个加载指令的作用。
指令用法为:lb rt, offset(base)
指令作用为:从内存中指定的加载地址处,读取一个字节,然后符号扩展至32位,保存到地址为rt的通用寄存器中。
指令用法为:lbu rt, offset(base)
指令作用为:从内存中指定的加载地址处,读取一个字节,然后无符号扩展至32位,保存到地址为rt的通用寄存器中。
指令用法为:lh rt, offset(base)
指令作用为:从内存中指定的加载地址处,读取一个半字,然后符号扩展至32位,保存到地址为rt的通用寄存器中。该指令有地址对齐要求,要求加载地址的最低位为0。
指令用法为:lhu rt, offset(base)
指令作用为:从内存中指定的加载地址处,读取一个半字,然后无符号扩展至32位,保存到地址为rt的通用寄存器中。该指令有地址对齐要求,要求加载地址的最低位为0。
指令用法为:lw rt, offset(base)
指令作用为:从内存中指定的加载地址处,读取一个字,保存到地址为rt的通用寄存器中。该指令有地址对齐要求,要求加载地址的最低两位为00。
存储指令sb、sh、sw的格式如图9-2所示。
从图9-2可知,这3条存储指令可以根据指令中26-31bit的指令码加以区分,另外,存储指令的0-15bit是offset、21-15bit是base,存储地址的计算方法如下,先将16位的offset符号扩展至32位,然后与地址为base的通用寄存器的值相加,即可得到存储地址。
存储地址 = signed_extended(offset) + GPR[base]
下面分别介绍各个存储指令的作用。
指令用法为:sb rt, offset(base)
指令作用为:将地址为rt的通用寄存器的最低字节存储到内存中的指定地址。
指令用法为:sh rt, offset(base)
指令作用为:将地址为rt的通用寄存器的最低两个字节存储到内存中的指定地址。该指令有地址对齐要求,要求计算出来的存储地址的最低位为0。
指令用法为:sw rt, offset(base)
指令作用为:将地址为rt的通用寄存器的值存储到内存中的指定地址。该指令有地址对齐要求,要求计算出来的存储地址的最低两位为00。
OpenMIPS处理器是按照字节寻址,并且是大端模式,在这种模式下,数据的高位保存在存储器的低地址中,而数据的低位保存在存储器的高地址中。比如:使用指令sb在0x50处存储0x81,存储器中实际存储效果如图9-3所示。
使用指令sh在0x54处存储0x8281,存储器中实际存储效果如图9-4所示。
使用指令sw在0x58处存储0x84838281,存储器中实际存储效果如图9-5所示。
此时使用加载指令会有如下效果。
(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条指令的作用不太容易理解,将在下一次专题介绍。
原文地址:http://blog.csdn.net/leishangwen/article/details/39873965