获取3条错误消息,MIPS汇编语言 [英] getting 3 error messages, mips assembly language
问题描述
这是一项作业。我们的想法是 提示用户:
- 输入第一个正整数
- 输入/、*、-、+中的任何一个操作
- 输入第二个正整数
然后调用do_math
,它调用以下其中之一:
do_add
如果运算符为+,则在不使用ADD或SUB MIPS指令的情况下将2个输入相加,并在寄存器中返回结果。如果存在溢出,则返回错误条件。
do_sub
如果运算符为-,请在不使用SUB或ADD MIPS指令(可以调用do_add两次)的情况下从第一个整数中减去第二个整数,然后在寄存器中返回结果。
do_multiply
如果运算符为*,则在两个寄存器中将两个输入相乘,而不使用加、减、乘和返回结果,一个寄存器保存乘积的最高有效32位,另一个寄存器保存乘积的最低32位。(我没有这样做,因为我不知道如何提取它们)
do_divide
如果运算符为/,则不使用ADD、SUB、MULT或DIV进行除法,并以X OP Y=Z的形式返回结果,其中Z被Q余数替换为R。Q=商,R=余数
以下是我的担忧:
首先如何提取产品的32MSB和32LSB
当我运行此代码时,错误消息为 PC=0x004002bc出现异常 无法将堆栈段扩展12字节到1048576字节。使用-|>1048576的堆栈编号 Instr/Data Fetch中的未对齐地址:0x7fffffff如果有人告诉我我做错了什么,我会非常感激,请告诉我,我对每件事都还是个新手。因此,在回复时要更加明确。非常感谢
更新:这是对昨天代码的更新。我认为这样更好,因为我没有昨天收到的错误消息,而且我的系统也不会在每次尝试运行此代码时崩溃。但不幸的是,我没有打印我想要打印的答案。成功输入数据后,它就会停止,什么也不会发生。有人能告诉我我做错了什么吗?感谢E
PS其他人友好地编辑了此代码,添加了注释/错误或注释/修复。所以如果你碰到他们,请不要介意。
这是我的代码:
.data
prompt: .asciiz "Please enter an integer
"
message: .asciiz "Please enter an operator (+, - , * , / )
:"
error1: .asciiz "invalid arithmetic operation "
err: .asciiz "Hmmmm!!! an overflow occured in one register"
newline: .asciiz "
"
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
推荐答案
我已经用"注意/错误"为您的代码添加了尽可能多的错误注释。还有其他一些错误,其中一些错误在其他地方重复出现。
注意:由于篇幅的限制,我在另一个单独的答案中发布了一个经过清理的工作版本,它是此答案的附录。
具体地说,一些函数在堆栈框架弹出之后调用函数。或者,一个函数有多个堆栈框架弹出窗口。这些可能是您收到的运行时异常的基础。
所有函数都应具有[种类]的标准形式:
fnca:
addiu $sp,$sp,-12
sw $ra,8($sp)
sw ...
# do stuff ...
fnca_exit:
lw $ra,8($sp)
lw ...
addiu $sp,$sp,12
jr $ra
有关良好ASM样式的详细信息,请参阅我的回答:MIPS linked list
似乎3 + 4
会产生溢出消息,所以我会先修复do_add
,作为其他do_*
函数的基础。
此外,在计算函数中调用打印函数会导致出现垃圾,因此打印函数应保存/还原任何寄存器(例如$v0
、$a0
),以便可以用于调试(即调用它们"没有任何危害")。
不知道您使用的是spim
还是mars
,但我两个都用过了,可能的话我更喜欢mars
:http://courses.missouristate.edu/KenVollmar/mars/
不管怎样,下面是带注释的代码[请原谅不必要的样式清理]:
.data
prompt: .asciiz "Please enter an integer
"
message: .asciiz "Please enter an operator (+, - , * , / )
:"
error1: .asciiz "invalid arithmetic operation "
err: .asciiz "Hmmmm!!! an overflow occured in one register"
newline: .asciiz "
"
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
# NOTE/BUG: doing the "la" does nothing as $s3 is immediately replaced
# do_math uses $s3/$s4, store storing to input1 only helps printdivans
# to actually store into input1, after the "la" we
la $s3,input1 # store input one into register $s3
# NOTE/FIX: store into input1
sw $v0,0($s3)
move $s3,$v0
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)
move $s4,$v0
# NOTE/BUG: these are incorrect -- they should be $s3/$s4
###blez $a0,main
###blez $a1,main # we only want positive integers
# NOTE/FIX:
blez $s3,main
blez $s4,main # we only want positive integers
# NOTE/BUG: this should just fall into do_math
###jal do_math
###jr $ra
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
j error
# NOTE/BUG: these jal insts should be followed by "j exit"
adding:
jal do_add
j exit # NOTE/FIX: prevent fall through
subtract:
jal do_sub
j exit # NOTE/FIX: prevent fall through
multiply:
jal do_multiply
j exit # NOTE/FIX: prevent fall through
divide:
jal do_divide
j exit # NOTE/FIX: prevent fall through
error:
li $v0,4
la $a0,error1 # print out the error message
syscall
li $v0,1
li $a3,5
syscall
exit:
li $v0,10
syscall
do_add:
addi $sp,$sp,-12
sw $ra,0($sp)
sw $a1,4($sp)
sw $a2,8($sp)
addition_loop:
beqz $a2,no_carrybits
xor $t7,$a1,$a2 # adding the two numbers without a carry
and $t8,$a1,$a2 # determining the carry bits
beqz $t8,overflow # checking for overflow
sll $t8,$t8,1 # shift the carry bits one place left
move $a1,$t7 # put the recent sum back into the argument register $a1
move $a2,$t8 # and put the carry bit into register $a2
j addition_loop # perform this operation until there are no more carry bits
# NOTE/BUG: have one-and-only-one place for stack frame pop!
# NOTE/BUG: this destroys the sum value???
no_carrybits:
lw $ra,0($sp)
lw $a1,4($sp)
lw $a2,8($sp)
addi $sp,$sp,12
move $v0,$a1
# NOTE/FIX: we are "falling through" into the overflow code -- we need to jump
# around it
j add_exit
# NOTE/BUG: this message _always_ prints -- try input of "3 + 4"
overflow:
li $v0,4
la $a0,err
syscall
li $v0,4
la $a0,newline
syscall
add_exit:
# NOTE/BUG: this trashes $v0 which has the result of the addition?
jal printanswer
lw $ra,0($sp)
lw $a1,4($sp)
lw $a2,8($sp)
addi $sp,$sp,12
# NOTE/BUG: this should go above the stack frame restore
# NOTE/BUG: since do_add is called by other functions why print unless this
# is for debug? -- this call should probably be moved immediately after the call
# to do_add in the do_math function
###jal printanswer
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
jal do_add # to add the user inputs
# NOTE/FIX: correct place for printanswer call
jal printanswer
lw $ra,0($sp)
lw $a1,4($sp)
lw $a2,8($sp)
addi $sp,$sp,12
# NOTE/BUG: this needs to go above the stack frame pop -- here it is an
# infinite loop
###jal printanswer
jr $ra
do_multiply:
sll $a1,$a1,5 # extend the multiplicant bits to 32 bits
sll $a2,$a2,6 # extend the multiplier bits to 64
mult_loop:
move $s0,$0
xor $s0,$s0,1
blt $s0,5,mult_loop1
j exit
mult_loop1:
# NOTE/BUG: setup of stack frame should be moved to top of function?
addi $sp,$sp,-12
sw $ra,0($sp)
sw $a1,4($sp)
sw $a2,8($sp)
andi $a2,$a2,1 # get the least significant bit and put it in the $a2
beqz $a2,then
jal do_add
move $a2,$v0
then:
sll $a2,$a2,1
j mult_loop
jal printansmult
lw $ra,0($sp)
lw $a1,4($sp)
lw $a2,8($sp)
addi $sp,$sp,12
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,-16
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
lw $ra,0($sp)
lw $a1,4($sp)
lw $a2,8($sp)
lw $a3,12($sp)
addi $sp,$sp,16
move $t5,$a3
move $t6,$a1
jal printdivans
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
lw $ra,0($sp)
lw $a1,4($sp)
lw $a2,8($sp)
lw $a3,12($sp)
addi $sp,$sp,16
move $t5,$a3
move $t6,$a1
# NOTE/BUG: this jal should be above the stack frame pop -- here it produces
# an infinite loop
jal printdivans
jr $ra
printanswer:
li $v0,1
syscall
# NOTE/BUG: missing return?
jr $ra
printansmult:
printdivans:
li $v0,1
lw $a0,input1
syscall
li $v0,4
la $a0,divi
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
# NOTE/BUG: there is no "jr $ra"
jr $ra
更新#2:
下面是既充当测试数据生成器又充当原型/模型的C程序。domul
函数是我的第二个答案中do_mul
函数的模型。
// mipscalc/mipscalc -- generate test data
#include <stdio.h>
#include <stdlib.h>
typedef unsigned int u32;
typedef unsigned long long u64;
#define dbgprt(_fmt...)
do {
if (opt_d)
printf(_fmt);
} while (0)
int opt_d; // 1=debug print
int opt_T; // number of tests
typedef struct {
u32 tst_opc; // opcode
u32 tst_num[3]; // input
u32 tst_anslsw; // lower 32 bits
u32 tst_ansmsw; // upper 32 bits
u64 zx; // large number
} tstctl_t;
u32 tstno; // current test number
u32 opc;
const char *opctag[] = {
"add", "sub", "mul", "div"
};
// xrand -- get random number
u32
xrand(void)
{
u32 msb;
u32 val;
// NOTE: this never sets the MSB
val = rand();
// so get a suitable selector
msb = val & 0x0F;
// isolate the bit
msb = (val >> msb) & 1;
// flip it
msb ^= 1;
// add it as the MSB
val |= msb << 31;
return val;
}
// domul -- do 64 bit multiply
void
domul(tstctl_t *inp,tstctl_t *rtn)
{
u32 y;
u32 xl;
u32 xh;
u32 cout;
u32 zh;
u32 zl;
dbgprt("domul: ENTER
");
// NOTE: this _is_ the shift-and-add algorithm
// this is the x term in pseudo-64 bits
xh = 0;
xl = inp->tst_num[0];
y = inp->tst_num[1];
// this is the product
zh = 0;
zl = 0;
// no need to loop if either argument is zero
if (xl == 0)
y = 0;
while (y != 0) {
dbgprt("domul: LOOP zh=%8.8X zl=%8.8X xh=%8.8X xl=%8.8X y=%8.8X
",
zh,zl,xh,xl,y);
if (y & 1) {
// get carry out of lower 32 bits (i.e. LSW "wraps")
cout = zl + xl;
cout = (cout < zl) ? 1 : 0;
// add in LSW
zl += xl;
// add in MSW + carry out from LSW
zh += xh;
zh += cout;
}
// get carry out for our shift
cout = (xl >> 31) & 1;
// shift LSW of x left
xl <<= 1;
// shift MSW of x left and merge with carry out of LSW shift
xh <<= 1;
xh |= cout;
// shift y right
y >>= 1;
}
rtn->tst_anslsw = zl;
rtn->tst_ansmsw = zh;
rtn->zx = zh;
rtn->zx <<= 32;
rtn->zx |= zl;
dbgprt("domul: EXIT
");
}
// zxsplit -- split up 64 bit result
void
zxsplit(tstctl_t *z)
{
z->tst_ansmsw = (z->zx >> 32);
z->tst_anslsw = (z->zx >> 0);
}
// testout -- output test
void
testout(tstctl_t *z)
{
if (z->tst_opc != opc) {
opc = z->tst_opc;
printf("
");
printf(" # %s tests
",opctag[opc]);
tstno = opc * 100;
}
printf(" .word %u, %u, 0x%8.8X, 0x%8.8X, 0x%8.8X, 0x%8.8X, 0x%8.8X
",
++tstno,
z->tst_opc,
z->tst_num[0],z->tst_num[1],z->tst_num[2],
z->tst_anslsw,z->tst_ansmsw);
}
// testchk -- cross-check test results
void
testchk(tstctl_t *z,tstctl_t *c)
{
if ((c->zx != z->zx) ||
(c->tst_anslsw != z->tst_anslsw) ||
(c->tst_ansmsw != z->tst_ansmsw)) {
printf(" FAIL 2, 0x%8.8X, 0x%8.8X 0x%8.8X, 0x%8.8X
",
z->tst_num[0],z->tst_num[1],c->tst_anslsw,c->tst_ansmsw);
exit(1);
}
}
// testadd -- generate add test
void
testadd(tstctl_t *z,tstctl_t *c)
{
u32 cout;
z->zx = z->tst_num[0];
z->zx += z->tst_num[1];
z->tst_anslsw = z->zx;
cout = (z->zx >> 32) ? 1 : 0;
z->tst_ansmsw = cout;
zxsplit(z);
z->tst_opc = 0;
z->tst_num[2] = 0;
testout(z);
}
// testsub -- generate add test
void
testsub(tstctl_t *z,tstctl_t *c)
{
z->zx = z->tst_num[0];
z->zx -= z->tst_num[1];
z->tst_anslsw = z->zx;
z->tst_ansmsw = (z->tst_num[0] < z->tst_num[1]) ? 1 : 0;
z->tst_opc = 1;
z->tst_num[2] = 0;
testout(z);
}
// testmul -- generate multiply test
void
testmul(tstctl_t *z,tstctl_t *c)
{
z->zx = z->tst_num[0];
z->zx *= z->tst_num[1];
zxsplit(z);
z->tst_opc = 2;
testout(z);
domul(z,c);
testchk(z,c);
}
// testdiv -- generate divide test
void
testdiv(tstctl_t *z,tstctl_t *c)
{
u32 div;
z->zx = z->tst_num[0];
z->zx *= z->tst_num[1];
div = z->tst_num[2];
z->tst_anslsw = z->zx / div;
z->tst_ansmsw = z->zx % div;
z->tst_opc = 3;
testout(z);
#if 0
dodiv(z,c);
testchk(z,c);
#endif
}
// main -- main program
int
main(int argc,char **argv)
{
char *cp;
tstctl_t z;
tstctl_t c;
--argc;
++argv;
for (; argc > 0; --argc, ++argv) {
cp = *argv;
if (*cp != '-')
break;
switch (cp[1]) {
case 'd':
opt_d = 1;
break;
case 'T':
cp += 2;
opt_T = (*cp != 0) ? atoi(cp) : 40;
break;
default:
break;
}
}
if (opt_T <= 0)
opt_T = 20;
opc = -1;
z.tst_num[0] = 0;
z.tst_num[1] = 1;
testadd(&z,&c);
z.tst_num[0] = 1;
z.tst_num[1] = 0;
testadd(&z,&c);
z.tst_num[0] = 3;
z.tst_num[1] = 4;
testadd(&z,&c);
z.tst_num[0] = 0x0B;
z.tst_num[1] = 0x03;
testadd(&z,&c);
for (int tstno = 1; tstno <= opt_T; ++tstno) {
z.tst_num[0] = xrand();
z.tst_num[1] = xrand();
testadd(&z,&c);
}
z.tst_num[0] = 3;
z.tst_num[1] = 1;
testsub(&z,&c);
z.tst_num[0] = 7;
z.tst_num[1] = -3;
testsub(&z,&c);
for (int tstno = 1; tstno <= opt_T; ++tstno) {
z.tst_num[0] = xrand();
z.tst_num[1] = xrand();
testsub(&z,&c);
}
z.tst_num[0] = 0x7FFFFFFF;
z.tst_num[1] = 0x7FFFFFFF;
testmul(&z,&c);
z.tst_num[0] = 0xFFFFFFFF;
z.tst_num[1] = 0xFFFFFFFF;
testmul(&z,&c);
z.tst_num[0] = 0x7FFFFFFF;
z.tst_num[1] = 0xFFFFFFFF;
testmul(&z,&c);
for (int tstno = 1; tstno <= opt_T; ++tstno) {
z.tst_num[0] = xrand();
z.tst_num[1] = xrand();
testmul(&z,&c);
}
for (int tstno = 1; tstno <= opt_T; ++tstno) {
z.tst_num[0] = xrand();
z.tst_num[1] = xrand();
while (1) {
z.tst_num[2] = xrand();
if (z.tst_num[2] != 0)
break;
}
testdiv(&z,&c);
}
return 0;
}
这篇关于获取3条错误消息,MIPS汇编语言的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!