An Introduction to Imperative Programming

Section3.1Number Conversion

The first example strengthens our skills in some low-level bit fiddling. We have already seen that we can use a simple sys call (see Section A.2) to print the contents of a register in decimal numbers. In this section, we want to write a procedure that prints the 32-bit contents of a register hexadecimally. To this end, we recall that one hexadecimal digit can represent exactly four bits. So a 32-bit register content can nicely be represented by 8 hexadecimal digits.
The idea for our program is to extract four-bit packets out of the register from most significant to least significant, one after another. For each “packet”, we convert the four bits into the respective ASCII code 6  of the character of the hexadecimal digit and print it.
For example, the four bits 1011 represent the number 11 and have the hexadecimal digit b. The ASCII code for the letter “b” is 98.
A brief look into an ASCII table reveals that the ASCII codes of decimal digits start at 48 and lower-case letters start at 97.
Let us focus first on the code that extracts the four bits and converts them into the ASCII character of the corresponding hexadecimal digit.
loop:
srlv  $a0$t0 $t1 andi$a0 $a0 15 sltiu$t3 $a0 10 bnez$t3 smaller10
addiu $a0$a0 39
smaller10:
addiu $a0$a0 48

Run
We assume here that the word to print is in register $t0. The first instruction is a shift that shifts the word to print down by $t1 bits. $t1 is supposed to index the four bit packets in the word and will assume the values 28, 24, 20, ..., 0 during the course of execution. To this end we will setup a loop later. Now, the shifts brings the four bits to be printed “down” so that the least significant bit of the packet is at bit position 0 of $a0. Since there may be several set bits in $t0 above the four bits we want to print, we need to clear all bits beyond bit 3 by and-ing with 15. Now, $a0 contains the four bits to print with the LSB at position 0.
The remaining code checks, if the four bits represent a value smaller than 10 in which case we want to compute the ASCII code of the corresponding decimal digit. This is done by the addiu instruction labeled smaller10. The branch at line 13 branches there if the four bits are smaller 10. If this is not the case, the branch “falls through” and the addiu with 39 is also executed. In that case, $a0 contains a value $$x$$ between 10 and 15 (including) and $$39+48+x=87+x$$ which gives the ASCII code for the lower-case hexadecimal letter representing the values between 10 and 15. Finally, we put a loop around this piece of code to iterate through all packets in $t0. The following listing shows the final version of the code with some main routine to test it.
     .data
msg:
.asciiz "Enter a number: "
.text
print_hex:
move  $t0$a0
li    $t1 28 li$v0 11
loop:
srlv  $a0$t0 $t1 andi$a0 $a0 15 sltiu$t3 $a0 10 bnez$t3 smaller10
addiu $a0$a0 39
smaller10:
addiu $a0$a0 48
syscall
addiu $t1$t1 -4
check:
bgez  $t1 loop jr$ra

main:
.globl main
la    $a0 msg li$v0 4
syscall
li    $v0 5 syscall move$a0 $v0 jal print_hex li$v0, 10
syscall

Run