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