; EVAL-local symbol-only HD61 gate accommodation (two private labels).
; Historical donor unchanged: history/sysv540_original.s
; sysv540.s -- shared cursor implementation v0.1, SOURCE CANDIDATE
; Alex Barragan & ChatGPT (Sol), 2026-10-15
; Public interface documented in sysv540.inc. Do not call SYS5_*.
; No language ROM calls or machine detection. ROM0 0197h writer only.
; IMPORTANT: caller enters from ROM2, with its valid SS and card context.
        ORG     &H7000

; Private RAM1 state: no application-owned direct reads or writes.
SYS5_POS:       EQU     &H2F20
SYS5_UNDER:     EQU     &H2F21
SYS5_VIS:       EQU     &H2F22
SYS5_ACTIVE:    EQU     &H2F23
SYS5_TM:        EQU     &H2F24
SYS5_SYNC:      EQU     &H2F25
SYS5_SCANS:     EQU     &H2F26
SYS5_HALF:      EQU     &H2F28
SYS5_ARM:       EQU     &H2F2A
SYS5_ODD:       EQU     &H2F2B

; One-time initialization; no painting. Fully preserve working regs.
SYS540_INIT:
        PHS     $8
        PHS     $9
        PHS     $10
        PHS     $11
        PHS     $12
        PHS     $13
        PHS     $18
        PHS     $19
        GRE     IX,$18
        PHS     $18
        PHS     $19
        GST     TM,$8
        GST     TM,$8
        PST     UA,&H54
        PRE     IX,SYS5_TM
        ST      $8,(IX+$SX)
        PRE     IX,SYS5_POS
        ST      $31,(IX+$SX)
        PRE     IX,SYS5_UNDER
        LD      $9,&H20
        ST      $9,(IX+$SX)
        PRE     IX,SYS5_VIS
        ST      $31,(IX+$SX)
        PRE     IX,SYS5_ACTIVE
        ST      $31,(IX+$SX)
        PRE     IX,SYS5_SYNC
        ST      $31,(IX+$SX)
        LDW     $10,0
        PRE     IX,SYS5_SCANS
        STW     $10,(IX+$SX)
        PRE     IX,SYS5_HALF
        STW     $10,(IX+$SX)
        PRE     IX,SYS5_ARM
        ST      $31,(IX+$SX)
        PRE     IX,SYS5_ODD
        ST      $31,(IX+$SX)
        PST     UA,&H14
        PPS     $19
        PPS     $18
        PRE     IX,$18
        PPS     $19
        PPS     $18
        PPS     $13
        PPS     $12
        PPS     $11
        PPS     $10
        PPS     $9
        PPS     $8
        RTN

; Public cursor actions. Wrap $29 so it never leaks to application.
SYS540_HIDE:
        PHS     $29
        LD      $29,$31
        CAL     SYS5_CONTROL
        PPS     $29
        RTN
SYS540_SHOW:
        PHS     $29
        LD      $29,$30
        CAL     SYS5_CONTROL
        PPS     $29
        RTN
SYS540_TOGGLE:
        PHS     $29
        LD      $29,&H02
        CAL     SYS5_CONTROL
        PPS     $29
        RTN
SYS540_PLACE:
        PHS     $29
        LD      $29,&H03
        CAL     SYS5_CONTROL
        PPS     $29
        RTN
SYS540_STOP:
        PHS     $29
        LD      $29,&H04
        CAL     SYS5_CONTROL
        PPS     $29
        RTN

; A single shared renderer. All general registers $0..$28, IX
; preserved; only flags and bank UA (becomes 14h) change.
SYS5_CONTROL:
        PHS     $0
        PHS     $1
        PHS     $2
        PHS     $3
        PHS     $4
        PHS     $5
        PHS     $6
        PHS     $7
        PHS     $8
        PHS     $9
        PHS     $10
        PHS     $11
        PHS     $12
        PHS     $13
        PHS     $14
        PHS     $15
        PHS     $16
        PHS     $17
        PHS     $18
        PHS     $19
        PHS     $20
        PHS     $21
        PHS     $22
        PHS     $23
        PHS     $24
        PHS     $25
        PHS     $26
        PHS     $27
        PHS     $28
        GRE     IX,$18
        PHS     $18
        PHS     $19
        PST     UA,&H54
        LD      $21,$29
        SBC     $21,&H03
        JP      Z,SYS5_REPLACE
        LD      $21,$29
        SBC     $21,&H04
        JP      Z,SYS5_STOP
        LD      $21,$29
        SBC     $21,&H02
        JP      Z,SYS5_TOG_CORE
        AN      $29,$29
        JP      Z,SYS5_HIDE_REQ
        CAL     SYS5_SHOW_CORE
        JP      SYS5_CTL_END
