several fixes

This commit is contained in:
2024-11-30 15:41:09 +01:00
parent 1ed6034d99
commit a5f5c6b9ef
227 changed files with 769511 additions and 94738 deletions

View File

@@ -0,0 +1 @@
../../../monitor_v2/zout/symbols.s

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,16 @@
INT_VEC_TABLE .equ [interrupt_vectors]
INT_PIO_ADDRD .equ CS_PIO_AD
INT_PIO_ADDRC .equ CS_PIO_AC
; jumps to isr. MUST be exited with RETI opcode!
_isr_pio_test:
di
ld hl, [_str_pio_interrupt]
call print_str
;get int from pio
in a,(INT_PIO_ADDRD)
call print_a_hex
reti

View File

@@ -0,0 +1,254 @@
;; VDP Terminal Driver
__VDPBUFFER_COUNTER equ var_idebuffer + 767
__VDPBUFFER_CURSORADDR equ var_idebuffer + 768
__VDPBUFFER_LINE equ var_idebuffer + 770
__VTERM_MAX_LINES equ 23
__VTERM_MAX_CPL equ 81
VTERM_INIT:
; init variables
xor a
ld (var_curserx),a
ld (var_cursery),a
ld (var_curseron),a
ld hl, 0x0A00
ld (__VDPBUFFER_CURSORADDR),hl
call _VTERM_SET_CURSORADDR
ret
; --- Console enable cursor ---
; destroy a
VTERM_CURSOR_ON:
push hl
push bc
push de
ld a,1
ld (var_curseron),a
call _VTERM_MOVE_CURSOR
pop de
pop bc
pop hl
ret
; --- Console disable cursor ---
; destroy a
VTERM_CURSOR_OFF:
push hl
push bc
xor a
ld (var_curseron),a
ld hl,(__VDPBUFFER_CURSORADDR)
call VDP_RAMADDR_WR
xor a
out (VDP_RAM),a ;clear old cursor
call _VTERM_SET_CURSORADDR
pop bc
pop hl
ret
; --- Console print string (null terminated) ---
; inputs: hl (pointer to string)
; modify hl
; destroy a
VTERM_PRINT_STR:
ld a,(hl)
or a
ret z
call VTERM_PRINT
inc hl
jr VTERM_PRINT_STR
; --- Console print char ---
; inputs: a (ascii char)
VTERM_PRINT:
push af
push bc
push de
push hl
push af
call print_a_hex
pop af
cp 0x08
jp z,_VTERM_PRINT_BACKSPC
cp 13
jp z, _VTERM_PRINT_CR
cp 10
jp z, _VTERM_PRINT_LF
; else print a
call _VTERM_CHAROUT
_VTERM_PRINT_END:
call _VTERM_MOVE_CURSOR
pop hl
pop de
pop bc
pop af
ret
_VTERM_PRINT_BACKSPC:
call _VTERM_CURSOR_BACK
ld a,' '
out (VDP_RAM),a
jp _VTERM_PRINT_END
_VTERM_PRINT_CR:
call _VTERM_CURSOR_START
jp _VTERM_PRINT_END
_VTERM_PRINT_LF:
call _VTERM_CURSOR_NEWLINE
jp _VTERM_PRINT_END
; only called by VTERM_PRINT
; destroys af,bc,de,hl
_VTERM_CHAROUT:
push af ;store char
ld a,(var_curserx) ;test for line wrap
inc a
cp __VTERM_MAX_CPL +1
jr nz, __VTERM_CHAROUT_NOBREAK ; if linewrap:
call _VTERM_CURSOR_START ; do new line
call _VTERM_CURSOR_NEWLINE
__VTERM_CHAROUT_NOBREAK: ; if not linewrap
ld a,(var_curserx) ; move curser by one
inc a
ld (var_curserx),a
pop af
out (VDP_RAM),a
ret
; destroys af,bc,de,hl
_VTERM_CURSOR_BACK:
ld a,(var_curserx)
or a
ret z;if line wrap, ignore
dec a
ld (var_curserx),a
jp _VTERM_MOVE_CURSOR
; --- Move cursor to start of line ---
; destroys af,bc,de,hl
_VTERM_CURSOR_START:
xor a
ld (var_curserx),a
jp _VTERM_MOVE_CURSOR
; --- Move cursor to next line ---
; destroys af,bc,de,hl
_VTERM_CURSOR_NEWLINE:
ld a,(var_cursery)
cp __VTERM_MAX_LINES
jp z, _VTERM_SCROLL
inc a
ld (var_cursery),a
jp _VTERM_MOVE_CURSOR
; --- Calculate 16bit VRAM adress of current char ---
; destroy AF,DE
; outputs HL
_VTERM_CALC_CURSORADDR:
ld d,0
ld a,(var_cursery)
ld e,a
ld hl,0
add hl, de ; Y x 1
add hl, hl ; Y x 2
add hl, hl ; Y x 4
add hl, de ; Y x 5
add hl, hl ; Y x 10
add hl, hl ; Y x 20
add hl, hl ; Y x 40
add hl, hl ; Y x 80
ld a,(var_curserx)
ld e,a
add hl, de ; add X for final address
ret
; destroy AF,DE,HL
_VTERM_SET_CURSORADDR:
call _VTERM_CALC_CURSORADDR
jp VDP_RAMADDR_WR
; destroy AF,DE,HL
_VTERM_SET_CURSORADDR_RD:
call _VTERM_CALC_CURSORADDR
jp VDP_RAMADDR_RD
; destroys af,bc,de,hl
_VTERM_MOVE_CURSOR:
ld a,(var_curseron)
or a
jp z, _VTERM_SET_CURSORADDR ;if cursor disable, only set new memory location
;if cursor is enabled
ld hl,(__VDPBUFFER_CURSORADDR)
call VDP_RAMADDR_WR
xor a
out (VDP_RAM),a ;clear old cursor
; calulate new position
call _VTERM_CALC_CURSORADDR
ld a,l ;load lower byte
and 0x07 ;mask lower 3 bits
ld b,a ;save lower 3 bits
srl h
rr l
srl h
rr l
srl h
rr l
ld de,0x0A00
add hl,de
ld (__VDPBUFFER_CURSORADDR), hl
call VDP_RAMADDR_WR
ld a,128
_VTERM_MOVE_CURSOR_LOOP:
rrca
djnz _VTERM_MOVE_CURSOR_LOOP
out (VDP_RAM),a
jp _VTERM_SET_CURSORADDR
; --- Memory Scroll ---
_VTERM_SCROLL:
;COPY / Scroll up using VDP commands
ld e,15 ;select status register
ld a,2
call VDP_SETREG
in a,(VDP_REGISTER)
and 0x40 ;Vertical retrace flag
jr z, _VTERM_SCROLL; if not loop
; else setup address
xor a
ld (var_curserx),a
ld (__VDPBUFFER_COUNTER),a
_VTERM_SCROLL_LINE:
ld a,(__VDPBUFFER_COUNTER) ;set next line
inc a
ld (var_cursery),a
call _VTERM_SET_CURSORADDR_RD
ld b,__VTERM_MAX_CPL
ld hl,__VDPBUFFER_LINE ;buffer location
ld c, VDP_RAM
_VTERM_SCROLL_LINE_L1:
ini ;load 80 bytes to ram
jr nz, _VTERM_SCROLL_LINE_L1
;setup target row
ld a,(__VDPBUFFER_COUNTER) ;set next line
ld (var_cursery),a
call _VTERM_SET_CURSORADDR
ld b,__VTERM_MAX_CPL
ld hl,__VDPBUFFER_LINE ;buffer location
_VTERM_SCROLL_LINE_L2:
outi ;store to vdp ram
jr nz, _VTERM_SCROLL_LINE_L2
;done with one line
ld a,(__VDPBUFFER_COUNTER)
inc a
ld (__VDPBUFFER_COUNTER),a
cp __VTERM_MAX_LINES
jp nz, _VTERM_SCROLL_LINE
ld (var_cursery),a
call _VTERM_SET_CURSORADDR
;fill
ld b,__VTERM_MAX_CPL
_VTERM_SCROLL_LINE_FILL:
xor a
out (VDP_RAM),a
djnz _VTERM_SCROLL_LINE_FILL
jp _VTERM_SET_CURSORADDR

