目录
1.add、addu、sub、subu、slt、sltu 指令
一 简单算术操作指令的介绍
简单算术操作指令-共有15条,具体包括: add、 addi、 addiu、 addu、 sub、 subu、 clo、
clz、 slt、 slti、 sltiu、 stu、 mul、 mult、 multu, 各指令的格式及作用说明如下。
1.add、addu、sub、subu、slt、sltu 指令
主要是加减和比较运算,需要注意的是,都分为有符号和无符号两种类型,有符号即需要判断正负,而且加法和减法指令还需要判断是否有溢出(符号位异常即可认为有溢出,如正正相加得负,负负相减的正),如果溢出就不写回目的地址。
2.addi、addiu、slti、sltiu 指令
对立即数进行加法和比较,也注意都区分有无符号,并且加法也需要考虑溢出情况。
3.clo、clz 指令
![](https://img-blog.csdnimg.cn/direct/4157b20ee77348479272be58b38a40a3.png)
这两个指令是进行计数运算的。
指令1作用为:rd<-counleadingzerosrs,对地址为rs的通用寄存器的值,从其最高位开始向最低位方向检查,直到遇到值为“1”的位,将该位之前“0”的个数保存到地址为rd的通用寄存器中,如果地址为rs的通用寄存器的所有位都为0(即0x0000000),那么将32保存到地址为rd的通用寄存器中。
指令2作用为: rd <- coun_ leading_ ones rs,对地址为rs的通用寄存器的值,从其最高位开始向最低位方向检查,直到遇到值为“0”的位,将该位之前“1”的个数保存到地址为rd的通用寄存器中,如果地址为rs 的通用寄存器的所有位都为1 (即OFFFFFF),那么将32保存到地址为rd的通用寄存器中。
4.multu、mult、mul 指令
.![](https://img-blog.csdnimg.cn/direct/54f613389f2042a4b23f2bfef22ef1f9.png)
这三条都是乘法指令,第一条做简单的有符号相乘,保存到通用寄存器中。后两条区分有无符号且将结果保存到特殊寄存器hilo中,低32位保存到lo中,高32位保存到hi中。
二 译码阶段的实现
这种R类型两个寄存器都要读且需要写回通用寄存器,故译码阶段的信号都赋值如下(除了op):
除了clz和clo有点特殊,rt寄存器没有用,只读了rs寄存器并且写回通用寄存器rd:
此类型两个寄存器都要读但是不写回通用寄存器而是特殊寄存器,赋值如下:
I型指令需要对立即数进行有符号扩展操作,只需要读第一个寄存器,写回通用寄存器rt:
三 执行阶段的实现
执行阶段才是重点,需要重点注意的点如下,在思考是要全面考虑多种情况:
1.加减运算
如何同时实现加减运算,可以通过补码的方式,对于需要减法的指令sub,subu,slt对操作数2加上补码(取反+1)否则保持原样。
这个时候sum的结果就可以同时实现加减法运算:
2.比较运算
比较运算分为有符号和无符号比较,主要实现计算操作数1是否小于操作数2,分以下几种情况讨论什么条件下操作数1小于操作数2:
有符号时:
1.一负一正,显然成立
2.都是正,减法结果为负时成立(看最高的符号位即可,使用上面说过的加减法操作即可)
3.都是负,减法结果为负时成立
无符号时直接使用<判断
3.计数运算
clz:从其最高位开始向最低位方向检查,直到遇到值为“1”的位,将该位之前“0”的个数保存到地址为rd的通用寄存器中,如果地址为rs的通用寄存器的所有位都为0(即0x0000000),那么将32保存到地址为rd的通用寄存器中。
clo:从其最高位开始向最低位方向检查,直到遇到值为“0”的位,将该位之前“1”的个数保存到地址为rd的通用寄存器中,如果地址为rs 的通用寄存器的所有位都为1 (即OFFFFFF),那么将32保存到地址为rd的通用寄存器中。
4.乘法运算
我们来考虑乘法运算的几种情况:
1.正正为正,负负为正
2.一正一负为负
所以我们可以先取出乘数和被乘数的绝对值(即如果是负数就取其补码,正数不变),再根据他们的符号进行判断最终的符号。
先取出绝对值,主要是对负数的做补码:
然后根据两个乘法的符号判断最终的结果,用逻辑原来说如果符号位不同(考虑到异或0,即输出补码,如果相同即不变。
5.溢出情况
我们之前在指令中知道加减法都有溢出判断,如果溢出就不写回结果。
那么如何判断溢出呢,可以根据异常的符号来判断:
如果溢出就不写回目的寄存器,即对写回使能进行赋值:
6.写入特殊寄存器的指令
我们知道mult和multu指令是将乘法的结果写入特殊寄存器hilo的,那么还需要对最终的hilo的相关信号的输出进行赋值,hi写乘法结果高位,lo写低位:
以上,简单的算术操作实现就完成了,我们需要重点关注执行阶段的实现,要全面考虑相关指令的各种情况,争取可以统一他们的输出,从而简化代码,提高效率。