【发布时间】:2017-03-19 05:23:38
【问题描述】:
这是一个任务。这个想法是 提示用户:
- 输入第一个正整数
- 输入/,*,-,+任一操作
- 输入第二个正整数
然后,调用do_math 调用以下之一:
do_add 如果运算符为 +,则不使用 add 或 sub mips 指令将 2 个输入相加,并将结果返回到寄存器中。如果发生溢出,则返回错误条件。
do_sub 如果运算符为 -,则不使用 sub 或 add mips 指令从第一个整数中减去第二个整数(可以调用 do_add 两次)并将结果返回到寄存器中。
do_multiply 如果运算符为 *,则将两个输入相乘,不使用 add、sub、mult 和 return 结果在两个寄存器中,一个保存乘积的最高有效 32 位,另一个保存乘积的最低 32 位。 (我没有这样做,因为我不知道如何提取它们)
do_divide 如果运算符是 /,不使用 add、sub、mult 或 div 的除法并以 X OP Y = Z 的形式返回结果。其中 Z 被 Q 余数 R 替换。Q= QUOTIENT AND R= REMAINDER
这是我的担忧:
首先我如何提取我产品的 32 MSB 和 32LSB
当我运行此代码时,错误消息是 异常发生在 pc=0x004002bc 无法将堆栈段扩展 12 个字节到 1048576 个字节。使用 -|stack #with > 1048576 instr/data fetch 中未对齐的地址:0x7fffffff
如果有人告诉我我做错了什么,我将不胜感激,并且请我在一切方面仍然很陌生。所以你的回应要更明确。非常感谢
更新:这是昨天代码的更新。我认为这更好,因为我没有昨天的错误消息,而且每次我尝试运行此代码时我的系统都不会崩溃。但不幸的是,我没有打印我想要打印的答案。成功输入数据后,它只是停止,没有任何反应。有人可以告诉我我做错了什么。谢谢E
PS 此代码由其他人友好编辑,带有 NOTE/BUG 或 NOTE/FIX。因此,如果您遇到它们,请不要介意。
这是我的代码:
.data
prompt: .asciiz "Please enter an integer\n"
message: .asciiz "Please enter an operator (+, - , * , / )\n:"
error1: .asciiz "invalid arithmetic operation "
err: .asciiz "Hmmmm!!! an overflow occured in one register"
newline: .asciiz "\n"
remainder: .asciiz "remainder"
sorry: .asciiz "sorry, division by zero is invalid"
equals: .asciiz "="
addition: .word 43
subtr: .word 45
multi: .word 42
divi: .word 47
input1: .word 1
input2: .word 1
.text
main:
li $v0,4 # system call code for printing a string
la $a0,prompt # string to print
syscall # telling the system to execute the action
li $v0,5 # system call for reading/displaying input
syscall # waits for input,puts input in $v0
sw $v0,0($s3)
li $v0,4
la $a0,message
syscall
li $v0,12 # code to get and print a char to the screen
syscall
move $a3,$v0 # putting the chracter in register $a3
li $v0,4
la $a0,newline
syscall
li $v0,4
la $a0,prompt # get the second integer
syscall
li $v0,5
syscall
la $s4,input2
sw $v0,0($s4)
blez $s3,main
blez $s4,main # we only want positive integers
jal do_math
do_math:
move $a1,$s3
move $a2,$s4
lw $t0,addition
beq $t0,$a3,adding
lw $t1,subtr
beq $t1,$a3,subtract
lw $t2,multi
beq $t2,$a3,multiply
lw $t3,divi
beq $t3,$a3,divide
li $v0,4
la $a0,error1 # print out the error message
syscall
li $v0,1
li $a3,5
syscall
j main #until we get the corrrect operator
adding:
jal do_add
j exit
subtract:
jal do_sub
j exit
multiply:
jal do_multiply
j exit
divide:
jal do_divide
j exit
exit:
li $v0,10
syscall
do_add:
addi $sp,$sp,-12
sw $ra,0($sp)
sw $a1,4($sp)
sw $a2,8($sp)
loop:
move $t8, $0
xor $a1,$a1,$a2 # adding the two numbers without a carry
and $t8,$a1,$a2 # determining the carry bits
sll $a2,$t8,1 # shift the carry bits one place left
bne $a2, $0, loop # perform this operation until there are no more carry bits
jal printanswer
move $a1, $v0
lw $ra,0($sp)
lw $a1,4($sp)
lw $a2,8($sp)
addi $sp,$sp,12
jr $ra
do_sub:
addi $sp,$sp,-12
sw $ra,0($sp)
sw $a1,4($sp)
sw $a2,8($sp)
nor $a2,$a2,$a2 # flip the bits but number decreases by one so...
xori $a1,$zero,1 # find the 2s complement
jal do_add
move $a2,$v0
lw $a1, 4($sp)
jal do_add # to add the user inputs
move $a1,$v0
jal printanswer
lw $ra,0($sp)
lw $a1,4($sp)
lw $a2,8($sp)
addi $sp,$sp,12
jr $ra
do_multiply:
beq $a1, $0, done
beq $a2, $0, done
addi $sp,$sp,-12
sw $ra,0($sp)
sw $a1,4($sp)
sw $a2,8($sp)
sll $a1, $a1, 5 #extend the multiplicant bits to 32 bits
sll $a2, $a2, 6 #extend the multiplier bits to 64 and it now becomes the product(in the book)
mult_loop:
move $s0, $0
xor $s0,$s0,1
blt $s0, 5,loop1
j printmult
loop1:
andi $a2,$a2,1 # get the least significant bit and put it in the $a2
beqz $a2,then
jal do_add
move $a2, $v0
srl $a2, $a2, 1
j mult_loop
printmult:
jal printansmult
then:
srl $a2, $a2, 1
j mult_loop
lw $ra,0($sp)
lw $a1,4($sp)
lw $a2,8($sp)
addi $sp,$sp,12
jr $ra
done:
jr $ra
do_divide:
sll $a1,$a1,4 # this is going to be our remainder
sll $a2,$a2,4 # this is the divisor
sll $a3,$a3,3 # this is the quotient
addi $sp,$sp,-12
sw $ra,0($sp)
sw $a1,4($sp)
sw $a2,8($sp)
sw $a3,12($sp)
counter:
move $t6,$0
xor $t6,$t6,1
beq $t6,17,exit
loopdiv:
jal do_sub
move $a1,$v0 # subtract divisor from remainder and put result in remainder
# getting the msb significant bit
andi $t5,$a1,32768
blt $t5,$0,quotientupdate
sll $a3,$a3,1 # shift quotient left
ori $a3,$a3,1 # add one to the least significant bit of quotient
srl $a2,$a2,1
j counter
move $t5,$a3
move $t6,$a1
jal printdivans
lw $ra,0($sp)
lw $a1,4($sp)
lw $a2,8($sp)
lw $a3,12($sp)
addi $sp,$sp,16
jr $ra
quotientupdate:
jal do_add
move $a1,$v0
sll $a3,$a3,1 # shift quotient left
ori $a3,$a3,0 # add zero to the least significant bit of quotient
srl $a2,$a2,1
j counter
# NOTE/BUG: this is dead/never reached code
move $t5,$a3
move $t6,$a1
jal printdivans
lw $ra,0($sp)
lw $a1,4($sp)
lw $a2,8($sp)
lw $a3,12($sp)
addi $sp,$sp,12
jr $ra
printanswer:
lw $a1, 4($sp)
li $v0,1
syscall
jr $ra
printansmult:
la $a1, 4($sp)
li $v0,1
syscall
jr $ra
printdivans:
lw $a0,input1
li $v0,1
syscall
la $a0,divi
li $v0,4
syscall
li $v0,1
la $a0,input2
syscall
li $v0,4
la $a0,equals
syscall
li $v0,1
la $a0,4($sp)
syscall
li $v0,4
la $a0,remainder
syscall
li $v0,1
la $a0,8($sp)
syscall
【问题讨论】:
-
printanswer似乎永远不会返回 (jr $ra)。而且你需要记住,每个jal都会修改$ra,所以像jal printdivans/jr $ra这样的东西很可能是不正确的。另外,考虑一下你需要做什么,例如jal do_add返回。 CPU 不仅会自动停止执行您的程序。您需要明确结束您的程序。 -
嗨,迈克尔,感谢您的帮助。我不确定你在说什么。如果 jal printdivans 不是正确的做法,那么你会建议我做什么。对于 printanswer 没有返回,你是说我必须在所有 printanswer 之后放一个 jr $ra 吗?关于如何提取 LSB 和 MSB 的任何想法?谢谢
-
当您使用
jal时,您表示打算直接在jal指令之后返回指令。因此,您的代码在jal之后可能采用的任何路径都应该以jr $ra结尾。我要指出的另一件事是,您需要注意每个jal都会修改$ra寄存器,因此您必须小心在正确的位置保存和恢复$ra。想想在jal指令之后直接使用jr $ra意味着什么。如果需要,请使用笔和纸跟踪执行情况。 -
如果你觉得你还没有完全理解这些基础知识,那么从编写一个更简单的程序开始。查找您在 MIPS 指令集参考(MIPS32™ 程序员架构第二卷:MIPS32™ 指令集)中使用的每条指令并阅读说明,并在 SPIM/ 中逐条指令执行代码MARS,直到您完全了解它们的作用。
-
天哪!而且我的系统不会停止崩溃,并且一遍又一遍地打印“嗯,发生溢出”!知道为什么吗?谢谢