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