A0 01 84 97 88 84 9E 84 9F B1 FB F0 20 A4 9F 91 FD C6 97 D0 10 A6 FF CA F0
05 C8 91 FD D0 F8 84 9F A5 FF 85 97 E6 9E A4 9E E6 9F D0 DC A4 9F 91 FD 60
This is a position-independent subroutine expecting a pointer to the input string (0-terminated aka C-string) in $fb
/$fc
, a pointer to the output buffer in $fd
/$fe
and the count (n
) in $ff
. It uses simple indexing, so it's limited to a maximum output length of 255 characters (+ 0 byte) due to the 8bit architecture.
Explanation (commented disassembly):
.rep:
A0 01 LDY #$01 ; init counter to next repetition sequence
84 97 STY $97
88 DEY ; init read and write index
84 9E STY $9E ; (read)
84 9F STY $9F ; (write)
.rep_loop:
B1 FB LDA ($FB),Y ; read next character
F0 20 BEQ .rep_done ; 0 -> finished
A4 9F LDY $9F ; load write index
91 FD STA ($FD),Y ; write next character
C6 97 DEC $97 ; decrement counter to nex rep. seq.
D0 10 BNE .rep_next ; not reached yet -> next iteration
A6 FF LDX $FF ; load repetition counter
.rep_seqloop:
CA DEX ; and decrement
F0 05 BEQ .rep_seqdone ; if 0, no more repetitions
C8 INY ; increment write index
91 FD STA ($FD),Y ; write character
D0 F8 BNE .rep_seqloop ; and repeat for this sequence
.rep_seqdone:
84 9F STY $9F ; store back write index
A5 FF LDA $FF ; re-init counter to next ...
85 97 STA $97 ; ... repetition sequence
.rep_next:
E6 9E INC $9E ; increment read index
A4 9E LDY $9E ; load read index
E6 9F INC $9F ; increment write index
D0 DC BNE .rep_loop ; jump back (main loop)
.rep_done:
A4 9F LDY $9F ; load write index
91 FD STA ($FD),Y ; and write terminating0-byte there
60 RTS ; done.
Example C64 machine code program using it:
This is a program in ca65-style assembler for the C64 using this routine (imported as rep
):
REP_IN = $fb
REP_IN_L = $fb
REP_IN_H = $fc
REP_OUT = $fd
REP_OUT_L = $fd
REP_OUT_H = $fe
REP_N = $ff
.import rep
.segment "LDADDR"
.word $c000
.code
jsr $aefd ; consume comma
jsr $ad9e ; evaluate expression
sta REP_IN_L ; store string length
jsr $b6a3 ; free string
ldy #$00 ; loop over string
readloop: cpy REP_IN_L ; end of string?
beq termstr ; then jump to 0-terminate string
lda ($22),y ; read next character
sta in,y ; store in input buffer
iny ; next
bne readloop
termstr: lda #$00 ; load 0 byte
sta in,y ; store in input buffer
jsr $b79b ; read 8bit unsigned int
stx REP_N ; store in `n`
lda #<in ; (
sta REP_IN_L ; store pointer to
lda #>in ; to input string
sta REP_IN_H ; )
lda #<out ; (
sta REP_OUT_L ; store pointer to
lda #>out ; output buffer
sta REP_OUT_H ; )
jsr rep ; call function
ldy #$00 ; output result
outloop: lda out,y
beq done
jsr $ffd2
iny
bne outloop
done: rts
.bss
in: .res $100
out: .res $100
Online demo
Usage: sys49152,"[s]",[n]
, e.g. sys49152,"Hello, World!",3
Important: If the program was load from disk (like in the online demo), issue a new
command first! This is necessary because loading a machine program trashes some C64 BASIC pointers.
s
as a character array? \$\endgroup\$s
" <- is this a strict requirement (overwriting the original string) or ist it ok to just output the final result? \$\endgroup\$