【问题标题】:getting 3 error messages, mips assembly language收到 3 条错误消息,mips 汇编语言
【发布时间】:2017-03-19 05:23:38
【问题描述】:

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

  1. 输入第一个正整数
  2. 输入/,*,-,+任一操作
  3. 输入第二个正整数

然后,调用do_math 调用以下之一:

do_add 如果运算符为 +,则不使用 add 或 sub mips 指令将 2 个输入相加,并将结果返回到寄存器中。如果发生溢出,则返回错误条件。

do_sub 如果运算符为 -,则不使用 sub 或 add mips 指令从第一个整数中减去第二个整数(可以调用 do_add 两次)并将结果返回到寄存器中。

do_multiply 如果运算符为 *,则将两个输入相乘,不使用 add、sub、mult 和 return 结果在两个寄存器中,一个保存乘积的最高有效 32 位,另一个保存乘积的最低 32 位。 (我没有这样做,因为我不知道如何提取它们)

do_divide 如果运算符是 /,不使用 add、sub、mult 或 div 的除法并以 X OP Y = Z 的形式返回结果。其中 Z 被 Q 余数 R 替换。Q= QUOTIENT AND R= REMAINDER

这是我的担忧:

首先我如何提取我产品的 32 MSB 和 32LSB

当我运行此代码时,错误消息是 异常发生在 pc=0x004002bc 无法将堆栈段扩展 12 个字节到 1048576 个字节。使用 -|stack #with > 1048576 instr/data fetch 中未对齐的地址:0x7fffffff

如果有人告诉我我做错了什么,我将不胜感激,并且请我在一切方面仍然很陌生。所以你的回应要更明确。非常感谢

更新:这是昨天代码的更新。我认为这更好,因为我没有昨天的错误消息,而且每次我尝试运行此代码时我的系统都不会崩溃。但不幸的是,我没有打印我想要打印的答案。成功输入数据后,它只是停止,没有任何反应。有人可以告诉我我做错了什么。谢谢E

PS 此代码由其他人友好编辑,带有 NOTE/BUG 或 NOTE/FIX。因此,如果您遇到它们,请不要介意。

这是我的代码:

                 .data
prompt:     .asciiz     "Please enter an integer\n"
message:    .asciiz     "Please enter an operator (+, - , * , / )\n:"
error1:     .asciiz     "invalid arithmetic operation "
err:        .asciiz     "Hmmmm!!! an overflow occured in one register"
newline:    .asciiz     "\n"
remainder:  .asciiz     "remainder"
sorry:      .asciiz     "sorry, division by zero is invalid"
equals:     .asciiz     "="
addition:   .word       43
subtr:      .word       45
multi:      .word       42
divi:       .word       47
input1:     .word       1
input2:     .word       1
    .text

main:
    li      $v0,4                   # system call code for printing a string
    la      $a0,prompt              # string to print
    syscall                         # telling the system to execute the action

    li      $v0,5                   # system call for reading/displaying input
    syscall                         # waits for input,puts input in $v0

    sw      $v0,0($s3)

    li      $v0,4
    la      $a0,message
    syscall

    li      $v0,12                  # code to get and print a char to the screen
    syscall
    move    $a3,$v0                 # putting the chracter in register $a3

    li      $v0,4
    la      $a0,newline
    syscall

    li      $v0,4
    la      $a0,prompt              # get the second integer
    syscall

    li      $v0,5
    syscall

    la      $s4,input2
    sw      $v0,0($s4)


    blez    $s3,main
    blez    $s4,main                # we only want positive integers

jal do_math

do_math:
    move    $a1,$s3
    move    $a2,$s4

    lw      $t0,addition
    beq     $t0,$a3,adding

    lw      $t1,subtr
    beq     $t1,$a3,subtract

    lw      $t2,multi
    beq     $t2,$a3,multiply

    lw      $t3,divi
    beq     $t3,$a3,divide

    li      $v0,4
    la      $a0,error1              # print out the error message
    syscall

    li      $v0,1
    li      $a3,5
    syscall

    j main                  #until we get the corrrect operator
adding:
    jal     do_add
    j       exit                    

subtract:
    jal     do_sub
    j       exit                    

multiply:
    jal     do_multiply
    j       exit                    

divide:
    jal     do_divide
    j       exit                    

exit:
    li      $v0,10
    syscall

do_add:
    addi    $sp,$sp,-12
    sw      $ra,0($sp)
    sw      $a1,4($sp)
    sw      $a2,8($sp)