View File

@@ -0,0 +1,151 @@
;----------------------------------------------------------------
;Keyboard interface driver for Z8C
;Controller used: vt82c42
;Datasheet: http://www.s100computers.com/My%20System%20Pages/MSDOS%20Board/vt82c42%20PC%20Keyboard%20conrtroller.pdf
;by Dennis Gunia (04/2022)
;----------------------------------------------------------------
;================================================================
; I/O registers
;================================================================
CS_VT82C42_DATA .EQU 0xF0
CS_VT82C42_CTRL .EQU 0xF1
;================================================================
; I/O access functions
;================================================================
keyboard_init:
ld a, 0xA7 ;Disable Mouse
out (CS_VT82C42_CTRL), A
ld a, 0xAD ;Disable Keyboard
out (CS_VT82C42_CTRL), A
_keyboard_init_flush_buffer:
in a,(CS_VT82C42_DATA) ;Read buffer
in a,(CS_VT82C42_CTRL) ;Read status byte
bit 0,a ;Test if buffer is empty
jr nz, _keyboard_init_flush_buffer
;buffer is now flushed. Now set the Controller Configuration Byte
ld a, 0x60 ;next byte is command byte register write
ld b, 11111100b ;Disable bits 0,1,6 (disable IRQ and Translation)
call keyb_cmd_wr
;Perform Controller Self Test
ld a, 0xAA
call keyb_cmd_rd
cp 0x55
jr nz, _keyboard_init_failed
;Perform Interface Tests
ld a, 0xAB
call keyb_cmd_rd
or a
jr nz, _keyboard_init_failed
;Enable Devices
ld a,0xAE
out (CS_VT82C42_CTRL), A
call keyb_wait_ibf_empty
;Test if device is present Devices
ld a,0xEE
out (CS_VT82C42_DATA), A ;Send echo to keboard (0xEE command)
call keyb_wait_ibf_empty
call keyb_wait_obf
in a,(CS_VT82C42_DATA)
cp a, 0xEE
jr z, _keyboard_init_okay ; 0xFC -> Success. Init done!
;Else device error
ld hl, [STR_keyboard_init_failed]
call print_str
ret
_keyboard_init_failed:
LD HL, [STR_keyboard_init_err]
CALL print_str
RET
_keyboard_init_dev_missing:
LD HL, [STR_keyboard_init_missing]
CALL print_str
RET
_keyboard_init_okay:
LD HL, [STR_keyboard_init_okay]
CALL print_str
RET
keyb_cmd_enable:
ld a, 0xF4
call keyb_wr_wait_ack
ld a, 0xED
call keyb_wr_wait_ack
ld a, 0x02
call keyb_wr_wait_ack
ret
keyb_enable_int:
ld a, 0x60 ;next byte is command byte register write
ld b, 00000001b ;Disable bits 0,1,6 (disable IRQ and Translation)
call keyb_cmd_wr
_keyb_enable_int_flush_buffer:
in a,(CS_VT82C42_DATA) ;Read buffer
in a,(CS_VT82C42_CTRL) ;Read status byte
bit 0,a ;Test if buffer is empty
jr nz, _keyb_enable_int_flush_buffer
ret
; a contains command
; b conatins data
keyb_cmd_wr:
out (CS_VT82C42_CTRL),a ;write command byte
ld a, b
out (CS_VT82C42_DATA),a
ret
; a contains command
; a returns data
keyb_cmd_rd:
out (CS_VT82C42_CTRL),a ;write command byte
_keyb_cmd_rd_l1:
in a, (CS_VT82C42_CTRL) ;read status
call print_a_hex
rra
jr nc, _keyb_cmd_rd_l1 ;wait until OBF is set (data avail)
in a, (CS_VT82C42_DATA)
ret
keyb_wait_ibf_empty:
in a, (CS_VT82C42_CTRL) ;read status
rra
rra
jr c, keyb_wait_ibf_empty ;if IBF, wait
ret
keyb_wait_obf:
in a, (CS_VT82C42_CTRL) ;read status
rra
jr nc, keyb_wait_obf ;if IBF, wait
ret
; a data
; z is 0 if success
keyb_wr_wait_ack:
out (CS_VT82C42_DATA),a ;write command byte
call keyb_wait_obf ;wait until sent
_keyb_wr_wait_ack_l1: ;wait for reponse
in a, (CS_VT82C42_CTRL) ;read status
bit 1,a ;check input buffer full
jr nz, _keyb_wr_wait_ack_l1
in a, (CS_VT82C42_DATA)
cp 0xFA
ret
;Status message strings
STR_keyboard_init_okay:
.BYTE "PS/2 Keyboard initialized.",0
STR_keyboard_init_err:
.BYTE "PS/2 Controller error! System HALT!",0
STR_keyboard_init_failed:
.BYTE "PS/2 Keyboard error! System HALT!",0
STR_keyboard_init_missing:
.BYTE "PS/2 no keyboard found!",0

