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