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