You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1078 lines
31 KiB

;======================================================================
; XOSERA DRIVER FOR RCBUS XOSERA CARD
;
; WRITTEN BY: ROB GOWIN -- 01/19/2025
;======================================================================
;
; TODO:
; * LOOK AT FONT STUFF IN MORE DETAIL
;
;======================================================================
; XOSERA DRIVER - CONSTANTS
;======================================================================
;
;XOS_BASE .EQU $E0
;
DEVECHO "XOSERA: "
DEVECHO "IO="
DEVECHO XOS_BASE
DEVECHO "\n"
;
#IF (XOSSIZ=V80X30)
XOS_ROWS_CONST .EQU 30
XOS_COLS_CONST .EQU 80
#ENDIF
#IF (XOSSIZ=V80X60)
XOS_ROWS_CONST .EQU 60
XOS_COLS_CONST .EQU 80
#ENDIF
; XOSERA MAIN REGISTER
ZXM_SYS_CTRL .EQU XOS_BASE
ZXM_INT_CTRL .EQU XOS_BASE+2
ZXM_TIMER .EQU XOS_BASE+4
ZXM_RD_XADDR .EQU XOS_BASE+6
ZXM_WR_XADDR .EQU XOS_BASE+8
ZXM_XDATA .EQU XOS_BASE+10
ZXM_RD_INCR .EQU XOS_BASE+12
ZXM_RD_ADDR .EQU XOS_BASE+14
ZXM_WR_INCR .EQU XOS_BASE+16
ZXM_WR_ADDR .EQU XOS_BASE+18
ZXM_DATA .EQU XOS_BASE+20
ZXM_DATA_2 .EQU XOS_BASE+22
ZXM_PIXEL_X .EQU XOS_BASE+24
ZXM_PIXEL_Y .EQU XOS_BASE+26
ZXM_UART .EQU XOS_BASE+28
ZXM_FEATURE .EQU XOS_BASE+30
; See: https:;github.com/XarkLabs/Xosera/blob/master/REFERENCE.md
; Xosera XR Memory Regions (size in 16-bit words)
XR_CONFIG_REGS .EQU $0000 ; (R/W) 0x0000-0x0007 8 config/ctrl registers
XR_PA_REGS .EQU $0010 ; (R/W) 0x0010-0x0017 8 playfield A video registers
XR_PB_REGS .EQU $0018 ; (R/W) 0x0018-0x001F 8 playfield B video registers
XR_AUDIO_REGS .EQU $0020 ; (-/W) 0x0020-0x002F 16 audio playback registers
XR_BLIT_REGS .EQU $0040 ; (-/W) 0x0040-0x0049 10 blitter registers
XR_TILE_ADDR .EQU $4000 ; (R/W) 0x4000-0x53FF tile glyph/tile map memory
XR_TILE_SIZE .EQU $1400 ; 4096+1024 x 16-bit tile glyph/tile map memory
XR_COLOR_ADDR .EQU $8000 ; (R/W) 0x8000-0x81FF 2 x A & B color lookup memory
XR_COLOR_SIZE .EQU $0200 ; 2 x 256 x 16-bit words (0xARGB)
XR_COLOR_A_ADDR .EQU $8000 ; (R/W) 0x8000-0x80FF A 256 entry color lookup memory
XR_COLOR_A_SIZE .EQU $0100 ; 256 x 16-bit words (0xARGB)
XR_COLOR_B_ADDR .EQU $8100 ; (R/W) 0x8100-0x81FF B 256 entry color lookup memory
XR_COLOR_B_SIZE .EQU $0100 ; 256 x 16-bit words (0xARGB)
XR_POINTER_ADDR .EQU $8200 ; (-/W) 0x8200-0x82FF 256 word 32x32 4-bpp pointer image
XR_POINTER_SIZE .EQU $0100 ; 256 x 16-bit words (4-bit pixels)
XR_COPPER_ADDR .EQU $C000 ; (R/W) 0xC000-0xC5FF copper memory (16-bit words)
XR_COPPER_SIZE .EQU $0600 ; 1024+512 x 16-bit copper memory words
; XR Extended Register / Region (accessed via XM_RD_XADDR/XM_WR_XADDR and XM_XDATA)
; Video Config and Copper XR Registers
XR_VID_CTRL .EQU $00 ; (R /W) display control and border color index
XR_COPP_CTRL .EQU $01 ; (R /W) display synchronized coprocessor control
XR_AUD_CTRL .EQU $02 ; (- /-) TODO: audio channel control
XR_SCANLINE .EQU $03 ; (R /W) read scanline (incl. offscreen), write signal video interrupt
XR_VID_LEFT .EQU $04 ; (R /W) left edge of active display window (typically 0)
XR_VID_RIGHT .EQU $05 ; (R /W) right edge of active display window +1 (typically 640 or 848)
XR_POINTER_H .EQU $06 ; (- /W) pointer sprite raw H position
XR_POINTER_V .EQU $07 ; (- /W) pointer sprite raw V position / pointer color select
; Playfield A Control XR Registers
XR_PA_GFX_CTRL .EQU $10 ; (R /W ) playfield A graphics control
XR_PA_TILE_CTRL .EQU $11 ; (R /W ) playfield A tile control
XR_PA_DISP_ADDR .EQU $12 ; (R /W ) playfield A display VRAM start address
XR_PA_LINE_LEN .EQU $13 ; (R /W ) playfield A display line width in words
XR_PA_HV_FSCALE .EQU $14 ; (R /W ) playfield A horizontal and vertical fractional scale
XR_PA_H_SCROLL .EQU $15 ; (R /W ) playfield A horizontal and vertical fine scroll
XR_PA_V_SCROLL .EQU $16 ; (R /W ) playfield A horizontal and vertical fine scroll
XR_PA_LINE_ADDR .EQU $17 ; (- /W ) playfield A scanline start address (loaded at start of line)
; Playfield B Control XR Registers
XR_PB_GFX_CTRL .EQU $18 ; (R /W ) playfield B graphics control
XR_PB_TILE_CTRL .EQU $19 ; (R /W ) playfield B tile control
XR_PB_DISP_ADDR .EQU $1A ; (R /W ) playfield B display VRAM start address
XR_PB_LINE_LEN .EQU $1B ; (R /W ) playfield B display line width in words
XR_PB_HV_FSCALE .EQU $1C ; (R /W ) playfield B horizontal and vertical fractional scale
XR_PB_H_SCROLL .EQU $1D ; (R /W ) playfield B horizontal and vertical fine scroll
XR_PB_V_SCROLL .EQU $1E ; (R /W ) playfield B horizontal and vertical fine scroll
XR_PB_LINE_ADDR .EQU $1F ; (- /W ) playfield B scanline start address (loaded at start of line)
; Default 1-bpp font glyphs in TILE memory (total 0x1400 words)
FONT_ST_8x16_ADDR .EQU XR_TILE_ADDR + $0000
FONT_ST_8x16_SIZE .EQU $800
FONT_ST_8x8_ADDR .EQU XR_TILE_ADDR + $0800
FONT_ST_8x8_SIZE .EQU $400
FONT_PC_8x8_ADDR .EQU XR_TILE_ADDR + $0C00
FONT_PC_8x8_SIZE .EQU $400
FONT_HEX_8x8_ADDR .EQU XR_TILE_ADDR + $1000
FONT_HEX_8x8_SIZE .EQU $400
TILE_CTRL_TILE_VRAM_F .EQU $0100
TILE_CTRL_DISP_TILEMEM_F .EQU $0200
; GET XOSERA MAIN REGISTER REG_NUM VALUE INTO DE.
#DEFINE XM_GETW(REG_NUM) \
#defcont \ LD C,REG_NUM
#defcont \ IN D,(C)
#defcont \ INC C
#defcont \ IN E,(C)
; SET XOSERA MAIN REGISTER REG_NUM TO VALUE IN DE.
#DEFINE XM_SETW(REG_NUM) \
#defcont \ LD C,REG_NUM
#defcont \ OUT (C),D
#defcont \ INC C
#defcont \ OUT (C),E
; SET LOW BYTE OF XOERA MAIN REGISTER REG_NUM TO VALUE IN A.
#DEFINE XM_SETBL(REG_NUM) \
#defcont \ LD C,REG_NUM+1
#defcont \ OUT (C),A
SYNC_RETRIES .EQU 250
TERMENABLE .SET TRUE ; INCLUDE TERMINAL PSEUDODEVICE DRIVER
;
;--------------------------------------------------------------------------------------------------
; HBIOS MODULE HEADER
;--------------------------------------------------------------------------------------------------
;
ORG_XOS .EQU $
;
.DW SIZ_XOS ; MODULE SIZE
.DW XOS_INITPHASE ; ADR OF INIT PHASE HANDLER
;
XOS_INITPHASE:
; INIT PHASE HANDLER, A=PHASE
CP HB_PHASE_PREINIT ; PREINIT PHASE?
JP Z,XOS_PREINIT ; DO PREINIT
CP HB_PHASE_INIT ; INIT PHASE?
JP Z,XOS_INIT ; DO INIT
RET ; DONE
;======================================================================
; XOSERA DRIVER - INITIALIZATION
;======================================================================
;
XOS_PREINIT:
LD IY,XOS_IDAT ; POINTER TO INSTANCE DATA
; JP KBD_PREINIT ; INITIALIZE KEYBOARD
RET
;
XOS_INIT:
LD IY,XOS_IDAT ; POINTER TO INSTANCE DATA
;
CALL NEWLINE ; FORMATTING
PRTS("XOSERA: IO=0x$")
LD A,XOS_BASE
CALL PRTHEXBYTE
CALL XOS_PROBE ; CHECK FOR HW PRESENCE
JR Z,XOS_INIT1 ; CONTINUE IF HW PRESENT
;
; HARDWARE NOT PRESENT
PRTS(" NOT PRESENT$")
OR $FF
RET
;
XOS_INIT1:
; RETRIEVE SOME CONFIGURATION INFO FROM XOSERA AND PRINT IT
LD A,' '
CALL COUT
CALL XOS_SHOW_INFO
CALL XOS_VDAINI
; ADD OURSELVES TO VDA DISPATCH TABLE
LD BC,XOS_FNTBL ; BC := FUNCTION TABLE ADDRESS
LD DE,XOS_IDAT ; DE := XOSERA INSTANCE DATA PTR
CALL VDA_ADDENT ; ADD ENTRY, A := UNIT ASSIGNED
; INITIALIZE EMULATION
LD C,A ; C := ASSIGNED VIDEO DEVICE NUM
LD DE,XOS_FNTBL ; DE := FUNCTION TABLE ADDRESS
LD HL,XOS_IDAT ; HL := XOSERA INSTANCE DATA PTR
CALL TERM_ATTACH ; DO IT
XOR A ; SIGNAL SUCCESS
RET
;----------------------------------------------------------------------
; XOS_SHOW_INFO:
; XOSERA HAS SOME BUILD-TIME INFO STORED IN THE UPPER 128 OF COPPER
; MEMORY. RETRIEVE THAT INFO AND DISPLAY IT.
;----------------------------------------------------------------------
XOS_SHOW_INFO:
LD DE,$C580 ; LAST 128 BYTES OF XOSERA COPPER MEM
XM_SETW(ZXM_RD_XADDR)
XOS_SHOW_INFO1:
XM_GETW(ZXM_XDATA) ; GET INFO DATA IN DE
LD A,D
CP 0
JR Z,XOS_SHOW_INFO2 ; EXIT LOOP IF D == 0
PUSH DE
CALL COUT ; PRINT THE CHAR IN D (COPIED TO A)
POP DE
LD A,E
CP 0
JR Z,XOS_SHOW_INFO2 ; EXIT LOOP IF E == 0
CALL COUT ; PRINT THE CHAR IN E (COPIED TO A)
JR XOS_SHOW_INFO1
XOS_SHOW_INFO2:
RET
;----------------------------------------------------------------------
; XOS_DETECT: DETECT PRESENCE OF A XOSERA BOARD
;
; READ XOSERA RD_INCR REGISTER, THEN XOR WITH CONSTANT TO CHANGE IT.
; WRITE XOR'D VALUE TO RD_INCR, THEN READ BACK. IF A MATCH,
; XOSERA BOARD IS DETECTED.
; EITHER WAY, RESTORE ORIGINAL RD_INCR THEN RETURN RESULT IN A.
; RESULT IN A: 0 IF VALUES MATCH, -8 (HARDWARE NOT PRESENT) OTHERWISE.
;----------------------------------------------------------------------
XOS_DETECT:
XM_GETW(ZXM_RD_INCR) ; DE := XOSERA RD_INCR REGISTER
PUSH DE ; SAVE A COPY
LD A,D
XOR $F5
LD D,A ; XOR RD_INCR MSB WITH $F5
LD A,E
XOR $FA
LD E,A ; XOR RD_INCR LSB WITH $FA
; DE = TEST_INCR = RD_INCR ^ 0xF5FA;
LD H,D
LD L,E ; SAVE TEST_INCR TO HL
XM_SETW(ZXM_RD_INCR) ; WRITE NEW RD_INCR VALUE
LD DE,$0000
XM_GETW(ZXM_RD_INCR) ; READ IT BACK INTO DE
LD A,H
CP D
JR NZ,XOS_DETECT1 ; D & H THE SAME?
LD A,L
CP E
JR NZ,XOS_DETECT1 ; E & L THE SAME?
XOR A ; YEP, LOOKS GOOD
JP XOS_DETECT2
XOS_DETECT1:
LD A,-8 ; READBACK VALUE DID NOT MATCH. SIGNAL HARDWARE NOT PRESENT
XOS_DETECT2:
; RESTORE THE ORGINAL VALUE OF RD_INCR
POP DE
XM_SETW(ZXM_RD_INCR)
OR A ; SET FLAGS
RET
;
;----------------------------------------------------------------------
; XOS_PROBE: PROBE FOR XOSERA, TRY UP TO `SYNC_RETRIES` TIMES, WAITING
; 10MS BETWEEN SYNC ATTEMPTS.
; RETURN IN A: 0 IF A XOSERA_BOARD IS DETECTED, OR -8 (HARDWARE NOT
; DETECTED) OTHERWISE.
;----------------------------------------------------------------------
;
XOS_PROBE:
LD B,SYNC_RETRIES
XOS_PROBE1:
CALL XOS_DETECT ; Z FLAG SET IF XOSERA DETECTED, CLEAR IF NOT
JR Z,XOS_PROBE2
; OUR ATTEMPT TO SYNC DID NOT WORK, SO WAIT 10MS TO TRY AGAIN
PUSH BC
LD DE,625 ; 625 * 16US = 10000US = 10MS
CALL VDELAY
POP BC
DJNZ XOS_PROBE1
LD A,-8 ; FAILED TO SYNC AFTER SEVERAL ATTEMPTS.
XOS_PROBE2:
; A WILL BE ZERO OR -8. SET THE Z FLAG ACCORDINGLY.
OR A ; SET FLAGS
RET
;
;----------------------------------------------------------------------
; XOS_CLR_TEXT_SCR: CALL FILL TO CLEAR ENTIRE ROWS*COLS TEXT SCREEN.
;----------------------------------------------------------------------
XOS_CLR_TXT_SCR:
LD A,(XOS_COLS) ; COMPUTE HOW MANY WORDS TO FILL
LD H,A
LD A,(XOS_ROWS)
LD E,A
CALL MULT8
LD B,H
LD C,L ; BC := WORD COUNT = ROWS * COLS
LD HL,(XOS_POS)
PUSH HL ; SAVE CURRENT CURSOR POS
LD HL,(XOS_OFF)
LD (XOS_POS),HL ; TELL FILL TO START AT 0,0 (POS = XOS_OFF)
LD A,$20 ; FILL WITH SPACE (AND CURRENT ATTR)
CALL XOS_FILL
CALL REVERSE_CURSOR_POS ; BIT OF A HACK
POP HL
LD HL,(XOS_POS) ; RESTORE ORIGINAL CURSOR POS
RET
;
;----------------------------------------------------------------------
; XOS_WRITE_XREGS: WRITE A GROUP OF XOSERA EXTENDED REGISTERS.
; HL POINTS TO SETUP TABLE, B HAS NUMBER OF WORDS.
; DE HAS FIRST XOSERA XREG ADDRESS
;----------------------------------------------------------------------
;
XOS_WRITE_XREGS:
XM_SETW(ZXM_WR_XADDR)
XOS_WRITE_XREGS1:
LD E,(HL)
INC HL
LD D,(HL)
INC HL
XM_SETW(ZXM_XDATA)
DEC B
JR NZ,XOS_WRITE_XREGS1
RET
;
;----------------------------------------------------------------------
; XOS_WRITE_PALETTE_B
; WHEN WRITING PALETTE B, WE NEED TO SET THE ALPHA VALUE TO $F
; SO THAT THE GRAPHICS/TEXT OVERLAP WORKS CORRECTLY. EXCEPT THAT
; WE DON'T WANT THIS FOR THE ZERO ENTRY SO HANDLE THAT SEPERATELY.
;----------------------------------------------------------------------
;
XOS_WRITE_PALETTE_B:
XM_SETW(ZXM_WR_XADDR)
LD E,(HL)
INC HL
LD D,(HL)
INC HL
XM_SETW(ZXM_XDATA)
DEC B
XOS_WRITE_PALETTE_B1:
LD E,(HL)
INC HL
LD D,(HL)
INC HL
LD A,D
OR $F0 ; SET ALPHA VALUE TO $F
LD D,A
XM_SETW(ZXM_XDATA)
DEC B
JR NZ,XOS_WRITE_PALETTE_B1
RET
;
;----------------------------------------------------------------------
; XOS_COPY_FONT_TO_VRAM
; COPY THE 8 X 8 ST FONT IN THE EXTENDED REGISTER AREA TO THE
; UPPER 1K OF VRAM. USED IN 80 X 60 MODE, BUT NOT IN
; 80 X 30 MODE.
;----------------------------------------------------------------------
;
XOS_COPY_FONT_TO_VRAM:
; SEE IF THE FONT HAS ALREADY BEEN COPIED. IF SO VRAM ADDRESS
; $FC04 WILL HAVE THE VALUE $183C.
LD DE,$FC04
XM_SETW(ZXM_RD_ADDR)
XM_GETW(ZXM_DATA)
LD A,D
CP $18
JR NZ,XOS_COPY_FONT_TO_VRAM1
LD A,E
CP $3C
JR NZ,XOS_COPY_FONT_TO_VRAM1
; FONT HAS ALREADY BEEN COPIED TO VRAM. JUST RETURN
RET
XOS_COPY_FONT_TO_VRAM1:
LD DE,FONT_ST_8x8_ADDR ; READ FROM FONT AREA
XM_SETW(ZXM_RD_XADDR)
LD DE,$FC00
XM_SETW(ZXM_WR_ADDR) ; WRITE TO VRAM
LD DE,$0001
XM_SETW(ZXM_WR_INCR) ; MAKE SURE WR INCR IS NONE
LD BC,FONT_ST_8x8_SIZE ; LOOP COUNTER
XOS_COPY_FONT_TO_VRAM2:
PUSH BC
XM_GETW(ZXM_XDATA)
XM_SETW(ZXM_DATA)
; CHECK COUNT
POP BC
DEC BC ; DECREMENT COUNT
LD A,B ; TEST FOR
OR C ; ... ZERO
RET Z ; DONE IF SO
JR XOS_COPY_FONT_TO_VRAM2
XOS_HW_SETUP:
LD DE,XR_VID_CTRL
LD HL,XOS_BASE_INIT
LD B,8
CALL XOS_WRITE_XREGS
; INITIALIZE PLAYFIELD A FOR BITMAP GRAPHICS
LD DE,XR_PA_REGS
LD HL,PF_640x480x4
LD B,7
CALL XOS_WRITE_XREGS
; INITIALIZE PLAYFIELD B FOR 80x30 TEXT MODE
LD DE,XR_PB_REGS
#IF (XOSSIZ=V80X60)
LD HL,PF_80X60_TILED
#ELSE
LD HL,PF_80X30_TILED
#ENDIF
LD B,7
CALL XOS_WRITE_XREGS
; INITIALIZE THE PALETTE FOR PLAYFIELD A
LD DE,XR_COLOR_A_ADDR
LD HL,XOS_PALETTE
LD B,16
CALL XOS_WRITE_XREGS
; INITIALIZE THE PALETTE FOR PLAYFIELD B
LD DE,XR_COLOR_B_ADDR
LD HL,XOS_PALETTE
LD B,16
CALL XOS_WRITE_PALETTE_B
; INITIALIZE THE COPPER PROGRAM WE ARE USING TO 'LETTERBOX'
; A 640 X 400 BITMAP ON A 640 X 480 DISPLAY. SEE COPPER NOTES
; WAY BELOW.
LD DE,$C100
XM_SETW(ZXM_WR_XADDR)
LD DE,(PF_640x480x4) ; DE := PA_GFX_CTRL
XM_SETW(ZXM_XDATA)
LD A,E
OR $80
LD E,A ; DE := PA_GFX_CTRL WITH BLANK BIT SET
XM_SETW(ZXM_XDATA)
LD DE,XR_COPPER_ADDR
LD HL,XOS_COPPER
LD B,19
CALL XOS_WRITE_XREGS
LD DE,XR_COPP_CTRL ; ENABLE THE COPPER
XM_SETW(ZXM_WR_XADDR)
LD DE,$8000
XM_SETW(ZXM_XDATA)
LD A,$0F ; SET DEFAUL PIXEL MASK
XM_SETBL(ZXM_SYS_CTRL)
LD DE,$0001
XM_SETW(ZXM_WR_INCR) ; SET DEFAULT READ/WRITE INCREMENTS
XM_SETW(ZXM_RD_INCR)
RET
;
;======================================================================
; XOSERA DRIVER - VIDEO DISPLAY ADAPTER (VDA) FUNCTIONS
;======================================================================
;
XOS_FNTBL:
.DW XOS_VDAINI
.DW XOS_VDAQRY
.DW XOS_VDARES
.DW XOS_VDADEV
.DW XOS_VDASCS
.DW XOS_VDASCP
.DW XOS_VDASAT
.DW XOS_VDASCO
.DW XOS_VDAWRC
.DW XOS_VDAFIL
.DW XOS_VDACPY
.DW XOS_VDASCR
.DW XKBD_STAT
.DW XKBD_FLUSH
.DW XKBD_READ
.DW XOS_VDARDC
#IF (($ - XOS_FNTBL) != (VDA_FNCNT * 2))
.ECHO "*** INVALID VGA FUNCTION TABLE ***\n"
!!!!!
#ENDIF
XOS_VDAINI:
LD A,$0F ; BRIGHT WHITE FG, BLACK BG
LD (XOS_ATTR),A
LD A,0
LD (XOS_RUB),A
LD A,80
LD (XOS_COLS),A
LD A,XOS_ROWS_CONST
LD (XOS_ROWS),A
#IF (XOSSIZ=V80X60)
LD HL,$4000
#ELSE
LD HL,$4800
#ENDIF
LD (XOS_OFF),HL
LD (XOS_POS),HL
; FONT DATA FOR 80x30 MODE WILL STAY IN TILE MEM, BUT
; FONT DATA FOR 80X60 MODE WILL LIVE IN VRAM. SO WE
; NEED TO COPY THE ST 8X8 FONT TO VRAM. WE MUST DO THIS
; BEFORE CLEARING THE TEXT SCREEN BECAUSE THE SCREEN
; DATA IS STORED WHERE FONT CURRENTLY RESIDES.
LD A,$0F
XM_SETBL(ZXM_SYS_CTRL) ; SET VRAM WRITE MASK
CALL XOS_COPY_FONT_TO_VRAM
CALL XOS_CLR_TXT_SCR ; CLEAR THE TEXT SCREEN
CALL XOS_HW_SETUP
; CALL XOS_CLR_GRAPHICS_SCR ; CLEAR THE GRAPHICS SCREEN
XOR A ; SIGNAL SUCCESS
RET
XOS_VDAQRY:
LD C,$00 ; MODE ZERO IS ALL WE KNOW
LD A,(XOS_ROWS)
LD D,A
LD A,(XOS_COLS)
LD E,A
LD HL,$0 ; EXTRACTION OF CURRENT BITMAP DATA NOT SUPPORTED YET
XOR A ; SIGNAL SUCCESS
RET
XOS_VDARES:
XOR A ; SIGNAL SUCCESS
RET
XOS_VDADEV:
LD C,0 ; C := ATTRIBUTES (UNDEFINED)
LD D,VDADEV_XOSERA ; D := DEVICE TYPE
LD E,0 ; E := PHYSICAL UNIT IS ALWAYS ZERO
LD H,0 ; H := 0, DRIVER HAS NO MODES
LD L,XOS_BASE ; L := BASE I/O ADDRESS
XOR A ; SIGNAL SUCCESS
RET
XOS_VDASCS:
SYSCHKERR(ERR_NOTIMPL) ; NOT IMPLEMENTED (YET)
RET
XOS_VDASCP:
; UNREVERSE THE CURRENT CURSOR
CALL REVERSE_CURSOR_POS
CALL XOS_XY ; SET CURSOR POSITION
; REVERSE VIDEO THE CHARACTER AT THE NEW CURSOR POSITION
CALL REVERSE_CURSOR_POS
XOR A ; SIGNAL SUCCESS
RET
XOS_VDASAT:
; INCOMING IS: -----RUB (R=REVERSE, U=UNDERLINE, B=BLINK)
;
; JUST SAVE THE VALUE AND FALL THROUGH. ONLY REVERSE IS
; SUPPORTED WHICH IS IMPLEMENTED BELOW.
LD A,E
LD (XOS_RUB),A ; SAVE IT
JR XOS_VDASCO1 ; IMPLEMENT SETTING
XOS_VDASCO:
; WE HANDLE ONLY PER-CHARACTER COLORS (D=0)
LD A,D ; GET CHAR/SCREEN SCOPE
OR A ; CHARACTER?
JR NZ,XOS_VDASCO2 ; IF NOT, JUST RETURN
LD A,E
LD (XOS_ATTR),A ; SAVE COLOR INFO
XOS_VDASCO1:
; CHECK FOR REVERSE VIDEO
LD A,(XOS_RUB) ; GET RUB SETTING
BIT 2,A ; REVERSE IS BIT 2
JR Z,XOS_VDASCO2 ; DONE IF REVERSE VID NOT SET
; IMPLEMENT REVERSE VIDEO
LD A,(XOS_ATTR) ; GET ATTRIBUTE
RLCA ; SWAP FG/BG COLORS
RLCA
RLCA
RLCA
LD (XOS_ATTR),A ; SAVE NEW VALUE
XOS_VDASCO2:
XOR A ; SIGNAL SUCCESS
RET
XOS_VDAWRC:
CALL REVERSE_CURSOR_POS
LD A,E ; CHARACTER TO WRITE GOES IN A
CALL XOS_PUTCHAR ; PUT IT ON THE SCREEN
CALL REVERSE_CURSOR_POS
XOR A ; SIGNAL SUCCESS
RET
XOS_VDAFIL:
CALL REVERSE_CURSOR_POS
LD A,E ; FILL CHARACTER GOES IN A
LD B,H
LD C,L ; FILL LENGTH GOES IN BC
CALL XOS_FILL ; DO THE FILL
CALL REVERSE_CURSOR_POS
XOR A ; SIGNAL SUCCESS
RET
XOS_VDACPY:
; LENGTH IN HL, SOURCE ROW/COL IN DE, DEST IS XOS_POS
; BLKCPY USES: HL=SOURCE, DE=DEST, BC=COUNT
CALL REVERSE_CURSOR_POS
PUSH HL ; SAVE LENGTH
CALL XOS_XY2IDX ; ROW/COL IN DE -> SOURCE ADR IN HL
PUSH DE
LD DE,(XOS_OFF) ; ADD IN VRAM START OFFSET
ADD HL,DE
POP DE
POP BC ; RECOVER LENGTH IN BC
LD DE,(XOS_POS) ; PUT DEST IN DE
; LD A,0 ; SOURCE IS MEMORY
CALL XOS_BLKCPY ; DO A BLOCK COPY
CALL REVERSE_CURSOR_POS
XOR A ; SIGNAL SUCCESS
RET
XOS_VDASCR:
CALL REVERSE_CURSOR_POS
LD A,E
OR A ; SET FLAGS
RET Z ; IF ZERO, WE ARE DONE
JP M,XOS_VDASCR1 ; E IS NEGATIVE, REVERSE SCROLL
CALL XOS_RSCROLL ; SCROLL FORWARD 'E' LINES
CALL REVERSE_CURSOR_POS
XOR A ; SIGNAL SUCCESS
RET
XOS_VDASCR1:
NEG ; A IS NEGATIVE, BUT NEED IT POSITIVE
LD E,A ; LINES TO SCROLL TO E
CALL XOS_SCROLL ; SCROLL REVERSE 'E' LINES
CALL REVERSE_CURSOR_POS
XOR A ; SIGNAL SUCCESS
RET
XKBD_STAT:
XKBD_FLUSH:
XKBD_READ:
OR $FF ; RETURN FAILURE STATUS
RET
XOS_VDARDC:
XOR A
RET
;
;======================================================================
; XOSERA DRIVER - PRIVATE DRIVER FUNCTIONS
;======================================================================
;
;----------------------------------------------------------------------
; SET CURSOR POSITION TO ROW IN D AND COLUMN IN E
;----------------------------------------------------------------------
;
XOS_XY:
CALL XOS_XY2IDX ; CONVERT ROW/COL TO BUF IDX
LD DE,(XOS_OFF)
ADD HL,DE
LD (XOS_POS),HL ; SAVE THE RESULT (DISPLAY POSITION)
RET
;
;----------------------------------------------------------------------
; CONVERT XY COORDINATES IN DE INTO LINEAR INDEX IN HL
; D=ROW, E=COL
;----------------------------------------------------------------------
;
XOS_XY2IDX:
LD A,E ; SAVE COLUMN NUMBER IN A
LD H,D ; SET H TO ROW NUMBER
PUSH AF
LD A,(XOS_COLS)
LD E,A ; SET E TO ROW LENGTH
CALL MULT8 ; MULTIPLY TO GET ROW OFFSET
POP AF
LD E,A ; GET COLUMN BACK
ADD HL,DE ; ADD IT IN
RET
;
;----------------------------------------------------------------------
; REVERSE_CURSOR_POS - REVERSE VIDEO THE CHARACTER AT THE CURRENT
; CURSOR POSITION.
;----------------------------------------------------------------------
;
REVERSE_CURSOR_POS:
PUSH AF
PUSH BC
PUSH DE
LD DE,(XOS_POS)
XM_SETW(ZXM_RD_XADDR)
XM_SETW(ZXM_WR_XADDR)
XM_GETW(ZXM_XDATA) ; GET THE ATTRIBUTE/CHAR AT CURSOR INTO DE
LD A,D
RLCA ; SWAP FG/BG COLORS
RLCA
RLCA
RLCA
LD D,A
XM_SETW(ZXM_XDATA)
POP DE
POP BC
POP AF
RET
;
;----------------------------------------------------------------------
; WRITE VALUE IN A TO CURRENT XOSERA BUFFER POSITION, ADVANCE CURSOR
;----------------------------------------------------------------------
;
XOS_PUTCHAR:
; SETUP DE WITH TILEMEM ADDRESS
LD DE,(XOS_POS)
XM_SETW(ZXM_WR_XADDR)
; SETUP CHAR/ATTR IN DE
LD E,A ; CHARACTER TO E
LD A,(XOS_ATTR) ; ATTRIBUTE
LD D,A ; ... TO D
; WRITE CHAR & ATTR
XM_SETW(ZXM_XDATA)
; UPDATE CURRENT POSITION
LD HL,(XOS_POS) ; GET CURSOR POSITION
INC HL ; INCREMENT
LD (XOS_POS),HL
RET
;
;----------------------------------------------------------------------
; FILL AREA IN BUFFER WITH SPECIFIED CHARACTER AND CURRENT COLOR/ATTRIBUTE
; STARTING AT THE CURRENT FRAME BUFFER POSITION
; A: FILL CHARACTER
; BC: NUMBER OF CHARACTERS TO FILL
;----------------------------------------------------------------------
;
XOS_FILL:
LD H,A ; CACHE FILL CHAR IN H
; SETUP DE WITH INITIAL BUFFER ADDRESS
LD DE,(XOS_POS) ; GET CURRENT POSITION
PUSH BC ; PRESERVE BC (C USED BY MACRO)
XM_SETW(ZXM_WR_XADDR) ; SET VRAM WRITE ADDRESS
POP BC ; RESTORE BC
XOS_FILL1:
; FILL ONE POSITION (ATTR & CHAR)
LD E,H ; CHARACTER TO E
LD A,(XOS_ATTR) ; ATTRIBUTE
LD D,A ; ... TO D
PUSH BC ; PRESERVE BC (C USED BY MACRO)
XM_SETW(ZXM_XDATA) ; WRITE CHAR & ATTR
POP BC ; RESTORE BC
; CHECK COUNT
DEC BC ; DECREMENT COUNT
LD A,B ; TEST FOR
OR C ; ... ZERO
JR Z,XOS_FILL2 ; DONE IF SO
; UPDATE CURSOR POSITION
PUSH HL
LD HL,(XOS_POS) ; GET CURSOR POSITION
INC HL ; INCREMENT
LD (XOS_POS),HL
POP HL
JR XOS_FILL1
XOS_FILL2:
RET
;
;----------------------------------------------------------------------
; BLOCK COPY BC BYTES FROM HL (SOURCE) TO DE (DEST).
;----------------------------------------------------------------------
;
XOS_BLKCPY:
PUSH BC ; COUNT ==> TOS
; SETUP XOSERA VRAM READ ADDRESS FROM HL
PUSH DE
LD D,H
LD E,L
XM_SETW(ZXM_RD_XADDR)
; SETUP XOSERA VRAM WRITE ADDRESS FROM DE
POP DE
XM_SETW(ZXM_WR_XADDR)
XOS_BLKCPY1:
; GET NEXT SOURCE WORD INTO DE
XM_GETW(ZXM_XDATA)
; WRITE DE TO DEST WORD
XM_SETW(ZXM_XDATA)
; DECREMENT BYTE COUNT AND CHECK FOR COMPLETION
EX (SP),HL ; GET COUNT, SAVE HL
DEC H ; DECREMENT
LD A,H ; TEST FOR
CP L ; ... ZERO
EX (SP),HL ; COUNT BACK TO TOS, RESTORE HL
JR NZ,XOS_BLKCPY1 ; LOOP IF NOT ZERO
POP BC ; CLEAN UP STACK
RET ; DONE
;
;----------------------------------------------------------------------
; SCROLL ENTIRE SCREEN FORWARD BY ONE OR MORE LINES (CURSOR POSITION UNCHANGED)
;----------------------------------------------------------------------
; NUMBER OF LINES TO SCROLL COMES IN E
XOS_SCROLL:
; DEST ADDR IS START OF LAST ROW
PUSH DE ; SAVE SCROLL LINE COUNT
PUSH DE ; SAVE IT TWICE
PUSH DE ; SAVE IT THRICE
LD A,(XOS_ROWS)
DEC A
LD H,A ; H := ROWS - 1
LD A,(XOS_COLS)
LD E,A
CALL MULT8
LD B,H
LD C,L
LD HL,(XOS_OFF)
ADD HL,BC ; HL := DEST TILEMEM ADDRESS
; SOURCE ADDRESS is DEST ADDRESS - (COLS * LINES)
POP DE ; RESTORE LINE COUNT IN E
PUSH HL ; SAVE DEST ADDRESS SO WE CAN USE H
LD A,(XOS_COLS)
LD H,A
CALL MULT8
LD D,H
LD E,L ; DE := COLS * LINES
POP HL ; RESTORE DEST ADDR BACK TO HL
PUSH HL
OR A ; CLEAR CARRY
SBC HL,DE ; HL := SOURCE ADDR
POP BC ; BC := DEST ADDRESS
LD A,(XOS_ROWS)
POP DE ; GET SCROLL LINE COUNT IN TO E
SUB E
LD D,B
LD E,C ; RESTORE DE AS DEST ADDR
LD B,A ; B := ROWS - LINE COUNT => LOOP COUNTER
; USE BLKCPY TO COPY ONE ROW
XOS_SCROLL1:
PUSH HL ; HL IS SOURCE ADDR FOR BLOCK COPY
PUSH DE ; DE IS DEST ADDR FOR BLOCK COPY
PUSH BC ; B IS OUR LOOP COUNTER
LD A,(XOS_COLS) ; EXCEPT THAT BLOCK COPY USES BC FOR COPY COUNT
LD C,A
LD B,0
CALL XOS_BLKCPY
POP BC ; RESTORE LOOP COUNTER
; CHECK COUNT
DEC B
JR Z,XOS_SCROLL2 ; MOVE ON TO FILL WHEN DONE
; DECREMENT SOURCE AND DEST BY ONE ROW
POP HL ; HL := DEST ADDRESS
LD A,(XOS_COLS)
LD E,A
LD D,0
OR A ; CLEAR CARRY
SBC HL,DE ; HL := UPDATED DEST ADDRESS (DEST ADDR - COLS)
POP DE ; DE := SOURCE ADDR
PUSH HL ; SAVE UPDATED DEST TEMPORARILY
LD H,D
LD L,E
LD A,(XOS_COLS)
LD E,A
LD D,0
OR A ; CLEAR CARRY
SBC HL,DE ; HL := UPDATED SOURCE ADDRESS
POP DE ; DE := UPDATED DEST ADDRESS
JR XOS_SCROLL1 ; LOOP AROUND
XOS_SCROLL2:
POP DE
POP HL ; CLEAN UP STACK
POP DE ; RESTORE SCROLL LINE COUNT
; NOW FILL THE E LINES AT THE TOP OF THE SCREEN.
; FIRST, SAVE OFF CURRENT CURSOR POSITION, THE SET IT TO 0,0
LD HL,(XOS_POS)
PUSH HL
LD HL,(XOS_OFF)
LD (XOS_POS),HL ; CURSOR POSITION NOW 0,0
; COMPUTE THE NUMBER OF BYTES FILL WHICH IS COLS * LINES
LD A,(XOS_COLS)
LD H,A
CALL MULT8
LD B,H
LD C,L
LD A,$20 ; FILL CHAR IS SPACE
CALL XOS_FILL
POP HL
LD (XOS_POS),HL ; RESTORE ORIGINAL CURSOR POSITION
RET
;
;----------------------------------------------------------------------
; REVERSE SCROLL ENTIRE SCREEN BY ONE LINE (CURSOR POSITION UNCHANGED)
;----------------------------------------------------------------------
; NUMBER OF LINES TO SCROLL COMES IN E
XOS_RSCROLL:
PUSH DE ; SAVE SCROLL LINE COUNT
PUSH DE ; NEED IT OFF THE STACK TWICE
PUSH DE ; NEED IT OFF THE STACK THRICE
; DEST ADDR IS ROW=0, COL=0
LD DE,(XOS_OFF)
XM_SETW(ZXM_WR_XADDR) ; SET DEST ADDR IN XOSERA
POP DE ; RESTORE SCROLL LINE COUNT IN E
; SOURCE ADDR (HL) = XOS_OFF + XOS_COLS * E
LD A,(XOS_COLS)
LD H,A
CALL MULT8 ; HL := XOS_COLS * E
LD BC,(XOS_OFF)
ADD HL,BC ; HL := SOURCE ADDR := XOS_OFF + XOS_COLS * E
LD D,H
LD E,L
XM_SETW(ZXM_RD_XADDR) ; SET SOURCE ADDR IN XOSERA
; COMPUTE THE COUNT OF WORDS TO MOVE = COLS * (ROWS - LINES)
POP DE ; RESTORE SCROLL LINE COUNT IN E
LD A,(XOS_ROWS)
SUB E
LD H,A ; H := ROWS - LINES
LD A,(XOS_COLS)
LD E,A ; E := COLS
CALL MULT8
LD B,H
LD C,L ; BC = COUNT := COLS * (ROW - LINES)
PUSH BC ; SAVE FOR LATER USE BY FILL
XOS_RSCROLL1:
PUSH BC ; MACROS BELOW ALTER C, SO SAVE
XM_GETW(ZXM_XDATA) ; TRANSFER A WORD FROM TILEMEM SRC TO DEST
XM_SETW(ZXM_XDATA)
POP BC ; RESTORE LOOP COUNT
; CHECK COUNT
DEC BC ; DECREMENT COUNT
LD A,B ; TEST FOR
OR C ; ... ZERO
JR Z,XOS_RSCROLL2 ; MOVE ON TO FILL WHEN DONE
JR XOS_RSCROLL1
XOS_RSCROLL2:
; NOW DO THE FILL OF THE EXPOSED LINES AT THE BOTTOM OF THE SCREEN.
; DESTINATION VRAM ADDRESS FOR THIS FILL IS THE COUNT FROM ABOVE PLUS VRAM OFFSET
POP BC ; RESTORE COUNT
POP DE ; RESTORE LINES IN E
LD A,(XOS_COLS)
LD H,A
PUSH BC ; SAVE COUNT AGAINT
CALL MULT8 ; HL := XOS_COLS * LINES
LD B,H
LD C,L ; BC NOW HAS FILL WORD COUNT
POP HL ; RESTORE SCROLL WORD COUNT TO HL
LD DE,(XOS_OFF)
ADD HL,DE ; ADD IN OFFSET
LD D,H
LD E,L ; DE NOW HAS DEST VRAM ADDR
LD HL,(XOS_POS) ; XOS_FILL USES XOS_POS AS DEST
PUSH HL ; SAVE CURRENT CURSOR POSITION
LD (XOS_POS),DE
LD A,$20 ; USE SPACE TO FILL (USING CURRENT COLOR/ATTR)
CALL XOS_FILL
POP HL
LD (XOS_POS),HL ; RESTORE PREVIOUS CURSOR POSITION
XOR A ; SIGNAL SUCCESS
RET
;
;==================================================================================================
; XOSERA DRIVER - DATA
;==================================================================================================
;
XOS_ATTR: .DB 0 ; CURRENT COLOR
XOS_POS: .DW 0 ; CURRENT DISPLAY POSITION
XOS_OFF: .DW 0 ; SCREEN START OFFSET INTO XOSERA VRAM
XOS_RUB: .DB 0 ; REVERSE/UNDERLINE/BLINK (-----RUB)
XOS_COLS: .DB 0 ; NUMBER OF COLUMNS
XOS_ROWS: .DB 0 ; NUMBER OF ROWS
XOS_BASE_INIT:
.DW $0000 ; XR_VID_CTRL => NO PLAYFIELD COLOR SWAP. BORDER CORDER = 0
.DW $0000 ; XR_COPP_CTRL => DISABLE COPPER
.DW $0000 ; XR_AUD_CTRL => DISABLE AUDIO
.DW $0000 ; XR_SCANLINE => JUST SET TO ZERO
.DW $0000 ; XR_VID_LEFT => LEFT EDGE OF ACTIVE DISPLAY => 0
.DW 640 ; XR_VID_RIGHT => RIGHT EDGE OF ACTIVE DISPLAY => 640
.DW $0000 ; XR_POINTER_H => HIDE POINTER, SO SET TO 0
.DW $0000 ; XR_POINTER_V => HIDE POINTER, SO SET TO 0
PF_640x480x4:
; CONFIGURE PLAYFIELD FOR 640x480x4BPP BITMAP GRAPHICS (LETTERBOXED TO 640 X 400)
.DW $0050 ; GFX_CTRL
.DW $0000 ; TILE_CTRL => IGNORED IN BITMAP MODE
.DW $0000 ; DISP_ADDR => START OF VRAM
.DW $00A0 ; LINE_LEN => 640 PIXELS WIDE / 4 PIXELS PER WORD = 160d
.DW $0000 ; HV_FSCALE => NO FRACTIONAL SCALING
.DW $0000 ; H_SCROLL => NO HORIZONTAL FINE SCROLLING
.DW $0000 ; V_SCROLL => NO VERTICAL FINE SCROLLING
PF_80X30_TILED:
; CONFIGURE PLAYFIELD FOR 80 X 30 TILED MODE
; TILEMAP AND 8x16 FONT DATA BOTH RESIDE IN TILEMEM (AS OPPOSED TO VRAM)
.DW $0000 ; GFX_CTRL
.DW FONT_ST_8x16_ADDR | TILE_CTRL_DISP_TILEMEM_F | 15; TILE_CTRL => (LAST ONE IS TILE HEIGHT - 1)
.DW FONT_ST_8x16_ADDR + FONT_ST_8x16_SIZE ; DISP_ADDR => TILEMAP STATS JUST AFTER FONT DATA IN TILEMEM.
.DW $0050 ; LINE_LEN => 80 COLS
.DW $0000 ; HV_FSCALE => NO FRACTIONAL SCALING
.DW $0000 ; H_SCROLL => NO HORIZONTAL FINE SCROLLING
.DW $0000 ; V_SCROLL => NO VERTICAL FINE SCROLLING
PF_80X60_TILED:
; CONFIGURE PLAYFIELD FOR 80 X 60 TILED MODE
; TILEMAP WILL RESIDE IN TILEMEM, BUT DATA IS AT $FC00 IN VRAM
.DW $0000 ; GFX_CTRL
.DW $FC00 | TILE_CTRL_DISP_TILEMEM_F | TILE_CTRL_TILE_VRAM_F | 7; TILE_CTRL => (LAST ONE IS TILE HEIGHT - 1)
.DW $4000 ; DISP_ADDR => TILEMAP STARTS AT BEGINNING OF TILEMEM
.DW $0050 ; LINE_LEN => 80 COLS
.DW $0000 ; HV_FSCALE => NO FRACTIONAL SCALING
.DW $0000 ; H_SCROLL => NO HORIZONTAL FINE SCROLLING
.DW $0000 ; V_SCROLL => NO VERTICAL FINE SCROLLING
XOS_PALETTE:
; SET THE FIRST SIXTEEN ENTRIES OF A XOSERA PALETTE TO MATCH WHAT IS EXPECTED BY ROMWBW.
.DW $0000 ; 0: BLACK
.DW $0A00 ; 1: RED
.DW $00A0 ; 2: GREEN
.DW $0A50 ; 3: BROWN
.DW $000A ; 4: BLUE
.DW $0A0A ; 5: MAGENTA
.DW $00AA ; 6: CYAN
.DW $0AAA ; 7: WHITE
.DW $0555 ; 8: GRAY
.DW $0F55 ; 9: LIGHT RED
.DW $05F5 ; 10: LIGHT GREEN
.DW $0FF5 ; 11: YELLOW
.DW $055F ; 12: LIGHT BLUE
.DW $0F5F ; 13: LIGHT MAGENTA
.DW $05FF ; 14: LIGHT CYAN
.DW $0FFF ; 15: BRIGHT WHITE
; XOSERA HAS A BUILT-IN AMIGA-ISH COPROCESSOR. WE USE IT HERE TO LIMIT THE GRAPHICS
; BITMAP DISPLAY TO 600x400. THIS IS REQUIRED BECAUSE WHILE XOSERA OUTPUTS a 640 X 480
; BY 60 HZ VGA SIGNAL, THERE IS NOT ENOUGH VRAM FOR A FULL 640 X 480 X 4BPP BITMAP. SO WE
; RESTRICT TO 640x400 AND USE SOME COPPER TRICKS TO BLANK THE OTHER 80 LINES OF
; THE DISPLAY. ESSENTIALLY WE ARE 'LETTERBOXING' A 640 X 400 BITMAP IN THE VERTICAL
; CENTER OF A 640 X 480 DISPLAY. NOTE THAT TEXT MODE STILL USES THE ENTIRE 640 X 480
; DISPLAY.
XOS_COPPER:
.DW $D101,$0800 ; LDM $C101
.DW $1800,$0010 ; STM XR_PA_GFX_CTRL ; start the frame by blanking the display
.DW $2828 ; VPOS #40 ; Wait for line 40
.DW $0800,$0000 ; LDI #0
.DW $1800,$0017 ; STM XR_PA_LINE_ADDR
.DW $D100,$0800 ; LDM $C100 ; get value of XR_PA_GFX_CTRL with BLANK bit NOT set
.DW $1800,$0010 ; STM XR_PA_GFX_CTRL ; unblank playfield A
.DW $D101,$0800 ; LDM $C101 ; get value of XR_PA_GFX_CTRL with BLANK bit set
.DW $29B8 ; VPOS #440 ; wait until vertical line 440
.DW $1800,$0010 ; STM XR_PA_GFX_CTRL ; blank playfield A
.DW $2BFF ; VPOS #V_EOF ; wait until end of frame
;
;==================================================================================================
; XOSERA DRIVER - INSTANCE DATA
;==================================================================================================
;
XOS_IDAT:
.DB KBDMODE_NONE
.DB 0
.DB 0
XOS_IDAT2:
.DB KBDMODE_NONE
.DB 0
.DB 0
;
;--------------------------------------------------------------------------------------------------
; HBIOS MODULE TRAILER
;--------------------------------------------------------------------------------------------------
;
END_XOS .EQU $
SIZ_XOS .EQU END_XOS - ORG_XOS
;
MEMECHO "XOS occupies "
MEMECHO SIZ_XOS
MEMECHO " bytes.\n"