loop:

    move    $t8, $0
    xor     $a1,$a1,$a2             # adding the two numbers without a carry
    and     $t8,$a1,$a2             # determining the carry bits
    sll     $a2,$t8,1               # shift the carry bits one place left
    bne     $a2, $0, loop           # perform this operation until there are no more carry bits

    jal     printanswer
    move    $a1, $v0   

    lw      $ra,0($sp)
    lw      $a1,4($sp)
    lw      $a2,8($sp)
    addi    $sp,$sp,12
    jr $ra

do_sub:
    addi    $sp,$sp,-12
    sw      $ra,0($sp)
    sw      $a1,4($sp)
    sw      $a2,8($sp)

    nor     $a2,$a2,$a2             # flip the bits but number decreases by one so...
    xori    $a1,$zero,1             # find the 2s complement
    jal     do_add

    move    $a2,$v0
    lw      $a1, 4($sp)
    jal     do_add                  # to add the user inputs
    move    $a1,$v0
    jal     printanswer


    lw      $ra,0($sp)
    lw      $a1,4($sp)
    lw      $a2,8($sp)
    addi    $sp,$sp,12
    jr      $ra

do_multiply:
            beq $a1, $0, done
            beq $a2, $0, done

 addi    $sp,$sp,-12
 sw      $ra,0($sp)
 sw      $a1,4($sp)
 sw      $a2,8($sp)

 sll $a1, $a1, 5           #extend the multiplicant bits to 32 bits
 sll $a2, $a2, 6           #extend the multiplier bits to 64 and it now becomes the product(in the book)

mult_loop:

 move $s0, $0
 xor $s0,$s0,1
 blt $s0, 5,loop1
  j printmult
 loop1:
    andi    $a2,$a2,1               # get the least significant bit and put it in the $a2
    beqz    $a2,then   
    jal do_add
    move $a2, $v0
    srl $a2, $a2, 1
    j mult_loop

printmult:
    jal printansmult 

then:
    srl $a2, $a2, 1
    j mult_loop

    lw      $ra,0($sp)
    lw      $a1,4($sp)
    lw      $a2,8($sp)
    addi    $sp,$sp,12

    jr      $ra
done:
jr $ra
do_divide:
    sll     $a1,$a1,4               # this is going to be our remainder
    sll     $a2,$a2,4               # this is the divisor
    sll     $a3,$a3,3               # this is the quotient

    addi    $sp,$sp,-12
    sw      $ra,0($sp)
    sw      $a1,4($sp)
    sw      $a2,8($sp)
    sw      $a3,12($sp)

counter:
    move    $t6,$0
    xor     $t6,$t6,1
    beq     $t6,17,exit

loopdiv:
    jal     do_sub
    move    $a1,$v0                 # subtract divisor from remainder and put result in remainder

    # getting the msb significant bit
    andi    $t5,$a1,32768
    blt     $t5,$0,quotientupdate
    sll     $a3,$a3,1               # shift quotient left
    ori     $a3,$a3,1               # add one to the least significant bit of quotient
    srl     $a2,$a2,1

    j       counter

    move    $t5,$a3
    move    $t6,$a1
    jal     printdivans
    lw      $ra,0($sp)
    lw      $a1,4($sp)
    lw      $a2,8($sp)
    lw      $a3,12($sp)
    addi    $sp,$sp,16
     jr      $ra

quotientupdate:
    jal     do_add
    move    $a1,$v0
    sll     $a3,$a3,1               # shift quotient left
    ori     $a3,$a3,0               # add zero to the least significant bit of quotient
    srl     $a2,$a2,1

    j       counter
# NOTE/BUG: this is dead/never reached code
    move    $t5,$a3
    move    $t6,$a1 
    jal     printdivans

    lw      $ra,0($sp)
    lw      $a1,4($sp)
    lw      $a2,8($sp)
    lw      $a3,12($sp)
    addi    $sp,$sp,12   
    jr      $ra

printanswer:
    lw  $a1, 4($sp) 
    li  $v0,1
    syscall
    jr      $ra

printansmult:

    la  $a1, 4($sp)
    li  $v0,1

    syscall
    jr $ra

printdivans:

    lw      $a0,input1
    li      $v0,1
    syscall

    la      $a0,divi
    li      $v0,4
    syscall


    li      $v0,1
    la      $a0,input2
    syscall

    li      $v0,4
    la      $a0,equals
    syscall

    li      $v0,1
    la      $a0,4($sp)
    syscall

    li      $v0,4
    la      $a0,remainder
    syscall

    li      $v0,1
    la      $a0,8($sp)
    syscall

