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