357 lines
4.6 KiB
ArmAsm
357 lines
4.6 KiB
ArmAsm
;; #LAYOUT# STD * #TAKE
|
|
;; #LAYOUT# CRT KERNAL_0 #TAKE
|
|
;; #LAYOUT# M65 KERNAL_1 #TAKE
|
|
;; #LAYOUT# * * #IGNORE
|
|
|
|
;
|
|
; Common routines for tape support
|
|
;
|
|
|
|
|
|
!ifdef HAS_TAPE {
|
|
|
|
|
|
;
|
|
; Loading terminated by user
|
|
;
|
|
|
|
tape_break_error:
|
|
|
|
pla
|
|
pla
|
|
cli
|
|
jmp kernalerror_ROUTINE_TERMINATED
|
|
|
|
|
|
;
|
|
; Ask user to press PLAY on tape deck,
|
|
; Unless user cancelled loading, blank screen and start motor
|
|
;
|
|
|
|
tape_ask_play:
|
|
|
|
!ifndef CONFIG_TAPE_NO_KEY_SENSE {
|
|
|
|
; First check whether the button is already pressed
|
|
|
|
lda CPU_R6510
|
|
and #$10
|
|
beq tape_wait_play_done
|
|
}
|
|
|
|
; Display message
|
|
|
|
ldx #__MSG_KERNAL_PRESS_PLAY
|
|
jsr print_kernal_message
|
|
|
|
; FALLTROUGH
|
|
|
|
!ifndef CONFIG_TAPE_NO_KEY_SENSE {
|
|
|
|
tape_wait_play_loop:
|
|
|
|
jsr STOP
|
|
bcs tape_break_error
|
|
|
|
lda CPU_R6510
|
|
and #$10 ; check for pressed button
|
|
bne tape_wait_play_loop
|
|
|
|
; FALLTROUGH
|
|
|
|
} else {
|
|
|
|
; The ROM is configured for tape adapter without the key sense - but it is still
|
|
; possible, that regular Datasette or Tapuino is connected
|
|
|
|
lda CPU_R6510
|
|
and #$10
|
|
beq tape_wait_first_pulse ; branch if button reported pressed, most likely really no key sense
|
|
|
|
; We have key sense - perform regular waiting
|
|
@1:
|
|
jsr STOP
|
|
bcs tape_break_error
|
|
|
|
lda CPU_R6510
|
|
and #$10
|
|
beq @1
|
|
|
|
tape_wait_first_pulse:
|
|
|
|
; We have no key sense - so just turn the motor on and wait for the first pulse
|
|
|
|
jsr tape_motor_on
|
|
|
|
@2:
|
|
jsr STOP
|
|
bcs tape_break_error
|
|
|
|
lda #$10
|
|
bit CIA1_ICR ; $DC0D
|
|
bne @2
|
|
@3:
|
|
jsr STOP
|
|
bcs tape_break_error
|
|
|
|
lda #$10
|
|
bit CIA1_ICR ; $DC0D
|
|
beq @3
|
|
}
|
|
|
|
; FALLTROUGH
|
|
|
|
tape_wait_play_done:
|
|
|
|
lda #$01
|
|
sta CAS1 ; set the interlock
|
|
|
|
!ifdef CONFIG_TAPE_HEAD_ALIGN {
|
|
|
|
rts
|
|
|
|
tape_prepare_reading:
|
|
|
|
} ; CONFIG_TAPE_HEAD_ALIGN
|
|
|
|
; Display confirmation
|
|
|
|
ldx #__MSG_KERNAL_OK
|
|
jsr print_kernal_message
|
|
|
|
; Prepare for reading
|
|
|
|
jsr print_return
|
|
jmp tape_screen_off_motor_on
|
|
|
|
|
|
;
|
|
; Handle file header - display it, decide whether load the file or not, etc.
|
|
;
|
|
|
|
tape_handle_header:
|
|
|
|
!ifndef CONFIG_TAPE_NO_MOTOR_CONTROL {
|
|
|
|
jsr tape_screen_on_motor_off
|
|
}
|
|
|
|
; Print FOUND + file name
|
|
|
|
ldx #__MSG_KERNAL_FOUND
|
|
jsr print_kernal_message
|
|
|
|
ldy #$05
|
|
@4:
|
|
lda (TAPE1), y
|
|
jsr JCHROUT
|
|
iny
|
|
cpy #$15
|
|
bne @4
|
|
|
|
!ifndef CONFIG_TAPE_NO_MOTOR_CONTROL {
|
|
|
|
; Header, wait for user decision
|
|
|
|
jsr tape_header_get_decision
|
|
bcs tape_break_error
|
|
}
|
|
|
|
; Check if file name matches
|
|
|
|
jsr tape_match_filename
|
|
bcs tape_handle_header_skip
|
|
|
|
; Setup STAL and EAL
|
|
|
|
ldy #$01
|
|
lda (TAPE1), y
|
|
sta STAL+0
|
|
|
|
iny
|
|
lda (TAPE1), y
|
|
sta STAL+1
|
|
|
|
iny
|
|
lda (TAPE1), y
|
|
sta EAL+0
|
|
|
|
iny
|
|
lda (TAPE1), y
|
|
sta EAL+1
|
|
|
|
; Handle the secondary address, 0 means loading to location from MEMUSS
|
|
|
|
lda SA
|
|
bne @5
|
|
|
|
; EAL = EAL - STAL
|
|
|
|
sec
|
|
lda EAL+0
|
|
sbc STAL+0
|
|
sta EAL+0
|
|
lda EAL+1
|
|
sbc STAL+1
|
|
sta EAL+1
|
|
|
|
; STAL = MEMUSS
|
|
|
|
lda MEMUSS+0
|
|
sta STAL+0
|
|
lda MEMUSS+1
|
|
sta STAL+1
|
|
|
|
; EAL = EAL + STAL
|
|
|
|
clc
|
|
lda EAL+0
|
|
adc STAL+0
|
|
sta EAL+0
|
|
lda EAL+1
|
|
adc STAL+1
|
|
sta EAL+1
|
|
@5:
|
|
; Setup MEMUSS (see Mapping the C64, page 36)
|
|
|
|
jsr lvs_STAL_to_MEMUSS
|
|
|
|
!ifdef CONFIG_MB_M65 {
|
|
|
|
; Switch to legacy mode if needed
|
|
|
|
jsr m65_load_autoswitch_tape
|
|
}
|
|
|
|
; Print LOADING and start address
|
|
|
|
jsr lvs_display_loading_verifying
|
|
|
|
; FALLTROUGH
|
|
|
|
!ifndef CONFIG_TAPE_NO_MOTOR_CONTROL {
|
|
|
|
tape_handle_header_displayed:
|
|
|
|
; Load the file
|
|
|
|
jsr tape_screen_off_motor_on
|
|
|
|
; FALLTROUGH
|
|
}
|
|
|
|
tape_return_ok:
|
|
|
|
clc
|
|
rts
|
|
|
|
tape_handle_header_skip:
|
|
|
|
; Skip this file
|
|
|
|
jsr print_return
|
|
jsr tape_screen_off_motor_on
|
|
|
|
; FALLTROUGH
|
|
|
|
tape_return_not_ok:
|
|
|
|
sec
|
|
rts
|
|
|
|
|
|
;
|
|
; Check whether file name matches the pattern
|
|
;
|
|
|
|
tape_match_filename:
|
|
|
|
lda FNLEN
|
|
beq tape_return_ok ; no pattern to match
|
|
|
|
ldy #$00
|
|
|
|
tape_match_loop:
|
|
|
|
lda #$20 ; default byte, for padding
|
|
cpy FNLEN
|
|
bcs @6 ; end of pattern
|
|
lda (FNADDR), y ; byte from pattern
|
|
@6:
|
|
cmp #KEY_ASTERISK
|
|
beq tape_return_ok
|
|
|
|
iny
|
|
iny
|
|
iny
|
|
iny
|
|
iny
|
|
|
|
cmp (TAPE1), y
|
|
bne tape_return_not_ok
|
|
|
|
dey
|
|
dey
|
|
dey
|
|
dey
|
|
|
|
cpy #$10
|
|
bne tape_match_loop
|
|
|
|
clc
|
|
rts
|
|
|
|
|
|
!ifndef CONFIG_TAPE_NO_MOTOR_CONTROL {
|
|
|
|
;
|
|
; Get user decision whether to load the file or not
|
|
;
|
|
|
|
tape_header_get_decision:
|
|
|
|
ldy #$00
|
|
@7:
|
|
jsr udtim_keyboard
|
|
lda STKEY
|
|
bpl tape_header_wait_stop ; STOP pressed
|
|
and #$10
|
|
beq tape_header_wait_space ; SPACE pressed
|
|
|
|
ldx #$80
|
|
jsr wait_x_bars ; sets .X to 0
|
|
dex
|
|
jsr wait_x_bars
|
|
|
|
dey
|
|
bne @7
|
|
|
|
; FALLTROUGH - timeout
|
|
|
|
tape_header_wait_space:
|
|
|
|
clc
|
|
rts
|
|
|
|
tape_header_wait_stop:
|
|
|
|
sec
|
|
rts
|
|
}
|
|
|
|
|
|
;
|
|
; Report that file loading succeeded (or not)
|
|
;
|
|
|
|
tape_load_success:
|
|
|
|
jsr tape_screen_on_motor_off
|
|
jsr lvs_display_done
|
|
jmp lvs_return_last_address
|
|
|
|
tape_load_error:
|
|
|
|
jsr tape_screen_on_motor_off
|
|
jmp lvs_load_verify_error
|
|
} |