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