]> git.sur5r.net Git - cc65/blob - libsrc/c128/c128-640-200-2.s
Comment fixes by Stefan Haubenthal
[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         .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 SCRBASE:        .res    1       ; High byte of screen base
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 $ff
176
177 SCN80CLR:       .byte 27,88,147,27,88,0
178
179 .code
180
181 ; ------------------------------------------------------------------------
182 ; INSTALL routine. Is called after the driver is loaded into memory. May
183 ; initialize anything that has to be done just once. Is probably empty
184 ; most of the time.
185 ;
186 ; Must set an error code: NO
187 ;
188
189 INSTALL:
190         ; check for VDC version and update register $19 value
191
192         ; check for VDC ram size and update number of available screens
193
194         ldx     #VDC_CSET       ; determine size of RAM...
195         jsr     VDCReadReg
196         sta     tmp1
197         ora     #%00010000
198         jsr     VDCWriteReg     ; turn on 64k
199
200         jsr     settestadr1     ; save original value of test byte
201         jsr     VDCReadByte
202         sta     tmp2
203
204         lda     #$55            ; write $55 here
205         ldy     #ptr1
206         jsr     test64k         ; read it here and there
207         lda     #$aa            ; write $aa here
208         ldy     #ptr2
209         jsr     test64k         ; read it here and there
210
211         jsr     settestadr1
212         lda     tmp2
213         jsr     VDCWriteByte    ; restore original value of test byte
214
215         lda     ptr1            ; do bytes match?
216         cmp     ptr1+1
217         bne     @have64k
218         lda     ptr2
219         cmp     ptr2+1
220         bne     @have64k
221
222         ldx     #VDC_CSET
223         lda     tmp1
224         jsr     VDCWriteReg     ; restore 16/64k flag
225         jmp     @endok          ; and leave default values for 16k
226
227 @have64k:
228         lda     #4
229         sta     pages
230 @endok:
231         lda     #0
232         sta     SCRBASE         ; draw page 0 as default
233         rts
234
235 test64k:
236         sta     tmp1
237         sty     ptr3
238         lda     #0
239         sta     ptr3+1
240         jsr     settestadr1
241         lda     tmp1
242         jsr     VDCWriteByte            ; write $55
243         jsr     settestadr1
244         jsr     VDCReadByte             ; read here
245         pha
246         jsr     settestadr2
247         jsr     VDCReadByte             ; and there
248         ldy     #1
249         sta     (ptr3),y
250         pla
251         dey
252         sta     (ptr3),y
253         rts
254
255 settestadr1:
256         ldy     #$02                    ; test page 2 (here)
257         .byte   $2c
258 settestadr2:
259         ldy     #$42                    ; or page 64+2 (there)
260         lda     #0
261         jmp     VDCSetSourceAddr
262
263 ; ------------------------------------------------------------------------
264 ; UNINSTALL routine. Is called before the driver is removed from memory. May
265 ; clean up anything done by INSTALL but is probably empty most of the time.
266 ;
267 ; Must set an error code: NO
268 ;
269
270 UNINSTALL:
271         rts
272
273
274 ; ------------------------------------------------------------------------
275 ; INIT: Changes an already installed device from text mode to graphics
276 ; mode.
277 ; Note that INIT/DONE may be called multiple times while the driver
278 ; is loaded, while INSTALL is only called once, so any code that is needed
279 ; to initializes variables and so on must go here. Setting palette and
280 ; clearing the screen is not needed because this is called by the graphics
281 ; kernel later.
282 ; The graphics kernel will never call INIT when a graphics mode is already
283 ; active, so there is no need to protect against that.
284 ;
285 ; Must set an error code: YES
286 ;
287
288 INIT:
289
290 ; Initialize variables
291
292 @L1:    ldx     #$FF
293         stx     BITMASK
294
295 ; Remeber current color value
296         ldx     #VDC_COLORS
297         jsr     VDCReadReg
298         sta     OLDCOLOR
299
300 ; Switch into graphics mode (set view page 0)
301
302         ldy     #0
303 @L2:    ldx     InitVDCTab,y
304         bmi     @L3
305         iny
306         lda     InitVDCTab,y
307         jsr     VDCWriteReg
308         iny
309         bne     @L2
310 @L3:
311
312 ; Done, reset the error code
313
314         lda     #TGI_ERR_OK
315         sta     ERROR
316         rts
317
318 ; ------------------------------------------------------------------------
319 ; DONE: Will be called to switch the graphics device back into text mode.
320 ; The graphics kernel will never call DONE when no graphics mode is active,
321 ; so there is no need to protect against that.
322 ;
323 ; Must set an error code: NO
324 ;
325
326 DONE:
327         ; This part is C128-mode specific
328         jsr $e179               ; reload character set and setup VDC
329         jsr $ff62
330         lda $d7                 ; in 80-columns?
331         bne @L01
332 @L0:    lda SCN80CLR,y
333         beq @L1
334         jsr $ffd2               ; print \xe,clr,\xe
335         iny
336         bne @L0
337 @L01:   lda #147
338         jsr $ffd2               ; print clr
339 @L1:    lda #0                  ; restore view page
340         ldx #VDC_DSP_HI
341         jsr VDCWriteReg
342         lda OLDCOLOR
343         ldx #VDC_COLORS
344         jsr VDCWriteReg         ; restore color (background)
345         lda #$47
346         ldx #VDC_HSCROLL
347         jmp VDCWriteReg         ; switch to text screen
348
349 ; ------------------------------------------------------------------------
350 ; GETERROR: Return the error code in A and clear it.
351
352 GETERROR:
353         ldx     #TGI_ERR_OK
354         lda     ERROR
355         stx     ERROR
356         rts
357
358 ; ------------------------------------------------------------------------
359 ; CONTROL: Platform/driver specific entry point.
360 ;
361 ; Must set an error code: YES
362 ;
363
364 CONTROL:
365         lda     #TGI_ERR_INV_FUNC
366         sta     ERROR
367         rts
368
369 ; ------------------------------------------------------------------------
370 ; CLEAR: Clears the screen.
371 ;
372 ; Must set an error code: NO
373 ;
374
375 CLEAR:
376         lda     #0
377         ldy     SCRBASE
378         jsr     VDCSetSourceAddr
379         lda     #0
380         ldx     #VDC_VSCROLL
381         jsr     VDCWriteReg                     ; set fill mode
382         lda     #0
383         jsr     VDCWriteByte                    ; put 1rst byte (fill value)
384         ldy     #62                             ; 62 times
385         lda     #0                              ; 256 bytes
386         ldx     #VDC_COUNT
387 @L1:    jsr     VDCWriteReg
388         dey
389         bne     @L1
390         lda     #127
391         jmp     VDCWriteReg                     ; 1+62*256+127=16000=(640*256)/8
392
393 ; ------------------------------------------------------------------------
394 ; SETVIEWPAGE: Set the visible page. Called with the new page in A (0..n).
395 ; The page number is already checked to be valid by the graphics kernel.
396 ;
397 ; Must set an error code: NO (will only be called if page ok)
398 ;
399
400 SETVIEWPAGE:
401         clc
402         ror
403         ror
404         ror
405         ldx     #VDC_DSP_HI
406         jmp     VDCWriteReg
407
408 ; ------------------------------------------------------------------------
409 ; SETDRAWPAGE: Set the drawable page. Called with the new page in A (0..n).
410 ; The page number is already checked to be valid by the graphics kernel.
411 ;
412 ; Must set an error code: NO (will only be called if page ok)
413 ;
414
415 SETDRAWPAGE:
416         clc
417         ror
418         ror
419         ror
420         sta     SCRBASE
421         rts
422
423 ; ------------------------------------------------------------------------
424 ; SETCOLOR: Set the drawing color (in A). The new color is already checked
425 ; to be in a valid range (0..maxcolor-1).
426 ;
427 ; Must set an error code: NO (will only be called if color ok)
428 ;
429
430 SETCOLOR:
431         tax
432         beq     @L1
433         lda     #$FF
434 @L1:    sta     BITMASK
435         rts
436
437 ; ------------------------------------------------------------------------
438 ; SETPALETTE: Set the palette (not available with all drivers/hardware).
439 ; A pointer to the palette is passed in ptr1. Must set an error if palettes
440 ; are not supported
441 ;
442 ; Must set an error code: YES
443 ;
444
445 SETPALETTE:
446         ldy     #PALETTESIZE - 1
447 @L1:    lda     (ptr1),y        ; Copy the palette
448         and     #$0F            ; Make a valid color
449         sta     PALETTE,y
450         dey
451         bpl     @L1
452
453 ; Get the color entries from the palette
454
455         ldy     PALETTE+1       ; Foreground color
456         lda     COLTRANS,y
457         asl     a
458         asl     a
459         asl     a
460         asl     a
461         ldy     PALETTE         ; Background color
462         ora     COLTRANS,y
463
464         ldx     #VDC_COLORS
465         jsr     VDCWriteReg     ; Clear error code
466         lda     #TGI_ERR_OK
467         sta     ERROR
468         rts
469
470 ; ------------------------------------------------------------------------
471 ; GETPALETTE: Return the current palette in A/X. Even drivers that cannot
472 ; set the palette should return the default palette here, so there's no
473 ; way for this function to fail.
474 ;
475 ; Must set an error code: NO
476 ;
477
478 GETPALETTE:
479         lda     #<PALETTE
480         ldx     #>PALETTE
481         rts
482
483 ; ------------------------------------------------------------------------
484 ; GETDEFPALETTE: Return the default palette for the driver in A/X. All
485 ; drivers should return something reasonable here, even drivers that don't
486 ; support palettes, otherwise the caller has no way to determine the colors
487 ; of the (not changeable) palette.
488 ;
489 ; Must set an error code: NO (all drivers must have a default palette)
490 ;
491
492 GETDEFPALETTE:
493         lda     #<DEFPALETTE
494         ldx     #>DEFPALETTE
495         rts
496
497 ; ------------------------------------------------------------------------
498 ; SETPIXEL: Draw one pixel at X1/Y1 = ptr1/ptr2 with the current drawing
499 ; color. The coordinates passed to this function are never outside the
500 ; visible screen area, so there is no need for clipping inside this function.
501 ;
502 ; Must set an error code: NO
503 ;
504
505 SETPIXELCLIP:
506         lda     Y1+1
507         bmi     @finito         ; y<0
508         lda     X1+1
509         bmi     @finito         ; x<0
510         lda     xres
511         ldx     xres+1
512         sta     ADDR
513         stx     ADDR+1
514         ldx     #ADDR
515         lda     X1
516         ldy     X1+1
517         jsr     icmp            ; if (xres<x1)
518         bcs     @cont           ; !(xres<x1)
519 @finito:rts
520 @cont:  lda     yres
521         ldx     yres+1
522         sta     ADDR
523         stx     ADDR+1
524         ldx     #ADDR
525         lda     Y1
526         ldy     Y1+1
527         jsr     icmp            ; if (yres<y1)
528         bcc     @finito
529
530 SETPIXEL:
531         jsr     CALC            ; Calculate coordinates
532
533         stx     TEMP
534         lda     ADDR
535         ldy     ADDR+1
536         jsr     VDCSetSourceAddr
537         jsr     VDCReadByte
538         ldx     TEMP
539
540         sta     TEMP
541         eor     BITMASK
542         and     BITTAB,X
543         eor     TEMP
544         pha
545         lda     ADDR
546         ldy     ADDR+1
547         jsr     VDCSetSourceAddr
548         pla
549         jsr     VDCWriteByte
550
551 @L9:    rts
552
553 ; ------------------------------------------------------------------------
554 ; GETPIXEL: Read the color value of a pixel and return it in A/X. The
555 ; coordinates passed to this function are never outside the visible screen
556 ; area, so there is no need for clipping inside this function.
557
558
559 GETPIXEL:
560         jsr     CALC            ; Calculate coordinates
561
562         stx     TEMP            ; preserve X
563         lda     ADDR
564         ldy     ADDR+1
565         jsr     VDCSetSourceAddr
566         jsr     VDCReadByte
567         ldx     TEMP
568
569         ldy     #$00
570         and     BITTAB,X
571         beq     @L1
572         iny
573
574 @L1:    tya                     ; Get color value into A
575         ldx     #$00            ; Clear high byte
576         rts
577
578 ; ------------------------------------------------------------------------
579 ; LINE: Draw a line from X1/Y1 to X2/Y2, where X1/Y1 = ptr1/ptr2 and
580 ; X2/Y2 = ptr3/ptr4 using the current drawing color.
581 ;
582 ; Must set an error code: NO
583 ;
584
585 LINE:
586         ; nx = abs(x2 - x1)
587         lda     X2
588         sec
589         sbc     X1
590         sta     NX
591         lda     X2+1
592         sbc     X1+1
593         tay
594         lda     NX
595         jsr     abs
596         sta     NX
597         sty     NX+1
598         ; ny = abs(y2 - y1)
599         lda     Y2
600         sec
601         sbc     Y1
602         sta     NY
603         lda     Y2+1
604         sbc     Y1+1
605         tay
606         lda     NY
607         jsr     abs
608         sta     NY
609         sty     NY+1
610         ; if (x2>=x1)
611         ldx     #X2
612         lda     X1
613         ldy     X1+1
614         jsr     icmp
615         bcc     @L0243
616         ; dx = 1;
617         lda     #1
618         bne     @L0244
619         ; else
620         ; dx = -1;
621 @L0243: lda     #$ff
622 @L0244: sta     DX
623         ; if (y2>=y1)
624         ldx     #Y2
625         lda     Y1
626         ldy     Y1+1
627         jsr     icmp
628         bcc     @L024A
629         ; dy = 1;
630         lda     #1
631         bne     @L024B
632         ; else
633         ; dy = -1;
634 @L024A: lda     #$ff
635 @L024B: sta     DY
636         ; err = ay = 0;
637         lda     #0
638         sta     ERR
639         sta     ERR+1
640         sta     AY
641
642         ; if (nx<ny) {
643         ldx     #NX
644         lda     NY
645         ldy     NY+1
646         jsr     icmp
647         bcs     @L0255
648         ;  nx <-> ny
649         lda     NX
650         ldx     NY
651         sta     NY
652         stx     NX
653         lda     NX+1
654         ldx     NY+1
655         sta     NY+1
656         stx     NX+1
657         ; ay = dx
658         lda     DX
659         sta     AY
660         ; dx = dy = 0;
661         lda     #0
662         sta     DX
663         sta     DY
664         ; ny = - ny;
665 @L0255: lda     NY
666         ldy     NY+1
667         jsr     neg
668         sta     NY
669         sty     NY+1
670         ; for (count=nx;count>0;--count) {
671         lda     NX
672         ldx     NX+1
673         sta     COUNT
674         stx     COUNT+1
675 @L0166: lda     COUNT           ; count>0
676         ora     COUNT+1
677         bne     @L0167
678         rts
679         ;    setpixel(X1,Y1)
680 @L0167: jsr     SETPIXELCLIP
681         ;    pb = err + ny
682         lda     ERR
683         clc
684         adc     NY
685         sta     PB
686         lda     ERR+1
687         adc     NY+1
688         sta     PB+1
689         tax
690         ;    ub = pb + nx
691         lda     PB
692         clc
693         adc     NX
694         sta     UB
695         txa
696         adc     NX+1
697         sta     UB+1
698         ;    x1 = x1 + dx
699         ldx     #0
700         lda     DX
701         bpl     @L027B
702         dex
703 @L027B: clc
704         adc     X1
705         sta     X1
706         txa
707         adc     X1+1
708         sta     X1+1
709         ;   y1 = y1 + ay
710         ldx     #0
711         lda     AY
712         bpl     @L027E
713         dex
714 @L027E: clc
715         adc     Y1
716         sta     Y1
717         txa
718         adc     Y1+1
719         sta     Y1+1
720         ; if (abs(pb)<abs(ub)) {
721         lda     PB
722         ldy     PB+1
723         jsr     abs
724         sta     TEMP3
725         sty     TEMP4
726         lda     UB
727         ldy     UB+1
728         jsr     abs
729         ldx     #TEMP3
730         jsr     icmp
731         bpl     @L027F
732         ;   err = pb
733         lda     PB
734         ldx     PB+1
735         jmp     @L0312
736         ; } else { x1 = x1 + ay
737 @L027F:
738         ldx     #0
739         lda     AY
740         bpl     @L0288
741         dex
742 @L0288: clc
743         adc     X1
744         sta     X1
745         txa
746         adc     X1+1
747         sta     X1+1
748         ;       y1 = y1 + dy
749         ldx     #0
750         lda     DY
751         bpl     @L028B
752         dex
753 @L028B: clc
754         adc     Y1
755         sta     Y1
756         txa
757         adc     Y1+1
758         sta     Y1+1
759         ;       err = ub }
760         lda     UB
761         ldx     UB+1
762 @L0312:
763         sta     ERR
764         stx     ERR+1
765         ; } (--count)
766         sec
767         lda     COUNT
768         sbc     #1
769         sta     COUNT
770         bcc     @L0260
771         jmp     @L0166
772 @L0260: dec     COUNT+1
773         jmp     @L0166
774
775 ; ------------------------------------------------------------------------
776 ; BAR: Draw a filled rectangle with the corners X1/Y1, X2/Y2, where
777 ; X1/Y1 = ptr1/ptr2 and X2/Y2 = ptr3/ptr4 using the current drawing color.
778 ; Contrary to most other functions, the graphics kernel will sort and clip
779 ; the coordinates before calling the driver, so on entry the following
780 ; conditions are valid:
781 ;       X1 <= X2
782 ;       Y1 <= Y2
783 ;       (X1 >= 0) && (X1 < XRES)
784 ;       (X2 >= 0) && (X2 < XRES)
785 ;       (Y1 >= 0) && (Y1 < YRES)
786 ;       (Y2 >= 0) && (Y2 < YRES)
787 ;
788 ; Must set an error code: NO
789 ;
790
791 BAR:
792         inc     Y2
793         bne     HORLINE
794         inc     Y2+1
795
796 ; Original code for a horizontal line
797
798 HORLINE:
799         lda X1
800         pha
801         lda X1+1
802         pha
803         jsr CALC                ; get data for LEFT
804         lda BITMASKL,x          ; remember left address and bitmask
805         pha
806         lda ADDR
807         pha
808         lda ADDR+1
809         pha
810
811         lda X2
812         sta X1
813         lda X2+1
814         sta X1+1
815         jsr CALC                ; get data for RIGHT
816         lda BITMASKR,x
817         sta TEMP3
818
819         pla                     ; recall data for LEFT
820         sta X1+1
821         pla
822         sta X1                  ; put left address into X1
823         pla
824
825         cmp #%11111111          ; if left bit <> 0
826         beq @L1
827         sta TEMP2               ; do left byte only...
828         lda X1
829         ldy X1+1
830         jsr VDCSetSourceAddr
831         jsr VDCReadByte
832         sta TEMP
833         eor BITMASK
834         and TEMP2
835         eor TEMP
836         pha
837         lda X1
838         ldy X1+1
839         jsr VDCSetSourceAddr
840         pla
841         jsr VDCWriteByte
842         inc X1                  ; ... and proceed
843         bne @L1
844         inc X1+1
845
846         ; do right byte (if Y2=0 ++ADDR and skip)
847 @L1:    lda TEMP3
848         cmp #%11111111          ; if right bit <> 7
849         bne @L11
850         inc ADDR                ; right bit = 7 - the next one is the last
851         bne @L10
852         inc ADDR+1
853 @L10:   bne @L2
854
855 @L11:   lda ADDR                ; do right byte only...
856         ldy ADDR+1
857         jsr VDCSetSourceAddr
858         jsr VDCReadByte
859         sta TEMP
860         eor BITMASK
861         and TEMP3
862         eor TEMP
863         pha
864         lda ADDR
865         ldy ADDR+1
866         jsr VDCSetSourceAddr
867         pla
868         jsr VDCWriteByte
869
870 @L2:                            ; do the fill in the middle
871         lda ADDR                ; calculate offset in full bytes
872         sec
873         sbc X1
874         beq @L3                 ; if equal - there are no more bytes
875         sta ADDR
876
877         lda X1                  ; setup for the left side
878         ldy X1+1
879         jsr VDCSetSourceAddr
880         lda BITMASK             ; get color
881         jsr VDCWriteByte        ; put 1st value
882         ldx ADDR
883         dex
884         beq @L3                 ; 1 byte already written
885
886         stx ADDR                ; if there are more bytes - fill them...
887         ldx #VDC_VSCROLL
888         lda #0
889         jsr VDCWriteReg         ; setup for fill
890         ldx #VDC_COUNT
891         lda ADDR
892         jsr VDCWriteReg         ; ... fill them NOW!
893
894 @L3:    pla
895         sta X1+1
896         pla
897         sta X1
898
899 ; End of horizontal line code
900
901         inc     Y1
902         bne     @L4
903         inc     Y1+1
904 @L4:    lda     Y1
905         cmp     Y2
906         bne     @L5
907         lda     Y1+1
908         cmp     Y2+1
909         bne     @L5
910         rts
911
912 @L5:    jmp     HORLINE
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+1
1154         sta     ADDR+1
1155         lda     Y1
1156         asl
1157         rol     ADDR+1
1158         asl
1159         rol     ADDR+1          ; Y*4
1160         clc
1161         adc     Y1
1162         sta     ADDR
1163         lda     Y1+1
1164         adc     ADDR+1
1165         sta     ADDR+1          ; Y*4+Y=Y*5
1166         lda     ADDR
1167         asl
1168         rol     ADDR+1
1169         asl
1170         rol     ADDR+1
1171         asl
1172         rol     ADDR+1
1173         asl
1174         rol     ADDR+1
1175         sta     ADDR            ; Y*5*16=Y*80
1176         lda     X1+1
1177         sta     TEMP
1178         lda     X1
1179         lsr     TEMP
1180         ror
1181         lsr     TEMP
1182         ror
1183         lsr     TEMP
1184         ror
1185         clc
1186         adc     ADDR
1187         sta     ADDR
1188         lda     ADDR+1          ; ADDR = Y*80+x/8
1189         adc     TEMP
1190         sta     ADDR+1
1191         lda     ADDR+1
1192         adc     SCRBASE
1193         sta     ADDR+1
1194         lda     X1
1195         and     #7
1196         tax
1197         rts
1198
1199 ;-------------
1200 ; copies of some runtime routines
1201
1202 abs:
1203         ; a/y := abs(a/y)
1204         cpy     #$00
1205         bpl     absend
1206         ; negay
1207 neg:    eor     #$ff
1208         add     #1
1209         pha
1210         tya
1211         eor     #$ff
1212         adc     #0
1213         tay
1214         pla
1215 absend: rts
1216
1217 icmp:
1218         ; compare a/y to zp,x
1219         sta     TEMP            ; TEMP/TEMP2 - arg2
1220         sty     TEMP2
1221         lda     $0,x
1222         pha
1223         lda     $1,x
1224         tay
1225         pla
1226         tax
1227         tya                     ; x/a - arg1 (a=high)
1228
1229         sec
1230         sbc     TEMP2
1231         bne     @L4
1232         cpx     TEMP
1233         beq     @L3
1234         adc     #$ff
1235         ora     #$01
1236 @L3:    rts
1237 @L4:    bvc     @L3
1238         eor     #$ff
1239         ora     #$01
1240         rts
1241
1242 ;-------------
1243 ; VDC helpers
1244
1245 VDCSetSourceAddr:
1246         pha
1247         tya
1248         ldx     #VDC_DATA_HI
1249         jsr     VDCWriteReg
1250         pla
1251         ldx     #VDC_DATA_LO
1252         bne     VDCWriteReg
1253
1254 VDCReadByte:
1255         ldx     #VDC_DATA
1256 VDCReadReg:
1257         stx     VDC_ADDR_REG
1258 @L0:    bit     VDC_ADDR_REG
1259         bpl     @L0
1260         lda     VDC_DATA_REG
1261         rts
1262
1263 VDCWriteByte:
1264         ldx     #VDC_DATA
1265 VDCWriteReg:
1266         stx     VDC_ADDR_REG
1267 @L0:    bit     VDC_ADDR_REG
1268         bpl     @L0
1269         sta     VDC_DATA_REG
1270         rts
1271