]> git.sur5r.net Git - cc65/blob - libsrc/apple2/apple2-40-40-16.s
Add interrupt handling code from Stefan Haubenthal
[cc65] / libsrc / apple2 / apple2-40-40-16.s
1 ;
2 ; Graphics driver for the 40x40x16 mode on the Apple II
3 ;
4 ; Stefan Haubenthal <polluks@sdf.lonestar.org>
5 ; Based on Maciej Witkowiak's line and circle routine
6 ;
7
8         .include        "zeropage.inc"
9
10         .include        "tgi-kernel.inc"
11         .include        "tgi-mode.inc"
12         .include        "tgi-error.inc"
13         .include        "apple2.inc"
14
15         .macpack        generic
16
17 ; ------------------------------------------------------------------------
18 ; Constants
19
20 H2              = $2C
21 PLOT            = $F800
22 HLINE           = $F819
23 CLRTOP          = $F836
24 SETCOL          = $F864
25 SCRN            = $F871
26 SETGR           = $FB40
27 VTABZ           = $FC24
28
29 ; ------------------------------------------------------------------------
30 ; ROM entry points
31
32 COUT    :=      $FDED   ; Vector to user output routine
33 TEXT    :=      $F399   ; Return to text screen
34
35 ; ------------------------------------------------------------------------
36 ; Header. Includes jump table and constants.
37
38 .segment        "JUMPTABLE"
39
40 ; First part of the header is a structure that has a magic and defines the
41 ; capabilities of the driver
42
43         .byte   $74, $67, $69           ; "tgi"
44         .byte   TGI_API_VERSION         ; TGI API version number
45 xres:   .word   40                      ; X resolution
46 yres:   .word   40                      ; Y resolution
47         .byte   16                      ; Number of drawing colors
48         .byte   1                       ; Number of screens available
49         .byte   8                       ; System font X size
50         .byte   8                       ; System font Y size
51         .res    4, $00                  ; Reserved for future extensions
52
53 ; Next comes the jump table. Currently all entries must be valid and may point
54 ; to an RTS for test versions (function not implemented).
55
56         .word   INSTALL
57         .word   UNINSTALL
58         .word   INIT
59         .word   DONE
60         .word   GETERROR
61         .word   CONTROL
62         .word   CLEAR
63         .word   SETVIEWPAGE
64         .word   SETDRAWPAGE
65         .word   SETCOLOR
66         .word   SETPALETTE
67         .word   GETPALETTE
68         .word   GETDEFPALETTE
69         .word   SETPIXEL
70         .word   GETPIXEL
71         .word   LINE
72         .word   BAR
73         .word   CIRCLE
74         .word   TEXTSTYLE
75         .word   OUTTEXT
76
77 ; ------------------------------------------------------------------------
78 ; Data.
79
80 ; Variables mapped to the zero page segment variables. Some of these are
81 ; used for passing parameters to the driver.
82
83 X1              = ptr1
84 Y1              = ptr2
85 X2              = ptr3
86 Y2              = ptr4
87 RADIUS          = tmp1
88
89 ADDR            = tmp1
90 TEMP            = tmp3
91 TEMP2           = tmp4
92 TEMP3           = sreg
93 TEMP4           = sreg+1
94
95 ; Line routine stuff (must be on zpage)
96 PB              = ptr3          ; (2)   LINE
97 UB              = ptr4          ; (2)   LINE
98 ERR             = regsave       ; (2)   LINE
99 NX              = regsave+2     ; (2)   LINE
100 ; Circle stuff
101 XX              = ptr3          ; (2)   CIRCLE
102 YY              = ptr4          ; (2)   CIRCLE
103 MaxO            = sreg          ; (overwritten by TEMP3+TEMP4, but restored from OG/OU anyway)
104 XS              = regsave       ; (2)   CIRCLE
105 YS              = regsave+2     ; (2)   CIRCLE
106
107 ; Absolute variables used in the code
108
109 .bss
110
111 ERROR:          .res    1       ; Error code
112
113 ; Line routine stuff (combined with CIRCLE to save space)
114
115 OGora:
116 COUNT:          .res    2
117 OUkos:
118 NY:             .res    2
119 Y3:
120 DX:             .res    1
121 DY:             .res    1
122 AY:             .res    1
123
124 ; Constants and tables
125
126 .rodata
127
128 DEFPALETTE:     .byte   $00, $0F, $01, $0E, $03, $04, $02, $0D
129                 .byte   $09, $08, $0B, $05, $0A, $0C, $06, $07
130
131 .code
132
133 ; ------------------------------------------------------------------------
134 ; INSTALL routine. Is called after the driver is loaded into memory. May
135 ; initialize anything that has to be done just once. Is probably empty
136 ; most of the time.
137 ;
138 ; Must set an error code: NO
139 ;
140
141 INSTALL:
142
143
144 ; ------------------------------------------------------------------------
145 ; UNINSTALL routine. Is called before the driver is removed from memory. May
146 ; clean up anything done by INSTALL but is probably empty most of the time.
147 ;
148 ; Must set an error code: NO
149 ;
150
151 UNINSTALL:
152         rts
153
154
155 ; ------------------------------------------------------------------------
156 ; INIT: Changes an already installed device from text mode to graphics
157 ; mode.
158 ; Note that INIT/DONE may be called multiple times while the driver
159 ; is loaded, while INSTALL is only called once, so any code that is needed
160 ; to initializes variables and so on must go here. Setting palette and
161 ; clearing the screen is not needed because this is called by the graphics
162 ; kernel later.
163 ; The graphics kernel will never call INIT when a graphics mode is already
164 ; active, so there is no need to protect against that.
165 ;
166 ; Must set an error code: YES
167 ;
168
169 INIT:
170
171 ; Switch into graphics mode
172
173         jsr     SETGR
174
175 ; Done, reset the error code
176
177         lda     #TGI_ERR_OK
178         sta     ERROR
179         rts
180
181 ; ------------------------------------------------------------------------
182 ; DONE: Will be called to switch the graphics device back into text mode.
183 ; The graphics kernel will never call DONE when no graphics mode is active,
184 ; so there is no need to protect against that.
185 ;
186 ; Must set an error code: NO
187 ;
188
189 DONE            = TEXT
190
191 ; ------------------------------------------------------------------------
192 ; GETERROR: Return the error code in A and clear it.
193
194 GETERROR:
195         ldx     #TGI_ERR_OK
196         lda     ERROR
197         stx     ERROR
198         rts
199
200 ; ------------------------------------------------------------------------
201 ; CONTROL: Platform/driver specific entry point.
202 ;
203 ; Must set an error code: YES
204 ;
205
206 CONTROL:
207         lda     #TGI_ERR_INV_FUNC
208         sta     ERROR
209         rts
210
211 ; ------------------------------------------------------------------------
212 ; CLEAR: Clears the screen.
213 ;
214 ; Must set an error code: NO
215 ;
216
217 CLEAR           = CLRTOP
218
219 ; ------------------------------------------------------------------------
220 ; SETVIEWPAGE: Set the visible page. Called with the new page in A (0..n).
221 ; The page number is already checked to be valid by the graphics kernel.
222 ;
223 ; Must set an error code: NO (will only be called if page ok)
224 ;
225
226 SETVIEWPAGE:
227
228 ; ------------------------------------------------------------------------
229 ; SETDRAWPAGE: Set the drawable page. Called with the new page in A (0..n).
230 ; The page number is already checked to be valid by the graphics kernel.
231 ;
232 ; Must set an error code: NO (will only be called if page ok)
233 ;
234
235 SETDRAWPAGE:
236         rts
237
238 ; ------------------------------------------------------------------------
239 ; SETCOLOR: Set the drawing color (in A). The new color is already checked
240 ; to be in a valid range (0..maxcolor-1).
241 ;
242 ; Must set an error code: NO (will only be called if color ok)
243 ;
244
245 SETCOLOR        = SETCOL
246
247 ; ------------------------------------------------------------------------
248 ; SETPALETTE: Set the palette (not available with all drivers/hardware).
249 ; A pointer to the palette is passed in ptr1. Must set an error if palettes
250 ; are not supported
251 ;
252 ; Must set an error code: YES
253 ;
254
255 SETPALETTE:
256         lda     #TGI_ERR_INV_FUNC
257         sta     ERROR
258         rts
259
260 ; ------------------------------------------------------------------------
261 ; GETPALETTE: Return the current palette in A/X. Even drivers that cannot
262 ; set the palette should return the default palette here, so there's no
263 ; way for this function to fail.
264 ;
265 ; Must set an error code: NO
266 ;
267
268 GETPALETTE:
269
270 ; ------------------------------------------------------------------------
271 ; GETDEFPALETTE: Return the default palette for the driver in A/X. All
272 ; drivers should return something reasonable here, even drivers that don't
273 ; support palettes, otherwise the caller has no way to determine the colors
274 ; of the (not changeable) palette.
275 ;
276 ; Must set an error code: NO (all drivers must have a default palette)
277 ;
278
279 GETDEFPALETTE:
280         lda     #<DEFPALETTE
281         ldx     #>DEFPALETTE
282         rts
283
284 ; ------------------------------------------------------------------------
285 ; SETPIXEL: Draw one pixel at X1/Y1 = ptr1/ptr2 with the current drawing
286 ; color. The coordinates passed to this function are never outside the
287 ; visible screen area, so there is no need for clipping inside this function.
288 ;
289 ; Must set an error code: NO
290 ;
291
292 SETPIXELCLIP:
293         lda     Y1+1
294         bmi     @finito         ; y<0
295         lda     X1+1
296         bmi     @finito         ; x<0
297         lda     X1
298         ldx     X1+1
299         sta     ADDR
300         stx     ADDR+1
301         ldx     #ADDR
302         lda     xres
303         ldy     xres+1
304         jsr     icmp            ; ( x < xres ) ...
305         bcs     @finito
306         lda     Y1
307         ldx     Y1+1
308         sta     ADDR
309         stx     ADDR+1
310         ldx     #ADDR
311         lda     yres
312         ldy     yres+1
313         jsr     icmp            ; ... && ( y < yres )
314         bcc     SETPIXEL
315 @finito:rts
316
317 SETPIXEL:
318         lda     X1
319         ldy     Y1
320         jmp     PLOT
321
322 ; ------------------------------------------------------------------------
323 ; GETPIXEL: Read the color value of a pixel and return it in A/X. The
324 ; coordinates passed to this function are never outside the visible screen
325 ; area, so there is no need for clipping inside this function.
326
327
328 GETPIXEL:
329         lda     X1
330         ldy     Y1
331         jsr     SCRN
332         ldx     #$00
333         rts
334
335 ; ------------------------------------------------------------------------
336 ; LINE: Draw a line from X1/Y1 to X2/Y2, where X1/Y1 = ptr1/ptr2 and
337 ; X2/Y2 = ptr3/ptr4 using the current drawing color.
338 ;
339 ; Must set an error code: NO
340 ;
341
342 LINE:
343         ; nx = abs(x2 - x1)
344         lda     X2
345         sub     X1
346         sta     NX
347         lda     X2+1
348         sbc     X1+1
349         tay
350         lda     NX
351         jsr     abs
352         sta     NX
353         sty     NX+1
354         ; ny = abs(y2 - y1)
355         lda     Y2
356         sub     Y1
357         sta     NY
358         lda     Y2+1
359         sbc     Y1+1
360         tay
361         lda     NY
362         jsr     abs
363         sta     NY
364         sty     NY+1
365         ; if (x2>x1)
366         ldx     #X2
367         lda     X1
368         ldy     X1+1
369         jsr     icmp
370         bcc     @L0243
371         beq     @L0243
372         ; dx = 1;
373         lda     #$01
374         bne     @L0244
375         ; else
376         ; dx = -1;
377 @L0243: lda     #$FF
378 @L0244: sta     DX
379         ; if (y2>y1)
380         ldx     #Y2
381         lda     Y1
382         ldy     Y1+1
383         jsr     icmp
384         bcc     @L024A
385         beq     @L024A
386         ; dy = 1;
387         lda     #$01
388         bne     @L024B
389         ; else
390         ; dy = -1;
391 @L024A: lda     #$FF
392 @L024B: sta     DY
393         ; err = ay = 0;
394         lda     #$00
395         sta     ERR
396         sta     ERR+1
397         sta     AY
398
399         ; if (nx<ny) {
400         ldx     #NX
401         lda     NY
402         ldy     NY+1
403         jsr     icmp
404         bcs     @L0255
405         ;  nx <-> ny
406         lda     NX
407         ldx     NY
408         sta     NY
409         stx     NX
410         lda     NX+1
411         ldx     NY+1
412         sta     NY+1
413         stx     NX+1
414         ; ay = dx
415         lda     DX
416         sta     AY
417         ; dx = dy = 0;
418         lda     #$00
419         sta     DX
420         sta     DY
421         ; ny = - ny;
422 @L0255: lda     NY
423         ldy     NY+1
424         jsr     neg
425         sta     NY
426         sty     NY+1
427         ; for (count=nx;count>0;--count) {
428         lda     NX
429         ldx     NX+1
430         sta     COUNT
431         stx     COUNT+1
432 @L0166: lda     COUNT           ; count>0
433         ora     COUNT+1
434         bne     @L0167
435         rts
436         ;    setpixel(X1,Y1)
437 @L0167: jsr     SETPIXELCLIP
438         ;    pb = err + ny
439         lda     ERR
440         add     NY
441         sta     PB
442         lda     ERR+1
443         adc     NY+1
444         sta     PB+1
445         tax
446         ;    ub = pb + nx
447         lda     PB
448         add     NX
449         sta     UB
450         txa
451         adc     NX+1
452         sta     UB+1
453         ;    x1 = x1 + dx
454         ldx     #$00
455         lda     DX
456         bpl     @L027B
457         dex
458 @L027B: add     X1
459         sta     X1
460         txa
461         adc     X1+1
462         sta     X1+1
463         ;   y1 = y1 + ay
464         ldx     #$00
465         lda     AY
466         bpl     @L027E
467         dex
468 @L027E: add     Y1
469         sta     Y1
470         txa
471         adc     Y1+1
472         sta     Y1+1
473         ; if (abs(pb)<abs(ub)) {
474         lda     PB
475         ldy     PB+1
476         jsr     abs
477         sta     TEMP3
478         sty     TEMP4
479         lda     UB
480         ldy     UB+1
481         jsr     abs
482         ldx     #TEMP3
483         jsr     icmp
484         bpl     @L027F
485         ;   err = pb
486         lda     PB
487         ldx     PB+1
488         jmp     @L0312
489         ; } else { x1 = x1 + ay
490 @L027F:
491         ldx     #$00
492         lda     AY
493         bpl     @L0288
494         dex
495 @L0288: add     X1
496         sta     X1
497         txa
498         adc     X1+1
499         sta     X1+1
500         ;       y1 = y1 + dy
501         ldx     #$00
502         lda     DY
503         bpl     @L028B
504         dex
505 @L028B: add     Y1
506         sta     Y1
507         txa
508         adc     Y1+1
509         sta     Y1+1
510         ;       err = ub }
511         lda     UB
512         ldx     UB+1
513 @L0312:
514         sta     ERR
515         stx     ERR+1
516         ; } (--count)
517         sec
518         lda     COUNT
519         sbc     #$01
520         sta     COUNT
521         bcc     @L0260
522         jmp     @L0166
523 @L0260: dec     COUNT+1
524         jmp     @L0166
525
526 ; ------------------------------------------------------------------------
527 ; BAR: Draw a filled rectangle with the corners X1/Y1, X2/Y2, where
528 ; X1/Y1 = ptr1/ptr2 and X2/Y2 = ptr3/ptr4 using the current drawing color.
529 ; Contrary to most other functions, the graphics kernel will sort and clip
530 ; the coordinates before calling the driver, so on entry the following
531 ; conditions are valid:
532 ;       X1 <= X2
533 ;       Y1 <= Y2
534 ;       (X1 >= 0) && (X1 < XRES)
535 ;       (X2 >= 0) && (X2 < XRES)
536 ;       (Y1 >= 0) && (Y1 < YRES)
537 ;       (Y2 >= 0) && (Y2 < YRES)
538 ;
539 ; Must set an error code: NO
540 ;
541
542 BAR:
543         inc     Y2
544         ldx     X2
545         stx     H2
546 @L1:    ldy     X1
547         lda     Y1
548         jsr     HLINE
549         inc     Y1
550         lda     Y2
551         cmp     Y1
552         bne     @L1
553         rts
554
555 ; ------------------------------------------------------------------------
556 ; CIRCLE: Draw a circle around the center X1/Y1 (= ptr1/ptr2) with the
557 ; radius in tmp1 and the current drawing color.
558 ;
559 ; Must set an error code: NO
560 ;
561
562 CIRCLE:
563         lda     RADIUS
564         bne     @L1
565         jmp     SETPIXELCLIP    ; Plot as a point
566
567 @L1:    sta     XX
568         ; x = r;
569         lda     #$00
570         sta     XX+1
571         sta     YY
572         sta     YY+1
573         sta     MaxO
574         sta     MaxO+1
575         ; y =0; mo=0;
576         lda     X1
577         ldx     X1+1
578         sta     XS
579         stx     XS+1
580         lda     Y1
581         ldx     Y1+1
582         sta     YS
583         stx     YS+1            ; XS/YS to remember the center
584
585         ; while (y<x) {
586 @L013B: ldx     #YY
587         lda     XX
588         ldy     XX+1
589         jsr     icmp
590         bcc     @L12
591         rts
592 @L12:   ; plot points in 8 slices...
593         lda     XS
594         add     XX
595         sta     X1
596         lda     XS+1
597         adc     XX+1
598         sta     X1+1            ; x1 = xs+x
599         lda     YS
600         add     YY
601         sta     Y1
602         pha
603         lda     YS+1
604         adc     YY+1
605         sta     Y1+1            ; (stack)=ys+y, y1=(stack)
606         pha
607         jsr     SETPIXELCLIP    ; plot(xs+x,ys+y)
608         lda     YS
609         sub     YY
610         sta     Y1
611         sta     Y3
612         lda     YS+1
613         sbc     YY+1
614         sta     Y1+1            ; y3 = y1 = ys-y
615         sta     Y3+1
616         jsr     SETPIXELCLIP    ; plot(xs+x,ys-y)
617         pla
618         sta     Y1+1
619         pla
620         sta     Y1              ; y1 = ys+y
621         lda     XS
622         sub     XX
623         sta     X1
624         lda     XS+1
625         sbc     XX+1
626         sta     X1+1
627         jsr     SETPIXELCLIP    ; plot (xs-x,ys+y)
628         lda     Y3
629         sta     Y1
630         lda     Y3+1
631         sta     Y1+1
632         jsr     SETPIXELCLIP    ; plot (xs-x,ys-y)
633
634         lda     XS
635         add     YY
636         sta     X1
637         lda     XS+1
638         adc     YY+1
639         sta     X1+1            ; x1 = xs+y
640         lda     YS
641         add     XX
642         sta     Y1
643         pha
644         lda     YS+1
645         adc     XX+1
646         sta     Y1+1            ; (stack)=ys+x, y1=(stack)
647         pha
648         jsr     SETPIXELCLIP    ; plot(xs+y,ys+x)
649         lda     YS
650         sub     XX
651         sta     Y1
652         sta     Y3
653         lda     YS+1
654         sbc     XX+1
655         sta     Y1+1            ; y3 = y1 = ys-x
656         sta     Y3+1
657         jsr     SETPIXELCLIP    ; plot(xs+y,ys-x)
658         pla
659         sta     Y1+1
660         pla
661         sta     Y1              ; y1 = ys+x(stack)
662         lda     XS
663         sub     YY
664         sta     X1
665         lda     XS+1
666         sbc     YY+1
667         sta     X1+1
668         jsr     SETPIXELCLIP    ; plot (xs-y,ys+x)
669         lda     Y3
670         sta     Y1
671         lda     Y3+1
672         sta     Y1+1
673         jsr     SETPIXELCLIP    ; plot (xs-y,ys-x)
674
675         ; og = mo+y+y+1
676         lda     MaxO
677         ldx     MaxO+1
678         add     YY
679         tay
680         txa
681         adc     YY+1
682         tax
683         tya
684         add     YY
685         tay
686         txa
687         adc     YY+1
688         tax
689         tya
690         add     #$01
691         bcc     @L0143
692         inx
693 @L0143: sta     OGora
694         stx     OGora+1
695         ; ou = og-x-x+1
696         sub     XX
697         tay
698         txa
699         sbc     XX+1
700         tax
701         tya
702         sub     XX
703         tay
704         txa
705         sbc     XX+1
706         tax
707         tya
708         add     #$01
709         bcc     @L0146
710         inx
711 @L0146: sta     OUkos
712         stx     OUkos+1
713         ; ++y
714         inc     YY
715         bne     @L0148
716         inc     YY+1
717 @L0148: ; if (abs(ou)<abs(og))
718         lda     OUkos
719         ldy     OUkos+1
720         jsr     abs
721         sta     TEMP3
722         sty     TEMP4
723         lda     OGora
724         ldy     OGora+1
725         jsr     abs
726         ldx     #TEMP3
727         jsr     icmp
728         bpl     @L0149
729         ; { --x;
730         lda     XX
731         sub     #$01
732         sta     XX
733         bcs     @L014E
734         dec     XX+1
735 @L014E: ; mo = ou; }
736         lda     OUkos
737         ldx     OUkos+1
738         jmp     @L014G
739         ; else { mo = og }
740 @L0149: lda     OGora
741         ldx     OGora+1
742 @L014G: sta     MaxO
743         stx     MaxO+1
744         ; }
745         jmp     @L013B
746
747 ; ------------------------------------------------------------------------
748 ; TEXTSTYLE: Set the style used when calling OUTTEXT. Text scaling in X and Y
749 ; direction is passend in X/Y, the text direction is passed in A.
750 ;
751 ; Must set an error code: NO
752 ;
753
754 TEXTSTYLE:
755         rts
756
757
758 ; ------------------------------------------------------------------------
759 ; OUTTEXT: Output text at X/Y = ptr1/ptr2 using the current color and the
760 ; current text style. The text to output is given as a zero terminated
761 ; string with address in ptr3.
762 ;
763 ; Must set an error code: NO
764 ;
765
766 OUTTEXT:
767         lda     ptr1
768         sta     CH
769         lda     ptr2
770         jsr     VTABZ
771         ldy     #$00
772 @L1:    lda     (ptr3),y
773         ora     #$80
774         jsr     COUT
775         iny
776         cmp     #$80
777         bne     @L1
778         rts
779
780 ;-------------
781 ; copies of some runtime routines
782
783 abs:
784         ; a/y := abs(a/y)
785         cpy     #$00
786         bpl     absend
787         ; negay
788 neg:    clc
789         eor     #$FF
790         adc     #$01
791         pha
792         tya
793         eor     #$FF
794         adc     #$00
795         tay
796         pla
797 absend: rts
798
799 icmp:
800         ; compare a/y to zp,x
801         sta     TEMP            ; TEMP/TEMP2 - arg2
802         sty     TEMP2
803         lda     $00,x
804         pha
805         lda     $01,x
806         tay
807         pla
808         tax
809         tya                     ; x/a - arg1 (a=high)
810
811         sub     TEMP2
812         bne     @L4
813         cpx     TEMP
814         beq     @L3
815         adc     #$FF
816         ora     #$01
817 @L3:    rts
818 @L4:    bvc     @L3
819         eor     #$FF
820         ora     #$01
821         rts