diff --git a/doc/cx16.sgml b/doc/cx16.sgml index 78a51206b..a718e52fa 100644 --- a/doc/cx16.sgml +++ b/doc/cx16.sgml @@ -243,6 +243,12 @@ point to
+
+
diff --git a/libsrc/cx16/tgi/cx640p1.s b/libsrc/cx16/tgi/cx640p1.s
new file mode 100644
index 000000000..287160f6b
--- /dev/null
+++ b/libsrc/cx16/tgi/cx640p1.s
@@ -0,0 +1,675 @@
+;
+; Graphics driver for the 640 pixels across, 480 pixels down, 2 color mode
+; on the Commander X16
+;
+; 2024-06-11, Scott Hutter
+; Based on code by Greg King
+;
+
+ .include "zeropage.inc"
+
+ .include "tgi-kernel.inc"
+ .include "tgi-error.inc"
+
+ .include "cbm_kernal.inc"
+ .include "cx16.inc"
+
+ .macpack generic
+ .macpack module
+
+
+; ------------------------------------------------------------------------
+; Header. Includes jump table and constants.
+
+ module_header _cx640p1_tgi ; 640 pixels across, 1 pixel per bit
+
+; First part of the header is a structure that has a signature,
+; and defines the capabilities of the driver.
+
+ .byte $74, $67, $69 ; ASCII "tgi"
+ .byte TGI_API_VERSION ; TGI API version number
+ .addr $0000 ; Library reference
+ .word 640 ; X resolution
+ .word 480 ; Y resolution
+ .byte 2 ; Number of drawing colors
+ .byte 0 ; Number of screens available
+ .byte 8 ; System font X size
+ .byte 8 ; System font Y size
+ .word $0100 ; Aspect ratio (based on VGA display)
+ .byte 0 ; TGI driver flags
+
+; Next, comes the jump table. Currently, 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
+
+
+; ------------------------------------------------------------------------
+; Constant
+
+
+
+; ------------------------------------------------------------------------
+; 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
+
+ADDR = tmp1 ; ADDR+1,2,3
+
+TEMP = tmp3
+TEMP2 = tmp4 ; HORLINE
+TEMP3 = sreg ; HORLINE
+
+
+; Absolute variables used in the code
+
+.bss
+
+; The colors are indicies into a TGI palette. The TGI palette is indicies into
+; VERA's palette. Vera's palette is a table of Red, Green, and Blue levels.
+; The first 16 RGB elements mimic the Commodore 64's colors.
+
+SCRBASE: .res 1 ; High byte of screen base
+BITMASK: .res 1 ; $00 = clear, $FF = set pixels
+
+defpalette: .res 2
+palette: .res 2
+
+color: .res 1 ; Stroke and fill index
+text_mode: .res 1 ; Old text mode
+
+tempX: .res 2
+tempY: .res 2
+ERR2: .res 1
+ERR: .res 1
+SY: .res 1
+SX: .res 1
+DY: .res 1
+DX: .res 1
+CURRENT_Y: .res 2
+CURRENT_X: .res 2
+
+.data
+
+ERROR: .byte TGI_ERR_OK ; Error code
+
+
+; Constants and tables
+
+.rodata
+
+veracolors:
+col_black: .byte %00000000, %00000000
+col_white: .byte %11111111, %00001111
+col_red: .byte %00000000, %00001000
+col_cyan: .byte %11111110, %00001010
+col_purple: .byte %01001100, %00001100
+col_green: .byte %11000101, %00000000
+col_blue: .byte %00001010, %00000000
+col_yellow: .byte %11100111, %00001110
+col_orange: .byte %10000101, %00001101
+col_brown: .byte %01000000, %00000110
+col_lred: .byte %01110111, %00001111
+col_gray1: .byte %00110011, %00000011
+col_gray2: .byte %01110111, %00000111
+col_lgreen: .byte %11110110, %00001010
+col_lblue: .byte %10001111, %00000000
+col_gray3: .byte %10111011, %00001011
+
+; Bit masks for setting pixels
+bitMasks1:
+ .byte %10000000, %01000000, %00100000, %00010000
+ .byte %00001000, %00000100, %00000010, %00000001
+bitMasks2:
+ .byte %01111111, %10111111, %11011111, %11101111
+ .byte %11110111, %11111011, %11111101, %11111110
+
+
+.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:
+; Create the default palette.
+ lda #$00
+ sta defpalette
+ lda #$01
+ sta defpalette+1
+
+ ; Fall through.
+
+; ------------------------------------------------------------------------
+; 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 called only once; so, any code that is needed
+; to initiate variables and so on must go here. Setting the palette is not
+; needed because that is called by the graphics kernel later.
+; The graphics kernel never will call INIT when a graphics mode already is
+; active, so there is no need to protect against that.
+;
+; Must set an error code: YES
+
+INIT: stz ERROR ; #TGI_ERR_OK
+
+; Save the current text mode.
+
+ sec
+ jsr SCREEN_MODE
+ sta text_mode
+
+; Switch into (640 x 480 x 2 bpp) graphics mode.
+
+ lda #%00000000 ; DCSEL = 0, VRAM port 1
+ sta VERA::CTRL
+ lda #%00100001 ; Disable sprites, layer 1 enable, VGA
+ sta VERA::DISP::VIDEO
+ lda #%00000100 ; Bitmap mode enable
+ sta VERA::L1::CONFIG
+ lda #%00000001 ; Tile width 640
+ sta VERA::L1::TILE_BASE
+ rts
+
+; ------------------------------------------------------------------------
+; DONE: Will be called to switch the graphics device back into text mode.
+; The graphics kernel never will call DONE when no graphics mode is active,
+; so there is no need to protect against that.
+;
+; Must set an error code: NO
+
+DONE:
+ jsr CINT
+ lda text_mode
+ clc
+ jmp SCREEN_MODE
+
+; ------------------------------------------------------------------------
+; GETERROR: Return the error code in .A, and clear it.
+
+GETERROR:
+ lda ERROR
+ stz ERROR
+ rts
+
+; ------------------------------------------------------------------------
+; CONTROL: Platform-/driver-specific entry point.
+;
+; Must set an error code: YES
+
+CONTROL:
+ lda #TGI_ERR_INV_FUNC
+ sta ERROR
+ rts
+
+; ------------------------------------------------------------------------
+; CLEAR: Clear the screen.
+;
+; Must set an error code: NO
+
+CLEAR:
+ .scope inner
+
+ ; set up DCSEL=2
+ lda #(2 << 1)
+ sta VERA::CTRL
+
+ ; set cache writes
+ lda #$40
+ tsb VERA::DISP::VIDEO ; VERA_FX_CTRL when DCSEL=2
+
+ ; set FX cache to all zeroes
+ lda #(6 << 1)
+ sta VERA::CTRL
+
+ lda #$00
+ sta VERA::DISP::VIDEO
+ sta VERA::DISP::HSCALE
+ sta VERA::DISP::VSCALE
+ sta VERA::DISP::FRAME
+
+ stz VERA::CTRL
+ ; set address and increment for bitmap area
+ stz VERA::ADDR
+ stz VERA::ADDR + 1
+ lda #$30 ; increment +4
+ sta VERA::ADDR + 2
+
+ ldy #$F0
+@blank_outer:
+ ldx #$0A
+@blank_loop:
+
+ .repeat 8
+ stz VERA::DATA0
+ .endrep
+
+ dex
+ bne @blank_loop
+ dey
+ bne @blank_outer
+
+ ; set up DCSEL=2
+ lda #(2 << 1)
+ sta VERA::CTRL
+
+ ; set FX off (cache write bit 1 -> 0)
+ stz VERA::DISP::VIDEO ; VERA_FX_CTRL when DCSEL=2
+ stz VERA::CTRL
+
+ .endscope
+ rts
+
+
+; ------------------------------------------------------------------------
+; SETVIEWPAGE: Set the visible page. Called with the new page in .A (0..n-1).
+; The page number already is checked to be valid by the graphics kernel.
+;
+; Must set an error code: NO (will be called only if page OK)
+
+SETVIEWPAGE:
+
+ ; Fall through.
+
+; ------------------------------------------------------------------------
+; SETDRAWPAGE: Set the drawable page. Called with the new page in .A (0..n-1).
+; The page number already is checked to be valid by the graphics kernel.
+;
+; Must set an error code: NO (will be called only if page OK)
+
+SETDRAWPAGE:
+ rts
+
+; ------------------------------------------------------------------------
+; 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:
+ stz ERROR ; #TGI_ERR_OK
+ ldy #$01 ; Palette size of 2 colors
+@L1: lda (ptr1),y ; Copy the palette
+ sta palette,y
+ dey
+ bpl @L1
+
+ ; set background color from palette color 0
+ lda #$00
+ sta VERA::ADDR
+ lda #$FA
+ sta VERA::ADDR+1
+ lda #$01
+ sta VERA::ADDR+2 ; write color RAM @ $1FA00
+
+ lda palette
+ asl
+ tay
+ lda veracolors,y
+ sta VERA::DATA0
+
+ inc VERA::ADDR ; $1FA01
+
+ lda palette
+ asl
+ tay
+ iny ; second byte of color
+ lda veracolors,y
+ sta VERA::DATA0
+
+ ; set foreground color from palette color 1
+ inc VERA::ADDR ; $1FA02
+
+ lda palette+1
+ asl
+ tay
+ lda veracolors,y
+ sta VERA::DATA0
+
+ inc VERA::ADDR ; $1FA03
+
+ lda palette+1
+ asl
+ tay
+ iny ; second byte of color
+ lda veracolors,y
+ sta VERA::DATA0
+ rts
+
+; ------------------------------------------------------------------------
+; SETCOLOR: Set the drawing color (in .A). The new color already is checked
+; to be in a valid range (0..maxcolor).
+;
+; Must set an error code: NO (will be called only if color OK)
+
+SETCOLOR:
+ tax
+ beq @L1
+ lda #$FF
+@L1: sta BITMASK
+ stx color
+ rts
+
+; ------------------------------------------------------------------------
+; GETPALETTE: Return the current palette in .XA. 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 #