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