]> git.sur5r.net Git - cc65/blob - libsrc/c128/c128-640-480-2.s
TGI drivers updated for current API (INIT call has changed)
[cc65] / libsrc / c128 / c128-640-480-2.s
1 ;
2 ; Graphics driver for the 640x480x2 mode on the C128 VDC 64k
3 ; (values for this mode based on Fred Bowen's document)
4 ; Maciej 'YTM/Elysium' Witkowiak <ytm@elysium.pl>
5 ; 23.12.2002
6 ;
7 ; NOTES:
8 ; For any smart monkey that will try to optimize this: PLEASE do tests on real VDC,
9 ; not only VICE.
10 ;
11 ; Only DONE routine contains C128-mode specific stuff, everything else will work in
12 ; C64-mode of C128 (C64 needs full VDC init then).
13 ;
14 ; With special initialization and CALC we can get 320x200 double-pixel mode.
15 ;
16 ; Color translation values for BROWN and GRAY3 are obviously wrong, they could
17 ; be replaced by equiv. of ORANGE and GRAY2 but this would give only 14 of 16 colors available.
18 ;
19 ; Register 25 ($19) is said to require different value for VDC v1, but I couldn't find what
20 ; it should be.
21
22         .include        "zeropage.inc"
23
24         .include        "tgi-kernel.inc"
25         .include        "tgi-mode.inc"
26         .include        "tgi-error.inc"
27
28
29         .macpack        generic
30
31 ; ------------------------------------------------------------------------
32 ; Constants
33
34 VDC_ADDR_REG      = $D600                 ; VDC address
35 VDC_DATA_REG      = $D601                 ; VDC data
36
37 VDC_DSP_HI        = 12                    ; registers used
38 VDC_DSP_LO        = 13
39 VDC_DATA_HI       = 18
40 VDC_DATA_LO       = 19
41 VDC_VSCROLL       = 24
42 VDC_HSCROLL       = 25
43 VDC_COLORS        = 26
44 VDC_CSET          = 28
45 VDC_COUNT         = 30
46 VDC_DATA          = 31
47
48 ; ------------------------------------------------------------------------
49 ; Header. Includes jump table and constants.
50
51 .segment        "JUMPTABLE"
52
53 ; First part of the header is a structure that has a magic and defines the
54 ; capabilities of the driver
55
56         .byte   $74, $67, $69           ; "tgi"
57         .byte   $00                     ; TGI version number
58 xres:   .word   640                     ; X resolution
59 yres:   .word   480                     ; Y resolution
60         .byte   2                       ; Number of drawing colors
61 pages:  .byte   0                       ; Number of screens available
62         .byte   8                       ; System font X size
63         .byte   8                       ; System font Y size
64         .res    4, $00                  ; Reserved for future extensions
65
66 ; Next comes the jump table. Currently all entries must be valid and may point
67 ; to an RTS for test versions (function not implemented). A future version may
68 ; allow for emulation: In this case the vector will be zero. Emulation means
69 ; that the graphics kernel will emulate the function by using lower level
70 ; primitives - for example ploting a line by using calls to SETPIXEL.
71
72         .word   INSTALL
73         .word   DEINSTALL
74         .word   INIT
75         .word   DONE
76         .word   GETERROR
77         .word   CONTROL
78         .word   CLEAR
79         .word   SETVIEWPAGE
80         .word   SETDRAWPAGE
81         .word   SETCOLOR
82         .word   SETPALETTE
83         .word   GETPALETTE
84         .word   GETDEFPALETTE
85         .word   SETPIXEL
86         .word   GETPIXEL
87         .word   HORLINE
88         .word   LINE
89         .word   BAR
90         .word   CIRCLE
91         .word   TEXTSTYLE
92         .word   OUTTEXT
93
94 ; ------------------------------------------------------------------------
95 ; Data.
96
97 ; Variables mapped to the zero page segment variables. Some of these are
98 ; used for passing parameters to the driver.
99
100 X1              = ptr1
101 Y1              = ptr2
102 X2              = ptr3
103 Y2              = ptr4
104 RADIUS          = tmp1
105
106 ADDR            = tmp1          ; (2)   CALC
107 TEMP            = tmp3          ;       CALC icmp
108 TEMP2           = tmp4          ;       icmp
109 TEMP3           = sreg          ;       LINE
110 TEMP4           = sreg+1        ;       LINE
111
112 ; Line routine stuff (must be on zpage)
113 PB              = ptr3          ; (2)   LINE
114 UB              = ptr4          ; (2)   LINE
115 ERR             = regsave       ; (2)   LINE
116 NX              = regsave+2     ; (2)   LINE
117 ; Circle stuff
118 XX              = ptr3          ; (2)   CIRCLE
119 YY              = ptr4          ; (2)   CIRCLE
120 MaxO            = sreg          ; (overwritten by TEMP3+TEMP4, but restored from OG/OU anyway)
121 XS              = regsave       ; (2)   CIRCLE
122 YS              = regsave+2     ; (2)   CIRCLE
123
124 ; Absolute variables used in the code
125
126 .bss
127
128 ERROR:          .res    1       ; Error code
129 PALETTE:        .res    2       ; The current palette
130
131 BITMASK:        .res    1       ; $00 = clear, $FF = set pixels
132
133 OLDCOLOR:       .res    1       ; colors before entering gfx mode
134
135 ; Line routine stuff (combined with CIRCLE to save space)
136
137 OGora:
138 COUNT:           .res   2
139 OUkos:
140 NY:              .res   2
141 Y3:
142 DX:              .res   1
143 DY:              .res   1
144 AY:              .res   1
145
146 ; Text output stuff
147 TEXTMAGX:       .res    1
148 TEXTMAGY:       .res    1
149 TEXTDIR:        .res    1
150
151 ; Constants and tables
152
153 .rodata
154
155 DEFPALETTE:     .byte   $00, $0f        ; White on black
156 PALETTESIZE     = * - DEFPALETTE
157
158 BITTAB:         .byte   $80,$40,$20,$10,$08,$04,$02,$01
159
160 BITMASKL:       .byte   %11111111, %01111111, %00111111, %00011111
161                 .byte   %00001111, %00000111, %00000011, %00000001
162
163 BITMASKR:       .byte   %10000000, %11000000, %11100000, %11110000
164                 .byte   %11111000, %11111100, %11111110, %11111111
165
166 ; color translation table (indexed by VIC color)
167 COLTRANS:       .byte $00, $0f, $08, $06, $0a, $04, $02, $0c
168                 .byte $0d, $0b, $09, $01, $0e, $05, $03, $07
169                 ; colors BROWN and GRAY3 are wrong
170
171 ; VDC initialization table (reg),(val),...,$ff
172 InitVDCTab:
173                 .byte VDC_DSP_HI, 0             ; viewpage 0 as default
174                 .byte VDC_DSP_LO, 0
175                 .byte VDC_HSCROLL, $87
176                 .byte 2, $66
177                 .byte 4, $4c
178                 .byte 5, $06
179                 .byte 6, $4c
180                 .byte 7, $47
181                 .byte 8, $03
182                 .byte 9, $06
183                 .byte 27, $00
184                 .byte $ff
185
186 SCN80CLR:       .byte 27,88,147,27,88,0
187
188 .code
189
190 ; ------------------------------------------------------------------------
191 ; INSTALL routine. Is called after the driver is loaded into memory. May
192 ; initialize anything that has to be done just once. Is probably empty
193 ; most of the time.
194 ;
195 ; Must set an error code: NO
196 ;
197
198 INSTALL:
199         ; check for VDC version and update register $19 value
200
201         ; check for VDC ram size and update number of available screens
202
203         ldx     #VDC_CSET       ; determine size of RAM...
204         jsr     VDCReadReg
205         sta     tmp1
206         ora     #%00010000
207         jsr     VDCWriteReg     ; turn on 64k
208
209         jsr     settestadr1     ; save original value of test byte
210         jsr     VDCReadByte
211         sta     tmp2
212
213         lda     #$55            ; write $55 here
214         ldy     #ptr1
215         jsr     test64k         ; read it here and there
216         lda     #$aa            ; write $aa here
217         ldy     #ptr2
218         jsr     test64k         ; read it here and there
219
220         jsr     settestadr1
221         lda     tmp2
222         jsr     VDCWriteByte    ; restore original value of test byte
223
224         lda     ptr1            ; do bytes match?
225         cmp     ptr1+1
226         bne     @have64k
227         lda     ptr2
228         cmp     ptr2+1
229         bne     @have64k
230
231         ldx     #VDC_CSET
232         lda     tmp1
233         jsr     VDCWriteReg     ; restore 16/64k flag
234         jmp     @endok          ; and leave default values for 16k
235
236 @have64k:
237         lda     #1
238         sta     pages
239 @endok:
240         rts
241
242 test64k:
243         sta     tmp1
244         sty     ptr3
245         lda     #0
246         sta     ptr3+1
247         jsr     settestadr1
248         lda     tmp1
249         jsr     VDCWriteByte            ; write $55
250         jsr     settestadr1
251         jsr     VDCReadByte             ; read here
252         pha
253         jsr     settestadr2
254         jsr     VDCReadByte             ; and there
255         ldy     #1
256         sta     (ptr3),y
257         pla
258         dey
259         sta     (ptr3),y
260         rts
261
262 settestadr1:
263         ldy     #$02                    ; test page 2 (here)
264         .byte   $2c
265 settestadr2:
266         ldy     #$42                    ; or page 64+2 (there)
267         lda     #0
268         jmp     VDCSetSourceAddr
269
270 ; ------------------------------------------------------------------------
271 ; DEINSTALL routine. Is called before the driver is removed from memory. May
272 ; clean up anything done by INSTALL but is probably empty most of the time.
273 ;
274 ; Must set an error code: NO
275 ;
276
277 DEINSTALL:
278         rts
279
280
281 ; ------------------------------------------------------------------------
282 ; INIT: Changes an already installed device from text mode to graphics
283 ; mode. The number of the graphics mode is passed to the function in A.
284 ; Note that INIT/DONE may be called multiple times while the driver
285 ; is loaded, while INSTALL is only called once, so any code that is needed
286 ; to initializes variables and so on must go here. Setting palette and
287 ; clearing the screen is not needed because this is called by the graphics
288 ; kernel later.
289 ; The graphics kernel will never call INIT when a graphics mode is already
290 ; active, so there is no need to protect against that.
291 ;
292 ; Must set an error code: YES
293 ;
294
295 INIT:
296         lda     pages                   ; is there enough memory?
297         bne     @L11                    ; Jump if there is one screen
298         lda     #TGI_ERR_INV_MODE       ; ## Error
299         bne     @L9
300
301 ; Initialize variables
302
303 @L11:   ldx     #$FF
304         stx     BITMASK
305
306 ; Remeber current color value
307         ldx     #VDC_COLORS
308         jsr     VDCReadReg
309         sta     OLDCOLOR
310
311 ; Switch into graphics mode (set view page 0)
312
313         ldy     #0
314 @L2:    ldx     InitVDCTab,y
315         bmi     @L3
316         iny
317         lda     InitVDCTab,y
318         jsr     VDCWriteReg
319         iny
320         bne     @L2
321 @L3:
322
323 ; Done, reset the error code
324
325         lda     #TGI_ERR_OK
326 @L9:    sta     ERROR
327         rts
328
329 ; ------------------------------------------------------------------------
330 ; DONE: Will be called to switch the graphics device back into text mode.
331 ; The graphics kernel will never call DONE when no graphics mode is active,
332 ; so there is no need to protect against that.
333 ;
334 ; Must set an error code: YES
335 ;
336
337 DONE:
338         ; This part is C128-mode specific
339         jsr $e179               ; reload character set and setup VDC
340         jsr $ff62
341         lda $d7                 ; in 80-columns?
342         bne @L01
343 @L0:    lda SCN80CLR,y
344         beq @L1
345         jsr $ffd2               ; print \xe,clr,\xe
346         iny
347         bne @L0
348 @L01:   lda #147
349         jsr $ffd2               ; print clr
350 @L1:    lda #0                  ; restore view page
351         ldx #VDC_DSP_HI
352         jsr VDCWriteReg
353         lda OLDCOLOR
354         ldx #VDC_COLORS
355         jsr VDCWriteReg         ; restore color (background)
356         lda #$47
357         ldx #VDC_HSCROLL
358         jmp VDCWriteReg         ; switch to text screen
359
360 ; ------------------------------------------------------------------------
361 ; GETERROR: Return the error code in A and clear it.
362
363 GETERROR:
364         ldx     #TGI_ERR_OK
365         lda     ERROR
366         stx     ERROR
367         rts
368
369 ; ------------------------------------------------------------------------
370 ; CONTROL: Platform/driver specific entry point.
371 ;
372 ; Must set an error code: YES
373 ;
374
375 CONTROL:
376         lda     #TGI_ERR_INV_FUNC
377         sta     ERROR
378         rts
379
380 ; ------------------------------------------------------------------------
381 ; CLEAR: Clears the screen.
382 ;
383 ; Must set an error code: NO
384 ;
385
386 CLEAR:  
387         lda     #0
388         tay
389         jsr     VDCSetSourceAddr
390         lda     #0
391         ldx     #VDC_VSCROLL
392         jsr     VDCWriteReg                     ; set fill mode
393         lda     #0
394         jsr     VDCWriteByte                    ; put 1rst byte (fill value)
395         ldy     #159                            ; 159 times
396         lda     #0                              ; 256 bytes
397         ldx     #VDC_COUNT
398 @L1:    jsr     VDCWriteReg
399         dey
400         bne     @L1
401         rts
402
403 ; ------------------------------------------------------------------------
404 ; SETVIEWPAGE: Set the visible page. Called with the new page in A (0..n).
405 ; The page number is already checked to be valid by the graphics kernel.
406 ;
407 ; Must set an error code: NO (will only be called if page ok)
408 ;
409
410 SETVIEWPAGE:
411         rts
412
413 ; ------------------------------------------------------------------------
414 ; SETDRAWPAGE: Set the drawable page. Called with the new page in A (0..n).
415 ; The page number is already checked to be valid by the graphics kernel.
416 ;
417 ; Must set an error code: NO (will only be called if page ok)
418 ;
419
420 SETDRAWPAGE:
421         rts
422
423 ; ------------------------------------------------------------------------
424 ; SETCOLOR: Set the drawing color (in A). The new color is already checked
425 ; to be in a valid range (0..maxcolor-1).
426 ;
427 ; Must set an error code: NO (will only be called if color ok)
428 ;
429
430 SETCOLOR:
431         tax
432         beq     @L1
433         lda     #$FF
434 @L1:    sta     BITMASK
435         rts
436
437 ; ------------------------------------------------------------------------
438 ; SETPALETTE: Set the palette (not available with all drivers/hardware).
439 ; A pointer to the palette is passed in ptr1. Must set an error if palettes
440 ; are not supported
441 ;
442 ; Must set an error code: YES
443 ;
444
445 SETPALETTE:
446         ldy     #PALETTESIZE - 1
447 @L1:    lda     (ptr1),y        ; Copy the palette
448         and     #$0F            ; Make a valid color
449         sta     PALETTE,y
450         dey
451         bpl     @L1
452
453 ; Get the color entries from the palette
454
455         ldy     PALETTE+1       ; Foreground color
456         lda     COLTRANS,y
457         asl     a
458         asl     a
459         asl     a
460         asl     a
461         ldy     PALETTE         ; Background color
462         ora     COLTRANS,y
463
464         ldx     #VDC_COLORS
465         jmp     VDCWriteReg
466
467 ; ------------------------------------------------------------------------
468 ; GETPALETTE: Return the current palette in A/X. Must return NULL and set an
469 ; error if palettes are not supported.
470 ;
471 ; Must set an error code: YES
472 ;
473
474 GETPALETTE:
475         lda     #<PALETTE
476         ldx     #>PALETTE
477         rts
478
479 ; ------------------------------------------------------------------------
480 ; GETDEFPALETTE: Return the default palette for the driver in A/X. Must
481 ; return NULL and set an error of palettes are not supported.
482 ;
483 ; Must set an error code: YES
484 ;
485
486 GETDEFPALETTE:
487         lda     #<DEFPALETTE
488         ldx     #>DEFPALETTE
489         rts
490
491 ; ------------------------------------------------------------------------
492 ; SETPIXEL: Draw one pixel at X1/Y1 = ptr1/ptr2 with the current drawing
493 ; color. The coordinates passed to this function are never outside the
494 ; visible screen area, so there is no need for clipping inside this function.
495 ;
496 ; Must set an error code: NO
497 ;
498
499 SETPIXELCLIP:
500         lda     Y1+1
501         bmi     @finito         ; y<0
502         lda     X1+1
503         bmi     @finito         ; x<0
504         lda     xres
505         ldx     xres+1
506         sta     ADDR
507         stx     ADDR+1
508         ldx     #ADDR
509         lda     X1
510         ldy     X1+1
511         jsr     icmp            ; if (xres<x1)
512         bcs     @cont           ; !(xres<x1)
513 @finito:rts
514 @cont:  lda     yres
515         ldx     yres+1
516         sta     ADDR
517         stx     ADDR+1
518         ldx     #ADDR
519         lda     Y1
520         ldy     Y1+1
521         jsr     icmp            ; if (yres<y1)
522         bcc     @finito
523
524 SETPIXEL:
525         jsr     CALC            ; Calculate coordinates
526
527         stx     TEMP
528         lda     ADDR
529         ldy     ADDR+1
530         jsr     VDCSetSourceAddr
531         jsr     VDCReadByte
532         ldx     TEMP
533
534         sta     TEMP
535         eor     BITMASK
536         and     BITTAB,X
537         eor     TEMP
538         pha
539         lda     ADDR
540         ldy     ADDR+1
541         jsr     VDCSetSourceAddr
542         pla
543         jsr     VDCWriteByte
544
545 @L9:    rts
546
547 ; ------------------------------------------------------------------------
548 ; GETPIXEL: Read the color value of a pixel and return it in A/X. The
549 ; coordinates passed to this function are never outside the visible screen
550 ; area, so there is no need for clipping inside this function.
551
552
553 GETPIXEL:
554         jsr     CALC            ; Calculate coordinates
555
556         stx     TEMP            ; preserve X
557         lda     ADDR
558         ldy     ADDR+1
559         jsr     VDCSetSourceAddr
560         jsr     VDCReadByte
561         ldx     TEMP
562
563         ldy     #$00
564         and     BITTAB,X
565         beq     @L1
566         iny
567
568 @L1:    tya                     ; Get color value into A
569         ldx     #$00            ; Clear high byte
570         rts
571
572 ; ------------------------------------------------------------------------
573 ; HORLINE: Draw a horizontal line from X1/Y to X2/Y, where X1 = ptr1,
574 ; Y = ptr2 and X2 = ptr3, using the current drawing color.
575 ;
576 ; This is a special line drawing entry used when the line is know to be
577 ; horizontal, for example by the BAR emulation routine. If the driver does
578 ; not have special code for horizontal lines, it may just copy Y to Y2 and
579 ; proceed with the generic line drawing code.
580 ;
581 ; Note: Line coordinates will always be sorted (Y1 <= X2) and clipped.
582 ;
583 ; Must set an error code: NO
584 ;
585
586 HORLINE:
587         lda X1
588         pha
589         lda X1+1
590         pha
591         jsr CALC                ; get data for LEFT
592         lda BITMASKL,x          ; remember left address and bitmask
593         pha
594         lda ADDR
595         pha
596         lda ADDR+1
597         pha
598
599         lda X2
600         sta X1
601         lda X2+1
602         sta X1+1
603         jsr CALC                ; get data for RIGHT
604         lda BITMASKR,x
605         sta TEMP3
606
607         pla                     ; recall data for LEFT
608         sta X1+1
609         pla
610         sta X1                  ; put left address into X1
611         pla
612
613         cmp #%11111111          ; if left bit <> 0
614         beq @L1
615         sta TEMP2               ; do left byte only...
616         lda X1
617         ldy X1+1
618         jsr VDCSetSourceAddr
619         jsr VDCReadByte
620         sta TEMP
621         eor BITMASK
622         and TEMP2
623         eor TEMP
624         pha
625         lda X1
626         ldy X1+1
627         jsr VDCSetSourceAddr
628         pla
629         jsr VDCWriteByte
630         inc X1                  ; ... and proceed
631         bne @L1
632         inc X1+1
633
634         ; do right byte (if Y2=0 ++ADDR and skip)
635 @L1:    lda TEMP3
636         cmp #%11111111          ; if right bit <> 7
637         bne @L11
638         inc ADDR                ; right bit = 7 - the next one is the last
639         bne @L10
640         inc ADDR+1
641 @L10:   bne @L2
642
643 @L11:   lda ADDR                ; do right byte only...
644         ldy ADDR+1
645         jsr VDCSetSourceAddr
646         jsr VDCReadByte
647         sta TEMP
648         eor BITMASK
649         and TEMP3
650         eor TEMP
651         pha
652         lda ADDR
653         ldy ADDR+1
654         jsr VDCSetSourceAddr
655         pla
656         jsr VDCWriteByte
657
658 @L2:                            ; do the fill in the middle
659         lda ADDR                ; calculate offset in full bytes
660         sec
661         sbc X1
662         beq @L3                 ; if equal - there are no more bytes
663         sta ADDR
664
665         lda X1                  ; setup for the left side
666         ldy X1+1
667         jsr VDCSetSourceAddr
668         lda BITMASK             ; get color
669         jsr VDCWriteByte        ; put 1st value
670         ldx ADDR
671         dex
672         beq @L3                 ; 1 byte already written
673
674         stx ADDR                ; if there are more bytes - fill them...
675         ldx #VDC_VSCROLL
676         lda #0
677         jsr VDCWriteReg         ; setup for fill
678         ldx #VDC_COUNT
679         lda ADDR
680         jsr VDCWriteReg         ; ... fill them NOW!
681
682 @L3:    pla
683         sta X1+1
684         pla
685         sta X1
686         rts
687
688 ; ------------------------------------------------------------------------
689 ; LINE: Draw a line from X1/Y1 to X2/Y2, where X1/Y1 = ptr1/ptr2 and
690 ; X2/Y2 = ptr3/ptr4 using the current drawing color.
691 ;
692 ; Must set an error code: NO
693 ;
694
695 LINE:
696         ; if (x2>x1) {
697         ldx     #X1
698         lda     X2
699         ldy     X2+1
700         jsr     icmp
701         bcc     @L0137
702         beq     @L0137
703         ;  x2<->x1 }
704         lda     X1
705         ldx     X2
706         sta     X2
707         stx     X1
708         lda     X1+1
709         ldx     X2+1
710         sta     X2+1
711         stx     X1+1
712 @L0137: ; if (y2>y1) {
713         ldx     #Y1
714         lda     Y2
715         ldy     Y2+1
716         jsr     icmp
717         bcc     @L013F
718         bne     @nequal
719         jmp     HORLINE         ; x1/x2 are sorted, y1==y2 - do faster horizontal line draw
720 @nequal:
721         ; y2<->y1 }
722         lda     Y1
723         ldx     Y2
724         sta     Y2
725         stx     Y1
726         lda     Y1+1
727         ldx     Y2+1
728         sta     Y2+1
729         stx     Y1+1
730 @L013F:
731         ; nx = x2 - x1
732         lda     X2
733         sec
734         sbc     X1
735         sta     NX
736         lda     X2+1
737         sbc     X1+1
738         sta     NX+1
739         ; ny = y2 - y1
740         lda     Y2
741         sec
742         sbc     Y1
743         sta     NY
744         lda     Y2+1
745         sbc     Y1+1
746         sta     NY+1
747         ; if (nx<ny) {
748         ldx     #NX
749         lda     NY
750         ldy     NY+1
751         jsr     icmp
752         bcs     @L041B
753         ;  nx <-> ny
754         lda     NX
755         ldx     NY
756         sta     NY
757         stx     NX
758         lda     NX+1
759         ldx     NY+1
760         sta     NY+1
761         stx     NX+1
762         ; dx = dy = 0; ax = ay = 1 }
763         ldy     #1
764         sty     AY
765         dey
766         beq     @L025A
767         ; else { dx = dy = 1; ax = ay = 0 }
768 @L041B: ldy     #0
769         sty     AY
770         iny
771 @L025A: sty     DX
772         sty     DY
773         ; err = 0
774         lda     #0
775         sta     ERR
776         sta     ERR+1
777         ; for (count=nx;count>0;--count) {
778         lda     NX
779         ldx     NX+1
780         sta     COUNT
781         stx     COUNT+1
782 @L0166: lda     COUNT           ; count>0
783         ora     COUNT+1
784         bne     @L0167
785         rts
786         ;    setpixel(X1,Y1)
787 @L0167: jsr     SETPIXELCLIP
788         ;    pb = err - ny
789         lda     ERR
790         sec
791         sbc     NY
792         sta     PB
793         lda     ERR+1
794         sbc     NY+1
795         sta     PB+1
796         tax
797         ;    ub = pb + nx
798         lda     PB
799         clc
800         adc     NX
801         sta     UB
802         txa
803         adc     NX+1
804         sta     UB+1
805         ;    x1 = x1 + dx
806         lda     X1
807         clc
808         adc     DX
809         sta     X1
810         bcc     @L0254
811         inc     X1+1
812         ;   y1 = y1 + ay
813 @L0254:
814         lda     Y1
815         clc
816         adc     AY
817         sta     Y1
818         bcc     @L0255
819         inc     Y1+1
820 @L0255:
821         ; if (abs(pb)<abs(ub)) {
822         lda     PB
823         ldy     PB+1
824         jsr     abs
825         sta     TEMP3
826         sty     TEMP4
827         lda     UB
828         ldy     UB+1
829         jsr     abs
830         ldx     #TEMP3
831         jsr     icmp
832         bpl     @L017B
833         ;   err = pb
834         lda     PB
835         ldx     PB+1
836         jmp     @L025B
837         ; } else { x1 = x1 + ay
838 @L017B: 
839         lda     X1
840         clc
841         adc     AY
842         sta     X1
843         bcc     @L0256
844         inc     X1+1
845         ;       y1 = y1 + dy
846 @L0256:
847         lda     Y1
848         clc
849         adc     DY
850         sta     Y1
851         bcc     @L0257
852         inc     Y1+1
853         ;       err = ub }
854 @L0257:
855         lda     UB
856         ldx     UB+1
857 @L025B:
858         sta     ERR
859         stx     ERR+1
860         ; } (--count)
861         sec
862         lda     COUNT
863         sbc     #1
864         sta     COUNT
865         bcc     @L0260
866         jmp     @L0166
867 @L0260: dec     COUNT+1
868         jmp     @L0166
869
870 ; ------------------------------------------------------------------------
871 ; BAR: Draw a filled rectangle with the corners X1/Y1, X2/Y2, where
872 ; X1/Y1 = ptr1/ptr2 and X2/Y2 = ptr3/ptr4 using the current drawing color.
873 ; Contrary to most other functions, the graphics kernel will sort and clip
874 ; the coordinates before calling the driver, so on entry the following
875 ; conditions are valid:
876 ;       X1 <= X2
877 ;       Y1 <= Y2
878 ;       (X1 >= 0) && (X1 < XRES)
879 ;       (X2 >= 0) && (X2 < XRES)
880 ;       (Y1 >= 0) && (Y1 < YRES)
881 ;       (Y2 >= 0) && (Y2 < YRES)
882 ;
883 ; Must set an error code: NO
884 ;
885
886 BAR:
887         inc     Y2
888         bne     @L0
889         inc     Y2+1
890 @L0:    jsr     HORLINE
891         inc     Y1
892         bne     @L1
893         inc     Y1+1
894 @L1:    lda     Y1
895         cmp     Y2
896         bne     @L0
897         lda     Y1+1
898         cmp     Y2+1
899         bne     @L0
900         rts
901
902 ; ------------------------------------------------------------------------
903 ; CIRCLE: Draw a circle around the center X1/Y1 (= ptr1/ptr2) with the
904 ; radius in tmp1 and the current drawing color.
905 ;
906 ; Must set an error code: NO
907 ;
908
909 CIRCLE: 
910         lda     RADIUS
911         bne     @L1
912         jmp     SETPIXELCLIP    ; Plot as a point
913
914 @L1:    sta     XX
915         ; x = r;
916         lda     #0
917         sta     XX+1
918         sta     YY
919         sta     YY+1
920         sta     MaxO
921         sta     MaxO+1
922         ; y =0; mo=0;
923         lda     X1
924         ldx     X1+1
925         sta     XS
926         stx     XS+1
927         lda     Y1
928         ldx     Y1+1
929         sta     YS
930         stx     YS+1            ; XS/YS to remember the center
931
932         ; while (y<x) {
933 @L013B: ldx     #YY
934         lda     XX
935         ldy     XX+1
936         jsr     icmp
937         bcc     @L12
938         rts
939 @L12:   ; plot points in 8 slices...
940         lda     XS
941         clc
942         adc     XX
943         sta     X1
944         lda     XS+1
945         adc     XX+1
946         sta     X1+1            ; x1 = xs+x
947         lda     YS
948         clc
949         adc     YY
950         sta     Y1
951         pha
952         lda     YS+1
953         adc     YY+1
954         sta     Y1+1            ; (stack)=ys+y, y1=(stack)
955         pha
956         jsr     SETPIXELCLIP    ; plot(xs+x,ys+y)
957         lda     YS
958         sec
959         sbc     YY
960         sta     Y1
961         sta     Y3
962         lda     YS+1
963         sbc     YY+1
964         sta     Y1+1            ; y3 = y1 = ys-y
965         sta     Y3+1
966         jsr     SETPIXELCLIP    ; plot(xs+x,ys-y)
967         pla
968         sta     Y1+1
969         pla
970         sta     Y1              ; y1 = ys+y
971         lda     XS
972         sec
973         sbc     XX
974         sta     X1
975         lda     XS+1
976         sbc     XX+1
977         sta     X1+1
978         jsr     SETPIXELCLIP    ; plot (xs-x,ys+y)
979         lda     Y3
980         sta     Y1
981         lda     Y3+1
982         sta     Y1+1
983         jsr     SETPIXELCLIP    ; plot (xs-x,ys-y)
984
985         lda     XS
986         clc
987         adc     YY
988         sta     X1
989         lda     XS+1
990         adc     YY+1
991         sta     X1+1            ; x1 = xs+y
992         lda     YS
993         clc
994         adc     XX
995         sta     Y1
996         pha
997         lda     YS+1
998         adc     XX+1
999         sta     Y1+1            ; (stack)=ys+x, y1=(stack)
1000         pha
1001         jsr     SETPIXELCLIP    ; plot(xs+y,ys+x)
1002         lda     YS
1003         sec
1004         sbc     XX
1005         sta     Y1
1006         sta     Y3
1007         lda     YS+1
1008         sbc     XX+1
1009         sta     Y1+1            ; y3 = y1 = ys-x
1010         sta     Y3+1
1011         jsr     SETPIXELCLIP    ; plot(xs+y,ys-x)
1012         pla
1013         sta     Y1+1
1014         pla
1015         sta     Y1              ; y1 = ys+x(stack)
1016         lda     XS
1017         sec
1018         sbc     YY
1019         sta     X1
1020         lda     XS+1
1021         sbc     YY+1
1022         sta     X1+1
1023         jsr     SETPIXELCLIP    ; plot (xs-y,ys+x)
1024         lda     Y3
1025         sta     Y1
1026         lda     Y3+1
1027         sta     Y1+1
1028         jsr     SETPIXELCLIP    ; plot (xs-y,ys-x)
1029
1030         ; og = mo+y+y+1
1031         lda     MaxO
1032         ldx     MaxO+1
1033         clc
1034         adc     YY
1035         tay
1036         txa
1037         adc     YY+1
1038         tax
1039         tya
1040         clc
1041         adc     YY
1042         tay
1043         txa
1044         adc     YY+1
1045         tax
1046         tya
1047         clc
1048         adc     #1
1049         bcc     @L0143
1050         inx
1051 @L0143: sta     OGora
1052         stx     OGora+1
1053         ; ou = og-x-x+1
1054         sec
1055         sbc     XX
1056         tay
1057         txa
1058         sbc     XX+1
1059         tax
1060         tya
1061         sec
1062         sbc     XX
1063         tay
1064         txa
1065         sbc     XX+1
1066         tax
1067         tya
1068         clc
1069         adc     #1
1070         bcc     @L0146
1071         inx
1072 @L0146: sta     OUkos
1073         stx     OUkos+1
1074         ; ++y
1075         inc     YY
1076         bne     @L0148
1077         inc     YY+1
1078 @L0148: ; if (abs(ou)<abs(og))
1079         lda     OUkos
1080         ldy     OUkos+1
1081         jsr     abs
1082         sta     TEMP3
1083         sty     TEMP4
1084         lda     OGora
1085         ldy     OGora+1
1086         jsr     abs
1087         ldx     #TEMP3
1088         jsr     icmp
1089         bpl     @L0149
1090         ; { --x;
1091         sec
1092         lda     XX
1093         sbc     #1
1094         sta     XX
1095         bcs     @L014E
1096         dec     XX+1
1097 @L014E: ; mo = ou; }
1098         lda     OUkos
1099         ldx     OUkos+1
1100         jmp     @L014G
1101         ; else { mo = og }
1102 @L0149: lda     OGora
1103         ldx     OGora+1
1104 @L014G: sta     MaxO
1105         stx     MaxO+1
1106         ; }
1107         jmp     @L013B
1108
1109 ; ------------------------------------------------------------------------
1110 ; TEXTSTYLE: Set the style used when calling OUTTEXT. Text scaling in X and Y
1111 ; direction is passend in X/Y, the text direction is passed in A.
1112 ;
1113 ; Must set an error code: NO
1114 ;
1115
1116 TEXTSTYLE:
1117         stx     TEXTMAGX
1118         sty     TEXTMAGY
1119         sta     TEXTDIR
1120         rts
1121
1122
1123 ; ------------------------------------------------------------------------
1124 ; OUTTEXT: Output text at X/Y = ptr1/ptr2 using the current color and the
1125 ; current text style. The text to output is given as a zero terminated
1126 ; string with address in ptr3.
1127 ;
1128 ; Must set an error code: NO
1129 ;
1130
1131 OUTTEXT:
1132         rts
1133
1134 ; ------------------------------------------------------------------------
1135 ; Calculate all variables to plot the pixel at X1/Y1.
1136 ;------------------------
1137 ;< X1,Y1 - pixel
1138 ;> ADDR - address of card
1139 ;> X - bit number (X1 & 7)
1140 CALC:
1141         lda     Y1
1142         pha
1143         lda     Y1+1
1144         pha
1145         lsr
1146         ror     Y1              ; Y=Y/2
1147         sta     Y1+1
1148         sta     ADDR+1
1149         lda     Y1
1150         asl
1151         rol     ADDR+1
1152         asl
1153         rol     ADDR+1          ; Y*4
1154         clc
1155         adc     Y1
1156         sta     ADDR
1157         lda     Y1+1
1158         adc     ADDR+1
1159         sta     ADDR+1          ; Y*4+Y=Y*5
1160         lda     ADDR
1161         asl
1162         rol     ADDR+1
1163         asl
1164         rol     ADDR+1
1165         asl
1166         rol     ADDR+1
1167         asl
1168         rol     ADDR+1
1169         sta     ADDR            ; Y*5*16=Y*80
1170         lda     X1+1
1171         sta     TEMP
1172         lda     X1
1173         lsr     TEMP
1174         ror
1175         lsr     TEMP
1176         ror
1177         lsr     TEMP
1178         ror
1179         clc
1180         adc     ADDR
1181         sta     ADDR
1182         lda     ADDR+1          ; ADDR = Y*80+x/8
1183         adc     TEMP
1184         sta     ADDR+1
1185         pla
1186         sta     Y1+1
1187         pla
1188         sta     Y1
1189         and     #1
1190         beq     @even           ; even line - no offset
1191         lda     ADDR
1192         clc
1193         adc     #<21360
1194         sta     ADDR
1195         lda     ADDR+1
1196         adc     #>21360
1197         sta     ADDR+1          ; odd lines are 21360 bytes farther
1198 @even:  lda     X1
1199         and     #7
1200         tax
1201         rts
1202
1203 ;-------------
1204 ; copies of some runtime routines
1205
1206 abs:
1207         ; a/y := abs(a/y)
1208         dey
1209         iny
1210         bpl     @L1
1211         ; negay
1212         clc
1213         eor     #$ff
1214         adc     #1
1215         pha
1216         tya
1217         eor     #$ff
1218         adc     #0
1219         tay
1220         pla
1221 @L1:    rts
1222
1223 icmp:
1224         ; compare a/y to zp,x
1225         sta     TEMP            ; TEMP/TEMP2 - arg2
1226         sty     TEMP2
1227         lda     $0,x
1228         pha
1229         lda     $1,x
1230         tay
1231         pla
1232         tax
1233         tya                     ; x/a - arg1 (a=high)
1234
1235         sec
1236         sbc     TEMP2
1237         bne     @L4
1238         cpx     TEMP
1239         beq     @L3
1240         adc     #$ff
1241         ora     #$01
1242 @L3:    rts
1243 @L4:    bvc     @L3
1244         eor     #$ff
1245         ora     #$01
1246         rts
1247
1248 ;-------------
1249 ; VDC helpers
1250
1251 VDCSetSourceAddr:
1252         pha
1253         tya
1254         ldx     #VDC_DATA_HI
1255         jsr     VDCWriteReg
1256         pla
1257         ldx     #VDC_DATA_LO
1258         bne     VDCWriteReg
1259
1260 VDCReadByte:
1261         ldx     #VDC_DATA
1262 VDCReadReg:
1263         stx     VDC_ADDR_REG
1264 @L0:    bit     VDC_ADDR_REG
1265         bpl     @L0
1266         lda     VDC_DATA_REG
1267         rts
1268
1269 VDCWriteByte:
1270         ldx     #VDC_DATA
1271 VDCWriteReg:
1272         stx     VDC_ADDR_REG
1273 @L0:    bit     VDC_ADDR_REG
1274         bpl     @L0
1275         sta     VDC_DATA_REG
1276         rts
1277