这是一项任务。这个想法是为了 提示用户:
然后,拨打do_math
,拨打以下电话之一:
do_add
如果operator是+,则在不使用add或sub mips指令的情况下添加2个输入,并将结果返回到寄存器中。如果有溢出,则返回错误条件。
do_sub
如果operator是 - ,则不使用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个字节。 use - | 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
答案 0 :(得分:1)
我已经用尽可能多的错误注释了你的代码"注意/ BUG"。还有其他一些,其中一些错误在其他地方重演。
注意:由于太空的SO限制,我在一个单独的答案中发布了一个清理过的和正在运行的版本,该答案是对此的补充。
特别是,一些函数在堆栈帧弹出后调用函数。或者,一个函数有多个堆栈框架弹出窗口。这些可能是您获得的运行时异常的基础。
所有功能都应该有[各种]的标准形式:
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
:{{3} }
无论如何,这里是带注释的代码[请原谅无偿的风格清理]:
.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
# 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\n");
// 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\n",
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\n");
}
// 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("\n");
printf("\t# %s tests\n",opctag[opc]);
tstno = opc * 100;
}
printf("\t.word\t%u,\t%u,\t0x%8.8X,\t0x%8.8X,\t0x%8.8X,\t0x%8.8X,\t0x%8.8X\n",
++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("\tFAIL\t2,\t0x%8.8X,\t0x%8.8X\t0x%8.8X,\t0x%8.8X\n",
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;
}
答案 1 :(得分:0)
注意:由于空间限制,这个答案是我之前的补充。
以下是具有add,sub和mul工作的代码版本。
作为测试生成器和原型/模型的C程序是我原来的答案[再次,由于空间限制]
这是清理过的代码。请注意,我将函数的参数更改为以$a0
开头。此外,它使用偏移量来表驱动,以实现C struct
的等价物。同样,由于空间限制,我必须删除任何非必要的代码。
由于十六进制输出系统调用[spim
不具有],这暂时只对mars
有效。
在试验IMO之后,以十六进制比十进制更容易看到工作结果。如果需要,程序输出可以被捕获并由脚本进行后处理,并使其执行“繁重的工作”。将两个十六进制数转换为单个64位十进制数。
.data
sdata:
# diagnostic test table
#
# struct format:
# <opcode> <input1> <input2> [input3] <answer LSW> [answer MSW]
#
# NOTE: for spim, replace with (e.g.):
# tst_opc = 0
.eqv tst_xid 0 # test number
.eqv tst_opc 4 # opcode
.eqv tst_num1 8 # input1 (add/sub/mul x, div LSW)
.eqv tst_num2 12 # input2 (add/sub/mul y, div MSW)
.eqv tst_num3 16 # input3 (div divisor)
.eqv tst_anslsw 20 # answer LSW (mul LSW, div quot)
.eqv tst_ansmsw 24 # answer MSW (mul, div rem)
.eqv tst_size 28 # struct size
.eqv svc_prt10 1 # print integer in decimal
.eqv svc_prtx 34 # print integer in hex
testlist:
# add tests
.word 1,0,0x00000000,0x00000001,0x00000000,0x00000001,0x00000000
.word 2,0,0x00000001,0x00000000,0x00000000,0x00000001,0x00000000
.word 3,0,0x00000003,0x00000004,0x00000000,0x00000007,0x00000000
.word 4,0,0x0000000B,0x00000003,0x00000000,0x0000000E,0x00000000
.word 5,0,0xEB8B4567,0x327B23C6,0x00000000,0x1E06692D,0x00000001
.word 6,0,0xE43C9869,0xE6334873,0x00000000,0xCA6FE0DC,0x00000001
.word 7,0,0xF4B0DC51,0x99495CFF,0x00000000,0x8DFA3950,0x00000001
.word 8,0,0x2AE8944A,0x625558EC,0x00000000,0x8D3DED36,0x00000000
.word 9,0,0x238E1F29,0x46E87CCD,0x00000000,0x6A769BF6,0x00000000
.word 10,0,0xBD1B58BA,0xD07ED7AB,0x00000000,0x8D9A3065,0x00000001
.word 11,0,0xAEB141F2,0x41B71EFB,0x00000000,0xF06860ED,0x00000000
.word 12,0,0xF9E2A9E3,0x7545E146,0x00000000,0x6F288B29,0x00000001
.word 13,0,0xD15F007C,0xDBD062C2,0x00000000,0xAD2F633E,0x00000001
.word 14,0,0x12200854,0x4DB127F8,0x00000000,0x5FD1304C,0x00000000
.word 15,0,0x8216231B,0x1F16E9E8,0x00000000,0xA12D0D03,0x00000000
.word 16,0,0x1190CDE7,0xE6EF438D,0x00000000,0xF8801174,0x00000000
.word 17,0,0x140E0F76,0x3352255A,0x00000000,0x476034D0,0x00000000
.word 18,0,0x109CF92E,0x8DED7263,0x00000000,0x9E8A6B91,0x00000000
.word 19,0,0xFFDCC233,0x1BEFD79F,0x00000000,0x1BCC99D2,0x00000001
.word 20,0,0xC1A7C4C9,0x6B68079A,0x00000000,0x2D0FCC63,0x00000001
.word 21,0,0x4E6AFB66,0xA5E45D32,0x00000000,0xF44F5898,0x00000000
.word 22,0,0xD19B500D,0x431BD7B7,0x00000000,0x14B727C4,0x00000001
.word 23,0,0xBF2DBA31,0xFC83E458,0x00000000,0xBBB19E89,0x00000001
.word 24,0,0xA57130A3,0xE2BBD95A,0x00000000,0x882D09FD,0x00000001
# sub tests
.word 101,1,0x00000003,0x00000001,0x00000000,0x00000002,0x00000000
.word 102,1,0x00000007,0xFFFFFFFD,0x00000000,0x0000000A,0x00000001
.word 103,1,0x436C6125,0xE28C895D,0x00000000,0x60DFD7C8,0x00000001
.word 104,1,0xB33AB105,0xF21DA317,0x00000000,0xC11D0DEE,0x00000001
.word 105,1,0xA443A858,0x2D1D5AE9,0x00000000,0x77264D6F,0x00000000
.word 106,1,0xE763845E,0x75A2A8D4,0x00000000,0x71C0DB8A,0x00000000
.word 107,1,0x08EDBDAB,0xF9838CB2,0x00000000,0x0F6A30F9,0x00000001
.word 108,1,0xC353D0CD,0x0B03E0C6,0x00000000,0xB84FF007,0x00000000
.word 109,1,0x989A769B,0x54E49EB4,0x00000000,0x43B5D7E7,0x00000000
.word 110,1,0x71F32454,0xACA88611,0x00000000,0xC54A9E43,0x00000001
.word 111,1,0x0836C40E,0x82901D82,0x00000000,0x85A6A68C,0x00000001
.word 112,1,0x3A95F874,0x88138641,0x00000000,0xB2827233,0x00000001
.word 113,1,0x9E7FF521,0x7C3DBD3D,0x00000000,0x224237E4,0x00000000
.word 114,1,0xF37B8DDC,0x6CEAF087,0x00000000,0x86909D55,0x00000000
.word 115,1,0xA2221A70,0xC516DDE9,0x00000000,0xDD0B3C87,0x00000001
.word 116,1,0x3006C83E,0xE14FD4A1,0x00000000,0x4EB6F39D,0x00000001
.word 117,1,0xC19AC241,0xD577F8E1,0x00000000,0xEC22C960,0x00000001
.word 118,1,0xC40BADFC,0x85072367,0x00000000,0x3F048A95,0x00000000
.word 119,1,0xB804823E,0xF7465F01,0x00000000,0xC0BE233D,0x00000001
.word 120,1,0x7724C67E,0x5C482A97,0x00000000,0x1ADC9BE7,0x00000000
.word 121,1,0xA463B9EA,0xDE884ADC,0x00000000,0xC5DB6F0E,0x00000001
.word 122,1,0xD1EAD36B,0xAD517796,0x00000000,0x24995BD5,0x00000000
# mul tests
.word 201,2,0x7FFFFFFF,0x7FFFFFFF,0x00000000,0x00000001,0x3FFFFFFF
.word 202,2,0xFFFFFFFF,0xFFFFFFFF,0x00000000,0x00000001,0xFFFFFFFE
.word 203,2,0x7FFFFFFF,0xFFFFFFFF,0x00000000,0x80000001,0x7FFFFFFE
.word 204,2,0x580BD78F,0x953EA438,0x00000000,0x4850C348,0x33546FCF
.word 205,2,0x3855585C,0x70A64E2A,0x00000000,0xCA948718,0x18C9EF32
.word 206,2,0xEA2342EC,0xAA487CB0,0x00000000,0x97085240,0x9BBDB665
.word 207,2,0x9D4ED43B,0xF25A06FB,0x00000000,0x780177D9,0x94EBD6A0
.word 208,2,0xACD89A32,0x57E4CCAF,0x00000000,0x1579402E,0x3B581783
.word 209,2,0xFA6D8D3C,0x4B588F54,0x00000000,0x7E76DBB0,0x49B4BA3E
.word 210,2,0xD42289EC,0x6DE91B18,0x00000000,0x8B94D220,0x5B13DE9C
.word 211,2,0x38437FDB,0xF644A45C,0x00000000,0xDE563EB4,0x361FF2E9
.word 212,2,0xB2FFF902,0xE84A481A,0x00000000,0xF69BDA34,0xA26BEA11
.word 213,2,0x579478FE,0xF49ABB43,0x00000000,0x4109347A,0x53AE72B3
.word 214,2,0xBDC240FB,0x1BA026FA,0x00000000,0x3B38B71E,0x147A3327
.word 215,2,0x79A1DEAA,0xF5C6C33A,0x00000000,0xC4C3F084,0x74C65A0C
.word 216,2,0x92E685FB,0xF0C6A529,0x00000000,0x0B683C33,0x8A2A1AAD
.word 217,2,0xD20EEDD1,0x374A3FE6,0x00000000,0x0B5A18C6,0x2D5E21D7
.word 218,2,0xCF4EF005,0xA3F9C13C,0x00000000,0xBD51062C,0x84C98315
.word 219,2,0x649BB77C,0x275AC794,0x00000000,0x9B3F77B0,0x0F776621
.word 220,2,0x39386575,0x1CF10FD8,0x00000000,0xE4AC75B8,0x06780CBA
.word 221,2,0x980115BE,0xA35BA861,0x00000000,0x0337ECFE,0x60FF1D35
.word 222,2,0xC7398C89,0xB54FE9F9,0x00000000,0x63296241,0x8D19E134
.word 223,2,0x95B5AF5C,0xF41226BB,0x00000000,0x5836C034,0x8EBBC890
# div tests
.word 301,3,0x8D34B6A8,0x90233C99,0x3F6AB60F,0x40F0FD5A,0x08C7B622
.word 302,3,0xE1574095,0xFE0C57B1,0xF7AE35EB,0xE7225A82,0x15A04AAF
.word 303,3,0xD79BE4F1,0xB10C50B3,0xDFF87E05,0xAA702DE8,0xBA4F4EFB
.word 304,3,0xAF305DEF,0x25A70BF7,0x9DBABF00,0x29D2041D,0x76794399
.word 305,3,0xCAD084E9,0x9F48EAA1,0x9381823A,0xDB0294AB,0x35E90BCB
.word 306,3,0x5DB70AE5,0x100F8FCA,0xE590700B,0x068E768A,0x69540BC4
.word 307,3,0x15014ACB,0xDF5E7FD0,0x098A3148,0xEBD22111,0x0919EC28
.word 308,3,0xF99D0247,0x86B94764,0xC2C296BD,0xACAB02A3,0xA8F32065
.word 309,3,0x968E121F,0x9EBA5D23,0xE61E3F1E,0x67D90FBD,0x42126217
.word 310,3,0xDDC79EA8,0xD40A471C,0x7BD3EE7B,0x7BC55826,0x184F441E
.word 311,3,0xD1D9C564,0xE13EFDC5,0x0BF72B14,0x6E5C254D,0x011EE0F0
.word 312,3,0x91447B73,0x42963E5A,0x8A0382C5,0x46162B2C,0x38DBAF92
.word 313,3,0x88F2B15E,0x9A32234B,0x3B0FD379,0x65899A52,0x24AC49C8
.word 314,3,0xE8EB2F63,0xC962813B,0xE0B6DF70,0xD0BCC3EB,0x65A96301
.word 315,3,0x86A5EE64,0x94330624,0xFFFFCA11,0x4DF2D487,0x2C8C3B19
.word 316,3,0x1A27709E,0xF1EA1109,0x100F59DC,0x89F6B118,0x044FEAEE
.word 317,3,0xFFB7E0AA,0x06EB5BD4,0x6F6DD9AC,0x0FE115CA,0x057B9D10
.word 318,3,0x894211F2,0x00885E1B,0xF6272110,0x004C0A56,0x3BEF0526
.word 319,3,0x4C04A8AF,0x9716703B,0x94E17E33,0x4D251E64,0x1DAB2A69
.word 320,3,0x3222E7CD,0xF4DE0EE3,0xE8EBC550,0x34B53408,0xD8645647
# end of table
.word 0
over_msg: .asciiz "Hmmmm!!! an overflow occured in one register\n"
newline: .asciiz "\n"
equals: .asciiz " ="
space: .asciiz " "
opclist: .asciiz "+-*/"
all_msg: .asciiz "Enter test number (0=all): "
test_msg: .asciiz "\ntest:"
xid_msg: .asciiz " XID: "
rtn_msg: .asciiz "RTN: "
fail_msg: .asciiz "FAIL"
.text
.globl main
main:
li $s6,1 # do signed (with overflow) addition
# get test number
li $v0,4
la $a0,all_msg
syscall
li $v0,5
syscall
blez $v0,testall # run all tests? if yes, fly
# locate test
move $a0,$v0
jal testfind
beqz $v0,main
main_testone:
jal testone
main_exit:
li $v0,10
syscall
# testall -- run diagnostic tests
#
# registers:
# s7 -- test table address
testall:
la $s7,testlist
testall_loop:
jal testone
addiu $s7,$s7,tst_size # advance to next set of test data
j testall_loop
# testfind -- find a specific diagnostic test
#
# RETURNS:
# v0 -- 1=match, 0=fail
#
# arguments:
# a0 -- test number to locate
#
# registers:
# s7 -- test table address
testfind:
la $s7,testlist
li $v0,0
testfind_loop:
lw $t0,tst_xid($s7) # get test number
blez $t0,testfind_done # EOT? if yes, done [failure]
bne $t0,$a0,testfind_next # test number match? if no, fly
li $v0,1 # report success
j testfind_done
testfind_next:
addiu $s7,$s7,tst_size # advance to next set of test data
j testfind_loop
testfind_done:
jr $ra # return
# testone -- run a single diagnostic test
#
# registers:
# s7 -- test table address
testone:
lw $a3,tst_xid($s7) # get test number
blez $a3,main_exit # stop on table end
subiu $sp,$sp,4
sw $ra,0($sp)
li $v0,4
la $a0,test_msg
syscall
# show first number
lw $a0,tst_num1($s7)
jal prtint
li $v0,4
la $a0,space
syscall
# show operation
lw $a3,tst_opc($s7) # get operation code
la $a0,opclist # point to opcode string
addu $a0,$a0,$a3 # index into it to point to char
lb $a0,0($a0) # get the character
li $v0,11 # putc syscall
syscall
# show second number
lw $a0,tst_num2($s7)
jal prtint
li $v0,4
la $a0,equals
syscall
# show expected solution (LSW)
lw $a0,tst_anslsw($s7)
jal prtint
# show expected solution (MSW)
lw $a0,tst_ansmsw($s7)
jal prtint
bne $a3,3,testone_notdiv # show divisor? if no, fly
lw $a0,tst_num3($s7)
jal prtint
testone_notdiv:
li $v0,4
la $a0,xid_msg
syscall
li $v0,1
lw $a0,tst_xid($s7)
syscall
li $v0,4
la $a0,newline
syscall
jal do_math # perform test
move $t0,$v0 # save LSW
move $t1,$v1 # save MSW
li $v0,4
la $a0,rtn_msg
syscall
# show LSW
move $a0,$t0
jal prtint
# show MSW
move $a0,$t1
jal prtint
li $v0,4
la $a0,newline
syscall
lw $t2,tst_anslsw($s7) # get expected result
bne $t0,$t2,testone_fail # stop on failure
lw $t2,tst_ansmsw($s7) # get expected result
beq $t1,$t2,testone_done # match? if yes, done
testone_fail:
# output failure message
li $v0,4
la $a0,fail_msg
syscall
j main_exit
testone_done:
lw $ra,0($sp)
addiu $sp,$sp,4
jr $ra # return
# do_math -- perform math operation
#
# RETURNS:
# v0 -- result
#
# arguments:
# a3 -- operation code
do_math:
subiu $sp,$sp,4
sw $ra,0($sp)
lw $a0,tst_num1($s7)
lw $a1,tst_num2($s7)
lw $a2,tst_num3($s7)
beq $a3,0,math_add
beq $a3,1,math_sub
beq $a3,2,math_mul
beq $a3,3,math_div
j math_done
math_add:
jal do_add
j math_done
math_sub:
jal do_sub
j math_done
math_mul:
jal do_mul
j math_done
math_div:
jal do_div
j math_done
math_done:
lw $ra,0($sp)
addiu $sp,$sp,4
jr $ra # return
# do_add -- perform signed addition
do_add:
li $s6,1
j do_addx
# do_addu -- perform unsigned addition
do_addu:
li $s6,0
j do_addx
# do_addx -- perform add
#
# RETURNS:
# v0 -- sum
# v1 -- 1=overflow/carry out
#
# arguments:
# a0 -- input1
# a1 -- input2
# s6 -- 1=overflow check
#
# registers:
# t9 -- carry bits
do_addx:
subiu $sp,$sp,12
sw $ra,0($sp)
sw $a0,4($sp)
sw $a1,8($sp)
li $v1,0 # say no overflow occurred
bnez $a0,add_loop # no point to adding to zero
move $a0,$a1 # set result
j add_done # fast return
add_loop:
beqz $a1,add_over # more carry in? if no, we're done
and $t9,$a0,$a1 # determining the carry out bits
xor $a0,$a0,$a1 # adding the two numbers without a carry
sll $a1,$t9,1 # shift the carry bits one place left
srl $t9,$t9,31 # overflow is non-zero MSB of carry
or $v1,$v1,$t9 # accumulate overflow
j add_loop
# test for and show overflow
# NOTE: we do _not_ alter a0 so the return value will be okay
add_over:
beqz $v1,add_done # overflow occurred? if no, fly
beqz $s6,add_done # overflow enabled? if no, fly
move $a1,$a0 # save return value
li $v0,4
la $a0,over_msg
syscall
move $a0,$a1 # restore return value
add_done:
move $v0,$a0 # move to return register
lw $ra,0($sp)
lw $a0,4($sp)
lw $a1,8($sp)
addiu $sp,$sp,12
jr $ra # return
# do_sub -- perform sub
#
# RETURNS:
# v0 -- difference
# v1 -- borrow
#
# arguments:
# a0 -- input1
# a1 -- input2
# s6 -- 1=overflow check
#
# registers:
# t8 -- carry bits
# t9 -- overflow
do_sub:
subiu $sp,$sp,12
sw $ra,0($sp)
sw $a0,4($sp)
sw $a1,8($sp)
# get two's complement
nor $a1,$a1,$a1 # flip the bits but number decreases by one
xori $a0,$zero,1 # so ... find the 2s complement
jal do_addu
move $a1,$v0
lw $a0,4($sp)
jal do_addu # to add the user inputs
# set the borrow
lw $a0,4($sp)
lw $a1,8($sp)
sltu $v1,$a0,$a1 # when doing x - y, if x < y, we borrow
lw $ra,0($sp)
lw $a0,4($sp)
lw $a1,8($sp)
addiu $sp,$sp,12
jr $ra # return
# do_mul -- do multiply
#
#@+
# // 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\n");
#
# // 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\n",
# 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\n");
# }
#@-
#
# RETURNS:
# v0 -- LSW of product (zl)
# v1 -- MSW of product (zh)
#
# arguments:
# a0 -- x argument
# a1 -- y argument
#
# registers:
# t0 -- zl (z LSW)
# t1 -- zh (z MSW)
# t2 -- xl (x LSW)
# t3 -- xh (x MSW)
# t4 -- y
# t5 -- cout
do_mul:
subiu $sp,$sp,12
sw $ra,0($sp)
sw $a0,4($sp)
sw $a1,8($sp)
li $t3,0 # xh = 0
move $t2,$a0 # xl = LSW of x
move $t4,$a1 # get local y
li $t0,0 # zl = 0
li $t1,0 # zh = 0
bnez $t2,mul_loop # is x non-zero? if yes, fly
li $t4,0 # no, zero out y to prevent loop
mul_loop:
beqz $t4,mul_done # y != 0? if no, we're done
andi $t5,$t4,1 # y & 1?
beqz $t5,mul_nosum # if no, fly
move $a0,$t0 # zl
move $a1,$t2 # xl
jal do_addu # get zl + xl
move $t0,$v0 # zl += xl
move $t5,$v1 # save cout
move $a0,$t1 # zh
move $a1,$t3 # xh
jal do_addu # get zh + xh
move $t1,$v0 # zh += xh
move $a0,$t1 # zh
move $a1,$t5 # cout
jal do_addu # get zh + cout
move $t1,$v0 # zh += cout
mul_nosum:
srl $t5,$t2,31 # cout = xl >> 31
andi $t5,$t5,1 # cout &= 1
sll $t2,$t2,1 # xl <<= 1
sll $t3,$t3,1 # xh <<= 1
or $t3,$t3,$t5 # xh |= cout
srl $t4,$t4,1 # y >>= 1
j mul_loop # try next round
mul_done:
move $v0,$t0 # rtn = zl
move $v1,$t1 # rtn = zh
lw $ra,0($sp)
lw $a0,4($sp)
lw $a1,8($sp)
addiu $sp,$sp,12
jr $ra # return
# do_div -- perform divide
#
# RETURNS:
# v0 -- quotient
# v1 -- remainder
#
# arguments:
# a0 -- dividend LSW
# a1 -- dividend MSW
# a2 -- divisor
#
do_div:
li $v0,0
li $v1,0
jr $ra # return
# prtint -- print integer (in hex)
#
# arguments:
# a0 -- number to print
prtint:
subiu $sp,$sp,8
sw $v0,0($sp)
sw $a0,4($sp)
li $v0,4
la $a0,space
syscall
lw $a0,4($sp)
li $v0,svc_prtx
syscall
lw $v0,0($sp)
lw $a0,4($sp)
addiu $sp,$sp,8
jr $ra # return
.data
edata: