1

This is an assignment. the idea is to prompt the user to:

  1. input the first positive integer
  2. input any one of the operations /,*,-,+
  3. input the second positive integer

Then, call do_math which calls one of:

do_add if operator is +, add the 2 inputs without using add or sub mips instruction and the return the result in a register. return an error condition if there is an overflow.

do_sub if operator is -, subtract the second integer from the first without using sub or add mips instruction (you can call do_add twice) and return result in a register.

do_multiply if operator is *, multiply the two inputs without using add, sub, mult and return result in two registers, one holds most significant 32 bits of product and the other holds the least 32 bits of the product. (which i did not do because i don't know how to extract them)

do_divide if operator is /,divide without using add, sub, mult or div and returning the result in the form X OP Y = Z. where Z is replaced by Q remainder R. Q= QUOTIENT AND R= REMAINDER

Here are my concerns:

first how do i extract the 32 MSB and 32LSB of my product

when i run this code, the error messages are exception occurred at pc=0x004002bc can't expand stack segment by 12 bytes to 1048576 bytes. use -|stack #with > 1048576 unaligned address in instr/data fetch:0x7fffffff

i would really appreciate if someone told me what i am doing wrong and please i am still very new at everything. so be more explicit with your responds. thanks a lot

UPDATE: this is an update of yesterday's code. i think this is better because i do't have the error messages i had yesterday and also my system does not crash everytime i try to run this code. but unfortunately,i does not print the answer i want it to print. after successfully inputting the data, it just stop and nothing happens. can someone please tell me what i am doing wrong. thanks E

PS this code was kindly edited by someone else, with NOTe/BUG or NOTE/FIX. So please don't mind them if you comme across them.

this is my code:

                 .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
TINA15
  • 13
  • 1
  • 10
  • `printanswer` never seems to return (`jr $ra`). And you need to keep in mind that every `jal` modifies `$ra`, so something like `jal printdivans` / `jr $ra` is most likely incorrect. Also, consider what you need to do when e.g. `jal do_add` returns. The CPU doesn't just stop executing your program automatically. You will need to explicitly end your program. – Michael Nov 05 '16 at 13:25
  • Hi Michael thanks for your help. I am not sure what you are saying. If jal printdivans is not the right thing to do, then what would you advise I do. For the printanswer not returning, are you saying I have to put a jr $ra after all the printanswer? Any idea on how to extract the LSB and the MSB? Thanks – TINA15 Nov 05 '16 at 15:16
  • When you use `jal` you're expressing an intent to return to the instruction directly following the `jal` instruction. So any path that your code might take after that `jal` should end with a `jr $ra`. The other thing I was pointing out is that you need be aware that every `jal` modifies the `$ra` register, so you have to be careful about preserving and restoring `$ra` at the right places. Think about what it would mean to have a `jr $ra` directly following a `jal` instruction. Trace the execution using pen and paper if you need to. – Michael Nov 05 '16 at 15:50
  • If you don't feel that you fully understand these basics, then start by writing a much simpler program. Look up every instruction you use in the MIPS instruction set reference (_MIPS32™ Architecture For Programmers Volume II: The MIPS32™ Instruction Set_) and read the descriptions, and step through your code instruction by instruction in SPIM/MARS until you understand exactly what they do. – Michael Nov 05 '16 at 15:51
  • Oh my!! And my system won t stop crashing, and printing the "hmm an overflow occurred" over and over again! Any idea why?Thanks – TINA15 Nov 05 '16 at 18:59
  • Can't expand stack segment by 12 bytes to 524288, use -|stack # with #> 524288 is the message – TINA15 Nov 05 '16 at 19:00

2 Answers2

1

I've annotated your code with as many bugs as I could find with "NOTE/BUG". There are others and some of the bugs repeat themselves in other places.

Note: Because of SO limitations on space, I'm posting a cleaned up and working version in a separate answer that is an addendum to this one.

In particular, some functions were calling functions after the stack frame pop. Or, a function had multiple stack frame pops. These were probably the basis for the runtime exception you were getting.

All functions should have a standard form [of sorts]:

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

For more on good asm style, see my answer: MIPS linked list

It seems that 3 + 4 produces an overflow message, so I'd fix do_add before anything else as its the basis for the other do_* functions.

Also, calling print functions within the calculation functions causes things to get trashed, so the print functions should save/restore any register (e.g. $v0, $a0), so they can be used for debug (i.e. a call to them "does no harm").

Don't know if you're using spim or mars, but I've used both and prefer mars where possible: http://courses.missouristate.edu/KenVollmar/mars/


Anyway, here's the annotated code [please pardon the gratuitous style cleanup]:

    .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

UPDATE #2:

Here is the C program that functions as both as a test data generator and prototype/model. The domul function is the model for the do_mul function in my second answer.

// 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;
}
Community
  • 1
  • 1
Craig Estey
  • 30,627
  • 4
  • 24
  • 48
  • Oh thanks . I will follow your corrections and make a better code. I appreciate it. – TINA15 Nov 05 '16 at 21:02
  • i an not sure what you mean with this update. what does it do please? Thanks for all your help. I worked on my code again and i made some adjustment, hence getting it to run without crashing but unfortunately, i still can't print the answer. here is the new code – TINA15 Nov 06 '16 at 16:28
  • I've downloaded your latest code. The `testall` is a way to run many tests automatically [table driven]. For example, in your original, the overflow test reported false positive for `3 + 4`, so that's part of the test data. Your updated `do_add` broke for a different reason, so I fixed that, adding back the [corrected] overflow test. Rather than merely annotating [with the "ugly" NOTE/BUG], I'm refactoring as I would do for my own code and I'll post the updated version when it's in a more complete state – Craig Estey Nov 06 '16 at 22:32
  • It would help to know what you want for multiply/divide. Are you multiplying two 32 bit numbers to get a 64 bit result? Do you need to print the 64 bit result in _decimal_? Are you trying to do multiply by "shift-and-add" or other algorithm? Likewise for divide--what is the algorithm you're trying to implement? – Craig Estey Nov 06 '16 at 22:44
  • I am trying to multiply two 32 bit numbers and return them in two registers ( the first returns the first 32 bits and the second returns the last 32 bits). I want to display the results in decimal yes. And yes a am suppose to do the mult using add and shift (and/ or call to do_add or do_sub) algorithm, same for division. Thanks so much Craig. – TINA15 Nov 06 '16 at 23:06
  • I've coded up the multiply in C [easy translate to asm]. _Printing_ the 64 bit product in _decimal_ is a bit problematic, however [in hex, it's _easy_]. For divide, I'm prepping for a 64 bit dividend, 32 bit divisor to produce a 32 bit quotient and 32 bit remainder. The dividend would be constructed by entering _two_ 32 bit numbers separately and inputting a _third_ number for the divisor. Actually, it gets cyclical, I think, because the 64 bit print needs a 64 bit divide [AFAICT, so far] – Craig Estey Nov 07 '16 at 09:31
  • ohhh ok i would not mind the product in hexadecimal. the most important thing is that i see how it is done and i understand it. thanks – TINA15 Nov 07 '16 at 11:45
0

Note: Because of SO space limitations, this answer is an addendum to my previous one.

Below is a version of code that has add, sub, and mul working.

The C program that is a test generator and prototype/model is in my original answer [Once again, due to space limitations]


Here is the cleaned up code. Note that I changed the arguments to functions to start with $a0. Also, it is table driven using offsets to implement the equivalent of a C struct. Again, because of space limits, I've had to remove any non-essential code.

Because of the hex output syscall [which spim does not have], this is, for the moment, only valid for mars.

After experimenting, IMO, it's much easier to see the working results in hex than decimal. If needed, the program output could be captured and post processed by a script and have it do the "heavy lifting" to convert two hex numbers into a single 64 bit decimal one.

     .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:
Craig Estey
  • 30,627
  • 4
  • 24
  • 48
  • I had to split this off into a 2nd answer. The division needs a few more support functions (e.g. a 64 bit subtract, a 64 bit shift left, etc.) before being able to code it up – Craig Estey Nov 08 '16 at 04:26