Files
riscv-cat/src/mod.S
T
2026-09-15 11:28:07 -04:00

231 lines
5.7 KiB
ArmAsm

.data
line_count: .space 6
.section .text
.globl add_endings, add_line_numbers, zero_line_count
# Print to stdout while adding "$" characters.
# @param[in] a0: ptr to null-terminated str.
# @param[in] a1: length of str.
# @param[in] a2: mod buf addr.
# @param[out] a0: result code.
# @param[out] a1: bytes written to mod buf.
add_endings:
addi sp, sp, -72
sd s7, 64(sp)
sd s6, 56(sp)
sd s5, 48(sp)
sd s4, 40(sp)
sd ra, 32(sp)
sd s3, 24(sp)
sd s2, 16(sp)
sd s1, 8(sp)
sd s0, 0(sp)
mv s0, a0 # put the str buf ptr in s0
mv s1, a1
li s2, 0 # set the str buf char counter to 0
li s3, 0 # set the mod buf char counter to 0
mv s5, a2
.LEndingsProcessChunk:
add s4, s0, s2 # Calculate the offset address
lb t6, 0(s4)
li t4, 0xA # newline
bne t6, t4, 1f # if the current byte is not a newline, skip to writing
add s4, s5, s3 # s4 = mod buf[s2]
li t5, '$'
sb t5, 0(s4) # mod buf[s2] = $
li t5, '\n'
addi s4, s4, 1
sb t5, 0(s4) # mod buf[s2] = \n
addi s3, s3, 2
j 2f
1:
add s4, s5, s3 # s4 = mod buf[s2]
sb t6, 0(s4) # mod buf[s2] = t6
addi s3, s3, 1 # inc mod buf pointer
2:
addi s2, s2, 1 # inc str buf pointer
blt s2, s1, .LEndingsProcessChunk
li a0, 0
mv a1, s3
ld s0, 0(sp)
ld s1, 8(sp)
ld s2, 16(sp)
ld s3, 24(sp)
ld ra, 32(sp)
ld s4, 40(sp)
ld s5, 48(sp)
ld s6, 56(sp)
ld s7, 64(sp)
addi sp, sp, 72
ret
# Prefix newlines with ######+TAB line count
# @param[in] a0: ptr to null-terminated str.
# @param[in] a1: length of str.
# @param[in] a2: mod buf addr.
# @param[in] a3: skip empty.
# @param[out] a0: result code.
# @param[out] a1: bytes written to mod buf.
add_line_numbers:
addi sp, sp, -72
sd s7, 64(sp) #unused
sd s6, 56(sp) # mod buf ptr
sd s5, 48(sp) # mod buf bp
sd s4, 40(sp) # str buf ptr
sd ra, 32(sp)
sd s3, 24(sp) # mod buf offset
sd s2, 16(sp) # str buf offset
sd s1, 8(sp) # len of str
sd s0, 0(sp) # str buf addr
mv s0, a0 # put the str ptr in s0
mv s1, a1 # move length of str into s1
li s2, 0 # set the str buf char offset to 0
li s3, 0 # set the mod buf char offset to 0
mv s5, a2 # move mod buf addr into s5
# there is always one line number at the very start
call _inc_line_count
li t2, 0 # lc char buf offset
li t3, 6 # lc char buf max offset
la t1, line_count # load the line count buffer addr
add s6, s5, s3 # update mod buf + offset addr
4:
add t4, t1, t2
lb t5, 0(t4)
sb t5, 0(s6) # mod buf[s4] = t4
addi t2, t2, 1
addi s3, s3, 1
add s6, s5, s3 # update mod buf + offset addr
blt t2, t3, 4b
li t5, 0x9 # tab character
sb t5, 0(s6)
addi s3, s3, 1
.LLineNumbersProcessChunk:
add s4, s0, s2 # Calculate the offset address
lb t6, 0(s4)
li t4, 0xA # newline
bne t6, t4, 1f # if the current byte is not a newline, skip to writing
mv t0, s2
addi t0, t0, 1 # move ahead one char and see if EOF
bge t0, s1, 1f # if the newline is at the veyr end, we don't indicate a new line number
call _inc_line_count
addi s3, s3, 1 # we want the ptr at the spot right after the newline
add s6, s5, s3 # update mod buf + offset addr
li t2, 0 # lc char buf offset
li t3, 6 # lc char buf max offset
la t1, line_count # load the line count buffer addr
li t5, 0xA # newline character
sb t5, 0(s6)
addi s3, s3, 1
add s6, s5, s3 # update mod buf + offset addr
3:
add t4, t1, t2
lb t5, 0(t4)
sb t5, 0(s6) # mod buf[s4] = t4
addi t2, t2, 1
addi s3, s3, 1
add s6, s5, s3 # update mod buf + offset addr
blt t2, t3, 3b
li t5, 0x9 # tab character
sb t5, 0(s6)
addi s3, s3, 1
j 2f
1:
add s6, s5, s3 # s4 = mod buf[s2]
sb t6, 0(s6) # mod buf[s2] = t6
addi s3, s3, 1 # inc mod buf pointer
2:
addi s2, s2, 1 # inc str buf pointer
blt s2, s1, .LLineNumbersProcessChunk
li a0, 0
mv a1, s3
ld s0, 0(sp)
ld s1, 8(sp)
ld s2, 16(sp)
ld s3, 24(sp)
ld ra, 32(sp)
ld s4, 40(sp)
ld s5, 48(sp)
ld s6, 56(sp)
ld s7, 64(sp)
addi sp, sp, 72
ret
# Increment the line count string
# @param[in] a0: not used
# @param[out] a0: result code
_inc_line_count:
la t0, line_count # load the line count buffer address
li t1, 5 # current offset, we move from right to left first
.LIncLine:
bltz t1, .LLineCountDoneInc
add t2, t0, t1 # load the correct offset address into t2
lb t3, 0(t2) # load the current ascii character into t3
li t4, 32 # load space character
bne t3, t4, .LLineCountNotSpaceChar # if the character is not a space, skip setting to zero
li t4, 48 # ascii '0'
sb t4, 0(t2) # store this at the current pointer
.LLineCountNotSpaceChar:
add t2, t0, t1 # load the correct offset address into t2
lb t3, 0(t2) # load the current ascii character into t3
li t4, 58 # ascii ':', right after ascii '9', overflow
addi t3, t3, 1
beq t3, t4, .LLineCountOverflow
sb t3, 0(t2)
j .LLineCountDoneInc
.LLineCountOverflow:
li t4, 48 # ascii '0'
sb t4, 0(t2) # store that ascii '0'
li t4, 1
sub t1, t1, t4 # move to the next digit to the left
j .LIncLine
.LLineCountDoneInc:
ret
# Set the line count to all space characters
# @param[in] a0: not used
# @param[out] a0: result code
zero_line_count:
la t0, line_count # load the line count buffer address
li t1, 0 # char ptr
li t2, 6 # max char
li t3, 32 # space character
1:
add t4, t0, t1 # load offset addr
sb t3, 0(t4) # store the space char in offset addr
addi t1, t1, 1
blt t1, t2, 1b
li a0, 0
ret