aboutsummaryrefslogtreecommitdiff
path: root/console.s
blob: 18b22bfc7ec9dd0f3c10ca013a7c6366dd08c19e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209


 .include "atari.inc"
 .export _clrtobot, _clrtoeol, _clr_screen, _clrtoline, _cspaces, _cblank, _backspace, _cprint_pipe, _cprint_bang, _cspace, _cputc_s, _comma_space, _cprint_colon_space, _cprint_question_space, _cprint_period, _cprint_taipan_prompt
 .export _rvs_on, _rvs_off

 .import mul40        ; from cc65's runtime
 .importzp tmp3       ; ditto
 .import _revflag     ; conio/revers.s
 .import bump_destptr ; these two are
 .importzp destptr    ; from draw_lorcha.s
 .importzp sreg
 .import _cprintulong, _cputc, _cprint_taipan

 .ifdef CART_TARGET
  .segment "HIGHCODE"
 .else
  .code
 .endif


; void clr_screen(void);
; void clrtobot(void);
; void clrtoeol(void);
; void clrtoline(unsigned char line);

; this stuff doesn't disturb conio's (and the OS's) idea of the
; current cursor position. It's *way* faster than writing them in
; C in terms of cclear() (which uses one cputc() call per blank).

_clr_screen: ; same as gotoxy(0,0); clrtobot();
 lda #0
 sta ROWCRS
 sta COLCRS

_clrtobot: ; same as clrtoline(24);
 lda #24
 ;bne _clrtoline ; we'd have to do this if ROWCRS were non-zero-page
 .byte $2c ; see "bit trick" explanation below

_clrtoeol:
 lda ROWCRS
 ; fall through to _clrtoline

_clrtoline:
 sta tmp3 ; stash our arg

 ;lda #0
 ;sta OLDCHR ; stop conio from redrawing stuff after we clear it,
             ; no longer needed with our custom conio.

 ; setup destptr to start of current line, NOT
 ; current cursor position.
 lda ROWCRS
 jsr mul40  ; AX = A*40 (addr of start-of-row)
 clc
 adc SAVMSC ; add AX to screen pointer
 sta destptr
 txa
 adc SAVMSC+1
 sta destptr+1

 ; X = current row, Y = current column. Stop clearing a line when Y == 40,
 ; we're done when X == 24. Apologies, the names X and Y are backwards
 ; compared to proper Cartesian coordinates.
 ldx ROWCRS
 ldy COLCRS
 lda #0

clrloop:
 sta (destptr),y ; blank a character (A == 0, screen code for a space)
 iny
 cpy #40
 bne clrloop
 ldy #0
 inx
 cpx tmp3
 bcs done

 jsr bump_destptr
 lda #0
 tay
 beq clrloop

done:
 rts

_cspaces:
 sta tmp3
@lp:
 jsr _cspace
 dec tmp3
 bne @lp
 rts

_backspace:
 dec COLCRS
 lda #1
 ; fall through to _cblank

_cblank:
 tax
 lda COLCRS
 pha
 lda ROWCRS
 pha
 txa
 jsr _cspaces
 pla
 sta ROWCRS
 pla
 sta COLCRS
 rts

_rvs_on:
 lda #$80
 .byte $2c ; BIT absolute opcode
_rvs_off:
 lda #0
 sta _revflag
 rts

 ; micro-optimizations here.
 ; the stuff below might be a bit hard to follow, but it saves code.
 ; calling this: cputs("? ");
 ; emits code like this:
 ;  lda #<Lxxx
 ;  ldx #>Lxxx
 ;  jsr _cputs
 ; ...which is 9 bytes per call (plus 3 bytes for the "? " string itself).
 ; replacing each cputs("? "); with cprint_question_space() means 3 bytes
 ; per call (a JSR). there are 3 'some char followed by a space' routines
 ; here, totalling 10 bytes. the actual space is printed by code shared
 ; with cspace().
 ; also, there are 5 'print a single character' routines. each one would
 ; normally be cputc('X'), which compiles to:
 ;  lda #'X'
 ;  jsr _cputc
 ; ...or 5 bytes each. we have 5 of them, so 25 bytes. using fall-thru
 ; and the BIT trick, they condense down to 17 bytes.
 ; if you're not familiar with the "BIT trick" to skip a 2-byte instruction,
 ; the stuff below looks like gibberish... here's a mini-tutorial:

 ;store1:
 ; lda #1
 ; .byte $2c ; this is the opcode for BIT absolute
 ;store2:
 ; lda #2
 ; sta $0600
 ; rts

 ; if entered via "jsr store1", the above code fragment executes these
 ; instructions:
 ; lda #1
 ; bit $02A9 ; $A9 is the LDA immediate opcode, 02 is the #2
 ; sta $0600
 ; rts

 ; if entered via "jsr store2", it's
 ; lda #2
 ; sta $0600
 ; rts

 ; the "bit $02a9' doesn't affect any registers other than the flags,
 ; and the "sta $0600 : rts" part doesn't depend on any of the flags,
 ; so the BIT is effectively a no-op that "masks" the 2-byte LDA #2
 ; instruction "hidden" as its operand.

 ; ", Taipan? "
 ; using fall-thru here saves 3 bytes (normally the last instruction
 ; would be "jmp _cprint_question_space")
_cprint_taipan_prompt:
 jsr _comma_space
 jsr _cprint_taipan
 ; fall thru

 ; each entry point here prints one character followed by a space
 ; "? "
_cprint_question_space:
 lda #'?'
 .byte $2c

 ; ": "
_cprint_colon_space:
 lda #':'
 .byte $2c

 ; ", "
_comma_space:
 lda #','
 jsr _cputc
 ; fall thru

 ; each entry point here prints one character
_cspace:
 lda #' '
 .byte $2c
_cprint_pipe:
 lda #'|'
 .byte $2c
_cputc_s:
 lda #'s'
 .byte $2c
_cprint_period:
 lda #'.'
 .byte $2c
_cprint_bang:
 lda #'!'
 jmp _cputc