|
- ; vml.s - machine code helpers for the c64 vim clone (called from power c).
- ;
- ; Assembled for $C000. vml.c holds the bytes; mlinit() calls highmem($C000)
- ; so power c keeps its heap and stack below, then copies the code up here.
- ; Parameters are written by C into a block at $C400 (PB) before each call;
- ; entry addresses come from the ld65 label file (see build-ml.ps1).
- ;
- ; Zero page: 34-42 ($22-$2A), 75-96 ($4B-$60) and 251-252 ($FB-$FC) are the
- ; temporaries power c leaves to machine language - but sys() itself is using
- ; some of them while our code runs (it keeps where to store A/X/Y back), so
- ; every entry that touches zero page saves all three ranges first (zsave) and
- ; puts them back before it returns (zrest). Without that, sys() wrote X/Y
- ; through our screen pointer and then jumped into zero page.
- ;
- ; Entries
- ; scrn paint screen rows r0..r1 straight from the buffer and line index
- ; row paint one row from a byte string (the status row)
- ; bmove overlapping block move (memmove)
- ; ladj add a 16 bit delta to n consecutive words (line index fix-up)
- ; kpop take one key from the kernal keyboard buffer, irqs masked: A = key or 0
-
- SAVE = $C410 ; zsave's copy of the zero page we use
- PB = $C400 ; above the code; NOT $CF00 - power c's stack lives under $D000
-
- ; paint's inputs
- src = $22 ; 2 text to show (petscii)
- len = $24 ; 1 bytes of it, 0..40
- dst = $25 ; 2 screen address of the row
- cur = $27 ; 1 column to invert, $FF = none
- rev = $28 ; 1 $00 normal, $80 whole row reverse
- endp = $29 ; 2 scrn: end offset of the line
-
- ; scrn's copy of its parameter block: PB+0..PB+15 -> $4B..$5A
- bfr = $4B ; 2 buffer address
- lptr = $4D ; 2 address of lptr[0]
- nl = $4F ; 2 number of lines
- top = $51 ; 2 first line on screen
- blen = $53 ; 2 bytes in buffer
- lcol = $55 ; 2 horizontal scroll
- crow = $57 ; 1 screen row of the cursor ($FF none)
- ccol = $58 ; 1 screen column of the cursor
- r0 = $59 ; 1 first row to paint
- r1 = $5A ; 1 last row to paint (inclusive)
- ln = $5B ; 2 line being painted
- lp = $5D ; 2 -> lptr[ln]
- rowc = $5F ; 1 screen row being painted
- st = $FB ; 2 start offset of the visible text
-
- .segment "CODE"
-
- ; ---------------------------------------------------------------- scrn
- scrn: jsr zsave
- ldx #15
- @cp: lda PB,x
- sta bfr,x
- dex
- bpl @cp
-
- clc ; ln = top + r0
- lda top
- adc r0
- sta ln
- lda top+1
- adc #0
- sta ln+1
-
- lda ln ; lp = lptr + 2*ln
- asl a
- sta lp
- lda ln+1
- rol a
- sta lp+1
- clc
- lda lp
- adc lptr
- sta lp
- lda lp+1
- adc lptr+1
- sta lp+1
-
- lda #0 ; dst = $0400 + 40*r0
- sta dst
- lda #4
- sta dst+1
- ldx r0
- beq @d1
- @dl: clc
- lda dst
- adc #40
- sta dst
- bcc @dn
- inc dst+1
- @dn: dex
- bne @dl
- @d1: lda r0
- sta rowc
-
- @row: lda #0
- sta rev
- sta len
- lda #$FF
- sta cur
-
- lda ln ; past the last line: a blank row
- cmp nl
- lda ln+1
- sbc nl+1
- bcs @paint
-
- ldy #0 ; st = lptr[ln]
- lda (lp),y
- sta st
- iny
- lda (lp),y
- sta st+1
-
- clc ; is ln the last line?
- lda ln
- adc #1
- tax
- lda ln+1
- adc #0
- cpx nl
- bne @mid
- cmp nl+1
- bne @mid
- lda blen ; last line ends at blen
- sta endp
- lda blen+1
- sta endp+1
- jmp @gotend
- @mid: ldy #2 ; else at lptr[ln+1] - 1 (before the $0d)
- lda (lp),y
- sec
- sbc #1
- sta endp
- iny
- lda (lp),y
- sbc #0
- sta endp+1
-
- @gotend:
- clc ; st += lcol
- lda st
- adc lcol
- sta st
- lda st+1
- adc lcol+1
- sta st+1
-
- sec ; len = min(40, end - st), 0 if negative
- lda endp
- sbc st
- tax
- lda endp+1
- sbc st+1
- bcc @src ; scrolled past the end of this line
- bne @full
- cpx #41
- bcc @setn
- @full: ldx #40
- @setn: stx len
-
- @src: clc ; src = bfr + st
- lda bfr
- adc st
- sta src
- lda bfr+1
- adc st+1
- sta src+1
-
- lda rowc ; the cursor row?
- cmp crow
- bne @paint
- lda ccol
- sta cur
-
- @paint: jsr paint
-
- lda rowc ; next row, until r1 is done
- cmp r1
- bcs @done
- inc rowc
- inc ln
- bne @l1
- inc ln+1
- @l1: clc
- lda lp
- adc #2
- sta lp
- bcc @l2
- inc lp+1
- @l2: clc
- lda dst
- adc #40
- sta dst
- bcc @l3
- inc dst+1
- @l3: jmp @row
- @done: jmp zrest
-
- ; ---------------------------------------------------------------- row
- ; PB+0 src, PB+2 len, PB+3 dst, PB+5 cur, PB+6 rev
- row: jsr zsave
- ldx #6
- @cp: lda PB,x
- sta src,x
- dex
- bpl @cp
- jsr paint
- jmp zrest
-
- ; ---------------------------------------------------------------- paint
- ; clear the row to blanks, copy len bytes converted petscii -> screen code,
- ; then invert the cursor cell
- paint: lda rev
- ora #$20
- ldy #39
- @clr: sta (dst),y
- dey
- bpl @clr
-
- ldy #0
- @cp: cpy len
- beq @cur
- lda (src),y
- cmp #$20
- bcs @ok
- lda #$20 ; control codes show as a blank
- @ok: cmp #$C0
- bcc @l1
- sbc #$80
- bcs @st
- @l1: cmp #$A0
- bcc @l2
- sbc #$40
- bcs @st
- @l2: cmp #$60
- bcc @l3
- sbc #$20
- bcs @st
- @l3: cmp #$40
- bcc @st
- sbc #$40
- @st: ora rev
- sta (dst),y
- iny
- bne @cp
-
- @cur: lda cur
- cmp #40
- bcs @fin ; $FF (none) or off screen
- tay
- lda (dst),y
- eor #$80
- sta (dst),y
- @fin: rts
-
- ; ---------------------------------------------------------------- bmove
- ; PB+0 from, PB+2 to, PB+4 count. Overlap safe.
- mfrom = $22
- mto = $25
- mcnt = $4B
-
- bmove: jsr zsave
- lda PB
- sta mfrom
- lda PB+1
- sta mfrom+1
- lda PB+2
- sta mto
- lda PB+3
- sta mto+1
- lda PB+4
- sta mcnt
- lda PB+5
- sta mcnt+1
-
- lda mto ; to < from: copy upwards from the start
- cmp mfrom
- lda mto+1
- sbc mfrom+1
- bcc @fwd
-
- ; to >= from: copy downwards from the end
- clc ; point both at their last whole page
- lda mfrom+1
- adc mcnt+1
- sta mfrom+1
- clc
- lda mto+1
- adc mcnt+1
- sta mto+1
- ldy mcnt ; the odd bytes at the top first
- beq @bpg
- @bodd: dey
- lda (mfrom),y
- sta (mto),y
- cpy #0
- bne @bodd
- @bpg: ldx mcnt+1 ; then whole pages, highest first
- beq @out
- @bnext: dec mfrom+1
- dec mto+1
- ldy #0
- @bpl: dey
- lda (mfrom),y
- sta (mto),y
- cpy #0
- bne @bpl
- dex
- bne @bnext
- @out: jmp zrest
-
- @fwd: ldy #0
- ldx mcnt+1 ; whole pages
- beq @fodd
- @fpg: lda (mfrom),y
- sta (mto),y
- iny
- bne @fpg
- inc mfrom+1
- inc mto+1
- dex
- bne @fpg
- @fodd: ldx mcnt ; then the rest
- beq @out
- @fo: lda (mfrom),y
- sta (mto),y
- iny
- dex
- bne @fo
- jmp zrest
-
- ; ---------------------------------------------------------------- ladj
- ; PB+0 address of the first word, PB+2 how many, PB+4 delta
- aptr = $22
- acnt = $4B
- adel = $4D
-
- ladj: jsr zsave
- ldx #5
- @cp: lda PB,x
- sta $4B,x
- dex
- bpl @cp
- lda $4B ; the address goes to $22 for (zp),y
- sta aptr
- lda $4C
- sta aptr+1
- lda $4D ; count to acnt, delta to adel
- sta acnt
- lda $4E
- sta acnt+1
- lda $4F
- sta adel
- lda $50
- sta adel+1
-
- @lp: lda acnt
- ora acnt+1
- beq @done
- ldy #0
- clc
- lda (aptr),y
- adc adel
- sta (aptr),y
- iny
- lda (aptr),y
- adc adel+1
- sta (aptr),y
- clc
- lda aptr
- adc #2
- sta aptr
- bcc @nc
- inc aptr+1
- @nc: lda acnt
- bne @dc
- dec acnt+1
- @dc: dec acnt
- jmp @lp
- @done: jmp zrest
-
- ; ---------------------------------------------------------------- kpop
- kpop: sei
- lda $C6
- beq @none
- ldx #0
- lda $0277
- pha
- @sh: lda $0278,x
- sta $0277,x
- inx
- cpx #9
- bne @sh
- dec $C6
- pla
- cli
- rts
- @none: cli
- lda #0
- rts
-
- ; ---------------------------------------------------------------- zsave / zrest
- ; $22-$2A -> SAVE+0..8, $4B-$60 -> SAVE+9..30, $FB-$FC -> SAVE+31..32
- zsave: ldx #8
- @a: lda $22,x
- sta SAVE,x
- dex
- bpl @a
- ldx #21
- @b: lda $4B,x
- sta SAVE+9,x
- dex
- bpl @b
- lda $FB
- sta SAVE+31
- lda $FC
- sta SAVE+32
- rts
-
- zrest: ldx #8
- @a: lda SAVE,x
- sta $22,x
- dex
- bpl @a
- ldx #21
- @b: lda SAVE+9,x
- sta $4B,x
- dex
- bpl @b
- lda SAVE+31
- sta $FB
- lda SAVE+32
- sta $FC
- rts
-
- .export scrn, row, bmove, ladj, kpop
|