]> git.sur5r.net Git - cc65/blob - libsrc/c128/c128-640-200-2.s
c43601fbc0b6f47f6da0221d27c1413e2a09b052
[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   UNINSTALL
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 ; UNINSTALL 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 UNINSTALL:
273         rts
274
275
276 ; ------------------------------------------------------------------------
277 ; INIT: Changes an already installed device from text mode to graphics
278 ; mode.
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         jsr VDCWriteReg         ; switch to text screen
350 ; fall through to GETERROR in order to clear ERROR status
351
352 ; ------------------------------------------------------------------------
353 ; GETERROR: Return the error code in A and clear it.
354
355 GETERROR:
356         ldx     #TGI_ERR_OK
357         lda     ERROR
358         stx     ERROR
359         rts
360
361 ; ------------------------------------------------------------------------
362 ; CONTROL: Platform/driver specific entry point.
363 ;
364 ; Must set an error code: YES
365 ;
366
367 CONTROL:
368         lda     #TGI_ERR_INV_FUNC
369         sta     ERROR
370         rts
371
372 ; ------------------------------------------------------------------------
373 ; CLEAR: Clears the screen.
374 ;
375 ; Must set an error code: NO
376 ;
377
378 CLEAR:
379         lda     #0
380         ldy     SCRBASE
381         jsr     VDCSetSourceAddr
382         lda     #0
383         ldx     #VDC_VSCROLL
384         jsr     VDCWriteReg                     ; set fill mode
385         lda     #0
386         jsr     VDCWriteByte                    ; put 1rst byte (fill value)
387         ldy     #62                             ; 62 times
388         lda     #0                              ; 256 bytes
389         ldx     #VDC_COUNT
390 @L1:    jsr     VDCWriteReg
391         dey
392         bne     @L1
393         lda     #127
394         jmp     VDCWriteReg                     ; 1+62*256+127=16000=(640*256)/8
395
396 ; ------------------------------------------------------------------------
397 ; SETVIEWPAGE: Set the visible page. Called with the new page in A (0..n).
398 ; The page number is already checked to be valid by the graphics kernel.
399 ;
400 ; Must set an error code: NO (will only be called if page ok)
401 ;
402
403 SETVIEWPAGE:
404         clc
405         ror
406         ror
407         ror
408         ldx     #VDC_DSP_HI
409         jmp     VDCWriteReg
410
411 ; ------------------------------------------------------------------------
412 ; SETDRAWPAGE: Set the drawable page. Called with the new page in A (0..n).
413 ; The page number is already checked to be valid by the graphics kernel.
414 ;
415 ; Must set an error code: NO (will only be called if page ok)
416 ;
417
418 SETDRAWPAGE:
419         clc
420         ror
421         ror
422         ror
423         sta     SCRBASE
424         rts
425
426 ; ------------------------------------------------------------------------
427 ; SETCOLOR: Set the drawing color (in A). The new color is already checked
428 ; to be in a valid range (0..maxcolor-1).
429 ;
430 ; Must set an error code: NO (will only be called if color ok)
431 ;
432
433 SETCOLOR:
434         tax
435         beq     @L1
436         lda     #$FF
437 @L1:    sta     BITMASK
438         rts
439
440 ; ------------------------------------------------------------------------
441 ; SETPALETTE: Set the palette (not available with all drivers/hardware).
442 ; A pointer to the palette is passed in ptr1. Must set an error if palettes
443 ; are not supported
444 ;
445 ; Must set an error code: YES
446 ;
447
448 SETPALETTE:
449         ldy     #PALETTESIZE - 1
450 @L1:    lda     (ptr1),y        ; Copy the palette
451         and     #$0F            ; Make a valid color
452         sta     PALETTE,y
453         dey
454         bpl     @L1
455
456 ; Get the color entries from the palette
457
458         ldy     PALETTE+1       ; Foreground color
459         lda     COLTRANS,y
460         asl     a
461         asl     a
462         asl     a
463         asl     a
464         ldy     PALETTE         ; Background color
465         ora     COLTRANS,y
466
467         ldx     #VDC_COLORS
468         jmp     VDCWriteReg
469
470 ; ------------------------------------------------------------------------
471 ; GETPALETTE: Return the current palette in A/X. Must return NULL and set an
472 ; error if palettes are not supported.
473 ;
474 ; Must set an error code: YES
475 ;
476
477 GETPALETTE:
478         lda     #<PALETTE
479         ldx     #>PALETTE
480         rts
481
482 ; ------------------------------------------------------------------------
483 ; GETDEFPALETTE: Return the default palette for the driver in A/X. Must
484 ; return NULL and set an error of palettes are not supported.
485 ;
486 ; Must set an error code: YES
487 ;
488
489 GETDEFPALETTE:
490         lda     #<DEFPALETTE
491         ldx     #>DEFPALETTE
492         rts
493
494 ; ------------------------------------------------------------------------
495 ; SETPIXEL: Draw one pixel at X1/Y1 = ptr1/ptr2 with the current drawing
496 ; color. The coordinates passed to this function are never outside the
497 ; visible screen area, so there is no need for clipping inside this function.
498 ;
499 ; Must set an error code: NO
500 ;
501
502 SETPIXELCLIP:
503         lda     Y1+1
504         bmi     @finito         ; y<0
505         lda     X1+1
506         bmi     @finito         ; x<0
507         lda     xres
508         ldx     xres+1
509         sta     ADDR
510         stx     ADDR+1
511         ldx     #ADDR
512         lda     X1
513         ldy     X1+1
514         jsr     icmp            ; if (xres<x1)
515         bcs     @cont           ; !(xres<x1)
516 @finito:rts
517 @cont:  lda     yres
518         ldx     yres+1
519         sta     ADDR
520         stx     ADDR+1
521         ldx     #ADDR
522         lda     Y1
523         ldy     Y1+1
524         jsr     icmp            ; if (yres<y1)
525         bcc     @finito
526
527 SETPIXEL:
528         jsr     CALC            ; Calculate coordinates
529
530         stx     TEMP
531         lda     ADDR
532         ldy     ADDR+1
533         jsr     VDCSetSourceAddr
534         jsr     VDCReadByte
535         ldx     TEMP
536
537         sta     TEMP
538         eor     BITMASK
539         and     BITTAB,X
540         eor     TEMP
541         pha
542         lda     ADDR
543         ldy     ADDR+1
544         jsr     VDCSetSourceAddr
545         pla
546         jsr     VDCWriteByte
547
548 @L9:    rts
549
550 ; ------------------------------------------------------------------------
551 ; GETPIXEL: Read the color value of a pixel and return it in A/X. The
552 ; coordinates passed to this function are never outside the visible screen
553 ; area, so there is no need for clipping inside this function.
554
555
556 GETPIXEL:
557         jsr     CALC            ; Calculate coordinates
558
559         stx     TEMP            ; preserve X
560         lda     ADDR
561         ldy     ADDR+1
562         jsr     VDCSetSourceAddr
563         jsr     VDCReadByte
564         ldx     TEMP
565
566         ldy     #$00
567         and     BITTAB,X
568         beq     @L1
569         iny
570
571 @L1:    tya                     ; Get color value into A
572         ldx     #$00            ; Clear high byte
573         rts
574
575 ; ------------------------------------------------------------------------
576 ; HORLINE: Draw a horizontal line from X1/Y to X2/Y, where X1 = ptr1,
577 ; Y = ptr2 and X2 = ptr3, using the current drawing color.
578 ;
579 ; This is a special line drawing entry used when the line is know to be
580 ; horizontal, for example by the BAR emulation routine. If the driver does
581 ; not have special code for horizontal lines, it may just copy Y to Y2 and
582 ; proceed with the generic line drawing code.
583 ;
584 ; Note: Line coordinates will always be sorted (Y1 <= X2) and clipped.
585 ;
586 ; Must set an error code: NO
587 ;
588
589 HORLINE:
590         lda X1
591         pha
592         lda X1+1
593         pha
594         jsr CALC                ; get data for LEFT
595         lda BITMASKL,x          ; remember left address and bitmask
596         pha
597         lda ADDR
598         pha
599         lda ADDR+1
600         pha
601
602         lda X2
603         sta X1
604         lda X2+1
605         sta X1+1
606         jsr CALC                ; get data for RIGHT
607         lda BITMASKR,x
608         sta TEMP3
609
610         pla                     ; recall data for LEFT
611         sta X1+1
612         pla
613         sta X1                  ; put left address into X1
614         pla
615
616         cmp #%11111111          ; if left bit <> 0
617         beq @L1
618         sta TEMP2               ; do left byte only...
619         lda X1
620         ldy X1+1
621         jsr VDCSetSourceAddr
622         jsr VDCReadByte
623         sta TEMP
624         eor BITMASK
625         and TEMP2
626         eor TEMP
627         pha
628         lda X1
629         ldy X1+1
630         jsr VDCSetSourceAddr
631         pla
632         jsr VDCWriteByte
633         inc X1                  ; ... and proceed
634         bne @L1
635         inc X1+1
636
637         ; do right byte (if Y2=0 ++ADDR and skip)
638 @L1:    lda TEMP3
639         cmp #%11111111          ; if right bit <> 7
640         bne @L11
641         inc ADDR                ; right bit = 7 - the next one is the last
642         bne @L10
643         inc ADDR+1
644 @L10:   bne @L2
645
646 @L11:   lda ADDR                ; do right byte only...
647         ldy ADDR+1
648         jsr VDCSetSourceAddr
649         jsr VDCReadByte
650         sta TEMP
651         eor BITMASK
652         and TEMP3
653         eor TEMP
654         pha
655         lda ADDR
656         ldy ADDR+1
657         jsr VDCSetSourceAddr
658         pla
659         jsr VDCWriteByte
660
661 @L2:                            ; do the fill in the middle
662         lda ADDR                ; calculate offset in full bytes
663         sec
664         sbc X1
665         beq @L3                 ; if equal - there are no more bytes
666         sta ADDR
667
668         lda X1                  ; setup for the left side
669         ldy X1+1
670         jsr VDCSetSourceAddr
671         lda BITMASK             ; get color
672         jsr VDCWriteByte        ; put 1st value
673         ldx ADDR
674         dex
675         beq @L3                 ; 1 byte already written
676
677         stx ADDR                ; if there are more bytes - fill them...
678         ldx #VDC_VSCROLL
679         lda #0
680         jsr VDCWriteReg         ; setup for fill
681         ldx #VDC_COUNT
682         lda ADDR
683         jsr VDCWriteReg         ; ... fill them NOW!
684
685 @L3:    pla
686         sta X1+1
687         pla
688         sta X1
689         rts
690
691 ; ------------------------------------------------------------------------
692 ; LINE: Draw a line from X1/Y1 to X2/Y2, where X1/Y1 = ptr1/ptr2 and
693 ; X2/Y2 = ptr3/ptr4 using the current drawing color.
694 ;
695 ; Must set an error code: NO
696 ;
697
698 LINE:
699         ; nx = abs(x2 - x1)
700         lda     X2
701         sec
702         sbc     X1
703         sta     NX
704         lda     X2+1
705         sbc     X1+1
706         tay
707         lda     NX
708         jsr     abs
709         sta     NX
710         sty     NX+1
711         ; ny = abs(y2 - y1)
712         lda     Y2
713         sec
714         sbc     Y1
715         sta     NY
716         lda     Y2+1
717         sbc     Y1+1
718         tay
719         lda     NY
720         jsr     abs
721         sta     NY
722         sty     NY+1
723         ; if (x2>x1)
724         ldx     #X2
725         lda     X1
726         ldy     X1+1
727         jsr     icmp
728         bcc     @L0243
729         beq     @L0243
730         ; dx = 1;
731         lda     #1
732         bne     @L0244
733         ; else
734         ; dx = -1;
735 @L0243: lda     #$ff
736 @L0244: sta     DX
737         ; if (y2>y1)
738         ldx     #Y2
739         lda     Y1
740         ldy     Y1+1
741         jsr     icmp
742         bcc     @L024A
743         beq     @L024A
744         ; dy = 1;
745         lda     #1
746         bne     @L024B
747         ; else
748         ; dy = -1;
749 @L024A: lda     #$ff
750 @L024B: sta     DY
751         ; err = ay = 0;
752         lda     #0
753         sta     ERR
754         sta     ERR+1
755         sta     AY
756
757         ; if (nx<ny) {
758         ldx     #NX
759         lda     NY
760         ldy     NY+1
761         jsr     icmp
762         bcs     @L0255
763         ;  nx <-> ny
764         lda     NX
765         ldx     NY
766         sta     NY
767         stx     NX
768         lda     NX+1
769         ldx     NY+1
770         sta     NY+1
771         stx     NX+1
772         ; ay = dx
773         lda     DX
774         sta     AY
775         ; dx = dy = 0;
776         lda     #0
777         sta     DX
778         sta     DY
779         ; ny = - ny;
780 @L0255: lda     NY
781         ldy     NY+1
782         jsr     neg
783         sta     NY
784         sty     NY+1
785         ; for (count=nx;count>0;--count) {
786         lda     NX
787         ldx     NX+1
788         sta     COUNT
789         stx     COUNT+1
790 @L0166: lda     COUNT           ; count>0
791         ora     COUNT+1
792         bne     @L0167
793         rts
794         ;    setpixel(X1,Y1)
795 @L0167: jsr     SETPIXELCLIP
796         ;    pb = err + ny
797         lda     ERR
798         clc
799         adc     NY
800         sta     PB
801         lda     ERR+1
802         adc     NY+1
803         sta     PB+1
804         tax
805         ;    ub = pb + nx
806         lda     PB
807         clc
808         adc     NX
809         sta     UB
810         txa
811         adc     NX+1
812         sta     UB+1
813         ;    x1 = x1 + dx
814         ldx     #0
815         lda     DX
816         bpl     @L027B
817         dex
818 @L027B: clc
819         adc     X1
820         sta     X1
821         txa
822         adc     X1+1
823         sta     X1+1
824         ;   y1 = y1 + ay
825         ldx     #0
826         lda     AY
827         bpl     @L027E
828         dex
829 @L027E: clc
830         adc     Y1
831         sta     Y1
832         txa
833         adc     Y1+1
834         sta     Y1+1
835         ; if (abs(pb)<abs(ub)) {
836         lda     PB
837         ldy     PB+1
838         jsr     abs
839         sta     TEMP3
840         sty     TEMP4
841         lda     UB
842         ldy     UB+1
843         jsr     abs
844         ldx     #TEMP3
845         jsr     icmp
846         bpl     @L027F
847         ;   err = pb
848         lda     PB
849         ldx     PB+1
850         jmp     @L0312
851         ; } else { x1 = x1 + ay
852 @L027F:
853         ldx     #0
854         lda     AY
855         bpl     @L0288
856         dex
857 @L0288: clc
858         adc     X1
859         sta     X1
860         txa
861         adc     X1+1
862         sta     X1+1
863         ;       y1 = y1 + dy
864         ldx     #0
865         lda     DY
866         bpl     @L028B
867         dex
868 @L028B: clc
869         adc     Y1
870         sta     Y1
871         txa
872         adc     Y1+1
873         sta     Y1+1
874         ;       err = ub }
875         lda     UB
876         ldx     UB+1
877 @L0312:
878         sta     ERR
879         stx     ERR+1
880         ; } (--count)
881         sec
882         lda     COUNT
883         sbc     #1
884         sta     COUNT
885         bcc     @L0260
886         jmp     @L0166
887 @L0260: dec     COUNT+1
888         jmp     @L0166
889
890 ; ------------------------------------------------------------------------
891 ; BAR: Draw a filled rectangle with the corners X1/Y1, X2/Y2, where
892 ; X1/Y1 = ptr1/ptr2 and X2/Y2 = ptr3/ptr4 using the current drawing color.
893 ; Contrary to most other functions, the graphics kernel will sort and clip
894 ; the coordinates before calling the driver, so on entry the following
895 ; conditions are valid:
896 ;       X1 <= X2
897 ;       Y1 <= Y2
898 ;       (X1 >= 0) && (X1 < XRES)
899 ;       (X2 >= 0) && (X2 < XRES)
900 ;       (Y1 >= 0) && (Y1 < YRES)
901 ;       (Y2 >= 0) && (Y2 < YRES)
902 ;
903 ; Must set an error code: NO
904 ;
905
906 BAR:
907         inc     Y2
908         bne     @L0
909         inc     Y2+1
910 @L0:    jsr     HORLINE
911         inc     Y1
912         bne     @L1
913         inc     Y1+1
914 @L1:    lda     Y1
915         cmp     Y2
916         bne     @L0
917         lda     Y1+1
918         cmp     Y2+1
919         bne     @L0
920         rts
921
922 ; ------------------------------------------------------------------------
923 ; CIRCLE: Draw a circle around the center X1/Y1 (= ptr1/ptr2) with the
924 ; radius in tmp1 and the current drawing color.
925 ;
926 ; Must set an error code: NO
927 ;
928
929 CIRCLE:
930         lda     RADIUS
931         bne     @L1
932         jmp     SETPIXELCLIP    ; Plot as a point
933
934 @L1:    sta     XX
935         ; x = r;
936         lda     #0
937         sta     XX+1
938         sta     YY
939         sta     YY+1
940         sta     MaxO
941         sta     MaxO+1
942         ; y =0; mo=0;
943         lda     X1
944         ldx     X1+1
945         sta     XS
946         stx     XS+1
947         lda     Y1
948         ldx     Y1+1
949         sta     YS
950         stx     YS+1            ; XS/YS to remember the center
951
952         ; while (y<x) {
953 @L013B: ldx     #YY
954         lda     XX
955         ldy     XX+1
956         jsr     icmp
957         bcc     @L12
958         rts
959 @L12:   ; plot points in 8 slices...
960         lda     XS
961         clc
962         adc     XX
963         sta     X1
964         lda     XS+1
965         adc     XX+1
966         sta     X1+1            ; x1 = xs+x
967         lda     YS
968         clc
969         adc     YY
970         sta     Y1
971         pha
972         lda     YS+1
973         adc     YY+1
974         sta     Y1+1            ; (stack)=ys+y, y1=(stack)
975         pha
976         jsr     SETPIXELCLIP    ; plot(xs+x,ys+y)
977         lda     YS
978         sec
979         sbc     YY
980         sta     Y1
981         sta     Y3
982         lda     YS+1
983         sbc     YY+1
984         sta     Y1+1            ; y3 = y1 = ys-y
985         sta     Y3+1
986         jsr     SETPIXELCLIP    ; plot(xs+x,ys-y)
987         pla
988         sta     Y1+1
989         pla
990         sta     Y1              ; y1 = ys+y
991         lda     XS
992         sec
993         sbc     XX
994         sta     X1
995         lda     XS+1
996         sbc     XX+1
997         sta     X1+1
998         jsr     SETPIXELCLIP    ; plot (xs-x,ys+y)
999         lda     Y3
1000         sta     Y1
1001         lda     Y3+1
1002         sta     Y1+1
1003         jsr     SETPIXELCLIP    ; plot (xs-x,ys-y)
1004
1005         lda     XS
1006         clc
1007         adc     YY
1008         sta     X1
1009         lda     XS+1
1010         adc     YY+1
1011         sta     X1+1            ; x1 = xs+y
1012         lda     YS
1013         clc
1014         adc     XX
1015         sta     Y1
1016         pha
1017         lda     YS+1
1018         adc     XX+1
1019         sta     Y1+1            ; (stack)=ys+x, y1=(stack)
1020         pha
1021         jsr     SETPIXELCLIP    ; plot(xs+y,ys+x)
1022         lda     YS
1023         sec
1024         sbc     XX
1025         sta     Y1
1026         sta     Y3
1027         lda     YS+1
1028         sbc     XX+1
1029         sta     Y1+1            ; y3 = y1 = ys-x
1030         sta     Y3+1
1031         jsr     SETPIXELCLIP    ; plot(xs+y,ys-x)
1032         pla
1033         sta     Y1+1
1034         pla
1035         sta     Y1              ; y1 = ys+x(stack)
1036         lda     XS
1037         sec
1038         sbc     YY
1039         sta     X1
1040         lda     XS+1
1041         sbc     YY+1
1042         sta     X1+1
1043         jsr     SETPIXELCLIP    ; plot (xs-y,ys+x)
1044         lda     Y3
1045         sta     Y1
1046         lda     Y3+1
1047         sta     Y1+1
1048         jsr     SETPIXELCLIP    ; plot (xs-y,ys-x)
1049
1050         ; og = mo+y+y+1
1051         lda     MaxO
1052         ldx     MaxO+1
1053         clc
1054         adc     YY
1055         tay
1056         txa
1057         adc     YY+1
1058         tax
1059         tya
1060         clc
1061         adc     YY
1062         tay
1063         txa
1064         adc     YY+1
1065         tax
1066         tya
1067         clc
1068         adc     #1
1069         bcc     @L0143
1070         inx
1071 @L0143: sta     OGora
1072         stx     OGora+1
1073         ; ou = og-x-x+1
1074         sec
1075         sbc     XX
1076         tay
1077         txa
1078         sbc     XX+1
1079         tax
1080         tya
1081         sec
1082         sbc     XX
1083         tay
1084         txa
1085         sbc     XX+1
1086         tax
1087         tya
1088         clc
1089         adc     #1
1090         bcc     @L0146
1091         inx
1092 @L0146: sta     OUkos
1093         stx     OUkos+1
1094         ; ++y
1095         inc     YY
1096         bne     @L0148
1097         inc     YY+1
1098 @L0148: ; if (abs(ou)<abs(og))
1099         lda     OUkos
1100         ldy     OUkos+1
1101         jsr     abs
1102         sta     TEMP3
1103         sty     TEMP4
1104         lda     OGora
1105         ldy     OGora+1
1106         jsr     abs
1107         ldx     #TEMP3
1108         jsr     icmp
1109         bpl     @L0149
1110         ; { --x;
1111         sec
1112         lda     XX
1113         sbc     #1
1114         sta     XX
1115         bcs     @L014E
1116         dec     XX+1
1117 @L014E: ; mo = ou; }
1118         lda     OUkos
1119         ldx     OUkos+1
1120         jmp     @L014G
1121         ; else { mo = og }
1122 @L0149: lda     OGora
1123         ldx     OGora+1
1124 @L014G: sta     MaxO
1125         stx     MaxO+1
1126         ; }
1127         jmp     @L013B
1128
1129 ; ------------------------------------------------------------------------
1130 ; TEXTSTYLE: Set the style used when calling OUTTEXT. Text scaling in X and Y
1131 ; direction is passend in X/Y, the text direction is passed in A.
1132 ;
1133 ; Must set an error code: NO
1134 ;
1135
1136 TEXTSTYLE:
1137         stx     TEXTMAGX
1138         sty     TEXTMAGY
1139         sta     TEXTDIR
1140         rts
1141
1142
1143 ; ------------------------------------------------------------------------
1144 ; OUTTEXT: Output text at X/Y = ptr1/ptr2 using the current color and the
1145 ; current text style. The text to output is given as a zero terminated
1146 ; string with address in ptr3.
1147 ;
1148 ; Must set an error code: NO
1149 ;
1150
1151 OUTTEXT:
1152         rts
1153
1154 ; ------------------------------------------------------------------------
1155 ; Calculate all variables to plot the pixel at X1/Y1.
1156 ;------------------------
1157 ;< X1,Y1 - pixel
1158 ;> ADDR - address of card
1159 ;> X - bit number (X1 & 7)
1160 CALC:
1161         lda     Y1+1
1162         sta     ADDR+1
1163         lda     Y1
1164         asl
1165         rol     ADDR+1
1166         asl
1167         rol     ADDR+1          ; Y*4
1168         clc
1169         adc     Y1
1170         sta     ADDR
1171         lda     Y1+1
1172         adc     ADDR+1
1173         sta     ADDR+1          ; Y*4+Y=Y*5
1174         lda     ADDR
1175         asl
1176         rol     ADDR+1
1177         asl
1178         rol     ADDR+1
1179         asl
1180         rol     ADDR+1
1181         asl
1182         rol     ADDR+1
1183         sta     ADDR            ; Y*5*16=Y*80
1184         lda     X1+1
1185         sta     TEMP
1186         lda     X1
1187         lsr     TEMP
1188         ror
1189         lsr     TEMP
1190         ror
1191         lsr     TEMP
1192         ror
1193         clc
1194         adc     ADDR
1195         sta     ADDR
1196         lda     ADDR+1          ; ADDR = Y*80+x/8
1197         adc     TEMP
1198         sta     ADDR+1
1199         lda     ADDR+1
1200         adc     SCRBASE
1201         sta     ADDR+1
1202         lda     X1
1203         and     #7
1204         tax
1205         rts
1206
1207 ;-------------
1208 ; copies of some runtime routines
1209
1210 abs:
1211         ; a/y := abs(a/y)
1212         dey
1213         iny
1214         bpl     absend
1215         ; negay
1216 neg:    clc
1217         eor     #$ff
1218         adc     #1
1219         pha
1220         tya
1221         eor     #$ff
1222         adc     #0
1223         tay
1224         pla
1225 absend: rts
1226
1227 icmp:
1228         ; compare a/y to zp,x
1229         sta     TEMP            ; TEMP/TEMP2 - arg2
1230         sty     TEMP2
1231         lda     $0,x
1232         pha
1233         lda     $1,x
1234         tay
1235         pla
1236         tax
1237         tya                     ; x/a - arg1 (a=high)
1238
1239         sec
1240         sbc     TEMP2
1241         bne     @L4
1242         cpx     TEMP
1243         beq     @L3
1244         adc     #$ff
1245         ora     #$01
1246 @L3:    rts
1247 @L4:    bvc     @L3
1248         eor     #$ff
1249         ora     #$01
1250         rts
1251
1252 ;-------------
1253 ; VDC helpers
1254
1255 VDCSetSourceAddr:
1256         pha
1257         tya
1258         ldx     #VDC_DATA_HI
1259         jsr     VDCWriteReg
1260         pla
1261         ldx     #VDC_DATA_LO
1262         bne     VDCWriteReg
1263
1264 VDCReadByte:
1265         ldx     #VDC_DATA
1266 VDCReadReg:
1267         stx     VDC_ADDR_REG
1268 @L0:    bit     VDC_ADDR_REG
1269         bpl     @L0
1270         lda     VDC_DATA_REG
1271         rts
1272
1273 VDCWriteByte:
1274         ldx     #VDC_DATA
1275 VDCWriteReg:
1276         stx     VDC_ADDR_REG
1277 @L0:    bit     VDC_ADDR_REG
1278         bpl     @L0
1279         sta     VDC_DATA_REG
1280         rts
1281