我正在尝试使用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
答案 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