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