View File

@@ -0,0 +1,256 @@
;----------------------------------------------------------------
;BIOS Driver for VDP V9958
;by Dennis Gunia (07/2024)
;----------------------------------------------------------------
;================================================================
; I/O registers
;================================================================
VDP_REGISTER .EQU 0xE1
VDP_RAM .EQU 0xE0
;================================================================
; VDP Registers
;================================================================
; registers
VDPR_MODE0 .EQU 0
VDPR_MODE1 .EQU 1
VDPR_MODE2 .EQU 8
VDPR_MODE3 .EQU 9
VDPR_COLOR .EQU 7
VDPR_PATNMEBASE .EQU 2
VDPR_PATGENBASE .EQU 4
VDPR_COLTBBASE0 .EQU 3
VDPR_COLTBBASE1 .EQU 10
; register bits
TMS_R8_MS .EQU 128 ;Mouse: when set to 1, sets the color bus into input mode and enables mouse. If set to 0, sets color bus into output mode and disables mouse
TMS_R8_LP .EQU 64 ;Light pen: when set to 1, enables light pen
TMS_R8_TP .EQU 32 ;Sets the color of code 0 to the color of the palette
TMS_R8_CB .EQU 16 ;Color bus: when set to 1, sets color bus into input mode. If set to 0, sets color bus into output mode
TMS_R8_VR .EQU 8 ;If set to 1, VRAM is 64Kx1Bit or 64Kx4bits. If set to 0, VRAM is 16Kx1Bit or 16Kx4Bits
TMS_R8_SPD .EQU 2 ;if set to 1, sprites are not displayed and related VRAM reads are not performed
TMS_R8_BW .EQU 1 ;if set to 1, output is grayscale in 32 tones
; colors
TmsTransparent .EQU 0
TmsBlack .EQU 1
TmsMediumGreen .EQU 2
TmsLightGreen .EQU 3
TmsDarkBlue .EQU 4
TmsLightBlue .EQU 5
TmsDarkRed .EQU 6
TmsCyan .EQU 7
TmsMediumRed .EQU 8
TmsLightRed .EQU 9
TmsDarkYellow .EQU 0ah
TmsLightYellow .EQU 0bh
TmsDarkGreen .EQU 0ch
TmsMagenta .EQU 0dh
TmsGray .EQU 0eh
TmsWhite .EQU 0fh
;================================================================
; I/O access functions
;================================================================
;------------------------------------------------------------------------------
; set vdp register
;
; inputs: a (value), e (register)
;------------------------------------------------------------------------------
VDP_SETREG:
out (VDP_REGISTER), a
ld a,e
or 80h
out (VDP_REGISTER), a
ret
;------------------------------------------------------------------------------
; read vdp status register
;
; inputs: a (register)
;------------------------------------------------------------------------------
VDP_STS:
out (VDP_RAM),a ;write addr
ld a,15 + 128
out (VDP_RAM),a ;selct reg for read
in a,(VDP_RAM)
ret
;------------------------------------------------------------------------------
; set vdp ram pointer for read
;
; inputs: ahl (address)
;------------------------------------------------------------------------------
VDP_RAMADDR_RD:
rlc h
rla
rlc h
rla
srl h
srl h
out (VDP_REGISTER),a
ld a,14 + 128
out (VDP_REGISTER),a
ld a,l
out (VDP_REGISTER),a
ld a,h
out (VDP_REGISTER),a
ret
;------------------------------------------------------------------------------
; set vdp ram pointer for write
;
; inputs: ahl (address)
;------------------------------------------------------------------------------
VDP_RAMADDR_WR:
rlc h
rla
rlc h
rla
srl h
srl h
out (VDP_REGISTER),a
ld a,14 + 128
out (VDP_REGISTER),a
ld a,l
out (VDP_REGISTER),a
ld a,h
or 64
out (VDP_REGISTER),a
ret
;------------------------------------------------------------------------------
; set vdp console color
;
; inputs: b (back color), c (front color)
; destroys: e, af
;------------------------------------------------------------------------------
VDP_COLOR:
ld a,c ;load front color to a
rlca
rlca
rlca
rlca
or b ;combine back color
ld e, VDPR_COLOR
call VDP_SETREG
; set blink color
ld e, 12 ; set blink color
ld a,b ;load front color to a
rlca
rlca
rlca
rlca
or c ;combine back color
call VDP_SETREG
ret
;------------------------------------------------------------------------------
; copy block of memory to vdp
;
; inputs: hl (source in local ram)
; de (destination in vram)
; bc (byte counter)
; destroys: af
;------------------------------------------------------------------------------
VDP_LOADRAM:
;setup address
push hl
ex de,hl
ld a,0
call VDP_RAMADDR_WR
pop hl
_VDP_LOADRAM_LOOP:
ld a,(hl) ;load byte from system
inc hl
out (VDP_RAM),a
dec bc ;decrement counter
ld a,b ;check if zero
or c
jr nz, _VDP_LOADRAM_LOOP ;if not loop
ret ;else exit
;------------------------------------------------------------------------------
; fill block of memory in vdp
;
; inputs: a (value to write)
; de (destination in vram)
; bc (byte counter)
; destroys: hl
;------------------------------------------------------------------------------
VDP_FILL:
push af
ex de,hl
call VDP_RAMADDR_WR
_VDP_FILL_LOOP:
pop af
out (VDP_RAM),a
push af
dec bc ;decrement counter
ld a,b ;check if zero
or c
jr nz, _VDP_FILL_LOOP ;if not loop
pop af
ret
;================================================================
; Init screen modes
;================================================================
VDP_INIT_TEXT2:
; init vdp (80col text)
ld e, VDPR_MODE0
ld a, 00000100b ;TEXT2
call VDP_SETREG
ld e, VDPR_MODE1 ;blank screen wit 64K enabled
ld a, 00001000b
call VDP_SETREG
ld e, VDPR_MODE2
ld a, TMS_R8_SPD
call VDP_SETREG
ld e, VDPR_MODE3
ld a, 00000010b
call VDP_SETREG
; set memory layout
; set pattern name table
ld e, VDPR_PATNMEBASE
ld a, 00000011b
call VDP_SETREG
ld e, VDPR_PATGENBASE
ld a, 00000010b
call VDP_SETREG
ld e, VDPR_COLTBBASE0
ld a, 00101111b
call VDP_SETREG
ld e, VDPR_COLTBBASE1
ld a, 00000000b
call VDP_SETREG
;enable cpu wait (for fast writes. Required!!!!)
ld e,25
ld a,4
call VDP_SETREG
;setup cursor:
ld e, 13 ; set blink rate
ld a, 0x22
call VDP_SETREG
;fill nametable to 0
ld de, 0x0000
ld bc, 0x2000
ld a, 0
call VDP_FILL
;load font
ld hl, [VDP_FONT_6x8_80COL]
ld bc, 256*8
ld de, 0x1000
call VDP_LOADRAM
;enable screen wit 64K enabled
ld e, VDPR_MODE1
ld a, 01010000b
call VDP_SETREG
ret
;================================================================
; Fonts
;================================================================
VDP_FONT_6x8_80COL:
.include "font80.s"

