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