mirror of
https://github.com/wwarthen/RomWBW.git
synced 2026-02-06 14:11:48 -06:00
Updated the TMS driver VRAM probe code to use the pre-existing driver routines for setting registers and RAM address. This makes the code substantially smaller and makes it consistent with the rest of the driver. No functional changes in the VRAM detection algorithm.
1732 lines
48 KiB
NASM
1732 lines
48 KiB
NASM
;======================================================================
|
|
; TMS9918, V9938/58 VDU DRIVER
|
|
;
|
|
; WRITTEN BY: DOUGLAS GOODALL
|
|
; UPDATED BY: WAYNE WARTHEN -- 4/7/2013
|
|
; UPDATED BY: DEAN NETHERTON -- 5/26/2021 - V9958 SUPPORT
|
|
; UPDATED BY: JOSE L. COLLADO -- 11/15/2023 - MEMORY MAP CHANGES
|
|
; UPDATED BY: DAN WERNER -- 2/11/2024 - DUODYNE SUPPORT
|
|
; UPDATED BY: DAN WERNER -- 11/27/2025 - N8PC SUPPORT
|
|
; UPDATED BY: DEAN NETHERTON -- 1/7/2026 - ADDED RUNTIME DETECTION OF CHIP TYPE AND VRAM SIZE
|
|
; UPDATED BY: HENK BERENDS - 1/15/2026 - ADDED F18A FPGA DETECTION AND REPORT VDP_ID IN VDADEV FUNCTION
|
|
;
|
|
;======================================================================
|
|
;
|
|
; TODO:
|
|
; - CAN WE SET 40/80 COLUMNS AT RUNTIME BASED ON DETECTED VDP_ID (40:ID=0 80:ID>0)?
|
|
; - IS THERE A NEED TO DETECT OTHER THAN F18A FPGA? IF YES WHICH ONE(S)?
|
|
; - IMPLEMENT SET CURSOR STYLE (VDASCS) FUNCTION?
|
|
; - IMPLEMENT ALTERNATE DISPLAY MODES?
|
|
; - IMPLEMENT DYNAMIC READ/WRITE OF CHARACTER BITMAP DATA?
|
|
; - SET REGISTERS DEPENDING ON TMSMODE AND VDP_ID (USE COLECO OR MSX DEFAULTS)?
|
|
; - DETECT VRAM SIZES 4KB,16KB AND 32KB
|
|
; - REPORT OTHER ATTRIBUTES IN VDADEV FUNCTION?
|
|
;
|
|
;
|
|
;======================================================================
|
|
;
|
|
; NOTES:
|
|
;
|
|
; - WHEN SETTING REGISTERS, YOU FIRST WRITE THE VALUE FOLLOWED BY
|
|
; THE REGISTER NUMBER. IF A TMS VDP INTERRUPT OCCURS BETWEEN THESE
|
|
; TWO PORT OUTPUTS, IT WILL DISRUPT THE SEQUENCE. IF VDP INTS
|
|
; ARE ACTIVE, THEN INTS MUST BE DISABLED WHEN SETTING REGISTERS.
|
|
;
|
|
; - THE TMS CHIP FAMILY IS VERY SENSITIVE TO REQUIRED DELAYS BETWEEN
|
|
; PORT WRITES. TMS9938/58 REQUIRES LONGER DELAY THAN 9918. THE
|
|
; DRIVER IMPLEMENTS THESE DELAYS IN SOFTWARE, BUT MAY NEED TO BE
|
|
; TUNED DEPENDING ON SPEED OF SYSTEM CPU. THE V9958 HAS A /WAIT
|
|
; PIN THAN CAN BE CONNECTED TO THE CPU. IF THIS IS USED, THEN
|
|
; THE SOFTWARE WAITS CAN POTENTIALLY BE DISABLED. HOWEVER, I
|
|
; HAVE NOT HAD SUCCESS WITH THIS IN PRACTICE. SEE THE TMS_IODELAY
|
|
; MACRO BELOW TO ADJUST THE DELAY. SEE MORE COMMENTS BELOW
|
|
; WHERE THE TMS_IODELAY MACRO IS DEFINED.
|
|
;
|
|
;======================================================================
|
|
; TMS DRIVER - CONSTANTS
|
|
;======================================================================
|
|
;
|
|
; 40 Column Video Memory Map
|
|
; -----------------------------------
|
|
; Start Length
|
|
; Pattern Table: $0000 $0800 Font data (8 x 256)
|
|
; Unused: $0800 $1000
|
|
; Sprite Patterns: $1800 $0800
|
|
; Color Table: $2000 $1800
|
|
; Name Table: $3800 $0400 Display characters (40 x 25)
|
|
; Sprite Attributes: $3B00 $0100
|
|
; Unused: $3C00 $0400
|
|
;
|
|
; 80 Column Video Memory Map (MSX like)
|
|
; -------------------------------------
|
|
; Start Length
|
|
; Pattern Table: $1000 $0800 Font data (8 x 256)
|
|
; Sprite Patterns: $???? $????
|
|
; Color Table: $???? $????
|
|
; Name Table: $0000 $0800 Display characters (80 x 25)
|
|
; Sprite Attributes: $???? $????
|
|
; Unused: $???? $????
|
|
;
|
|
TMSCTRL1: .EQU 1 ; CONTROL BITS
|
|
TMSINTEN: .EQU 5 ; INTERRUPT ENABLE BIT
|
|
;
|
|
TMSKBD_NONE .EQU 0
|
|
TMSKBD_KBD .EQU 1
|
|
TMSKBD_PPK .EQU 2
|
|
TMSKBD_MKY .EQU 3
|
|
TMSKBD_NABU .EQU 4
|
|
TMSKBD_USB .EQU 5
|
|
;
|
|
TMSKBD .EQU TMSKBD_NONE ; ASSUME NONE
|
|
;
|
|
DEVECHO "TMS: MODE="
|
|
;
|
|
#IF (TMSMODE == TMSMODE_SCG)
|
|
TMS_DATREG .EQU $98 ; READ/WRITE DATA
|
|
TMS_CMDREG .EQU $99 ; READ STATUS / WRITE REG SEL
|
|
TMS_ACR .EQU $9C ; AUX CONTROL REGISTER
|
|
DEVECHO "SCG"
|
|
#ENDIF
|
|
;
|
|
#IF (TMSMODE == TMSMODE_N8)
|
|
TMS_DATREG .EQU $98 ; READ/WRITE DATA
|
|
TMS_CMDREG .EQU $99 ; READ STATUS / WRITE REG SEL
|
|
TMS_PPIA .EQU $84 ; PPI PORT A
|
|
TMS_PPIB .EQU $85 ; PPI PORT B
|
|
TMS_PPIC .EQU $86 ; PPI PORT C
|
|
TMS_PPIX .EQU $87 ; PPI CONTROL PORT
|
|
TMSKBD .SET TMSKBD_PPK ; PPK KEYBOARD
|
|
DEVECHO "N8"
|
|
#ENDIF
|
|
;
|
|
#IF (TMSMODE == TMSMODE_N8PC)
|
|
TMS_DATREG .EQU $98 ; READ/WRITE DATA
|
|
TMS_CMDREG .EQU $99 ; READ STATUS / WRITE REG SEL
|
|
TMS_KBDDATA .EQU $80 ; KBD CTLR DATA PORT
|
|
TMS_KBDST .EQU $81 ; KBD CTLR STATUS/CMD PORT
|
|
TMSKBD .SET TMSKBD_KBD ; PS2 KEYBOARD
|
|
DEVECHO "N8PC"
|
|
#ENDIF
|
|
;
|
|
|
|
#IF (TMSMODE == TMSMODE_MSX)
|
|
TMS_DATREG .EQU $98 ; READ/WRITE DATA
|
|
TMS_CMDREG .EQU $99 ; READ STATUS / WRITE REG SEL
|
|
DEVECHO "MSX"
|
|
#ENDIF
|
|
;
|
|
#IF (TMSMODE == TMSMODE_MSXKBD)
|
|
TMS_DATREG .EQU $98 ; READ/WRITE DATA
|
|
TMS_CMDREG .EQU $99 ; READ STATUS / WRITE REG SEL
|
|
TMS_KBDDATA .EQU $60 ; KBD CTLR DATA PORT
|
|
TMS_KBDST .EQU $64 ; KBD CTLR STATUS/CMD PORT
|
|
TMSKBD .SET TMSKBD_KBD ; PS2 KEYBOARD
|
|
DEVECHO "MSXKBD"
|
|
#ENDIF
|
|
;
|
|
#IF (TMSMODE == TMSMODE_MSXMKY)
|
|
TMS_DATREG .EQU $98 ; READ/WRITE DATA
|
|
TMS_CMDREG .EQU $99 ; READ STATUS / WRITE REG SEL
|
|
TMSKBD .SET TMSKBD_MKY ; MSX KEYBOARD
|
|
DEVECHO "MSXMKY"
|
|
#ENDIF
|
|
;
|
|
#IF (TMSMODE == TMSMODE_MSXUKY)
|
|
TMS_DATREG .EQU $98 ; READ/WRITE DATA
|
|
TMS_CMDREG .EQU $99 ; READ STATUS / WRITE REG SEL
|
|
TMSKBD .SET TMSKBD_USB ; MSX KEYBOARD
|
|
DEVECHO "MSX-USB_KYB"
|
|
#ENDIF
|
|
;
|
|
#IF (TMSMODE == TMSMODE_MBC)
|
|
TMS_DATREG .EQU $98 ; READ/WRITE DATA
|
|
TMS_CMDREG .EQU $99 ; READ STATUS / WRITE REG SEL
|
|
TMS_ACR .EQU $9C ; AUX CONTROL REGISTER
|
|
TMS_KBDDATA .EQU $E2 ; KBD CTLR DATA PORT
|
|
TMS_KBDST .EQU $E3 ; KBD CTLR STATUS/CMD PORT
|
|
TMSKBD .SET TMSKBD_KBD ; PS2 KEYBOARD
|
|
DEVECHO "MBC"
|
|
#ENDIF
|
|
;
|
|
#IF (TMSMODE == TMSMODE_COLECO)
|
|
TMS_DATREG .EQU $BE ; READ/WRITE DATA
|
|
TMS_CMDREG .EQU $BF ; READ STATUS / WRITE REG SEL
|
|
DEVECHO "COLECO"
|
|
#ENDIF
|
|
;
|
|
#IF (TMSMODE == TMSMODE_DUO)
|
|
TMS_DATREG .EQU $A0 ; READ/WRITE DATA
|
|
TMS_CMDREG .EQU $A1 ; READ STATUS / WRITE REG SEL
|
|
TMS_ACR .EQU $A6 ; AUX CONTROL REGISTER
|
|
TMS_KBDDATA .EQU $4C ; KBD CTLR DATA PORT
|
|
TMS_KBDST .EQU $4D ; KBD CTLR STATUS/CMD PORT
|
|
TMSKBD .SET TMSKBD_KBD ; PS2 KEYBOARD
|
|
DEVECHO "DUO"
|
|
#ENDIF
|
|
;
|
|
#IF (TMSMODE == TMSMODE_NABU)
|
|
TMS_DATREG .EQU $A0 ; READ/WRITE DATA
|
|
TMS_CMDREG .EQU $A1 ; READ STATUS / WRITE REG SEL
|
|
TMSKBD .SET TMSKBD_NABU ; NABU KEYBOARD
|
|
DEVECHO "NABU"
|
|
#ENDIF
|
|
;
|
|
DEVECHO ", IO="
|
|
DEVECHO TMS_DATREG
|
|
;
|
|
TMS_ROWS .EQU 24
|
|
;
|
|
#IF (TMS80COLS)
|
|
TMS_FNTVADDR .EQU $1000 ; VRAM ADDRESS OF FONT DATA
|
|
TMS_FNTSIZE .EQU 8*256 ; ### JLC Mod for JBL compatibility ### = 8x8 Font 256 Chars
|
|
TMS_CHRVADDR .EQU $0000 ; VRAM ADDRESS OF CHAR SCREEN DATA (NEW CONSTANT) = REG2 * $400
|
|
TMS_COLS .EQU 80
|
|
#ELSE ; ALL OTHER MODES...
|
|
;TMS_FNTVADDR .EQU $0800 ; VRAM ADDRESS OF FONT DATA
|
|
TMS_FNTVADDR .EQU $0000 ; VRAM ADDRESS OF FONT DATA ### JLC Mod for JBL compatibility ### = REG4 * $800
|
|
TMS_FNTSIZE .EQU 8*256 ; ### JLC Mod for JBL compatibility ### = 8x8 Font 256 Chars
|
|
; ### JLC Fix to allow Name Table Addresses other than $0000 and JBL Compatibility ###
|
|
TMS_CHRVADDR .EQU $3800 ; VRAM ADDRESS OF CHAR SCREEN DATA (NEW CONSTANT) = REG2 * $400
|
|
TMS_COLS .EQU 40
|
|
#ENDIF
|
|
;
|
|
DEVECHO ", SCREEN="
|
|
DEVECHO TMS_COLS
|
|
DEVECHO "X"
|
|
DEVECHO TMS_ROWS
|
|
;
|
|
;;;#DEFINE USEFONT8X8
|
|
;;;#DEFINE TMS_FONT FONT8X8
|
|
#DEFINE USEFONT6X8
|
|
#DEFINE TMS_FONT FONT6X8
|
|
;
|
|
TERMENABLE .SET TRUE ; INCLUDE TERMINAL PSEUDODEVICE DRIVER
|
|
;
|
|
DEVECHO ", KEYBOARD="
|
|
;
|
|
#IF (TMSKBD == TMSKBD_NONE)
|
|
DEVECHO "NONE"
|
|
#ENDIF
|
|
;
|
|
#IF (TMSKBD == TMSKBD_PPK)
|
|
PPKENABLE .SET TRUE ; INCLUDE PPK KEYBOARD SUPPORT
|
|
DEVECHO "PPK"
|
|
#ENDIF
|
|
;
|
|
#IF (TMSKBD == TMSKBD_KBD)
|
|
KBDENABLE .SET TRUE ; INCLUDE PS2 KEYBOARD SUPPORT
|
|
DEVECHO "KBD"
|
|
#ENDIF
|
|
;
|
|
#IF (TMSKBD == TMSKBD_MKY)
|
|
MKYENABLE .SET TRUE ; INCLUDE MSX KEYBOARD SUPPORT
|
|
DEVECHO "MKY"
|
|
#ENDIF
|
|
;
|
|
#IF (TMSKBD == TMSKBD_NABU)
|
|
NABUKBENABLE .SET TRUE ; INCLUDE NABU KEYBOARD SUPPORT
|
|
DEVECHO "NABU"
|
|
#ENDIF
|
|
;
|
|
#IF (TMSKBD == TMSKBD_USB)
|
|
USBKYBENABLE .SET TRUE ; INCLUDE USB KEYBOARD SUPPORT
|
|
DEVECHO "USB-KYB"
|
|
#ENDIF
|
|
;
|
|
#IF (TMSTIMENABLE & (INTMODE > 0))
|
|
DEVECHO ", INTERRUPTS ENABLED"
|
|
#ENDIF
|
|
DEVECHO "\n"
|
|
;
|
|
; TMS_IODELAY IS USED TO ADD REQUIRED RECOVERY TIME TO TMS9918/V9958 I/O.
|
|
; THE DELAYS DEFINED BELOW ARE PRETTY CONSERVATIVE AND WILL PROBABLY BE
|
|
; OK FOR THE V9958 (SLOWEST VDP).
|
|
; THE DELAYS IMPLEMENTED HERE ARE PRETTY CONSERVATIVE AND SHOULD WORK
|
|
; IN MOST SCENARIOS.
|
|
; AT PRESENT, THE MACRO JUST INJECTS A DELAY BASED ON THE SPEED OF THE
|
|
; CPU.
|
|
; IF YOUR VDP IS NOT DETECTED OR YOU SEE SCREEN CORRUPTION, YOU MAY NEED
|
|
; TO INCREASE THE DELAY.
|
|
; DEPENDING ON YOUR SYSTEM AND YOUR VDP CHIP, YOU MAY BE ABLE TO
|
|
; DECREASE THE DELAY. THIS IS ESPECIALLY TRUE IF YOU ARE USING AN
|
|
; FPGA-BASED 99X8 EMULATOR -- THESE CAN NORMALLY RUN WITH NO DELAYS.
|
|
;
|
|
; TO MODIFY THE DELAY MACRO, IT IS RECOMMENDED THAT YOU JUST DEFINE
|
|
; YOUR OWN DEFINITION IN YOUR CONFIG FILE. THE FIRST INSTANCE OF A
|
|
; #DEFINE WILL "WIN", SO A DEFINE IN YOUR CONFIG FILE WILL TAKE
|
|
; PRECEDENCE.
|
|
;
|
|
#IF (CPUMHZ > 10)
|
|
#DEFINE TMS_IODELAY CALL DLY4 ; 100 T/S
|
|
#ELSE
|
|
#DEFINE TMS_IODELAY EX (SP),HL \ EX (SP),HL ; 38 T/S
|
|
#ENDIF
|
|
;
|
|
;;;#IF (CPUFAM == CPU_Z180)
|
|
;;; ; BELOW WAS TUNED FOR Z180 AT 18MHZ
|
|
;;; ;#DEFINE TMS_IODELAY EX (SP),HL \ EX (SP),HL ; 38 T/S
|
|
;;; ;#DEFINE TMS_IODELAY EX (SP),HL \ EX (SP),HL \ EX (SP),HL \ EX (SP),HL \ EX (SP),HL \ EX (SP),HL ; 76 T/S
|
|
;;; #DEFINE TMS_IODELAY CALL DLY4 ; 100 T/S
|
|
;;;
|
|
;;; ;#DEFINE TMS_IODELAY NOP \ NOP \ NOP \ NOP \ NOP ; 20 T/S ### JLC Mod for Clock/2 (9 MHz) ###
|
|
;;;#ELSE
|
|
;;; #IF (PLATFORM == PLT_MSX)
|
|
;;; #DEFINE TMS_IODELAY EX (SP),HL \ EX (SP),HL
|
|
;;; #ELSE
|
|
;;; ; BELOW WAS TUNED FOR Z80 AT 8MHZ
|
|
;;; #IF (TMS80COLS)
|
|
;;; #DEFINE TMS_IODELAY NOP \ NOP \ NOP \ NOP \ NOP \ NOP \ NOP ; V9958 NEEDS AT WORST CASE, APPROX 4us (28T) DELAY BETWEEN I/O (WHEN IN TEXT MODE)
|
|
;;; #ELSE
|
|
;;; #DEFINE TMS_IODELAY NOP \ NOP ; 8 T/S
|
|
;;; #ENDIF
|
|
;;; #ENDIF
|
|
;;;#ENDIF
|
|
;
|
|
;--------------------------------------------------------------------------------------------------
|
|
; HBIOS MODULE HEADER
|
|
;--------------------------------------------------------------------------------------------------
|
|
;
|
|
ORG_TMS .EQU $
|
|
;
|
|
.DW SIZ_TMS ; MODULE SIZE
|
|
.DW TMS_INITPHASE ; ADR OF INIT PHASE HANDLER
|
|
;
|
|
TMS_INITPHASE:
|
|
; INIT PHASE HANDLER, A=PHASE
|
|
CP HB_PHASE_PREINIT ; PREINIT PHASE?
|
|
JP Z,TMS_PREINIT ; DO PREINIT
|
|
CP HB_PHASE_INIT ; INIT PHASE?
|
|
JP Z,TMS_INIT ; DO INIT
|
|
RET ; DONE
|
|
;
|
|
;======================================================================
|
|
; TMS DRIVER - INITIALIZATION
|
|
;======================================================================
|
|
;
|
|
TMS_PREINIT:
|
|
#IF (TMSKBD == TMSKBD_KBD)
|
|
LD IY,TMS_IDAT ; POINTER TO INSTANCE DATA
|
|
CALL KBD_PREINIT
|
|
#ENDIF
|
|
; DISABLE INTERRUPT GENERATION UNTIL AFTER INTERRUPT HANDLER
|
|
; HAS BEEN INSTALLED.
|
|
LD A, (TMS_INITVDU_REG_1)
|
|
RES TMSINTEN, A ; RESET INTERRUPT ENABLE BIT
|
|
LD (TMS_INITVDU_REG_1),A
|
|
LD C, TMSCTRL1
|
|
JP TMS_SET_X ; SET REG W/O INT MGMT
|
|
;
|
|
TMS_INIT:
|
|
#IF (CPUFAM == CPU_Z180)
|
|
CALL TMS_Z180IO
|
|
#ENDIF
|
|
;
|
|
#IF ((TMSMODE == TMSMODE_SCG) | (TMSMODE == TMSMODE_MBC) | (TMSMODE == TMSMODE_DUO))
|
|
LD A,$FF
|
|
EZ80_IO
|
|
OUT (TMS_ACR),A ; INIT AUX CONTROL REG
|
|
#ENDIF
|
|
;
|
|
CALL NEWLINE ; FORMATTING
|
|
PRTS("TMS: MODE=$")
|
|
|
|
#IF ((TMSMODE == TMSMODE_MBC) | (TMSMODE == TMSMODE_DUO))
|
|
LD A,$FE
|
|
EZ80_IO
|
|
OUT (TMS_ACR),A ; CLEAR VDP RESET
|
|
#ENDIF
|
|
;
|
|
LD IY,TMS_IDAT ; POINTER TO INSTANCE DATA
|
|
;
|
|
#IF (TMSMODE == TMSMODE_SCG)
|
|
PRTS("SCG$")
|
|
#ENDIF
|
|
#IF (TMSMODE == TMSMODE_N8)
|
|
PRTS("N8$")
|
|
#ENDIF
|
|
#IF (TMSMODE == TMSMODE_N8PC)
|
|
PRTS("N8PC$")
|
|
#ENDIF
|
|
#IF (TMSMODE == TMSMODE_MSX)
|
|
PRTS("MSX$")
|
|
#ENDIF
|
|
#IF (TMSMODE == TMSMODE_MSXKBD)
|
|
PRTS("MSXKBD$")
|
|
#ENDIF
|
|
#IF (TMSMODE == TMSMODE_MSXMKY)
|
|
PRTS("MSXMKY$")
|
|
#ENDIF
|
|
#IF (TMSMODE == TMSMODE_MSXUKY)
|
|
PRTS("MSXUKY$")
|
|
#ENDIF
|
|
#IF (TMSMODE == TMSMODE_MBC)
|
|
PRTS("MBC$")
|
|
#ENDIF
|
|
#IF (TMSMODE == TMSMODE_COLECO)
|
|
PRTS("COLECO$")
|
|
#ENDIF
|
|
#IF (TMSMODE == TMSMODE_DUO)
|
|
PRTS("DUO$")
|
|
#ENDIF
|
|
#IF (TMSMODE == TMSMODE_NABU)
|
|
PRTS("NABU$")
|
|
#ENDIF
|
|
;
|
|
PRTS(" IO=0x$")
|
|
LD A,TMS_DATREG
|
|
CALL PRTHEXBYTE
|
|
CALL TMS_PROBE ; CHECK FOR HW EXISTENCE
|
|
JR Z,TMS_INIT1 ; CONTINUE IF PRESENT
|
|
;
|
|
; *** HARDWARE NOT PRESENT ***
|
|
PRTS(" NOT PRESENT$")
|
|
OR $FF ; SIGNAL FAILURE
|
|
RET
|
|
;
|
|
TMS_INIT1:
|
|
HB_DI ; NO INTERRUPTS DURING PROBES AND INITIALIZATION
|
|
;
|
|
; PROBE AND RECORD CHIP TYPE
|
|
CALL TMS_GETTYP ; A <- 0: TMS9918A, 1: V9938, 2: V9958, 3: SUPER V9958, 4:F18A
|
|
LD (TMS_VDPID),A ; SET VDP_ID IN LOW BYTE OF DEVICE ATTRIBUTES
|
|
;
|
|
; PRINT THE CHIP TYPE DETECTED
|
|
PRTS(" VDP=$") ; TAG
|
|
LD DE,TMS_CHIPSTR ; POINT TO CHIP ID STRINGS
|
|
CALL PRTIDXDEA ; PRINT
|
|
;
|
|
; PRIMARY CRT INITIALIZATION
|
|
CALL TMS_CRTINIT ; SETUP THE TMS/V99x8 CHIP REGISTERS
|
|
|
|
; PROBE AND RECORD CHIP VRAM SIZE
|
|
CALL TMS_VRMPRB ; PROBE FOR VRAM SIZE
|
|
LD (TMS_RAMID),A ; SET VDP_RAMID IN HIGH BYTE OF DEVICE ATTRIBUTES
|
|
;
|
|
; PRINT CHIP VRAM SIZE
|
|
OR A ; SET FLAGS
|
|
JR Z,TMS_INIT3 ; IF SIZE UNKNOWN, SKIP
|
|
PRTS(" VRAM=$") ; TAG
|
|
LD DE,TMS_VRAMSTR ; POINT TO VRAM SIZE STRINGS
|
|
CALL PRTIDXDEA ; PRINT
|
|
;
|
|
TMS_INIT3:
|
|
HB_EI ; RESTORE INTERRUPTS
|
|
;
|
|
#IF (TMSTIMENABLE)
|
|
CALL PRTSTRD
|
|
#IF (TICKFREQ == 50)
|
|
.TEXT " INTERRUPT=50HZ$"
|
|
#ELSE
|
|
.TEXT " INTERRUPT=60HZ$"
|
|
#ENDIF
|
|
|
|
#ENDIF
|
|
TMS_INIT4:
|
|
CALL PC_SPACE
|
|
LD A,TMS_COLS
|
|
CALL PRTDEC8
|
|
LD A,'X'
|
|
CALL COUT
|
|
LD A,TMS_ROWS
|
|
CALL PRTDEC8
|
|
;
|
|
CALL TMS_LOADFONT ; LOAD FONT DATA FROM ROM TO TMS STRORAGE
|
|
; *** DIAGNOSE FONT LOAD ERROR HERE!!! ***
|
|
CALL TMS_CLEAR ; CLEAR SCREEN, HOME CURSOR
|
|
#IF (TMSKBD == TMSKBD_PPK)
|
|
CALL PPK_INIT ; INITIALIZE PPI KEYBOARD DRIVER
|
|
#ENDIF
|
|
#IF (TMSKBD == TMSKBD_KBD)
|
|
CALL KBD_INIT ; INITIALIZE 8242 KEYBOARD DRIVER
|
|
#ENDIF
|
|
#IF (TMSKBD == TMSKBD_MKY)
|
|
CALL MKY_INIT ; INITIALIZE MKY KEYBOARD DRIVER
|
|
#ENDIF
|
|
#IF (TMSKBD == TMSKBD_NABU)
|
|
CALL NABUKB_INIT ; INITIALIZE NABU KEYBOARD DRIVER
|
|
#ENDIF
|
|
#IF (TMSKBD == TMSKBD_USB)
|
|
CALL CHUKB_INIT
|
|
#ENDIF
|
|
|
|
#IF (TMSTIMENABLE & (INTMODE > 0))
|
|
;
|
|
#IF (INTMODE == 1)
|
|
; ADD IM1 INT CALL LIST ENTRY
|
|
LD HL,TMS_TSTINT ; GET INT VECTOR
|
|
CALL HB_ADDIM1 ; ADD TO IM1 CALL LIST
|
|
#ELSE
|
|
; INSTALL VECTOR
|
|
LD HL,TMS_TSTINT
|
|
LD (IVT(INT_VDP)),HL ; IVT INDEX
|
|
#ENDIF
|
|
;
|
|
; ENABLE VDP INTERRUPTS NOW
|
|
LD A, (TMS_INITVDU_REG_1)
|
|
SET TMSINTEN,A ; SET INTERRUPT ENABLE BIT
|
|
LD (TMS_INITVDU_REG_1),A
|
|
LD C, TMSCTRL1
|
|
CALL TMS_SET
|
|
;
|
|
#IF (TMSMODE == TMSMODE_NABU)
|
|
; ENABLE VDP INTERRUPTS ON NABU INTERRUPT CONTROLLER
|
|
LD A,14 ; PSG R14 (PORT A DATA)
|
|
OUT (NABU_RSEL),A ; SELECT IT
|
|
LD A,(NABU_CTLVAL) ; GET NABU CTL PORT SHADOW REG
|
|
SET 4,A ; ENABLE VDP INTERRUPTS
|
|
LD (NABU_CTLVAL),A ; UPDATE SHADOW REG
|
|
OUT (NABU_RDAT),A ; WRITE TO HARDWARE
|
|
#ENDIF
|
|
;
|
|
#ENDIF
|
|
;
|
|
; ADD OURSELVES TO VDA DISPATCH TABLE
|
|
LD BC,TMS_FNTBL ; BC := FUNCTION TABLE ADDRESS
|
|
LD DE,TMS_IDAT ; DE := TMS INSTANCE DATA PTR
|
|
CALL VDA_ADDENT ; ADD ENTRY, A := UNIT ASSIGNED
|
|
;
|
|
; INITIALIZE EMULATION
|
|
LD C,A ; C := ASSIGNED VIDEO DEVICE NUM
|
|
LD DE,TMS_FNTBL ; DE := FUNCTION TABLE ADDRESS
|
|
LD HL,TMS_IDAT ; HL := TMS INSTANCE DATA PTR
|
|
CALL TERM_ATTACH ; DO IT
|
|
;
|
|
XOR A ; SIGNAL SUCCESS
|
|
RET
|
|
;
|
|
;======================================================================
|
|
; TMS DRIVER - VIDEO DISPLAY ADAPTER (VDA) FUNCTIONS
|
|
;======================================================================
|
|
;
|
|
TMS_FNTBL:
|
|
.DW TMS_VDAINI
|
|
.DW TMS_VDAQRY
|
|
.DW TMS_VDARES
|
|
.DW TMS_VDADEV
|
|
.DW TMS_VDASCS
|
|
.DW TMS_VDASCP
|
|
.DW TMS_VDASAT
|
|
.DW TMS_VDASCO
|
|
.DW TMS_VDAWRC
|
|
.DW TMS_VDAFIL
|
|
.DW TMS_VDACPY
|
|
.DW TMS_VDASCR
|
|
#IF (TMSKBD == TMSKBD_NONE)
|
|
.DW TMS_STAT
|
|
.DW TMS_FLUSH
|
|
.DW TMS_READ
|
|
#ENDIF
|
|
#IF (TMSKBD == TMSKBD_PPK)
|
|
.DW PPK_STAT
|
|
.DW PPK_FLUSH
|
|
.DW PPK_READ
|
|
#ENDIF
|
|
#IF (TMSKBD == TMSKBD_KBD)
|
|
.DW KBD_STAT
|
|
.DW KBD_FLUSH
|
|
.DW KBD_READ
|
|
#ENDIF
|
|
#IF (TMSKBD == TMSKBD_MKY)
|
|
.DW MKY_STAT
|
|
.DW MKY_FLUSH
|
|
.DW MKY_READ
|
|
#ENDIF
|
|
#IF (TMSKBD == TMSKBD_USB)
|
|
.DW UKY_STAT
|
|
.DW UKY_FLUSH
|
|
.DW UKY_READ
|
|
#ENDIF
|
|
#IF (TMSKBD == TMSKBD_NABU)
|
|
.DW NABUKB_STAT
|
|
.DW NABUKB_FLUSH
|
|
.DW NABUKB_READ
|
|
#ENDIF
|
|
.DW TMS_VDARDC
|
|
#IF (($ - TMS_FNTBL) != (VDA_FNCNT * 2))
|
|
.ECHO "*** INVALID TMS FUNCTION TABLE ***\n"
|
|
!!!!!
|
|
#ENDIF
|
|
;
|
|
TMS_VDAINI:
|
|
; RESET VDA
|
|
; CURRENTLY IGNORES VIDEO MODE AND BITMAP DATA
|
|
CALL TMS_VDARES ; RESET VDA
|
|
CALL TMS_CLEAR ; CLEAR SCREEN
|
|
XOR A ; SIGNAL SUCCESS
|
|
RET
|
|
;
|
|
TMS_VDAQRY:
|
|
LD C,$00 ; MODE ZERO IS ALL WE KNOW
|
|
LD D,TMS_ROWS ; ROWS
|
|
LD E,TMS_COLS ; COLS
|
|
LD HL,0 ; EXTRACTION OF CURRENT BITMAP DATA NOT SUPPORTED YET
|
|
XOR A ; SIGNAL SUCCESS
|
|
RET
|
|
;
|
|
TMS_VDARES:
|
|
#IF (CPUFAM == CPU_Z180)
|
|
CALL TMS_Z180IO
|
|
#ENDIF
|
|
CALL TMS_CRTINIT1A
|
|
CALL TMS_CLRCUR ; CLEAR CURSOR
|
|
CALL TMS_LOADFONT ; RELOAD FONT
|
|
LD A,$FF ; REMOVE
|
|
LD (TMS_CURSAV),A ; ... SAVED CURSOR CHAR
|
|
CALL TMS_SETCUR ; RESTORE CURSOR
|
|
XOR A
|
|
RET
|
|
|
|
TMS_VDADEV:
|
|
LD BC,(TMS_ATTRIB) ; C := DEVICE ATTRIBUTES (C=VDPID, B=VRAM SIZE ID)
|
|
LD D,VDADEV_TMS ; D := DEVICE TYPE
|
|
LD E,0 ; E := PHYSICAL UNIT IS ALWAYS ZERO
|
|
LD H,TMSMODE ; H := MODE
|
|
LD L,TMS_DATREG ; L := BASE I/O ADDRESS
|
|
XOR A ; SIGNAL SUCCESS
|
|
RET
|
|
|
|
TMS_VDASCS:
|
|
SYSCHKERR(ERR_NOTIMPL) ; NOT IMPLEMENTED (YET)
|
|
RET
|
|
|
|
TMS_VDASCP:
|
|
#IF (CPUFAM == CPU_Z180)
|
|
CALL TMS_Z180IO
|
|
#ENDIF
|
|
CALL TMS_CLRCUR
|
|
CALL TMS_XY ; SET CURSOR POSITION
|
|
CALL TMS_SETCUR
|
|
XOR A ; SIGNAL SUCCESS
|
|
RET
|
|
|
|
TMS_VDASAT:
|
|
XOR A ; NOT POSSIBLE, JUST SIGNAL SUCCESS
|
|
RET
|
|
|
|
TMS_VDASCO:
|
|
; ### JLC Mod - Implement Default Text Mode Colors via ANSI_VDASCO or direct HBIOS Call
|
|
;
|
|
; Color setting is in reg D in ANSI Format as described in RomWBW System Guide
|
|
; Convert Color Format from ANSI to TMS shuffling bits arround and using
|
|
; Color Conversion Table at TMS_COLOR_TBL (approximated equivalences)
|
|
; Save converted value to (TMS_TMSCOLOR)
|
|
;
|
|
; TMS hardware only allows setting a global (screen) foreground/background color. So, we
|
|
; only process this command if E is 1.
|
|
;
|
|
LD A,D ; GET CHAR/SCREEN SCOPE
|
|
CP 1 ; SCREEN?
|
|
JR NZ,TMS_VDASCO_Z ; IF NOT, JUST RETURN
|
|
;
|
|
LD A,E ; GET COLOR BYTE
|
|
AND $F0 ; ISOLATE BACKGROUND
|
|
RRCA \ RRCA \ RRCA \ RRCA ; MOVE TO LOWER NIBBLE
|
|
LD HL,TMS_COLOR_TBL ; POINT TO COLOR CONVERSION TABLE
|
|
CALL ADDHLA ; OFFSET TO DESIRED COLOR
|
|
LD B,(HL) ; PUT NEW BG IN B
|
|
;
|
|
LD A,E ; GET COLOR BYTE
|
|
AND $0F ; ISOLATE FOREGROUND
|
|
LD HL,TMS_COLOR_TBL ; POINT TO COLOR CONVERSION TABLE
|
|
CALL ADDHLA ; OFFSET TO DESIRED COLOR
|
|
LD A,(HL) ; PUT NEW FG IN A
|
|
RLCA \ RLCA \ RLCA \ RLCA ; MOVE TO UPPER NIBBLE
|
|
;
|
|
OR B ; COMBINE WITH FG
|
|
LD C, 7 ; C = Color Register, A = Desired new Color in TMS Format
|
|
CALL TMS_SET ; Write to specific TMS Register, Change Default Text Color
|
|
;
|
|
TMS_VDASCO_Z:
|
|
XOR A ; SIGNAL SUCCESS
|
|
RET
|
|
|
|
TMS_VDAWRC:
|
|
#IF (CPUFAM == CPU_Z180)
|
|
CALL TMS_Z180IO
|
|
#ENDIF
|
|
CALL TMS_CLRCUR ; CURSOR OFF
|
|
LD A,E ; CHARACTER TO WRITE GOES IN A
|
|
CALL TMS_PUTCHAR ; PUT IT ON THE SCREEN
|
|
CALL TMS_SETCUR
|
|
XOR A ; SIGNAL SUCCESS
|
|
RET
|
|
|
|
TMS_VDAFIL:
|
|
#IF (CPUFAM == CPU_Z180)
|
|
CALL TMS_Z180IO
|
|
#ENDIF
|
|
CALL TMS_CLRCUR
|
|
LD A,E ; FILL CHARACTER GOES IN A
|
|
EX DE,HL ; FILL LENGTH GOES IN DE
|
|
CALL TMS_FILL ; DO THE FILL
|
|
CALL TMS_SETCUR
|
|
XOR A ; SIGNAL SUCCESS
|
|
RET
|
|
|
|
TMS_VDACPY:
|
|
#IF (CPUFAM == CPU_Z180)
|
|
CALL TMS_Z180IO
|
|
#ENDIF
|
|
CALL TMS_CLRCUR
|
|
; LENGTH IN HL, SOURCE ROW/COL IN DE, DEST IS TMS_POS
|
|
; BLKCPY USES: HL=SOURCE, DE=DEST, BC=COUNT
|
|
PUSH HL ; SAVE LENGTH
|
|
CALL TMS_XY2IDX ; ROW/COL IN DE -> SOURCE ADR IN HL
|
|
POP BC ; RECOVER LENGTH IN BC
|
|
LD DE,(TMS_POS) ; PUT DEST IN DE
|
|
CALL TMS_BLKCPY ; DO A BLOCK COPY
|
|
CALL TMS_SETCUR
|
|
XOR A
|
|
RET
|
|
|
|
TMS_VDASCR:
|
|
#IF (CPUFAM == CPU_Z180)
|
|
CALL TMS_Z180IO
|
|
#ENDIF
|
|
CALL TMS_CLRCUR
|
|
TMS_VDASCR0:
|
|
LD A,E ; LOAD E INTO A
|
|
OR A ; SET FLAGS
|
|
JR Z,TMS_VDASCR2 ; IF ZERO, WE ARE DONE
|
|
PUSH DE ; SAVE E
|
|
JP M,TMS_VDASCR1 ; E IS NEGATIVE, REVERSE SCROLL
|
|
CALL TMS_SCROLL ; SCROLL FORWARD ONE LINE
|
|
POP DE ; RECOVER E
|
|
DEC E ; DECREMENT IT
|
|
JR TMS_VDASCR0 ; LOOP
|
|
TMS_VDASCR1:
|
|
CALL TMS_RSCROLL ; SCROLL REVERSE ONE LINE
|
|
POP DE ; RECOVER E
|
|
INC E ; INCREMENT IT
|
|
JR TMS_VDASCR0 ; LOOP
|
|
TMS_VDASCR2:
|
|
CALL TMS_SETCUR
|
|
XOR A
|
|
RET
|
|
|
|
;----------------------------------------------------------------------
|
|
; READ VALUE AT CURRENT VDU BUFFER POSITION
|
|
; RETURN E = CHARACTER, B = COLOUR, C = ATTRIBUTES
|
|
;----------------------------------------------------------------------
|
|
|
|
TMS_VDARDC:
|
|
OR $FF ; UNSUPPORTED FUNCTION
|
|
RET
|
|
|
|
; DUMMY FUNCTIONS BELOW BECAUSE SCG BOARD HAS NO
|
|
; KEYBOARD INTERFACE
|
|
|
|
TMS_STAT:
|
|
XOR A ; SIGNAL NOTHING READY
|
|
JP CIO_IDLE ; DO IDLE PROCESSING
|
|
|
|
TMS_FLUSH:
|
|
XOR A ; SIGNAL SUCCESS
|
|
RET
|
|
|
|
TMS_READ:
|
|
LD E,26 ; RETURN <SUB> (CTRL-Z)
|
|
XOR A ; SIGNAL SUCCESS
|
|
RET
|
|
;
|
|
;======================================================================
|
|
; TMS DRIVER - PRIVATE DRIVER FUNCTIONS
|
|
;======================================================================
|
|
;
|
|
;----------------------------------------------------------------------
|
|
; SET TMS9918 REGISTER VALUE
|
|
; TMS_SET WRITES VALUE IN A TO VDU REGISTER SPECIFIED IN C
|
|
; TMS_SET_X IS A VARIANT THAT DOES NOT DO INT MGMT (TMS_PREINIT)
|
|
;----------------------------------------------------------------------
|
|
;
|
|
TMS_SET:
|
|
#IF TMSTIMENABLE
|
|
; IF WE ARE USING THE VDP VB TIMER INTERRUPT, WE NEED TO
|
|
; DISABLE INTERRUPTS DURING THE PAIR OF OUTPUS FOR A REGISTER
|
|
; WRITE. IF A VDP INTERRUPT OCCURS BETWEEN THE 2 I/O FOR A
|
|
; REGISTER WRITE, THEN IT WILL FAIL.
|
|
HB_DI
|
|
CALL TMS_SET_X
|
|
HB_EI
|
|
RET
|
|
#ENDIF
|
|
;
|
|
TMS_SET_X:
|
|
; ENTRY POINT W/O INT MGMT NEEDED BY TMS_PREINIT
|
|
EZ80_IO
|
|
OUT (TMS_CMDREG),A ; WRITE IT
|
|
TMS_IODELAY
|
|
LD A,C ; GET THE DESIRED REGISTER
|
|
OR $80 ; SET BIT 7
|
|
EZ80_IO
|
|
OUT (TMS_CMDREG),A ; SELECT THE DESIRED REGISTER
|
|
TMS_IODELAY
|
|
RET
|
|
;
|
|
;----------------------------------------------------------------------
|
|
; SET TMS9918 READ/WRITE ADDRESS
|
|
; TMS_WR SETS TMS9918 TO BEGIN WRITING AT VDU ADDRESS SPECIFIED IN HL
|
|
; TMS_RD SETS TMS9918 TO BEGIN READING AT VDU ADDRESS SPECIFIED IN HL
|
|
;----------------------------------------------------------------------
|
|
;
|
|
TMS_WR:
|
|
PUSH HL
|
|
SET 6,H ; SET WRITE BIT
|
|
CALL TMS_RD
|
|
POP HL
|
|
RET
|
|
;
|
|
TMS_RD:
|
|
#IF TMSTIMENABLE
|
|
; SEE COMMENTS FROM TMS_SET ROUTINE
|
|
HB_DI
|
|
#ENDIF
|
|
LD A,L
|
|
EZ80_IO
|
|
OUT (TMS_CMDREG),A
|
|
TMS_IODELAY
|
|
LD A,H
|
|
EZ80_IO
|
|
OUT (TMS_CMDREG),A
|
|
TMS_IODELAY
|
|
#IF TMSTIMENABLE
|
|
HB_EI
|
|
#ENDIF
|
|
RET
|
|
;
|
|
;----------------------------------------------------------------------
|
|
; PROBE FOR TMS HARDWARE
|
|
;----------------------------------------------------------------------
|
|
;
|
|
; ON RETURN, ZF SET INDICATES HARDWARE FOUND
|
|
;
|
|
TMS_PROBE:
|
|
; SET WRITE ADDRESS TO $0000
|
|
LD HL,0
|
|
CALL TMS_WR
|
|
; WRITE TEST PATTERN TO FIRST TWO BYTES
|
|
LD A,$A5 ; FIRST BYTE
|
|
EZ80_IO
|
|
OUT (TMS_DATREG),A ; OUTPUT
|
|
TMS_IODELAY
|
|
CPL ; COMPLEMENT ACCUM
|
|
EZ80_IO
|
|
OUT (TMS_DATREG),A ; SECOND BYTE
|
|
TMS_IODELAY
|
|
;
|
|
; SET READ ADDRESS TO $0000
|
|
LD HL,0
|
|
CALL TMS_RD
|
|
; READ TEST PATTERN
|
|
LD C,$A5 ; VALUE TO EXPECT
|
|
EZ80_IO
|
|
IN A,(TMS_DATREG) ; READ FIRST BYTE
|
|
TMS_IODELAY
|
|
CP C ; COMPARE
|
|
RET NZ ; RETURN ON MISCOMPARE
|
|
EZ80_IO
|
|
IN A,(TMS_DATREG) ; READ SECOND BYTE
|
|
TMS_IODELAY
|
|
CPL ; COMPLEMENT IT
|
|
CP C ; COMPARE
|
|
RET ; RETURN WITH RESULT IN Z
|
|
;
|
|
; DETECT VDP VERSION
|
|
;
|
|
; ASSUMES INTERRUPTS ARE DISABLED (DI)
|
|
;
|
|
; A <- 0: TMS9918A, 1: V9938, 2: V9958, 3: Super V9958, 4: F18A
|
|
;
|
|
TMS_GETTYP:
|
|
; Code sourced from https://map.grauw.nl/sources/vdp_detection.php
|
|
CALL TMS_IS9918 ; USE A DIFFERENT WAY TO DETECT TMS9918A
|
|
JR Z,TMS_ISF18A ; IF TMS9918A CHECK FOR F18A VARIANT
|
|
;
|
|
; NOT A 9918 OR F18A, SO USE VDP ID
|
|
LD C,15 ; REGISTER #15
|
|
LD A,1 ; SELECT STATUS REGISTER #1
|
|
CALL TMS_SET_X ; DO IT
|
|
EZ80_IO
|
|
IN A,(TMS_CMDREG) ; READ STATUS BYTE (VDP ID)
|
|
TMS_IODELAY
|
|
|
|
AND 00111110B ; ISOLATE VDP ID BITS
|
|
RRCA ; 00000 - V9938 1
|
|
; 00010 - V9958 2
|
|
; 10010 - v9958 3
|
|
;
|
|
; RESTORE SELECT REGISTER TO S#0 FOR INT HANDLER
|
|
PUSH AF ; SAVE VDP ID
|
|
LD C,15 ; REG #15
|
|
XOR A ; SELECT STATUS REG #0
|
|
CALL TMS_SET_X ; DO IT
|
|
POP AF ; RESTORE VDP ID
|
|
;
|
|
; RETURN THE IDENTIFIED CHIP ID
|
|
LD E,TMSVDP_V9938 ; ASSUME 9938
|
|
OR A ; IS IT SO?
|
|
JR Z,TMS_GETTYP_Z ; IF YES, DONE
|
|
INC E ; ASSUME 9958
|
|
CP %00000010 ; IS IT SO?
|
|
JR Z,TMS_GETTYP_Z ; IF YES, DONE
|
|
INC E ; ASSUME SUPER 9958
|
|
CP %00010010 ; IS IT SO?
|
|
JR Z,TMS_GETTYP_Z ; IF YES, DONE
|
|
LD E,TMSVDP_UNK ; FAILSAFE OF UNKNOWN
|
|
;
|
|
TMS_GETTYP_Z:
|
|
LD A,E ; VDP ID TO A
|
|
RET ; AND DONE
|
|
|
|
TMS_ISF18A:
|
|
; CHECK FOR F18A FPGA/EMULATOR VARIANT
|
|
; THE VDP REGISTERS MUST BE (RE)INITIALIZED AFTER THE CHECK
|
|
; RETURN A <- 0:TMS9918A 4:F18A
|
|
;
|
|
; UNLOCK THE F18A: SEND VALUE $1C TO REGISTER 57 TWICE
|
|
LD C,57 ; REG #57
|
|
LD A,$1C ; UNLOCK VALUE
|
|
CALL TMS_SET_X ; DO IT
|
|
LD A,$1C ; UNLOCK VALUE
|
|
CALL TMS_SET_X ; DO IT AGAIN
|
|
;
|
|
; READ STATUS REGISTER #1
|
|
LD C,15 ; REG #15
|
|
LD A,1 ; SELECT STATUS REG #1
|
|
CALL TMS_SET_X ; DO IT
|
|
EZ80_IO
|
|
IN A,(TMS_CMDREG) ; READ STATUS REG #1
|
|
TMS_IODELAY
|
|
;
|
|
; CHECK FOR F18A
|
|
AND 11110000B ; MASK HIGH NIBBLE
|
|
CP $E0 ; IS IT A F18A?
|
|
JR Z,TMS_ISF18A1 ; HANDLE IT IF SO
|
|
;
|
|
; ON A TRUE 9918, THE F18A UNLOCK CODE ABOVE WILL ENABLE
|
|
; INTERRUPTS (REGISTER 57 ON A REAL 9918 WILL BE TREATED
|
|
; AS REGISTER 1!). HERE WE GET INTERRUPTS TURNED BACK OFF.
|
|
LD C,TMSCTRL1 ; REGISTER #1
|
|
LD A,(TMS_INITVDU_REG_1) ; VALUE TO SET
|
|
RES TMSINTEN,A ; CLEAR INTERRUPT ENABLE BIT
|
|
CALL TMS_SET_X ; DO IT
|
|
|
|
; WE DON'T BOTHER TO RESET THE STATUS REGISTER SELECTION OR
|
|
; RELOCK BECAUSE THIS IS NOT AN F18A!
|
|
LD A,TMSVDP_TMS9918 ; CHIP ID FOR 9918A
|
|
RET ; DONE
|
|
|
|
TMS_ISF18A1:
|
|
LD C,15 ; REG #15
|
|
XOR A ; VALUE
|
|
CALL TMS_SET_X ; DO IT
|
|
;
|
|
LD C,57 ; REG #57
|
|
XOR A ; VALUE
|
|
CALL TMS_SET_X ; DO IT
|
|
;
|
|
LD A,TMSVDP_F18A ; F18A
|
|
RET
|
|
|
|
;
|
|
; TEST IF THE VDP IS A TMS9918A.
|
|
;
|
|
; THE VDP ID NUMBER WAS ONLY INTRODUCED IN THE V9938, SO WE HAVE TO USE A
|
|
; DIFFERENT METHOD TO DETECT THE TMS9918A. WE WAIT FOR THE VERTICAL BLANKING
|
|
; INTERRUPT FLAG, AND THEN QUICKLY READ STATUS REGISTER 2 AND EXPECT BIT 6
|
|
; (VR, VERTICAL RETRACE FLAG) TO BE SET AS WELL. THE TMS9918A HAS ONLY ONE
|
|
; STATUS REGISTER, SO BIT 6 (5S, 5TH SPRITE FLAG) WILL RETURN 0 INSTEAD.
|
|
;
|
|
; ASSUMES INTERRUPTS ARE DISABLED (DI)
|
|
;
|
|
; F <- Z: TMS9918A, NZ: V99X8
|
|
;
|
|
TMS_IS9918:
|
|
LD C,TMS_CMDREG ; POINT TO CMD REG PORT
|
|
TMS_IODELAY
|
|
;
|
|
TMSIS9918_WAIT1:
|
|
EZ80_IO
|
|
IN A,(C) ; READ S#0
|
|
TMS_IODELAY
|
|
JP M,TMSIS9918_WAIT1 ; LOOP UNTIL INT FLAG (F) IS RESET
|
|
;
|
|
TMS_IS9918_WAIT2:
|
|
EZ80_IO
|
|
IN A,(C) ; READ S#0
|
|
TMS_IODELAY
|
|
JP P,TMS_IS9918_WAIT2 ; WAIT UNTIL INTERRUPT FLAG (F) IS SET
|
|
;
|
|
; READ VB STATUS
|
|
LD C,15 ; REG #15 (MIRRORS #7 ON 9918 VDP)
|
|
LD A,2 ; SELECT STATUS REG #2
|
|
CALL TMS_SET_X ; DO IT
|
|
EZ80_IO
|
|
IN A,(TMS_CMDREG) ; READ STATUS #2 (9938/58) / STATUS #0 (9918)
|
|
TMS_IODELAY
|
|
;
|
|
; RESTORE SELECT REGISTER TO S#0 FOR INT HANDLER
|
|
PUSH AF
|
|
LD C,15 ; REG #15
|
|
XOR A ; SELECT STATUS REG #0
|
|
CALL TMS_SET_X ; DO IT
|
|
POP AF
|
|
;
|
|
; SET ZF APPROPRIATELY AND RETURN
|
|
AND 01000000B ; CHECK IF BIT 6 WAS 0 (S#0 5S) OR 1 (S#2 VR)
|
|
RET
|
|
|
|
; PROBE VRAM SIZE OF V99x8 VDP
|
|
;
|
|
; ASSUMES INTERRUPTS ARE DISABLED (DI)
|
|
; ASSUMES CHIP VARIANT HAS ALREADY BEEN IDENTIFIED
|
|
;
|
|
; A <- 0: <UNKNOWN> 1: 4K 2: 16K 3: 32K 4: 64K 5: 128K 6: 192K 7: 1MB
|
|
;
|
|
TMS_VRMPRB:
|
|
;; HANDLE EXCEPTIONS
|
|
LD A,(TMS_VDPID) ; GET VDP ID
|
|
CP TMSVDP_TMS9918 ; IF BASIC TMS9918
|
|
JR Z,TMS_VRMPRB_UNK ; ... THEN VRAM SIZE IS UNKNOWN
|
|
CP TMSVDP_F18A ; IF FPGA
|
|
JR Z,TMS_VRMPRB_UNK ; ... THEN VRAM SIZE IS UNKNOWN
|
|
CP TMSVDP_SUPER ; IF SUPER V9958
|
|
JR Z,TMS_VRMPRB_1MB ; ... THEN VRAM SIZE IS ALWAYS 1MB
|
|
JR TMS_VRMPRB1 ; OTHERWISE, PROCEED TO DETECTION LOGIC
|
|
;
|
|
TMS_VRMPRB_UNK:
|
|
XOR A ; SET VALUE TO UNKNOWN
|
|
RET ; AND RETURN
|
|
;
|
|
TMS_VRMPRB_1MB:
|
|
LD A,7 ; SET VALUE TO 1MB
|
|
RET ; AND RETURN
|
|
;
|
|
TMS_VRMPRB1:
|
|
; START OF REAL VRAM PROBING
|
|
LD A,4 ; SET RETURN VALUE FOR 64K
|
|
EX AF,AF'
|
|
; R#14=4: A16-A14=100
|
|
LD A,4
|
|
LD C,14
|
|
CALL TMS_SET_X
|
|
; A13-A0=0, MODE=WRITE
|
|
LD HL,0
|
|
CALL TMS_WR
|
|
; WRITE $76 TO VRAM
|
|
LD A,$76
|
|
EZ80_IO
|
|
OUT (TMS_DATREG),A
|
|
TMS_IODELAY
|
|
; A13-A0=0, MODE=READ
|
|
LD HL,0
|
|
CALL TMS_RD
|
|
; READ VRAM
|
|
EZ80_IO
|
|
IN A,(TMS_DATREG)
|
|
TMS_IODELAY
|
|
; CHECK FOR VALUE WRITTEN
|
|
CP $76
|
|
JR Z,VRAMSIZE_128K ; IF ITS $76, WE HAVE AT LEAST 128K
|
|
; OTHERWISE ITS ONLY 64K
|
|
JR VRAMSIZE_DONE
|
|
|
|
VRAMSIZE_128K:
|
|
; WE HAVE AT LEAST 128K
|
|
EX AF, AF'
|
|
INC A ; SET RETURN VALUE TO 5 FOR 128K
|
|
EX AF, AF'
|
|
; R#45=$40: ENABLE EXTENDED MEMORY ACCESS
|
|
; MXC=1, MXD,MXS,DIY,DIX,EQ,MAJ=0
|
|
LD A,$40
|
|
LD C,45
|
|
CALL TMS_SET_X
|
|
; R#14=1: A16-A14=001
|
|
LD A,1
|
|
LD C,14
|
|
CALL TMS_SET_X
|
|
; A13-A0=0, MODE=WRITE
|
|
LD HL,0
|
|
CALL TMS_WR
|
|
; WRITE $5A TO VRAM
|
|
LD A,$5A
|
|
EZ80_IO
|
|
OUT (TMS_DATREG),A
|
|
TMS_IODELAY
|
|
; A13-A0=0, MODE=READ
|
|
LD HL,0
|
|
CALL TMS_RD
|
|
; READ VRAM
|
|
EZ80_IO
|
|
IN A,(TMS_DATREG)
|
|
TMS_IODELAY
|
|
; CHECK FOR VALUE WRITTEN
|
|
CP $5A
|
|
JR NZ,VRAMSIZE_DONE ; IF ITS $5A, WE HAVE EXAPANSION VRAM
|
|
;
|
|
VRAMSIZE_192K:
|
|
EX AF, AF'
|
|
INC A ; SET RETURN VALUE TO 6 FOR 192K
|
|
EX AF, AF'
|
|
;
|
|
VRAMSIZE_DONE:
|
|
; R#45=$00: RESET EXTENDED MEMORY ACCESS
|
|
XOR A
|
|
LD C,45
|
|
CALL TMS_SET_X
|
|
; R14=0: A16-A14=000
|
|
XOR A
|
|
LD C,14
|
|
CALL TMS_SET_X
|
|
;
|
|
EX AF, AF'
|
|
RET
|
|
;
|
|
;----------------------------------------------------------------------
|
|
; TMS9918 DISPLAY CONTROLLER CHIP INITIALIZATION
|
|
;----------------------------------------------------------------------
|
|
;
|
|
; THIS ASSUMES THAT THE CHIP DETECTION HAS BEEN DONE
|
|
;
|
|
TMS_CRTINIT:
|
|
; SET WRITE ADDRESS TO $0000 Beginning of VRAM
|
|
LD HL,0
|
|
CALL TMS_WR
|
|
;
|
|
; FILL ENTIRE 16KB VRAM CONTENTS with $00
|
|
LD DE,$4000 ; 16KB
|
|
TMS_CRTINIT1:
|
|
XOR A
|
|
EZ80_IO
|
|
OUT (TMS_DATREG),A
|
|
TMS_IODELAY ; DELAY
|
|
DEC DE
|
|
LD A,D
|
|
OR E
|
|
JR NZ,TMS_CRTINIT1
|
|
;
|
|
TMS_CRTINIT1A:
|
|
;
|
|
; INITIALIZE VDU REGISTERS
|
|
LD C,0 ; START WITH REGISTER 0
|
|
LD B,TMS_INITVDULEN ; NUMBER OF REGISTERS TO INIT
|
|
LD HL,TMS_INITVDU ; HL = POINTER TO THE DEFAULT VALUES
|
|
TMS_CRTINIT2:
|
|
LD A,(HL) ; GET VALUE
|
|
CALL TMS_SET ; WRITE IT
|
|
INC HL ; POINT TO NEXT VALUE
|
|
INC C ; POINT TO NEXT REGISTER
|
|
DJNZ TMS_CRTINIT2 ; LOOP
|
|
;
|
|
; ENABLE WAIT SIGNAL IF V9958
|
|
LD A,(TMS_VDPID) ; GET VDP ID
|
|
CP TMSVDP_V9958 ; V9958?
|
|
JR NZ,TMS_CRTINIT3 ; IF NOT, SKIP
|
|
LD C,25 ; REGISTER 25
|
|
LD A,%00000100 ; ONLY WTE BIT SET
|
|
CALL TMS_SET ; DO IT
|
|
;
|
|
TMS_CRTINIT3:
|
|
; RESET VRAM BASE ADDRESS FOR ALL CHIPS OTHER
|
|
; THAN BASIC TMS9918
|
|
LD A,(TMS_VDPID) ; GET VDP ID
|
|
CP TMSVDP_TMS9918 ; TMS9918?
|
|
JR Z,TMS_CRTINIT4 ; IF SO, SKIP
|
|
LD C,14 ; REGISTER 14
|
|
XOR A ; VALUE 0
|
|
CALL TMS_SET ; DO IT
|
|
;
|
|
TMS_CRTINIT4:
|
|
RET
|
|
;
|
|
;----------------------------------------------------------------------
|
|
; CLEAR SCREEN AND HOME CURSOR
|
|
;----------------------------------------------------------------------
|
|
;
|
|
TMS_CLEAR:
|
|
LD DE,0 ; ROW = 0, COL = 0
|
|
CALL TMS_XY ; SEND CURSOR TO TOP LEFT
|
|
LD A,' ' ; BLANK THE SCREEN
|
|
LD DE,TMS_ROWS * TMS_COLS ; FILL ENTIRE BUFFER
|
|
CALL TMS_FILL ; DO IT
|
|
LD DE,0 ; ROW = 0, COL = 0
|
|
CALL TMS_XY ; SEND CURSOR TO TOP LEFT
|
|
XOR A
|
|
DEC A
|
|
LD (TMS_CURSAV),A
|
|
CALL TMS_SETCUR ; SET CURSOR
|
|
;
|
|
XOR A ; SIGNAL SUCCESS
|
|
RET
|
|
;
|
|
;----------------------------------------------------------------------
|
|
; LOAD FONT DATA
|
|
;----------------------------------------------------------------------
|
|
;
|
|
TMS_LOADFONT:
|
|
; SET WRITE ADDRESS TO TMS_FNTVADDR
|
|
LD HL,TMS_FNTVADDR
|
|
CALL TMS_WR
|
|
;
|
|
; THE USE OF COMPRESSED FONT STORAGE FOR THE TMS DRIVER IS DISABLED
|
|
; SO THAT WE CAN RELOAD THE FONT DATA ON USER RESET. THE TMS CHIP
|
|
; IS FREQUENTLY REPROGRAMMED BY GAMES, ETC., SO IT IS NECESSARY TO
|
|
; REINIT AND RELOAD FONTS. RELOADING A COMPRESSED FONT AFTER
|
|
; SYSTEM INITIALIZATION REQUIRES A LARGE DECOMPRESSION BUFFER THAT WE
|
|
; HAVE NO WAY TO ACCOMMODATE WITHOUT TRASHING OS/APP MEMORY.
|
|
;
|
|
LD A,FONTID_6X8 ; WE WANT 6X8
|
|
CALL FNT_SELECT ; SELECT IT
|
|
RET NZ ; ERROR RETURN
|
|
;
|
|
; FILL TMS_FNTVADDR BYTES FROM FONTDATA
|
|
LD DE,TMS_FNTSIZE
|
|
TMS_LOADFONT1:
|
|
CALL FNT_NEXT ; NEXT FONT DATA BYTE
|
|
EZ80_IO
|
|
OUT (TMS_DATREG),A
|
|
TMS_IODELAY ; DELAY
|
|
DEC DE
|
|
LD A,D
|
|
OR E
|
|
JR NZ,TMS_LOADFONT1
|
|
XOR A ; SIGNAL SUCCESS
|
|
RET
|
|
;
|
|
;----------------------------------------------------------------------
|
|
; VIRTUAL CURSOR MANAGEMENT
|
|
; TMS_SETCUR CONFIGURES AND DISPLAYS CURSOR AT CURRENT CURSOR LOCATION
|
|
; TMS_CLRCUR REMOVES THE CURSOR
|
|
;
|
|
; VIRTUAL CURSOR IS GENERATED BY DYNAMICALLY CHANGING FONT GLYPH
|
|
; FOR CHAR 255 TO BE THE INVERSE OF THE GLYPH OF THE CHARACTER UNDER
|
|
; THE CURRENT CURSOR POSITION. THE CHARACTER CODE IS THEN SWITCHED TO
|
|
; THE VALUE 255 AND THE ORIGINAL VALUE IS SAVED. WHEN THE DISPLAY
|
|
; NEEDS TO BE CHANGED THE PROCESS IS UNDONE. IT IS ESSENTIAL THAT
|
|
; ALL DISPLAY CHANGES BE BRACKETED WITH CALLS TO TMS_CLRCUR PRIOR TO
|
|
; CHANGES AND TMS_SETCUR AFTER CHANGES.
|
|
;----------------------------------------------------------------------
|
|
;
|
|
TMS_SETCUR:
|
|
PUSH HL ; PRESERVE HL
|
|
PUSH DE ; PRESERVE DE
|
|
LD HL,(TMS_POS) ; GET CURSOR POSITION
|
|
CALL TMS_RD ; SETUP TO READ VDU BUF
|
|
EZ80_IO
|
|
IN A,(TMS_DATREG) ; GET REAL CHAR UNDER CURSOR
|
|
TMS_IODELAY ; DELAY
|
|
PUSH AF ; SAVE THE CHARACTER
|
|
CALL TMS_WR ; SETUP TO WRITE TO THE SAME PLACE
|
|
LD A,$FF ; REPLACE REAL CHAR WITH 255
|
|
EZ80_IO
|
|
OUT (TMS_DATREG),A ; DO IT
|
|
TMS_IODELAY ; DELAY
|
|
POP AF ; RECOVER THE REAL CHARACTER
|
|
LD B,A ; PUT IT IN B
|
|
LD A,(TMS_CURSAV) ; GET THE CURRENTLY SAVED CHAR
|
|
CP B ; COMPARE TO CURRENT
|
|
JR Z,TMS_SETCUR3 ; IF EQUAL, BYPASS EXTRA WORK
|
|
LD A,B ; GET REAL CHAR BACK TO A
|
|
LD (TMS_CURSAV),A ; SAVE IT
|
|
; GET THE GLYPH DATA FOR REAL CHARACTER
|
|
LD HL,0 ; ZERO HL
|
|
LD L,A ; HL IS NOW RAW CHAR INDEX
|
|
LD B,3 ; LEFT SHIFT BY 3 BITS
|
|
TMS_SETCUR0: ; MULT BY 8 FOR FONT INDEX
|
|
SLA L ; SHIFT LSB INTO CARRY
|
|
RL H ; SHFT MSB FROM CARRY
|
|
DJNZ TMS_SETCUR0 ; LOOP 3 TIMES
|
|
LD DE,TMS_FNTVADDR ; OFFSET TO START OF FONT TABLE
|
|
ADD HL,DE ; ADD TO FONT INDEX
|
|
CALL TMS_RD ; SETUP TO READ GLYPH
|
|
LD B,8 ; 8 BYTES
|
|
LD HL,TMS_BUF ; INTO BUFFER
|
|
TMS_SETCUR1: ; READ GLYPH LOOP
|
|
EZ80_IO
|
|
IN A,(TMS_DATREG) ; GET NEXT BYTE
|
|
TMS_IODELAY ; IO DELAY
|
|
LD (HL),A ; SAVE VALUE IN BUF
|
|
INC HL ; BUMP BUF POINTER
|
|
DJNZ TMS_SETCUR1 ; LOOP FOR 8 BYTES
|
|
;
|
|
; NOW WRITE INVERTED GLYPH INTO FONT INDEX 255
|
|
LD HL,TMS_FNTVADDR + (255 * 8) ; LOC OF GLPYPH DATA FOR CHAR 255
|
|
CALL TMS_WR ; SETUP TO WRITE THE INVERTED GLYPH
|
|
LD B,8 ; 8 BYTES PER GLYPH
|
|
LD HL,TMS_BUF ; POINT TO BUFFER
|
|
TMS_SETCUR2: ; WRITE INVERTED GLYPH LOOP
|
|
LD A,(HL) ; GET THE BYTE
|
|
INC HL ; BUMP THE BUF POINTER
|
|
XOR $FF ; INVERT THE VALUE
|
|
EZ80_IO
|
|
OUT (TMS_DATREG),A ; WRITE IT TO VDU
|
|
TMS_IODELAY ; IO DELAY
|
|
DJNZ TMS_SETCUR2 ; LOOP FOR ALL 8 BYTES OF GLYPH
|
|
;
|
|
TMS_SETCUR3: ; RESTORE REGISTERS AND RETURN
|
|
POP DE ; RECOVER DE
|
|
POP HL ; RECOVER HL
|
|
RET ; RETURN
|
|
;
|
|
;
|
|
;
|
|
TMS_CLRCUR: ; REMOVE VIRTUAL CURSOR FROM SCREEN
|
|
PUSH HL ; SAVE HL
|
|
LD HL,(TMS_POS) ; POINT TO CURRENT CURSOR POS
|
|
CALL TMS_WR ; SET UP TO WRITE TO VDU
|
|
LD A,(TMS_CURSAV) ; GET THE REAL CHARACTER
|
|
EZ80_IO
|
|
OUT (TMS_DATREG),A ; WRITE IT
|
|
TMS_IODELAY ; IO DELAY
|
|
POP HL ; RECOVER HL
|
|
RET ; RETURN
|
|
;
|
|
;----------------------------------------------------------------------
|
|
; SET CURSOR POSITION TO ROW IN D AND COLUMN IN E
|
|
;----------------------------------------------------------------------
|
|
;
|
|
TMS_XY:
|
|
CALL TMS_XY2IDX ; CONVERT ROW/COL TO BUF IDX
|
|
LD (TMS_POS),HL ; SAVE THE RESULT (DISPLAY POSITION)
|
|
RET
|
|
;
|
|
;----------------------------------------------------------------------
|
|
; CONVERT XY COORDINATES IN DE INTO LINEAR INDEX IN HL
|
|
; D=ROW, E=COL
|
|
;----------------------------------------------------------------------
|
|
;
|
|
TMS_XY2IDX:
|
|
LD A,E ; SAVE COLUMN NUMBER IN A
|
|
LD H,D ; SET H TO ROW NUMBER
|
|
LD E,TMS_COLS ; SET E TO ROW LENGTH
|
|
CALL MULT8 ; MULTIPLY TO GET ROW OFFSET
|
|
LD E,A ; GET COLUMN BACK
|
|
ADD HL,DE ; ADD IT IN
|
|
LD DE,TMS_CHRVADDR ; Add offset Address to start of Name Table (Char)
|
|
ADD HL,DE
|
|
RET ; RETURN
|
|
;
|
|
;----------------------------------------------------------------------
|
|
; WRITE VALUE IN A TO CURRENT VDU BUFFER POSITION, ADVANCE CURSOR
|
|
;----------------------------------------------------------------------
|
|
;
|
|
TMS_PUTCHAR:
|
|
PUSH AF ; SAVE CHARACTER
|
|
LD HL,(TMS_POS) ; LOAD CURRENT POSITION INTO HL
|
|
CALL TMS_WR ; SET THE WRITE ADDRESS
|
|
POP AF ; RECOVER CHARACTER TO WRITE
|
|
EZ80_IO
|
|
OUT (TMS_DATREG),A ; WRITE THE CHARACTER
|
|
TMS_IODELAY
|
|
LD HL,(TMS_POS) ; LOAD CURRENT POSITION INTO HL
|
|
INC HL
|
|
LD (TMS_POS),HL
|
|
RET
|
|
;
|
|
;----------------------------------------------------------------------
|
|
; FILL AREA IN BUFFER WITH SPECIFIED CHARACTER AND CURRENT COLOR/ATTRIBUTE
|
|
; STARTING AT THE CURRENT FRAME BUFFER POSITION
|
|
; A: FILL CHARACTER
|
|
; DE: NUMBER OF CHARACTERS TO FILL
|
|
;----------------------------------------------------------------------
|
|
;
|
|
TMS_FILL:
|
|
LD C,A ; SAVE THE CHARACTER TO WRITE
|
|
LD HL,(TMS_POS) ; SET STARTING POSITION
|
|
CALL TMS_WR ; SET UP FOR WRITE
|
|
;
|
|
TMS_FILL1:
|
|
LD A,C ; RECOVER CHARACTER TO WRITE
|
|
EZ80_IO
|
|
OUT (TMS_DATREG),A
|
|
TMS_IODELAY
|
|
DEC DE
|
|
LD A,D
|
|
OR E
|
|
JR NZ,TMS_FILL1
|
|
;
|
|
RET
|
|
;
|
|
;----------------------------------------------------------------------
|
|
; SCROLL ENTIRE SCREEN FORWARD BY ONE LINE (CURSOR POSITION UNCHANGED)
|
|
;----------------------------------------------------------------------
|
|
;
|
|
TMS_SCROLL:
|
|
LD HL,TMS_CHRVADDR ; SOURCE ADDRESS OF CHARACTER BUFFER
|
|
LD C,TMS_ROWS - 1 ; SET UP LOOP COUNTER FOR ROWS - 1
|
|
;
|
|
TMS_SCROLL0: ; READ LINE THAT IS ONE PAST CURRENT DESTINATION
|
|
PUSH HL ; SAVE CURRENT DESTINATION
|
|
LD DE,TMS_COLS
|
|
ADD HL,DE ; POINT TO NEXT ROW SOURCE
|
|
CALL TMS_RD ; SET UP TO READ
|
|
LD DE,TMS_BUF
|
|
LD B,TMS_COLS
|
|
TMS_SCROLL1:
|
|
EZ80_IO
|
|
IN A,(TMS_DATREG)
|
|
TMS_IODELAY
|
|
LD (DE),A
|
|
INC DE
|
|
DJNZ TMS_SCROLL1
|
|
POP HL ; RECOVER THE DESTINATION
|
|
;
|
|
; WRITE THE BUFFERED LINE TO CURRENT DESTINATION
|
|
CALL TMS_WR ; SET UP TO WRITE
|
|
LD DE,TMS_BUF
|
|
LD B,TMS_COLS
|
|
TMS_SCROLL2:
|
|
LD A,(DE)
|
|
EZ80_IO
|
|
OUT (TMS_DATREG),A
|
|
TMS_IODELAY
|
|
INC DE
|
|
DJNZ TMS_SCROLL2
|
|
;
|
|
; BUMP TO NEXT LINE
|
|
LD DE,TMS_COLS
|
|
ADD HL,DE
|
|
DEC C ; DECREMENT ROW COUNTER
|
|
JR NZ,TMS_SCROLL0 ; LOOP THRU ALL ROWS
|
|
;
|
|
; FILL THE NEWLY EXPOSED BOTTOM LINE
|
|
CALL TMS_WR
|
|
LD A,' '
|
|
LD B,TMS_COLS
|
|
TMS_SCROLL3:
|
|
EZ80_IO
|
|
OUT (TMS_DATREG),A
|
|
TMS_IODELAY
|
|
DJNZ TMS_SCROLL3
|
|
;
|
|
RET
|
|
;
|
|
;----------------------------------------------------------------------
|
|
; REVERSE SCROLL ENTIRE SCREEN BY ONE LINE (CURSOR POSITION UNCHANGED)
|
|
;----------------------------------------------------------------------
|
|
;
|
|
TMS_RSCROLL:
|
|
LD HL,TMS_COLS * (TMS_ROWS - 1)
|
|
LD DE,TMS_CHRVADDR ; Add offset Address to start of Name Table (Char)
|
|
ADD HL,DE
|
|
LD C,TMS_ROWS - 1
|
|
;
|
|
TMS_RSCROLL0: ; READ THE LINE THAT IS ONE PRIOR TO CURRENT DESTINATION
|
|
PUSH HL ; SAVE THE DESTINATION ADDRESS
|
|
LD DE,-TMS_COLS
|
|
ADD HL,DE ; SET SOURCE ADDRESS
|
|
CALL TMS_RD ; SET UP TO READ
|
|
LD DE,TMS_BUF ; POINT TO BUFFER
|
|
LD B,TMS_COLS ; LOOP FOR EACH COLUMN
|
|
TMS_RSCROLL1:
|
|
EZ80_IO
|
|
IN A,(TMS_DATREG) ; GET THE CHAR
|
|
TMS_IODELAY ; RECOVER
|
|
LD (DE),A ; SAVE IN BUFFER
|
|
INC DE ; BUMP BUFFER POINTER
|
|
DJNZ TMS_RSCROLL1 ; LOOP THRU ALL COLS
|
|
POP HL ; RECOVER THE DESTINATION ADDRESS
|
|
;
|
|
; WRITE THE BUFFERED LINE TO CURRENT DESTINATION
|
|
CALL TMS_WR ; SET THE WRITE ADDRESS
|
|
LD DE,TMS_BUF ; POINT TO BUFFER
|
|
LD B,TMS_COLS ; INIT LOOP COUNTER
|
|
TMS_RSCROLL2:
|
|
LD A,(DE) ; LOAD THE CHAR
|
|
EZ80_IO
|
|
OUT (TMS_DATREG),A ; WRITE TO SCREEN
|
|
TMS_IODELAY ; DELAY
|
|
INC DE ; BUMP BUF POINTER
|
|
DJNZ TMS_RSCROLL2 ; LOOP THRU ALL COLS
|
|
;
|
|
; BUMP TO THE PRIOR LINE
|
|
LD DE,-TMS_COLS ; LOAD COLS (NEGATIVE)
|
|
ADD HL,DE ; BACK UP THE ADDRESS
|
|
DEC C ; DECREMENT ROW COUNTER
|
|
JR NZ,TMS_RSCROLL0 ; LOOP THRU ALL ROWS
|
|
;
|
|
; FILL THE NEWLY EXPOSED BOTTOM LINE
|
|
CALL TMS_WR
|
|
LD A,' '
|
|
LD B,TMS_COLS
|
|
TMS_RSCROLL3:
|
|
EZ80_IO
|
|
OUT (TMS_DATREG),A
|
|
TMS_IODELAY
|
|
DJNZ TMS_RSCROLL3
|
|
;
|
|
RET
|
|
;
|
|
;----------------------------------------------------------------------
|
|
; BLOCK COPY BC BYTES FROM HL TO DE
|
|
;----------------------------------------------------------------------
|
|
;
|
|
TMS_BLKCPY:
|
|
; SAVE DESTINATION AND LENGTH
|
|
PUSH BC ; LENGTH
|
|
PUSH DE ; DEST
|
|
;
|
|
; READ FROM THE SOURCE LOCATION
|
|
TMS_BLKCPY1:
|
|
CALL TMS_RD ; SET UP TO READ FROM ADDRESS IN HL
|
|
LD DE,TMS_BUF ; POINT TO BUFFER
|
|
LD B,C
|
|
TMS_BLKCPY2:
|
|
EZ80_IO
|
|
IN A,(TMS_DATREG) ; GET THE NEXT BYTE
|
|
TMS_IODELAY ; DELAY
|
|
LD (DE),A ; SAVE IN BUFFER
|
|
INC DE ; BUMP BUF PTR
|
|
DJNZ TMS_BLKCPY2 ; LOOP AS NEEDED
|
|
;
|
|
; WRITE TO THE DESTINATION LOCATION
|
|
POP HL ; RECOVER DESTINATION INTO HL
|
|
CALL TMS_WR ; SET UP TO WRITE
|
|
LD DE,TMS_BUF ; POINT TO BUFFER
|
|
POP BC ; GET LOOP COUNTER BACK
|
|
LD B,C
|
|
TMS_BLKCPY3:
|
|
LD A,(DE) ; GET THE CHAR FROM BUFFER
|
|
EZ80_IO
|
|
OUT (TMS_DATREG),A ; WRITE TO VDU
|
|
TMS_IODELAY ; DELAY
|
|
INC DE ; BUMP BUF PTR
|
|
DJNZ TMS_BLKCPY3 ; LOOP AS NEEDED
|
|
;
|
|
RET
|
|
;
|
|
;----------------------------------------------------------------------
|
|
; Z180 LOW SPEED I/O CODE BRACKETING
|
|
;----------------------------------------------------------------------
|
|
;
|
|
#IF (CPUFAM == CPU_Z180)
|
|
;
|
|
TMS_Z180IO:
|
|
; HOOK CALLERS RETURN TO RESTORE DCNTL
|
|
EX (SP),HL ; SAVE HL & HL := RET ADR
|
|
LD (TMS_Z180IOR),HL ; SET RET ADR
|
|
LD HL,TMS_Z180IOX ; HL := SPECIAL RETURN ADR
|
|
EX (SP),HL ; RESTORE HL, INS NEW RET ADR
|
|
; SET Z180 MAX I/O WAIT STATES
|
|
PUSH AF ; SAVE AF
|
|
IN0 A,(Z180_DCNTL) ; GET CURRENT Z180 DCNTL
|
|
LD (TMS_DCNTL),A ; SAVE IT
|
|
OR %00110000 ; NEW DCNTL VALUE (MAX I/O W/S)
|
|
OUT0 (Z180_DCNTL),A ; IMPLEMENT IT
|
|
POP AF ; RESTORE AF
|
|
; BACK TO CALLER
|
|
TMS_Z180IOR .EQU $+1
|
|
JP $0000 ; BACK TO CALLER
|
|
;
|
|
TMS_Z180IOX:
|
|
; RESTORE ORIGINAL DCNTL
|
|
PUSH AF ; SAVE AF
|
|
LD A,(TMS_DCNTL) ; ORIG DCNTL
|
|
OUT0 (Z180_DCNTL),A ; IMPLEMENT IT
|
|
POP AF ; RESTORE AF
|
|
RET ; DONE
|
|
;
|
|
#ENDIF
|
|
|
|
#IF (TMSTIMENABLE & (INTMODE > 0))
|
|
TMS_TSTINT:
|
|
IN_A_NN(TMS_CMDREG)
|
|
AND $80
|
|
JR NZ,TMS_INTHNDL
|
|
AND $00 ; RETURN Z - NOT HANDLED
|
|
RET
|
|
|
|
TMS_INTHNDL:
|
|
CALL HB_TIMINT ; RETURN NZ - HANDLED
|
|
OR $FF
|
|
RET
|
|
#ENDIF
|
|
;
|
|
;==================================================================================================
|
|
; TMS DRIVER - DATA
|
|
;==================================================================================================
|
|
;
|
|
TMS_POS .DW 0 ; CURRENT DISPLAY POSITION
|
|
TMS_CURSAV .DB 0 ; SAVES ORIGINAL CHARACTER UNDER CURSOR
|
|
TMS_BUF .FILL 256,0 ; COPY BUFFER
|
|
;
|
|
TMS_CHIPSTR:
|
|
TMS_STRUNK .TEXT "UNKNOWN$" ; 0
|
|
TMS_STR9918 .TEXT "TMS9918A$" ; 1
|
|
TMS_STR9938 .TEXT "V9938$" ; 2
|
|
TMS_STR9958 .TEXT "V9958$" ; 3
|
|
TMS_STR9958X .TEXT "SUPER V9958$" ; 4
|
|
TMS_STRF18A .TEXT "F18A$" ; 5
|
|
;
|
|
TMS_VRAMSTR:
|
|
TMS_STRRAMUNK .TEXT "UNK$" ; 0
|
|
TMS_STRRAM4K .TEXT "4K$" ; 1
|
|
TMS_STRRAM16K .TEXT "16K$" ; 2
|
|
TMS_STRRAM32K .TEXT "32K$" ; 3
|
|
TMS_STRRAM64K .TEXT "64K$" ; 4
|
|
TMS_STRRAM128K .TEXT "128K$" ; 5
|
|
TMS_STRRAM192K .TEXT "192K$" ; 6
|
|
TMS_STRRAM1MB .TEXT "1MB$" ; 7
|
|
;
|
|
; ### JLC Mod
|
|
; ANSI-->TMS Color Conversion Table
|
|
TMS_COLOR_TBL .DB $01,$08,$02,$0A,$04,$06,$0C,$0F,$0E,$09,$03,$0B,$05,$0D,$07,$0F
|
|
;
|
|
TMS_ATTRIB:
|
|
TMS_VDPID .DB 0 ; VDP CHIP ID (TMSVDP_...)
|
|
TMS_RAMID .DB 0 ; VDP VRAM SIZE ID
|
|
;
|
|
;==================================================================================================
|
|
; TMS DRIVER - INSTANCE DATA
|
|
;==================================================================================================
|
|
;
|
|
TMS_IDAT:
|
|
#IF ((TMSKBD == TMSKBD_NONE) | (TMSKBD == TMSKBD_MKY) | (TMSKBD == TMSKBD_NABU))
|
|
.FILL 4,0 ; DUMMY KEYBOARD CONFIG DATA
|
|
#ENDIF
|
|
#IF (TMSKBD == TMSKBD_PPK)
|
|
.DB TMS_PPIA ; PPI PORT A
|
|
.DB TMS_PPIB ; PPI PORT B
|
|
.DB TMS_PPIC ; PPI PORT C
|
|
.DB TMS_PPIX ; PPI CONTROL PORT
|
|
#ENDIF
|
|
#IF (TMSKBD == TMSKBD_KBD)
|
|
.DB KBDMODE_PS2 ; PS/2 8242 KEYBOARD CONTROLLER
|
|
.DB TMS_KBDST ; 8242 CMD/STATUS PORT
|
|
.DB TMS_KBDDATA ; 8242 DATA PORT
|
|
.DB 0 ; FILLER
|
|
#ENDIF
|
|
;
|
|
.DB TMS_DATREG
|
|
.DB TMS_CMDREG
|
|
;
|
|
;==================================================================================================
|
|
; TMS DRIVER - TMS9918 REGISTER INITIALIZATION
|
|
;==================================================================================================
|
|
;
|
|
; Control Registers (write CMDREG):
|
|
;
|
|
; Reg Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0 Description
|
|
; 0 - - - - - - M3 EXTVID
|
|
; 1 4/16K BL GINT M1 M2 - SI MAG
|
|
; 2 - - - - PN13 PN12 PN11 PN10
|
|
; 3 CT13 CT12 CT11 CT10 CT9 CT8 CT7 CT6
|
|
; 4 - - - - - PG13 PG12 PG11
|
|
; 5 - SA13 SA12 SA11 SA10 SA9 SA8 SA7
|
|
; 6 - - - - - SG13 SG12 SG11
|
|
; 7 TC3 TC2 TC1 TC0 BD3 BD2 BD1 BD0
|
|
;
|
|
; Status (read CMDREG):
|
|
;
|
|
; Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0 Description
|
|
; INT 5S C FS4 FS3 FS2 FS1 FS0
|
|
;
|
|
; M1,M2,M3 Select screen mode
|
|
; EXTVID Enables external video input.
|
|
; 4/16K Selects 16kB RAM if set. No effect in MSX1 system.
|
|
; BL Blank screen if reset; just backdrop. Sprite system inactive
|
|
; SI 16x16 sprites if set; 8x8 if reset
|
|
; MAG Sprites enlarged if set (sprite pixels are 2x2)
|
|
; GINT Generate interrupts if set
|
|
; PN* Address for pattern name table
|
|
; CT* Address for colour table (special meaning in M2)
|
|
; PG* Address for pattern generator table (special meaning in M2)
|
|
; SA* Address for sprite attribute table
|
|
; SG* Address for sprite generator table
|
|
; TC* Text colour (foreground)
|
|
; BD* Back drop (background). Sets the colour of the border around
|
|
; the drawable area. If it is 0, it is black (like colour 1).
|
|
; FS* Fifth sprite (first sprite that's not displayed). Only valid
|
|
; if 5S is set.
|
|
; C Sprite collision detected
|
|
; 5S Fifth sprite (not displayed) detected. Value in FS* is valid.
|
|
; INT Set at each screen update, used for interrupts.
|
|
;
|
|
#IF (TMS80COLS)
|
|
;
|
|
; NOTE: YAMAHA 9938/58 DOCUMENTATION SAYS R3 IS SAME AS 9918 (ADR >> 10),
|
|
; BUT THIS SEEMS TO BE WRONG AND CORRECTLY DOCUMENTED AT
|
|
; https://www.msx.org/wiki/Screen_Modes_Description#SCREEN_0_in_80-column_.28Text_mode_2.29
|
|
; BITS 1-0 SHOULD BE 1. BITS 8-2 SHOULD BE (ADR >> 8).
|
|
;
|
|
; ### JLC Mod
|
|
; TEXT MODE DEFAULT COLOR (REG 7) CAN BE CHANGED INVOKING VDASCO
|
|
; OR VIA ANSI PRIVATE ESC SEQ. (SEE ANSI.ASM FOR DETAILS)
|
|
;
|
|
TMS_INITVDU: ; V9958 REGISTER SET
|
|
.DB $04 ; REG 0 - NO EXTERNAL VID, SET M4 = 1 FOR 80 COLS
|
|
TMS_INITVDU_REG_1:
|
|
.DB $50 ; REG 1 - ENABLE SCREEN, SET M1
|
|
.DB $03 ; REG 2 - SET PATTERN NAME TABLE TO (TMS_CHRVADDR >> 8) | $03
|
|
.DB $00 ; REG 3 - NO COLOR TABLE
|
|
.DB $02 ; REG 4 - SET PATTERN GENERATOR TABLE TO (TMS_FNTVADDR -> $1000)
|
|
.DB $00 ; REG 5 - SPRITE ATTRIBUTE IRRELEVANT
|
|
.DB $00 ; REG 6 - NO SPRITE GENERATOR TABLE
|
|
.DB $F0 ; REG 7 - WHITE ON BLACK
|
|
.DB $88 ; REG 8 - COLOUR BUS INPUT, DRAM 64K
|
|
#IF (TICKFREQ == 50)
|
|
.DB $02 ; REG 9
|
|
#ELSE
|
|
.DB $00 ; REG 9
|
|
#ENDIF
|
|
.DB $00 ; REG 10 - COLOUR TABLE A14-A16 (TMS_FNTVADDR - $1000)
|
|
;
|
|
#ELSE ; _______TMS9918 REGISTER SET_______
|
|
;
|
|
TMS_INITVDU: ; V9918 REGISTER SET
|
|
.DB $00 ; REG 0 - SET TEXT MODE, NO EXTERNAL VID
|
|
TMS_INITVDU_REG_1:
|
|
.DB $D0 ; REG 1 - SET 16K VRAM, ENABLE SCREEN, NO INTERRUPTS, TEXT MODE ($50 TO BLANK SCREEN)
|
|
.DB $0E ; REG 2 - SET PATTERN NAME TABLE TO (TMS_CHRVADDR >> 10)
|
|
.DB $FF ; REG 3 - NO COLOR TABLE, SET TO MODE II DEFAULT VALUE
|
|
.DB $00 ; REG 4 - SET PATTERN GENERATOR TABLE TO (TMS_FNTVADDR -> $0000)
|
|
.DB $76 ; REG 5 - SPRITE ATTRIBUTE IRRELEVANT, SET TO MODE II DEFAULT VALUE
|
|
.DB $03 ; REG 6 - NO SPRITE GENERATOR TABLE, SET TO MODE II DEFAULT VALUE
|
|
.DB $E1 ; REG 7 - TEXT COLOR
|
|
;
|
|
#ENDIF
|
|
;
|
|
TMS_INITVDULEN .EQU $ - TMS_INITVDU
|
|
;
|
|
;
|
|
#IF (CPUFAM == CPU_Z180)
|
|
TMS_DCNTL .DB $00 ; SAVE Z180 DCNTL AS NEEDED
|
|
#ENDIF
|
|
;
|
|
; ### JLC Mod
|
|
;===============================================================================
|
|
; BASIC ANSI to TMS COLOR CONVERSION TABLE (NIBBLES FOR FOREGROUND & BACKGROUND)
|
|
; Follows RomWBW System Guide Chapter 8, HBIOS Reference
|
|
;-------------------------------------------------------------------------------
|
|
; ANSI Color TMS Equivalent
|
|
;-------------------------------------------------------------------------------
|
|
; 0 Black 1
|
|
; 1 Red 8
|
|
; 2 Green 2
|
|
; 3 Brown A
|
|
; 4 Blue 4
|
|
; 5 Magenta 6
|
|
; 6 Cyan C
|
|
; 7 White F
|
|
; 8 Gray E
|
|
; 9 Light Red 9
|
|
; A Light Green 3
|
|
; B Yellow B
|
|
; C Light Blue 5
|
|
; D Light Magenta D
|
|
; E Light Cyan 7
|
|
; F Bright White F
|
|
;===============================================================================
|
|
;
|
|
;
|
|
;--------------------------------------------------------------------------------------------------
|
|
; HBIOS MODULE TRAILER
|
|
;--------------------------------------------------------------------------------------------------
|
|
;
|
|
END_TMS .EQU $
|
|
SIZ_TMS .EQU END_TMS - ORG_TMS
|
|
;
|
|
MEMECHO "TMS occupies "
|
|
MEMECHO SIZ_TMS
|
|
MEMECHO " bytes.\n"
|