Printing an integer with RISC-V

Writing an integer to stdout in RISC-V Assembly.

When working in Assembly Language, you are not getting any short cuts in life. If you want to output a single integer you need to add 48 to it to turn it in to an ASCII numeric character and then output that single character with a system call to the Linux write syscall.

Things get more complicated when you want output a multi-digit integer. First you need to split the number in to individual characters by getting the modulus 10 of the number, add 48 and put that on a stack, then divide the number by 10 and repeat until there are no more digets left in the integer

Finally we pop each ascii number off the stack and send to stdout with a syscall. We loop this action until the stack is empty.

intout.s

#
# Risc-V Assembler program to convert an integer to a string
# and output the result to stdout.
#
# a0-a2 - parameters to linux function services
# a7 - linux function number
#

.data

stack:      .space 1024 # Allocate space for stack
newline:    .asciz "\n" # Newline character

.section .text 
.global _start      # Provide program starting address to linker

.align 2
_start:
   la sp, stack  # set stack pointer
   la a4, stack  # set address of stack to a4
   li a2, 10     # load constant for division
   li a0, 147856790    # load integer to print

convert_loop:
   rem a3, a0, a2     # get remainder
   addi a3, a3, 48    # convert to ascii
   sw a3, 0(sp)       # store in stack
   addi sp, sp, -4    # decrement stack pointer
   div a0, a0, a2     # divide by 10
   bnez a0, convert_loop # loop until a0 is zero

   addi  a0, x0, 1      # 1 = StdOut
   addi  sp, sp, 4      # increment stack pointer to point to the start of the string
   mv    a1, sp         # copy stack pointer to a1
   sub   a2, a4, sp     # calculate length of string
   slli  a2, a2, 2      # multiply length by 4
   addi  a7, x0, 64     # linux write system call
   ecall                # Call linux to output the string

   addi  a0, x0, 1      # 1 = StdOut
   la    a1, newline    # load address of helloworld
   addi  a2, x0, 1      # length of our string
   addi  a7, x0, 64     # linux write system call
   ecall                # Call linux to output the string
   
# Call linux to terminate the program

# Exit the program cleanly
   li a7, 93     # Exit system call for RISC-V
   li a0, 0      # Exit status code
   ecall
		

Assemble and Run

as -mno-relax -o intout.o intout.s
ld -o intout intout.o
./intout
				

Mission Accomplished

And there we have it, you have a printed an integer to stdout. Its feels like alot of code which in C is basically one line, but this is just a step on the journey to understanding RISC-V and getting to a position where you can take advantage of everything that RISC-V can offer.