Reputation: 135
I was just wondering, is there any way in MIPS to store a summation of numbers as a string and later read them byte by byte, for example:
the sum 657 -> sw into a .ascii directive -> later lb on the first index to get 6 (in ascii code) same with 5 and so on. Is this possible?
Upvotes: 1
Views: 13852
Reputation: 26646
Here's another implementation, factored into utoa
for unsigned integers, and itoa
for signed integers that uses utoa
. These provide two return values, one is the address of the string to print, and the other is a count of the number of characters in the string to print — this count is helpful when using file I/O syscalls. The string buffer (of at least 12 characters in length) is passed in as parameter, so can be a global, or on the stack as the test main
illustrates.
.text
j main # jump around functions, start at main for testing itoa
# function utoa ( unsigned int, char* ) returns struct { char *, int }
# a0, unsigned number to convert to sring
# a1, pointer to free space large enough to hold integer as string (at least 11 bytes)
# v0, pointer to the beginning of the converted string
# v1, count of number of characters in the string
utoa:
addiu $a1, $a1, 11 # move to the end of the buffer
sb $0, ($a1) # null terminator (sometimes helpful not always necessary)
li $t0, 10
li $v1, 0
utoaLoop:
div $a0, $t0 # divide by 10
mfhi $t2 # remainder is digit to print
addiu $a1, $a1, -1 # back up one byte's worth
addi $t2, $t2, '0' # convert numeric digit to ascii digit
sb $t2, ($a1) # store in buffer
addi $v1, $v1, 1 # increment counter of how many characters
mflo $a0 # capture quotient
bnez $a0, utoaLoop # quotient not zero, so repeat to get another digit
move $v0, $a1 # return pointer to start of character string
# note: $v1 holds count of number of characters in string
# the string is null terminated (but the null is not counted)
jr $ra
# function itoa ( int, char* ) returns struct { char *, int }
# a0, signed number to convert to sring
# a1, pointer to free space large enough to hold integer as string (at least 12 bytes)
# v0, pointer to the beginning of the converted string
# v1, count of number of charactes in the string
# itoa calls utoa (using tco if the number is positive),
# and otherwise prepends a '-' to the string.
itoa:
bltz $a0, ineg
j utoa # tail call optimization
ineg:
addiu $sp, $sp, -4 # space for our return address
sw $ra, ($sp)
neg $a0, $a0 # negate number and convert as unsigned
jal utoa
addiu $v0, $v0, -1 # prepend a '-' character
li $t0, '-'
sb $t0, ($v0)
addi $v1, $v1, 1 # and increment character count
lw $ra, ($sp)
addiu $sp, $sp, 4
jr $ra
# a simple main for testing itoa
main:
addiu $sp, $sp, -64 # create some stack space
li $a0, 1234 # number to print
move $a1, $sp
jal itoa
move $a0, $v0 # return 1: where to print
move $s0, $v1 # return 2: how many chars to print
li $v0, 4
syscall
li $a0, '\n'
li $v0, 11
syscall
move $a0, $s0
li $v0, 1
syscall
li $a0, '\n'
li $v0, 11
syscall
li $a0, -1234
move $a1, $sp
jal itoa
move $a0, $v0 # return 1: address of string to print
move $s0, $v1 # return 2: how many chars to print
li $v0, 4
syscall
li $a0, '\n'
li $v0, 11
syscall
move $a0, $s0
li $v0, 1
syscall
li $a0, '\n'
li $v0, 11
syscall
li $v0, 10
syscall
Upvotes: 0
Reputation: 9671
Of course. The ".ascii" directive is none but a .byte directive focused on the storage of ASCII text
.ascii "PP"
is like
.byte 80,80
You can use .space
to make room for your ASCII string, and then use the buffer in the convertion from integer to ASCII, if you mean this by "sw into .ascii directive" of in integer. The following code converts the "binary number" into a ASCII string using itoa and prints it (just for testing) with print_string. The function uses a buffer and returns the pointer to the first ASCII digit usable for printing. This could be used as a first helper function for a sprintf-like function implementation.
.data
buffer:
.space 32
.text
# the main supposes env. like spim or MARS
main:
li $a0, 1234 # a number
jal itoa
move $a0, $v0
li $v0, 4 # print_string
syscall
li $v0, 10
syscall # exit
itoa:
la $t0, buffer+30 # pointer to almost-end of buffer
sb $0, 1($t0) # null-terminated str
li $t1, '0'
sb $t1, ($t0) # init. with ascii 0
li $t3, 10 # preload 10
slt $t2, $a0, $0 # keep the sign
beq $a0, $0, iend # end if 0
bgtz $a0, loop
neg $a0, $a0 # absolute value (unsigned)
loop:
div $a0, $t3 # a /= 10
mflo $a0
mfhi $t4 # get remainder
add $t4, $t4, $t1 # convert to ASCII digit
sb $t4, ($t0) # store it
subu $t0, $t0, 1 # dec. buf ptr
bne $a0, $0, loop # if not zero, loop
addiu $t0, $t0, 1 # adjust buf ptr
iend:
beq $t2, $0, nolz # was < 0?
addiu $t0, $t0, -1
li $t1, '-'
sb $t1, ($t0)
nolz:
move $v0, $t0 # return the addr.
jr $ra # of the string
After you have $v0 in the main, lb R, ($v0)
picks "1", lb R, 1($v0)
picks second digit (2) and so on; remember the string is null-terminated, so if you pick 0 (numeric), you have to stop
Upvotes: 2
Reputation: 21
I believe there is a flaw in ShinTakezou's answer. The line neg $a0, $a0 will convert the positive number to negative, which results in a weird output for the code. If we remove this line. The codes work fine for positive integer
Upvotes: 2