calculator/fmt.s

83 lines
2.4 KiB
ArmAsm

.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