View File

@@ -0,0 +1,5 @@
;----------------------------------------------------------------
;Ringbuffer data structure
;by Dennis Gunia (07/2024)
;----------------------------------------------------------------

View File

@@ -0,0 +1,706 @@
; TMS9918A graphics subroutines
; Copyright 2018-2020 J.B. Langston
;
; Permission is hereby granted, free of charge, to any person obtaining a
; copy of this software and associated documentation files (the "Software"),
; to deal in the Software without restriction, including without limitation
; the rights to use, copy, modify, merge, publish, distribute, sublicense,
; and/or sell copies of the Software, and to permit persons to whom the
; Software is furnished to do so, subject to the following conditions:
;
; The above copyright notice and this permission notice shall be included in
; all copies or substantial portions of the Software.
;
; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
; DEALINGS IN THE SOFTWARE.
; VDP Programmer's Guide: http://map.grauw.nl/resources/video/ti-vdp-programmers-guide.pdf
phase 0xE400
; ---------------------------------------------------------------------------
; configuration parameters; can be changed at runtime
TmsPort:
defb 0xE0 ; port for TMS vram (reg is 1 higher)
TmsWait:
defb 64 ; iterations to wait after ram access
TmsMode:
defw 0 ; mode registers
TmsNameAddr:
defw 3800h ; name table address (multiples of 400H)
TmsColorAddr:
defw 2000h ; color table address (multiples of 40H)
TmsPatternAddr:
defw 0 ; pattern table (multiples of 800H)
TmsSpritePatternAddr:
defw 1800h ; sprite attribute table (multiples of 80H)
TmsSpriteAttrAddr:
defw 3bc0h ; sprite pattern table (multiples of 800H)
TmsScreenColors:
defb 0 ; background (low nybble), text color (high nybble)
; ---------------------------------------------------------------------------
; register constants
dephase
setup_vars:
ld a,0xE0
ld (TmsPort),a
ld a,2
ld (TmsWait),a
ld a,0
ld (TmsMode),a
ld a,0
ld (TmsMode+1),a
ld a,0
ld (TmsNameAddr),a
ld a,38h
ld (TmsNameAddr+1),a
ld a,0
ld (TmsPatternAddr),a
ld a,0
ld (TmsPatternAddr+1),a
ld a,0
ld (TmsColorAddr),a
ld a,20h
ld (TmsColorAddr+1),a
ld a,0
ld (TmsSpritePatternAddr),a
ld a,0x18
ld (TmsSpritePatternAddr+1),a
ld a,0xc0
ld (TmsSpriteAttrAddr),a
ld a,0x3b
ld (TmsSpriteAttrAddr+1),a
ret
TmsWriteBit: equ 40h ; bit to indicate memory write
; Registers
TmsCtrl0Reg: equ 80h
TmsCtrl1Reg: equ 81h
TmsNameReg: equ 82h
TmsColorTableReg: equ 83h
TmsPatternReg: equ 84h
TmsSpriteAttrReg: equ 85h
TmsSpritePatternReg: equ 86h
TmsColorReg: equ 87h
; Control Register Bits
TmsM3: equ 200h
TmsExtVideo: equ 100h
Tms16k: equ 80h
TmsDisplayEnable: equ 40h
TmsIntEnableBit: equ 20h
TmsM1: equ 10h
TmsM2: equ 8
TmsSprite32: equ 2
TmsSpriteMag: equ 1
; ---------------------------------------------------------------------------
; table lengths
TmsTileNameLen: equ 300h
TmsTextNameLen: equ 3c0h
TmsTileColorLen: equ 20h
TmsBitmapColorLen: equ 800h
TmsTilePatternLen: equ 800h
TmsTextPatternLen: equ 800h
TmsMulticolorPatternLen: equ 600h
TmsBitmapPatternLen: equ 1800h
; ---------------------------------------------------------------------------
; color constants
TmsTransparent: equ 0
TmsBlack: equ 1
TmsMediumGreen: equ 2
TmsLightGreen: equ 3
TmsDarkBlue: equ 4
TmsLightBlue: equ 5
TmsDarkRed: equ 6
TmsCyan: equ 7
TmsMediumRed: equ 8
TmsLightRed: equ 9
TmsDarkYellow: equ 0ah
TmsLightYellow: equ 0bh
TmsDarkGreen: equ 0ch
TmsMagenta: equ 0dh
TmsGray: equ 0eh
TmsWhite: equ 0fh
; ---------------------------------------------------------------------------
; port I/O routines
; These routines access the ports configured in TmsPort.
; These memory locations can be set at runtime to support different hardware
; configurations from the same binary. TmsProbe automatically detects the
; TMS9918A on common ports.
; The TMS9918A RAM must not be accessed more than once every 8 us or display
; corruption may occur. During vblank and with the display disabled,
; accesses can be 2 us apart, but we will always use 8 us minimum delay.
; TmsRamIn/TmsRamOut include a configurable delay loop, which waits for the
; configured iterations between VRAM writes to work properly with faster CPUs
; Minimum time to execute each procedure call:
; Z80: 88 cycles, 8.8 us @ 10 MHz
; Z180: 80 cycles, 8.64 us @ 9.216 MHz, 4.32 us @ 18.432, 2.16 us @ 36.864
;
; Additional delay per djnz iteration:
; Z80: 8 cycles * (iterations - 1)
; 0.8 us @ 10 MHz
; Z180: 7 cycles * (iterations - 1)
; 0.756 us @ 9.216 MHz, 0.378 us @ 18.432, 0.189 us @ 36.864
; Delay loop iterations required for different CPU speeds:
; Z80 @ 10 MHz or less: 1
; Z180 @ 9.216 MHz or less: 1
; Z180 @ 18.432 MHz: 10
; Z180 @ 36.864 MHz: 31
TmsWaits: defb 1, 10, 31 ; wait iterations to add for different CPU speeds
; set up wait time based on clock multiplier in E
TmsSetWait:
ld a,1
ld (TmsWait), a
ret
; try to find TMS9918A on common ports
TmsProbe:
ld hl, TmsPorts
ld b, TmsNumPorts
TmsProbeNext:
ld a, (hl)
ld (TmsPort), a
call TmsRegIn ; clear vsync bit
call TmsRegIn ; check it again
jp m, TmsProbeFailed ; if still set, not a TMS9918A
ld de, 0ffffh ; long enough for another vsync
TmsProbeWait:
call TmsRegIn ; check vsync bit again
ret m ; if set, it's a TMS9918A (and Z is clear)
dec de ; otherwise, keep waiting
ld a, e
or d
jp nz, TmsProbeWait
TmsProbeFailed:
inc hl ; if still clear after this long, try next port
djnz TmsProbeNext
xor a ; set Z if we ran out of ports to check
ret
TmsPorts: ; List of ports to probe:
defb 0x80 ; ColecoVision / SG-1000
defb 98h ; MSX
defb 10h ; Sord M5 (conflicts with z80ctrl SIO port)
;defb 8 ; Tatung Einstein (conflicts with z80ctrl drive ports)
;defb 1 ; MTX (not supported by TMS9918A video card)
; add additional ports to check here
TmsNumPorts: equ $ - TmsPorts
; set a single register value
; A = register value
; E = register to set
TmsSetReg:
call TmsRegOut
ld a, e
; fallthrough to TmsRegOut
; write to configured register port
; parameters:
; A = value to write
TmsRegOut:
push bc
ld bc, (TmsPort)
inc c
out (c), a
pop bc
ret
; read from configured register port
; returns:
; A = value read
TmsRegIn:
push bc
ld bc, (TmsPort)
inc c
in a, (c)
pop bc
ret
; write to configured VRAM port
; parameters:
; A = value to write
; Z80 | Z180 cycles...
TmsRamOut: ; 17 | 16 (call)
push bc ; 11 | 11
ld bc, (TmsPort) ; 20 | 18
out (c), a ; 12 | 10
TmsRamOutDelay:
djnz TmsRamOutDelay ; 8 | 7 plus (13 | 9) * (iterations-1)
pop bc ; 10 | 9
ret ; 10 | 9
; read from configured VRAM port
; returns:
; A = value read
TmsRamIn:
push bc
ld bc, (TmsPort)
TmsRamInDelay:
djnz TmsRamInDelay
in a, (c)
ld bc, (TmsPort)
TmsRamInDelay2:
djnz TmsRamInDelay2
pop bc
ret
; ---------------------------------------------------------------------------
; register configuration routines
; set the background color
; A = requested color
TmsBackground:
and 0fh
ld b, a
ld a, (TmsScreenColors)
and 0f0h
or b
ld (TmsScreenColors), a
ld e, TmsColorReg
jp TmsSetReg
; set the sprite configuration
; A = sprite options
TmsSpriteConfig:
and TmsSprite32|TmsSpriteMag
ld b, a
ld a, (TmsMode)
and ~(TmsSprite32|TmsSpriteMag)
or b
ld (TmsMode), a
ld e, TmsCtrl1Reg
jp TmsSetReg
; enable vblank interrupts
TmsIntEnable:
ld a, (TmsMode)
or TmsIntEnableBit
ld (TmsMode), a
ld e, TmsCtrl1Reg
jp TmsSetReg
; disable vblank interrupts
TmsIntDisable:
ld a, (TmsMode)
and ~TmsIntEnableBit
ld (TmsMode), a
ld e, TmsCtrl1Reg
jp TmsSetReg
; ---------------------------------------------------------------------------
; initialization routines
TmsBlankFlags: equ Tms16k
TmsTileFlags: equ Tms16k | TmsDisplayEnable
TmsTextFlags: equ Tms16k | TmsDisplayEnable | TmsM1
TmsMulticolorFlags: equ Tms16k | TmsDisplayEnable | TmsM2
TmsBitmapFlags: equ Tms16k | TmsDisplayEnable | TmsM3
; reset registers and clear all 16KB of video memory
TmsReset:
ld hl, TmsBlankFlags ; blank the screen with 16KB enabled
ld (TmsMode), hl
ld a, l
ld e, TmsCtrl1Reg
call TmsSetReg
ld a, h
ld e, TmsCtrl0Reg
call TmsSetReg
ld a, TmsTransparent
call TmsBackground
ld a, TmsTransparent
call TmsTextColor
ld de, 0 ; clear entire VRAM
ld bc, 4000h
ld a, 0
call TmsFill
ret
; initialize for multicolor mode
TmsMulticolor:
call TmsReset
ld de, (TmsNameAddr)
call TmsWriteAddr
ld d, 6 ; name table has 6 sections
ld e, 0 ; lines in first section start at 0
TmsSectionLoop:
ld c, 4 ; each section has 4 identical lines
TmsLineLoop:
ld b, 32 ; each line is 32 bytes long
ld a, e ; same starting value for each line in section
TmsByteLoop:
call TmsRamOut
inc a ; byte value
djnz TmsByteLoop
dec c ; line counter
jp nz, TmsLineLoop
ld e, a ; next starting value = current + 32
dec d ; section counter
jp nz, TmsSectionLoop
ld hl, TmsMulticolorFlags
ld (TmsMode), hl
jp TmsInitNonBitmap
; initialize for tiled graphics
TmsTile:
call TmsReset
ld hl, TmsTileFlags
ld (TmsMode), hl
jp TmsInitNonBitmap
; initialize for text mode
; HL = address of font to load
TmsTextMode:
push hl
call TmsReset
pop hl
ld de, (TmsPatternAddr) ; load font from address in hl
ld bc, TmsTextPatternLen
call TmsWrite
ld hl, TmsTextFlags
ld (TmsMode), hl
; fallthrough to TmsInitNonBitmap
; non-bitmap color and pattern table configuration
TmsInitNonBitmap:
; set up color table address (register = address / 400H)
ld a, (TmsColorAddr)
and 0c0h
ld (TmsColorAddr), a
ld d, a
ld a, (TmsColorAddr+1)
and 3fh
ld (TmsColorAddr+1), a
rl d
rla
rl d
rla
ld e, TmsColorTableReg
call TmsSetReg
; set up pattern table address (register = address / 800H)
xor a
ld (TmsPatternAddr), a
ld a, (TmsPatternAddr+1)
and 38h
ld (TmsPatternAddr+1), a
rrca
rrca
rrca
ld e, TmsPatternReg
call TmsSetReg
jp TmsInitCommon
; initialize for bitmapped graphics
TmsBitmap:
call TmsReset
ld de, (TmsNameAddr) ; initialize name table with 3 sets
call TmsWriteAddr ; of 256 bytes ranging from 00-FF
ld b, 3
xor a
TmsBitmapLoop:
call TmsRamOut
inc a
jp nz, TmsBitmapLoop
djnz TmsBitmapLoop
ld hl, TmsBitmapFlags
ld (TmsMode), hl
; set up color table at 0H (register = 7FH) or 2000H (register = 0FFH)
xor a
ld (TmsColorAddr), a
ld (TmsPatternAddr), a
ld a, (TmsColorAddr+1)
and 20h
ld (TmsColorAddr+1), a
ld a, 0ffh ; color table at 2000H
jp nz, TmsColorTableHigh
ld a, 7fh ; color table at 0H
TmsColorTableHigh:
ld e, TmsColorTableReg
call TmsSetReg
; set up pattern table at 0H (register = 3) or 2000H (register = 7)
ld a, (TmsPatternAddr+1)
and 20h
ld (TmsPatternAddr+1), a
ld a, 7 ; pattern table at 2000H
jp nz, TmsPatternTableHigh
ld a, 3 ; pattern table at 0H
TmsPatternTableHigh:
ld e, TmsPatternReg
call TmsSetReg
; fall through to TmsInitCommon
; common initialization for all modes
TmsInitCommon:
; set up name table address (register = address / 400H)
xor a
ld (TmsNameAddr), a
ld a, (TmsNameAddr+1)
and 3ch
ld (TmsNameAddr+1), a
rrca
rrca
ld e, TmsNameReg
call TmsSetReg
; set up sprite pattern table address (register = address / 80H)
ld a, (TmsSpriteAttrAddr)
and 80h
ld (TmsSpriteAttrAddr), a
ld d, a
ld a, (TmsSpriteAttrAddr+1)
and 7fh
rl d
rla
ld e, TmsSpriteAttrReg
call TmsSetReg
; set up sprite attribute table address (register = address / 800H)
xor a
ld (TmsSpritePatternAddr), a
ld a, (TmsSpritePatternAddr+1)
and 38h
ld (TmsSpritePatternAddr+1), a
rrca
rrca
rrca
ld e, TmsSpritePatternReg
call TmsSetReg
; set up control registers
ld e, TmsCtrl1Reg
ld a, (TmsMode)
call TmsSetReg
ld a, (TmsMode+1)
ld e, TmsCtrl0Reg
jp TmsSetReg
; ---------------------------------------------------------------------------
; memory access routines
; set the next address of vram to write
; DE = address
TmsWriteAddr:
ld a, e ; send lsb
call TmsRegOut
ld a, d ; mask off msb to max of 16KB
and 3fh
or TmsWriteBit ; indicate that this is a write
call TmsRegOut
ret
; set the next address of vram to read
; DE = address
TmsReadAddr:
ld a, e ; send lsb
call TmsRegOut
ld a, d ; mask off msb to max of 16KB
and 3Fh
call TmsRegOut
ret
; copy bytes from ram to vram
; HL = ram source address
; DE = vram destination address
; BC = byte count
TmsWrite:
call TmsWriteAddr
TmsWriteLoop:
ld a, (hl)
call TmsRamOut
inc hl
dec bc
ld a, b
or c
jp nz, TmsWriteLoop
ret
; fill a section of memory with a single value
; A = value to fill
; DE = vram destination address
; BC = byte count
TmsFill:
push af
call TmsWriteAddr
pop af
TmsFillLoop:
call TmsRamOut
dec c
jp nz, TmsFillLoop
djnz TmsFillLoop
ret
; ---------------------------------------------------------------------------
; text routines
; set text color
; A = requested color
TmsTextColor:
add a, a ; text color into high nybble
add a, a
add a, a
add a, a
ld b, a ; save for later
ld a, (TmsScreenColors) ; get current colors
and 0fh ; mask off old text color
or b ; set new text color
ld (TmsScreenColors), a
ld e, TmsColorReg
jp TmsSetReg ; save it back
; set the address to place text at X/Y coordinate
; A = X
; E = Y
TmsTextPos:
ld d, 0
ld hl, 0
add hl, de ; Y x 1
add hl, hl ; Y x 2
add hl, hl ; Y x 4
add hl, de ; Y x 5
add hl, hl ; Y x 10
add hl, hl ; Y x 20
add hl, hl ; Y x 40
ld e, a
add hl, de ; add X for final address
ld de, (TmsNameAddr) ; add name table base address
add hl, de
ex de, hl
jp TmsWriteAddr
; copy a null-terminated string to VRAM
; HL = ram source address
TmsStrOut:
ld a, (hl)
cp 0 ; return when NULL is encountered
ret z
call TmsRamOut
inc hl
jp TmsStrOut
; repeat a character a certain number of times
; A = character to output
; B = count
TmsRepeat:
call TmsRamOut
djnz TmsRepeat
ret
; output a character
; A = character to output
TmsChrOut: equ TmsRamOut
; ---------------------------------------------------------------------------
; bitmap routines
TmsClearPixel: equ 0A02Fh ; cpl, and b
TmsSetPixel: equ 0B0h ; nop, or b
; set operation for TmsPlotPixel to perform
; HL = pixel operation (TmsClearPixel, TmsSetPixel)
TmsPixelOp:
ld (TmsPixelOpPlaceHolder), hl
ret
; set or clear pixel at X, Y position
; B = Y position
; C = X position
TmsPlotPixel:
ld a, b ; bail out if Y coord > 191
cp 192
ret nc
call TmsXYAddr ; get address in DE for X/Y coord in BC
ld a, c ; get lower 3 bits of X coord
and 7
ld b, 0
ld c, a
ld hl, TmsMaskLookup ; address of mask in table
add hl, bc
ld b, (hl) ; save mask in B
ld hl, (TmsPatternAddr) ; get base address for pattern table
add hl, de
ex de, hl
call TmsReadAddr ; set read within pattern table
call TmsRamIn
TmsPixelOpPlaceHolder:
or b ; mask bit in previous byte
nop ; place holder for 2 byte mask operation
push af
call TmsWriteAddr ; set write address within pattern table
pop af
jp TmsRamOut
TmsMaskLookup:
defb 80h, 40h, 20h, 10h, 8h, 4h, 2h, 1h
; set the color for a block of pixels in bitmap mode
; B = Y position
; C = X position
; A = foreground/background color to set
TmsPixelColor:
push af
ld a, b ; bail out if Y coord > 191
cp 192
ret nc
call TmsXYAddr ; get address in DE for X/Y coord in BC
ld hl, (TmsColorAddr) ; add the color table base address
add hl, de
ex de, hl
call TmsWriteAddr ; set write address within color table
pop af
jp TmsRamOut
; calculate address byte containing X/Y coordinate
; B = Y position
; C = X position
; returns address in DE
TmsXYAddr:
ld a, b ; d = (y / 8)
rrca
rrca
rrca
and 1fh
ld d, a
ld a, c ; e = (x & f8)
and 0f8h
ld e, a
ld a, b ; e += (y & 7)
and 7
or e
ld e, a
ret

File diff suppressed because it is too large Load Diff