2014-11-09 122 views
1

我一直在研究一個程序在不使用MIPS mult(multu)或div(divu)命令的情況下對兩個32位無符號整數進行乘法運算。 我希望輸出看起來像multu函數一樣,作爲64位高位字/低位字組合。 我一直在使用一個模型,其中乘數是產品的右側像這樣:MIPS 32位無符號乘法,不使用多或div

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

您是否使用過調試器/模擬器來隔離問題? – Jester 2014-11-09 01:56:29

+0

我正在使用PcSpim來模擬程序...我嘗試使用單步執行,但並不確定如何使用它。 除此之外,程序本身不顯示任何錯誤。 – 2014-11-10 07:46:05

回答

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 
+0

謝謝你的代碼工程!我正在看它來試圖理解它爲什麼起作用。我意識到我錯誤地意外地調用了$ s2的lw產品和$ s1的乘數,當時我真的打算叫$ s2硬件產品和$ s1 lw乘數。 我給出的算法是[例子](http://imgur.com/jDIxH2d) 根據那個例子,它應該工作,這只是意味着我的實現一定是錯誤的。 – 2014-11-12 20:59:05

+0

我看到了,這是一種不同的算法,但當然你沒有說前面的話:P無論如何,你的右移需要將高位字的LSB移到低位字的MSB,就像我的左移對面。此外,進位需要插入到MSB中,而不是像您那樣插入到LSB中。 – Jester 2014-11-12 22:19:53