]> git.sur5r.net Git - cc65/blob - libsrc/c64/soft80_cputc.s
optimize charcode conversion, shorter and faster now :)
[cc65] / libsrc / c64 / soft80_cputc.s
1 ;
2 ; Groepaz/Hitmen, 11.10.2015
3 ;
4 ; void cputcxy (unsigned char x, unsigned char y, char c);
5 ; void cputc (char c);
6 ;
7
8         .export         soft80_cputcxy, soft80_cputc
9         .export         soft80_cputdirect, soft80_putchar
10         .export         soft80_newline, soft80_plot
11
12         .import         popa, _gotoxy
13
14         .import         soft80_kplot
15         .import         soft80_internal_bgcolor, soft80_internal_textcolor
16         .import         soft80_internal_cursorxlsb
17
18         .importzp       tmp4,tmp3
19
20         .include        "c64.inc"
21         .include        "soft80.inc"
22
23 soft80_cputcxy:
24         pha                     ; Save C
25         jsr     popa            ; Get Y
26         jsr     _gotoxy         ; Set cursor, drop x
27         pla                     ; Restore C
28
29 ; Plot a character - also used as internal function
30
31 soft80_cputc:
32         cmp     #$0A            ; CR?
33         bne     L1
34
35         lda     #0
36         sta     CURS_X
37
38         ; Set cursor position, calculate RAM pointers
39 soft80_plot:
40         ldx     CURS_Y
41         ldy     CURS_X
42         clc
43         jmp     soft80_kplot    ; Set the new cursor
44
45 L1:     cmp     #$0D            ; LF?
46         beq     soft80_newline  ; Recalculate pointers
47
48         ; shortcut for codes < $80 ... codes $20-$7f can be printed directly,
49         ; codes $00-$1f are control codes which are not printable and thus may
50         ; give undefined result.
51         tay
52         bpl     @L10
53
54         ; codes $80-$ff must get converted like this:
55         ; $80-$9f  ->   dont care (control codes)
56         ; $a0-$bf  ->   $00-$1f
57         ; $c0-$df  ->   $60-$7f
58         ; $e0-$ff  ->   $00-$1f
59
60         ora     #%01000000      ; $40
61         clc
62         adc     #%00100000      ; $20
63         and     #%01111111      ; $7f
64 @L10:
65
66         ; entry point for direct output of a character. the value passed in
67         ; akku must match the offset in the charset.
68         ; - the following may not modify tmp1
69 soft80_cputdirect:
70         jsr     soft80_putchar  ; Write the character to the screen
71
72         ; Advance cursor position
73         iny                     ; contains CURS_X
74         cpy     #charsperline
75         beq     L3
76
77         sty     CURS_X
78         tya
79         and     #$01
80         sta     soft80_internal_cursorxlsb
81         bne     @L5
82
83         lda     SCREEN_PTR
84         clc
85         adc     #8
86         sta     SCREEN_PTR
87         bcc     @L4
88         inc     SCREEN_PTR+1
89 @L4:
90         inc     CRAM_PTR
91         bne     @L5
92         inc     CRAM_PTR+1
93 @L5:
94         rts
95 L3:
96         inc     CURS_Y          ; new line
97         ldy     #0              ; + cr
98         sty     CURS_X
99         jmp     soft80_plot
100
101         ; - the following may not modify tmp1
102 soft80_newline:
103
104         lda     SCREEN_PTR
105         clc
106         adc     #<(40*8)
107         sta     SCREEN_PTR
108
109         lda     SCREEN_PTR+1
110         adc     #>(40*8)
111         sta     SCREEN_PTR+1
112
113         lda     CRAM_PTR
114         clc
115         adc     #40
116         sta     CRAM_PTR
117         bcc     L5
118         inc     CRAM_PTR+1
119 L5:
120         inc     CURS_Y
121         rts
122
123 ;-------------------------------------------------------------------------------
124 ; All following code belongs to the character output to bitmap
125 ;
126 ; this stuff is going to be used a lot so we unroll it a bit for speed
127 ;-------------------------------------------------------------------------------
128
129 .if SOFT80FASTSPACE = 1
130
131 ; output inverted space (odd)
132 draw_spaceinvers_odd:
133         .repeat 8,line
134         lda     (SCREEN_PTR),y
135         and     #$f0
136         sta     (SCREEN_PTR),y
137         .if line < 7
138         iny
139         .endif
140         .endrepeat
141         jmp     draw_back
142
143 ; output inverted space (general entry point)
144 ; in: y must be $00
145 draw_spaceinvers:
146
147 .if SOFT80COLORVOODOO = 1
148         jsr     soft80_putcolor
149 .else
150         lda     CHARCOLOR
151         sta     (CRAM_PTR),y    ; vram
152 .endif
153
154         lda     soft80_internal_cursorxlsb
155         bne     draw_spaceinvers_odd
156
157 ; output inverted space (even)
158         .repeat 8,line
159         lda     (SCREEN_PTR),y
160         and     #$0f
161         sta     (SCREEN_PTR),y
162         .if line < 7
163         iny
164         .endif
165         .endrepeat
166         jmp     draw_back
167
168 ; output space (odd)
169 draw_space_odd:
170         .repeat 8,line
171         lda     (SCREEN_PTR),y
172         ora     #$0f
173         sta     (SCREEN_PTR),y
174         .if line < 7
175         iny
176         .endif
177         .endrepeat
178         jmp     draw_back
179
180 ; output space (general entry point)
181 ; in: y must be $00
182 draw_space:
183
184         lda     RVS
185         bne     draw_spaceinvers
186
187 .if SOFT80COLORVOODOO = 1
188         jsr     remcolor
189 .endif
190         ;ldy     #$00            ; is still $00
191
192         lda     soft80_internal_cursorxlsb
193         bne     draw_space_odd
194
195 ; output space (even)
196         .repeat 8,line
197         lda     (SCREEN_PTR),y
198         ora     #$f0
199         sta     (SCREEN_PTR),y
200         .if (line < 7)
201         iny
202         .endif
203         .endrepeat
204         jmp     draw_back
205 .endif
206
207 ;-------------------------------------------------------------------------------
208 ; output one character in internal encoding without advancing cursor position
209 ; generic entry point
210 ;
211 ; - the following may not modify tmp1
212 ; in:   A: charcode
213 ; out:  Y: CURS_X
214 ;
215 soft80_putchar:
216         sta     tmp3            ; remember charcode
217
218         sei
219         ldx     $01
220         stx     tmp4
221         ldx     #$34
222
223         stx     $01             ; will stay $34 for space
224         ldy     #$00            ; will be $00 from now on
225
226 .if SOFT80FASTSPACE = 1
227         cmp     #' '            ; space is a special (optimized) case
228         beq     draw_space
229 .endif
230
231 .if SOFT80COLORVOODOO = 1
232         jsr     soft80_putcolor
233 .else
234         lda     CHARCOLOR
235         sta     (CRAM_PTR),y    ; vram
236 .endif
237
238 ; output character
239         ldx     tmp3            ; get charcode
240
241         lda     RVS
242         beq     @skp
243         jmp     draw_charinvers
244 @skp:
245         lda     soft80_internal_cursorxlsb
246         bne     draw_char_even
247
248 ; output character (odd)
249         .repeat 8,line
250         lda     (SCREEN_PTR),y
251         and     #$0f
252         ora     soft80_hi_charset+(line*$80),x
253         sta     (SCREEN_PTR),y
254         .if line < 7
255         iny
256         .endif
257         .endrepeat
258         jmp     draw_back
259
260 ; output character (even)
261 draw_char_even:
262         .repeat 8,line
263         lda     (SCREEN_PTR),y
264         and     #$f0
265         ora     soft80_lo_charset+(line*$80),x
266         sta     (SCREEN_PTR),y
267         .if line < 7
268         iny
269         .endif
270         .endrepeat
271
272 draw_back:
273         lda     tmp4
274         sta     $01
275         cli
276
277         ldy     CURS_X
278         rts
279
280 ; output inverted character (odd)
281 draw_charinvers_odd:
282         .repeat 8,line
283         lda     (SCREEN_PTR),y
284         ora     #$0f
285         eor     soft80_lo_charset+(line*$80),x
286         sta     (SCREEN_PTR),y
287         .if line < 7
288         iny
289         .endif
290         .endrepeat
291         jmp     draw_back
292
293 ; output inverted character (generic)
294 draw_charinvers:
295         lda     soft80_internal_cursorxlsb
296         bne     draw_charinvers_odd
297
298         .repeat 8,line
299         lda     (SCREEN_PTR),y
300         ora     #$f0
301         eor     soft80_hi_charset+(line*$80),x
302         sta     (SCREEN_PTR),y
303         .if line < 7
304         iny
305         .endif
306         .endrepeat
307         jmp     draw_back
308
309 ;-------------------------------------------------------------------------------
310 ; optional "color voodoo". the problem is that each 8x8 cell can only contain
311 ; two colors, one of which is used for the background color, so two characters
312 ; have to share the same text color.
313 ;
314 ; - in a cell that contains two spaces, both the color ram and the text color
315 ;   in vram contain the background color
316 ;
317 ; - in a cell that contains one character, its text color goes into vram. the
318 ;   color ram contains the background color.
319 ;
320 ; - in a cell that contains two characters, the color of the left character goes
321 ;   to vram (and is shared by both for display). the "would be" color of the
322 ;   right character goes to color ram as a reminder and can be restored when one
323 ;   of the two characters is cleared by a space.
324
325 .if SOFT80COLORVOODOO = 1
326
327 ; remove color from cell, called before putting a "space" character to the bitmap
328 ;
329 ; __ -> __      -
330 ; _A -> _A      -
331 ; B_ -> B_      -
332 ; _A -> __      vram = bgcol
333 ; B_ -> __      vram = bgcol
334 ; BA -> _A      vram = colram, colram = bgcol
335 ; BA -> B_      colram = bgcol
336 ;
337 ; in:  x must be $34
338 ;      y must be $00
339 ; out: y = $00
340 remcolor:
341
342         ;ldy     #$00            ; is still $00
343
344         ; if the textcolor in vram is equal to the background color, then
345         ; no (visible) character is in the current cell and we can exit
346         ; immediately.
347         lda     (CRAM_PTR),y    ; vram (textcolor)
348         and     #$0f
349         cmp     soft80_internal_bgcolor
350         beq     @sk1            ; yes, vram==bgcolor
351
352         ; now check if the textcolor in color ram is equal the background color,
353         ; if yes then there is only one (visible) character in the current cell
354         inc     $01             ; $35
355         lda     (CRAM_PTR),y    ; colram (2nd textcolor)
356         stx     $01             ; $34
357         and     #$0f
358         cmp     soft80_internal_bgcolor
359         beq     @sk2            ; yes, colram==bgcolor
360
361         ; two characters in the current cell, of which one will get removed
362
363         ; vram = colram
364         ;inc     $01
365         ;lda     (CRAM_PTR),y    ; colram
366         ;stx     $01             ;$34
367         ;and     #$0f
368         sta     tmp3            ; A contains colram
369
370         lda     soft80_internal_cursorxlsb
371         bne     @sk3
372
373         ; vram = colram
374         lda     (CRAM_PTR),y    ; vram
375         and     #$f0
376         ora     tmp3
377         sta     (CRAM_PTR),y    ; vram
378 @sk3:
379         ; colram = bgcolor
380         lda     soft80_internal_bgcolor
381         inc     $01             ; $35
382         sta     (CRAM_PTR),y    ; colram
383         stx     $01             ; $34
384
385         rts
386
387 @sk2:
388         ; colram is bgcolor
389         ; => only one char in cell used
390
391         jsr     soft80_checkchar
392         bcc     @sk1            ; space at current position
393
394         ; vram (textcolor) = bgcolor
395         lda     (CRAM_PTR),y    ; vram
396         and     #$f0
397         ora     soft80_internal_bgcolor
398         sta     (CRAM_PTR),y    ; vram
399 @sk1:
400         rts
401
402 ; put color to cell
403 ;
404 ; __ -> _A      vram = textcol
405 ; __ -> B_      vram = textcol
406 ; _A -> BA      colram = vram, vram = textcol
407 ; B_ -> BA      colram = textcol
408 ;
409 ; _A -> _C      vram = textcol
410 ; B_ -> C_      vram = textcol
411 ; BA -> BC      colram = textcol
412 ; BA -> CA      vram = textcol
413 ;
414 ; in:  $01 is $34 (RAM under I/O) when entering
415 ;      x must be $34
416 ;      y must be $00
417 ; out: x = $34
418 ;      y = $00
419 soft80_putcolor:
420
421         ;ldy     #$00            ; is still $00
422
423         lda     (CRAM_PTR),y    ; vram
424         and     #$0f
425         cmp     soft80_internal_bgcolor
426         beq     @sk1            ; vram==bgcolor => first char in cell
427
428         ; vram!=bgcolor => second char in cell
429
430         inc     $01             ; $35
431         lda     (CRAM_PTR),y    ; colram
432         stx     $01             ; $34
433         and     #$0f
434         cmp     soft80_internal_bgcolor
435         beq     @l2s            ; colram==bgcolor -> second char in cell
436
437         ; botch characters in the cell are used
438
439         lda     soft80_internal_cursorxlsb
440         bne     @sk2            ; jump if odd xpos
441
442         ; vram = textcol
443         lda     CHARCOLOR
444         sta     (CRAM_PTR),y    ; vram
445         rts
446
447 @l2s:
448         ; one character in cell is already used
449         jsr     soft80_checkchar
450         bcs     @sk1            ; char at current position => overwrite 1st
451
452         lda     soft80_internal_cursorxlsb
453         beq     @sk3            ; jump if even xpos
454 @sk2:
455         ; colram = textcol
456         lda     soft80_internal_textcolor
457         inc     $01             ; $35
458         sta     (CRAM_PTR),y    ; colram
459         stx     $01             ; $34
460         rts
461
462 @sk3:
463         ; colram=vram
464         lda     (CRAM_PTR),y    ; vram
465         inc     $01             ; $35
466         sta     (CRAM_PTR),y    ; colram
467         stx     $01             ; $34
468 @sk1:
469         ; vram = textcol
470         lda     CHARCOLOR
471         sta     (CRAM_PTR),y    ; vram
472         rts
473
474 ;
475 ; test if there is a space or a character at current position
476 ;
477 ; in:  x = $34
478 ;      y must be $00
479 ; out: CLC: space        SEC: character
480 ;      x = $34
481 ;      y = $00
482 soft80_checkchar:
483
484         ;ldy     #$00                            ; is still $00
485
486         lda     soft80_internal_cursorxlsb
487         bne     @l1a
488
489         ; check charset data from bottom up, since a lot of eg lowercase chars
490         ; have no data in the top rows, but all of them DO have data in the
491         ; second to bottom row, this will likely be faster in average.
492
493         ldy     #7
494         .repeat 8,line
495         lda     (SCREEN_PTR),y
496         and     #$f0
497         cmp     #$f0
498         bne     @ischar
499         .if (line < 7)
500         dey
501         .endif
502         .endrepeat
503         ;ldy     #$00                            ; is 0
504         clc
505         rts
506 @ischar:
507         ldy     #$00
508         sec
509         rts
510 @l1a:
511         ldy     #$07
512         .repeat 8,line
513         lda     (SCREEN_PTR),y
514         and     #$0f
515         cmp     #$0f
516         bne     @ischar
517         .if line < 7
518         dey
519         .endif
520         .endrepeat
521         ;ldy     #$00                            ; is 0
522         clc
523         rts
524 .endif