]> git.sur5r.net Git - cc65/blob - libsrc/c128/c128-640-200-2.s
Added the IRQ entry
[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 AY:              .res   1
145
146 ; Text output stuff
147 TEXTMAGX:       .res    1
148 TEXTMAGY:       .res    1
149 TEXTDIR:        .res    1
150
151 ; Constants and tables
152
153 .rodata
154
155 DEFPALETTE:     .byte   $00, $0f        ; White on black
156 PALETTESIZE     = * - DEFPALETTE
157
158 BITTAB:         .byte   $80,$40,$20,$10,$08,$04,$02,$01
159
160 BITMASKL:       .byte   %11111111, %01111111, %00111111, %00011111
161                 .byte   %00001111, %00000111, %00000011, %00000001
162
163 BITMASKR:       .byte   %10000000, %11000000, %11100000, %11110000
164                 .byte   %11111000, %11111100, %11111110, %11111111
165
166 ; color translation table (indexed by VIC color)
167 COLTRANS:       .byte $00, $0f, $08, $06, $0a, $04, $02, $0c
168                 .byte $0d, $0b, $09, $01, $0e, $05, $03, $07
169                 ; colors BROWN and GRAY3 are wrong
170
171 ; VDC initialization table (reg),(val),...,$ff
172 InitVDCTab:
173                 .byte VDC_DSP_HI, 0             ; viewpage 0 as default
174                 .byte VDC_DSP_LO, 0
175                 .byte VDC_HSCROLL, $87
176                 .byte $ff
177
178 SCN80CLR:       .byte 27,88,147,27,88,0
179
180 .code
181
182 ; ------------------------------------------------------------------------
183 ; INSTALL routine. Is called after the driver is loaded into memory. May
184 ; initialize anything that has to be done just once. Is probably empty
185 ; most of the time.
186 ;
187 ; Must set an error code: NO
188 ;
189
190 INSTALL:
191         ; check for VDC version and update register $19 value
192
193         ; check for VDC ram size and update number of available screens
194
195         ldx     #VDC_CSET       ; determine size of RAM...
196         jsr     VDCReadReg
197         sta     tmp1
198         ora     #%00010000
199         jsr     VDCWriteReg     ; turn on 64k
200
201         jsr     settestadr1     ; save original value of test byte
202         jsr     VDCReadByte
203         sta     tmp2
204
205         lda     #$55            ; write $55 here
206         ldy     #ptr1
207         jsr     test64k         ; read it here and there
208         lda     #$aa            ; write $aa here
209         ldy     #ptr2
210         jsr     test64k         ; read it here and there
211
212         jsr     settestadr1
213         lda     tmp2
214         jsr     VDCWriteByte    ; restore original value of test byte
215
216         lda     ptr1            ; do bytes match?
217         cmp     ptr1+1
218         bne     @have64k
219         lda     ptr2
220         cmp     ptr2+1
221         bne     @have64k
222
223         ldx     #VDC_CSET
224         lda     tmp1
225         jsr     VDCWriteReg     ; restore 16/64k flag
226         jmp     @endok          ; and leave default values for 16k
227
228 @have64k:
229         lda     #4
230         sta     pages
231 @endok:
232         lda     #0
233         sta     SCRBASE         ; draw page 0 as default
234         rts
235
236 test64k:
237         sta     tmp1
238         sty     ptr3
239         lda     #0
240         sta     ptr3+1
241         jsr     settestadr1
242         lda     tmp1
243         jsr     VDCWriteByte            ; write $55
244         jsr     settestadr1
245         jsr     VDCReadByte             ; read here
246         pha
247         jsr     settestadr2
248         jsr     VDCReadByte             ; and there
249         ldy     #1
250         sta     (ptr3),y
251         pla
252         dey
253         sta     (ptr3),y
254         rts
255
256 settestadr1:
257         ldy     #$02                    ; test page 2 (here)
258         .byte   $2c
259 settestadr2:
260         ldy     #$42                    ; or page 64+2 (there)
261         lda     #0
262         jmp     VDCSetSourceAddr
263
264 ; ------------------------------------------------------------------------
265 ; UNINSTALL routine. Is called before the driver is removed from memory. May
266 ; clean up anything done by INSTALL but is probably empty most of the time.
267 ;
268 ; Must set an error code: NO
269 ;
270
271 UNINSTALL:
272         rts
273
274
275 ; ------------------------------------------------------------------------
276 ; INIT: Changes an already installed device from text mode to graphics
277 ; mode.
278 ; Note that INIT/DONE may be called multiple times while the driver
279 ; is loaded, while INSTALL is only called once, so any code that is needed
280 ; to initializes variables and so on must go here. Setting palette and
281 ; clearing the screen is not needed because this is called by the graphics
282 ; kernel later.
283 ; The graphics kernel will never call INIT when a graphics mode is already
284 ; active, so there is no need to protect against that.
285 ;
286 ; Must set an error code: YES
287 ;
288
289 INIT:
290
291 ; Initialize variables
292
293 @L1:    ldx     #$FF
294         stx     BITMASK
295
296 ; Remeber current color value
297         ldx     #VDC_COLORS
298         jsr     VDCReadReg
299         sta     OLDCOLOR
300
301 ; Switch into graphics mode (set view page 0)
302
303         ldy     #0
304 @L2:    ldx     InitVDCTab,y
305         bmi     @L3
306         iny
307         lda     InitVDCTab,y
308         jsr     VDCWriteReg
309         iny
310         bne     @L2
311 @L3:
312
313 ; Done, reset the error code
314
315         lda     #TGI_ERR_OK
316         sta     ERROR
317         rts
318
319 ; ------------------------------------------------------------------------
320 ; DONE: Will be called to switch the graphics device back into text mode.
321 ; The graphics kernel will never call DONE when no graphics mode is active,
322 ; so there is no need to protect against that.
323 ;
324 ; Must set an error code: NO
325 ;
326
327 DONE:
328         ; This part is C128-mode specific
329         jsr $e179               ; reload character set and setup VDC
330         jsr $ff62
331         lda $d7                 ; in 80-columns?
332         bne @L01
333 @L0:    lda SCN80CLR,y
334         beq @L1
335         jsr $ffd2               ; print \xe,clr,\xe
336         iny
337         bne @L0
338 @L01:   lda #147
339         jsr $ffd2               ; print clr
340 @L1:    lda #0                  ; restore view page
341         ldx #VDC_DSP_HI
342         jsr VDCWriteReg
343         lda OLDCOLOR
344         ldx #VDC_COLORS
345         jsr VDCWriteReg         ; restore color (background)
346         lda #$47
347         ldx #VDC_HSCROLL
348         jmp VDCWriteReg         ; switch to text screen
349
350 ; ------------------------------------------------------------------------
351 ; GETERROR: Return the error code in A and clear it.
352
353 GETERROR:
354         ldx     #TGI_ERR_OK
355         lda     ERROR
356         stx     ERROR
357         rts
358
359 ; ------------------------------------------------------------------------
360 ; CONTROL: Platform/driver specific entry point.
361 ;
362 ; Must set an error code: YES
363 ;
364
365 CONTROL:
366         lda     #TGI_ERR_INV_FUNC
367         sta     ERROR
368         rts
369
370 ; ------------------------------------------------------------------------
371 ; CLEAR: Clears the screen.
372 ;
373 ; Must set an error code: NO
374 ;
375
376 CLEAR:
377         lda     #0
378         ldy     SCRBASE
379         jsr     VDCSetSourceAddr
380         lda     #0
381         ldx     #VDC_VSCROLL
382         jsr     VDCWriteReg                     ; set fill mode
383         lda     #0
384         jsr     VDCWriteByte                    ; put 1rst byte (fill value)
385         ldy     #62                             ; 62 times
386         lda     #0                              ; 256 bytes
387         ldx     #VDC_COUNT
388 @L1:    jsr     VDCWriteReg
389         dey
390         bne     @L1
391         lda     #127
392         jmp     VDCWriteReg                     ; 1+62*256+127=16000=(640*256)/8
393
394 ; ------------------------------------------------------------------------
395 ; SETVIEWPAGE: Set the visible page. Called with the new page in A (0..n).
396 ; The page number is already checked to be valid by the graphics kernel.
397 ;
398 ; Must set an error code: NO (will only be called if page ok)
399 ;
400
401 SETVIEWPAGE:
402         clc
403         ror
404         ror
405         ror
406         ldx     #VDC_DSP_HI
407         jmp     VDCWriteReg
408
409 ; ------------------------------------------------------------------------
410 ; SETDRAWPAGE: Set the drawable page. Called with the new page in A (0..n).
411 ; The page number is already checked to be valid by the graphics kernel.
412 ;
413 ; Must set an error code: NO (will only be called if page ok)
414 ;
415
416 SETDRAWPAGE:
417         clc
418         ror
419         ror
420         ror
421         sta     SCRBASE
422         rts
423
424 ; ------------------------------------------------------------------------
425 ; SETCOLOR: Set the drawing color (in A). The new color is already checked
426 ; to be in a valid range (0..maxcolor-1).
427 ;
428 ; Must set an error code: NO (will only be called if color ok)
429 ;
430
431 SETCOLOR:
432         tax
433         beq     @L1
434         lda     #$FF
435 @L1:    sta     BITMASK
436         rts
437
438 ; ------------------------------------------------------------------------
439 ; SETPALETTE: Set the palette (not available with all drivers/hardware).
440 ; A pointer to the palette is passed in ptr1. Must set an error if palettes
441 ; are not supported
442 ;
443 ; Must set an error code: YES
444 ;
445
446 SETPALETTE:
447         ldy     #PALETTESIZE - 1
448 @L1:    lda     (ptr1),y        ; Copy the palette
449         and     #$0F            ; Make a valid color
450         sta     PALETTE,y
451         dey
452         bpl     @L1
453
454 ; Get the color entries from the palette
455
456         ldy     PALETTE+1       ; Foreground color
457         lda     COLTRANS,y
458         asl     a
459         asl     a
460         asl     a
461         asl     a
462         ldy     PALETTE         ; Background color
463         ora     COLTRANS,y
464
465         ldx     #VDC_COLORS
466         jsr     VDCWriteReg     ; Clear error code
467         lda     #TGI_ERR_OK
468         sta     ERROR
469         rts
470
471 ; ------------------------------------------------------------------------
472 ; GETPALETTE: Return the current palette in A/X. Even drivers that cannot
473 ; set the palette should return the default palette here, so there's no
474 ; way for this function to fail.
475 ;
476 ; Must set an error code: NO
477 ;
478
479 GETPALETTE:
480         lda     #<PALETTE
481         ldx     #>PALETTE
482         rts
483
484 ; ------------------------------------------------------------------------
485 ; GETDEFPALETTE: Return the default palette for the driver in A/X. All
486 ; drivers should return something reasonable here, even drivers that don't
487 ; support palettes, otherwise the caller has no way to determine the colors
488 ; of the (not changeable) palette.
489 ;
490 ; Must set an error code: NO (all drivers must have a default palette)
491 ;
492
493 GETDEFPALETTE:
494         lda     #<DEFPALETTE
495         ldx     #>DEFPALETTE
496         rts
497
498 ; ------------------------------------------------------------------------
499 ; SETPIXEL: Draw one pixel at X1/Y1 = ptr1/ptr2 with the current drawing
500 ; color. The coordinates passed to this function are never outside the
501 ; visible screen area, so there is no need for clipping inside this function.
502 ;
503 ; Must set an error code: NO
504 ;
505
506 SETPIXELCLIP:
507         lda     Y1+1
508         bmi     @finito         ; y<0
509         lda     X1+1
510         bmi     @finito         ; x<0
511         lda     xres
512         ldx     xres+1
513         sta     ADDR
514         stx     ADDR+1
515         ldx     #ADDR
516         lda     X1
517         ldy     X1+1
518         jsr     icmp            ; if (xres<x1)
519         bcs     @cont           ; !(xres<x1)
520 @finito:rts
521 @cont:  lda     yres
522         ldx     yres+1
523         sta     ADDR
524         stx     ADDR+1
525         ldx     #ADDR
526         lda     Y1
527         ldy     Y1+1
528         jsr     icmp            ; if (yres<y1)
529         bcc     @finito
530
531 SETPIXEL:
532         jsr     CALC            ; Calculate coordinates
533
534         stx     TEMP
535         lda     ADDR
536         ldy     ADDR+1
537         jsr     VDCSetSourceAddr
538         jsr     VDCReadByte
539         ldx     TEMP
540
541         sta     TEMP
542         eor     BITMASK
543         and     BITTAB,X
544         eor     TEMP
545         pha
546         lda     ADDR
547         ldy     ADDR+1
548         jsr     VDCSetSourceAddr
549         pla
550         jsr     VDCWriteByte
551
552 @L9:    rts
553
554 ; ------------------------------------------------------------------------
555 ; GETPIXEL: Read the color value of a pixel and return it in A/X. The
556 ; coordinates passed to this function are never outside the visible screen
557 ; area, so there is no need for clipping inside this function.
558
559
560 GETPIXEL:
561         jsr     CALC            ; Calculate coordinates
562
563         stx     TEMP            ; preserve X
564         lda     ADDR
565         ldy     ADDR+1
566         jsr     VDCSetSourceAddr
567         jsr     VDCReadByte
568         ldx     TEMP
569
570         ldy     #$00
571         and     BITTAB,X
572         beq     @L1
573         iny
574
575 @L1:    tya                     ; Get color value into A
576         ldx     #$00            ; Clear high byte
577         rts
578
579 ; ------------------------------------------------------------------------
580 ; LINE: Draw a line from X1/Y1 to X2/Y2, where X1/Y1 = ptr1/ptr2 and
581 ; X2/Y2 = ptr3/ptr4 using the current drawing color.
582 ;
583 ; Must set an error code: NO
584 ;
585
586 LINE:
587         ; nx = abs(x2 - x1)
588         lda     X2
589         sec
590         sbc     X1
591         sta     NX
592         lda     X2+1
593         sbc     X1+1
594         tay
595         lda     NX
596         jsr     abs
597         sta     NX
598         sty     NX+1
599         ; ny = abs(y2 - y1)
600         lda     Y2
601         sec
602         sbc     Y1
603         sta     NY
604         lda     Y2+1
605         sbc     Y1+1
606         tay
607         lda     NY
608         jsr     abs
609         sta     NY
610         sty     NY+1
611         ; if (x2>=x1)
612         ldx     #X2
613         lda     X1
614         ldy     X1+1
615         jsr     icmp
616         bcc     @L0243
617         ; dx = 1;
618         lda     #1
619         bne     @L0244
620         ; else
621         ; dx = -1;
622 @L0243: lda     #$ff
623 @L0244: sta     DX
624         ; if (y2>=y1)
625         ldx     #Y2
626         lda     Y1
627         ldy     Y1+1
628         jsr     icmp
629         bcc     @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         cpy     #$00
1206         bpl     absend
1207         ; negay
1208 neg:    eor     #$ff
1209         add     #1
1210         pha
1211         tya
1212         eor     #$ff
1213         adc     #0
1214         tay
1215         pla
1216 absend: rts
1217
1218 icmp:
1219         ; compare a/y to zp,x
1220         sta     TEMP            ; TEMP/TEMP2 - arg2
1221         sty     TEMP2
1222         lda     $0,x
1223         pha
1224         lda     $1,x
1225         tay
1226         pla
1227         tax
1228         tya                     ; x/a - arg1 (a=high)
1229
1230         sec
1231         sbc     TEMP2
1232         bne     @L4
1233         cpx     TEMP
1234         beq     @L3
1235         adc     #$ff
1236         ora     #$01
1237 @L3:    rts
1238 @L4:    bvc     @L3
1239         eor     #$ff
1240         ora     #$01
1241         rts
1242
1243 ;-------------
1244 ; VDC helpers
1245
1246 VDCSetSourceAddr:
1247         pha
1248         tya
1249         ldx     #VDC_DATA_HI
1250         jsr     VDCWriteReg
1251         pla
1252         ldx     #VDC_DATA_LO
1253         bne     VDCWriteReg
1254
1255 VDCReadByte:
1256         ldx     #VDC_DATA
1257 VDCReadReg:
1258         stx     VDC_ADDR_REG
1259 @L0:    bit     VDC_ADDR_REG
1260         bpl     @L0
1261         lda     VDC_DATA_REG
1262         rts
1263
1264 VDCWriteByte:
1265         ldx     #VDC_DATA
1266 VDCWriteReg:
1267         stx     VDC_ADDR_REG
1268 @L0:    bit     VDC_ADDR_REG
1269         bpl     @L0
1270         sta     VDC_DATA_REG
1271         rts
1272