SYS5_HIDE_REQ:
        CAL     SYS5_HIDE_CORE
        JP      SYS5_CTL_END
SYS5_TOG_CORE:
        PRE     IX,SYS5_VIS
        LD      $20,(IX+$SX)
        AN      $20,$20
        JP      Z,SYS5_TOGGLE_ON
        CAL     SYS5_HIDE_CORE
        JP      SYS5_CTL_END
SYS5_TOGGLE_ON:
        CAL     SYS5_SHOW_CORE
        JP      SYS5_CTL_END
SYS5_STOP:
        CAL     SYS5_HIDE_CORE
        PRE     IX,SYS5_ACTIVE
        ST      $31,(IX+$SX)
        JP      SYS5_CTL_END

; PLACE is atomic: restore old glyph, then validate, store and show new.
; Save caller position / underlying character before hide changes them.
SYS5_REPLACE:
        LD      $24,$6
        LD      $25,$16
; R0197 is a ROM service; do not trust it to preserve scratch operands.
        PHS     $24
        PHS     $25
        CAL     SYS5_HIDE_CORE
        PPS     $25
        PPS     $24
        PRE     IX,SYS5_ACTIVE
        ST      $31,(IX+$SX)
        LD      $20,$24
        SBC     $20,&H80
        JP      NC,SYS5_CTL_END
        AN      $25,$25
        JP      NZ,SYS5_UNDER_NZ
        LD      $25,&H20
SYS5_UNDER_NZ:
        LD      $20,$25
        SBC     $20,&H20
        JP      C,SYS5_CTL_END
        LD      $20,$25
        SBC     $20,&H7F
        JP      NC,SYS5_CTL_END
        PRE     IX,SYS5_POS
        ST      $24,(IX+$SX)
        PRE     IX,SYS5_UNDER
        ST      $25,(IX+$SX)
        PRE     IX,SYS5_ACTIVE
        ST      $30,(IX+$SX)
        CAL     SYS5_SHOW_CORE
        JP      SYS5_CTL_END

SYS5_HIDE_CORE:
        PRE     IX,SYS5_VIS
        LD      $20,(IX+$SX)
        AN      $20,$20
        RTN     Z
        PRE     IX,SYS5_POS
        LD      $6,(IX+$SX)
        PRE     IX,SYS5_UNDER
        LD      $16,(IX+$SX)
        PRE     IX,SYS5_VIS
        ST      $31,(IX+$SX)
        CAL     SYS5_PUTC
        RTN
SYS5_SHOW_CORE:
        PRE     IX,SYS5_ACTIVE
        LD      $20,(IX+$SX)
        AN      $20,$20
        RTN     Z
        PRE     IX,SYS5_VIS
        LD      $20,(IX+$SX)
        AN      $20,$20
        RTN     NZ
        ST      $30,(IX+$SX)
        PRE     IX,SYS5_POS
        LD      $6,(IX+$SX)
        LD      $16,&H5F
        CAL     SYS5_PUTC
        RTN
SYS5_PUTC:
; Only graphics primitive; matches r020's proven K8_PUTC ABI.
        PST     UA,&H14
        LD      $7,$16
        LD      $0,$7
        DIU     $7
        DID     $0
        OR      $7,$SZ
        CAL     &H0197
        PST     UA,&H54
        RTN
SYS5_CTL_END:
        PST     UA,&H14
        PPS     $19
        PPS     $18
        PRE     IX,$18
        PPS     $28
        PPS     $27
        PPS     $26
        PPS     $25
        PPS     $24
        PPS     $23
        PPS     $22
        PPS     $21
        PPS     $20
        PPS     $19
        PPS     $18
        PPS     $17
        PPS     $16
        PPS     $15
        PPS     $14
        PPS     $13
        PPS     $12
        PPS     $11
        PPS     $10
        PPS     $9
        PPS     $8
        PPS     $7
        PPS     $6
        PPS     $5
        PPS     $4
        PPS     $3
        PPS     $2
        PPS     $1
        PPS     $0
        RTN

