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)
一个问题是您$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
Run Code Online (Sandbox Code Playgroud)