Given a pointer to the end of a large-enough buffer in $a1
, and an input integer in $a0
, this function stores ASCII digits to form a string.
This uses an AND to extract the low bit. It works from low to high bits, so we store backwards from the end of a buffer, leaving an ASCII string in printing order.
.globl to_base2_end # args: (unsigned a, char *buf_end)
to_base2_end:
# Runs at least once, so we get "0" instead of the empty string for 0
.loop: # do {
andi $t0, $a0, 1 # extract the low bit
ori $t0, $t0, '0' # ASCII digit
addiu $a1, $a1, -1
sb $t0, ($a1) # *--buf = ASCII digit
srl $a0, $a0, 1 # a0 >>= 1
bne $a0, $zero, .loop # }while (a0!=0);
move $v0, $a1 # return pointer to the first digit
jr $ra
Note that this decrements before the first store, so you could pass it a pointer to a '\n'
at the end of a buffer.
You can of course inline this loop instead of using it as a callable function. It stops when the integer is zero instead of looping a fixed 32 times, so it doesn't print leading zeros.
This algorithm is the base2 special case of the basic
do { digit = a % base; } while(a /= base);
.
If you're going to print the digits in the order they're generated, you can use
slt $t0, $a0, $zero # t0 = 0 or 1 = high bit of a0
sll $a0, $a0, 1
This would give you a branchless version of @JeffE's code. But if you care about efficiency, one system call that writes a whole string is much more efficient than 32 system calls to write 32 integers. (And of course real OSes don't have write-int system calls; that's a Mars/SPIM thing.)