得到3条错误消息,mips汇编语言

时间:2016-11-05 13:02:42

标签: assembly mips

这是一项任务。这个想法是为了 提示用户:

  1. 输入第一个正整数
  2. 输入任何一个操作/,*, - ,+
  3. 输入第二个正整数
  4. 然后,拨打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
    

2 个答案:

答案 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),所以他们可以用于调试(即打电话给他们"没有伤害")。

不知道您是否正在使用spimmars,但我已使用过两者并且尽可能选择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: