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