【问题标题】:Convert Binary to Decimal in MIPS, Assembly MARS在 MIPS、汇编 MARS 中将二进制转换为十进制
【发布时间】:2014-04-26 00:55:07
【问题描述】:

我正在尝试使用 MARS 模拟器将 MIPS 语言中的二进制转换为十进制。 程序接受一个二进制数,然后通过乘法进行转换(左移数字的位置 $t9)。另一种说法是将每个 1 位数字乘以 2 乘以该位的幂,然后将结果相加。

我对值如何在 ascii、十进制之间存储和通信并没有很好的理解,问题是“总和”是 40,000,而不是十进制二进制数的值。我在这里做错了什么?

 .data
  msg1:
    .asciiz "Enter a number in base 2 (-2 to quit): "
  msg2:
    .asciiz "\nResult: "
  allOnes:
    .asciiz "1111111111111111"
  empty:
    .space 16
  newLine:
    .asciiz "\n"
  sum:
    .space 16 
  sumMsg:
    .asciiz "\nSUM: "
  oneFound:
    .asciiz "\nOne found\n"
  zeroFound:
     .asciiz "\nZero found\n"
.text
.globl main
main:

getNum:
li $v0,4        # Print string system call
la $a0,msg1         #"Please insert value (A > 0) : "
syscall

la $a0, empty
li $a1, 16              # load 16 as max length to read into $a1
li $v0,8                # 8 is string system call
syscall

la $a0, empty
li $v0, 4               # print string
syscall

li $t4, 0               # initialize sum to 0

startConvert:
  la $t1, empty
  li $t9, 16                # initialize counter to 16

firstByte:
  lb $a0, ($t1)      # load the first byte
  blt $a0, 48, printSum 
  addi $t1, $t1, 1          # increment offset
  subi $a0, $a0, 48         # subtract 48 to convert to int value
  beq $a0, 0, isZero
  beq $a0, 1, isOne
  j convert     # 

isZero:
   subi $t9, $t9, 1 # decrement counter
   j firstByte

 isOne:                   # do 2^counter 
   li $t8, 1               # load 1
   sllv $t5, $t8, $t9    # shift left by counter = 1 * 2^counter, store in $t5
   add $t4, $t4, $t5         # add sum to previous sum 

   move $a0, $t4        # load sum
   li $v0, 1              # print int
   syscall
   subi $t9, $t9, 1 # decrement counter
   j firstByte

convert:

printSum:
   srlv $t4, $t4, $t9
   la $a0, sumMsg
   li $v0, 4
   syscall

 move $a0, $t4      # load sum
 li $v0, 1      # print int
 syscall

exit:
   li $v0, 10       # exit system call
   syscall

【问题讨论】:

    标签: assembly mips base-conversion mars-simulator


    【解决方案1】:

    一个问题是您每次迭代都会将$t9 递减两次。您应该将第一个减量(减去 48 之后的那个)保留在原处,并删除其他两个。

    另一个问题是,如果您从左到右解析字符串,那么您需要在某些时候考虑字符串的长度。理想情况下,您会将$t9 设置为字符串的长度而不是0(在startConvert 之后的第二行),但我们还不知道字符串的长度。

    一种选择是预先解析字符串以确定其长度,并将$t9 设置为该值。

    更优雅的方法是一次性完成所有操作:假设字符串长度为 16 个字符,包括分隔符(因此,首先将 16 分配给 $t9)。假设字符串实际上是 5 个字符长。然后在你的循环之后,总和将太高2^(16-5) = 2^11。但请注意$t9 的最终值为11。因此,您可以通过将求和寄存器向右移动$t9 多个位来修复错误。

    最后,看起来 MARS 将一个字符 0x0A(这是按 Enter 键)放在字符串的末尾(除非您使用全部 15 个字符;然后它使用 0x00 代替,因为它在第 15 个字符之后自动停止,然后您有机会按 Enter)。所以在beqz 行上,不要与0 比较,而是检查$a0 < 48 是否。这将处理这两种情况,无论分隔符是 0x00 还是 0x0A


    这是我的修复版本:

    .data
      msg1:
        .asciiz "Enter a number in base 2 (-2 to quit): "
      msg2:
        .asciiz "\nResult: "
      allOnes:
        .asciiz "1111111111111111"
      empty:
        .space 16
      newLine:
        .asciiz "\n"
      sum:
        .space 16 
      sumMsg:
        .asciiz "\nSUM: "
      oneFound:
        .asciiz "\nOne found\n"
      zeroFound:
         .asciiz "\nZero found\n"
    .text
    .globl main
    main:
    
    getNum:
    li $v0,4        # Print string system call
    la $a0,msg1         #"Please insert value (A > 0) : "
    syscall
    
    la $a0, empty
    li $a1, 16              # load 16 as max length to read into $a1
    li $v0,8                # 8 is string system call
    syscall
    
    la $a0, empty
    li $v0, 4               # print string
    syscall
    
    li $t4, 0               # initialize sum to 0
    
    startConvert:
      la $t1, empty
      li $t9, 16             # initialize counter to 16
    
    firstByte:
      lb $a0, ($t1)      # load the first byte
      blt $a0, 48, printSum    # I don't think this line works 
      addi $t1, $t1, 1          # increment offset
      subi $a0, $a0, 48         # subtract 48 to convert to int value
      subi $t9, $t9, 1          # decrement counter
      beq $a0, 0, isZero
      beq $a0, 1, isOne
      j convert     # 
    
    isZero:
       j firstByte
    
     isOne:                   # do 2^counter 
       li $t8, 1               # load 1
       sllv $t5, $t8, $t9    # shift left by counter = 1 * 2^counter, store in $t5
       add $t4, $t4, $t5         # add sum to previous sum 
    
       move $a0, $t4        # load sum
       li $v0, 1              # print int
       syscall
       j firstByte
    
    convert:
    
    printSum:
       srlv $t4, $t4, $t9
    
       la $a0, sumMsg
       li $v0, 4
       syscall
    
     move $a0, $t4      # load sum
     li $v0, 1      # print int
     syscall
    
    exit:
       li $v0, 10       # exit system call
       syscall
    

    【讨论】:

    • 感谢您的想法,我很感激。我实施了您关于右移等的建议,尽管对于我正在使用的示例,总和现在在正确的范围内,但它仍然会产生不正确的输出。我将尝试通读字符串以确定接下来的长度。有没有办法从右到左解析字符串?
    猜你喜欢
    • 2017-04-12
    • 2014-05-24
    • 2014-07-20
    • 2016-10-16
    • 2015-05-29
    • 2015-06-02
    • 2015-02-04
    • 2012-06-02
    • 2015-01-28
    相关资源
    最近更新 更多