Convert Binary to Decimal in MIPS, Assembly MARS

use*_*214 1 assembly base-conversion mips mars-simulator

I am trying to convert binary to decimal in the MIPS language, using the MARS simulator. The program accepts a binary number, and then does the conversion, by multiplying (shift left by the number's place $t9). Another way of saying that is multiplying each 1 digit by 2 raised to the power of the place, and summing that result.

I do not have a very good understanding of how values are stored and communicated between ascii, decimal, and the problem is that the "sum" is coming out to be 40,000 something rather than the value of the binary number in decimal. What am I doing wrong here?

 .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
Run Code Online (Sandbox Code Playgroud)

Jef*_*f E 5

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

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

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

一种更优雅的方法是一次性完成整个事情:假设字符串长度为 16 个字符,包括分隔符(因此,分配16$t9第一个)。假设字符串实际上有 5 个字符长。然后在您的循环之后,总和将高出2^(16-5) = 2^11. 但观察到的终值$t911。因此,您可以通过将和寄存器向右移动$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
Run Code Online (Sandbox Code Playgroud)