【问题讨论】:

  • printanswer 似乎永远不会返回 (jr $ra)。而且你需要记住,每个jal 都会修改$ra,所以像jal printdivans / jr $ra 这样的东西很可能是不正确的。另外,考虑一下你需要做什么,例如jal do_add 返回。 CPU 不仅会自动停止执行您的程序。您需要明确结束您的程序。
  • 嗨,迈克尔,感谢您的帮助。我不确定你在说什么。如果 jal printdivans 不是正确的做法,那么你会建议我做什么。对于 printanswer 没有返回,你是说我必须在所有 printanswer 之后放一个 jr $ra 吗?关于如何提取 LSB 和 MSB 的任何想法?谢谢
  • 当您使用jal 时,您表示打算直接在jal 指令之后返回指令。因此,您的代码在jal 之后可能采用的任何路径都应该以jr $ra 结尾。我要指出的另一件事是,您需要注意每个jal 都会修改$ra 寄存器,因此您必须小心在正确的位置保存和恢复$ra。想想在jal 指令之后直接使用jr $ra 意味着什么。如果需要,请使用笔和纸跟踪执行情况。
  • 如果你觉得你还没有完全理解这些基础知识,那么从编写一个更简单的程序开始。查找您在 MIPS 指令集参考(MIPS32™ 程序员架构第二卷:MIPS32™ 指令集)中使用的每条指令并阅读说明,并在 SPIM/ 中逐条指令执行代码MARS,直到您完全了解它们的作用。
  • 天哪!而且我的系统不会停止崩溃,并且一遍又一遍地打印“嗯,发生溢出”!知道为什么吗?谢谢

标签: assembly mips


【解决方案1】:

我已经用“NOTE/BUG”为您的代码添加了尽可能多的错误注释。还有其他一些错误,其中一些错误在其他地方重复出现。

注意:由于空间有限,我在一个单独的答案中发布了一个经过清理和工作的版本,该答案是这个答案的附录。

特别是,一些函数在堆栈帧弹出后调用了函数。或者,一个函数有多个堆栈帧弹出。这些可能是您得到的运行时异常的基础。

所有函数都应该有一个标准形式 [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

有关良好 asm 风格的更多信息,请参阅我的回答:MIPS linked list

似乎3 + 4 产生了溢出消息,所以我会先修复do_add 作为其他do_* 函数的基础。

此外,在计算函数中调用打印函数会导致数据被丢弃,因此打印函数应该保存/恢复 any 寄存器(例如 $v0$a0),因此它们可以用于调试(即调用它们“没有害处”)。

不知道您使用的是spim 还是mars,但我两者都使用过,如果可能,我更喜欢marshttp://courses.missouristate.edu/KenVollmar/mars/


无论如何,这是带注释的代码[请原谅无偿的样式清理]:

    .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 函数是我的 second 答案中 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;
}

【讨论】:

  • 哦,谢谢。我会按照您的更正并制作更好的代码。我很感激。
  • 我不确定你对这个更新的意思。请问它有什么作用?感谢你的帮助。我再次处理我的代码并进行了一些调整,因此让它运行而不会崩溃,但不幸的是,我仍然无法打印答案。这是新代码
  • 我已经下载了你的最新代码。 testall 是一种自动运行许多测试的方法[表驱动]。例如,在您的原始文件中,溢出测试报告了 3 + 4 的误报,因此这是测试数据的一部分。您更新的do_add 因不同的原因而损坏,所以我修复了这个问题,添加了 [更正后的] 溢出测试。我不只是注释 [使用“丑陋”的 NOTE/BUG],而是像我为自己的代码所做的那样进行重构,当它处于更完整的状态时,我将发布更新的版本
  • 了解您想要乘/除的内容会有所帮助。您是否将两个 32 位数字相乘以获得 64 位结果?您需要以十进制 打印 64 位结果吗?您是否尝试通过“移位加法”或其他算法进行乘法运算?同样对于除法-您要实现的算法是什么?
  • 我正在尝试将两个 32 位数字相乘并将它们返回到两个寄存器中(第一个返回前 32 位,第二个返回后 32 位)。我想以十进制显示结果是的。是的,我假设使用 add 和 shift(和/或调用 do_add 或 do_sub)算法进行 mult,除法相同。非常感谢克雷格。
【解决方案2】:

注意:由于篇幅限制,这个回答是我之前回答的补充。

下面是具有 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:

【讨论】:

  • 我不得不将其拆分为第二个答案。除法需要更多支持函数(例如 64 位减法、64 位左移等)才能对其进行编码
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-08-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-10-18
相关资源
最近更新 更多