]> git.sur5r.net Git - cc65/blob - libsrc/c128/tgi/c128-hi.s
tgi driver for c128 VIC-II
[cc65] / libsrc / c128 / tgi / c128-hi.s
1 ;
2 ; Graphics driver for the 320x200x2 mode on the C128.
3 ;
4 ; Based on Stephen L. Judd's GRLIB code.
5 ;
6 ; 2017-01-13, Greg King
7 ; 2018-03-13, Sven Klose
8 ; 2018-07-22, Scott Hutter
9 ;
10
11         .include        "zeropage.inc"
12
13         .include        "tgi-kernel.inc"
14         .include        "tgi-error.inc"
15
16         .macpack        generic
17         .macpack        module
18
19
20 ; ------------------------------------------------------------------------
21 ; Header. Includes jump table and constants.
22
23         module_header   _c128_hi_tgi
24
25 ; First part of the header is a structure that has a magic and defines the
26 ; capabilities of the driver
27
28         .byte   $74, $67, $69           ; "tgi"
29         .byte   TGI_API_VERSION         ; TGI API version number
30         .addr   $0000                   ; Library reference
31         .word   320                     ; X resolution
32         .word   200                     ; Y resolution
33         .byte   2                       ; Number of drawing colors
34         .byte   1                       ; Number of screens available
35         .byte   8                       ; System font X size
36         .byte   8                       ; System font Y size
37         .word   $00D4                   ; Aspect ratio (based on 4/3 display)
38         .byte   0                       ; TGI driver flags
39
40 ; Next comes the jump table. With the exception of IRQ, all entries must be
41 ; valid and may point to an RTS for test versions (function not implemented).
42
43         .addr   INSTALL
44         .addr   UNINSTALL
45         .addr   INIT
46         .addr   DONE
47         .addr   GETERROR
48         .addr   CONTROL
49         .addr   CLEAR
50         .addr   SETVIEWPAGE
51         .addr   SETDRAWPAGE
52         .addr   SETCOLOR
53         .addr   SETPALETTE
54         .addr   GETPALETTE
55         .addr   GETDEFPALETTE
56         .addr   SETPIXEL
57         .addr   GETPIXEL
58         .addr   LINE
59         .addr   BAR
60         .addr   TEXTSTYLE
61         .addr   OUTTEXT
62
63 ; ------------------------------------------------------------------------
64 ; Data.
65
66 ; Variables mapped to the zero page segment variables. Some of these are
67 ; used for passing parameters to the driver.
68
69 X1              := ptr1
70 Y1              := ptr2
71 X2              := ptr3
72 Y2              := ptr4
73 TEXT            := ptr3
74
75 TEMP            := tmp4
76 TEMP2           := sreg
77 POINT           := regsave
78
79 CHUNK           := X2           ; Used in the line routine
80 OLDCHUNK        := X2+1         ; Dito
81
82 ; Absolute variables used in the code
83
84 .bss
85
86 ERROR:          .res    1       ; Error code
87 PALETTE:        .res    2       ; The current palette
88
89 BITMASK:        .res    1       ; $00 = clear, $FF = set pixels
90
91 ; INIT/DONE
92 OLDD018:        .res    1       ; Old register value
93
94 ; Line routine stuff
95 DX:             .res    2
96 DY:             .res    2
97
98 ; BAR variables
99 X1SAVE:         .res    2
100 Y1SAVE:         .res    2
101 X2SAVE:         .res    2
102 Y2SAVE:         .res    2
103
104 ; Text output stuff
105 TEXTMAGX:       .res    1
106 TEXTMAGY:       .res    1
107 TEXTDIR:        .res    1
108
109 ; Constants and tables
110
111 .rodata
112
113 DEFPALETTE:     .byte   $00, $01        ; White on black
114 PALETTESIZE     = * - DEFPALETTE
115
116 BITTAB:         .byte   $80,$40,$20,$10,$08,$04,$02,$01
117 BITCHUNK:       .byte   $FF,$7F,$3F,$1F,$0F,$07,$03,$01
118
119 CHARROM         := $D000                ; Character rom base address
120 CBASE           := $5C00                ; Color memory base address
121 VBASE           := $6000                ; Video memory base address
122                                                                                 ; BASE + $4000 for each bank above VIC bank 0
123                                                                                 ; $2000 = VIC bank 0 (base)
124                                                                                 ; $6000 = VIC bank 1
125                                                                                 ; $A000 = VIC bank 2
126                                                                                 ; $E000 = VIC bank 3
127
128
129 .code
130
131 ; ------------------------------------------------------------------------
132 ; INSTALL routine. Is called after the driver is loaded into memory. May
133 ; initialize anything that has to be done just once. Is probably empty
134 ; most of the time.
135 ;
136 ; Must set an error code: NO
137 ;
138
139 INSTALL:
140 ;       rts                     ; fall through
141
142
143 ; ------------------------------------------------------------------------
144 ; UNINSTALL routine. Is called before the driver is removed from memory. May
145 ; clean up anything done by INSTALL but is probably empty most of the time.
146 ;
147 ; Must set an error code: NO
148 ;
149
150 UNINSTALL:
151         rts
152
153
154 ; ------------------------------------------------------------------------
155 ; INIT: Changes an already installed device from text mode to graphics
156 ; mode.
157 ; Note that INIT/DONE may be called multiple times while the driver
158 ; is loaded, while INSTALL is only called once, so any code that is needed
159 ; to initializes variables and so on must go here. Setting palette and
160 ; clearing the screen is not needed because this is called by the graphics
161 ; kernel later.
162 ; The graphics kernel will never call INIT when a graphics mode is already
163 ; active, so there is no need to protect against that.
164 ;
165 ; Must set an error code: YES
166 ;
167
168 INIT:
169 ; Initialize variables
170         ldx     #$FF
171         stx     BITMASK
172
173 ; Switch into graphics mode
174
175                 ; select video bank
176                 ; bank 0=3 ($0-$3FFF) (default)
177                 ; bank 1=2 ($4000-$7FFF) *
178                 ; bank 2=1 ($8000-$BFFF)
179                 ; bank 3=0 ($C000-$FFFF)
180                 lda $DD00
181                 and #$FC
182                 ora #$02        ; bank number 1 ($4000)
183                 sta $DD00
184
185                 ; Switch to bitmap mode
186                 lda $D8
187                 ora #$20
188                 sta $D8
189                 
190 DONE1:  lda     #TGI_ERR_OK
191         sta     ERROR
192         rts
193
194 ; ------------------------------------------------------------------------
195 ; DONE: Will be called to switch the graphics device back into text mode.
196 ; The graphics kernel will never call DONE when no graphics mode is active,
197 ; so there is no need to protect against that.
198 ;
199 ; Must set an error code: NO
200 ;
201
202 DONE:   ; select video bank
203                 lda $DD00
204                 and #$FC
205                 ora #$03        ; bank 0=3 ($0-$3FFF), 1=2 ($4000-$7FFF), 2=1 ($8000-$BFFF), 3=0 ($C000-$FFFF)
206                 sta $DD00
207
208                 lda $0A2D       ; change screen ram location
209                 AND #$0F
210                 ORA #$10        ; $0400
211                 STA $0A2D   
212
213                 LDA #$00        ; switch back to text mode
214                 STA $D8
215         rts
216
217 ; ------------------------------------------------------------------------
218 ; GETERROR: Return the error code in A and clear it.
219
220 GETERROR:
221         ldx     #TGI_ERR_OK
222         lda     ERROR
223         stx     ERROR
224         rts
225
226 ; ------------------------------------------------------------------------
227 ; CONTROL: Platform/driver specific entry point.
228 ;
229 ; Must set an error code: YES
230 ;
231
232 CONTROL:
233         lda     #TGI_ERR_INV_FUNC
234         sta     ERROR
235         rts
236
237 ; ------------------------------------------------------------------------
238 ; CLEAR: Clears the screen.
239 ;
240 ; Must set an error code: NO
241 ;
242
243 CLEAR:  
244                 ldy     #$00
245         tya
246 @L1:    sta     VBASE+$0000,y
247         sta     VBASE+$0100,y
248         sta     VBASE+$0200,y
249         sta     VBASE+$0300,y
250         sta     VBASE+$0400,y
251         sta     VBASE+$0500,y
252         sta     VBASE+$0600,y
253         sta     VBASE+$0700,y
254         sta     VBASE+$0800,y
255         sta     VBASE+$0900,y
256         sta     VBASE+$0A00,y
257         sta     VBASE+$0B00,y
258         sta     VBASE+$0C00,y
259         sta     VBASE+$0D00,y
260         sta     VBASE+$0E00,y
261         sta     VBASE+$0F00,y
262         sta     VBASE+$1000,y
263         sta     VBASE+$1100,y
264         sta     VBASE+$1200,y
265         sta     VBASE+$1300,y
266         sta     VBASE+$1400,y
267         sta     VBASE+$1500,y
268         sta     VBASE+$1600,y
269         sta     VBASE+$1700,y
270         sta     VBASE+$1800,y
271         sta     VBASE+$1900,y
272         sta     VBASE+$1A00,y
273         sta     VBASE+$1B00,y
274         sta     VBASE+$1C00,y
275         sta     VBASE+$1D00,y
276         sta     VBASE+$1E00,y
277         sta     VBASE+$1E40,y   ; preserve vectors
278         iny
279         bne     @L1
280         rts
281
282 ; ------------------------------------------------------------------------
283 ; SETVIEWPAGE: Set the visible page. Called with the new page in A (0..n).
284 ; The page number is already checked to be valid by the graphics kernel.
285 ;
286 ; Must set an error code: NO (will only be called if page ok)
287 ;
288
289 SETVIEWPAGE:
290 ;       rts                     ; fall through
291
292 ; ------------------------------------------------------------------------
293 ; SETDRAWPAGE: Set the drawable page. Called with the new page in A (0..n).
294 ; The page number is already checked to be valid by the graphics kernel.
295 ;
296 ; Must set an error code: NO (will only be called if page ok)
297 ;
298
299 SETDRAWPAGE:
300         rts
301
302 ; ------------------------------------------------------------------------
303 ; SETCOLOR: Set the drawing color (in A). The new color is already checked
304 ; to be in a valid range (0..maxcolor-1).
305 ;
306 ; Must set an error code: NO (will only be called if color ok)
307 ;
308
309 SETCOLOR:
310         tax
311         beq     @L1
312         lda     #$FF
313 @L1:    sta     BITMASK
314         rts
315
316 ; ------------------------------------------------------------------------
317 ; SETPALETTE: Set the palette (not available with all drivers/hardware).
318 ; A pointer to the palette is passed in ptr1. Must set an error if palettes
319 ; are not supported
320 ;
321 ; Must set an error code: YES
322 ;
323
324 SETPALETTE:
325         ldy     #PALETTESIZE - 1
326 @L1:    lda     (ptr1),y        ; Copy the palette
327         and     #$0F            ; Make a valid color
328         sta     PALETTE,y
329         dey
330         bpl     @L1
331
332 ; Get the color entries from the palette
333
334         lda     PALETTE+1       ; Foreground color
335         asl     a
336         asl     a
337         asl     a
338         asl     a
339         ora     PALETTE         ; Background color
340         tax
341
342 ; Initialize the color map with the new color settings (it is below the
343 ; I/O area)
344
345         ldy     #$00
346         sei
347         lda     $01             ; Get ROM config
348         pha                     ; Save it
349         and     #%11111100      ; Clear bit 0 and 1
350         sta     $01
351         txa                     ; Load color code
352 @L2:    sta     CBASE+$0000,y
353         sta     CBASE+$0100,y
354         sta     CBASE+$0200,y
355         sta     CBASE+$02e8,y
356         iny
357         bne     @L2
358         pla
359         sta     $01
360         cli
361
362 ; Done, reset the error code
363
364         lda     #TGI_ERR_OK
365         sta     ERROR
366         rts
367
368 ; ------------------------------------------------------------------------
369 ; GETPALETTE: Return the current palette in A/X. Even drivers that cannot
370 ; set the palette should return the default palette here, so there's no
371 ; way for this function to fail.
372 ;
373 ; Must set an error code: NO
374 ;
375
376 GETPALETTE:
377         lda     #<PALETTE
378         ldx     #>PALETTE
379         rts
380
381 ; ------------------------------------------------------------------------
382 ; GETDEFPALETTE: Return the default palette for the driver in A/X. All
383 ; drivers should return something reasonable here, even drivers that don't
384 ; support palettes, otherwise the caller has no way to determine the colors
385 ; of the (not changeable) palette.
386 ;
387 ; Must set an error code: NO (all drivers must have a default palette)
388 ;
389
390 GETDEFPALETTE:
391         lda     #<DEFPALETTE
392         ldx     #>DEFPALETTE
393         rts
394
395 ; ------------------------------------------------------------------------
396 ; SETPIXEL: Draw one pixel at X1/Y1 = ptr1/ptr2 with the current drawing
397 ; color. The coordinates passed to this function are never outside the
398 ; visible screen area, so there is no need for clipping inside this function.
399 ;
400 ; Must set an error code: NO
401 ;
402
403 SETPIXEL:
404         jsr     CALC            ; Calculate coordinates
405
406         sei                     ; Get underneath ROM
407         lda     $01
408         pha
409         lda     #$34
410         sta     $01
411
412         lda     (POINT),Y
413         eor     BITMASK
414         and     BITTAB,X
415         eor     (POINT),Y
416         sta     (POINT),Y
417
418         pla
419         sta     $01
420         cli
421
422 @L9:    rts
423
424 ; ------------------------------------------------------------------------
425 ; GETPIXEL: Read the color value of a pixel and return it in A/X. The
426 ; coordinates passed to this function are never outside the visible screen
427 ; area, so there is no need for clipping inside this function.
428
429
430 GETPIXEL:
431         jsr     CALC            ; Calculate coordinates
432
433         sei                     ; Get underneath ROM
434         lda     $01
435         pha
436         lda     #$34
437         sta     $01
438
439         lda     (POINT),Y
440         ldy     #$00
441         and     BITTAB,X
442         beq     @L1
443         iny
444
445 @L1:    pla
446         sta     $01
447         cli
448
449         tya                     ; Get color value into A
450         ldx     #$00            ; Clear high byte
451         rts
452
453 ; ------------------------------------------------------------------------
454 ; LINE: Draw a line from X1/Y1 to X2/Y2, where X1/Y1 = ptr1/ptr2 and
455 ; X2/Y2 = ptr3/ptr4 using the current drawing color.
456 ;
457 ; X1,X2 etc. are set up above (x2=LINNUM in particular)
458 ; Format is LINE x2,y2,x1,y1
459 ;
460 ; Must set an error code: NO
461 ;
462
463 LINE:
464
465 @CHECK: lda     X2           ;Make sure x1<x2
466         sec
467         sbc     X1
468         tax
469         lda     X2+1
470         sbc     X1+1
471         bpl     @CONT
472         lda     Y2           ;If not, swap P1 and P2
473         ldy     Y1
474         sta     Y1
475         sty     Y2
476         lda     Y2+1
477         ldy     Y1+1
478         sta     Y1+1
479         sty     Y2+1
480         lda     X1
481         ldy     X2
482         sty     X1
483         sta     X2
484         lda     X2+1
485         ldy     X1+1
486         sta     X1+1
487         sty     X2+1
488         bcc     @CHECK
489
490 @CONT:  sta     DX+1
491         stx     DX
492
493         ldx     #$C8         ;INY
494         lda     Y2           ;Calculate dy
495         sec
496         sbc     Y1
497         tay
498         lda     Y2+1
499         sbc     Y1+1
500         bpl     @DYPOS       ;Is y2>=y1?
501         lda     Y1           ;Otherwise dy=y1-y2
502         sec
503         sbc     Y2
504         tay
505         ldx     #$88         ;DEY
506
507 @DYPOS: sty     DY              ; 8-bit DY -- FIX ME?
508         stx     YINCDEC
509         stx     XINCDEC
510
511         jsr     CALC            ; Set up .X, .Y, and POINT
512         lda     BITCHUNK,X
513         sta     OLDCHUNK
514         sta     CHUNK
515
516         sei                     ; Get underneath ROM
517         lda     #$34
518         sta     $01
519
520         ldx     DY
521         cpx     DX           ;Who's bigger: dy or dx?
522         bcc     STEPINX      ;If dx, then...
523         lda     DX+1
524         bne     STEPINX
525
526 ;
527 ; Big steps in Y
528 ;
529 ;   To simplify my life, just use PLOT to plot points.
530 ;
531 ;   No more!
532 ;   Added special plotting routine -- cool!
533 ;
534 ;   X is now counter, Y is y-coordinate
535 ;
536 ; On entry, X=DY=number of loop iterations, and Y=
537 ;   Y1 AND #$07
538 STEPINY:
539         lda     #00
540         sta     OLDCHUNK     ;So plotting routine will work right
541         lda     CHUNK
542         lsr                  ;Strip the bit
543         eor     CHUNK
544         sta     CHUNK
545         txa
546         beq     YCONT2       ;If dy=0, it's just a point
547 @CONT:  lsr                  ;Init counter to dy/2
548 ;
549 ; Main loop
550 ;
551 YLOOP:  sta     TEMP
552
553         lda     (POINT),y
554         eor     BITMASK
555         and     CHUNK
556         eor     (POINT),y
557         sta     (POINT),y
558 YINCDEC:
559         iny                  ;Advance Y coordinate
560         cpy     #8
561         bcc     @CONT        ;No prob if Y=0..7
562         jsr     FIXY
563 @CONT:  lda     TEMP         ;Restore A
564         sec
565         sbc     DX
566         bcc     YFIXX
567 YCONT:  dex                  ;X is counter
568         bne     YLOOP
569 YCONT2: lda     (POINT),y    ;Plot endpoint
570         eor     BITMASK
571         and     CHUNK
572         eor     (POINT),y
573         sta     (POINT),y
574         lda     #$36
575         sta     $01
576         cli
577         rts
578
579 YFIXX:                    ;x=x+1
580         adc     DY
581         lsr     CHUNK
582         bne     YCONT        ;If we pass a column boundary...
583         ror     CHUNK        ;then reset CHUNK to $80
584         sta     TEMP2
585         lda     POINT        ;And add 8 to POINT
586         adc     #8
587         sta     POINT
588         bcc     @CONT
589         inc     POINT+1
590 @CONT:  lda     TEMP2
591         dex
592         bne     YLOOP
593         beq     YCONT2
594
595 ;
596 ; Big steps in X direction
597 ;
598 ; On entry, X=DY=number of loop iterations, and Y=
599 ;   Y1 AND #$07
600
601 .bss
602 COUNTHI:
603         .byte   $00       ;Temporary counter
604                           ;only used once
605 .code
606 STEPINX:
607         ldx     DX
608         lda     DX+1
609         sta     COUNTHI
610         cmp     #$80
611         ror                  ;Need bit for initialization
612         sta     Y1           ;High byte of counter
613         txa
614         bne     @CONT        ;Could be $100
615         dec     COUNTHI
616 @CONT:  ror
617 ;
618 ; Main loop
619 ;
620 XLOOP:  lsr     CHUNK
621         beq     XFIXC        ;If we pass a column boundary...
622 XCONT1: sbc     DY
623         bcc     XFIXY        ;Time to step in Y?
624 XCONT2: dex
625         bne     XLOOP
626         dec     COUNTHI      ;High bits set?
627         bpl     XLOOP
628
629         lsr     CHUNK        ;Advance to last point
630         jsr     LINEPLOT     ;Plot the last chunk
631         lda     #$36
632         sta     $01
633         cli
634         rts
635 ;
636 ; CHUNK has passed a column, so plot and increment pointer
637 ; and fix up CHUNK, OLDCHUNK.
638 ;
639 XFIXC:  sta     TEMP
640         jsr     LINEPLOT
641         lda     #$FF
642         sta     CHUNK
643         sta     OLDCHUNK
644         lda     POINT
645         clc
646         adc     #8
647         sta     POINT
648         lda     TEMP
649         bcc     XCONT1
650         inc     POINT+1
651         jmp     XCONT1
652 ;
653 ; Check to make sure there isn't a high bit, plot chunk,
654 ; and update Y-coordinate.
655 ;
656 XFIXY:  dec     Y1           ;Maybe high bit set
657         bpl     XCONT2
658         adc     DX
659         sta     TEMP
660         lda     DX+1
661         adc     #$FF         ;Hi byte
662         sta     Y1
663
664         jsr     LINEPLOT     ;Plot chunk
665         lda     CHUNK
666         sta     OLDCHUNK
667
668         lda     TEMP
669 XINCDEC:
670         iny                  ;Y-coord
671         cpy     #8           ;0..7 is ok
672         bcc     XCONT2
673         sta     TEMP
674         jsr     FIXY
675         lda     TEMP
676         jmp     XCONT2
677
678 ;
679 ; Subroutine to plot chunks/points (to save a little
680 ; room, gray hair, etc.)
681 ;
682 LINEPLOT:                       ; Plot the line chunk
683         lda     (POINT),Y
684         eor     BITMASK
685         ora     CHUNK
686         and     OLDCHUNK
687         eor     CHUNK
688         eor     (POINT),Y
689         sta     (POINT),Y
690         rts
691
692 ;
693 ; Subroutine to fix up pointer when Y decreases through
694 ; zero or increases through 7.
695 ;
696 FIXY:   cpy     #255         ;Y=255 or Y=8
697         beq     @DECPTR
698
699 @INCPTR:                     ;Add 320 to pointer
700         ldy     #0           ;Y increased through 7
701         lda     POINT
702         adc     #<320
703         sta     POINT
704         lda     POINT+1
705         adc     #>320
706         sta     POINT+1
707         rts
708
709 @DECPTR:                     ;Okay, subtract 320 then
710         ldy     #7           ;Y decreased through 0
711         lda     POINT
712         sec
713         sbc     #<320
714         sta     POINT
715         lda     POINT+1
716         sbc     #>320
717         sta     POINT+1
718         rts
719
720 ; ------------------------------------------------------------------------
721 ; BAR: Draw a filled rectangle with the corners X1/Y1, X2/Y2, where
722 ; X1/Y1 = ptr1/ptr2 and X2/Y2 = ptr3/ptr4 using the current drawing color.
723 ; Contrary to most other functions, the graphics kernel will sort and clip
724 ; the coordinates before calling the driver, so on entry the following
725 ; conditions are valid:
726 ;       X1 <= X2
727 ;       Y1 <= Y2
728 ;       (X1 >= 0) && (X1 < XRES)
729 ;       (X2 >= 0) && (X2 < XRES)
730 ;       (Y1 >= 0) && (Y1 < YRES)
731 ;       (Y2 >= 0) && (Y2 < YRES)
732 ;
733 ; Must set an error code: NO
734 ;
735
736 ; Note: This function needs optimization. It's just a cheap translation of
737 ; the original C wrapper and could be written much smaller (besides that,
738 ; calling LINE is not a good idea either).
739
740 BAR:    lda     Y2
741         sta     Y2SAVE
742         lda     Y2+1
743         sta     Y2SAVE+1
744
745         lda     X2
746         sta     X2SAVE
747         lda     X2+1
748         sta     X2SAVE+1
749
750         lda     Y1
751         sta     Y1SAVE
752         lda     Y1+1
753         sta     Y1SAVE+1
754
755         lda     X1
756         sta     X1SAVE
757         lda     X1+1
758         sta     X1SAVE+1
759
760 @L1:    lda     Y1
761         sta     Y2
762         lda     Y1+1
763         sta     Y2+1
764         jsr     LINE
765
766         lda     Y1SAVE
767         cmp     Y2SAVE
768         bne     @L2
769         lda     Y1SAVE
770         cmp     Y2SAVE
771         beq     @L4
772
773 @L2:    inc     Y1SAVE
774         bne     @L3
775         inc     Y1SAVE+1
776
777 @L3:    lda     Y1SAVE
778         sta     Y1
779         lda     Y1SAVE+1
780         sta     Y1+1
781
782         lda     X1SAVE
783         sta     X1
784         lda     X1SAVE+1
785         sta     X1+1
786
787         lda     X2SAVE
788         sta     X2
789         lda     X2SAVE+1
790         sta     X2+1
791         jmp     @L1
792
793 @L4:    rts
794
795
796 ; ------------------------------------------------------------------------
797 ; TEXTSTYLE: Set the style used when calling OUTTEXT. Text scaling in X and Y
798 ; direction is passend in X/Y, the text direction is passed in A.
799 ;
800 ; Must set an error code: NO
801 ;
802
803 TEXTSTYLE:
804         stx     TEXTMAGX
805         sty     TEXTMAGY
806         sta     TEXTDIR
807         rts
808
809
810 ; ------------------------------------------------------------------------
811 ; OUTTEXT: Output text at X/Y = ptr1/ptr2 using the current color and the
812 ; current text style. The text to output is given as a zero terminated
813 ; string with address in ptr3.
814 ;
815 ; Must set an error code: NO
816 ;
817
818 OUTTEXT:
819
820 ; Calculate a pointer to the representation of the character in the
821 ; character ROM
822
823         ldx     #((>(CHARROM + $0800)) >> 3)
824         ldy     #0
825         lda     (TEXT),y
826         bmi     @L1
827         ldx     #((>(CHARROM + $0000)) >> 3)
828 @L1:    stx     ptr4+1
829         asl     a
830         rol     ptr4+1
831         asl     a
832         rol     ptr4+1
833         asl     a
834         rol     ptr4+1
835         sta     ptr4
836
837
838
839
840
841         rts
842
843 ; ------------------------------------------------------------------------
844 ; Calculate all variables to plot the pixel at X1/Y1.
845
846 CALC:   lda     Y1
847         sta     TEMP2
848         and     #7
849         tay
850         lda     Y1+1
851         lsr                     ; Neg is possible
852         ror     TEMP2
853         lsr
854         ror     TEMP2
855         lsr
856         ror     TEMP2
857
858         lda     #00
859         sta     POINT
860         lda     TEMP2
861         cmp     #$80
862         ror
863         ror     POINT
864         cmp     #$80
865         ror
866         ror     POINT           ; row*64
867         adc     TEMP2           ; +row*256
868         clc
869         adc     #>VBASE         ; +bitmap base
870         sta     POINT+1
871
872         lda     X1
873         tax
874         and     #$F8
875         clc
876         adc     POINT           ; +(X AND #$F8)
877         sta     POINT
878         lda     X1+1
879         adc     POINT+1
880         sta     POINT+1
881         txa
882         and     #7
883         tax
884         rts