]> git.sur5r.net Git - cc65/blob - libsrc/c128/c128-640-480-2.s
Removed tgi_load() and all corresponding infrastructure. The idea behind tgi_load...
[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 ; 2004-04-04, Greg King
7 ;
8 ; NOTES:
9 ; For any smart monkey that will try to optimize this: PLEASE do tests on
10 ; real VDC, not only VICE.
11 ;
12 ; Only DONE routine contains C128-mode specific stuff, everything else will
13 ; work in C64-mode of C128 (C64 needs full VDC init then).
14 ;
15 ; With special initialization and CALC we can get 320x200 double-pixel mode.
16 ;
17 ; Color translation values for BROWN and GRAY3 are obviously wrong, they
18 ; could be replaced by equiv. of ORANGE and GRAY2 but this would give only
19 ; 14 of 16 colors available.
20 ;
21 ; Register 25 ($19) is said to require different value for VDC v1, but I
22 ; couldn't find what it should be.
23
24         .include        "zeropage.inc"
25
26         .include        "tgi-kernel.inc"
27         .include        "tgi-error.inc"
28
29
30         .macpack        generic
31
32 ; ------------------------------------------------------------------------
33 ; Constants
34
35 VDC_ADDR_REG      = $D600                 ; VDC address
36 VDC_DATA_REG      = $D601                 ; VDC data
37
38 VDC_DSP_HI        = 12                    ; registers used
39 VDC_DSP_LO        = 13
40 VDC_DATA_HI       = 18
41 VDC_DATA_LO       = 19
42 VDC_VSCROLL       = 24
43 VDC_HSCROLL       = 25
44 VDC_COLORS        = 26
45 VDC_CSET          = 28
46 VDC_COUNT         = 30
47 VDC_DATA          = 31
48
49 ; ------------------------------------------------------------------------
50 ; Header. Includes jump table and constants.
51
52 .segment        "JUMPTABLE"
53
54 ; First part of the header is a structure that has a magic and defines the
55 ; capabilities of the driver
56
57         .byte   $74, $67, $69           ; "tgi"
58         .byte   TGI_API_VERSION         ; TGI API version number
59 xres:   .word   640                     ; X resolution
60 yres:   .word   480                     ; Y resolution
61         .byte   2                       ; Number of drawing colors
62 pages:  .byte   0                       ; Number of screens available
63         .byte   8                       ; System font X size
64         .byte   8                       ; System font Y size
65         .word   $0100                   ; Aspect ratio (based on 4/3 display)
66
67 ; Next comes the jump table. Currently all entries must be valid and may point
68 ; to an RTS for test versions (function not implemented).
69
70         .addr   INSTALL
71         .addr   UNINSTALL
72         .addr   INIT
73         .addr   DONE
74         .addr   GETERROR
75         .addr   CONTROL
76         .addr   CLEAR
77         .addr   SETVIEWPAGE
78         .addr   SETDRAWPAGE
79         .addr   SETCOLOR
80         .addr   SETPALETTE
81         .addr   GETPALETTE
82         .addr   GETDEFPALETTE
83         .addr   SETPIXEL
84         .addr   GETPIXEL
85         .addr   LINE
86         .addr   BAR
87         .addr   TEXTSTYLE
88         .addr   OUTTEXT
89         .addr   0                       ; IRQ entry is unused
90
91 ; ------------------------------------------------------------------------
92 ; Data.
93
94 ; Variables mapped to the zero page segment variables. Some of these are
95 ; used for passing parameters to the driver.
96
97 X1              = ptr1
98 Y1              = ptr2
99 X2              = ptr3
100 Y2              = ptr4
101
102 ADDR            = tmp1
103 TEMP            = tmp3
104 TEMP2           = tmp4          ; HORLINE
105 TEMP3           = sreg          ; HORLINE
106
107 ; Absolute variables used in the code
108
109 .bss
110
111 ERROR:          .res    1       ; Error code
112 PALETTE:        .res    2       ; The current palette
113
114 BITMASK:        .res    1       ; $00 = clear, $FF = set pixels
115
116 OLDCOLOR:       .res    1       ; colors before entering gfx mode
117
118 ; Text output stuff
119 TEXTMAGX:       .res    1
120 TEXTMAGY:       .res    1
121 TEXTDIR:        .res    1
122
123 ; Constants and tables
124
125 .rodata
126
127 DEFPALETTE:     .byte   $00, $0f        ; White on black
128 PALETTESIZE     = * - DEFPALETTE
129
130 BITTAB:         .byte   $80,$40,$20,$10,$08,$04,$02,$01
131
132 BITMASKL:       .byte   %11111111, %01111111, %00111111, %00011111
133                 .byte   %00001111, %00000111, %00000011, %00000001
134
135 BITMASKR:       .byte   %10000000, %11000000, %11100000, %11110000
136                 .byte   %11111000, %11111100, %11111110, %11111111
137
138 ; color translation table (indexed by VIC color)
139 COLTRANS:       .byte $00, $0f, $08, $06, $0a, $04, $02, $0c
140                 .byte $0d, $0b, $09, $01, $0e, $05, $03, $07
141                 ; colors BROWN and GRAY3 are wrong
142
143 ; VDC initialization table (reg),(val),...,$ff
144 InitVDCTab:
145                 .byte VDC_DSP_HI, 0             ; viewpage 0 as default
146                 .byte VDC_DSP_LO, 0
147                 .byte VDC_HSCROLL, $87
148                 .byte 2, $66
149                 .byte 4, $4c
150                 .byte 5, $06
151                 .byte 6, $4c
152                 .byte 7, $47
153                 .byte 8, $03
154                 .byte 9, $06
155                 .byte 27, $00
156                 .byte $ff
157
158 SCN80CLR:       .byte 27,88,147,27,88,0
159
160 .code
161
162 ; ------------------------------------------------------------------------
163 ; INSTALL routine. Is called after the driver is loaded into memory. May
164 ; initialize anything that has to be done just once. Is probably empty
165 ; most of the time.
166 ;
167 ; Must set an error code: NO
168 ;
169
170 INSTALL:
171         ; check for VDC version and update register $19 value
172
173         ; check for VDC ram size and update number of available screens
174
175         ldx     #VDC_CSET       ; determine size of RAM...
176         jsr     VDCReadReg
177         sta     tmp1
178         ora     #%00010000
179         jsr     VDCWriteReg     ; turn on 64k
180
181         jsr     settestadr1     ; save original value of test byte
182         jsr     VDCReadByte
183         sta     tmp2
184
185         lda     #$55            ; write $55 here
186         ldy     #ptr1
187         jsr     test64k         ; read it here and there
188         lda     #$aa            ; write $aa here
189         ldy     #ptr2
190         jsr     test64k         ; read it here and there
191
192         jsr     settestadr1
193         lda     tmp2
194         jsr     VDCWriteByte    ; restore original value of test byte
195
196         lda     ptr1            ; do bytes match?
197         cmp     ptr1+1
198         bne     @have64k
199         lda     ptr2
200         cmp     ptr2+1
201         bne     @have64k
202
203         ldx     #VDC_CSET
204         lda     tmp1
205         jsr     VDCWriteReg     ; restore 16/64k flag
206         jmp     @endok          ; and leave default values for 16k
207
208 @have64k:
209         lda     #1
210         sta     pages
211 @endok:
212         rts
213
214 test64k:
215         sta     tmp1
216         sty     ptr3
217         lda     #0
218         sta     ptr3+1
219         jsr     settestadr1
220         lda     tmp1
221         jsr     VDCWriteByte            ; write $55
222         jsr     settestadr1
223         jsr     VDCReadByte             ; read here
224         pha
225         jsr     settestadr2
226         jsr     VDCReadByte             ; and there
227         ldy     #1
228         sta     (ptr3),y
229         pla
230         dey
231         sta     (ptr3),y
232         rts
233
234 settestadr1:
235         ldy     #$02                    ; test page 2 (here)
236         .byte   $2c
237 settestadr2:
238         ldy     #$42                    ; or page 64+2 (there)
239         lda     #0
240         jmp     VDCSetSourceAddr
241
242 ; ------------------------------------------------------------------------
243 ; UNINSTALL routine. Is called before the driver is removed from memory. May
244 ; clean up anything done by INSTALL but is probably empty most of the time.
245 ;
246 ; Must set an error code: NO
247 ;
248
249 UNINSTALL:
250         rts
251
252
253 ; ------------------------------------------------------------------------
254 ; INIT: Changes an already installed device from text mode to graphics
255 ; mode.
256 ; Note that INIT/DONE may be called multiple times while the driver
257 ; is loaded, while INSTALL is only called once, so any code that is needed
258 ; to initializes variables and so on must go here. Setting palette and
259 ; clearing the screen is not needed because this is called by the graphics
260 ; kernel later.
261 ; The graphics kernel will never call INIT when a graphics mode is already
262 ; active, so there is no need to protect against that.
263 ;
264 ; Must set an error code: YES
265 ;
266
267 INIT:
268         lda     pages                   ; is there enough memory?
269         bne     @L1                     ; Jump if there is one screen
270         lda     #TGI_ERR_INV_MODE       ; Error
271         bne     @L9
272
273 ; Initialize variables
274
275 @L1:    ldx     #$FF
276         stx     BITMASK
277
278 ; Remeber current color value
279         ldx     #VDC_COLORS
280         jsr     VDCReadReg
281         sta     OLDCOLOR
282
283 ; Switch into graphics mode (set view page 0)
284
285         ldy     #0
286 @L2:    ldx     InitVDCTab,y
287         bmi     @L3
288         iny
289         lda     InitVDCTab,y
290         jsr     VDCWriteReg
291         iny
292         bne     @L2
293 @L3:
294
295 ; Done, reset the error code
296
297         lda     #TGI_ERR_OK
298 @L9:    sta     ERROR
299         rts
300
301 ; ------------------------------------------------------------------------
302 ; DONE: Will be called to switch the graphics device back into text mode.
303 ; The graphics kernel will never call DONE when no graphics mode is active,
304 ; so there is no need to protect against that.
305 ;
306 ; Must set an error code: NO
307 ;
308
309 DONE:
310         ; This part is C128-mode specific
311         jsr $e179               ; reload character set and setup VDC
312         jsr $ff62
313         lda $d7                 ; in 80-columns?
314         bne @L01
315 @L0:    lda SCN80CLR,y
316         beq @L1
317         jsr $ffd2               ; print \xe,clr,\xe
318         iny
319         bne @L0
320 @L01:   lda #147
321         jsr $ffd2               ; print clr
322 @L1:    lda #0                  ; restore view page
323         ldx #VDC_DSP_HI
324         jsr VDCWriteReg
325         lda OLDCOLOR
326         ldx #VDC_COLORS
327         jsr VDCWriteReg         ; restore color (background)
328         lda #$47
329         ldx #VDC_HSCROLL
330         jmp VDCWriteReg         ; switch to text screen
331
332 ; ------------------------------------------------------------------------
333 ; GETERROR: Return the error code in A and clear it.
334
335 GETERROR:
336         ldx     #TGI_ERR_OK
337         lda     ERROR
338         stx     ERROR
339         rts
340
341 ; ------------------------------------------------------------------------
342 ; CONTROL: Platform/driver specific entry point.
343 ;
344 ; Must set an error code: YES
345 ;
346
347 CONTROL:
348         lda     #TGI_ERR_INV_FUNC
349         sta     ERROR
350         rts
351
352 ; ------------------------------------------------------------------------
353 ; CLEAR: Clears the screen.
354 ;
355 ; Must set an error code: NO
356 ;
357
358 CLEAR:
359         lda     #0
360         tay
361         jsr     VDCSetSourceAddr
362         lda     #0
363         ldx     #VDC_VSCROLL
364         jsr     VDCWriteReg                     ; set fill mode
365         lda     #0
366         jsr     VDCWriteByte                    ; put 1rst byte (fill value)
367         ldy     #159                            ; 159 times
368         lda     #0                              ; 256 bytes
369         ldx     #VDC_COUNT
370 @L1:    jsr     VDCWriteReg
371         dey
372         bne     @L1
373         rts
374
375 ; ------------------------------------------------------------------------
376 ; SETVIEWPAGE: Set the visible page. Called with the new page in A (0..n).
377 ; The page number is already checked to be valid by the graphics kernel.
378 ;
379 ; Must set an error code: NO (will only be called if page ok)
380 ;
381
382 SETVIEWPAGE:
383         rts
384
385 ; ------------------------------------------------------------------------
386 ; SETDRAWPAGE: Set the drawable page. Called with the new page in A (0..n).
387 ; The page number is already checked to be valid by the graphics kernel.
388 ;
389 ; Must set an error code: NO (will only be called if page ok)
390 ;
391
392 SETDRAWPAGE:
393         rts
394
395 ; ------------------------------------------------------------------------
396 ; SETCOLOR: Set the drawing color (in A). The new color is already checked
397 ; to be in a valid range (0..maxcolor-1).
398 ;
399 ; Must set an error code: NO (will only be called if color ok)
400 ;
401
402 SETCOLOR:
403         tax
404         beq     @L1
405         lda     #$FF
406 @L1:    sta     BITMASK
407         rts
408
409 ; ------------------------------------------------------------------------
410 ; SETPALETTE: Set the palette (not available with all drivers/hardware).
411 ; A pointer to the palette is passed in ptr1. Must set an error if palettes
412 ; are not supported
413 ;
414 ; Must set an error code: YES
415 ;
416
417 SETPALETTE:
418         ldy     #PALETTESIZE - 1
419 @L1:    lda     (ptr1),y        ; Copy the palette
420         and     #$0F            ; Make a valid color
421         sta     PALETTE,y
422         dey
423         bpl     @L1
424
425 ; Get the color entries from the palette
426
427         ldy     PALETTE+1       ; Foreground color
428         lda     COLTRANS,y
429         asl     a
430         asl     a
431         asl     a
432         asl     a
433         ldy     PALETTE         ; Background color
434         ora     COLTRANS,y
435
436         ldx     #VDC_COLORS
437         jsr     VDCWriteReg
438         lda     #TGI_ERR_OK     ; Clear error code
439         sta     ERROR
440         rts
441
442 ; ------------------------------------------------------------------------
443 ; GETPALETTE: Return the current palette in A/X. Even drivers that cannot
444 ; set the palette should return the default palette here, so there's no
445 ; way for this function to fail.
446 ;
447 ; Must set an error code: NO
448 ;
449
450 GETPALETTE:
451         lda     #<PALETTE
452         ldx     #>PALETTE
453         rts
454
455 ; ------------------------------------------------------------------------
456 ; GETDEFPALETTE: Return the default palette for the driver in A/X. All
457 ; drivers should return something reasonable here, even drivers that don't
458 ; support palettes, otherwise the caller has no way to determine the colors
459 ; of the (not changeable) palette.
460 ;
461 ; Must set an error code: NO (all drivers must have a default palette)
462 ;
463
464 GETDEFPALETTE:
465         lda     #<DEFPALETTE
466         ldx     #>DEFPALETTE
467         rts
468
469 ; ------------------------------------------------------------------------
470 ; SETPIXEL: Draw one pixel at X1/Y1 = ptr1/ptr2 with the current drawing
471 ; color. The coordinates passed to this function are never outside the
472 ; visible screen area, so there is no need for clipping inside this function.
473 ;
474 ; Must set an error code: NO
475 ;
476
477 SETPIXEL:
478         jsr     CALC            ; Calculate coordinates
479
480         stx     TEMP
481         lda     ADDR
482         ldy     ADDR+1
483         jsr     VDCSetSourceAddr
484         jsr     VDCReadByte
485         ldx     TEMP
486
487         sta     TEMP
488         eor     BITMASK
489         and     BITTAB,X
490         eor     TEMP
491         pha
492         lda     ADDR
493         ldy     ADDR+1
494         jsr     VDCSetSourceAddr
495         pla
496         jsr     VDCWriteByte
497
498 @L9:    rts
499
500 ; ------------------------------------------------------------------------
501 ; GETPIXEL: Read the color value of a pixel and return it in A/X. The
502 ; coordinates passed to this function are never outside the visible screen
503 ; area, so there is no need for clipping inside this function.
504
505
506 GETPIXEL:
507         jsr     CALC            ; Calculate coordinates
508
509         stx     TEMP            ; preserve X
510         lda     ADDR
511         ldy     ADDR+1
512         jsr     VDCSetSourceAddr
513         jsr     VDCReadByte
514         ldx     TEMP
515
516         ldy     #$00
517         and     BITTAB,X
518         beq     @L1
519         iny
520
521 @L1:    tya                     ; Get color value into A
522         ldx     #$00            ; Clear high byte
523         rts
524
525 ; ------------------------------------------------------------------------
526 ; BAR: Draw a filled rectangle with the corners X1/Y1, X2/Y2, where
527 ; X1/Y1 = ptr1/ptr2 and X2/Y2 = ptr3/ptr4 using the current drawing color.
528 ; Contrary to most other functions, the graphics kernel will sort and clip
529 ; the coordinates before calling the driver, so on entry the following
530 ; conditions are valid:
531 ;       X1 <= X2
532 ;       Y1 <= Y2
533 ;       (X1 >= 0) && (X1 < XRES)
534 ;       (X2 >= 0) && (X2 < XRES)
535 ;       (Y1 >= 0) && (Y1 < YRES)
536 ;       (Y2 >= 0) && (Y2 < YRES)
537 ;
538 ; Must set an error code: NO
539 ;
540
541 BAR:
542         inc     Y2
543         bne     HORLINE
544         inc     Y2+1
545
546 ; Original code for a horizontal line
547
548 HORLINE:
549         lda X1
550         pha
551         lda X1+1
552         pha
553         jsr CALC                ; get data for LEFT
554         lda BITMASKL,x          ; remember left address and bitmask
555         pha
556         lda ADDR
557         pha
558         lda ADDR+1
559         pha
560
561         lda X2
562         sta X1
563         lda X2+1
564         sta X1+1
565         jsr CALC                ; get data for RIGHT
566         lda BITMASKR,x
567         sta TEMP3
568
569         pla                     ; recall data for LEFT
570         sta X1+1
571         pla
572         sta X1                  ; put left address into X1
573         pla
574
575         cmp #%11111111          ; if left bit <> 0
576         beq @L1
577         sta TEMP2               ; do left byte only...
578         lda X1
579         ldy X1+1
580         jsr VDCSetSourceAddr
581         jsr VDCReadByte
582         sta TEMP
583         eor BITMASK
584         and TEMP2
585         eor TEMP
586         pha
587         lda X1
588         ldy X1+1
589         jsr VDCSetSourceAddr
590         pla
591         jsr VDCWriteByte
592         inc X1                  ; ... and proceed
593         bne @L1
594         inc X1+1
595
596         ; do right byte (if Y2=0 ++ADDR and skip)
597 @L1:    lda TEMP3
598         cmp #%11111111          ; if right bit <> 7
599         bne @L11
600         inc ADDR                ; right bit = 7 - the next one is the last
601         bne @L10
602         inc ADDR+1
603 @L10:   bne @L2
604
605 @L11:   lda ADDR                ; do right byte only...
606         ldy ADDR+1
607         jsr VDCSetSourceAddr
608         jsr VDCReadByte
609         sta TEMP
610         eor BITMASK
611         and TEMP3
612         eor TEMP
613         pha
614         lda ADDR
615         ldy ADDR+1
616         jsr VDCSetSourceAddr
617         pla
618         jsr VDCWriteByte
619
620 @L2:                            ; do the fill in the middle
621         lda ADDR                ; calculate offset in full bytes
622         sec
623         sbc X1
624         beq @L3                 ; if equal - there are no more bytes
625         sta ADDR
626
627         lda X1                  ; setup for the left side
628         ldy X1+1
629         jsr VDCSetSourceAddr
630         lda BITMASK             ; get color
631         jsr VDCWriteByte        ; put 1st value
632         ldx ADDR
633         dex
634         beq @L3                 ; 1 byte already written
635
636         stx ADDR                ; if there are more bytes - fill them...
637         ldx #VDC_VSCROLL
638         lda #0
639         jsr VDCWriteReg         ; setup for fill
640         ldx #VDC_COUNT
641         lda ADDR
642         jsr VDCWriteReg         ; ... fill them NOW!
643
644 @L3:    pla
645         sta X1+1
646         pla
647         sta X1
648
649 ; End of horizontal line code
650
651         inc     Y1
652         bne     @L4
653         inc     Y1+1
654 @L4:    lda     Y1
655         cmp     Y2
656         bne     @L5
657         lda     Y1+1
658         cmp     Y2+1
659         bne     @L5
660         rts
661
662 @L5:    jmp     HORLINE
663
664
665 ; ------------------------------------------------------------------------
666 ; TEXTSTYLE: Set the style used when calling OUTTEXT. Text scaling in X and Y
667 ; direction is passend in X/Y, the text direction is passed in A.
668 ;
669 ; Must set an error code: NO
670 ;
671
672 TEXTSTYLE:
673         stx     TEXTMAGX
674         sty     TEXTMAGY
675         sta     TEXTDIR
676         rts
677
678
679 ; ------------------------------------------------------------------------
680 ; OUTTEXT: Output text at X/Y = ptr1/ptr2 using the current color and the
681 ; current text style. The text to output is given as a zero terminated
682 ; string with address in ptr3.
683 ;
684 ; Must set an error code: NO
685 ;
686
687 OUTTEXT:
688         rts
689
690 ; ------------------------------------------------------------------------
691 ; Calculate all variables to plot the pixel at X1/Y1.
692 ;------------------------
693 ;< X1,Y1 - pixel
694 ;> ADDR - address of card
695 ;> X - bit number (X1 & 7)
696 CALC:
697         lda     Y1
698         pha
699         lda     Y1+1
700         pha
701         lsr
702         ror     Y1              ; Y=Y/2
703         sta     Y1+1
704         sta     ADDR+1
705         lda     Y1
706         asl
707         rol     ADDR+1
708         asl
709         rol     ADDR+1          ; Y*4
710         clc
711         adc     Y1
712         sta     ADDR
713         lda     Y1+1
714         adc     ADDR+1
715         sta     ADDR+1          ; Y*4+Y=Y*5
716         lda     ADDR
717         asl
718         rol     ADDR+1
719         asl
720         rol     ADDR+1
721         asl
722         rol     ADDR+1
723         asl
724         rol     ADDR+1
725         sta     ADDR            ; Y*5*16=Y*80
726         lda     X1+1
727         sta     TEMP
728         lda     X1
729         lsr     TEMP
730         ror
731         lsr     TEMP
732         ror
733         lsr     TEMP
734         ror
735         clc
736         adc     ADDR
737         sta     ADDR
738         lda     ADDR+1          ; ADDR = Y*80+x/8
739         adc     TEMP
740         sta     ADDR+1
741         pla
742         sta     Y1+1
743         pla
744         sta     Y1
745         and     #1
746         beq     @even           ; even line - no offset
747         lda     ADDR
748         clc
749         adc     #<21360
750         sta     ADDR
751         lda     ADDR+1
752         adc     #>21360
753         sta     ADDR+1          ; odd lines are 21360 bytes farther
754 @even:  lda     X1
755         and     #7
756         tax
757         rts
758
759 ;-------------
760 ; VDC helpers
761
762 VDCSetSourceAddr:
763         pha
764         tya
765         ldx     #VDC_DATA_HI
766         jsr     VDCWriteReg
767         pla
768         ldx     #VDC_DATA_LO
769         bne     VDCWriteReg
770
771 VDCReadByte:
772         ldx     #VDC_DATA
773 VDCReadReg:
774         stx     VDC_ADDR_REG
775 @L0:    bit     VDC_ADDR_REG
776         bpl     @L0
777         lda     VDC_DATA_REG
778         rts
779
780 VDCWriteByte:
781         ldx     #VDC_DATA
782 VDCWriteReg:
783         stx     VDC_ADDR_REG
784 @L0:    bit     VDC_ADDR_REG
785         bpl     @L0
786         sta     VDC_DATA_REG
787         rts
788
789 ; ------------------------------------------------------------------------
790
791         .include        "../tgi/tgidrv_line.inc"