]> git.sur5r.net Git - cc65/blob - libsrc/c128/c128-640-480-2.s
fixed addressing problems seen on the Real Machine (tm)
[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   DEINSTALL
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 ; DEINSTALL 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 DEINSTALL:
278         rts
279
280
281 ; ------------------------------------------------------------------------
282 ; INIT: Changes an already installed device from text mode to graphics
283 ; mode. The number of the graphics mode is passed to the function in A.
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:   cmp     #TGI_MODE_640_480_2     ; Correct mode?
296         beq     @L1                     ; Jump if yes
297         lda     #TGI_ERR_INV_MODE       ; ## Error
298         bne     @L9
299
300 @L1:    lda     pages                   ; is there enough memory?
301         bne     @L11                    ; Jump if there is one screen
302         lda     #TGI_ERR_INV_MODE       ; ## Error
303         bne     @L9
304
305 ; Initialize variables
306
307 @L11:   ldx     #$FF
308         stx     BITMASK
309
310 ; Remeber current color value
311         ldx     #VDC_COLORS
312         jsr     VDCReadReg
313         sta     OLDCOLOR
314
315 ; Switch into graphics mode (set view page 0)
316
317         ldy     #0
318 @L2:    ldx     InitVDCTab,y
319         bmi     @L3
320         iny
321         lda     InitVDCTab,y
322         jsr     VDCWriteReg
323         iny
324         bne     @L2
325 @L3:
326
327 ; Done, reset the error code
328
329         lda     #TGI_ERR_OK
330 @L9:    sta     ERROR
331         rts
332
333 ; ------------------------------------------------------------------------
334 ; DONE: Will be called to switch the graphics device back into text mode.
335 ; The graphics kernel will never call DONE when no graphics mode is active,
336 ; so there is no need to protect against that.
337 ;
338 ; Must set an error code: YES
339 ;
340
341 DONE:
342         ; This part is C128-mode specific
343         jsr $e179               ; reload character set and setup VDC
344         jsr $ff62
345         lda $d7                 ; in 80-columns?
346         bne @L01
347 @L0:    lda SCN80CLR,y
348         beq @L1
349         jsr $ffd2               ; print \xe,clr,\xe
350         iny
351         bne @L0
352 @L01:   lda #147
353         jsr $ffd2               ; print clr
354 @L1:    lda #0                  ; restore view page
355         ldx #VDC_DSP_HI
356         jsr VDCWriteReg
357         lda OLDCOLOR
358         ldx #VDC_COLORS
359         jsr VDCWriteReg         ; restore color (background)
360         lda #$47
361         ldx #VDC_HSCROLL
362         jmp VDCWriteReg         ; switch to text screen
363
364 ; ------------------------------------------------------------------------
365 ; GETERROR: Return the error code in A and clear it.
366
367 GETERROR:
368         ldx     #TGI_ERR_OK
369         lda     ERROR
370         stx     ERROR
371         rts
372
373 ; ------------------------------------------------------------------------
374 ; CONTROL: Platform/driver specific entry point.
375 ;
376 ; Must set an error code: YES
377 ;
378
379 CONTROL:
380         lda     #TGI_ERR_INV_FUNC
381         sta     ERROR
382         rts
383
384 ; ------------------------------------------------------------------------
385 ; CLEAR: Clears the screen.
386 ;
387 ; Must set an error code: NO
388 ;
389
390 CLEAR:  
391         lda     #0
392         tay
393         jsr     VDCSetSourceAddr
394         lda     #0
395         ldx     #VDC_VSCROLL
396         jsr     VDCWriteReg                     ; set fill mode
397         lda     #0
398         jsr     VDCWriteByte                    ; put 1rst byte (fill value)
399         ldy     #159                            ; 159 times
400         lda     #0                              ; 256 bytes
401         ldx     #VDC_COUNT
402 @L1:    jsr     VDCWriteReg
403         dey
404         bne     @L1
405         rts
406
407 ; ------------------------------------------------------------------------
408 ; SETVIEWPAGE: Set the visible page. Called with the new page in A (0..n).
409 ; The page number is already checked to be valid by the graphics kernel.
410 ;
411 ; Must set an error code: NO (will only be called if page ok)
412 ;
413
414 SETVIEWPAGE:
415         rts
416
417 ; ------------------------------------------------------------------------
418 ; SETDRAWPAGE: Set the drawable page. Called with the new page in A (0..n).
419 ; The page number is already checked to be valid by the graphics kernel.
420 ;
421 ; Must set an error code: NO (will only be called if page ok)
422 ;
423
424 SETDRAWPAGE:
425         rts
426
427 ; ------------------------------------------------------------------------
428 ; SETCOLOR: Set the drawing color (in A). The new color is already checked
429 ; to be in a valid range (0..maxcolor-1).
430 ;
431 ; Must set an error code: NO (will only be called if color ok)
432 ;
433
434 SETCOLOR:
435         tax
436         beq     @L1
437         lda     #$FF
438 @L1:    sta     BITMASK
439         rts
440
441 ; ------------------------------------------------------------------------
442 ; SETPALETTE: Set the palette (not available with all drivers/hardware).
443 ; A pointer to the palette is passed in ptr1. Must set an error if palettes
444 ; are not supported
445 ;
446 ; Must set an error code: YES
447 ;
448
449 SETPALETTE:
450         ldy     #PALETTESIZE - 1
451 @L1:    lda     (ptr1),y        ; Copy the palette
452         and     #$0F            ; Make a valid color
453         sta     PALETTE,y
454         dey
455         bpl     @L1
456
457 ; Get the color entries from the palette
458
459         ldy     PALETTE+1       ; Foreground color
460         lda     COLTRANS,y
461         asl     a
462         asl     a
463         asl     a
464         asl     a
465         ldy     PALETTE         ; Background color
466         ora     COLTRANS,y
467
468         ldx     #VDC_COLORS
469         jmp     VDCWriteReg
470
471 ; ------------------------------------------------------------------------
472 ; GETPALETTE: Return the current palette in A/X. Must return NULL and set an
473 ; error if palettes are not supported.
474 ;
475 ; Must set an error code: YES
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. Must
485 ; return NULL and set an error of palettes are not supported.
486 ;
487 ; Must set an error code: YES
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         ; if (x2>x1) {
701         ldx     #X1
702         lda     X2
703         ldy     X2+1
704         jsr     icmp
705         bcc     @L0137
706         beq     @L0137
707         ;  x2<->x1 }
708         lda     X1
709         ldx     X2
710         sta     X2
711         stx     X1
712         lda     X1+1
713         ldx     X2+1
714         sta     X2+1
715         stx     X1+1
716 @L0137: ; if (y2>y1) {
717         ldx     #Y1
718         lda     Y2
719         ldy     Y2+1
720         jsr     icmp
721         bcc     @L013F
722         bne     @nequal
723         jmp     HORLINE         ; x1/x2 are sorted, y1==y2 - do faster horizontal line draw
724 @nequal:
725         ; y2<->y1 }
726         lda     Y1
727         ldx     Y2
728         sta     Y2
729         stx     Y1
730         lda     Y1+1
731         ldx     Y2+1
732         sta     Y2+1
733         stx     Y1+1
734 @L013F:
735         ; nx = x2 - x1
736         lda     X2
737         sec
738         sbc     X1
739         sta     NX
740         lda     X2+1
741         sbc     X1+1
742         sta     NX+1
743         ; ny = y2 - y1
744         lda     Y2
745         sec
746         sbc     Y1
747         sta     NY
748         lda     Y2+1
749         sbc     Y1+1
750         sta     NY+1
751         ; if (nx<ny) {
752         ldx     #NX
753         lda     NY
754         ldy     NY+1
755         jsr     icmp
756         bcs     @L041B
757         ;  nx <-> ny
758         lda     NX
759         ldx     NY
760         sta     NY
761         stx     NX
762         lda     NX+1
763         ldx     NY+1
764         sta     NY+1
765         stx     NX+1
766         ; dx = dy = 0; ax = ay = 1 }
767         ldy     #1
768         sty     AY
769         dey
770         beq     @L025A
771         ; else { dx = dy = 1; ax = ay = 0 }
772 @L041B: ldy     #0
773         sty     AY
774         iny
775 @L025A: sty     DX
776         sty     DY
777         ; err = 0
778         lda     #0
779         sta     ERR
780         sta     ERR+1
781         ; for (count=nx;count>0;--count) {
782         lda     NX
783         ldx     NX+1
784         sta     COUNT
785         stx     COUNT+1
786 @L0166: lda     COUNT           ; count>0
787         ora     COUNT+1
788         bne     @L0167
789         rts
790         ;    setpixel(X1,Y1)
791 @L0167: jsr     SETPIXELCLIP
792         ;    pb = err - ny
793         lda     ERR
794         sec
795         sbc     NY
796         sta     PB
797         lda     ERR+1
798         sbc     NY+1
799         sta     PB+1
800         tax
801         ;    ub = pb + nx
802         lda     PB
803         clc
804         adc     NX
805         sta     UB
806         txa
807         adc     NX+1
808         sta     UB+1
809         ;    x1 = x1 + dx
810         lda     X1
811         clc
812         adc     DX
813         sta     X1
814         bcc     @L0254
815         inc     X1+1
816         ;   y1 = y1 + ay
817 @L0254:
818         lda     Y1
819         clc
820         adc     AY
821         sta     Y1
822         bcc     @L0255
823         inc     Y1+1
824 @L0255:
825         ; if (abs(pb)<abs(ub)) {
826         lda     PB
827         ldy     PB+1
828         jsr     abs
829         sta     TEMP3
830         sty     TEMP4
831         lda     UB
832         ldy     UB+1
833         jsr     abs
834         ldx     #TEMP3
835         jsr     icmp
836         bpl     @L017B
837         ;   err = pb
838         lda     PB
839         ldx     PB+1
840         jmp     @L025B
841         ; } else { x1 = x1 + ay
842 @L017B: 
843         lda     X1
844         clc
845         adc     AY
846         sta     X1
847         bcc     @L0256
848         inc     X1+1
849         ;       y1 = y1 + dy
850 @L0256:
851         lda     Y1
852         clc
853         adc     DY
854         sta     Y1
855         bcc     @L0257
856         inc     Y1+1
857         ;       err = ub }
858 @L0257:
859         lda     UB
860         ldx     UB+1
861 @L025B:
862         sta     ERR
863         stx     ERR+1
864         ; } (--count)
865         sec
866         lda     COUNT
867         sbc     #1
868         sta     COUNT
869         bcc     @L0260
870         jmp     @L0166
871 @L0260: dec     COUNT+1
872         jmp     @L0166
873
874 ; ------------------------------------------------------------------------
875 ; BAR: Draw a filled rectangle with the corners X1/Y1, X2/Y2, where
876 ; X1/Y1 = ptr1/ptr2 and X2/Y2 = ptr3/ptr4 using the current drawing color.
877 ; Contrary to most other functions, the graphics kernel will sort and clip
878 ; the coordinates before calling the driver, so on entry the following
879 ; conditions are valid:
880 ;       X1 <= X2
881 ;       Y1 <= Y2
882 ;       (X1 >= 0) && (X1 < XRES)
883 ;       (X2 >= 0) && (X2 < XRES)
884 ;       (Y1 >= 0) && (Y1 < YRES)
885 ;       (Y2 >= 0) && (Y2 < YRES)
886 ;
887 ; Must set an error code: NO
888 ;
889
890 BAR:
891         inc     Y2
892         bne     @L0
893         inc     Y2+1
894 @L0:    jsr     HORLINE
895         inc     Y1
896         bne     @L1
897         inc     Y1+1
898 @L1:    lda     Y1
899         cmp     Y2
900         bne     @L0
901         lda     Y1+1
902         cmp     Y2+1
903         bne     @L0
904         rts
905
906 ; ------------------------------------------------------------------------
907 ; CIRCLE: Draw a circle around the center X1/Y1 (= ptr1/ptr2) with the
908 ; radius in tmp1 and the current drawing color.
909 ;
910 ; Must set an error code: NO
911 ;
912
913 CIRCLE: 
914         lda     RADIUS
915         bne     @L1
916         jmp     SETPIXELCLIP    ; Plot as a point
917
918 @L1:    sta     XX
919         ; x = r;
920         lda     #0
921         sta     XX+1
922         sta     YY
923         sta     YY+1
924         sta     MaxO
925         sta     MaxO+1
926         ; y =0; mo=0;
927         lda     X1
928         ldx     X1+1
929         sta     XS
930         stx     XS+1
931         lda     Y1
932         ldx     Y1+1
933         sta     YS
934         stx     YS+1            ; XS/YS to remember the center
935
936         ; while (y<x) {
937 @L013B: ldx     #YY
938         lda     XX
939         ldy     XX+1
940         jsr     icmp
941         bcc     @L12
942         rts
943 @L12:   ; plot points in 8 slices...
944         lda     XS
945         clc
946         adc     XX
947         sta     X1
948         lda     XS+1
949         adc     XX+1
950         sta     X1+1            ; x1 = xs+x
951         lda     YS
952         clc
953         adc     YY
954         sta     Y1
955         pha
956         lda     YS+1
957         adc     YY+1
958         sta     Y1+1            ; (stack)=ys+y, y1=(stack)
959         pha
960         jsr     SETPIXELCLIP    ; plot(xs+x,ys+y)
961         lda     YS
962         sec
963         sbc     YY
964         sta     Y1
965         sta     Y3
966         lda     YS+1
967         sbc     YY+1
968         sta     Y1+1            ; y3 = y1 = ys-y
969         sta     Y3+1
970         jsr     SETPIXELCLIP    ; plot(xs+x,ys-y)
971         pla
972         sta     Y1+1
973         pla
974         sta     Y1              ; y1 = ys+y
975         lda     XS
976         sec
977         sbc     XX
978         sta     X1
979         lda     XS+1
980         sbc     XX+1
981         sta     X1+1
982         jsr     SETPIXELCLIP    ; plot (xs-x,ys+y)
983         lda     Y3
984         sta     Y1
985         lda     Y3+1
986         sta     Y1+1
987         jsr     SETPIXELCLIP    ; plot (xs-x,ys-y)
988
989         lda     XS
990         clc
991         adc     YY
992         sta     X1
993         lda     XS+1
994         adc     YY+1
995         sta     X1+1            ; x1 = xs+y
996         lda     YS
997         clc
998         adc     XX
999         sta     Y1
1000         pha
1001         lda     YS+1
1002         adc     XX+1
1003         sta     Y1+1            ; (stack)=ys+x, y1=(stack)
1004         pha
1005         jsr     SETPIXELCLIP    ; plot(xs+y,ys+x)
1006         lda     YS
1007         sec
1008         sbc     XX
1009         sta     Y1
1010         sta     Y3
1011         lda     YS+1
1012         sbc     XX+1
1013         sta     Y1+1            ; y3 = y1 = ys-x
1014         sta     Y3+1
1015         jsr     SETPIXELCLIP    ; plot(xs+y,ys-x)
1016         pla
1017         sta     Y1+1
1018         pla
1019         sta     Y1              ; y1 = ys+x(stack)
1020         lda     XS
1021         sec
1022         sbc     YY
1023         sta     X1
1024         lda     XS+1
1025         sbc     YY+1
1026         sta     X1+1
1027         jsr     SETPIXELCLIP    ; plot (xs-y,ys+x)
1028         lda     Y3
1029         sta     Y1
1030         lda     Y3+1
1031         sta     Y1+1
1032         jsr     SETPIXELCLIP    ; plot (xs-y,ys-x)
1033
1034         ; og = mo+y+y+1
1035         lda     MaxO
1036         ldx     MaxO+1
1037         clc
1038         adc     YY
1039         tay
1040         txa
1041         adc     YY+1
1042         tax
1043         tya
1044         clc
1045         adc     YY
1046         tay
1047         txa
1048         adc     YY+1
1049         tax
1050         tya
1051         clc
1052         adc     #1
1053         bcc     @L0143
1054         inx
1055 @L0143: sta     OGora
1056         stx     OGora+1
1057         ; ou = og-x-x+1
1058         sec
1059         sbc     XX
1060         tay
1061         txa
1062         sbc     XX+1
1063         tax
1064         tya
1065         sec
1066         sbc     XX
1067         tay
1068         txa
1069         sbc     XX+1
1070         tax
1071         tya
1072         clc
1073         adc     #1
1074         bcc     @L0146
1075         inx
1076 @L0146: sta     OUkos
1077         stx     OUkos+1
1078         ; ++y
1079         inc     YY
1080         bne     @L0148
1081         inc     YY+1
1082 @L0148: ; if (abs(ou)<abs(og))
1083         lda     OUkos
1084         ldy     OUkos+1
1085         jsr     abs
1086         sta     TEMP3
1087         sty     TEMP4
1088         lda     OGora
1089         ldy     OGora+1
1090         jsr     abs
1091         ldx     #TEMP3
1092         jsr     icmp
1093         bpl     @L0149
1094         ; { --x;
1095         sec
1096         lda     XX
1097         sbc     #1
1098         sta     XX
1099         bcs     @L014E
1100         dec     XX+1
1101 @L014E: ; mo = ou; }
1102         lda     OUkos
1103         ldx     OUkos+1
1104         jmp     @L014G
1105         ; else { mo = og }
1106 @L0149: lda     OGora
1107         ldx     OGora+1
1108 @L014G: sta     MaxO
1109         stx     MaxO+1
1110         ; }
1111         jmp     @L013B
1112
1113 ; ------------------------------------------------------------------------
1114 ; TEXTSTYLE: Set the style used when calling OUTTEXT. Text scaling in X and Y
1115 ; direction is passend in X/Y, the text direction is passed in A.
1116 ;
1117 ; Must set an error code: NO
1118 ;
1119
1120 TEXTSTYLE:
1121         stx     TEXTMAGX
1122         sty     TEXTMAGY
1123         sta     TEXTDIR
1124         rts
1125
1126
1127 ; ------------------------------------------------------------------------
1128 ; OUTTEXT: Output text at X/Y = ptr1/ptr2 using the current color and the
1129 ; current text style. The text to output is given as a zero terminated
1130 ; string with address in ptr3.
1131 ;
1132 ; Must set an error code: NO
1133 ;
1134
1135 OUTTEXT:
1136         rts
1137
1138 ; ------------------------------------------------------------------------
1139 ; Calculate all variables to plot the pixel at X1/Y1.
1140 ;------------------------
1141 ;< X1,Y1 - pixel
1142 ;> ADDR - address of card
1143 ;> X - bit number (X1 & 7)
1144 CALC:
1145         lda     Y1
1146         pha
1147         lda     Y1+1
1148         pha
1149         lsr
1150         ror     Y1              ; Y=Y/2
1151         sta     Y1+1
1152         sta     ADDR+1
1153         lda     Y1
1154         asl
1155         rol     ADDR+1
1156         asl
1157         rol     ADDR+1          ; Y*4
1158         clc
1159         adc     Y1
1160         sta     ADDR
1161         lda     Y1+1
1162         adc     ADDR+1
1163         sta     ADDR+1          ; Y*4+Y=Y*5
1164         lda     ADDR
1165         asl
1166         rol     ADDR+1
1167         asl
1168         rol     ADDR+1
1169         asl
1170         rol     ADDR+1
1171         asl
1172         rol     ADDR+1
1173         sta     ADDR            ; Y*5*16=Y*80
1174         lda     X1+1
1175         sta     TEMP
1176         lda     X1
1177         lsr     TEMP
1178         ror
1179         lsr     TEMP
1180         ror
1181         lsr     TEMP
1182         ror
1183         clc
1184         adc     ADDR
1185         sta     ADDR
1186         lda     ADDR+1          ; ADDR = Y*80+x/8
1187         adc     TEMP
1188         sta     ADDR+1
1189         pla
1190         sta     Y1+1
1191         pla
1192         sta     Y1
1193         and     #1
1194         beq     @even           ; even line - no offset
1195         lda     ADDR
1196         clc
1197         adc     #<21360
1198         sta     ADDR
1199         lda     ADDR+1
1200         adc     #>21360
1201         sta     ADDR+1          ; odd lines are 21360 bytes farther
1202 @even:  lda     X1
1203         and     #7
1204         tax
1205         rts
1206
1207 ;-------------
1208 ; copies of some runtime routines
1209
1210 abs:
1211         ; a/y := abs(a/y)
1212         dey
1213         iny
1214         bpl     @L1
1215         ; negay
1216         clc
1217         eor     #$ff
1218         adc     #1
1219         pha
1220         tya
1221         eor     #$ff
1222         adc     #0
1223         tay
1224         pla
1225 @L1:    rts
1226
1227 icmp:
1228         ; compare a/y to zp,x
1229         sta     TEMP            ; TEMP/TEMP2 - arg2
1230         sty     TEMP2
1231         lda     $0,x
1232         pha
1233         lda     $1,x
1234         tay
1235         pla
1236         tax
1237         tya                     ; x/a - arg1 (a=high)
1238
1239         sec
1240         sbc     TEMP2
1241         bne     @L4
1242         cpx     TEMP
1243         beq     @L3
1244         adc     #$ff
1245         ora     #$01
1246 @L3:    rts
1247 @L4:    bvc     @L3
1248         eor     #$ff
1249         ora     #$01
1250         rts
1251
1252 ;-------------
1253 ; VDC helpers
1254
1255 VDCSetSourceAddr:
1256         pha
1257         tya
1258         ldx     #VDC_DATA_HI
1259         jsr     VDCWriteReg
1260         pla
1261         ldx     #VDC_DATA_LO
1262         bne     VDCWriteReg
1263
1264 VDCReadByte:
1265         ldx     #VDC_DATA
1266 VDCReadReg:
1267         stx     VDC_ADDR_REG
1268 @L0:    bit     VDC_ADDR_REG
1269         bpl     @L0
1270         lda     VDC_DATA_REG
1271         rts
1272
1273 VDCWriteByte:
1274         ldx     #VDC_DATA
1275 VDCWriteReg:
1276         stx     VDC_ADDR_REG
1277 @L0:    bit     VDC_ADDR_REG
1278         bpl     @L0
1279         sta     VDC_DATA_REG
1280         rts
1281