]> git.sur5r.net Git - cc65/blob - libsrc/apple2/apple2-40-48-16.s
b3d319861351084208c89fced65194033f0430b1
[cc65] / libsrc / apple2 / apple2-40-48-16.s
1 ;
2 ; Graphics driver for the 40x48x16 mode on the Apple II
3 ;
4 ; Stefan Haubenthal <polluks@sdf.lonestar.org>
5 ; Oliver Schmidt <ol.sc@web.de>
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 ; ------------------------------------------------------------------------
16
17 ; Zero page stuff
18
19 H2      :=      $2C
20 COLOR   :=      $30
21
22 ; ROM entry points
23
24 TEXT    :=      $F399
25 PLOT    :=      $F800
26 HLINE   :=      $F819
27 CLRSC2  :=      $F838
28 SETCOL  :=      $F864
29 SCRN    :=      $F871
30 SETGR   :=      $FB40
31 HOME    :=      $FC58
32
33 ; ------------------------------------------------------------------------
34
35 ; Variables mapped to the zero page segment variables. Some of these are
36 ; used for passing parameters to the driver.
37
38 X1      :=      ptr1
39 Y1      :=      ptr2
40 X2      :=      ptr3
41 Y2      :=      ptr4
42
43 TEMP    :=      tmp3
44 TEMP2   :=      tmp4
45 TEMP3   :=      sreg
46 TEMP4   :=      sreg+1
47
48 ; Line routine stuff (must be on zpage)
49
50 PB      :=      ptr3            ; (2)   LINE
51 UB      :=      ptr4            ; (2)   LINE
52 ERR     :=      regsave         ; (2)   LINE
53 NX      :=      regsave+2       ; (2)   LINE
54
55 ; ------------------------------------------------------------------------
56
57         .segment        "JUMPTABLE"
58
59 ; Header. Includes jump table and constants.
60
61 ; First part of the header is a structure that has a magic and defines the
62 ; capabilities of the driver
63
64         .byte   $74, $67, $69   ; "tgi"
65         .byte   TGI_API_VERSION ; TGI API version number
66         .word   40              ; X resolution
67         .word   48              ; Y resolution
68         .byte   16              ; Number of drawing colors
69         .byte   1               ; Number of screens available
70         .byte   8               ; System font X size
71         .byte   8               ; System font Y size
72         .word   $100            ; Aspect ratio
73
74 ; Next comes the jump table. With the exception of IRQ, all entries must be
75 ; valid and may point to an RTS for test versions (function not implemented).
76
77         .addr   INSTALL
78         .addr   UNINSTALL
79         .addr   INIT
80         .addr   DONE
81         .addr   GETERROR
82         .addr   CONTROL
83         .addr   CLEAR
84         .addr   SETVIEWPAGE
85         .addr   SETDRAWPAGE
86         .addr   SETCOLOR
87         .addr   SETPALETTE
88         .addr   GETPALETTE
89         .addr   GETDEFPALETTE
90         .addr   SETPIXEL
91         .addr   GETPIXEL
92         .addr   LINE
93         .addr   BAR
94         .addr   TEXTSTYLE
95         .addr   OUTTEXT
96         .addr   0               ; IRQ entry is unused
97
98 ; ------------------------------------------------------------------------
99
100         .bss
101
102 ; Absolute variables used in the code
103
104 ERROR:  .res    1               ; Error code
105 MIX:    .res    1               ; 4 lines of text
106
107 ; Line routine stuff
108
109 COUNT:  .res    2
110 NY:     .res    2
111 DX:     .res    1
112 DY:     .res    1
113 AX:     .res    1
114 AY:     .res    1
115
116 ; ------------------------------------------------------------------------
117
118         .rodata
119
120 ; Constants and tables
121
122 DEFPALETTE: .byte $00, $01, $02, $03, $04, $05, $06, $07
123             .byte $08, $09, $0A, $0B, $0C, $0D, $0E, $0F
124
125 MAXY:   .byte 47, 39
126
127 ; ------------------------------------------------------------------------
128
129         .code
130
131 ; INIT: Changes an already installed device from text mode to graphics mode.
132 ; Note that INIT/DONE may be called multiple times while the driver
133 ; is loaded, while INSTALL is only called once, so any code that is needed
134 ; to initializes variables and so on must go here. Setting palette and
135 ; clearing the screen is not needed because this is called by the graphics
136 ; kernel later.
137 ; The graphics kernel will never call INIT when a graphics mode is already
138 ; active, so there is no need to protect against that.
139 ; Must set an error code: YES
140 INIT:
141         ; Switch into graphics mode
142         bit     $C082           ; Switch in ROM
143         jsr     SETGR
144         bit     MIXCLR
145         bit     $C080           ; Switch in LC bank 2 for R/O
146
147         ; Done, reset the error code
148         lda     #TGI_ERR_OK
149         sta     ERROR
150         sta     MIX
151
152         ; Fall through
153
154 ; INSTALL routine. Is called after the driver is loaded into memory. May
155 ; initialize anything that has to be done just once. Is probably empty
156 ; most of the time.
157 ; Must set an error code: NO
158 INSTALL:
159         ; Fall through
160
161 ; UNINSTALL routine. Is called before the driver is removed from memory. May
162 ; clean up anything done by INSTALL but is probably empty most of the time.
163 ; Must set an error code: NO
164 UNINSTALL:
165         ; Fall through
166
167 ; SETVIEWPAGE: Set the visible page. Called with the new page in A (0..n).
168 ; The page number is already checked to be valid by the graphics kernel.
169 ; Must set an error code: NO (will only be called if page ok)
170 SETVIEWPAGE:
171         ; Fall through
172
173 ; SETDRAWPAGE: Set the drawable page. Called with the new page in A (0..n).
174 ; The page number is already checked to be valid by the graphics kernel.
175 ; Must set an error code: NO (will only be called if page ok)
176 SETDRAWPAGE:
177         ; Fall through
178
179 ; TEXTSTYLE: Set the style used when calling OUTTEXT. Text scaling in X and Y
180 ; direction is passend in X/Y, the text direction is passed in A.
181 ; Must set an error code: NO
182 TEXTSTYLE:
183         ; Fall through
184
185 ; OUTTEXT: Output text at X/Y = ptr1/ptr2 using the current color and the
186 ; current text style. The text to output is given as a zero terminated
187 ; string with address in ptr3.
188 ; Must set an error code: NO
189 OUTTEXT:
190         rts
191
192 ; DONE: Will be called to switch the graphics device back into text mode.
193 ; The graphics kernel will never call DONE when no graphics mode is active,
194 ; so there is no need to protect against that.
195 ; Must set an error code: NO
196 DONE:
197         bit     $C082           ; Switch in ROM
198         jsr     TEXT
199         jsr     HOME
200         bit     $C080           ; Switch in LC bank 2 for R/O
201         rts
202
203 ; GETERROR: Return the error code in A and clear it.
204 GETERROR:
205         lda     ERROR
206         ldx     #TGI_ERR_OK
207         stx     ERROR
208         rts
209
210 ; CLEAR: Clears the screen.
211 ; Must set an error code: NO
212 CLEAR:
213         bit     $C082           ; Switch in ROM
214         lda     COLOR           ; Save current drawing color
215         pha
216         ldx     MIX
217         ldy     MAXY,x          ; Max Y depends on 4 lines of text
218         jsr     CLRSC2
219         pla
220         sta     COLOR           ; Save current drawing color
221         bit     $C080           ; Switch in LC bank 2 for R/O
222         rts
223
224 ; SETCOLOR: Set the drawing color (in A). The new color is already checked
225 ; to be in a valid range (0..maxcolor-1).
226 ; Must set an error code: NO (will only be called if color ok)
227 SETCOLOR:
228         bit     $C082           ; Switch in ROM
229         jsr     SETCOL
230         bit     $C080           ; Switch in LC bank 2 for R/O
231         rts
232
233 ; CONTROL: Platform/driver specific entry point.
234 ; Must set an error code: YES
235 CONTROL:
236         ; Check data msb and code to be 0
237         ora     ptr1+1
238         bne     err
239
240         ; Check data lsb to be [0..1]
241         lda     ptr1
242         cmp     #1+1
243         bcs     err
244         bit     $C082           ; Switch in ROM
245
246         ; Switch 4 lines of text
247         tax
248         .assert MIXCLR + 1 = MIXSET, error
249         lda     MIXCLR,x        ; No BIT absolute,X available
250
251         ; Save current switch setting
252         txa
253         sta     MIX
254         bne     text
255
256         ; Clear 8 lines of graphics
257         lda     COLOR           ; Save current drawing color
258         pha
259         lda     #39             ; Rightmost column
260         sta     H2
261         ldx     #40             ; First line
262 :       txa
263         ldy     #$00            ; Leftmost column
264         sty     COLOR           ; Black
265         jsr     HLINE           ; Preserves X
266         inx
267         cpx     #47+1           ; Last line
268         bcc     :-
269         pla
270         sta     COLOR           ; Save current drawing color
271         bcs     :+              ; Branch always
272
273         ; Clear 4 lines of text
274 text:   jsr     HOME
275 :       bit     $C080           ; Switch in LC bank 2 for R/O
276
277         ; Done, reset the error code
278         lda     #TGI_ERR_OK
279         beq     :+              ; Branch always
280         
281         ; Done, set the error code
282 err:    lda     #TGI_ERR_INV_ARG
283 :       sta     ERROR
284         rts
285
286 ; SETPALETTE: Set the palette (not available with all drivers/hardware).
287 ; A pointer to the palette is passed in ptr1. Must set an error if palettes
288 ; are not supported
289 ; Must set an error code: YES
290 SETPALETTE:
291         lda     #TGI_ERR_INV_FUNC
292         sta     ERROR
293         rts
294
295 ; GETPALETTE: Return the current palette in A/X. Even drivers that cannot
296 ; set the palette should return the default palette here, so there's no
297 ; way for this function to fail.
298 ; Must set an error code: NO
299 GETPALETTE:
300         ; Fall through
301
302 ; GETDEFPALETTE: Return the default palette for the driver in A/X. All
303 ; drivers should return something reasonable here, even drivers that don't
304 ; support palettes, otherwise the caller has no way to determine the colors
305 ; of the (not changeable) palette.
306 ; Must set an error code: NO (all drivers must have a default palette)
307 GETDEFPALETTE:
308         lda     #<DEFPALETTE
309         ldx     #>DEFPALETTE
310         rts
311
312 ; SETPIXEL: Draw one pixel at X1/Y1 = ptr1/ptr2 with the current drawing
313 ; color. The coordinates passed to this function are never outside the
314 ; visible screen area, so there is no need for clipping inside this function.
315 ; Must set an error code: NO
316 SETPIXEL:
317         bit     $C082           ; Switch in ROM
318         ldy     X1
319         lda     Y1
320         jsr     PLOT
321         bit     $C080           ; Switch in LC bank 2 for R/O
322         rts
323
324 ; GETPIXEL: Read the color value of a pixel and return it in A/X. The
325 ; coordinates passed to this function are never outside the visible screen
326 ; area, so there is no need for clipping inside this function.
327 GETPIXEL:
328         bit     $C082           ; Switch in ROM
329         ldy     X1
330         lda     Y1
331         jsr     SCRN
332         ldx     #$00
333         bit     $C080           ; Switch in LC bank 2 for R/O
334         rts
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 ; Must set an error code: NO
339 LINE:
340         ; nx = abs (x2 - x1)
341         sec
342         lda     X2
343         sbc     X1
344         sta     NX
345         lda     X2+1
346         sbc     X1+1
347         tay
348         lda     NX
349         jsr     abs
350         sta     NX
351         sty     NX+1
352
353         ; ny = abs (y2 - y1)
354         sec
355         lda     Y2
356         sbc     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
366         ; if (x2 >= x1)
367         ldx     #X2
368         lda     X1
369         ldy     X1+1
370         jsr     icmp
371         bcc     :+
372
373         ;    dx = 1
374         lda     #$01
375         bne     :++
376
377         ; else
378         ;    dx = -1
379 :       lda     #$FF
380 :       sta     DX
381
382         ; if (y2 >= y1)
383         ldx     #Y2
384         lda     Y1
385         ldy     Y1+1
386         jsr     icmp
387         bcc     :+
388
389         ;    dy = 1
390         lda     #$01
391         bne     :++
392
393         ; else
394         ;    dy = -1
395 :       lda     #$FF
396 :       sta     DY
397
398         ; err = ax = ay = 0
399         lda     #$00
400         sta     ERR
401         sta     ERR+1
402         sta     AX
403         sta     AY
404
405         ; if (nx < ny) {
406         ldx     #NX
407         lda     NY
408         ldy     NY+1
409         jsr     icmp
410         bcs     :+
411
412         ;    nx <-> ny
413         lda     NX
414         ldx     NY
415         sta     NY
416         stx     NX
417         lda     NX+1
418         ldx     NY+1
419         sta     NY+1
420         stx     NX+1
421
422         ;    ax = dx
423         lda     DX
424         sta     AX
425
426         ;    ay = dy
427         lda     DY
428         sta     AY
429
430         ;    dx = dy = 0 }
431         lda     #$00
432         sta     DX
433         sta     DY
434
435         ; ny = - ny
436 :       lda     NY
437         ldy     NY+1
438         jsr     neg
439         sta     NY
440         sty     NY+1
441
442         ; for (count = nx; count > 0; --count) {
443         lda     NX
444         ldx     NX+1
445         sta     COUNT
446         stx     COUNT+1
447 for:    lda     COUNT           ; count > 0
448         ora     COUNT+1
449         bne     :+
450         rts
451
452         ;    setpixel (X1, Y1)
453 :       jsr     SETPIXEL
454
455         ;    pb = err + ny
456         clc
457         lda     ERR
458         adc     NY
459         sta     PB
460         lda     ERR+1
461         adc     NY+1
462         sta     PB+1
463         tax
464
465         ;    ub = pb + nx
466         clc
467         lda     PB
468         adc     NX
469         sta     UB
470         txa
471         adc     NX+1
472         sta     UB+1
473
474         ;    x1 = x1 + dx
475         ldx     #$00
476         lda     DX
477         bpl     :+
478         dex
479 :       clc
480         adc     X1
481         sta     X1
482         txa
483         adc     X1+1
484         sta     X1+1
485
486         ;    y1 = y1 + ay
487         ldx     #$00
488         lda     AY
489         bpl     :+
490         dex
491 :       clc
492         adc     Y1
493         sta     Y1
494         txa
495         adc     Y1+1
496         sta     Y1+1
497
498         ;    if (abs (pb) < abs (ub)) {
499         lda     PB
500         ldy     PB+1
501         jsr     abs
502         sta     TEMP3
503         sty     TEMP4
504         lda     UB
505         ldy     UB+1
506         jsr     abs
507         ldx     #TEMP3
508         jsr     icmp
509         bpl     :+
510
511         ;       err = pb }
512         lda     PB
513         ldx     PB+1
514         jmp     next
515
516         ;    else { x1 = x1 + ax
517 :       ldx     #$00
518         lda     AX
519         bpl     :+
520         dex
521 :       clc
522         adc     X1
523         sta     X1
524         txa
525         adc     X1+1
526         sta     X1+1
527
528         ;       y1 = y1 + dy
529         ldx     #$00
530         lda     DY
531         bpl     :+
532         dex
533 :       clc
534         adc     Y1
535         sta     Y1
536         txa
537         adc     Y1+1
538         sta     Y1+1
539
540         ;       err = ub }
541         lda     UB
542         ldx     UB+1
543 next:   sta     ERR
544         stx     ERR+1
545
546         ; } (--count)
547         lda     COUNT
548         sec
549         sbc     #$01
550         sta     COUNT
551         bcc     :+
552         jmp     for
553 :       dec     COUNT+1
554         jmp     for
555
556 ; BAR: Draw a filled rectangle with the corners X1/Y1, X2/Y2, where
557 ; X1/Y1 = ptr1/ptr2 and X2/Y2 = ptr3/ptr4 using the current drawing color.
558 ; Contrary to most other functions, the graphics kernel will sort and clip
559 ; the coordinates before calling the driver, so on entry the following
560 ; conditions are valid:
561 ;       X1 <= X2
562 ;       Y1 <= Y2
563 ;       (X1 >= 0) && (X1 < XRES)
564 ;       (X2 >= 0) && (X2 < XRES)
565 ;       (Y1 >= 0) && (Y1 < YRES)
566 ;       (Y2 >= 0) && (Y2 < YRES)
567 ; Must set an error code: NO
568 BAR:
569         bit     $C082           ; Switch in ROM
570         inc     Y2
571         ldx     X2
572         stx     H2
573 :       ldy     X1
574         lda     Y1
575         jsr     HLINE
576         inc     Y1
577         lda     Y2
578         cmp     Y1
579         bne     :-
580         bit     $C080           ; Switch in LC bank 2 for R/O
581         rts
582
583 ; Copies of some runtime routines
584
585 abs:
586         ; A/Y := abs (A/Y)
587         cpy     #$00
588         bpl     :+
589         
590         ; A/Y := neg (A/Y)
591 neg:    clc
592         eor     #$FF
593         adc     #$01
594         pha
595         tya
596         eor     #$FF
597         adc     #$00
598         tay
599         pla
600 :       rts
601
602 icmp:
603         ; Compare A/Y to zp,X
604         sta     TEMP            ; TEMP/TEMP2 - arg2
605         sty     TEMP2
606         lda     $00,x
607         pha
608         lda     $01,x
609         tay
610         pla
611         tax
612         tya                     ; X/A - arg1 (a = high)
613
614         sec
615         sbc     TEMP2
616         bne     :++
617         cpx     TEMP
618         beq     :+
619         adc     #$FF
620         ora     #$01
621 :       rts
622 :       bvc     :+
623         eor     #$FF
624         ora     #$01
625 :       rts