MIPS 32位无符号乘法,不使用mult或div

时间:2014-11-09 01:25:33

标签: assembly mips multiplication unsigned

我一直在研究一个程序,它使两个32位无符号整数相乘而不使用MIPS mult(multu)或div(divu)命令。 我希望输出看起来就像multu函数一样,作为一个64位高字/低字组合。 我一直在使用模型,乘数是产品的右侧,因为:

for (i=0; i<32; i++)
{
   if LSB(multiplier)==1
   {
       LH product += multiplicand;
   }
   right shift product-multiplier 1;
}

目前在我的代码中,我不确定我是否正在正确处理32位加法中的可能进位位。

无论我选择操作什么整数值,我目前的输出都是“0 0”。

在我的代码中,我调用最右边的LSB(低位字),最左边的MSB(高位字)。

我的代码:

.data

    promptStart:    .asciiz "This prrogram does AxB without using mult or div"
           getA:    .asciiz "Please enter the first number(multiplicand): "
           getB:    .asciiz "Please enter the second number(multiplier): "

          space:    .asciiz " "

         result:    .asciiz "The product, using my program is: "
         mipMult:   .asciiz "The product, using MIPs multu is: "

       endLine: .asciiz "\n"

.text

main:
    #"welcome" screen
    li  $v0,4           # code for print_string
    la  $a0,promptStart     # point $a0 to prompt string
    syscall             # print the prompt


    li  $v0,4           # code for print_string
    la  $a0,endLine     # point $a0 to prompt string
    syscall             # print the prompt

    #prompt for multiplicand
    li  $v0,4           # code for print_string
    la  $a0,getA        # point $a0 to prompt string
    syscall             # print the prompt

    #acquire multiplicand
    li  $v0,5           # code for read_int
    syscall             # get an int from user --> returned in $v0
    move    $s0,$v0         # move the resulting int to $s0

    move    $s4,$s0         #copy of multiplicand to use in multu

    #prompt for multiplier
    li  $v0,4           # code for print_string
    la  $a0,getB        # point $a0 to prompt string
    syscall             # print the prompt

    #acquire multiplier
    li  $v0,5           # code for read_int
    syscall             # get an int from user --> returned in $v0
    move    $s1,$v0         # move the resulting int to $s0

    move    $s5,$s1         #copy of multiplier to use in multu 

    jal MyMult
    j   print

MyMult:

    #$s2 -> lw product, $s1 -> hw multiplier, $s0 -> multiplicand

    beq $s1, $0, done       # if multiplier=0--> mult gives 0
    beq $s0, $0, done

    move    $t0, $0         #initialize 'counter'= 31
    add $t0, $t0, 31

    move    $s2, $0         #initialize product = 0

    loopOut:
        beq $t0, $0, done   #loop check

        andi    $t1, $s1, 1 #Stores LSB(MSB?) of $s1 in $t1
        bne $t1, $0, loopIn #check if LSB is equal to 1
        srl $s1, $s1, 1
        srl $s2, $s2, 1 #right shift product & multiplier

        add $t0, $t0,-1 # counter = counter -1
        j   loopOut

    loopIn:
        addu    $s2, $s2, $s0   #Lw product($s2/$s1)+= multiplicand($s0)
        sltu    $t2, $s2, $s0   #catch carry-out(0 or 1) and stores in $t2      

        srl $s1, $s1, 1
        srl $s2, $s2, 1 #right shift pro-plier..how to save LSB of $s2?

        #add carry-out $t2 to LSB of product $s2
        addu    $s2, $s2, $t0   #Is this right?

        addu    $t0, $t0,-1 # counter = counter -1
        j   loopOut

    done:
        jr $ra

print:
    # print result string
    li  $v0,4           # code for print_string
    la  $a0,result      # point $a0 to string
    syscall             # print the result string

    # print out the result
    li  $v0,1           # code for print_int
    move    $a0,$s2         # put result in $a0
    syscall             # print out result

    li  $v0,4           # code for print_string
    la  $a0,space       # point $a0 to string
    syscall             # print the result string

    li  $v0,1           # code for print_int
    move    $a0,$s1         # put result in $a0
    syscall             # print out result


    # print the line feed
    li  $v0,4           # code for print_string
    la  $a0,endLine     # point $a0 to string
    syscall             # print the linefeed

