2014-11-09 115 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