【问题标题】:Multiplication in MIPS by shifting and adding, without mult在 MIPS 中通过移位和加法进行乘法,无需乘法
【发布时间】:2019-03-27 05:20:41
【问题描述】:

我有以下代码,但我不断收到算术溢出错误。我要解决的问题是将两个 31 位数字相乘并将结果存储在 $t2 $t3 中并打印出正确的结果。看来我已经编码了两个数字相乘,最终结果是一个 31 位数字。

我很想缩小我觉得自己出错的地方,但老实说,我看不出我需要改变的地方和地方。

# program to multiply two 31 bit binary numbers (A & B),

# using the “shift and add” .

.data

# declare the variable lables of ASCII storage type.

prompt1: .asciiz "Enter number 1: "

prompt2: .asciiz "Enter number 2: "

result: .asciiz "The multiplication of two 31 bit binary numbers is: "

.text

主要:

            #prompt1.

            li $v0, 4   

            la $a0, prompt1

            syscall

           #read number 1 and store in the register $t0

            li $v0, 5        

            syscall  

            move $t0, $v0

         

            #prompt2.

            li $v0, 4   

            la $a0, prompt2

            syscall

           

            #read number 2 and store in the register $t1

            li $v0, 5        

            syscall  

            move $t1, $v0

                          

            li $t2, 0 # The final result of the multiplication

                            #is saved into the register $t2

            li $t3, 1 # Mask for extracting bit!

            li $s1, 0 # set the Counter to 0 for loop.   

相乘:

            #if the Counter $s1 is equal to 31, then go the lable exit

            beq $s1, 31, exit

            and $s2, $t1, $t3

            sll $t3, $t3, 1

                    beq $s2, 0, increment

            add $t2, $t2, $t0

增量:

            sll $t0, $t0, 1

            addi $s1, $s1, 1

            j multiply

退出:

            #display the result string.

            li $v0, 4   

            la $a0, result

            syscall

                            #display the result value.

            li $v0, 1

            add $a0, $t2, $zero

            syscall

         

            li $v0, 10 # system call code for exit = 10

            syscall   # call operating sys

示例输入 A:1143330295(十进制) 样本输入 B:999999223(十进制)

【问题讨论】:

  • 您的算法看起来是正确的,但是当您将两个 32 位数字相乘时,结果是 64 位。您可能正在使用 32 位 mips,并且您的算法存在算术溢出。您可以使用 $t3 来存储结果的 lsb 部分,并且在循环中而不是增量移动 $t0,a/ 将 $t2 的 lsb 保留在 $t4 b/ srl $t2 $t2 1srl $t3,$t3,1 c/ 重新注入 lsb $t3 的 msb 中的 $t4 通过将其移动 31 并与 $t3 进行或运算。
  • 我的想法是一样的,将它的一部分存储在 $t3 中以避免错误。我尝试实施您所说的,但我认为我正在修改错误的部分。到目前为止,你一直非常有帮助。我相信你会恨我,但你可以根据你的评论修改它。我好像修改错了。抱歉,我是组装新手,仍然有点模糊,也许如果我将您的思维过程可视化,它会让我更清楚。我将不胜感激。我真的很想了解这个过程是如何运作的。

标签: assembly mips mars-simulator


【解决方案1】:

这是一个可能的实现。

与您的代码的不同之处:

  • 32x32 乘法生成 64 位结果。在 32 位 mips 上,结果必须拆分到两个寄存器中

  • 而不是左移操作数,这将导致溢出,结果是右移。被驱逐的位被保存并在结果的下部重新注入

  • 使用 addu 进行添加。数字是无符号的,没有无符号操作可能会发生溢出

  • 以“do while”形式更改了循环。循环计数器递减

显示的结果目前分为两部分。如果设置了 LSB(并且被 display int 系统调用视为负符号),则可能会出现不正确的显示),但大多数 mips 模拟器无法显示大的无符号。

# program to multiply two 31 bit binary numbers (A & B),
# using the “shift and add” .

.data
# declare the variable lables of ASCII storage type.
prompt1: .asciiz "Enter number 1: "
prompt2: .asciiz "Enter number 2: "
result: .asciiz "The multiplication of two 31 bit binary numbers is: "
result2: .asciiz "\nand the upper part of result is: "

.text
main:
        #prompt1.
        li $v0, 4   
        la $a0, prompt1
        syscall

        #read number 1 and store in the register $t0
        li $v0, 5        
        syscall  
        move $t0, $v0

        #prompt2.
        li $v0, 4   
        la $a0, prompt2
        syscall

        #read number 2 and store in the register $t1
        li $v0, 5        
        syscall  
        move $t1, $v0

        li $t2, 0 # The final result of the multiplication is 64 bits
                  # MSB part is in register $t2
        li $t4, 0 #  and LSB part of result is in $t4
        li $t3, 1 # Mask for extracting bit!
        li $s1, 32 # set the Counter to 32 for loop.   

multiply:
        and $s2, $t1, $t3
        beq $s2, 0, increment
        addu $t2, $t2, $t0

increment:
        sll $t3, $t3, 1 # update mask
        ##sll $t0, $t0, 1 # useless, we srl result instead
        andi $s4, $t2,1  # save lsb of result
        srl $t2,$t2,1    # t2>>=1
        srl $t4,$t4,1    # t4>>=1
        sll $s4,$s4,31
        or  $t4,$t4,$s4  # reinject saved lsb of result in msb of $t4
        addi $s1, $s1, -1 # decrement loop counter
        #if the Counter $s1 reaches 0 then go the label exit
        beq $s1, $zero, exit
        j multiply

exit:
        #display the result string.
        ## must be changed to take into account the 64 bits of the result
        ## but AFAIK, there is no syscall for that
        ## can be done in two steps t4 and t2
        ## and result is t4+2**32*t2
        #display the result value.
        li $v0, 4   
        la $a0, result
        syscall
        li $v0, 1  # if using mars replace 1 by 36 to print as an unsigned
        add $a0, $t4, $zero
        syscall
        li $v0, 4   
        la $a0, result2
        syscall
        li $v0, 1 # if using mars replace 1 by 36 to print as an unsigned
        add $a0, $t2, $zero
        syscall

        li $v0, 10 # system call code for exit = 10
        syscall   # call operating sys

【讨论】:

  • 只需要 32x32 产品的低 32 位是很常见的;大概这就是OP试图实现的。顺便说一句,MIPS 可以用一条指令(bltz)在寄存器的符号位上分支。但它没有循环指令,所以这无助于减少 AND/SLL 开销,除非我们从 MSB 开始(并考虑另一个被乘数从左移 32 开始)。或者,也许您可​​以使用递减计数器作为移位计数来使用可变计数移位。 (但是,当您将所有位移出一个操作数时,您就不能放弃它并跳出循环。)
  • 非常感谢彼得的帮助。每行代码中的 cmets 对我的思考过程产生了奇妙的影响。我不能感谢你。以这种方式处理问题,我感觉好多了。
  • @rdopler:我只评论了 Alain 的回答。如果您认为它足以回答问题,您应该通过单击向上/向下投票箭头下方的复选标记将其标记为“已接受”来感谢他。
猜你喜欢
  • 2011-02-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-26
  • 2015-04-12
相关资源
最近更新 更多