doMult:
#Do same computation using Mult
    multu   $s4, $s5
    mfhi    $t0
    mflo    $t1

    li  $v0,4           # code for print_string
    la  $a0,mipMult     # point $a0 to string
    syscall 

    # print out the result
    li  $v0,1           # code for print_int
    move    $a0,$t0         # put high in $a0
    syscall             # print out result

    li  $v0,4           # code for print_string
    la  $a0,space       # point $a0 to string
    syscall             # print the result string

    # print out the result
    li  $v0,1           # code for print_int
    move    $a0,$t1         # put low in $a0
    syscall             # print out result

    # print the line feed
    li  $v0,4           # code for print_string
    la  $a0,endLine     # point $a0 to string
    syscall             # print the linefeed

    # All done, thank you!
    li  $v0,10          # code for exit
    syscall             # exit program

1 个答案:

答案 0 :(得分:3)

据我所知,即使你的算法也被打破了。您应该将被乘数向左移动(用于加法),将因子移到右侧(用于位测试)。产品不应该转移。此外,被乘数需要扩展到64位,并且需要64位移位才能正确地在字边界上传输位。

.data

    promptStart:    .asciiz "This program does AxB without using mult or div"
           getA:    .asciiz "Please enter the first number(multiplicand): "
           getB:    .asciiz "Please enter the second number(multiplier): "

          space:    .asciiz " "

         result:    .asciiz "The product, using my program is: "
         mipMult:   .asciiz "The product, using MIPs multu is: "

       endLine: .asciiz "\n"

.text

main:
    #"welcome" screen
    li  $v0,4           # code for print_string
    la  $a0,promptStart # point $a0 to prompt string
    syscall             # print the prompt


    li  $v0,4           # code for print_string
    la  $a0,endLine     # point $a0 to prompt string
    syscall             # print the prompt

    #prompt for multiplicand
    li  $v0,4           # code for print_string
    la  $a0,getA        # point $a0 to prompt string
    syscall             # print the prompt

    #acquire multiplicand
    li  $v0,5           # code for read_int
    syscall             # get an int from user --> returned in $v0
    move    $s0,$v0     # move the resulting int to $s0
    move    $s5,$s0     # copy of multiplicand to use in multu

    #prompt for multiplier
    li  $v0,4           # code for print_string
    la  $a0,getB        # point $a0 to prompt string
    syscall             # print the prompt

    #acquire multiplier
    li  $v0,5           # code for read_int
    syscall             # get an int from user --> returned in $v0
    move    $s1,$v0     # move the resulting int to $s0

    move    $s6,$s1     # copy of multiplier to use in multu

    jal MyMult
    j   print

MyMult:
    move $s3, $0        # lw product
    move $s4, $0        # hw product

    beq $s1, $0, done
    beq $s0, $0, done

    move $s2, $0        # extend multiplicand to 64 bits

loop:
    andi $t0, $s0, 1    # LSB(multiplier)
    beq $t0, $0, next   # skip if zero
    addu $s3, $s3, $s1  # lw(product) += lw(multiplicand)
    sltu $t0, $s3, $s1  # catch carry-out(0 or 1)
    addu $s4, $s4, $t0  # hw(product) += carry
    addu $s4, $s4, $s2  # hw(product) += hw(multiplicand)
next:
    # shift multiplicand left
    srl $t0, $s1, 31    # copy bit from lw to hw
    sll $s1, $s1, 1
    sll $s2, $s2, 1
    addu $s2, $s2, $t0

    srl $s0, $s0, 1     # shift multiplier right
    bne $s0, $0, loop

done:
    jr $ra

print:
    # print result string
    li  $v0,4           # code for print_string
    la  $a0,result      # point $a0 to string
    syscall             # print the result string

    # print out the result
    li  $v0,1           # code for print_int
    move    $a0,$s4     # put result in $a0
    syscall             # print out result

    li  $v0,4           # code for print_string
    la  $a0,space       # point $a0 to string
    syscall             # print the result string

    li  $v0,1           # code for print_int
    move    $a0,$s3     # put result in $a0
    syscall             # print out result


    # print the line feed
    li  $v0,4           # code for print_string
    la  $a0,endLine     # point $a0 to string
    syscall             # print the linefeed

doMult:
#Do same computation using Mult
    multu   $s5, $s6
    mfhi    $t0
    mflo    $t1

    li  $v0,4           # code for print_string
    la  $a0,mipMult     # point $a0 to string
    syscall

    # print out the result
    li  $v0,1           # code for print_int
    move    $a0,$t0         # put high in $a0
    syscall             # print out result

    li  $v0,4           # code for print_string
    la  $a0,space       # point $a0 to string
    syscall             # print the result string

    # print out the result
    li  $v0,1           # code for print_int
    move    $a0,$t1         # put low in $a0
    syscall             # print out result

    # print the line feed
    li  $v0,4           # code for print_string
    la  $a0,endLine     # point $a0 to string
    syscall             # print the linefeed

    # All done, thank you!
    li  $v0,10          # code for exit
    syscall             # exit program