From 936a3958a5b746831b9becf4a049b72a13f946b0 Mon Sep 17 00:00:00 2001 From: Rob Gowin Date: Mon, 2 Jun 2025 08:53:56 -0400 Subject: [PATCH] Add VDA driver for Xosera, an FPGA-based video controller. --- Doc/ChangeLog.txt | 3 +- Source/Doc/Hardware.md | 1 + Source/Doc/Introduction.md | 6 +- Source/Doc/SystemGuide.md | 19 +- Source/HBIOS/Config/RCZ80_xosera.asm | 54 ++ Source/HBIOS/cfg_MASTER.asm | 3 + Source/HBIOS/hbios.asm | 16 + Source/HBIOS/hbios.inc | 1 + Source/HBIOS/xosera.asm | 1050 ++++++++++++++++++++++++++ 9 files changed, 1142 insertions(+), 11 deletions(-) create mode 100644 Source/HBIOS/Config/RCZ80_xosera.asm create mode 100644 Source/HBIOS/xosera.asm diff --git a/Doc/ChangeLog.txt b/Doc/ChangeLog.txt index 83adccf5..f790b31a 100644 --- a/Doc/ChangeLog.txt +++ b/Doc/ChangeLog.txt @@ -1,12 +1,13 @@ Version 3.6 ----------- +- RDG: Added VDA driver for Xosera FPGA-based VDC - MGG: Added COBOL language disk image - WDC: Added config options to PCF driver - WBW: Enabled dynamic CPU speed update on LCD screen - WBW: Improve LPT driver boot messaging when not detected (per Robb Bates) - WBW: Correct DS1307 boot date/time display (per Tadeusz Pycio) - WBW: Add -DELAY option to TUNE app (per Robb Bates) -- R?G: Add online documentation site +- RDG: Add online documentation site - WBW: Added enhanced Hi-Tech C Compiler files from Ladislau Szilagyi - WBW: Added boundary check to ram/rom disk driver diff --git a/Source/Doc/Hardware.md b/Source/Doc/Hardware.md index 46776993..93185ab4 100644 --- a/Source/Doc/Hardware.md +++ b/Source/Doc/Hardware.md @@ -2279,6 +2279,7 @@ the active platform and configuration. | VDU | MC6845 Family Video Display Controller (*) | | VGA | HD6445CP4-based Video Display Controller | | VRC | VGARC Video Display Controller | +| XOSERA | XOSERA FPGA-based Video Display Controller | Note: diff --git a/Source/Doc/Introduction.md b/Source/Doc/Introduction.md index 82a6fd57..bbfd6a8f 100644 --- a/Source/Doc/Introduction.md +++ b/Source/Doc/Introduction.md @@ -41,7 +41,7 @@ Supported hardware features of RomWBW include: * Banked memory services for several banking designs * Disk drivers for RAM, ROM, Floppy, IDE ATA/ATAPI, CF, SD, USB, Zip, Iomega * Serial drivers including UART (16550-like), ASCI, ACIA, SIO -* Video drivers including TMS9918, SY6545, MOS8563, HD6445 +* Video drivers including TMS9918, SY6545, MOS8563, HD6445, Xosera * Keyboard (PS/2) drivers via VT8242 or PPI interfaces * Real time clock drivers including DS1302, BQ4845 * Support for CP/NET networking using Wiznet, MT011 or Serial @@ -324,7 +324,9 @@ please let me know if I missed you! * Les Bird has contributed support for the NABU w/ Option Board -* Rob Gowin created an online documentation site via MkDocs. +* Rob Gowin created an online documentation site via MkDocs, and + contributed a driver for the Xosera FPGA-based video + controller. `\clearpage`{=latex} diff --git a/Source/Doc/SystemGuide.md b/Source/Doc/SystemGuide.md index c43443dd..c9d6180b 100644 --- a/Source/Doc/SystemGuide.md +++ b/Source/Doc/SystemGuide.md @@ -1756,14 +1756,17 @@ All video units are assigned a Device Type ID which indicates the specific hardware device driver that handles the unit. The table below enumerates their values. -| **Device Type** | **ID** | **Description** | **Driver** | -|-----------------|-------:|------------------------------------------|------------| -| VDADEV_VDU | 0x00 | MC6845 Family Video Display Controller | vdu.asm | -| VDADEV_CVDU | 0x01 | MC8563-based Video Display Controller | cvdu.asm | -| VDADEV_GDC | 0x02 | uPD7220 Video Display Controller | gdc.asm | -| VDADEV_TMS | 0x03 | TMS9918/38/58 Video Display Controller | tms.asm | -| VDADEV_VGA | 0x04 | HD6445CP4-based Video Display Controller | vga.asm | -| VDADEV_VRC | 0x05 | VGARC | vrc.asm | +| **Device Type** | **ID** | **Description** | **Driver** | +|-----------------|-------:|--------------------------------------------|------------| +| VDADEV_VDU | 0x00 | MC6845 Family Video Display Controller | vdu.asm | +| VDADEV_CVDU | 0x01 | MC8563-based Video Display Controller | cvdu.asm | +| VDADEV_GDC | 0x02 | uPD7220 Video Display Controller | gdc.asm | +| VDADEV_TMS | 0x03 | TMS9918/38/58 Video Display Controller | tms.asm | +| VDADEV_VGA | 0x04 | HD6445CP4-based Video Display Controller | vga.asm | +| VDADEV_VRC | 0x05 | VGARC | vrc.asm | +| VDADEV_EF | 0x06 | EF9345 | ef.asm | +| VDADEV_FV | 0x07 | S100 FPGA VGA | fv.asm | +| VDADEV_XOSERA | 0x08 | Xosera FPGA-based Video Display Controller | xosera.asm | Depending on the capabilities of the hardware, the use of colors and attributes may or may not be supported. If the hardware does not support diff --git a/Source/HBIOS/Config/RCZ80_xosera.asm b/Source/HBIOS/Config/RCZ80_xosera.asm new file mode 100644 index 00000000..51098f56 --- /dev/null +++ b/Source/HBIOS/Config/RCZ80_xosera.asm @@ -0,0 +1,54 @@ +; +;================================================================================================== +; ROMWBW CUSTOM USER BUILD SETTINGS EXAMPLE FOR RCBUS Z80 +;================================================================================================== +; +; THIS FILE IS AN EXAMPLE OF A CUSTOM USER SETTINGS FILE. THESE +; SETTINGS OVERRIDE THE DEFAULT SETTINGS OF THE INHERITED FILES AS +; DESIRED BY A USER. +; +; ROMWBW USES CASCADING CONFIGURATION FILES AS INDICATED BELOW: +; +; cfg_MASTER.asm - MASTER: CONFIGURATION FILE DEFINES ALL POSSIBLE ROMWBW SETTINGS +; | +; +-> cfg_.asm - PLATFORM: DEFAULT SETTINGS FOR SPECIFIC PLATFORM +; | +; +-> Config/_std.asm - BUILD: SETTINGS FOR EACH OFFICIAL DIST BUILD +; | +; +-> Config/_.asm - USER: CUSTOM USER BUILD SETTINGS +; +; THE TOP (MASTER CONFIGURATION) FILE DEFINES ALL POSSIBLE ROMWBW +; CONFIGURATION SETTINGS. EACH FILE BELOW THE MASTER CONFIGURATION FILE +; INHERITS THE CUMULATIVE SETTINGS OF THE FILES ABOVE IT AND MAY +; OVERRIDE THESE SETTINGS AS DESIRED. +; +; OTHER THAN THE TOP MASTER FILE, EACH FILE MUST "#INCLUDE" ITS PARENT +; FILE (SEE #INCLUDE STATEMENT BELOW). THE TOP TWO FILES SHOULD NOT BE +; MODIFIED. +; +; THIS FILE EXEMPLIFIES THE IDEAL WAY TO CREATE A USER SPECIFIC BUILD +; CONFIGURATION. NOTICE THAT IT INCLUDES THE DEFAULT BUILD SETTINGS +; FILE AND OVERRIDES SOME DESIRED SETTINGS. +; +; BY CREATING A CUSTOM USER SETTINGS FILE, YOU ARE LESS LIKELY TO BE +; IMPACTED BY FUTURE CHANGES BECAUSE YOU WILL BE INHERITING MOST +; OF YOUR SETTINGS WHICH WILL BE UPDATED BY AUTHORS AS ROMWBW EVOLVES. +; +; PLEASE REFER TO THE CUSTOM BUILD INSTRUCTIONS (README.TXT) IN THE +; SOURCE DIRECTORY (TWO DIRECTORIES ABOVE THIS ONE). +; +; *** WARNING: ASIDE FROM THE MASTER CONFIGURATION FILE, YOU MUST USE +; ".SET" TO OVERRIDE SETTINGS. THE ASSEMBLER WILL ERROR IF YOU ATTEMPT +; TO USE ".EQU" BECAUSE IT WON'T LET YOU REDEFINE A SETTING WITH ".EQU". +; +; THIS FILE ENABLES THE XOSERA DRIVER WITH A BASE ADDRESS Of 0XE0 +; AND DISPLAY SIZE OF 80 COLUMNS X 30 ROWS +; +#INCLUDE "Config/RCZ80_std.asm" ; INHERIT FROM OFFICIAL BUILD SETTINGS +; +XOSENABLE .SET TRUE ; XOSERA: ENABLE XOSERA VIDEO DRIVERS (XOSERA.ASM) +XOS_BASE .SET $20 ; XOSERA: I/O BASE ADDRESS (REQUIRES 32 BYTES) +XOSSIZ .SET V80X30 ; XOSERA: DISPLAY FORMAT [V80X30|V80X60] +; +AUTOCON .SET FALSE ; ENABLE CONSOLE TAKEOVER AT LOADER PROMPT +VDAEMU_SERKBD .SET $0 ; VDA EMULATION: SERIAL KBD UNIT #, OR $FF FOR HW KBD diff --git a/Source/HBIOS/cfg_MASTER.asm b/Source/HBIOS/cfg_MASTER.asm index a117f480..cad61333 100644 --- a/Source/HBIOS/cfg_MASTER.asm +++ b/Source/HBIOS/cfg_MASTER.asm @@ -311,6 +311,9 @@ VRCENABLE .EQU FALSE ; VRC: ENABLE VGARC VIDEO/KBD DRIVER (VRC.ASM) SCONENABLE .EQU FALSE ; SCON: ENABLE S100 CONSOLE DRIVER (SCON.ASM) EFENABLE .EQU FALSE ; EF: ENABLE EF9345 VIDEO DRIVER (EF.ASM) FVENABLE .EQU FALSE ; FV: ENABLE FPGA VGA VIDEO DRIVER (FV.ASM) +XOSENABLE .EQU FALSE ; XOSERA: ENABLE XOSERA VIDEO DRIVERS (XOSERA.ASM) +XOS_BASE .EQU $20 ; XOSERA: I/O BASE ADDRESS (REQUIRES 32 BYTES) +XOSSIZ .EQU V80X30 ; XOSERA: DISPLAY FORMAT [V80X30|V80X60] ; MDENABLE .EQU TRUE ; MD: ENABLE MEMORY (ROM/RAM) DISK DRIVER (MD.ASM) MDROM .EQU TRUE ; MD: ENABLE ROM DISK diff --git a/Source/HBIOS/hbios.asm b/Source/HBIOS/hbios.asm index e12fd369..f261b53c 100644 --- a/Source/HBIOS/hbios.asm +++ b/Source/HBIOS/hbios.asm @@ -3955,6 +3955,9 @@ HB_PCINITTBL: #IF (PIO_4P | PIO_ZP) .DW PIO_PREINIT #ENDIF +#IF (XOSENABLE) + .DW XOS_PREINIT +#ENDIF ; HB_PCINITTBLLEN .EQU (($ - HB_PCINITTBL) / 2) ; @@ -4090,6 +4093,9 @@ HB_INITTBL: #IF (SCONENABLE) .DW SCON_INIT #ENDIF +#IF (XOSENABLE) + .DW XOS_INIT +#ENDIF #IF (LPTENABLE) .DW LPT_INIT #ENDIF @@ -8831,6 +8837,7 @@ PS_VDVGA .TEXT "VGA$" PS_VDVRC .TEXT "VRC$" PS_VDEF .TEXT "EF$" PS_VDFV .TEXT "FV$" +PS_VDXOSERA .TEXT "XOSERA$" ; ; VIDEO TYPE STRINGS ; @@ -9168,6 +9175,15 @@ SIZ_FV .EQU $ - ORG_FV MEMECHO " bytes.\n" #ENDIF ; +#IF (XOSENABLE) +ORG_XOS .EQU $ + #INCLUDE "xosera.asm" +SIZ_XOS .EQU $ - ORG_XOS + MEMECHO "XOS occupies " + MEMECHO SIZ_XOS + MEMECHO " bytes.\n" +#ENDIF +; #IF (DMAENABLE) ORG_DMA .EQU $ #INCLUDE "dma.asm" diff --git a/Source/HBIOS/hbios.inc b/Source/HBIOS/hbios.inc index c542a497..425536b6 100644 --- a/Source/HBIOS/hbios.inc +++ b/Source/HBIOS/hbios.inc @@ -450,6 +450,7 @@ VDADEV_VGA .EQU $04 ; ECB VGA3 - HITACHI HD6445 VDADEV_VRC .EQU $05 ; VGARC VDADEV_EF .EQU $06 ; EF9345 VDADEV_FV .EQU $07 ; S100 FPGA VGA +VDADEV_XOSERA .EQU $08 ; XOSERA RCBUS ; ; SOUND DEVICE IDS ; diff --git a/Source/HBIOS/xosera.asm b/Source/HBIOS/xosera.asm new file mode 100644 index 00000000..54564f82 --- /dev/null +++ b/Source/HBIOS/xosera.asm @@ -0,0 +1,1050 @@ +;====================================================================== +; 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 0x0000 ; (R/W) 0x0000-0x0007 8 config/ctrl registers +XR_PA_REGS .EQU 0x0010 ; (R/W) 0x0010-0x0017 8 playfield A video registers +XR_PB_REGS .EQU 0x0018 ; (R/W) 0x0018-0x001F 8 playfield B video registers +XR_AUDIO_REGS .EQU 0x0020 ; (-/W) 0x0020-0x002F 16 audio playback registers +XR_BLIT_REGS .EQU 0x0040 ; (-/W) 0x0040-0x0049 10 blitter registers +XR_TILE_ADDR .EQU 0x4000 ; (R/W) 0x4000-0x53FF tile glyph/tile map memory +XR_TILE_SIZE .EQU 0x1400 ; 4096+1024 x 16-bit tile glyph/tile map memory +XR_COLOR_ADDR .EQU 0x8000 ; (R/W) 0x8000-0x81FF 2 x A & B color lookup memory +XR_COLOR_SIZE .EQU 0x0200 ; 2 x 256 x 16-bit words (0xARGB) +XR_COLOR_A_ADDR .EQU 0x8000 ; (R/W) 0x8000-0x80FF A 256 entry color lookup memory +XR_COLOR_A_SIZE .EQU 0x0100 ; 256 x 16-bit words (0xARGB) +XR_COLOR_B_ADDR .EQU 0x8100 ; (R/W) 0x8100-0x81FF B 256 entry color lookup memory +XR_COLOR_B_SIZE .EQU 0x0100 ; 256 x 16-bit words (0xARGB) +XR_POINTER_ADDR .EQU 0x8200 ; (-/W) 0x8200-0x82FF 256 word 32x32 4-bpp pointer image +XR_POINTER_SIZE .EQU 0x0100 ; 256 x 16-bit words (4-bit pixels) +XR_COPPER_ADDR .EQU 0xC000 ; (R/W) 0xC000-0xC5FF copper memory (16-bit words) +XR_COPPER_SIZE .EQU 0x0600 ; 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 0x00 ; (R /W) display control and border color index +XR_COPP_CTRL .EQU 0x01 ; (R /W) display synchronized coprocessor control +XR_AUD_CTRL .EQU 0x02 ; (- /-) TODO: audio channel control +XR_SCANLINE .EQU 0x03 ; (R /W) read scanline (incl. offscreen), write signal video interrupt +XR_VID_LEFT .EQU 0x04 ; (R /W) left edge of active display window (typically 0) +XR_VID_RIGHT .EQU 0x05 ; (R /W) right edge of active display window +1 (typically 640 or 848) +XR_POINTER_H .EQU 0x06 ; (- /W) pointer sprite raw H position +XR_POINTER_V .EQU 0x07 ; (- /W) pointer sprite raw V position / pointer color select +; Playfield A Control XR Registers +XR_PA_GFX_CTRL .EQU 0x10 ; (R /W ) playfield A graphics control +XR_PA_TILE_CTRL .EQU 0x11 ; (R /W ) playfield A tile control +XR_PA_DISP_ADDR .EQU 0x12 ; (R /W ) playfield A display VRAM start address +XR_PA_LINE_LEN .EQU 0x13 ; (R /W ) playfield A display line width in words +XR_PA_HV_FSCALE .EQU 0x14 ; (R /W ) playfield A horizontal and vertical fractional scale +XR_PA_H_SCROLL .EQU 0x15 ; (R /W ) playfield A horizontal and vertical fine scroll +XR_PA_V_SCROLL .EQU 0x16 ; (R /W ) playfield A horizontal and vertical fine scroll +XR_PA_LINE_ADDR .EQU 0x17 ; (- /W ) playfield A scanline start address (loaded at start of line) +; Playfield B Control XR Registers +XR_PB_GFX_CTRL .EQU 0x18 ; (R /W ) playfield B graphics control +XR_PB_TILE_CTRL .EQU 0x19 ; (R /W ) playfield B tile control +XR_PB_DISP_ADDR .EQU 0x1A ; (R /W ) playfield B display VRAM start address +XR_PB_LINE_LEN .EQU 0x1B ; (R /W ) playfield B display line width in words +XR_PB_HV_FSCALE .EQU 0x1C ; (R /W ) playfield B horizontal and vertical fractional scale +XR_PB_H_SCROLL .EQU 0x1D ; (R /W ) playfield B horizontal and vertical fine scroll +XR_PB_V_SCROLL .EQU 0x1E ; (R /W ) playfield B horizontal and vertical fine scroll +XR_PB_LINE_ADDR .EQU 0x1F ; (- /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 + 0x0000 +FONT_ST_8x16_SIZE .EQU 0x800 +FONT_ST_8x8_ADDR .EQU XR_TILE_ADDR + 0x0800 +FONT_ST_8x8_SIZE .EQU 0x400 +FONT_PC_8x8_ADDR .EQU XR_TILE_ADDR + 0x0C00 +FONT_PC_8x8_SIZE .EQU 0x400 +FONT_HEX_8x8_ADDR .EQU XR_TILE_ADDR + 0x1000 +FONT_HEX_8x8_SIZE .EQU 0x400 + +TILE_CTRL_TILE_VRAM_F .EQU 0x0100 +TILE_CTRL_DISP_TILEMEM_F .EQU 0x0200 + +; 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 + +;====================================================================== +; 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