********************************************************************************
* Starship Commander for the Apple II, by Gilman Louie *
* Copyright 1981 Voyager Software *
* *
* Disassembly of "H" (hi-res character generator). *
********************************************************************************
* This is a fairly deluxe HRCG. It has multiple fonts, a blinking underline *
* cursor, inverse/normal text, the ability to overwrite or blend with existing *
* contents, page flipping, and full support for the text window. *
* *
* The code is nearly identical to the HRCG from the DOS Toolkit, Copyright *
* 1980 Apple Computer, Inc. Presumably this and a couple of the fonts were *
* licensed from Apple. *
********************************************************************************
* Disassembly by Andy McFadden, using 6502bench SourceGen v1.5. *
* Last updated 2020/01/22 *
********************************************************************************
MON_WNDLEFT .eq $20 ;left column of scroll window
MON_WNDWDTH .eq $21 ;width of scroll window
MON_WNDTOP .eq $22 ;top of scroll window
MON_WNDBTM .eq $23 ;bottom of scroll window
MON_CH .eq $24 ;cursor horizontal displacement
MON_CV .eq $25 ;cursor vertical displacement
MON_BASL .eq $28 ;base address for text output (lo)
MON_BASH .eq $29 ;base address for text output (hi)
hptr .eq $2a {addr/2}
SavedY .eq $35
MON_CSWL .eq $36 ;character output hook (lo)
MON_CSWH .eq $37 ;character output hook (hi)
MON_KSWL .eq $38 ;character input hook (lo)
MON_KSWH .eq $39 ;character input hook (hi)
MON_RNDL .eq $4e ;low byte of KEYIN "random" value
MON_RNDH .eq $4f ;high byte of KEYIN "random" value
SavedX .eq $eb
hptr2 .eq $ec {addr/2}
temp .eq $ee {addr/2}
SavedAcc .eq $ff
DOS_CHARIO .eq $03ea ;jumps to routine that connects DOS KSW/CSW
KBD .eq $c000 ;R last key pressed + 128
KBDSTRB .eq $c010 ;RW keyboard strobe
TXTCLR .eq $c050 ;RW display graphics
MIXCLR .eq $c052 ;RW display full screen
TXTPAGE1 .eq $c054 ;RW display page 1
TXTPAGE2 .eq $c055 ;RW display page 2 (or read/write aux mem)
HIRES .eq $c057 ;RW display hi-res graphics
MON_BELL1 .eq $fbdd ;sound bell regardless of output device
MON_VTAB .eq $fc22 ;tab to row specified in Acc
MON_VTABZ .eq $fc24
MON_CLREOP .eq $fc42 ;clear screen from cursor to end of page
MON_HOME .eq $fc58 ;clear screen and reset text output to top-left
MON_SCROLL .eq $fc70 ;scroll up one line
MON_CLREOL .eq $fc9c ;clear to end of line
.org $88fe
88fe: 4c 0d 89 INIT jmp InitWithBanner ;called by INTRO
8901: 4c 1e 89 jmp Init ;not used?
8904: 0a .dd1 $0a
8905: 68 12 ExtFontBase .dd2 $1268 ;external font base addr; set by START to $1268
8907: 4c 23 8c DoReturn1? jmp Return
890a: 4c 23 8c DoReturn2? jmp Return
890d: 20 1e 89 InitWithBanner jsr Init ;do regular init
8910: a0 00 ldy #$00 ;print the program title
8912: b9 41 89 :Loop lda ProgName,y
8915: ea nop ;NOPs set by START
8916: ea nop ;this calls MON_COUT in DOS Toolkit version
8917: ea nop
8918: c8 iny
8919: c0 1d cpy #$1d
891b: 90 f5 bcc :Loop
891d: 60 rts
891e: a9 73 Init lda #<HandleKbdIn ;set our code as keyboard input handler
8920: 85 38 sta MON_KSWL
8922: a9 89 lda #>HandleKbdIn
8924: 85 39 sta MON_KSWH
8926: a9 17 lda #<HandleCharOut ;set our code as char output handler
8928: 85 36 sta MON_CSWL
892a: a9 8a lda #>HandleCharOut
892c: 85 37 sta MON_CSWH
892e: 20 ea 03 jsr DOS_CHARIO ;reconnect DOS
8931: 2c 52 c0 bit MIXCLR ;full screen
8934: 2c 57 c0 bit HIRES ;hi-res
8937: 20 53 8c jsr InitState
893a: 20 0c 8b jsr FlipPage
893d: 2c 50 c0 bit TXTCLR ;graphics mode
8940: 60 rts
8941: 90 ProgName .dd1 $90 ;Ctrl+P: clear window
8942: c8 c9 ad d2+ .str “HI-RES CHAR GEN VERSION 1.0”,$8d
; Command modifier flags.
895e: 00 EscMode .dd1 $00 ;$00=normal, $80=ESC mode active
895f: 00 CmdFlags .dd1 $00 ;$80=font change pending, $40=2nd cmd set
; State reset by initialization ($8960-8972).
8960: 20 HiResPage .dd1 $20 ;$20 or $40
8961: 00 InvFlag .dd1 $00 ;$00=normal, $7f=inverse
8962: 00 MixFlag .dd1 $00 ;$00=overwrite, $80=blend (ORA/AND), $c0=xdraw (EOR)
8963: 00 PageFlipMask .dd1 $00 ;$00=draw on current page, $60=draw on hidden page
8964: 00 VertWrapFlag .dd1 $00 ;$00=normal, $ff=wrap to top instead of scroll
8965: 80 LowerCaseFlag .dd1 $80 ;$00=normal, $80=conv upper to lower, $c0=noconv first
8966: 68 12 FontAddr .dd2 $1268 ;font address
8968: 00 SavedState .dd1 $00 ;$8960-8967 copied here
8969: 00 .dd1 $00
896a: 00 .dd1 $00
896b: 00 .dd1 $00
896c: 00 .dd1 $00
896d: 00 .dd1 $00
896e: 00 .dd1 $00
896f: 00 .dd1 $00
8970: 00 StateSavedFlag .dd1 $00 ;$00=state not saved, $ff=saved
8971: 00 SavedHtab .dd1 $00
8972: 00 SavedVtab .dd1 $00
; Handle request for keyboard input. Called from monitor RDKEY.
;
; On entry:
; A-reg: character under cursor
; Y-reg: horizontal offset
8973: 91 28 HandleKbdIn sta (MON_BASL),y ;replace flashing text with normal
8975: 86 eb stx SavedX ;preserve X
8977: a5 28 lda MON_BASL
8979: 85 2a sta hptr ;set up pointer to point at hi-res page
897b: a5 29 lda MON_BASH ; using the text page addr as the base
897d: 09 1c ora #$1c
897f: 0d 60 89 ora HiResPage
8982: 85 2b sta hptr+1
8984: a2 01 ldx #$01
8986: b1 2a lda (hptr),y ;save original value
8988: 48 pha
8989: e6 4e :InputLoop inc MON_RNDL ;update RNG
898b: d0 0b bne :CheckKbd ;didn't roll, branch
898d: e6 4f inc MON_RNDH ;update high byte
898f: ca dex ;time to invert value?
8990: d0 06 bne :CheckKbd ;nope, not yet
8992: 49 7f eor #$7f ;yes, invert hi-res byte
8994: 91 2a sta (hptr),y ;this gives us a blinking underline cursor
8996: a2 50 ldx #$50 ;reset timer
8998: 2c 00 c0 :CheckKbd bit KBD ;got input?
899b: 10 ec bpl :InputLoop ;branch if not yet
899d: 68 pla
899e: 91 2a sta (hptr),y ;restore hi-res byte
89a0: ba tsx
89a1: bd 04 01 lda $0104,x ;check caller's caller's caller
89a4: c9 f8 cmp #$f8 ;in ROM?
89a6: ad 00 c0 lda KBD ;get pending key
89a9: 2c 10 c0 bit KBDSTRB ;clear pending key
89ac: 90 1b bcc :Done ;not called from ROM, don't do extras
89ae: 48 pha
89af: 2c 5e 89 bit EscMode ;in ESC mode?
89b2: 30 18 bmi HandleEscActions ;yes, handle ESC Char
89b4: c9 9b cmp #$9b ;is this ESC?
89b6: d0 07 bne :NotEsc ;nope
89b8: a9 80 lda #$80 ;yes, set ESC mode
89ba: 8d 5e 89 sta EscMode
89bd: d0 09 bne :PlaDone ;(always)
89bf: c9 8d :NotEsc cmp #$8d ;is this carriage return?
89c1: d0 05 bne :PlaDone ;no, done
89c3: 20 8c 8d jsr ClearToEol
89c6: a4 24 :LdyPlaDone ldy MON_CH ;restore Y
89c8: 68 :PlaDone pla ;char in A
89c9: a6 eb :Done ldx SavedX ;restore X
89cb: 60 rts
; Handle ESC mode actions. The movement keys are handled by the monitor, but we
; need to drop out of ESC mode after one key if it isn't IJKM, and we need to
; handle things like screen clears and scrolling when we reach the bottom.
HandleEscActions
89cc: c9 c9 cmp #“I” ;is char < 'I'?
89ce: 90 0c bcc :NotIJKM ;yes, so not IJKM
89d0: c9 cd cmp #“M”
89d2: f0 36 beq :CursorDown ;'M' moves cursor down
89d4: b0 06 bcs :NotIJKM ;if > 'M', it's not IJKM
89d6: c9 cb cmp #“K”
89d8: f0 2b beq :CursorRight ;'K' moves cursor right
89da: 90 ec bcc :PlaDone ;it's 'I' (up) or 'J' (left), nothing to do
89dc: 0e 5e 89 :NotIJKM asl EscMode ;clear ESC mode
89df: c9 c0 cmp #“@” ;'@' clears the screen
89e1: d0 06 bne :NotAt
89e3: 20 6f 8d jsr ClearWindow
89e6: 4c c6 89 jmp :LdyPlaDone
89e9: c9 c5 :NotAt cmp #“E” ;'E' clears to end of line
89eb: d0 06 bne :NotE
89ed: 20 8c 8d jsr ClearToEol
89f0: 4c c6 89 jmp :LdyPlaDone
89f3: c9 c6 :NotE cmp #“F” ;'F' clears to end of screen
89f5: d0 06 bne :NotF
89f7: 20 79 8d jsr ClearToEos
89fa: 4c c6 89 jmp :LdyPlaDone
89fd: c9 c3 :NotF cmp #“C” ;'C' moves down a line
89ff: f0 09 beq :CursorDown
8a01: c9 c1 cmp #“A” ;A=right
8a03: d0 c3 bne :PlaDone ;B=left, D=up
8a05: c8 :CursorRight iny ;check move right
8a06: c4 21 cpy MON_WNDWDTH ;did we reach the right edge of window?
8a08: 90 bc bcc :LdyPlaDone ;nope, nothing to do
8a0a: a4 25 :CursorDown ldy MON_CV ;check move down
8a0c: c8 iny
8a0d: c4 23 cpy MON_WNDBTM ;did we reach bottom of window?
8a0f: 90 b5 bcc :LdyPlaDone ;nope, nothing to do
8a11: 20 20 8d jsr ScrollUp ;scroll entire screen up one line
8a14: 4c c6 89 jmp :LdyPlaDone
8a17: 85 ff HandleCharOut sta SavedAcc ;save A/X/Y
8a19: 86 eb stx SavedX
8a1b: 84 35 sty SavedY
8a1d: 20 27 8a jsr OutputChar ;output character
8a20: a4 35 ldy SavedY ;restore A/X/Y
8a22: a6 eb ldx SavedX
8a24: a5 ff lda SavedAcc
8a26: 60 rts
8a27: 29 7f OutputChar and #$7f ;clear high bit
8a29: 0e 5f 89 asl CmdFlags ;are we changing fonts?
8a2c: b0 57 bcs SelectFont ;yes, get the font index
8a2e: c9 20 cmp #‘ ’ ;is it a control char?
8a30: 90 03 bcc OutputCtrlChar ;yes
8a32: 4c 7a 8c jmp DoOutput ;no, just draw it
8a35: c9 1b OutputCtrlChar cmp #$1b ;is is Ctrl-@ through Ctrl-Z?
8a37: b0 0a bcs :NotSpecial ;nope
8a39: 0a asl A ;get handler address
8a3a: aa tax
8a3b: bd 48 8a lda JumpTable+1,x
8a3e: 48 pha
8a3f: bd 47 8a lda JumpTable,x
8a42: 48 pha
8a43: 0e 5f 89 :NotSpecial asl CmdFlags
8a46: 60 rts
; Jump table for control commands.
;
; Printing a control character from Ctrl+A to Ctrl+Z invokes a command. The
; table below maps characters to code.
;
; Each letter potentially represents two commands; the second set is used if the
; previous character output was Ctrl+O. The carry flag will be clear for
; primary set, set for secondary set.
8a47: 45 8b JumpTable .dd2 :Return-1 ;80 @: (no-op)
8a49: 7c 8a .dd2 SetSelectFontFlag-1 ;81 A: select font (next char is index) | set hpage=1
8a4b: a8 8a .dd2 SaveState-1 ;82 B: save state | set hpage=2
8a4d: d0 8a .dd2 RestoreHtab-1 ;83 C: restore HTAB | set xdraw/no-flip
8a4f: eb 8a .dd2 RestoreState-1 ;84 D: restore state | flip page
8a51: 19 8b .dd2 CmdClearToEol-1 ;85 E: clear to end of line | (no-op)
8a53: 21 8b .dd2 CmdClearToEos-1 ;86 F: clear to end of screen | (no-op)
8a55: dc fb .dd2 MON_BELL1-1 ;87 G: beep
8a57: 29 8b .dd2 Backspace-1 ;88 H: backspace | (no-op)
8a59: 3e 8b .dd2 SetInvFlag-1 ;89 I: sets inverse flag | (no-op)
8a5b: 02 8d .dd2 MoveDown-1 ;8A J: move down a line
8a5d: 46 8b .dd2 ClearLowerCaseFlag-1 ;8B K: clear lower-case flag | (no-op)
8a5f: 4e 8b .dd2 SetLowerCaseFlag-1 ;8C L: set lower-case flag | (no-op)
8a61: 56 8b .dd2 HandleCr-1 ;8D M: carriage return (checks Ctrl+S for pause)
8a63: 71 8b .dd2 ClearInvFlag-1 ;8E N: clear inverse flag | (no-op)
8a65: 79 8b .dd2 SetSecondCmdFlag-1 ;8F O: next cmd is from 2nd set | set blend/no-flip
8a67: 8c 8b .dd2 CmdClearWindow-1 ;90 P: clear window contents | set no-blend/no-flip
8a69: 9d 8b .dd2 RestoreVtabHtab-1 ;91 Q: restore saved VTAB/HTAB | (no-op)
8a6b: ac 8b .dd2 SetXdrawFlip-1 ;92 R: set xdraw/flip | (no-op)
8a6d: b9 8b .dd2 SetLowerCaseSkip-1 ;93 S: lower case conv one char only | clear vert wrap flag
8a6f: c7 8b .dd2 SetBlendFlip-1 ;94 T: set blend/flip | (no-op)
8a71: 45 8b .dd2 :Return-1 ;95 U: (no-op)
8a73: d4 8b .dd2 SetWinTopLeft-1 ;96 V: sets window top/left | (no-op)
8a75: 02 8c .dd2 SetWinBotRight-1 ;97 W: sets window bottom/right | set vert wrap flag
8a77: 45 8b .dd2 :Return-1 ;98 X: (no-op)
8a79: 29 8c .dd2 ResetWindow-1 ;99 Y: reset window to full screen | (special no-op)
8a7b: 50 8c .dd2 ReinitState-1 ;9A Z: reinit state | (special no-op)
; Sets the "select font" flag, so we interpret the next character received as
; the font index.
SetSelectFontFlag
8a7d: b0 24 bcs SetHiResPage1
8a7f: a9 80 lda #$80
8a81: 8d 5f 89 sta CmdFlags
8a84: 60 rts
; The previous character was Ctrl+A, so this char is the font index.
8a85: e9 31 SelectFont sbc #‘1’ ;change ['1','9'] to [0,8]
8a87: c9 09 cmp #$09 ;in range?
8a89: b0 0d bcs SetDefaultFont ;nope
8a8b: ae 05 89 ldx ExtFontBase ;get low byte (always the same)
8a8e: 85 ee sta temp ;multiply value by 3
8a90: 0a asl A
8a91: 65 ee adc temp
8a93: 6d 06 89 adc ExtFontBase+1 ;add it to base ($300 per font)
8a96: d0 04 bne :SetFont
8a98: a2 fe SetDefaultFont ldx #<DefaultFont
8a9a: a9 8d lda #>DefaultFont
8a9c: 8e 66 89 :SetFont stx FontAddr ;set new font address
8a9f: 8d 67 89 sta FontAddr+1
8aa2: 60 rts
8aa3: a9 20 SetHiResPage1 lda #$20
8aa5: 8d 60 89 sta HiResPage
8aa8: 60 rts
8aa9: b0 20 SaveState bcs SetHiResPage2
8aab: 2c 70 89 bit StateSavedFlag ;do we have saved state?
8aae: 30 10 bmi :HaveState ;yes, just update VTAB/HTAB
8ab0: a9 ff lda #$ff ;no, set flag and copy state
8ab2: 8d 70 89 sta StateSavedFlag
8ab5: a0 07 ldy #$07
8ab7: b9 60 89 :Loop lda HiResPage,y
8aba: 99 68 89 sta SavedState,y
8abd: 88 dey
8abe: 10 f7 bpl :Loop
8ac0: a5 24 :HaveState lda MON_CH ;copy HTAB/VTAB to save area
8ac2: 8d 71 89 sta SavedHtab
8ac5: a5 25 lda MON_CV
8ac7: 8d 72 89 sta SavedVtab
8aca: 60 rts
8acb: a9 40 SetHiResPage2 lda #$40
8acd: 8d 60 89 sta HiResPage
8ad0: 60 rts
8ad1: b0 0e RestoreHtab bcs SetXdrawNoFlip
8ad3: ad 71 89 lda SavedHtab ;? not entirely sure what this does
8ad6: c5 24 cmp MON_CH
8ad8: 85 24 sta MON_CH
8ada: f0 02 beq :LE ;if saved is <= HTAB, move down
8adc: b0 68 bcs :Return
8ade: 4c 03 8d :LE jmp MoveDown
8ae1: a9 c0 SetXdrawNoFlip lda #$c0
8ae3: 8d 62 89 sta MixFlag
8ae6: a9 00 lda #$00
8ae8: 8d 63 89 sta PageFlipMask
8aeb: 60 rts
8aec: b0 1e RestoreState bcs FlipPage
8aee: 2c 70 89 bit StateSavedFlag ;is there state to restore?
8af1: 10 53 bpl :Return ;no, bail
8af3: a0 07 ldy #$07
8af5: b9 68 89 :Loop lda SavedState,y
8af8: 99 60 89 sta HiResPage,y
8afb: 88 dey
8afc: 10 f7 bpl :Loop
8afe: a9 00 lda #$00
8b00: 8d 70 89 sta StateSavedFlag ;clear flag
8b03: 8d 71 89 sta SavedHtab ;reset saved HTAB/VTAB
8b06: a5 22 lda MON_WNDTOP
8b08: 8d 72 89 sta SavedVtab
8b0b: 60 rts
; Displays hi-res page 1 or 2 based on current page setting.
8b0c: 2c 54 c0 FlipPage bit TXTPAGE1
8b0f: ad 60 89 lda HiResPage
8b12: c9 40 cmp #$40
8b14: d0 30 bne :Return
8b16: 2c 55 c0 bit TXTPAGE2
8b19: 60 rts
8b1a: b0 2a CmdClearToEol bcs :Return
8b1c: 20 8c 8d jsr ClearToEol
8b1f: 4c 9c fc jmp MON_CLREOL
8b22: b0 22 CmdClearToEos bcs :Return
8b24: 20 79 8d jsr ClearToEos
8b27: 4c 42 fc jmp MON_CLREOP
8b2a: c6 24 Backspace dec MON_CH ;reduce HTAB
8b2c: 10 18 bpl :Return ;if >= 0, done
8b2e: a5 21 lda MON_WNDWDTH ;set HTAB to window width
8b30: 85 24 sta MON_CH
8b32: c6 24 dec MON_CH
8b34: a5 22 lda MON_WNDTOP ;back up one line if not yet at top
8b36: c5 25 cmp MON_CV
8b38: b0 0c bcs :Return
8b3a: c6 25 dec MON_CV
8b3c: 4c 22 fc jmp MON_VTAB ;update monitor VTAB
8b3f: b0 05 SetInvFlag bcs :Return
8b41: a9 7f lda #$7f
8b43: 8d 61 89 sta InvFlag
8b46: 60 :Return rts
ClearLowerCaseFlag
8b47: b0 fd bcs :Return
8b49: a9 00 lda #$00
8b4b: 8d 65 89 sta LowerCaseFlag
8b4e: 60 rts
SetLowerCaseFlag
8b4f: b0 f5 bcs :Return
8b51: a9 80 lda #$80
8b53: 8d 65 89 sta LowerCaseFlag
8b56: 60 rts
8b57: ac 00 c0 HandleCr ldy KBD ;key pending?
8b5a: 10 13 bpl :NoKey ;nope
8b5c: c0 93 cpy #$93 ;Ctrl+S?
8b5e: d0 0f bne :NoKey ;nope
8b60: 2c 10 c0 bit KBDSTRB ;clear key
8b63: ac 00 c0 :Loop ldy KBD ;wait for another key press
8b66: 10 fb bpl :Loop
8b68: c0 83 cpy #$83 ;was it Ctrl+C?
8b6a: f0 03 beq :NoKey ;yes, don't clear it
8b6c: 2c 10 c0 bit KBDSTRB ;no, eat it
8b6f: 4c ff 8c :NoKey jmp MoveToLeftAndDown ;handle CR output
8b72: b0 d2 ClearInvFlag bcs :Return
8b74: a9 00 lda #$00
8b76: 8d 61 89 sta InvFlag
8b79: 60 rts
SetSecondCmdFlag
8b7a: b0 06 bcs SetBlendNoFlip
8b7c: a9 40 lda #$40
8b7e: 8d 5f 89 sta CmdFlags
8b81: 60 rts
8b82: a9 80 SetBlendNoFlip lda #$80
8b84: 8d 62 89 sta MixFlag
8b87: a9 00 lda #$00
8b89: 8d 63 89 sta PageFlipMask
8b8c: 60 rts
8b8d: b0 06 CmdClearWindow bcs SetNoBlendNoFlip
8b8f: 20 6f 8d jsr ClearWindow
8b92: 4c 58 fc jmp MON_HOME
SetNoBlendNoFlip
8b95: a9 00 lda #$00
8b97: 8d 62 89 sta MixFlag
8b9a: 8d 63 89 sta PageFlipMask
8b9d: 60 rts
8b9e: b0 a6 RestoreVtabHtab bcs :Return
8ba0: ad 71 89 lda SavedHtab
8ba3: 85 24 sta MON_CH
8ba5: ad 72 89 lda SavedVtab
8ba8: 85 25 sta MON_CV
8baa: 4c 24 fc jmp MON_VTABZ
8bad: 90 74 SetXdrawFlip bcc Return
8baf: a9 c0 lda #$c0
8bb1: 8d 62 89 sta MixFlag
8bb4: a9 60 lda #$60
8bb6: 8d 63 89 sta PageFlipMask
8bb9: 60 rts
SetLowerCaseSkip
8bba: b0 06 bcs ClearVertWrapFlag
8bbc: a9 c0 lda #$c0
8bbe: 8d 65 89 sta LowerCaseFlag
8bc1: 60 rts
ClearVertWrapFlag
8bc2: a9 00 lda #$00
8bc4: 8d 64 89 sta VertWrapFlag
8bc7: 60 rts
8bc8: 90 59 SetBlendFlip bcc Return
8bca: a9 80 lda #$80
8bcc: 8d 62 89 sta MixFlag
8bcf: a9 60 lda #$60
8bd1: 8d 63 89 sta PageFlipMask
8bd4: 60 rts
; Set the window top/left to match current HTAB/VTAB, and reduces width to
; maintain the current right edge.
8bd5: b0 4c SetWinTopLeft bcs Return
8bd7: a5 24 lda MON_CH ;get htab
8bd9: 65 20 adc MON_WNDLEFT ;add current left window posn
8bdb: c9 28 cmp #40 ;on screen?
8bdd: 90 02 bcc :NotOffRight ;yes
8bdf: a9 27 lda #39 ;no, clamp
8be1: 85 20 :NotOffRight sta MON_WNDLEFT ;set left edge
8be3: 38 sec
8be4: a5 21 lda MON_WNDWDTH ;update width
8be6: e5 24 sbc MON_CH
8be8: 85 21 sta MON_WNDWDTH
8bea: a9 00 lda #$00 ;set HTAB to 0
8bec: 85 24 sta MON_CH
8bee: a5 25 lda MON_CV ;now update window bottom
8bf0: c9 18 cmp #24 ;on screen?
8bf2: 90 02 bcc :NotOffBottom ;yes
8bf4: a9 17 lda #23 ;no, clamp
8bf6: 85 22 :NotOffBottom sta MON_WNDTOP
8bf8: 2c 70 89 bit StateSavedFlag ;do we have saved state?
8bfb: 30 03 bmi :Done ;no, bail
8bfd: 8d 72 89 sta SavedVtab ;yes, update VTAB
8c00: 4c 22 fc :Done jmp MON_VTAB ;update text routines
8c03: b0 1f SetWinBotRight bcs SetVertWrapFlag
8c05: a5 24 lda MON_CH ;get htab
8c07: 85 21 sta MON_WNDWDTH ;set width
8c09: 65 20 adc MON_WNDLEFT
8c0b: c9 28 cmp #40 ;on screen?
8c0d: 90 06 bcc :OnScreen ;yes
8c0f: a9 27 lda #39 ;no, clamp
8c11: e5 20 sbc MON_WNDLEFT
8c13: 85 21 sta MON_WNDWDTH ;update width
8c15: e6 21 :OnScreen inc MON_WNDWDTH ;HTAB starts at 0, width starts at 1
8c17: a5 25 lda MON_CV ;get vtab
8c19: c9 18 cmp #24 ;on screen?
8c1b: 90 02 bcc :OnScreen ;yes, good
8c1d: a9 17 lda #23 ;no, clamp
8c1f: 85 23 :OnScreen sta MON_WNDBTM ;set window bottom
8c21: e6 23 inc MON_WNDBTM ; to vtab+1
8c23: 60 Return rts
8c24: a9 ff SetVertWrapFlag lda #$ff
8c26: 8d 64 89 sta VertWrapFlag
8c29: 60 rts
8c2a: b0 22 ResetWindow bcs CallDoReturn1
8c2c: a5 20 DoResetWindow lda MON_WNDLEFT ;preserve HTAB, which is relative to WNDLEFT
8c2e: 65 24 adc MON_CH
8c30: 85 24 sta MON_CH
8c32: a9 00 lda #$00 ;set left/top to edge of screen
8c34: 85 20 sta MON_WNDLEFT
8c36: 85 22 sta MON_WNDTOP
8c38: 2c 70 89 bit StateSavedFlag ;do we have saved state?
8c3b: 30 06 bmi :HaveState ;yes, do not disturb
8c3d: 8d 71 89 sta SavedHtab
8c40: 8d 72 89 sta SavedVtab
8c43: a9 28 :HaveState lda #40
8c45: 85 21 sta MON_WNDWDTH ;set with to 40
8c47: a9 18 lda #24
8c49: 85 23 sta MON_WNDBTM ;set height to 24
8c4b: 4c 22 fc jmp MON_VTAB ;update the monitor text routines
8c4e: 4c 07 89 CallDoReturn1 jmp DoReturn1?
8c51: b0 24 ReinitState bcs CallDoReturn2
8c53: a9 00 InitState lda #$00 ;zero out $8960-8972
8c55: a0 12 ldy #$12
8c57: 99 60 89 :Loop sta HiResPage,y
8c5a: 88 dey
8c5b: 10 fa bpl :Loop
8c5d: 20 2c 8c jsr DoResetWindow
8c60: 20 98 8a jsr SetDefaultFont
8c63: 20 a3 8a jsr SetHiResPage1
8c66: a9 23 lda #<Return
8c68: 8d 08 89 sta DoReturn1?+1
8c6b: 8d 0b 89 sta DoReturn2?+1
8c6e: a9 8c lda #>Return
8c70: 8d 09 89 sta DoReturn1?+2
8c73: 8d 0c 89 sta DoReturn2?+2
8c76: 60 rts
8c77: 4c 0a 89 CallDoReturn2 jmp DoReturn2?
; Copies font data to the screen.
8c7a: 0e 5f 89 DoOutput asl CmdFlags ;check flag for second command set
8c7d: b0 a4 bcs Return ;it's raised; do nothing
8c7f: 2c 65 89 bit LowerCaseFlag ;check lower case flag
8c82: 10 0f bpl :NoConv ;not set, do nothing
8c84: 50 05 bvc :CheckRange ;set to $80, do conversion
8c86: 0e 65 89 asl LowerCaseFlag ;set to $c0; shift left to make it $80
8c89: b0 08 bcs :NoConv ;(always)
8c8b: c9 41 :CheckRange cmp #‘A’ ;< 'A'?
8c8d: 90 04 bcc :NoConv ;yes, don't convert
8c8f: c9 5b cmp #‘[’ ;< 'Z'+1?
8c91: 90 03 bcc :NoSub ;yes, convert to lower by skipping the -$20
8c93: 38 :NoConv sec ;fonts don't store control character, so
8c94: e9 20 sbc #$20 ; subtract $20 to find start
8c96: 0a :NoSub asl A ;multiply by 8
8c97: 26 ef rol temp+1 ;($ef not initialized, but that's okay)
8c99: 0a asl A
8c9a: 26 ef rol temp+1
8c9c: 0a asl A
8c9d: 26 ef rol temp+1
8c9f: 18 clc
8ca0: 6d 66 89 adc FontAddr ;add to font address
8ca3: 85 ee sta temp ;save
8ca5: a5 ef lda temp+1 ;now the high byte of address
8ca7: 29 07 and #$07 ;mask off the uninitialized bits
8ca9: 6d 67 89 adc FontAddr+1
8cac: 85 ef sta temp+1
8cae: 20 ca 8d jsr GetHiResAddr ;get address in $2a-2b
8cb1: 65 24 adc MON_CH
8cb3: 85 2a sta hptr
8cb5: 85 ec sta hptr2
8cb7: a5 2b lda hptr+1 ;set hptr2 to be the source addr for blending
8cb9: 4d 63 89 eor PageFlipMask
8cbc: 85 ed sta hptr2+1
8cbe: a4 24 ldy MON_CH ;update text screen
8cc0: a5 ff lda SavedAcc
8cc2: 91 28 sta (MON_BASL),y
; Copy 8 bytes from the font to the screen. If we're merging with the existing
; contents, we pull them from hptr2, which may be the other page.
8cc4: a2 00 ldx #$00 ;always 0; "OP (dp)" introduced in 65c02
8cc6: a0 00 ldy #$00
8cc8: b1 ee :Loop lda (temp),y
8cca: 4d 61 89 eor InvFlag
8ccd: 2c 62 89 bit MixFlag ;how should we mix with existing pixels?
8cd0: 10 11 bpl :DoStore ;overwrite
8cd2: 70 0d bvs :DoXdraw ;xdraw
8cd4: 2c 61 89 bit InvFlag ;is inverse flag set?
8cd7: 70 04 bvs :DoInvMerge ;yes, AND our bits with the screen
8cd9: 01 ec ora (hptr2,x) ;no, OR our bits with the screen
8cdb: 50 06 bvc :DoStore
8cdd: 21 ec :DoInvMerge and (hptr2,x)
8cdf: 70 02 bvs :DoStore ;(always)
8ce1: 41 ec :DoXdraw eor (hptr2,x)
8ce3: 81 2a :DoStore sta (hptr,x) ;store merged value
8ce5: c8 iny
8ce6: c0 08 cpy #$08 ;did 8 lines?
8ce8: b0 0d bcs :CopyDone ;yes
8cea: a5 2b lda hptr+1 ;no, update hi-res addresses
8cec: 69 04 adc #$04 ;(within an aligned 8-line range, just add 4 to hi)
8cee: 85 2b sta hptr+1
8cf0: 4d 63 89 eor PageFlipMask
8cf3: 85 ed sta hptr2+1
8cf5: 90 d1 bcc :Loop ;(always)
8cf7: e6 24 :CopyDone inc MON_CH ;advance HTAB
8cf9: a5 24 lda MON_CH
8cfb: c5 21 cmp MON_WNDWDTH ;reached right edge?
8cfd: 90 20 bcc :Return ;no, good
MoveToLeftAndDown
8cff: a9 00 lda #$00 ;set HTAB to left edge
8d01: 85 24 sta MON_CH
8d03: e6 25 MoveDown inc MON_CV ;advance to next line
8d05: a5 25 lda MON_CV
8d07: c5 23 cmp MON_WNDBTM ;hit bottom?
8d09: 90 11 bcc :NotBottom ;no
8d0b: 2c 64 89 bit VertWrapFlag ;yes, should we scroll?
8d0e: 70 08 bvs :NoScroll ;no
8d10: c6 25 dec MON_CV ;yes, dec VTAB so we're back on screen
8d12: 20 20 8d jsr ScrollUp ;redraw screen contents
8d15: 4c 70 fc jmp MON_SCROLL ;scroll text screen
8d18: a5 22 :NoScroll lda MON_WNDTOP ;get window top
8d1a: 85 25 sta MON_CV ;store in VTAB
8d1c: 20 24 fc :NotBottom jsr MON_VTABZ ;update monitor text routines
8d1f: 60 :Return rts
; Scrolls the current text window up one line.
8d20: a5 22 ScrollUp lda MON_WNDTOP ;get top row
8d22: 48 pha
8d23: 20 cc 8d jsr GetHiResAddrA ;get hi-res base address for row + window left
8d26: a5 2a :TextLineLoop lda hptr ;this will be the destination row
8d28: 85 ec sta hptr2 ;copy to hptr2
8d2a: a5 2b lda hptr+1
8d2c: 29 e3 and #$e3 ;for 2nd and later iterations, reset to top of 8-row
8d2e: 85 ed sta hptr2+1 ; section
8d30: 68 pla
8d31: 18 clc
8d32: 69 01 adc #$01
8d34: c5 23 cmp MON_WNDBTM ;have we reached the bottom row?
8d36: b0 22 bcs :CopyDone ;yes, done
8d38: 48 pha
8d39: 20 cc 8d jsr GetHiResAddrA ;get hi-res base address for source row
8d3c: a2 07 ldx #$07 ;copy 8 rows
8d3e: a4 21 :RowLoop ldy MON_WNDWDTH ;from right to left
8d40: 88 dey
8d41: b1 2a :ColLoop lda (hptr),y
8d43: 91 ec sta (hptr2),y
8d45: 88 dey
8d46: 10 f9 bpl :ColLoop
8d48: ca dex
8d49: 30 db bmi :TextLineLoop ;if all rows done, move on to next line of text
8d4b: 18 clc ;advance pointers to next row
8d4c: a5 2b lda hptr+1
8d4e: 69 04 adc #$04
8d50: 85 2b sta hptr+1
8d52: a5 ed lda hptr2+1
8d54: 69 04 adc #$04
8d56: 85 ed sta hptr2+1
8d58: d0 e4 bne :RowLoop
8d5a: ad 62 89 :CopyDone lda MixFlag ;save MixFlag
8d5d: 48 pha
8d5e: a5 23 lda MON_WNDBTM ;clear last line
8d60: e9 01 sbc #$01
8d62: a0 00 ldy #$00 ;always clear
8d64: 8c 62 89 sty MixFlag
8d67: 20 90 8d jsr ClearToEol2 ;A=row, Y=col
8d6a: 68 pla
8d6b: 8d 62 89 sta MixFlag ;restore MixFlag
8d6e: 60 rts
8d6f: a5 22 ClearWindow lda MON_WNDTOP ;start from the top of the window
8d71: 85 25 sta MON_CV
8d73: a0 00 ldy #$00
8d75: 84 24 sty MON_CH
8d77: f0 04 beq :LineLoop
8d79: a4 24 ClearToEos ldy MON_CH ;start from current VTAB/HTAB
8d7b: a5 25 lda MON_CV
8d7d: 48 :LineLoop pha
8d7e: 20 90 8d jsr ClearToEol2
8d81: 68 pla
8d82: 18 clc
8d83: 69 01 adc #$01
8d85: c5 23 cmp MON_WNDBTM
8d87: a0 00 ldy #$00
8d89: 90 f2 bcc :LineLoop
8d8b: 60 rts
8d8c: a4 24 ClearToEol ldy MON_CH
8d8e: a5 25 lda MON_CV
; Clear from the current position (VTAB in A-reg, HTAB in Y-reg) to the end of
; the line by drawing individual bytes, obeying the inverse and mix flags as
; well as the page flip mode.
;
; On exit, Y will have its initial value.
8d90: 84 ee ClearToEol2 sty temp ;save Y-reg
8d92: 20 cc 8d jsr GetHiResAddrA ;get address in $2a-2b for line in A-reg
8d95: a2 07 ldx #$07 ;write 8 bytes
8d97: ad 61 89 :Loop lda InvFlag ;clear to $00 or $7f
8d9a: 2c 62 89 bit MixFlag ;check mix mode
8d9d: 10 15 bpl :DoDraw ;branch if overwrite
8d9f: a5 2a lda hptr ;set up alternate page source for blend modes
8da1: 85 ec sta hptr2
8da3: a5 2b lda hptr+1
8da5: 4d 63 89 eor PageFlipMask
8da8: 85 ed sta hptr2+1
8daa: b1 ec lda (hptr2),y ;get current data
8dac: 2c 62 89 bit MixFlag
8daf: 50 03 bvc :DoDraw ;blend mode, keep existing
8db1: 4d 61 89 eor InvFlag ;invert if invert flag set
8db4: 91 2a :DoDraw sta (hptr),y
8db6: c8 iny
8db7: c4 21 cpy MON_WNDWDTH ;reached right edge of window?
8db9: 90 dc bcc :Loop ;not yet
8dbb: ca dex ;done 8 bytes?
8dbc: 30 0b bmi :Done ;yes, bail
8dbe: a4 ee ldy temp ;advance hptr
8dc0: a5 2b lda hptr+1
8dc2: 18 clc
8dc3: 69 04 adc #$04
8dc5: 85 2b sta hptr+1
8dc7: d0 ce bne :Loop ;(always)
8dc9: 60 :Done rts
; Gets the hi-res base address, and stores it in $2a-2b.
8dca: a5 25 GetHiResAddr lda MON_CV ;get VTAB (0-23)
8dcc: 4a GetHiResAddrA lsr A ;do some math to get hi-res base address
8dcd: aa tax
8dce: 29 03 and #$03
8dd0: 0d 60 89 ora HiResPage
8dd3: 85 2b sta hptr+1
8dd5: bd de 8d lda HiResAddrLo,x ;table lookups make the math easier
8dd8: 6a ror A
8dd9: 65 20 adc MON_WNDLEFT ;add window left
8ddb: 85 2a sta hptr
8ddd: 60 rts
8dde: 00 00 00 00+ HiResAddrLo .bulk 0000000050505050a0a0a0a0
8dea: b9 a2 a0 d2+ .bulk b9a2a0d2e9a0f2a0a5b9c180c4cda08ca0aca0a0 ;unused?
8dfe: 00 00 00 00+ DefaultFont .bulk 00000000000000000808080808000800141414000000000014143e143e141400
+ 083c0a1c281e08000626100804323000040a0a042a122c000808080000000000
+ 08040202020408000810202020100800082a1c081c2a08000008083e08080000
+ 00000000080804000000003e0000000000000000000008000020100804020000
+ 1c22322a26221c00080c080808081c001c22201804023e003e20101820221c00
+ 101814123e1010003e021e2020221c003804021e22221c003e20100804040400
+ 1c22221c22221c001c22223c20100e0000000800080000000000080008080400
+ 100804020408100000003e003e00000004081020100804001c22100808000800
+ 1c222a3a1a023c00081422223e2222001e22221e22221e001c22020202221c00
+ 1e22222222221e003e02021e02023e003e02021e020202003c02020232223c00
+ 2222223e222222001c08080808081c002020202020221c0022120a060a122200
+ 0202020202023e0022362a2a222222002222262a322222001c22222222221c00
+ 1e22221e020202001c2222222a122c001e22221e0a1222001c22021c20221c00
+ 3e080808080808002222222222221c0022222222221408002222222a2a362200
+ 222214081422220022221408080808003e20100804023e003e06060606063e00
+ 00020408102000003e30303030303e000000081422000000000000000000007f
+ 040810000000000000001c203c223c0002021e2222221e0000003c0202023c00
+ 20203c2222223c0000001c223e023c001824041e0404040000001c22223c201c
+ 02021e222222220008000c0808081c00100018101010120c020222120e122200
+ 0c08080808081c000000362a2a2a220000001e222222220000001c2222221c00
+ 00001e22221e020200003c22223c202000003a060202020000003c021c201e00
+ 04041e04042418000000222222322c000000222222140800000022222a2a3600
+ 000022140814220000002222223c201c00003e1008043e00380c0c060c0c3800
+ 08080808080808080e18183018180e002c1a0000000000007f7f7f7f7f7f7f7f