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