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