]> git.sur5r.net Git - cc65/blob - libsrc/c64/tgi/c64-hi.s
Removed IRQ support from TGI drivers.
[cc65] / libsrc / c64 / tgi / c64-hi.s
1 ;
2 ; Graphics driver for the 320x200x2 mode on the C64.
3 ;
4 ; Based on Stephen L. Judd's GRLIB code.
5 ;
6 ; 2017-01-13, Greg King
7 ;
8
9         .include        "zeropage.inc"
10
11         .include        "tgi-kernel.inc"
12         .include        "tgi-error.inc"
13
14         .macpack        generic
15         .macpack        module
16
17
18 ; ------------------------------------------------------------------------
19 ; Header. Includes jump table and constants.
20
21         module_header   _c64_hi_tgi
22
23 ; First part of the header is a structure that has a magic and defines the
24 ; capabilities of the driver
25
26         .byte   $74, $67, $69           ; "tgi"
27         .byte   TGI_API_VERSION         ; TGI API version number
28         .addr   $0000                   ; Library reference
29         .word   320                     ; X resolution
30         .word   200                     ; Y resolution
31         .byte   2                       ; Number of drawing colors
32         .byte   1                       ; Number of screens available
33         .byte   8                       ; System font X size
34         .byte   8                       ; System font Y size
35         .word   $00D4                   ; Aspect ratio (based on 4/3 display)
36         .byte   0                       ; TGI driver flags
37
38 ; Next comes the jump table. With the exception of IRQ, all entries must be
39 ; valid and may point to an RTS for test versions (function not implemented).
40
41         .addr   INSTALL
42         .addr   UNINSTALL
43         .addr   INIT
44         .addr   DONE
45         .addr   GETERROR
46         .addr   CONTROL
47         .addr   CLEAR
48         .addr   SETVIEWPAGE
49         .addr   SETDRAWPAGE
50         .addr   SETCOLOR
51         .addr   SETPALETTE
52         .addr   GETPALETTE
53         .addr   GETDEFPALETTE
54         .addr   SETPIXEL
55         .addr   GETPIXEL
56         .addr   LINE
57         .addr   BAR
58         .addr   TEXTSTYLE
59         .addr   OUTTEXT
60
61 ; ------------------------------------------------------------------------
62 ; Data.
63
64 ; Variables mapped to the zero page segment variables. Some of these are
65 ; used for passing parameters to the driver.
66
67 X1              := ptr1
68 Y1              := ptr2
69 X2              := ptr3
70 Y2              := ptr4
71 TEXT            := ptr3
72
73 ROW             := tmp2         ; Bitmap row...
74 COL             := tmp3         ; ...and column, both set by PLOT
75 TEMP            := tmp4
76 TEMP2           := sreg
77 POINT           := regsave
78 INRANGE         := regsave+2    ; PLOT variable, $00 = coordinates in range
79
80 CHUNK           := X2           ; Used in the line routine
81 OLDCHUNK        := X2+1         ; Dito
82
83 ; Absolute variables used in the code
84
85 .bss
86
87 ERROR:          .res    1       ; Error code
88 PALETTE:        .res    2       ; The current palette
89
90 BITMASK:        .res    1       ; $00 = clear, $FF = set pixels
91
92 ; INIT/DONE
93 OLDD018:        .res    1       ; Old register value
94
95 ; Line routine stuff
96 DX:             .res    2
97 DY:             .res    2
98
99 ; BAR variables
100 X1SAVE:         .res    2
101 Y1SAVE:         .res    2
102 X2SAVE:         .res    2
103 Y2SAVE:         .res    2
104
105 ; Text output stuff
106 TEXTMAGX:       .res    1
107 TEXTMAGY:       .res    1
108 TEXTDIR:        .res    1
109
110 ; Constants and tables
111
112 .rodata
113
114 DEFPALETTE:     .byte   $00, $01        ; White on black
115 PALETTESIZE     = * - DEFPALETTE
116
117 BITTAB:         .byte   $80,$40,$20,$10,$08,$04,$02,$01
118 BITCHUNK:       .byte   $FF,$7F,$3F,$1F,$0F,$07,$03,$01
119
120 CHARROM         := $D000                ; Character rom base address
121 CBASE           := $D000                ; Color memory base address
122 VBASE           := $E000                ; Video memory base address
123
124
125 .code
126
127 ; ------------------------------------------------------------------------
128 ; INSTALL routine. Is called after the driver is loaded into memory. May
129 ; initialize anything that has to be done just once. Is probably empty
130 ; most of the time.
131 ;
132 ; Must set an error code: NO
133 ;
134
135 INSTALL:
136         rts
137
138
139 ; ------------------------------------------------------------------------
140 ; UNINSTALL routine. Is called before the driver is removed from memory. May
141 ; clean up anything done by INSTALL but is probably empty most of the time.
142 ;
143 ; Must set an error code: NO
144 ;
145
146 UNINSTALL:
147         rts
148
149
150 ; ------------------------------------------------------------------------
151 ; INIT: Changes an already installed device from text mode to graphics
152 ; mode.
153 ; Note that INIT/DONE may be called multiple times while the driver
154 ; is loaded, while INSTALL is only called once, so any code that is needed
155 ; to initializes variables and so on must go here. Setting palette and
156 ; clearing the screen is not needed because this is called by the graphics
157 ; kernel later.
158 ; The graphics kernel will never call INIT when a graphics mode is already
159 ; active, so there is no need to protect against that.
160 ;
161 ; Must set an error code: YES
162 ;
163
164 INIT:
165
166 ; Initialize variables
167
168         ldx     #$FF
169         stx     BITMASK
170
171 ; Switch into graphics mode
172
173         lda     $DD02           ; Set the data direction regs
174         ora     #3
175         sta     $DD02
176         lda     $DD00
177         and     #$FC            ; Switch to bank 3
178         sta     $DD00
179
180         lda     $D018
181         sta     OLDD018
182         lda     #$48            ; Set color map to $D000, screen to $E000
183         sta     $D018
184
185         lda     $D011           ; And turn on bitmap
186         ora     #$20
187 DONE1:  sta     $D011
188
189 ; Done, reset the error code
190
191         lda     #TGI_ERR_OK
192         sta     ERROR
193         rts
194
195 ; ------------------------------------------------------------------------
196 ; DONE: Will be called to switch the graphics device back into text mode.
197 ; The graphics kernel will never call DONE when no graphics mode is active,
198 ; so there is no need to protect against that.
199 ;
200 ; Must set an error code: NO
201 ;
202
203 DONE:   lda     $DD02           ; Set the data direction regs
204         ora     #3
205         sta     $DD02
206         lda     $DD00
207         ora     #$03            ; Bank 0
208         sta     $DD00
209
210         lda     OLDD018         ; Screen mem --> $0400
211         sta     $D018
212
213         lda     $D011
214         and     #<~$20
215         sta     $D011
216         rts
217
218 ; ------------------------------------------------------------------------
219 ; GETERROR: Return the error code in A and clear it.
220
221 GETERROR:
222         ldx     #TGI_ERR_OK
223         lda     ERROR
224         stx     ERROR
225         rts
226
227 ; ------------------------------------------------------------------------
228 ; CONTROL: Platform/driver specific entry point.
229 ;
230 ; Must set an error code: YES
231 ;
232
233 CONTROL:
234         lda     #TGI_ERR_INV_FUNC
235         sta     ERROR
236         rts
237
238 ; ------------------------------------------------------------------------
239 ; CLEAR: Clears the screen.
240 ;
241 ; Must set an error code: NO
242 ;
243
244 CLEAR:  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+$1F00,y
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
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 ; To deal with off-screen coordinates, the current row
458 ; and column (40x25) is kept track of.  These are set
459 ; negative when the point is off the screen, and made
460 ; positive when the point is within the visible screen.
461 ;
462 ; X1,X2 etc. are set up above (x2=LINNUM in particular)
463 ; Format is LINE x2,y2,x1,y1
464 ;
465 ; Must set an error code: NO
466 ;
467
468 LINE:
469
470 @CHECK: lda     X2           ;Make sure x1<x2
471         sec
472         sbc     X1
473         tax
474         lda     X2+1
475         sbc     X1+1
476         bpl     @CONT
477         lda     Y2           ;If not, swap P1 and P2
478         ldy     Y1
479         sta     Y1
480         sty     Y2
481         lda     Y2+1
482         ldy     Y1+1
483         sta     Y1+1
484         sty     Y2+1
485         lda     X1
486         ldy     X2
487         sty     X1
488         sta     X2
489         lda     X2+1
490         ldy     X1+1
491         sta     X1+1
492         sty     X2+1
493         bcc     @CHECK
494
495 @CONT:  sta     DX+1
496         stx     DX
497
498         ldx     #$C8         ;INY
499         lda     Y2           ;Calculate dy
500         sec
501         sbc     Y1
502         tay
503         lda     Y2+1
504         sbc     Y1+1
505         bpl     @DYPOS       ;Is y2>=y1?
506         lda     Y1           ;Otherwise dy=y1-y2
507         sec
508         sbc     Y2
509         tay
510         ldx     #$88         ;DEY
511
512 @DYPOS: sty     DY              ; 8-bit DY -- FIX ME?
513         stx     YINCDEC
514         stx     XINCDEC
515
516         jsr     CALC            ; Set up .X,.Y,POINT, and INRANGE
517         lda     BITCHUNK,X
518         sta     OLDCHUNK
519         sta     CHUNK
520
521         sei                     ; Get underneath ROM
522         lda     #$34
523         sta     $01
524
525         ldx     DY
526         cpx     DX           ;Who's bigger: dy or dx?
527         bcc     STEPINX      ;If dx, then...
528         lda     DX+1
529         bne     STEPINX
530
531 ;
532 ; Big steps in Y
533 ;
534 ;   To simplify my life, just use PLOT to plot points.
535 ;
536 ;   No more!
537 ;   Added special plotting routine -- cool!
538 ;
539 ;   X is now counter, Y is y-coordinate
540 ;
541 ; On entry, X=DY=number of loop iterations, and Y=
542 ;   Y1 AND #$07
543 STEPINY:
544         lda     #00
545         sta     OLDCHUNK     ;So plotting routine will work right
546         lda     CHUNK
547         lsr                  ;Strip the bit
548         eor     CHUNK
549         sta     CHUNK
550         txa
551         bne     @CONT        ;If dy=0 it's just a point
552         inx
553 @CONT:  lsr                  ;Init counter to dy/2
554 ;
555 ; Main loop
556 ;
557 YLOOP:  sta     TEMP
558
559         lda     INRANGE      ;Range check
560         bne     @SKIP
561
562         lda     (POINT),y    ;Otherwise plot
563         eor     BITMASK
564         and     CHUNK
565         eor     (POINT),y
566         sta     (POINT),y
567 @SKIP:
568 YINCDEC:
569         iny                  ;Advance Y coordinate
570         cpy     #8
571         bcc     @CONT        ;No prob if Y=0..7
572         jsr     FIXY
573 @CONT:  lda     TEMP         ;Restore A
574         sec
575         sbc     DX
576         bcc     YFIXX
577 YCONT:  dex                  ;X is counter
578         bne     YLOOP
579 YCONT2: lda     (POINT),y    ;Plot endpoint
580         eor     BITMASK
581         and     CHUNK
582         eor     (POINT),y
583         sta     (POINT),y
584 YDONE:  lda     #$36
585         sta     $01
586         cli
587         rts
588
589 YFIXX:                    ;x=x+1
590         adc     DY
591         lsr     CHUNK
592         bne     YCONT        ;If we pass a column boundary...
593         ror     CHUNK        ;then reset CHUNK to $80
594         sta     TEMP2
595         lda     COL
596         bmi     @C1          ;Skip if column is negative
597         cmp     #39          ;End if move past end of screen
598         bcs     YDONE
599 @C1:    lda     POINT        ;And add 8 to POINT
600         adc     #8
601         sta     POINT
602         bcc     @CONT
603         inc     POINT+1
604 @CONT:  inc     COL          ;Increment column
605         bne     @C2
606         lda     ROW          ;Range check
607         cmp     #25
608         bcs     @C2
609         lda     #00          ;Passed into col 0
610         sta     INRANGE
611 @C2:    lda     TEMP2
612         dex
613         bne     YLOOP
614         beq     YCONT2
615
616 ;
617 ; Big steps in X direction
618 ;
619 ; On entry, X=DY=number of loop iterations, and Y=
620 ;   Y1 AND #$07
621
622 .bss
623 COUNTHI:
624         .byte   $00       ;Temporary counter
625                           ;only used once
626 .code
627 STEPINX:
628         ldx     DX
629         lda     DX+1
630         sta     COUNTHI
631         cmp     #$80
632         ror                  ;Need bit for initialization
633         sta     Y1           ;High byte of counter
634         txa
635         bne     @CONT        ;Could be $100
636         dec     COUNTHI
637 @CONT:  ror
638 ;
639 ; Main loop
640 ;
641 XLOOP:  lsr     CHUNK
642         beq     XFIXC        ;If we pass a column boundary...
643 XCONT1: sbc     DY
644         bcc     XFIXY        ;Time to step in Y?
645 XCONT2: dex
646         bne     XLOOP
647         dec     COUNTHI      ;High bits set?
648         bpl     XLOOP
649
650 XDONE:  lsr     CHUNK        ;Advance to last point
651         jsr     LINEPLOT     ;Plot the last chunk
652 EXIT:   lda     #$36
653         sta     $01
654         cli
655         rts
656 ;
657 ; CHUNK has passed a column, so plot and increment pointer
658 ; and fix up CHUNK, OLDCHUNK.
659 ;
660 XFIXC:  sta     TEMP
661         jsr     LINEPLOT
662         lda     #$FF
663         sta     CHUNK
664         sta     OLDCHUNK
665         lda     COL
666         bmi     @C1          ;Skip if column is negative
667         cmp     #39          ;End if move past end of screen
668         bcs     EXIT
669 @C1:    lda     POINT
670         adc     #8
671         sta     POINT
672         bcc     @CONT
673         inc     POINT+1
674 @CONT:  inc     COL
675         bne     @C2
676         lda     ROW
677         cmp     #25
678         bcs     @C2
679         lda     #00
680         sta     INRANGE
681 @C2:    lda     TEMP
682         sec
683         bcs     XCONT1
684 ;
685 ; Check to make sure there isn't a high bit, plot chunk,
686 ; and update Y-coordinate.
687 ;
688 XFIXY:  dec     Y1           ;Maybe high bit set
689         bpl     XCONT2
690         adc     DX
691         sta     TEMP
692         lda     DX+1
693         adc     #$FF         ;Hi byte
694         sta     Y1
695
696         jsr     LINEPLOT     ;Plot chunk
697         lda     CHUNK
698         sta     OLDCHUNK
699
700         lda     TEMP
701 XINCDEC:
702         iny                  ;Y-coord
703         cpy     #8           ;0..7 is ok
704         bcc     XCONT2
705         sta     TEMP
706         jsr     FIXY
707         lda     TEMP
708         jmp     XCONT2
709
710 ;
711 ; Subroutine to plot chunks/points (to save a little
712 ; room, gray hair, etc.)
713 ;
714 LINEPLOT:                       ; Plot the line chunk
715         lda     INRANGE
716         bne     @SKIP
717
718         lda     (POINT),Y       ; Otherwise plot
719         eor     BITMASK
720         ora     CHUNK
721         and     OLDCHUNK
722         eor     CHUNK
723         eor     (POINT),Y
724         sta     (POINT),Y
725 @SKIP:  rts
726
727 ;
728 ; Subroutine to fix up pointer when Y decreases through
729 ; zero or increases through 7.
730 ;
731 FIXY:   cpy     #255         ;Y=255 or Y=8
732         beq     @DECPTR
733 @INCPTR:                     ;Add 320 to pointer
734         ldy     #0           ;Y increased through 7
735         lda     ROW
736         bmi     @C1          ;If negative, then don't update
737         cmp     #24
738         bcs     @TOAST       ;If at bottom of screen then quit
739 @C1:    lda     POINT
740         adc     #<320
741         sta     POINT
742         lda     POINT+1
743         adc     #>320
744         sta     POINT+1
745 @CONT1: inc     ROW
746         bne     @DONE
747         lda     COL
748         bpl     @CLEAR
749 @DONE:  rts
750
751 @DECPTR:                     ;Okay, subtract 320 then
752         ldy     #7           ;Y decreased through 0
753         lda     POINT
754         sec
755         sbc     #<320
756         sta     POINT
757         lda     POINT+1
758         sbc     #>320
759         sta     POINT+1
760 @CONT2: dec     ROW
761         bmi     @TOAST
762         lda     ROW
763         cmp     #24
764         bne     @DONE
765         lda     COL
766         bmi     @DONE
767 @CLEAR: lda     #00
768         sta     INRANGE
769         rts
770
771 @TOAST: pla                  ;Remove old return address
772         pla
773         jmp     EXIT         ;Restore interrupts, etc.
774
775 ; ------------------------------------------------------------------------
776 ; BAR: Draw a filled rectangle with the corners X1/Y1, X2/Y2, where
777 ; X1/Y1 = ptr1/ptr2 and X2/Y2 = ptr3/ptr4 using the current drawing color.
778 ; Contrary to most other functions, the graphics kernel will sort and clip
779 ; the coordinates before calling the driver, so on entry the following
780 ; conditions are valid:
781 ;       X1 <= X2
782 ;       Y1 <= Y2
783 ;       (X1 >= 0) && (X1 < XRES)
784 ;       (X2 >= 0) && (X2 < XRES)
785 ;       (Y1 >= 0) && (Y1 < YRES)
786 ;       (Y2 >= 0) && (Y2 < YRES)
787 ;
788 ; Must set an error code: NO
789 ;
790
791 ; Note: This function needs optimization. It's just a cheap translation of
792 ; the original C wrapper and could be written much smaller (besides that,
793 ; calling LINE is not a good idea either).
794
795 BAR:    lda     Y2
796         sta     Y2SAVE
797         lda     Y2+1
798         sta     Y2SAVE+1
799
800         lda     X2
801         sta     X2SAVE
802         lda     X2+1
803         sta     X2SAVE+1
804
805         lda     Y1
806         sta     Y1SAVE
807         lda     Y1+1
808         sta     Y1SAVE+1
809
810         lda     X1
811         sta     X1SAVE
812         lda     X1+1
813         sta     X1SAVE+1
814
815 @L1:    lda     Y1
816         sta     Y2
817         lda     Y1+1
818         sta     Y2+1
819         jsr     LINE
820
821         lda     Y1SAVE
822         cmp     Y2SAVE
823         bne     @L2
824         lda     Y1SAVE
825         cmp     Y2SAVE
826         beq     @L4
827
828 @L2:    inc     Y1SAVE
829         bne     @L3
830         inc     Y1SAVE+1
831
832 @L3:    lda     Y1SAVE
833         sta     Y1
834         lda     Y1SAVE+1
835         sta     Y1+1
836
837         lda     X1SAVE
838         sta     X1
839         lda     X1SAVE+1
840         sta     X1+1
841
842         lda     X2SAVE
843         sta     X2
844         lda     X2SAVE+1
845         sta     X2+1
846         jmp     @L1
847
848 @L4:    rts
849
850
851 ; ------------------------------------------------------------------------
852 ; TEXTSTYLE: Set the style used when calling OUTTEXT. Text scaling in X and Y
853 ; direction is passend in X/Y, the text direction is passed in A.
854 ;
855 ; Must set an error code: NO
856 ;
857
858 TEXTSTYLE:
859         stx     TEXTMAGX
860         sty     TEXTMAGY
861         sta     TEXTDIR
862         rts
863
864
865 ; ------------------------------------------------------------------------
866 ; OUTTEXT: Output text at X/Y = ptr1/ptr2 using the current color and the
867 ; current text style. The text to output is given as a zero terminated
868 ; string with address in ptr3.
869 ;
870 ; Must set an error code: NO
871 ;
872
873 OUTTEXT:
874
875 ; Calculate a pointer to the representation of the character in the
876 ; character ROM
877
878         ldx     #((>(CHARROM + $0800)) >> 3)
879         ldy     #0
880         lda     (TEXT),y
881         bmi     @L1
882         ldx     #((>(CHARROM + $0000)) >> 3)
883 @L1:    stx     ptr4+1
884         asl     a
885         rol     ptr4+1
886         asl     a
887         rol     ptr4+1
888         asl     a
889         rol     ptr4+1
890         sta     ptr4
891
892
893
894
895
896         rts
897
898 ; ------------------------------------------------------------------------
899 ; Calculate all variables to plot the pixel at X1/Y1. If the point is out
900 ; of range, a carry is returned and INRANGE is set to a value !0 zero. If
901 ; the coordinates are valid, INRANGE is zero and the carry clear.
902
903 CALC:   lda     Y1
904         sta     ROW
905         and     #7
906         tay
907         lda     Y1+1
908         lsr                     ; Neg is possible
909         ror     ROW
910         lsr
911         ror     ROW
912         lsr
913         ror     ROW
914
915         lda     #00
916         sta     POINT
917         lda     ROW
918         cmp     #$80
919         ror
920         ror     POINT
921         cmp     #$80
922         ror
923         ror     POINT           ; row*64
924         adc     ROW             ; +row*256
925         clc
926         adc     #>VBASE         ; +bitmap base
927         sta     POINT+1
928
929         lda     X1
930         tax
931         sta     COL
932         lda     X1+1
933         lsr
934         ror     COL
935         lsr
936         ror     COL
937         lsr
938         ror     COL
939
940         txa
941         and     #$F8
942         clc
943         adc     POINT           ; +(X AND #$F8)
944         sta     POINT
945         lda     X1+1
946         adc     POINT+1
947         sta     POINT+1
948         txa
949         and     #7
950         tax
951
952         lda     ROW
953         cmp     #25
954         bcs     @L9
955         lda     COL
956         cmp     #40
957         bcs     @L9
958         lda     #00
959 @L9:    sta     INRANGE
960         rts