在MIPS,汇编MARS中将二进制转换为十进制

时间:2014-04-25 01:10:28

标签: assembly mips base-conversion mars-simulator

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

我不太清楚如何在ascii,decimal之间存储和传递值,问题是“sum”是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

1 个答案:

答案 0 :(得分:3)

一个问题是每次迭代你减少$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