]> git.sur5r.net Git - cc65/blob - libsrc/c128/c128-640-480-2.s
Added the IRQ entry
[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         .addr   INSTALL
72         .addr   UNINSTALL
73         .addr   INIT
74         .addr   DONE
75         .addr   GETERROR
76         .addr   CONTROL
77         .addr   CLEAR
78         .addr   SETVIEWPAGE
79         .addr   SETDRAWPAGE
80         .addr   SETCOLOR
81         .addr   SETPALETTE
82         .addr   GETPALETTE
83         .addr   GETDEFPALETTE
84         .addr   SETPIXEL
85         .addr   GETPIXEL
86         .addr   LINE
87         .addr   BAR
88         .addr   CIRCLE
89         .addr   TEXTSTYLE
90         .addr   OUTTEXT
91         .addr   0                       ; IRQ entry is unused
92
93 ; ------------------------------------------------------------------------
94 ; Data.
95
96 ; Variables mapped to the zero page segment variables. Some of these are
97 ; used for passing parameters to the driver.
98
99 X1              = ptr1
100 Y1              = ptr2
101 X2              = ptr3
102 Y2              = ptr4
103 RADIUS          = tmp1
104
105 ADDR            = tmp1          ; (2)   CALC
106 TEMP            = tmp3          ;       CALC icmp
107 TEMP2           = tmp4          ;       icmp
108 TEMP3           = sreg          ;       LINE
109 TEMP4           = sreg+1        ;       LINE
110
111 ; Line routine stuff (must be on zpage)
112 PB              = ptr3          ; (2)   LINE
113 UB              = ptr4          ; (2)   LINE
114 ERR             = regsave       ; (2)   LINE
115 NX              = regsave+2     ; (2)   LINE
116 ; Circle stuff
117 XX              = ptr3          ; (2)   CIRCLE
118 YY              = ptr4          ; (2)   CIRCLE
119 MaxO            = sreg          ; (overwritten by TEMP3+TEMP4, but restored from OG/OU anyway)
120 XS              = regsave       ; (2)   CIRCLE
121 YS              = regsave+2     ; (2)   CIRCLE
122
123 ; Absolute variables used in the code
124
125 .bss
126
127 ERROR:          .res    1       ; Error code
128 PALETTE:        .res    2       ; The current palette
129
130 BITMASK:        .res    1       ; $00 = clear, $FF = set pixels
131
132 OLDCOLOR:       .res    1       ; colors before entering gfx mode
133
134 ; Line routine stuff (combined with CIRCLE to save space)
135
136 OGora:
137 COUNT:           .res   2
138 OUkos:
139 NY:              .res   2
140 Y3:
141 DX:              .res   1
142 DY:              .res   1
143 AY:              .res   1
144
145 ; Text output stuff
146 TEXTMAGX:       .res    1
147 TEXTMAGY:       .res    1
148 TEXTDIR:        .res    1
149
150 ; Constants and tables
151
152 .rodata
153
154 DEFPALETTE:     .byte   $00, $0f        ; White on black
155 PALETTESIZE     = * - DEFPALETTE
156
157 BITTAB:         .byte   $80,$40,$20,$10,$08,$04,$02,$01
158
159 BITMASKL:       .byte   %11111111, %01111111, %00111111, %00011111
160                 .byte   %00001111, %00000111, %00000011, %00000001
161
162 BITMASKR:       .byte   %10000000, %11000000, %11100000, %11110000
163                 .byte   %11111000, %11111100, %11111110, %11111111
164
165 ; color translation table (indexed by VIC color)
166 COLTRANS:       .byte $00, $0f, $08, $06, $0a, $04, $02, $0c
167                 .byte $0d, $0b, $09, $01, $0e, $05, $03, $07
168                 ; colors BROWN and GRAY3 are wrong
169
170 ; VDC initialization table (reg),(val),...,$ff
171 InitVDCTab:
172                 .byte VDC_DSP_HI, 0             ; viewpage 0 as default
173                 .byte VDC_DSP_LO, 0
174                 .byte VDC_HSCROLL, $87
175                 .byte 2, $66
176                 .byte 4, $4c
177                 .byte 5, $06
178                 .byte 6, $4c
179                 .byte 7, $47
180                 .byte 8, $03
181                 .byte 9, $06
182                 .byte 27, $00
183                 .byte $ff
184
185 SCN80CLR:       .byte 27,88,147,27,88,0
186
187 .code
188
189 ; ------------------------------------------------------------------------
190 ; INSTALL routine. Is called after the driver is loaded into memory. May
191 ; initialize anything that has to be done just once. Is probably empty
192 ; most of the time.
193 ;
194 ; Must set an error code: NO
195 ;
196
197 INSTALL:
198         ; check for VDC version and update register $19 value
199
200         ; check for VDC ram size and update number of available screens
201
202         ldx     #VDC_CSET       ; determine size of RAM...
203         jsr     VDCReadReg
204         sta     tmp1
205         ora     #%00010000
206         jsr     VDCWriteReg     ; turn on 64k
207
208         jsr     settestadr1     ; save original value of test byte
209         jsr     VDCReadByte
210         sta     tmp2
211
212         lda     #$55            ; write $55 here
213         ldy     #ptr1
214         jsr     test64k         ; read it here and there
215         lda     #$aa            ; write $aa here
216         ldy     #ptr2
217         jsr     test64k         ; read it here and there
218
219         jsr     settestadr1
220         lda     tmp2
221         jsr     VDCWriteByte    ; restore original value of test byte
222
223         lda     ptr1            ; do bytes match?
224         cmp     ptr1+1
225         bne     @have64k
226         lda     ptr2
227         cmp     ptr2+1
228         bne     @have64k
229
230         ldx     #VDC_CSET
231         lda     tmp1
232         jsr     VDCWriteReg     ; restore 16/64k flag
233         jmp     @endok          ; and leave default values for 16k
234
235 @have64k:
236         lda     #1
237         sta     pages
238 @endok:
239         rts
240
241 test64k:
242         sta     tmp1
243         sty     ptr3
244         lda     #0
245         sta     ptr3+1
246         jsr     settestadr1
247         lda     tmp1
248         jsr     VDCWriteByte            ; write $55
249         jsr     settestadr1
250         jsr     VDCReadByte             ; read here
251         pha
252         jsr     settestadr2
253         jsr     VDCReadByte             ; and there
254         ldy     #1
255         sta     (ptr3),y
256         pla
257         dey
258         sta     (ptr3),y
259         rts
260
261 settestadr1:
262         ldy     #$02                    ; test page 2 (here)
263         .byte   $2c
264 settestadr2:
265         ldy     #$42                    ; or page 64+2 (there)
266         lda     #0
267         jmp     VDCSetSourceAddr
268
269 ; ------------------------------------------------------------------------
270 ; UNINSTALL routine. Is called before the driver is removed from memory. May
271 ; clean up anything done by INSTALL but is probably empty most of the time.
272 ;
273 ; Must set an error code: NO
274 ;
275
276 UNINSTALL:
277         rts
278
279
280 ; ------------------------------------------------------------------------
281 ; INIT: Changes an already installed device from text mode to graphics
282 ; mode.
283 ; Note that INIT/DONE may be called multiple times while the driver
284 ; is loaded, while INSTALL is only called once, so any code that is needed
285 ; to initializes variables and so on must go here. Setting palette and
286 ; clearing the screen is not needed because this is called by the graphics
287 ; kernel later.
288 ; The graphics kernel will never call INIT when a graphics mode is already
289 ; active, so there is no need to protect against that.
290 ;
291 ; Must set an error code: YES
292 ;
293
294 INIT:
295         lda     pages                   ; is there enough memory?
296         bne     @L11                    ; Jump if there is one screen
297         lda     #TGI_ERR_INV_MODE       ; Error
298         bne     @L9
299
300 ; Initialize variables
301
302 @L11:   ldx     #$FF
303         stx     BITMASK
304
305 ; Remeber current color value
306         ldx     #VDC_COLORS
307         jsr     VDCReadReg
308         sta     OLDCOLOR
309
310 ; Switch into graphics mode (set view page 0)
311
312         ldy     #0
313 @L2:    ldx     InitVDCTab,y
314         bmi     @L3
315         iny
316         lda     InitVDCTab,y
317         jsr     VDCWriteReg
318         iny
319         bne     @L2
320 @L3:
321
322 ; Done, reset the error code
323
324         lda     #TGI_ERR_OK
325 @L9:    sta     ERROR
326         rts
327
328 ; ------------------------------------------------------------------------
329 ; DONE: Will be called to switch the graphics device back into text mode.
330 ; The graphics kernel will never call DONE when no graphics mode is active,
331 ; so there is no need to protect against that.
332 ;
333 ; Must set an error code: NO
334 ;
335
336 DONE:
337         ; This part is C128-mode specific
338         jsr $e179               ; reload character set and setup VDC
339         jsr $ff62
340         lda $d7                 ; in 80-columns?
341         bne @L01
342 @L0:    lda SCN80CLR,y
343         beq @L1
344         jsr $ffd2               ; print \xe,clr,\xe
345         iny
346         bne @L0
347 @L01:   lda #147
348         jsr $ffd2               ; print clr
349 @L1:    lda #0                  ; restore view page
350         ldx #VDC_DSP_HI
351         jsr VDCWriteReg
352         lda OLDCOLOR
353         ldx #VDC_COLORS
354         jsr VDCWriteReg         ; restore color (background)
355         lda #$47
356         ldx #VDC_HSCROLL
357         jmp VDCWriteReg         ; switch to text screen
358
359 ; ------------------------------------------------------------------------
360 ; GETERROR: Return the error code in A and clear it.
361
362 GETERROR:
363         ldx     #TGI_ERR_OK
364         lda     ERROR
365         stx     ERROR
366         rts
367
368 ; ------------------------------------------------------------------------
369 ; CONTROL: Platform/driver specific entry point.
370 ;
371 ; Must set an error code: YES
372 ;
373
374 CONTROL:
375         lda     #TGI_ERR_INV_FUNC
376         sta     ERROR
377         rts
378
379 ; ------------------------------------------------------------------------
380 ; CLEAR: Clears the screen.
381 ;
382 ; Must set an error code: NO
383 ;
384
385 CLEAR:
386         lda     #0
387         tay
388         jsr     VDCSetSourceAddr
389         lda     #0
390         ldx     #VDC_VSCROLL
391         jsr     VDCWriteReg                     ; set fill mode
392         lda     #0
393         jsr     VDCWriteByte                    ; put 1rst byte (fill value)
394         ldy     #159                            ; 159 times
395         lda     #0                              ; 256 bytes
396         ldx     #VDC_COUNT
397 @L1:    jsr     VDCWriteReg
398         dey
399         bne     @L1
400         rts
401
402 ; ------------------------------------------------------------------------
403 ; SETVIEWPAGE: Set the visible page. Called with the new page in A (0..n).
404 ; The page number is already checked to be valid by the graphics kernel.
405 ;
406 ; Must set an error code: NO (will only be called if page ok)
407 ;
408
409 SETVIEWPAGE:
410         rts
411
412 ; ------------------------------------------------------------------------
413 ; SETDRAWPAGE: Set the drawable page. Called with the new page in A (0..n).
414 ; The page number is already checked to be valid by the graphics kernel.
415 ;
416 ; Must set an error code: NO (will only be called if page ok)
417 ;
418
419 SETDRAWPAGE:
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
465         lda     #TGI_ERR_OK     ; Clear error code
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         ; dx = 1;
616         lda     #1
617         bne     @L0244
618         ; else
619         ; dx = -1;
620 @L0243: lda     #$ff
621 @L0244: sta     DX
622         ; if (y2>=y1)
623         ldx     #Y2
624         lda     Y1
625         ldy     Y1+1
626         jsr     icmp
627         bcc     @L024A
628         ; dy = 1;
629         lda     #1
630         bne     @L024B
631         ; else
632         ; dy = -1;
633 @L024A: lda     #$ff
634 @L024B: sta     DY
635         ; err = ay = 0;
636         lda     #0
637         sta     ERR
638         sta     ERR+1
639         sta     AY
640
641         ; if (nx<ny) {
642         ldx     #NX
643         lda     NY
644         ldy     NY+1
645         jsr     icmp
646         bcs     @L0255
647         ;  nx <-> ny
648         lda     NX
649         ldx     NY
650         sta     NY
651         stx     NX
652         lda     NX+1
653         ldx     NY+1
654         sta     NY+1
655         stx     NX+1
656         ; ay = dx
657         lda     DX
658         sta     AY
659         ; dx = dy = 0;
660         lda     #0
661         sta     DX
662         sta     DY
663         ; ny = - ny;
664 @L0255: lda     NY
665         ldy     NY+1
666         jsr     neg
667         sta     NY
668         sty     NY+1
669         ; for (count=nx;count>0;--count) {
670         lda     NX
671         ldx     NX+1
672         sta     COUNT
673         stx     COUNT+1
674 @L0166: lda     COUNT           ; count>0
675         ora     COUNT+1
676         bne     @L0167
677         rts
678         ;    setpixel(X1,Y1)
679 @L0167: jsr     SETPIXELCLIP
680         ;    pb = err + ny
681         lda     ERR
682         clc
683         adc     NY
684         sta     PB
685         lda     ERR+1
686         adc     NY+1
687         sta     PB+1
688         tax
689         ;    ub = pb + nx
690         lda     PB
691         clc
692         adc     NX
693         sta     UB
694         txa
695         adc     NX+1
696         sta     UB+1
697         ;    x1 = x1 + dx
698         ldx     #0
699         lda     DX
700         bpl     @L027B
701         dex
702 @L027B: clc
703         adc     X1
704         sta     X1
705         txa
706         adc     X1+1
707         sta     X1+1
708         ;   y1 = y1 + ay
709         ldx     #0
710         lda     AY
711         bpl     @L027E
712         dex
713 @L027E: clc
714         adc     Y1
715         sta     Y1
716         txa
717         adc     Y1+1
718         sta     Y1+1
719         ; if (abs(pb)<abs(ub)) {
720         lda     PB
721         ldy     PB+1
722         jsr     abs
723         sta     TEMP3
724         sty     TEMP4
725         lda     UB
726         ldy     UB+1
727         jsr     abs
728         ldx     #TEMP3
729         jsr     icmp
730         bpl     @L027F
731         ;   err = pb
732         lda     PB
733         ldx     PB+1
734         jmp     @L0312
735         ; } else { x1 = x1 + ay
736 @L027F:
737         ldx     #0
738         lda     AY
739         bpl     @L0288
740         dex
741 @L0288: clc
742         adc     X1
743         sta     X1
744         txa
745         adc     X1+1
746         sta     X1+1
747         ;       y1 = y1 + dy
748         ldx     #0
749         lda     DY
750         bpl     @L028B
751         dex
752 @L028B: clc
753         adc     Y1
754         sta     Y1
755         txa
756         adc     Y1+1
757         sta     Y1+1
758         ;       err = ub }
759         lda     UB
760         ldx     UB+1
761 @L0312:
762         sta     ERR
763         stx     ERR+1
764         ; } (--count)
765         sec
766         lda     COUNT
767         sbc     #1
768         sta     COUNT
769         bcc     @L0260
770         jmp     @L0166
771 @L0260: dec     COUNT+1
772         jmp     @L0166
773
774 ; ------------------------------------------------------------------------
775 ; BAR: Draw a filled rectangle with the corners X1/Y1, X2/Y2, where
776 ; X1/Y1 = ptr1/ptr2 and X2/Y2 = ptr3/ptr4 using the current drawing color.
777 ; Contrary to most other functions, the graphics kernel will sort and clip
778 ; the coordinates before calling the driver, so on entry the following
779 ; conditions are valid:
780 ;       X1 <= X2
781 ;       Y1 <= Y2
782 ;       (X1 >= 0) && (X1 < XRES)
783 ;       (X2 >= 0) && (X2 < XRES)
784 ;       (Y1 >= 0) && (Y1 < YRES)
785 ;       (Y2 >= 0) && (Y2 < YRES)
786 ;
787 ; Must set an error code: NO
788 ;
789
790 BAR:
791         inc     Y2
792         bne     HORLINE
793         inc     Y2+1
794
795 ; Original code for a horizontal line
796
797 HORLINE:
798         lda X1
799         pha
800         lda X1+1
801         pha
802         jsr CALC                ; get data for LEFT
803         lda BITMASKL,x          ; remember left address and bitmask
804         pha
805         lda ADDR
806         pha
807         lda ADDR+1
808         pha
809
810         lda X2
811         sta X1
812         lda X2+1
813         sta X1+1
814         jsr CALC                ; get data for RIGHT
815         lda BITMASKR,x
816         sta TEMP3
817
818         pla                     ; recall data for LEFT
819         sta X1+1
820         pla
821         sta X1                  ; put left address into X1
822         pla
823
824         cmp #%11111111          ; if left bit <> 0
825         beq @L1
826         sta TEMP2               ; do left byte only...
827         lda X1
828         ldy X1+1
829         jsr VDCSetSourceAddr
830         jsr VDCReadByte
831         sta TEMP
832         eor BITMASK
833         and TEMP2
834         eor TEMP
835         pha
836         lda X1
837         ldy X1+1
838         jsr VDCSetSourceAddr
839         pla
840         jsr VDCWriteByte
841         inc X1                  ; ... and proceed
842         bne @L1
843         inc X1+1
844
845         ; do right byte (if Y2=0 ++ADDR and skip)
846 @L1:    lda TEMP3
847         cmp #%11111111          ; if right bit <> 7
848         bne @L11
849         inc ADDR                ; right bit = 7 - the next one is the last
850         bne @L10
851         inc ADDR+1
852 @L10:   bne @L2
853
854 @L11:   lda ADDR                ; do right byte only...
855         ldy ADDR+1
856         jsr VDCSetSourceAddr
857         jsr VDCReadByte
858         sta TEMP
859         eor BITMASK
860         and TEMP3
861         eor TEMP
862         pha
863         lda ADDR
864         ldy ADDR+1
865         jsr VDCSetSourceAddr
866         pla
867         jsr VDCWriteByte
868
869 @L2:                            ; do the fill in the middle
870         lda ADDR                ; calculate offset in full bytes
871         sec
872         sbc X1
873         beq @L3                 ; if equal - there are no more bytes
874         sta ADDR
875
876         lda X1                  ; setup for the left side
877         ldy X1+1
878         jsr VDCSetSourceAddr
879         lda BITMASK             ; get color
880         jsr VDCWriteByte        ; put 1st value
881         ldx ADDR
882         dex
883         beq @L3                 ; 1 byte already written
884
885         stx ADDR                ; if there are more bytes - fill them...
886         ldx #VDC_VSCROLL
887         lda #0
888         jsr VDCWriteReg         ; setup for fill
889         ldx #VDC_COUNT
890         lda ADDR
891         jsr VDCWriteReg         ; ... fill them NOW!
892
893 @L3:    pla
894         sta X1+1
895         pla
896         sta X1
897
898 ; End of horizontal line code
899
900         inc     Y1
901         bne     @L4
902         inc     Y1+1
903 @L4:    lda     Y1
904         cmp     Y2
905         bne     @L5
906         lda     Y1+1
907         cmp     Y2+1
908         bne     @L5
909         rts
910
911 @L5:    jmp     HORLINE
912
913
914 ; ------------------------------------------------------------------------
915 ; CIRCLE: Draw a circle around the center X1/Y1 (= ptr1/ptr2) with the
916 ; radius in tmp1 and the current drawing color.
917 ;
918 ; Must set an error code: NO
919 ;
920
921 CIRCLE:
922         lda     RADIUS
923         bne     @L1
924         jmp     SETPIXELCLIP    ; Plot as a point
925
926 @L1:    sta     XX
927         ; x = r;
928         lda     #0
929         sta     XX+1
930         sta     YY
931         sta     YY+1
932         sta     MaxO
933         sta     MaxO+1
934         ; y =0; mo=0;
935         lda     X1
936         ldx     X1+1
937         sta     XS
938         stx     XS+1
939         lda     Y1
940         ldx     Y1+1
941         sta     YS
942         stx     YS+1            ; XS/YS to remember the center
943
944         ; while (y<x) {
945 @L013B: ldx     #YY
946         lda     XX
947         ldy     XX+1
948         jsr     icmp
949         bcc     @L12
950         rts
951 @L12:   ; plot points in 8 slices...
952         lda     XS
953         clc
954         adc     XX
955         sta     X1
956         lda     XS+1
957         adc     XX+1
958         sta     X1+1            ; x1 = xs+x
959         lda     YS
960         clc
961         adc     YY
962         sta     Y1
963         pha
964         lda     YS+1
965         adc     YY+1
966         sta     Y1+1            ; (stack)=ys+y, y1=(stack)
967         pha
968         jsr     SETPIXELCLIP    ; plot(xs+x,ys+y)
969         lda     YS
970         sec
971         sbc     YY
972         sta     Y1
973         sta     Y3
974         lda     YS+1
975         sbc     YY+1
976         sta     Y1+1            ; y3 = y1 = ys-y
977         sta     Y3+1
978         jsr     SETPIXELCLIP    ; plot(xs+x,ys-y)
979         pla
980         sta     Y1+1
981         pla
982         sta     Y1              ; y1 = ys+y
983         lda     XS
984         sec
985         sbc     XX
986         sta     X1
987         lda     XS+1
988         sbc     XX+1
989         sta     X1+1
990         jsr     SETPIXELCLIP    ; plot (xs-x,ys+y)
991         lda     Y3
992         sta     Y1
993         lda     Y3+1
994         sta     Y1+1
995         jsr     SETPIXELCLIP    ; plot (xs-x,ys-y)
996
997         lda     XS
998         clc
999         adc     YY
1000         sta     X1
1001         lda     XS+1
1002         adc     YY+1
1003         sta     X1+1            ; x1 = xs+y
1004         lda     YS
1005         clc
1006         adc     XX
1007         sta     Y1
1008         pha
1009         lda     YS+1
1010         adc     XX+1
1011         sta     Y1+1            ; (stack)=ys+x, y1=(stack)
1012         pha
1013         jsr     SETPIXELCLIP    ; plot(xs+y,ys+x)
1014         lda     YS
1015         sec
1016         sbc     XX
1017         sta     Y1
1018         sta     Y3
1019         lda     YS+1
1020         sbc     XX+1
1021         sta     Y1+1            ; y3 = y1 = ys-x
1022         sta     Y3+1
1023         jsr     SETPIXELCLIP    ; plot(xs+y,ys-x)
1024         pla
1025         sta     Y1+1
1026         pla
1027         sta     Y1              ; y1 = ys+x(stack)
1028         lda     XS
1029         sec
1030         sbc     YY
1031         sta     X1
1032         lda     XS+1
1033         sbc     YY+1
1034         sta     X1+1
1035         jsr     SETPIXELCLIP    ; plot (xs-y,ys+x)
1036         lda     Y3
1037         sta     Y1
1038         lda     Y3+1
1039         sta     Y1+1
1040         jsr     SETPIXELCLIP    ; plot (xs-y,ys-x)
1041
1042         ; og = mo+y+y+1
1043         lda     MaxO
1044         ldx     MaxO+1
1045         clc
1046         adc     YY
1047         tay
1048         txa
1049         adc     YY+1
1050         tax
1051         tya
1052         clc
1053         adc     YY
1054         tay
1055         txa
1056         adc     YY+1
1057         tax
1058         tya
1059         clc
1060         adc     #1
1061         bcc     @L0143
1062         inx
1063 @L0143: sta     OGora
1064         stx     OGora+1
1065         ; ou = og-x-x+1
1066         sec
1067         sbc     XX
1068         tay
1069         txa
1070         sbc     XX+1
1071         tax
1072         tya
1073         sec
1074         sbc     XX
1075         tay
1076         txa
1077         sbc     XX+1
1078         tax
1079         tya
1080         clc
1081         adc     #1
1082         bcc     @L0146
1083         inx
1084 @L0146: sta     OUkos
1085         stx     OUkos+1
1086         ; ++y
1087         inc     YY
1088         bne     @L0148
1089         inc     YY+1
1090 @L0148: ; if (abs(ou)<abs(og))
1091         lda     OUkos
1092         ldy     OUkos+1
1093         jsr     abs
1094         sta     TEMP3
1095         sty     TEMP4
1096         lda     OGora
1097         ldy     OGora+1
1098         jsr     abs
1099         ldx     #TEMP3
1100         jsr     icmp
1101         bpl     @L0149
1102         ; { --x;
1103         sec
1104         lda     XX
1105         sbc     #1
1106         sta     XX
1107         bcs     @L014E
1108         dec     XX+1
1109 @L014E: ; mo = ou; }
1110         lda     OUkos
1111         ldx     OUkos+1
1112         jmp     @L014G
1113         ; else { mo = og }
1114 @L0149: lda     OGora
1115         ldx     OGora+1
1116 @L014G: sta     MaxO
1117         stx     MaxO+1
1118         ; }
1119         jmp     @L013B
1120
1121 ; ------------------------------------------------------------------------
1122 ; TEXTSTYLE: Set the style used when calling OUTTEXT. Text scaling in X and Y
1123 ; direction is passend in X/Y, the text direction is passed in A.
1124 ;
1125 ; Must set an error code: NO
1126 ;
1127
1128 TEXTSTYLE:
1129         stx     TEXTMAGX
1130         sty     TEXTMAGY
1131         sta     TEXTDIR
1132         rts
1133
1134
1135 ; ------------------------------------------------------------------------
1136 ; OUTTEXT: Output text at X/Y = ptr1/ptr2 using the current color and the
1137 ; current text style. The text to output is given as a zero terminated
1138 ; string with address in ptr3.
1139 ;
1140 ; Must set an error code: NO
1141 ;
1142
1143 OUTTEXT:
1144         rts
1145
1146 ; ------------------------------------------------------------------------
1147 ; Calculate all variables to plot the pixel at X1/Y1.
1148 ;------------------------
1149 ;< X1,Y1 - pixel
1150 ;> ADDR - address of card
1151 ;> X - bit number (X1 & 7)
1152 CALC:
1153         lda     Y1
1154         pha
1155         lda     Y1+1
1156         pha
1157         lsr
1158         ror     Y1              ; Y=Y/2
1159         sta     Y1+1
1160         sta     ADDR+1
1161         lda     Y1
1162         asl
1163         rol     ADDR+1
1164         asl
1165         rol     ADDR+1          ; Y*4
1166         clc
1167         adc     Y1
1168         sta     ADDR
1169         lda     Y1+1
1170         adc     ADDR+1
1171         sta     ADDR+1          ; Y*4+Y=Y*5
1172         lda     ADDR
1173         asl
1174         rol     ADDR+1
1175         asl
1176         rol     ADDR+1
1177         asl
1178         rol     ADDR+1
1179         asl
1180         rol     ADDR+1
1181         sta     ADDR            ; Y*5*16=Y*80
1182         lda     X1+1
1183         sta     TEMP
1184         lda     X1
1185         lsr     TEMP
1186         ror
1187         lsr     TEMP
1188         ror
1189         lsr     TEMP
1190         ror
1191         clc
1192         adc     ADDR
1193         sta     ADDR
1194         lda     ADDR+1          ; ADDR = Y*80+x/8
1195         adc     TEMP
1196         sta     ADDR+1
1197         pla
1198         sta     Y1+1
1199         pla
1200         sta     Y1
1201         and     #1
1202         beq     @even           ; even line - no offset
1203         lda     ADDR
1204         clc
1205         adc     #<21360
1206         sta     ADDR
1207         lda     ADDR+1
1208         adc     #>21360
1209         sta     ADDR+1          ; odd lines are 21360 bytes farther
1210 @even:  lda     X1
1211         and     #7
1212         tax
1213         rts
1214
1215 ;-------------
1216 ; copies of some runtime routines
1217
1218 abs:
1219         ; a/y := abs(a/y)
1220         cpy     #$00
1221         bpl     absend
1222         ; negay
1223 neg:    eor     #$ff
1224         add     #1
1225         pha
1226         tya
1227         eor     #$ff
1228         adc     #0
1229         tay
1230         pla
1231 absend: rts
1232
1233 icmp:
1234         ; compare a/y to zp,x
1235         sta     TEMP            ; TEMP/TEMP2 - arg2
1236         sty     TEMP2
1237         lda     $0,x
1238         pha
1239         lda     $1,x
1240         tay
1241         pla
1242         tax
1243         tya                     ; x/a - arg1 (a=high)
1244
1245         sec
1246         sbc     TEMP2
1247         bne     @L4
1248         cpx     TEMP
1249         beq     @L3
1250         adc     #$ff
1251         ora     #$01
1252 @L3:    rts
1253 @L4:    bvc     @L3
1254         eor     #$ff
1255         ora     #$01
1256         rts
1257
1258 ;-------------
1259 ; VDC helpers
1260
1261 VDCSetSourceAddr:
1262         pha
1263         tya
1264         ldx     #VDC_DATA_HI
1265         jsr     VDCWriteReg
1266         pla
1267         ldx     #VDC_DATA_LO
1268         bne     VDCWriteReg
1269
1270 VDCReadByte:
1271         ldx     #VDC_DATA
1272 VDCReadReg:
1273         stx     VDC_ADDR_REG
1274 @L0:    bit     VDC_ADDR_REG
1275         bpl     @L0
1276         lda     VDC_DATA_REG
1277         rts
1278
1279 VDCWriteByte:
1280         ldx     #VDC_DATA
1281 VDCWriteReg:
1282         stx     VDC_ADDR_REG
1283 @L0:    bit     VDC_ADDR_REG
1284         bpl     @L0
1285         sta     VDC_DATA_REG
1286         rts
1287