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