使用MIPS的addu指令实现溢出检测遇到问题求助
MIPS银行账本程序溢出检测问题排查
这是一项学校作业,我们拿到了一个基础银行账本程序,该程序会请求用户输入,若输入为正数则增加余额,为负数则减少余额。我已按作业要求完成了非整数输入的检测,现在需要实现溢出检测:当检测到溢出时抛出错误信息,不修改余额并重新提示交易。
我认为对于加法操作,若两个操作数符号相同但结果符号相反则发生溢出,若符号相反则不会溢出。但目前我的溢出检测逻辑似乎被直接跳过,程序能运行但无法按要求检测溢出,请问我哪里出错了?
相关代码
loopB: li $s1, 0 #### reset $s1 add $s1, $zero, $t3 #### load integer value into $s1 beqz $s1, done # If $s1 equals zero, branch to done li $s2, 0 #### initialize $s2 for temporary balance addu $s2, $s0, $t6 #### set temporary balance to initial balance addu $s2, $s0, $s1 # add transaction amount to the temporary Balance oTest: sltiu $t6, $s0, 0 #### if $t6 == 1 then number is negative sltiu $t7, $s1, 0 #### if $t7 == 1 then number is negative bne $t6, $t7, LoopC #### if opposite signs then no overflow sltiu $t8, $s2, 0 #### if $t8 == 1 then the number is negative and $t9, $t6, $t7 #### if $t9 == 1 then $t6 and $t7 are both negative bne $t9, $t8, over #### if $t9 and $t8 are not both negative, then overflow has occured sgtu $t6, $s0, $zero #### if $t6 == 1 then number is positive sgtu $t7, $s0, $zero #### if $t7 == 1 then number is positive sgtu $t8, $s0, $zero #### if $t8 == 1 then number is positive and $t9, $t6, $t7 #### if $t9 == 1 then $t6 and $t7 are both positive bne $t9, $t8, over #### if $t8 and $t9 are not equal then overflow has occured LoopC: addu $s0, $s0, $s1 #### add transaction to balance li $v0, 4 # system call code for print_string la $a0, tabs # load address of tabs into $a0 syscall # used to space over to the Balance column li $v0, 1 # system call code for print_integer move $a0, $s0 # move Bank Balance value to $a0 syscall # print Bank Balance b loop # branch to loop over: li $v0, 4 #### system call code for print_string la $a0, oMsg #### load address of msg. into $a0 syscall #### print the string li $s2, 0 #### reset $s2 li $v0, 1 #### system call code for print_integer move $a0, $s0 #### move Bank Balance value to $a0 syscall #### print Bank Balance b loop # branch to loop
问题排查与修复
1. 临时余额计算错误
在loopB段,你先执行addu $s2, $s0, $t6,紧接着又执行addu $s2, $s0, $s1,这不仅会覆盖之前的赋值,而且$t6此时是未初始化的垃圾值,完全没有意义。正确做法是删掉第一行错误的赋值,只保留addu $s2, $s0, $s1来计算临时余额。
2. 溢出检测逻辑冗余且无效
当你完成同号判断后,后续重新给$t6、$t7、$t8赋值为sgtu $s0, $zero,这三个寄存器全部被设置为余额$s0的正负判断,直接覆盖了之前的操作数和结果符号信息,导致后面的检测代码完全失效。这部分冗余代码必须删除。
实际上,当两数同号时,只需要判断结果符号是否与操作数一致:
- 若两数都是负数,结果应为负数,若结果为正则溢出;
- 若两数都是正数,结果应为正数,若结果为负则溢出。
3. 指令使用错误
sgtu是无符号数的大于判断,而你需要判断的是有符号数的正负,应该用slt(判断是否小于0,即负数)或sgt(判断是否大于0,即正数),否则会把最高位为1的无符号数(对应有符号的负数)误判为正数。
修复后的关键代码
loopB: li $s1, 0 #### reset $s1 add $s1, $zero, $t3 #### load integer value into $s1 beqz $s1, done # If $s1 equals zero, branch to done li $s2, 0 #### initialize $s2 for temporary balance addu $s2, $s0, $s1 # 仅保留这行,计算临时余额 oTest: slt $t6, $s0, 0 #### $t6=1 表示余额$s0是负数 slt $t7, $s1, 0 #### $t7=1 表示交易金额$s1是负数 bne $t6, $t7, LoopC #### 符号相反,无溢出,跳转到更新余额 slt $t8, $s2, 0 #### $t8=1 表示计算结果是负数 # 检测两数均为负数但结果为正的溢出情况 and $t9, $t6, $t7 bne $t9, $t8, over # 检测两数均为正数但结果为负的溢出情况 nor $t9, $t6, $zero # 取反$t6(此时$t6=0,取反后为1) nor $t10, $t7, $zero # 取反$t7(此时$t7=0,取反后为1) and $t9, $t9, $t10 # $t9=1 表示两数都是正数 sgt $t11, $s2, $zero # $t11=1 表示结果是正数 bne $t9, $t11, over LoopC: addu $s0, $s0, $s1 li $v0, 4 la $a0, tabs syscall li $v0, 1 move $a0, $s0 syscall b loop over: li $v0, 4 la $a0, oMsg syscall li $s2, 0 li $v0, 1 move $a0, $s0 syscall b loop
内容的提问来源于stack exchange,提问作者TJream
相关产品推荐
相关产品推荐

