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