ys2-intro/loader/src/hal/hal-c16.inc
2025-11-13 19:07:39 +03:00

364 lines
10 KiB
PHP

.ifndef _HAL_C16_INC_
_HAL_C16_INC_ = 1
.include "cpu.inc"
.include "pio.inc"
.include "ted.inc"
.macro CHECK_INSTALL_END_ADDRESS
.assert * <= $8000, error, "Install code exceeds $8000, please make sure the DISKIO_INSTALL segment ends below $8000"
.endmacro
.if LOAD_VIA_KERNAL_FALLBACK
.macro CHECK_RESIDENT_START_ADDRESS
RESIDENT_START_ADDRESS = *
.endmacro
.macro CHECK_RESIDENT_END_ADDRESS
.assert * <= $8000, error, "Resident code exceeds $8000, please make sure the DISKIO segment ends below $8000"
.endmacro
.else
.macro CHECK_RESIDENT_START_ADDRESS
.assert * <= $fd00, error, "Resident code exceeds $fd00, please make sure the DISKIO segment ends below $fd00"
.endmacro
.macro CHECK_RESIDENT_END_ADDRESS
.assert * <= $fd00, error, "Resident code exceeds $fd00, please make sure the DISKIO segment ends below $fd00"
.endmacro
.endif
.macro OK_CLC
lda #diskio::status::OK; $00
clc; all ok
.endmacro
.macro PREPARE_DRIVE_DISTURBANCE_VALIDATION
; disregard drive if it is a 1551, as
; it is not connected to the serial bus
lda #$01
sta USE4DY
.endmacro
.macro BRANCH_IF_DRIVE_DOES_NOT_DISTURB_SERIAL_BUS to
lda USE4DY; calling LISTEN will set USE4DY to $00 if 1551 at #9,
eor #$01 ; $30 if 1551 at #8, and leave it at $01 otherwise,
bne to ; then drvlistn will return with $80, $b0, or $01
.endmacro
.if LOAD_VIA_KERNAL_FALLBACK
.macro BUFFER_MEMCONFIG
GET_MEMCONFIG
pha
.endmacro
.macro RESTORE_MEMCONFIG_Y
tay
pla
SET_MEMCONFIG
tya
.endmacro
.macro PREPARE_PARALLEL_CHECK
lda #$01 ; calling LISTEN will set USE4DY to $00 if 1551 at #9,
sta USE4DY; $30 if 1551 at #8, and leave it at $01 otherwise
.endmacro
.macro ENABLE_KERNAL_SERIAL_ROUTINES
sta TED_ROM_ENABLE
.endmacro
.macro ENABLE_KERNAL_SERIAL_ROUTINES_Y
sta TED_ROM_ENABLE
.endmacro
.macro ENABLE_ALL_RAM
sta TED_RAM_ENABLE
.endmacro
.macro ENABLE_ALL_RAM_Y
sty TED_RAM_ENABLE
.endmacro
.macro GET_MEMCONFIG
lda #ROM_IS_ENABLED
and TED_CHARGEN_ADDR
.endmacro
.macro SET_MEMCONFIG
.local use_ram
sta TED_RAM_ENABLE
beq use_ram
sta TED_ROM_ENABLE
use_ram:
.endmacro
.macro SET_MEMCONFIG_Y
.local use_ram
sty TED_RAM_ENABLE
beq use_ram
sty TED_ROM_ENABLE
use_ram:
.endmacro
.endif; !LOAD_VIA_KERNAL_FALLBACK
IO_PORT_DIR_COMMON = IO_PORT_SERIAL_DATA_IN_INPUT | IO_PORT_SERIAL_CLK_IN_INPUT | IO_PORT_CST_MTR_OUTPUT | IO_PORT_SERIAL_ATN_OUT_OUTPUT | IO_PORT_SERIAL_CLK_OUT_OUTPUT | IO_PORT_SERIAL_DATA_OUT_OUTPUT; $0f
; effectively, this is the KERNAL flag:
; 0 = input = KERNAL,
; 1 = output = loader
IO_PORT_DIR_KERNAL = IO_PORT_DIR_COMMON | IO_PORT_CST_RD_INPUT ; $0f
IO_PORT_DIR_OPERATE = IO_PORT_DIR_COMMON | IO_PORT_CST_RD_OUTPUT; $1f
.macro INSTALL_IDLE
lda #IO_PORT_CST_MTR | IO_PORT_SERIAL_ATN_OUT | IO_PORT_SERIAL_CLK_OUT | IO_PORT_SERIAL_DATA_OUT; $0f
sta IO_PORT
lda #IO_PORT_DIR_OPERATE
sta IO_PORT_DIRECTION
.endmacro
.macro CLEAR store; store is ignored
lda #IO_PORT_CST_MTR | IO_PORT_SERIAL_ATN_OUT | (0 & IO_PORT_SERIAL_CLK_OUT) | (0 & IO_PORT_SERIAL_DATA_OUT); $0c
sta IO_PORT
.endmacro
.macro CLOSE_FILE
SYNC
ldx #IO_PORT_CST_MTR | (0 & IO_PORT_SERIAL_ATN_OUT) | IO_PORT_SERIAL_CLK_OUT | (0 & IO_PORT_SERIAL_DATA_OUT); $0a
stx IO_PORT
: dex
bne :-
lda IO_PORT
asl
IDLE
.endmacro
.macro SYNC
lda #IO_PORT_CST_MTR | IO_PORT_SERIAL_ATN_OUT | IO_PORT_SERIAL_CLK_OUT | (0 & IO_PORT_SERIAL_DATA_OUT); $0e
sta IO_PORT
.endmacro
.macro PUSH_CLOCKCONFIG_AND_FORCE_SLOW_CLOCK
.local singleclk
lda TED_CHARGEN_ADDR
and #FORCE_SINGLE_CLOCK
pha
bne singleclk
lda #FORCE_SINGLE_CLOCK
php
sei ; 2
ora TED_CHARGEN_ADDR ; 4
sta TED_CHARGEN_ADDR ; 4
plp ; 4
singleclk: ; = 14
.endmacro
.macro POP_CLOCKCONFIG
.local singleclk
pla
bne singleclk
lda #255 - FORCE_SINGLE_CLOCK
php
sei ; 2
and TED_CHARGEN_ADDR ; 4
sta TED_CHARGEN_ADDR ; 4
plp ; 4
singleclk: ; = 14
.endmacro
.macro SENDBYTE sendstore
; does not clobber y
.local sendbyte
.local bitset
tax
PUSH_CLOCKCONFIG_AND_FORCE_SLOW_CLOCK
txa
ldx #$07
sendbyte: lsr
pha
lda IO_PORT
ora #IO_PORT_SERIAL_ATN_OUT | IO_PORT_SERIAL_CLK_OUT
bcs bitset
and #255 - IO_PORT_SERIAL_CLK_OUT
bitset: eor #IO_PORT_SERIAL_DATA_OUT
sta IO_PORT
pla
dex
bpl sendbyte
POP_CLOCKCONFIG
.endmacro
.macro RECEIVEBYTE
PUSH_CLOCKCONFIG_AND_FORCE_SLOW_CLOCK
lda #$01
: pha
pla
pha
lda #IO_PORT_SERIAL_CLK_OUT
eor IO_PORT
ldx #IO_PORT_SERIAL_DATA_IN
cpx IO_PORT
sta IO_PORT
pla
rol
bcc :-
tax
POP_CLOCKCONFIG
txa
.endmacro
.macro SET_FLAGS_N_DATA_V_CLK
bit IO_PORT
.endmacro
CLOCK = IO_PORT_CST_MTR | (0 & IO_PORT_SERIAL_CLK_OUT) | (0 & IO_PORT_SERIAL_DATA_OUT)
CLOCK_ATN_HI = CLOCK | IO_PORT_SERIAL_ATN_OUT ; 1st and 3rd bit pairs; $0c
CLOCK_ATN_LO = CLOCK | (0 & IO_PORT_SERIAL_ATN_OUT); 2nd and 4th bit pairs; $08
.macro ENABLE_WAITBUSY_KERNAL
lda #.lobyte(~IO_PORT_SERIAL_CLK_OUT)
and IO_PORT
sta IO_PORT
.endmacro
.macro INIT_CLEAR_ATN_OUT_CLEAR_CLK_OUT_CLEAR_DATA_OUT
lda #IO_PORT_CST_MTR | (0 & IO_PORT_SERIAL_ATN_OUT) | (0 & IO_PORT_SERIAL_CLK_OUT) | (0 & IO_PORT_SERIAL_DATA_OUT); $08
sta IO_PORT
.endmacro
.macro IDLE
ldx #IO_PORT_CST_MTR | IO_PORT_SERIAL_ATN_OUT | IO_PORT_SERIAL_CLK_OUT | IO_PORT_SERIAL_DATA_OUT; $0f
stx IO_PORT
.endmacro
.if LOAD_VIA_KERNAL_FALLBACK
KERNALFILENO = 2
.macro CLEAR_DATA_OUT_CLEAR_CLK_OUT_ASSERT_ATN
lda IO_PORT
and #.lobyte(~(IO_PORT_SERIAL_CLK_OUT | IO_PORT_SERIAL_DATA_OUT))
ora #IO_PORT_SERIAL_ATN_OUT
sta IO_PORT
.endmacro
.endif
.macro BRANCH_IF_INSTALLED to
lda #IO_PORT_DIR_KERNAL
cmp IO_PORT_DIRECTION
bne to
.endmacro
.macro BRANCH_IF_NOT_INSTALLED to
lda #IO_PORT_DIR_KERNAL
cmp IO_PORT_DIRECTION
beq to
.endmacro
.macro CHECK_AND_BRANCH_IF_DRIVE_PARALLEL to
jsr CHECKPARALLEL
bcc to
.endmacro
.macro BRANCH_IF_DRIVE_PARALLEL to
lda USE4DY
lsr
bcc to
.endmacro
.macro POLL_BLOCK idle_eof, block_not_yet_ready, device_not_present
lda #IO_PORT_CST_MTR | IO_PORT_SERIAL_ATN_OUT | IO_PORT_SERIAL_CLK_OUT | IO_PORT_SERIAL_DATA_OUT; $0f
cmp IO_PORT
beq idle_eof; branches with carry set on idle/eof
clc
lda #diskio::status::DEVICE_NOT_PRESENT; $fe
SET_FLAGS_N_DATA_V_CLK
bvc block_not_yet_ready
sec
bmi device_not_present
.endmacro
.macro SEND_BLOCK_SIGNAL
ldy #CLOCK_ATN_LO; use y to ensure that y < $fe when
sty IO_PORT ; calling getbyte for the 2 control bytes
PUSH_CLOCKCONFIG_AND_FORCE_SLOW_CLOCK
pha; delay
pla
.endmacro
.macro RECEIVE_SETUP
; nothing to do
.endmacro
.macro RECEIVE store, out
.local loop
; 16 cycles per bitpair ~ 18 cycles at 1 MHz = 18 µs
; PAL: 16 / 886723 Hz = 18.04 µs
; NTSC: 16 / 894886 Hz = 17.88 µs
loop: ldx #CLOCK_ATN_HI ; 2
lda IO_PORT ; 3
stx IO_PORT; ATN high ; 3
; = 16
iny ; 2
beq out ; 2
lsr ; 2
lsr ; 2
ldx #CLOCK_ATN_LO ; 2
eor IO_PORT ; 3
stx IO_PORT; ATN low ; 3
; = 16
lsr ; 2
lsr ; 2
nop ; 2 - delay
nop ; 2 - delay
ldx #CLOCK_ATN_HI ; 2
eor IO_PORT ; 3
stx IO_PORT; ATN high ; 3
; = 16
lsr ; 2
lsr ; 2
nop ; 2 - delay
eor #CLOCK_ATN_HI | (CLOCK_ATN_LO >> 2) ; 2
ldx #CLOCK_ATN_LO ; 2
eor IO_PORT ; 3
stx IO_PORT; ATN low ; 3
; = 16
store ; 5 - sta mem16,y
jmp loop ; 3
out:
.endmacro
.macro STOREBYTE_ALLRAM
storebytio: sta $0000,y
.endmacro
.macro ENDGETBLOCK
POP_CLOCKCONFIG
.endmacro
.macro SET_IO_KERNAL
INIT_CLEAR_ATN_OUT_CLEAR_CLK_OUT_CLEAR_DATA_OUT
lda #IO_PORT_DIR_KERNAL
sta IO_PORT_DIRECTION
.endmacro
.endif; !_HAL_C16_INC_