Assembly 不使用mult或div的32位无符号乘法
我一直在编写一个程序,它不使用MIPS mult(multu)或div(divu)命令,而是将两个32位无符号整数相乘。 我希望输出看起来就像multu函数一样,是一个64位高字/低字组合。 我一直在使用一个模型,其中乘数是产品的右侧,因此:Assembly 不使用mult或div的32位无符号乘法,assembly,mips,multiplication,unsigned,Assembly,Mips,Multiplication,Unsigned,我一直在编写一个程序,它不使用MIPS mult(multu)或div(divu)命令,而是将两个32位无符号整数相乘。 我希望输出看起来就像multu函数一样,是一个64位高字/低字组合。 我一直在使用一个模型,其中乘数是产品的右侧,因此: for (i=0; i<32; i++) { if LSB(multiplier)==1 { LH product += multiplicand; } right shift product-multiplie
for (i=0; i<32; i++)
{
if LSB(multiplier)==1
{
LH product += multiplicand;
}
right shift product-multiplier 1;
}
据我所知,连你的算法都坏了。您应该将被乘数向左移动(用于加法),将因子向右移动(用于位测试)。产品不应移动。此外,被乘数需要扩展到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
您是否使用调试器/模拟器来隔离问题?我使用PcSpim来模拟程序…我尝试使用单步执行,但不确定如何使用它。除此之外,程序本身没有显示任何错误。谢谢你的代码!我正在研究它,试图理解它为什么有效。我意识到我无意中将$s2称为lw乘积,将$s1称为hw乘数是一个错误,而我真正想将$s2称为hw乘积,将$s1称为lw乘数。我给出的算法是根据那个例子演示的,它应该可以工作,这意味着我的实现一定是错误的。我明白了,这是一个不同的算法,但你当然没有这么说:P无论如何,右移需要将高位字的LSB移到低位字的MSB,就像我的左班车做的相反。此外,进位需要插入MSB,而不是像您那样插入LSB。
.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