Monday, April 7, 2014

0003 - Human-readable Numbers in MIPS

For our latest assignment in COMP3410 (where we're using MIPS...see previous post), we're having to implement the Sieve of Eratosthenes in MIPS to count the number of primes between 2 and a given number (in our case, an array of 10, 100, 1,000, 10,000, 100,000, and 1,000,000). Simple enough, right?

The second part of the assignment is to display the given number alongside of the count of prime numbers for the interval [2,i]. Still not difficult. But then...we have to use "human-readable" numbers (i.e. '1,000' instead of '1000').

So, for those poor souls who have a similar task at some point in the future, check out these handy generic procedures for adding commas to your large numbers (see below for more notes):

##########################################################
# this procedure formats our count and max values, then
# prints them to the terminal window
##########################################################
formatOutput:
li $t3, 0 # $t3 is number of bytes written to 'temp'
li $t2, 10 # will be printing 10 leading spaces
jal printBuffer # print the leading spaces
move $s4, $t9 # loading current 'i' from $t9 to $s4
jal printFormat # format and print current 'i'
li $t2, 25 # will be printing 25 spaces between first char of each number
jal printBuffer # print the spaces
move $s4, $s7 # loading current prime count into $s4
jal printFormat # format and print prime count
li $v0, 4 # get ready to print a carriage return
la $a0, cr # move to the next line
syscall # do it now!
li $sp, 0x7fffeffc # reset stack pointer for next 'i'
j initialize # see if there be mo'!

printBuffer:
li $v0, 11 # print string (what is 11 again?)
lb $a0, space # print a space
syscall # do it now!
addi $t3, $t3, 1 # increment our current number of spaces
blt $t3, $t2, printBuffer # loop if we need more spaces to make quota
jr $ra # get back, Jojo!

printFormat:
la $s5, newLine # load address for where we'll be storing formatted string
li $t0, 0 # $t0 = comma counter; add comma every 3
li $t1, 10 # will be dividing by 10 to get number to add to formatted string
li $t2, 0 # will store the remainder after division
li $t3, 0 # resetting $t3
li $t7, 3
j formatChars

formatChars:
div $s4, $t1 # divide number by 10
mfhi $t2 # $t2 is the remainder (last digit)
mflo $s4 # $s1 is the quotient (everything but last digit)
addi $t2, $t2, 0x30 # making the number an ASCII number
addi $t3, $t3, 1 # increment count of bytes used (to make uniform spacing)
sb $t2, ($s5) # storing $t2 as the current byte in the temp space
blt $s4, 1, preComma # if there are no digits left (i.e. 1/10), move on
addi $s5, $s5, 1 # increment address for storing bytes
addi $t0, $t0, 1 # increment comma counter
beq $t0, $t7, addComma # every three passes, add a comma as the next byte
j formatChars

addComma:
lb $t2, comma # loading the comma byte from above
sb $t2, ($s5) # storing the comma byte in the next address inside temp
addi $s5, $s5, 1 # increment address for storying bytes
li $t0, 0 # reset comma counter
addi $t3, $t3, 1 # increment count of bytes used (to make uniform spacing)
j formatChars

preComma:
la $s5, newLine # reloading newLine address to $s5
la $t8, newLine # loading the same address to $t8
add $s5, $s5, $t3 # going to start at the end of the number (bytes were stored in reverse)
subi $s5, $s5, 1 # decrement $s5
j printOut

printOut:
li $v0, 11 # seriously, what is this doing? I forgot...
lb $a0, ($s5) # load the byte from $s5 (next character)
syscall # print that character
addi $s5, $s5, -1 # decrement $s5
blt $s5, $t8, printDone # is $s5 address at newLine address?
j printOut # if not, loop around again

printDone:
jr $ra # return


Obviously, there are some memory addresses referenced above (newLine: .space 15; space: .asciiz " "; cr: .asciiz "\n"; comma: .asciiz ","). Also, you're going to want $t9 and $s7 to reference your numbers (or just change those registers). The fun thing is that you can actually call the printFormat procedure with any number moved into $s4 from anywhere in a program, and it will print out that human-readable format. Boom.