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