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