; TIMER PREDICATE. Returns $18 due flag; no drawing. It must return
; before the caller invokes SYS540_TOGGLE. In particular do NOT call
; ROM0 0197h inside this stack frame (r017 negative control).
SYS540_POLL:
        PHS     $7
        PHS     $8
        PHS     $9
        PHS     $10
        PHS     $11
        PHS     $12
        PHS     $13
        PHS     $18
        PHS     $19
        GRE     IX,$18
        PHS     $18
        PHS     $19
        GST     TM,$8
        GST     TM,$8
        PST     UA,&H54
        PRE     IX,SYS5_TM
        LD      $9,(IX+$SX)
        SBC     $9,$8
        JP      NZ,SYS5_EDGE
        PRE     IX,SYS5_SYNC
        LD      $9,(IX+$SX)
        AN      $9,$9
        JP      Z,SYS5_NO_EVENT
; A complete second has begun. Count alternating idle RAW polls.
        PRE     IX,SYS5_ODD
        LD      $9,(IX+$SX)
        XR      $9,$30
        ST      $9,(IX+$SX)
        AN      $9,$9
        JP      Z,SYS5_NOCOUNT
        PRE     IX,SYS5_SCANS
        LDW     $10,(IX+$SX)
        ADW     $10,$SY
        STW     $10,(IX+$SX)
SYS5_NOCOUNT:
        PRE     IX,SYS5_ARM
        LD      $9,(IX+$SX)
        AN      $9,$9
        JP      Z,SYS5_NO_EVENT
        PRE     IX,SYS5_HALF
        LDW     $10,(IX+$SX)
        SBW     $10,$SY
        JP      Z,SYS5_MID
        STW     $10,(IX+$SX)
        JP      SYS5_NO_EVENT
SYS5_MID:
        STW     $10,(IX+$SX)
        PRE     IX,SYS5_ARM
        ST      $31,(IX+$SX)
        JP      SYS5_EVENT
SYS5_EDGE:
        ST      $8,(IX+$SX)
        PRE     IX,SYS5_SYNC
        LD      $9,(IX+$SX)
        AN      $9,$9
        JP      Z,SYS5_FIRST_EDGE
; Subsequent full edges toggle and arm the next calibrated midpoint.
        PRE     IX,SYS5_SCANS
        LDW     $10,(IX+$SX)
        LDW     $12,0
        STW     $12,(IX+$SX)
        PRE     IX,SYS5_HALF
        STW     $10,(IX+$SX)
        PRE     IX,SYS5_ODD
        ST      $31,(IX+$SX)
        PRE     IX,SYS5_ARM
        LD      $9,$10
        OR      $9,$11
        AN      $9,$9
        JP      Z,SYS5_DISARM
        LD      $9,$30
SYS5_DISARM:
        ST      $9,(IX+$SX)
        JP      SYS5_EVENT
SYS5_FIRST_EDGE:
; Human-observed startup hesitation: discard partial interval and do
; not toggle the underline on this edge. No estimated half-rate yet.
        ST      $30,(IX+$SX)
        LDW     $10,0
        PRE     IX,SYS5_SCANS
        STW     $10,(IX+$SX)
        PRE     IX,SYS5_HALF
        STW     $10,(IX+$SX)
        PRE     IX,SYS5_ODD
        ST      $31,(IX+$SX)
        PRE     IX,SYS5_ARM
        ST      $31,(IX+$SX)
        JP      SYS5_NO_EVENT
SYS5_EVENT:
        LD      $7,$30
        JP      SYS5_POLL_DONE
SYS5_NO_EVENT:
        LD      $7,$31
SYS5_POLL_DONE:
        PST     UA,&H14
        PPS     $19
        PPS     $18
        PRE     IX,$18
        PPS     $19
        PPS     $18
        PPS     $13
        PPS     $12
        PPS     $11
        PPS     $10
        PPS     $9
        PPS     $8
        LD      $18,$7
        PPS     $7
        RTN
