mirror of
https://github.com/cc65/cc65.git
synced 2024-08-27 11:29:12 +00:00
682 lines
17 KiB
ArmAsm
682 lines
17 KiB
ArmAsm
;
|
|
; Graphics driver for the 320x200x2 and 640x200x2 modes on GEOS 64/128
|
|
; 2010-08-17, Maciej 'YTM/Elysium' Witkowiak <ytm@elysium.pl>
|
|
; 2010-08-18, Greg King
|
|
|
|
.include "zeropage.inc"
|
|
.include "tgi-kernel.inc"
|
|
.include "tgi-error.inc"
|
|
.include "const.inc"
|
|
.include "jumptab.inc"
|
|
.include "geossym.inc"
|
|
.include "geossym2.inc"
|
|
|
|
.macpack generic
|
|
|
|
; ------------------------------------------------------------------------
|
|
; Constants
|
|
|
|
VDC_ADDR_REG := $D600 ; VDC address
|
|
VDC_DATA_REG := $D601 ; VDC data
|
|
|
|
VDC_DSP_HI = 12 ; registers used
|
|
VDC_DSP_LO = 13
|
|
VDC_DATA_HI = 18
|
|
VDC_DATA_LO = 19
|
|
VDC_VSCROLL = 24
|
|
VDC_HSCROLL = 25
|
|
VDC_COLORS = 26
|
|
VDC_CSET = 28
|
|
VDC_COUNT = 30
|
|
VDC_DATA = 31
|
|
|
|
; ------------------------------------------------------------------------
|
|
; Header. Includes jump table and constants.
|
|
|
|
.segment "JUMPTABLE"
|
|
|
|
; First part of the header is a structure that has a magic signature,
|
|
; and defines the capabilities of the driver.
|
|
|
|
.byte $74, $67, $69 ; "tgi"
|
|
.byte TGI_API_VERSION ; TGI API version number
|
|
.addr $0000 ; Library reference
|
|
xres: .word 320 ; X resolution
|
|
yres: .word 200 ; Y resolution
|
|
.byte 2 ; Number of drawing colors
|
|
pages: .byte 1 ; Number of screens available
|
|
.byte 8 ; System font X size
|
|
.byte 8 ; System font Y size
|
|
aspect: .word $00D4 ; Aspect ratio (based on 4/3 display)
|
|
.byte 0 ; TGI driver flags
|
|
|
|
; Next comes the jump table. With the exception of IRQ, all entries must be
|
|
; valid, and may point to an RTS for test versions (function not implemented).
|
|
|
|
.addr INSTALL
|
|
.addr UNINSTALL
|
|
.addr INIT
|
|
.addr DONE
|
|
.addr GETERROR
|
|
.addr CONTROL
|
|
.addr CLEAR
|
|
.addr SETVIEWPAGE
|
|
.addr SETDRAWPAGE
|
|
.addr SETCOLOR
|
|
.addr SETPALETTE
|
|
.addr GETPALETTE
|
|
.addr GETDEFPALETTE
|
|
.addr SETPIXEL
|
|
.addr GETPIXEL
|
|
.addr LINE
|
|
.addr BAR
|
|
.addr TEXTSTYLE
|
|
.addr OUTTEXT
|
|
.addr 0 ; IRQ entry is unused
|
|
|
|
; ------------------------------------------------------------------------
|
|
; Data.
|
|
|
|
; Variables mapped to the zero-page segment variables. Some of these are
|
|
; used for passing parameters to the driver.
|
|
|
|
X1 = ptr1
|
|
Y1 = ptr2
|
|
X2 = ptr3
|
|
Y2 = ptr4
|
|
|
|
; Absolute variables used in the code
|
|
|
|
.bss
|
|
|
|
SCRBASE:
|
|
.res 1 ; High byte of screen base (64k VDC only)
|
|
|
|
ERROR:
|
|
.res 1 ; Error code
|
|
PALETTE:
|
|
.res 2 ; The current palette
|
|
|
|
BITMASK:
|
|
.res 1 ; $00 = clear, $01 = set pixels
|
|
|
|
OLDCOLOR:
|
|
.res 1 ; colors before entering gfx mode
|
|
|
|
; Text output stuff
|
|
TEXTMAGX:
|
|
.res 1
|
|
TEXTMAGY:
|
|
.res 1
|
|
TEXTDIR:
|
|
.res 1
|
|
|
|
; Constants and tables
|
|
|
|
.rodata
|
|
|
|
DEFPALETTE:
|
|
.byte $00, $0f ; White on black
|
|
PALETTESIZE = * - DEFPALETTE
|
|
|
|
; color translation table (indexed by VIC color)
|
|
COLTRANS:
|
|
.byte $00, $0f, $08, $06, $0a, $04, $02, $0c
|
|
.byte $0d, $0b, $09, $01, $0e, $05, $03, $07
|
|
; colors BROWN and GRAY3 are wrong
|
|
|
|
.code
|
|
|
|
; ------------------------------------------------------------------------
|
|
; INSTALL routine. Is called after the driver is loaded into memory. May
|
|
; initialize anything that has to be done just once. Is probably empty
|
|
; most of the time.
|
|
;
|
|
; Must set an error code: NO
|
|
;
|
|
|
|
INSTALL:
|
|
lda version ; if GEOS 1.0...
|
|
and #$f0
|
|
cmp #$10
|
|
beq @L40
|
|
lda c128Flag ; at least GEOS 2.0, but we're on C128?
|
|
bpl @L40
|
|
lda graphMode ; GEOS 2.0, C128, but is 80 column screen enabled?
|
|
bmi @L80
|
|
@L40: rts ; leave default values for 40 column screen
|
|
|
|
; check for VDC version and update register $19 value
|
|
|
|
@L80:
|
|
; double the x resolution and halve the aspect ratio
|
|
|
|
asl xres
|
|
rol xres+1
|
|
|
|
lsr aspect+1
|
|
ror aspect
|
|
|
|
; update number of available screens
|
|
|
|
ldx #VDC_CSET ; determine size of RAM...
|
|
jsr VDCReadReg
|
|
sta tmp1
|
|
ora #%00010000
|
|
jsr VDCWriteReg ; turn on 64k
|
|
|
|
jsr settestadr1 ; save original value of test byte
|
|
jsr VDCReadByte
|
|
sta tmp2
|
|
|
|
lda #$55 ; write $55 here
|
|
ldy #ptr1
|
|
jsr test64k ; read it here and there
|
|
lda #$aa ; write $aa here
|
|
ldy #ptr2
|
|
jsr test64k ; read it here and there
|
|
|
|
jsr settestadr1
|
|
lda tmp2
|
|
jsr VDCWriteByte ; restore original value of test byte
|
|
|
|
lda ptr1 ; do bytes match?
|
|
cmp ptr1+1
|
|
bne @have64k
|
|
lda ptr2
|
|
cmp ptr2+1
|
|
bne @have64k
|
|
|
|
ldx #VDC_CSET
|
|
lda tmp1
|
|
jsr VDCWriteReg ; restore 16/64k flag
|
|
jmp @endok ; and leave default values for 16k
|
|
|
|
@have64k:
|
|
lda #4
|
|
sta pages
|
|
@endok:
|
|
lda #0
|
|
sta SCRBASE ; draw page 0 as default
|
|
rts
|
|
|
|
test64k:
|
|
sta tmp1
|
|
sty ptr3
|
|
lda #0
|
|
sta ptr3+1
|
|
jsr settestadr1
|
|
lda tmp1
|
|
jsr VDCWriteByte ; write $55
|
|
jsr settestadr1
|
|
jsr VDCReadByte ; read here
|
|
pha
|
|
jsr settestadr2
|
|
jsr VDCReadByte ; and there
|
|
ldy #1
|
|
sta (ptr3),y
|
|
pla
|
|
dey
|
|
sta (ptr3),y
|
|
rts
|
|
|
|
settestadr1:
|
|
ldy #$02 ; test page 2 (here)
|
|
.byte $2c
|
|
settestadr2:
|
|
ldy #$42 ; or page 64+2 (there)
|
|
lda #0
|
|
jmp VDCSetSourceAddr
|
|
|
|
; ------------------------------------------------------------------------
|
|
; UNINSTALL routine. Is called before the driver is removed from memory. May
|
|
; clean up anything done by INSTALL but is probably empty most of the time.
|
|
;
|
|
; Must set an error code: NO
|
|
;
|
|
|
|
UNINSTALL:
|
|
rts
|
|
|
|
|
|
; ------------------------------------------------------------------------
|
|
; INIT: Changes an already installed device from text mode to graphics
|
|
; mode.
|
|
; Note that INIT/DONE may be called multiple times while the driver
|
|
; is loaded, while INSTALL is only called once, so any code that is needed
|
|
; to initializes variables and so on must go here. Setting palette and
|
|
; clearing the screen is not needed because this is called by the graphics
|
|
; kernel later.
|
|
; The graphics kernel will never call INIT when a graphics mode is already
|
|
; active, so there is no need to protect against that.
|
|
;
|
|
; Must set an error code: YES
|
|
;
|
|
|
|
INIT:
|
|
ldx #$01
|
|
stx BITMASK ; solid black as pattern
|
|
lda #1
|
|
jsr SetPattern
|
|
lda #ST_WR_FORE ; write only on foreground
|
|
sta dispBufferOn
|
|
|
|
lda graphMode
|
|
bmi @L80
|
|
|
|
; Remember current color value (40 columns)
|
|
lda screencolors
|
|
sta OLDCOLOR
|
|
jmp @L99
|
|
|
|
; Remember current color value (80 columns)
|
|
@L80: lda scr80colors
|
|
sta OLDCOLOR
|
|
@L99: lda #0
|
|
jsr SETVIEWPAGE ; switch into viewpage 0
|
|
|
|
; Done, reset the error code
|
|
|
|
lda #TGI_ERR_OK
|
|
sta ERROR
|
|
rts
|
|
|
|
; ------------------------------------------------------------------------
|
|
; DONE: Will be called to switch the graphics device back into text mode.
|
|
; The graphics kernel will never call DONE when no graphics mode is active,
|
|
; so there is no need to protect against that.
|
|
;
|
|
; Must set an error code: NO
|
|
;
|
|
|
|
DONE:
|
|
lda #0
|
|
jsr SETVIEWPAGE ; switch into viewpage 0
|
|
|
|
lda graphMode
|
|
bmi @L80
|
|
|
|
lda OLDCOLOR
|
|
sta screencolors ; restore color for 40 columns
|
|
ldx #0
|
|
@L1: sta COLOR_MATRIX,x
|
|
sta COLOR_MATRIX+$0100,x
|
|
sta COLOR_MATRIX+$0200,x
|
|
sta COLOR_MATRIX+1000-256,x
|
|
inx
|
|
bne @L1
|
|
rts
|
|
|
|
@L80: lda OLDCOLOR ; restore color for 80 columns
|
|
ldx #VDC_COLORS
|
|
jmp VDCWriteReg
|
|
|
|
; ------------------------------------------------------------------------
|
|
; GETERROR: Return the error code in A and clear it.
|
|
|
|
GETERROR:
|
|
ldx #TGI_ERR_OK
|
|
lda ERROR
|
|
stx ERROR
|
|
rts
|
|
|
|
; ------------------------------------------------------------------------
|
|
; CONTROL: Platform/driver specific entry point.
|
|
;
|
|
; Must set an error code: YES
|
|
;
|
|
|
|
CONTROL:
|
|
lda #TGI_ERR_INV_FUNC
|
|
sta ERROR
|
|
rts
|
|
|
|
; ------------------------------------------------------------------------
|
|
; CLEAR: Clears the screen.
|
|
;
|
|
; Must set an error code: NO
|
|
;
|
|
|
|
CLEAR:
|
|
lda curPattern
|
|
pha
|
|
lda #0
|
|
jsr SetPattern
|
|
ldx #0
|
|
stx r3L
|
|
stx r3H
|
|
stx r2L
|
|
lda #199
|
|
sta r2H
|
|
lda graphMode
|
|
bpl @L40
|
|
lda #>639 ; 80 columns
|
|
ldx #<639
|
|
bne @L99
|
|
@L40: lda #>319 ; 40 columns
|
|
ldx #<319
|
|
@L99: sta r4H
|
|
stx r4L
|
|
jsr Rectangle
|
|
pla
|
|
sta curPattern
|
|
rts
|
|
|
|
; ------------------------------------------------------------------------
|
|
; SETVIEWPAGE: Set the visible page. Called with the new page in A (0..n).
|
|
; The page number is already checked to be valid by the graphics kernel.
|
|
;
|
|
; Must set an error code: NO (will only be called if page ok)
|
|
;
|
|
|
|
SETVIEWPAGE:
|
|
ldx graphMode
|
|
bmi @L80
|
|
rts
|
|
@L80: clc
|
|
ror
|
|
ror
|
|
ror
|
|
ldx #VDC_DSP_HI
|
|
jmp VDCWriteReg
|
|
|
|
; ------------------------------------------------------------------------
|
|
; SETDRAWPAGE: Set the drawable page. Called with the new page in A (0..n).
|
|
; The page number is already checked to be valid by the graphics kernel.
|
|
;
|
|
; Must set an error code: NO (will only be called if page ok)
|
|
;
|
|
|
|
SETDRAWPAGE:
|
|
ldx graphMode
|
|
bmi @L80
|
|
rts
|
|
@L80: clc
|
|
ror
|
|
ror
|
|
ror
|
|
sta SCRBASE
|
|
rts
|
|
|
|
; ------------------------------------------------------------------------
|
|
; SETCOLOR: Set the drawing color (in A). The new color is already checked
|
|
; to be in a valid range (0..maxcolor-1).
|
|
;
|
|
; Must set an error code: NO (will only be called if color ok)
|
|
;
|
|
|
|
SETCOLOR:
|
|
tax
|
|
beq @L1
|
|
lda #1
|
|
@L1: sta BITMASK
|
|
jmp SetPattern ; need to have either 0 or 1
|
|
|
|
; ------------------------------------------------------------------------
|
|
; SETPALETTE: Set the palette (not available with all drivers/hardware).
|
|
; A pointer to the palette is passed in ptr1. Must set an error if palettes
|
|
; are not supported
|
|
;
|
|
; Must set an error code: YES
|
|
;
|
|
|
|
SETPALETTE:
|
|
jsr GETERROR ; clear error (if any)
|
|
|
|
ldy #PALETTESIZE - 1
|
|
@L1: lda (ptr1),y ; Copy the palette
|
|
and #$0F ; Make a valid color
|
|
sta PALETTE,y
|
|
dey
|
|
bpl @L1
|
|
|
|
; Put colors from palette into screen
|
|
|
|
lda graphMode
|
|
bmi @L80
|
|
|
|
lda PALETTE+1 ; foreground
|
|
asl a
|
|
asl a
|
|
asl a
|
|
asl a
|
|
ora PALETTE ; background
|
|
ldx #0
|
|
@L2: sta COLOR_MATRIX,x
|
|
sta COLOR_MATRIX+$0100,x
|
|
sta COLOR_MATRIX+$0200,x
|
|
sta COLOR_MATRIX+1000-256,x
|
|
inx
|
|
bne @L2
|
|
rts
|
|
|
|
@L80: ldy PALETTE+1 ; Foreground color
|
|
lda COLTRANS,y
|
|
asl a
|
|
asl a
|
|
asl a
|
|
asl a
|
|
ldy PALETTE ; Background color
|
|
ora COLTRANS,y
|
|
|
|
ldx #VDC_COLORS
|
|
jmp VDCWriteReg
|
|
|
|
; ------------------------------------------------------------------------
|
|
; GETPALETTE: Return the current palette in A/X. Even drivers that cannot
|
|
; set the palette should return the default palette here, so there's no
|
|
; way for this function to fail.
|
|
;
|
|
; Must set an error code: NO
|
|
;
|
|
|
|
GETPALETTE:
|
|
lda #<PALETTE
|
|
ldx #>PALETTE
|
|
rts
|
|
|
|
; ------------------------------------------------------------------------
|
|
; GETDEFPALETTE: Return the default palette for the driver in A/X. All
|
|
; drivers should return something reasonable here, even drivers that don't
|
|
; support palettes, otherwise the caller has no way to determine the colors
|
|
; of the (not changeable) palette.
|
|
;
|
|
; Must set an error code: NO (all drivers must have a default palette)
|
|
;
|
|
|
|
GETDEFPALETTE:
|
|
lda #<DEFPALETTE
|
|
ldx #>DEFPALETTE
|
|
rts
|
|
|
|
; ------------------------------------------------------------------------
|
|
; SETPIXEL: Draw one pixel at X1/Y1 = ptr1/ptr2 with the current drawing
|
|
; color. The coordinates passed to this function are never outside the
|
|
; visible screen area, so there is no need for clipping inside this function.
|
|
;
|
|
; Must set an error code: NO
|
|
;
|
|
|
|
SETPIXEL:
|
|
lda X1
|
|
ldx X1+1
|
|
ldy Y1
|
|
sta r3L
|
|
stx r3H
|
|
sty r11L
|
|
sec
|
|
lda BITMASK ; set or clear C flag
|
|
bne @L1
|
|
clc
|
|
@L1: lda #0
|
|
jmp DrawPoint
|
|
|
|
; ------------------------------------------------------------------------
|
|
; GETPIXEL: Read the color value of a pixel and return it in A/X. The
|
|
; coordinates passed to this function are never outside the visible screen
|
|
; area, so there is no need for clipping inside this function.
|
|
|
|
|
|
GETPIXEL:
|
|
lda X1
|
|
ldx X1+1
|
|
ldy Y1
|
|
sta r3L
|
|
stx r3H
|
|
sty r11L
|
|
jsr TestPoint
|
|
ldx #0
|
|
bcc @L1
|
|
inx
|
|
@L1: txa
|
|
ldx #0
|
|
rts
|
|
|
|
; ------------------------------------------------------------------------
|
|
; LINE: Draw a line from X1/Y1 to X2/Y2, where X1/Y1 = ptr1/ptr2 and
|
|
; X2/Y2 = ptr3/ptr4 using the current drawing color.
|
|
;
|
|
; Must set an error code: NO
|
|
;
|
|
|
|
LINE:
|
|
lda X1
|
|
ldx X1+1
|
|
ldy Y1
|
|
sta r3L
|
|
stx r3H
|
|
sty r11L
|
|
lda X2
|
|
ldx X2+1
|
|
ldy Y2
|
|
sta r4L
|
|
stx r4H
|
|
sty r11H
|
|
sec
|
|
lda BITMASK ; set or clear C flag
|
|
bne @L1
|
|
clc
|
|
@L1: lda #0
|
|
jmp DrawLine
|
|
|
|
; ------------------------------------------------------------------------
|
|
; BAR: Draw a filled rectangle with the corners X1/Y1, X2/Y2, where
|
|
; X1/Y1 = ptr1/ptr2 and X2/Y2 = ptr3/ptr4 using the current drawing color.
|
|
; Contrary to most other functions, the graphics kernel will sort and clip
|
|
; the coordinates before calling the driver, so on entry the following
|
|
; conditions are valid:
|
|
; X1 <= X2
|
|
; Y1 <= Y2
|
|
; (X1 >= 0) && (X1 < XRES)
|
|
; (X2 >= 0) && (X2 < XRES)
|
|
; (Y1 >= 0) && (Y1 < YRES)
|
|
; (Y2 >= 0) && (Y2 < YRES)
|
|
;
|
|
; Must set an error code: NO
|
|
;
|
|
|
|
BAR:
|
|
lda X1
|
|
ldx X1+1
|
|
ldy Y1
|
|
sta r3L
|
|
stx r3H
|
|
sty r2L
|
|
lda X2
|
|
ldx X2+1
|
|
ldy Y2
|
|
sta r4L
|
|
stx r4H
|
|
sty r2H
|
|
jmp Rectangle
|
|
|
|
; ------------------------------------------------------------------------
|
|
; TEXTSTYLE: Set the style used when calling OUTTEXT. Text scaling in X and Y
|
|
; direction is passend in X/Y, the text direction is passed in A.
|
|
;
|
|
; Must set an error code: NO
|
|
;
|
|
|
|
TEXTSTYLE:
|
|
stx TEXTMAGX
|
|
sty TEXTMAGY
|
|
sta TEXTDIR
|
|
rts
|
|
|
|
|
|
; ------------------------------------------------------------------------
|
|
; OUTTEXT: Output text at X/Y = ptr1/ptr2 using the current color and the
|
|
; current text style. The text to output is given as a zero terminated
|
|
; string with address in ptr3.
|
|
;
|
|
; Must set an error code: NO
|
|
;
|
|
|
|
OUTTEXT:
|
|
lda TEXTDIR
|
|
; cmp #TGI_TEXT_HORIZONTAL ; this is equal 0
|
|
bne @vertical
|
|
|
|
lda X1 ; horizontal text output
|
|
ldx X1+1
|
|
ldy Y1
|
|
sta r11L
|
|
stx r11H
|
|
sty r1H
|
|
lda ptr3
|
|
ldx ptr3+1
|
|
sta r0L
|
|
stx r0H
|
|
jmp PutString
|
|
|
|
@vertical:
|
|
lda X1 ; vertical text output
|
|
ldx X1+1
|
|
ldy Y1
|
|
sta r11L
|
|
stx r11H
|
|
sty r1H
|
|
ldy #0
|
|
lda (ptr3),y
|
|
beq @end
|
|
jsr PutChar
|
|
inc ptr3
|
|
bne @L1
|
|
inc ptr3+1
|
|
@L1: lda Y1
|
|
clc
|
|
adc #8
|
|
sta Y1
|
|
bne @vertical
|
|
@end: rts
|
|
|
|
;-------------
|
|
; VDC helpers
|
|
|
|
VDCSetSourceAddr:
|
|
pha
|
|
tya
|
|
ldx #VDC_DATA_HI
|
|
jsr VDCWriteReg
|
|
pla
|
|
ldx #VDC_DATA_LO
|
|
bne VDCWriteReg
|
|
|
|
VDCReadByte:
|
|
ldx #VDC_DATA
|
|
VDCReadReg:
|
|
stx VDC_ADDR_REG
|
|
@L0: bit VDC_ADDR_REG
|
|
bpl @L0
|
|
lda VDC_DATA_REG
|
|
rts
|
|
|
|
VDCWriteByte:
|
|
ldx #VDC_DATA
|
|
VDCWriteReg:
|
|
stx VDC_ADDR_REG
|
|
@L0: bit VDC_ADDR_REG
|
|
bpl @L0
|
|
sta VDC_DATA_REG
|
|
rts
|