.global fmt_decimal
.global count_digits

.extern clz
.extern divmod

.section .rodata

hexchars:
  .ascii "0123456789ABCDEF"

powers10:
    .word 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000
    .set powers10_end, .

.text

# Write decimal representation of word into buffer
#    arguments:
#       a0: value to format
#       a1: address of buffer to write to
#           buffer must have room for at least 10 bytes
#   temporaries used:
#       t0
#    return:
#       a0: length of string written to buffer
fmt_decimal:
    # until the value is zero:
    #    divmod value by 10
    #    write remainder to output buffer as ASCII char
    #    increment string length
    #    subtract remainder from value
    # if we can know how many digits there will be up front we can write to the buffer
    # in the right order, if not the buffer will have to be reversed at the end
    addi sp, sp, -16
    sw ra, 12(sp)
    sw s1, 8(sp)
    sw s0, 4(sp)
    mv s0, a0         # save value in a0 to s0
    mv s1, a1         # save buffer address to s1
    jal count_digits
    sw a0, 0(sp)      # save digit count to return at the end
    addi a0, a0, -1   # a0 -= 1
    add s1, s1, a0    # add the digit count to the buffer address
1:
    mv a0, s0         # load dividend from s0
    li a1, 10         # set divisor to 10
    jal divmod        # divmod value by 10, a1 = remainder
    mv s0, a0         # move quotent to s0
    addi a1, a1, 0x30 # turn remainder into ASCII digit
    sb a1, 0(s1)      # write the digit to the output buffer
    addi s1, s1, -1   # decrement buffer address
    bnez s0, 1b

    lw a0, 0(sp)      # load digit count into a0
    lw s0, 4(sp)
    lw s1, 8(sp)
    lw ra, 12(sp)
    addi sp, sp, 16
    ret


# Calculate number of decimal digits input word has.
#    arguments:
#       a0: value to count
#    return:
#       a0: count of decimal digits
count_digits:
    mv a2, a0           # a2 = value
    la a1, powers10     # a1 = powers10
    la a4, powers10_end # a4 = powers10_end
    li a0, 0            # a0 = powers array offset * 4
1:
    bgeu a1, a4, 2f     # if a1 >= powers10_end return 10
    lw a3, 0(a1)        # a3 = load value from powers array
    addi a0, a0, 1      # increment offset
    bltu a2, a3, 3f     # if a2 < a3 return
    addi a1, a1, 4      # a1 = index into powers array
    j 1b                # loop
2:
    li a0, 10
3:
    ret