more sane directory name, updated binaries

This commit is contained in:
FeralChild64 committed 2020-06-26 19:44:01 +02:00
1 parent d4d32095d1
commit 76aaf298b8
697 files changed
+56 -56

No files matched your search

+172
View File
@@ -0,0 +1,172 @@
// #LAYOUT# STD * #TAKE
// #LAYOUT# M65 KERNAL_1 #TAKE
// #LAYOUT# * * #IGNORE
//
// Tape (normal) part of the LOAD routine
//
// We have the following possible CPU frequencies:
// - C64    PAL:  CPU frequency 0.985248 MHz
// - C64    NTSC: CPU frequency 1.022727 MHz
// The clock difference is about 4% - it is unlikely to cause problems.
//
// We have to distinguish the following pulse lengths (http://sidpreservation.6581.org/tape-format/):
// - S (short)    tap value $30 (PAL: 352 us)
// - M (medium)   tap value $42 (PAL: 512 us)
// - L (long)     tap value $56 (PAL: 672 us)
//
// The TAP format (http://unusedino.de/ec64/technical/formats/tap.html) uses a resolution of 8 PAL ticks;
// this implementation sets the timer for twice the precision (timer B is triggered every 4 CPU cycles),
// probably an overkill, but in realityy it does not cost us anything.
//
// So - we have the following thresholds:
// - S vs M       $72 (in our units of 4 ticks)
// - M vs L       $98 (in our units of 4 ticks)
//
// We need to recognize the following pulse sequences:
//
// (S,M) = 0 bit
// (M,S) = 1 bit
// (L,M) = new-data marker
// (L,S) = end-of-data marker
#if CONFIG_TAPE_NORMAL
#if !CONFIG_TAPE_AUTODETECT
load_tape_normal:
jsr tape_ditch_verify // only LOAD is supported, no VERIFY
// Start playing
jsr tape_common_prepare_cia
jsr tape_ask_play
#if CONFIG_TAPE_HEAD_ALIGN
jsr tape_prepare_reading
#endif
// FALLTROUGH
load_tape_normal_header:
#else
load_tape_normal_takeover: // entry point for turbo->normal takeover
#endif
jsr load_MEMUSS_to_STAL
// Try to load header into tape buffer (we will restore MEMUSS later)
jsr tape_normal_get_pilot_header
#if CONFIG_TAPE_AUTODETECT
bcs load_tape_normal_switch_turbo // failed, try turbo
#endif
jsr load_TAPE1_to_MEMUSS
jsr tape_normal_get_data_1
#if !CONFIG_TAPE_AUTODETECT
bcs load_tape_normal_header // unable to read block, try again
#else
bcc !+
load_tape_normal_switch_turbo:
jsr lvs_STAL_to_MEMUSS
jmp load_tape_turbo_takeover // unable to read block, try turbo instead
!:
#endif
#if CONFIG_TAPE_NO_ERROR_CORRECTION
lda RIPRTY
cmp #$01 // sets Carry if checksum verification fails
#else
jsr load_TAPE1_to_MEMUSS
jsr tape_normal_get_data_2
#endif
#if !CONFIG_TAPE_AUTODETECT
bcs load_tape_normal_header // block load error, try again
#else
bcs load_tape_normal_switch_turbo // block load error, try turbo instead
#endif
// Check header type
ldy #$00
lda (TAPE1),y
cmp #$05
beq_16 tape_load_error // end of tape mark, nothing to load
cmp #$01
beq !+
cmp #$03
#if !CONFIG_TAPE_AUTODETECT
bne load_tape_normal_header // header types 1 and 3 are loadable, see Mapping the C64, page 77
#else
bne load_tape_normal_takeover
#endif
lda #$01
sta SA // this file is non-relocatable; override secondary address with 1
!:
// Restore MEMUSS, handle header
jsr lvs_STAL_to_MEMUSS
jsr tape_handle_header
#if !CONFIG_TAPE_AUTODETECT
bcs load_tape_normal_header // if name does not match, look for other header
#else
bcs load_tape_normal_takeover
#endif
// FALLTROUGH
load_tape_normal_payload:
// Retrieve data
jsr tape_normal_get_pilot_data
ldy #$00 // no data size limit
jsr tape_normal_get_data_1
bcs_16 tape_load_error
jsr lvs_check_EAL
bne_16 tape_load_error // amount of data read does not match header info
#if CONFIG_TAPE_NO_ERROR_CORRECTION
lda RIPRTY
cmp #$01 // sets Carry if checksum verification fails
#else
jsr lvs_STAL_to_MEMUSS
jsr tape_normal_get_data_2
#endif
bcs_16 tape_load_error
jmp tape_load_success
load_TAPE1_to_MEMUSS: // set MEMUSS (start address) as tape buffer
lda TAPE1+1
sta MEMUSS+1
lda TAPE1+0
sta MEMUSS+0
rts
load_MEMUSS_to_STAL: // preserve MEMUSS
lda MEMUSS+1
sta STAL+1
lda MEMUSS+0
sta STAL+0
rts
#endif
+161
View File
@@ -0,0 +1,161 @@
// #LAYOUT# STD * #TAKE
// #LAYOUT# M65 KERNAL_1 #TAKE
// #LAYOUT# * * #IGNORE
//
// Tape (turbo) part of the LOAD routine
//
// Initially based on routine by enthusi/Onslaught, found here:
// - https://codebase64.pokefinder.org/doku.php?id=base:turbotape_loader_source
// but heavily reworked since then. Still, original authors deserve credits!
#if CONFIG_TAPE_TURBO
#if !CONFIG_TAPE_AUTODETECT
load_tape_turbo:
#else
load_tape_auto:
#endif
jsr tape_ditch_verify // only LOAD is supported, no VERIFY
// Prepare for sound effects
jsr tape_clean_sid
// Start playing
jsr tape_common_prepare_cia
jsr tape_ask_play
#if CONFIG_TAPE_HEAD_ALIGN
jsr tape_prepare_reading
#endif
// FALLTROUGH
#if CONFIG_TAPE_AUTODETECT
load_tape_turbo_takeover: // entry point for normal->turbo takeover
jsr tape_common_autodetect
bcc_16 load_tape_normal_takeover
#endif
// FALLTROUGH
load_tape_turbo_header:
// Read file header; structure described here:
// - https://www.luigidifraia.com/c64/docs/tapeloaders.html#turbotape64
//
// 1 byte - file type (0 = data, odd value = relocatable, even value = non-relocatable)
// 2 bytes - start address
// 2 bytes - end address + 1
// 1 byte - if $B0 (tape timing) contained at the time of saving
// (we skip this one to match normal system header)
// 16 bytes - filename, padded with 0x20
jsr tape_turbo_sync_header
#if CONFIG_TAPE_AUTODETECT
bcs_16 load_tape_normal_takeover // failure, probably not a turbo tape file
#endif
ldy #$00
sta (TAPE1), y // store header type
iny
// FALLTROUGH
load_tape_turbo_header_loop:
jsr tape_turbo_get_byte
sta (TAPE1), y
iny
cpy #$05
bne !+
jsr tape_turbo_get_byte // tape timing - skip this one
!:
cpy #$C0 // header is 192 bytes long in total
bne load_tape_turbo_header_loop
// For non-relocatable files, override secondary address
ldy #$00 // XXX optimize out for 65C02
lda (TAPE1), y
beq !+
and #$01
bne !+
lda #$01 // XXX for 65C02 just set the bit with one instruction
sta SA
!:
// Handle the header
jsr tape_clean_sid
jsr tape_handle_header
bcs load_tape_turbo_header // if name does not match, look for other header
// FALLTROUGH
load_tape_turbo_payload:
// Copy helper byte store routine to RAM, provide default memory mapping
ldx #(__tape_turbo_bytestore_size - 1)
!:
lda tape_turbo_bytestore_source, x
sta __tape_turbo_bytestore, x
dex
bpl !-
lda CPU_R6510
sta __tape_turbo_bytestore_defmap
// Initial checksum value
lda #$00
sta PRTY
// Read file payload
!:
jsr tape_turbo_sync_payload
#if CONFIG_TAPE_AUTODETECT
bcs !-
#endif
// FALLTROUGH
load_tape_turbo_loop:
jsr tape_turbo_get_byte
jsr __tape_turbo_bytestore // like 'sta (MEMUSS),y' - but under I/O
eor PRTY // handle checksum
sta PRTY
// Advance MEMUSS (see Mapping the C64, page 36)
#if !HAS_OPCODES_65CE02
jsr lvs_advance_MEMUSS
#else
inw MEMUSS+0
#endif
jsr lvs_check_EAL
bne load_tape_turbo_loop
// Get the checksum
jsr tape_turbo_get_byte
tax
// Silence audio
jsr tape_clean_sid
// Verify the checksum
cpx PRTY
beq_16 tape_load_success
jmp tape_load_error
#endif // CONFIG_TAPE_TURBO
+351
View File
@@ -0,0 +1,351 @@
// #LAYOUT# STD * #TAKE
// #LAYOUT# M65 KERNAL_1 #TAKE
// #LAYOUT# * * #IGNORE
//
// Common routines for tape support
//
#if CONFIG_TAPE_NORMAL || CONFIG_TAPE_TURBO
//
// 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:
#if !CONFIG_TAPE_NO_KEY_SENSE
// First check whether the button is already pressed
lda CPU_R6510
and #$10
beq tape_wait_play_done
#endif
// Display message
ldx #__MSG_KERNAL_PRESS_PLAY
jsr print_kernal_message
// FALLTROUGH
#if !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
!:
jsr STOP
bcs tape_break_error
lda CPU_R6510
and #$10
beq !-
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
!:
jsr STOP
bcs tape_break_error
lda #$10
bit CIA1_ICR // $DC0D
bne !-
!:
jsr STOP
bcs tape_break_error
lda #$10
bit CIA1_ICR // $DC0D
beq !-
#endif
// FALLTROUGH
tape_wait_play_done:
lda #$01
sta CAS1 // set the interlock
#if CONFIG_TAPE_HEAD_ALIGN
rts
tape_prepare_reading:
#endif // CONFIG_TAPE_HEAD_ALIGN
#if CONFIG_MB_MEGA_65
// Display confirmation
ldx #__MSG_KERNAL_OK_SEARCHING
jsr print_kernal_message
#endif
// 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:
#if !CONFIG_TAPE_NO_MOTOR_CONTROL
jsr tape_screen_on_motor_off
#endif
// Print FOUND + file name
ldx #__MSG_KERNAL_FOUND
jsr print_kernal_message
ldy #$05
!:
lda (TAPE1), y
jsr JCHROUT
iny
cpy #$15
bne !-
#if !CONFIG_TAPE_NO_MOTOR_CONTROL
// Header, wait for user decision
jsr tape_header_get_decision
bcs tape_break_error
#endif
// 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 !+
// 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
!:
// Setup MEMUSS (see Mapping the C64, page 36)
jsr lvs_STAL_to_MEMUSS
// Print LOADING and start address
jsr lvs_display_loading_verifying
// FALLTROUGH
#if !CONFIG_TAPE_NO_MOTOR_CONTROL
tape_handle_header_displayed:
// Load the file
jsr tape_screen_off_motor_on
// FALLTROUGH
#endif
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 !+ // end of pattern
lda (FNADDR), y // byte from pattern
!:
cmp #KEY_ASTERISK
beq tape_return_ok
cmp (TAPE1), y
bne tape_return_not_ok
iny
cpy #$10
bne tape_match_loop
clc
rts
#if !CONFIG_TAPE_NO_MOTOR_CONTROL
//
// Get user decision whether to load the file or not
//
tape_header_get_decision:
ldy #$00
!:
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 !-
// FALLTROUGH - timeout
tape_header_wait_space:
clc
rts
tape_header_wait_stop:
sec
rts
#endif
//
// 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
#endif
+102
View File
@@ -0,0 +1,102 @@
// #LAYOUT# STD * #TAKE
// #LAYOUT# M65 KERNAL_1 #TAKE
// #LAYOUT# * * #IGNORE
//
// Tries to detect
//
// Carry clear - normal, Carry set - turbo
//
#if CONFIG_TAPE_AUTODETECT
tape_common_autodetect:
// Set screen color to something neutral, silence the audio
lda #$0B
sta VIC_EXTCOL
lda #$00
#if CONFIG_MB_MEGA_65
sta SID_SIGVOL + __SID_R1_OFFSET
sta SID_SIGVOL + __SID_L1_OFFSET
#else
sta SID_SIGVOL
#endif
// FALLTROUGH
tape_common_autodetect_retry:
// It is not trivial to distinguish between normal and turbo,
// as short pulses of normal (and sync uses only shorts)
// have similar lengths as long pulses of turbo
// Thus, the routine here reads certain amount of pulses
// looking for evidence for either normal or turbo system;
// in case of no evidence found, assume normal
lda #$00 // plus = probably normal, minus = turbo
sta XSAV
ldy #$60 // $60 pulses cover 12 bytes of turbo recording
jsr tape_common_get_pulse // first pulse might be a garbage, ignore it
// FALLTROUGH
tape_common_autodetect_loop:
jsr tape_common_get_pulse // read pulse for detection attempt
// If garbage found, retry detection
cmp #$28
bcc tape_common_autodetect_retry // this is a VERY long pulse
cmp #$E8
bcs tape_common_autodetect_retry // this is a VERY short pulse
// First try to distinguish turbo short signal (reference: $CD)
// from normal signals (reference: $A5 or lower), these values
// give us threshold of ($CD + $A5) / 2 = $B9
cmp #$B9
bcc !+
dec XSAV // above $B9 (so signal is shorter), looks like turbo
!:
// Now try to distinguish turbo signals (reference: $B1 or higher)
// from normal medium/long signals (reference: $7D or below), these values
// give us threshold of ($B1 + $7D) / 2 = $97
cmp #$97
bcs !+
inc XSAV
!:
// The sync for turbo is not too long - if we have enough evidence,
// assume turbo recording already
lda XSAV
cmp #$FD
beq tape_common_autodetect_turbo
// Next iteration
dey
bpl tape_common_autodetect_loop
// Last chance for turbo
lda XSAV
bmi tape_common_autodetect_turbo
// FALLTROUGH
tape_common_autodetect_normal:
clc
rts
tape_common_autodetect_turbo:
sec
rts
#endif
+40
View File
@@ -0,0 +1,40 @@
// #LAYOUT# STD * #TAKE
// #LAYOUT# M65 KERNAL_1 #TAKE
// #LAYOUT# * * #IGNORE
//
// Clear the SID settings - for sound effects during LOAD
//
#if CONFIG_TAPE_TURBO
tape_clean_sid:
lda #$00
ldy #$1C
!:
#if CONFIG_MB_MEGA_65
// It should be safer than cleaning whole $D400-D47C range
sta __SID_BASE + __SID_R1_OFFSET, y
sta __SID_BASE + __SID_R2_OFFSET, y
sta __SID_BASE + __SID_L1_OFFSET, y
sta __SID_BASE + __SID_L2_OFFSET, y
#else
sta __SID_BASE, y
#endif
dey
bpl !-
rts
#endif
@@ -0,0 +1,24 @@
// #LAYOUT# STD * #TAKE
// #LAYOUT# M65 KERNAL_1 #TAKE
// #LAYOUT# * * #IGNORE
//
// Check if VERIFY asked - if yes, terminate loading
//
#if CONFIG_TAPE_NORMAL || CONFIG_TAPE_TURBO
tape_ditch_verify:
lda VERCKK
bne !+
rts
!:
pla
pla
jmp lvs_device_not_found_error
#endif
+33
View File
@@ -0,0 +1,33 @@
// #LAYOUT# STD * #TAKE
// #LAYOUT# M65 KERNAL_1 #TAKE
// #LAYOUT# * * #IGNORE
//
// Tape helper routine - pulse reading
//
// Returns pulse length (with a bias, see comments) in .A
//
#if CONFIG_TAPE_NORMAL || CONFIG_TAPE_TURBO
tape_common_get_pulse:
// Contrary to original ROM implementation we do not use interrupts
// (see http://unusedino.de/ec64/technical/formats/tap.html) - busy wait
// implementation is probably just shorter
lda #$10
!:
bit CIA1_ICR // $DC0D
beq !- // busy loop to detect signal, restart timer afterwards
lda CIA2_TIMBLO // $DD06
ldx #%01010001 // start timer, force latch reload, count timer A underflows
stx CIA2_CRB // $DD0F
cmp __pulse_threshold // default pulse check
rts
#endif
+28
View File
@@ -0,0 +1,28 @@
// #LAYOUT# STD * #TAKE
// #LAYOUT# * KERNAL_0 #TAKE
// #LAYOUT# * * #IGNORE
//
// Handle tape deck motor
//
#if CONFIG_TAPE_NORMAL || CONFIG_TAPE_TURBO
tape_motor_off:
lda CPU_R6510
ora #$20
bne !+ // branch always
tape_motor_on:
lda CPU_R6510
and #($FF - $20)
!:
sta CPU_R6510
rts
#endif
+65
View File
@@ -0,0 +1,65 @@
// #LAYOUT# STD * #TAKE
// #LAYOUT# M65 KERNAL_1 #TAKE
// #LAYOUT# * * #IGNORE
//
// Prepare CIA timers for tape reading
//
//
// Checked under VICE, PAL, average of 256 pulses:
//
// normal - short - timer goes down to $A5
// normal - medium - timer goes down to $7D
// normal - long - timer goes down to $52
//
// turbo - short - timer goes down to $CD
// turbo - long - timer goes down to $B1
//
//
// Measurement subroutine: .A should contain timer value, $C000-$C002 zeroed
//
// clc
// adc $C001
// sta $C001
// bcc !+
// inc $C000
// !:
// inc $C002
// beq !+
// rts
// !:
// lda $C000
// .break // .A contains our average
// rts
//
#if CONFIG_TAPE_NORMAL || CONFIG_TAPE_TURBO
tape_common_prepare_cia:
// Setup CIA #2 timers
ldx #$03 // set timer A to 4 ticks
// FALLTROUGH
tape_common_prepare_cia_by_x: // entry point for head align tool
stx CIA2_TIMALO // $DD04
ldx #$00
stx CIA2_TIMAHI // $DD05
stx CIA2_TIMBHI // $DD07
dex // puts $FF - for running timer B as long as possible
stx CIA2_TIMBLO // $DD06
// Let timer A run continuously
ldx #%00010001 // start timer, force latch reload
stx CIA2_CRA // $DD0E
rts
#endif
+72
View File
@@ -0,0 +1,72 @@
// #LAYOUT# STD * #TAKE
// #LAYOUT# M65 KERNAL_1 #TAKE
// #LAYOUT# * * #IGNORE
//
// Handle screen (visible/blanked) + tape deck motor (on/off),
// store/restore screen color
//
#if CONFIG_TAPE_NORMAL || CONFIG_TAPE_TURBO
// XXX for Mega65 do not disable screen, just disable badline emulation
tape_screen_on_motor_off:
jsr tape_motor_off
lda COLSTORE
sta VIC_EXTCOL
#if !CONFIG_MB_MEGA_65
jmp screen_on
#else
// On Mega65 just reenable badline emulation
lda #$FF
sta M65_BADL_SLI
sta VIC_KEY
rts
#endif
tape_screen_off_motor_on:
// We do not want interrupts and CHROUT reenables them
sei
// Clear keyboard buffer
lda #$00
sta NDX
// Set screen color
lda VIC_EXTCOL
sta COLSTORE
#if !CONFIG_MB_MEGA_65
jsr screen_off
#else
// On Mega65 we do not have to turn the screen off;
// it is enough to disable badline emulation
jsr mega65_unhide
lda #$00
sta M65_BADL_SLI
#endif
jmp tape_motor_on
#endif
+267
View File
@@ -0,0 +1,267 @@
// #LAYOUT# STD * #TAKE
// #LAYOUT# M65 KERNAL_1 #TAKE
// #LAYOUT# * * #IGNORE
//
// Tape head alignemnt tool
//
#if CONFIG_TAPE_HEAD_ALIGN
.label __ha_start = 12 // starting row of the chart
.label __ha_rows = 11 // number of rows for scrolling
// Helper tables
.label __ha_offsets = $1000;
.label __ha_masks = $1100;
// Generated code location
.label __ha_scroll = $1300;
// Flag for GFX effects - reuse BASIC numeric work area on zero page
.label __ha_gfxflag = TEMPF2; // 1 byte
tape_head_align:
// Make sure user really wants to launch the tool
jsr tape_ask_play
// Disable interrupts, set proper I/O values
jsr CLALL
sei
jsr IOINIT
// jsr CINT
jsr nmi_lock
// Prepare CIA timers
ldx #$02 // set timer A to 3 ticks
jsr tape_common_prepare_cia_by_x
ldx #$FF // timer to control scroll speed
stx CIA1_TIMBLO // $DC06
stx CIA1_TIMBHI // $DC07
jsr tape_motor_on
// Clear color data ($0800)
ldy #$00
!:
lda #(CONFIG_COLOR_TXT * $10 + CONFIG_COLOR_BG)
sta $0800, y
sta $0900, y
sta $0A00, y
sta $0B00, y
iny
bne !-
// Clear bitmap data ($2000)
lda #$20
sta SAL+1
tya // put 0 to .A
sta SAL+0
!:
sta (SAL), y
iny
bne !-
inc SAL+1
ldx SAL+1
cpx #$40
bne !-
// Print help message
jsr tape_head_align_print_help
// Make sure the row where the chart is being created is not visible
lda #(CONFIG_COLOR_TXT * $10 + CONFIG_COLOR_TXT)
ldy #$24
!:
sta $0800 + __ha_start * 40 + 1, y
sta $0800 + __ha_start * 40 + 1 + (__ha_rows + 1) * 40, y
dey
bne !-
// Set graphics mode
lda #$28 // graphics start at $2000, color at $0800
sta VIC_YMCSB
lda #$3B // set bit 5 to enable graphic mode
sta VIC_SCROLY
// Prepare lookup tables - to speed drawing, we are going to use two of them:
// - byte offset table will tell us which byte in memory to alter
// - mask will allow us to quickly put the pixel
ldx #$00 // loop index
ldy #$00 // temporary value for mask calculation
!:
// Byte offset is simple, just zero the 3 least significant bits
txa
and #%11111000
sta __ha_offsets, x
// Mask changes with each iteration, use our temporary value in .Y
tya
clc
ror
bne !+
lda #%10000000
!:
tay
sta __ha_masks, x
// Next iteration
inx
bne !--
// Initialize flag for additional GFX effects
stx __ha_gfxflag // .X is 0 at this moment
// Generate helper code for screen scrolling
jsr tape_head_align_gen_code
// Provide new IRQ routine address
lda #<tape_head_align_irq
sta CINV+0
lda #>tape_head_align_irq
sta CINV+1
// Setup raster interrupt routine - see https://www.c64-wiki.com/wiki/Raster_interrupt
lda #%01111111 // prevent CIA from generating interrupts
sta CIA1_ICR // $DC0D
and VIC_SCROLY // clear the highest bit of RASTER
sta VIC_SCROLY // $D011
lda #$FB // we want no badlines during the interrupt, this raster is 100% safe
sta VIC_RASTER
lda #%00000001 // enable raster interrupts
sta VIC_IRQMSK // $D01A
cli
tape_head_align_loop_1:
// Check for STOP key
jsr udtim_keyboard
jsr STOP
bcs tape_head_align_quit
// Launch the timer
ldx #%00011001 // start timer, one-shot force latch reload, count system ticks
stx CIA1_CRB // $DC0F
// Scroll the whole chart one line down
ldx #$00
!:
jsr __ha_scroll // scroll one column down, using fast generated code
txa
clc
adc #$08
tax
bne !-
// Draw decorations
lda __ha_gfxflag
inc __ha_gfxflag
clc
adc #$08
and #%00001100
bne !+
ldy #%11110001
lda #%10001111
bne !++
!:
ldy #%00000001
lda #%10000000
!:
ora __ha_chart + 7 + 8 * 0
sta __ha_chart + 7 + 8 * 0
tya
ora __ha_chart + 7 + 8 * 31
sta __ha_chart + 7 + 8 * 31
// Draw helper lines
lda __ha_gfxflag
and #%00000010
beq !+
// For 'normal'
lda #%00000001
ora __ha_chart + 7 + 8 * 6
sta __ha_chart + 7 + 8 * 6
lda #%00000001
ora __ha_chart + 7 + 8 * 13
sta __ha_chart + 7 + 8 * 13
// For 'turbo'
lda #%00010000
ora __ha_chart + 7 + 8 * 21
sta __ha_chart + 7 + 8 * 21
!:
// FALLTROUGH
tape_head_align_loop_2:
lda CIA1_TIMBLO
and CIA1_TIMBHI
eor #$FF
bne tape_head_align_loop_2
beq tape_head_align_loop_1
tape_head_align_quit:
// It makes no sense to return to system, as we already destroyed
// a lot of memory; fust clear initial BASIC text area to prevent
// data recovery attempts, and reset
ldx #$00
txa
!:
sta $0800, x
inx
bne !-
jmp hw_entry_reset
#endif // CONFIG_TAPE_HEAD_ALIGN
+138
View File
@@ -0,0 +1,138 @@
// #LAYOUT# STD * #TAKE
// #LAYOUT# M65 KERNAL_1 #TAKE
// #LAYOUT# * * #IGNORE
//
// Tape head alignemnt tool - helper code generator
//
#if CONFIG_TAPE_HEAD_ALIGN
// Helper variables - reuse BASIC numeric work area on zero page
.label __ha_lda_addr = TEMPF1 + 0; // 2 bytes, for code generator
.label __ha_sta_addr = TEMPF1 + 2; // 2 bytes, for code generator
tape_head_align_gen_code:
// Setup generated code start address
lda #<__ha_scroll
sta SAL+0
lda #>__ha_scroll
sta SAL+1
// Setup initial source and destination addresses
ldy #<(__ha_chart + __ha_rows * (8 * 40) + 6)
sty __ha_lda_addr + 0
iny
sty __ha_sta_addr + 0
ldy #>(__ha_chart + __ha_rows * (8 * 40) + 6)
sty __ha_lda_addr + 1
sty __ha_sta_addr + 1
// Emit code to move 7 rows of one 8x8 cell
!:
ldx #$07
!:
jsr tape_head_align_gen_code_emit_pair
dec __ha_lda_addr + 0
dec __ha_sta_addr + 0
dex
bne !-
// Emit code to fetch a top row from the cell above
inc __ha_lda_addr + 0
sec
lda __ha_lda_addr + 0
sbc #<(8 * 40 - 7)
sta __ha_lda_addr + 0
lda __ha_lda_addr + 1
sbc #>(8 * 40 - 7)
sta __ha_lda_addr + 1
jsr tape_head_align_gen_code_emit_pair
// Prepare addresses for the next iteration
lda __ha_lda_addr + 0
sta __ha_sta_addr + 0
lda __ha_lda_addr + 1
sta __ha_sta_addr + 1
dec __ha_lda_addr + 0
// Now, new iteration - if needed
lda __ha_sta_addr + 0
cmp #<(__ha_chart + 7)
bne !--
lda __ha_sta_addr + 1
cmp #>(__ha_chart + 7)
bne !--
// Last pair to be generated starts from LDA #$00
lda #$A9
jsr tape_head_align_gen_code_emit_byte
lda #$00
jsr tape_head_align_gen_code_emit_byte
jsr tape_head_align_gen_code_emit_sta
// Emit RTS and quit
lda #$60
jmp tape_head_align_gen_code_emit_byte
tape_head_align_gen_code_emit_pair:
lda #$BD // LDA absolute, x
jsr tape_head_align_gen_code_emit_byte
lda __ha_lda_addr + 0
jsr tape_head_align_gen_code_emit_byte
lda __ha_lda_addr + 1
jsr tape_head_align_gen_code_emit_byte
// FALLTROUGH
tape_head_align_gen_code_emit_sta:
lda #$9D // STA absolute, x
jsr tape_head_align_gen_code_emit_byte
lda __ha_sta_addr + 0
jsr tape_head_align_gen_code_emit_byte
lda __ha_sta_addr + 1
// FALLTROUGH
tape_head_align_gen_code_emit_byte:
ldy #$00
sta (SAL), y
#if HAS_OPCODES_65CE02
inw SAL
#else
inc SAL+0
bne !+
inc SAL+1
!:
#endif
rts
#endif // CONFIG_TAPE_HEAD_ALIGN
@@ -0,0 +1,45 @@
// #LAYOUT# STD * #TAKE
// #LAYOUT# M65 KERNAL_1 #TAKE
// #LAYOUT# * * #IGNORE
//
// Tape head alignemnt tool - reading pulses from tape
//
#if CONFIG_TAPE_HEAD_ALIGN
tape_head_align_get_pulse:
// This routine differs from the one used to read pulse during tape reading:
// - it is not as precise
// - it terminates when timer reaches $FF
// - it returns value in .Y
lda #$10
!:
// Loop to detect signal
ldy CIA2_TIMBLO // $DD06
bit CIA1_ICR // $DC0D
bne !+
cpy #$FF
bne !-
!:
// FALLTROUGH
tape_head_align_get_pulse_start_timer:
// Start timer again, force latch reload, count timer A underflows
lda #%01010001
sta CIA2_CRB // $DD0F
// Return with time elapsed in .Y
rts
#endif // CONFIG_TAPE_HEAD_ALIGN
+147
View File
@@ -0,0 +1,147 @@
// #LAYOUT# STD * #TAKE
// #LAYOUT# M65 KERNAL_1 #TAKE
// #LAYOUT# * * #IGNORE
//
// Tape head alignemnt tool - prints out a help message on screen
//
#if CONFIG_TAPE_HEAD_ALIGN
// Helper variable - reuse BASIC numeric work area on zero page
.label __ha_storage = TEMPF1; // 1 byte
tape_head_align_print_help:
// Make screen font visible
lda CPU_R6510
pha
and #%11111011
sta CPU_R6510
// Print help message
ldy #$00
// Retrieve address
!:
lda tape_head_align_help_text, y
iny
cmp #$FF
beq tape_head_align_print_end
sta EAL+0
lda tape_head_align_help_text, y
iny
sta EAL+1
!:
// Retrieve and print character
lda tape_head_align_help_text, y
iny
cmp #$FF
beq !--
sty __ha_storage
jsr tape_head_align_print_char
ldy __ha_storage
bne !- // branch alwats
tape_head_align_print_end:
// Restore normal memory configuration and quit
pla
sta CPU_R6510
rts
tape_head_align_print_string:
tape_head_align_print_char:
// Calculate start address of character in .A
sta SAL+0
lda #$00
sta SAL+1
asl SAL+0
rol SAL+1
asl SAL+0
rol SAL+1
asl SAL+0
rol SAL+1
clc
lda SAL+1
adc #$D0
sta SAL+1
// Print out the character
ldy #$07
!:
lda (SAL), y
sta (EAL), y
dey
bpl !-
// Prepare EAL for the next character
lda EAL+0
clc
adc #$08
sta EAL+0
bne !+
inc EAL+1
!:
rts
//
// Strings to print
//
.encoding "screencode_upper"
tape_head_align_help_text:
// Each string consists of:
// - destination (start byte) address
// - text in screencodes
// - $FF to mark end
.word $2000 + (40 * 8) * 0 + 8 * 1
.text "COMPUTER HAS TO TELL THE SIGNALS APART"
.byte $FF
.word $2000 + (40 * 8) * 3 + 8 * 6
.text "ALIGN HEAD FOR MINIMUM NOISE"
.byte $FF
.word $2000 + (40 * 8) * 6 + 8 * 2
.text "IF THE DECK HAS A PITCH (TAPE SPEED)"
.byte $FF
.word $2000 + (40 * 8) * 7 + 8 * 1
.text "CONTROL, TWEAK IT SO THAT DOTTED LINES"
.byte $FF
.word $2000 + (40 * 8) * 8 + 8 * 5
.text "ARE HALF A WAY BETWEEN SIGNALS"
.byte $FF
.byte $FF // end of strings
#endif
+75
View File
@@ -0,0 +1,75 @@
// #LAYOUT# STD * #TAKE
// #LAYOUT# M65 KERNAL_1 #TAKE
// #LAYOUT# * * #IGNORE
//
// Tape head alignemnt tool - interrupt routine
//
#if CONFIG_TAPE_HEAD_ALIGN
tape_head_align_irq:
// Acknowledge interrupt
asl VIC_IRQ
// Ignore 2 first pulses, they can be garbage
jsr tape_head_align_get_pulse
jsr tape_head_align_get_pulse
// Now, we can retrieve pulses for the chart
ldx #$00
// FALLTROUGH
tape_head_align_irq_loop:
jsr tape_head_align_get_pulse
// If we approached badlines again - we cannot use this measurement anymore
lda VIC_SCROLY
bmi !+ // branch if lower border
lda VIC_RASTER
cmp #$33 // first line where badline can occur
bcs tape_head_align_irq_end
!:
// Draw pulse on the screen
cpy #$FF
beq !+
// Center the chart horizontaly, with some margin from top
.label __ha_chart = $2000 + 8 * (40 * __ha_start + 4)
phx_trash_a
lda __ha_offsets, y
tax
lda __ha_masks, y
ora __ha_chart + 7, x
sta __ha_chart + 7, x
plx_trash_a
!:
// Next iteration
inx
cpx #$40
bne tape_head_align_irq_loop
// FALLTROUGH
tape_head_align_irq_end:
jmp return_from_interrupt
#endif // CONFIG_TAPE_HEAD_ALIGN
+126
View File
@@ -0,0 +1,126 @@
// #LAYOUT# STD * #TAKE
// #LAYOUT# M65 KERNAL_1 #TAKE
// #LAYOUT# * * #IGNORE
//
// Tape (normal) helper routine - reading speed calibration
//
// Needs pulse length in .A
//
#if CONFIG_TAPE_NORMAL
tape_normal_calibrate_during_pilot: // reecalibration during the pilot
sta __normal_time_S
// We do not have any recent medium pulse measurement,
// probably the only solution is to estimate it
lda #$FF
sec
sbc __normal_time_S
// We now have a difference from the starting point ($FF)
clc
ror
sta __normal_time_M // this is temporary only!
// We now have half the difference, substract it from
// short pulse measurement result
lda __normal_time_S
sec
sbc __normal_time_M
// Add a small correction to gain $7D if starting from $A5. Dirty, ugly,
// and imprecise hack - but in real life should be good enough
clc
adc #$05
sta __normal_time_M // estimated medium pulse length
jmp tape_normal_calibrate_common
tape_normal_calibrate_after_S: // recalibration after short pulse
sta __normal_time_S
rts
skip_2_bytes_trash_nvz
// FALLTROUGH
tape_normal_calibrate_after_M: // recalibration after medium pulse
sta __normal_time_M
// FALLTROUGH
tape_normal_calibrate_common:
// Now compare results with current threshold
lda __normal_time_S
sec
sbc __pulse_threshold
clc
adc __normal_time_M
cmp __pulse_threshold
beq tape_normal_calibrate_done // branch if no recalibration needed
// Correct the thresholds (default is $91 for the S/M one)
bcs tape_normal_calibrate_threshold_inc // branch if .A >= memory
// FALLTROUGH
tape_normal_calibrate_threshold_dec:
lda __pulse_threshold
cmp #($91-10)
bcc tape_normal_calibrate_done // do not decrement thresholds too far
sec
sbc #$02
sta __pulse_threshold
lda __pulse_threshold_ML
sec
sbc #$03
sta __pulse_threshold_ML
bne tape_normal_calibrate_done // branch always
tape_normal_calibrate_threshold_inc:
lda __pulse_threshold
cmp #($91+11)
bcs tape_normal_calibrate_done // do not increment thresholds too far
clc
adc #$02
sta __pulse_threshold
lda __pulse_threshold_ML
clc
adc #$03
sta __pulse_threshold_ML
// FALLTROUGH
tape_normal_calibrate_done:
rts
#endif
+68
View File
@@ -0,0 +1,68 @@
// #LAYOUT# STD * #TAKE
// #LAYOUT# M65 KERNAL_1 #TAKE
// #LAYOUT# * * #IGNORE
//
// Tape (normal) helper routine - bit reading
//
// Returns bit in Zero flag, Carry set means error, on 0 bit .A is 0 too
//
#if CONFIG_TAPE_NORMAL
tape_normal_get_bit:
// Fetch the first pulse
jsr tape_common_get_pulse
bcc tape_normal_get_bit_1
// First impulse was short, second should be medium
jsr tape_normal_calibrate_after_S
jsr tape_common_get_pulse
bcs tape_normal_get_bit_error
jsr tape_normal_calibrate_after_M
// We have a bit '0'
lda #$00
// FALLTROUGH
tape_normal_get_bit_done:
sta VIC_EXTCOL
clc
rts
tape_normal_get_bit_1:
// First impulse was medium, second should be short
jsr tape_normal_calibrate_after_M
jsr tape_common_get_pulse
bcc tape_normal_get_bit_error
jsr tape_normal_calibrate_after_S
// We have a bit '1'
clc
lda #$06
bne tape_normal_get_bit_done // branch always
tape_normal_get_bit_error:
sec
rts
#endif // CONFIG_TAPE_NORMAL
+73
View File
@@ -0,0 +1,73 @@
// #LAYOUT# STD * #TAKE
// #LAYOUT# M65 KERNAL_1 #TAKE
// #LAYOUT# * * #IGNORE
//
// Tape (normal) helper routine - byte reading
//
// Returns byte in .A (also sotred in INBIT), Carry flag set = error
//
#if CONFIG_TAPE_NORMAL
tape_normal_get_byte:
// Init parity bit and canary bit
lda #$01
sta PRTY
lda #%01111111 // canary bit is 0
sta INBIT
// Now fetch individual bits
tape_normal_get_byte_loop:
jsr tape_normal_get_bit
bcs tape_normal_get_byte_error
beq !+
// Handle parity bit
lda #$01
eor PRTY
sta PRTY
sec
!: // moved bit state from Zero to Carry flag
ror INBIT // put the bit in
bcs tape_normal_get_byte_loop // loop if no canary bit reached
// Byte retrieved (on stack), now we need to validate the parity
jsr tape_normal_get_bit
bcs tape_normal_get_byte_error
beq !+
lda #$01
!:
eor PRTY
bne tape_normal_get_byte_error
// Checksum validated succesfully
ldx #$0B
// Carry already clear
// FALLTROUGH
tape_normal_get_byte_done:
stx VIC_EXTCOL
lda INBIT
rts
tape_normal_get_byte_error:
ldx #$09
sec // make sure Carry is set to indicate error
bcs tape_normal_get_byte_done
#endif
+121
View File
@@ -0,0 +1,121 @@
// #LAYOUT# STD * #TAKE
// #LAYOUT# M65 KERNAL_1 #TAKE
// #LAYOUT# * * #IGNORE
//
// Tape (normal) helper routine - data block (primary) reading
//
// Stores data starting from MEMUSS, Carry set means error, on 0 bit .A is 0 too
// .Y not equal to 0 - returns error if data block is longer (length includes checksum)
// XXX improve error handling - do not ignore second copy, handle damaged sync part
#if CONFIG_TAPE_NORMAL
tape_normal_get_data_1:
// Initialize checksum (RIPRTY, see http://sta.c64.org/cbm64mem.html)
// and pointers for error log and correction mechanism
lda #$00
sta RIPRTY
#if !CONFIG_TAPE_NO_ERROR_CORRECTION
sta PTR2
sta PTR1
#endif
// FALLTROUGH
tape_normal_get_data_1_block:
//
// Read the 1st copy of the block
//
// Read sync of the block
ldy #$89
jsr tape_normal_sync
bcs tape_normal_get_data_1_fail
jsr tape_normal_get_marker
tape_normal_get_data_1_loop:
jsr tape_normal_get_byte
bcc tape_normal_get_data_1_loop_byte_OK
#if CONFIG_TAPE_NO_ERROR_CORRECTION
bcs tape_normal_get_data_1_fail
#else
// Problem reading a byte, try to add it to the error log
tsx
cpx #$20 // just to be on a safe side
bcc tape_normal_get_data_1_fail // branch if no more space in error log
ldx PTR1
lda MEMUSS+0
sta STACK, x
inx
lda MEMUSS+1
sta STACK, x
inx
stx PTR1
// Addres added to error log, check if this was a checksum
jsr tape_normal_get_marker
bcc tape_normal_get_data_1_loop_advance
bcs tape_normal_get_data_1_success
#endif
tape_normal_get_data_1_loop_byte_OK:
jsr tape_normal_get_marker
bcc !+
// End of the block
jsr tape_normal_update_checksum
jmp tape_normal_get_data_1_success
!:
// Store byte, calculate checksum
lda INBIT
ldy #$00
#if ROM_LAYOUT_M65
jsr tape_normal_byte_store
#else
sta (MEMUSS), y
#endif
jsr tape_normal_update_checksum
// FALLTROUGH
tape_normal_get_data_1_loop_advance:
// Advance pointer
#if !HAS_OPCODES_65CE02
jsr lvs_advance_MEMUSS
#else
inw MEMUSS+0
#endif
jmp tape_normal_get_data_1_loop
tape_normal_get_data_1_success:
clc
rts
tape_normal_get_data_1_fail:
sec
rts
#endif
+124
View File
@@ -0,0 +1,124 @@
// #LAYOUT# STD * #TAKE
// #LAYOUT# M65 KERNAL_1 #TAKE
// #LAYOUT# * * #IGNORE
//
// Tape (normal) helper routine - data block (backup) reading
//
#if CONFIG_TAPE_NORMAL && !CONFIG_TAPE_NO_ERROR_CORRECTION
tape_normal_get_data_2:
// First check if there is a need to read anything
lda PTR1
beq tape_normal_get_data_2_log_checksum
// Read sync of the block
ldy #$09
jsr tape_normal_sync
bcs tape_normal_get_data_2_done // Carry already set, will indicate error
jsr tape_normal_get_marker
// FALLTROUGH
tape_normal_get_data_2_loop:
// Check if there are missing bytes to read
lda PTR1
cmp PTR2
beq tape_normal_get_data_2_log_checksum // branch if no more errors to correct
// Read missing bytes
jsr tape_normal_get_byte
bcc tape_normal_get_data_2_loop_byte_OK
// Problem reading a byte - just skip it
bcs tape_normal_get_data_2_loop_advance
tape_normal_get_data_2_loop_byte_OK:
jsr load_cmp_log_MEMUSS
beq tape_normal_get_data_2_loop_from_log // branch if byte from the log
jsr tape_normal_get_marker
bcs tape_normal_get_data_2_log_checksum // branch if end of blocks
bcc tape_normal_get_data_2_loop_advance
tape_normal_get_data_2_loop_from_log:
// This is a byte from the log
jsr tape_normal_get_marker
bcs !+
lda INBIT
ldy #$00
#if ROM_LAYOUT_M65
jsr tape_normal_byte_store
#else
sta (MEMUSS), y
#endif
!:
jsr tape_normal_update_checksum
// FALLTROUGH
tape_normal_get_data_2_loop_advance:
// Advance pointer
#if !HAS_OPCODES_65CE02
jsr lvs_advance_MEMUSS
#else
inw MEMUSS+0
#endif
jmp tape_normal_get_data_2_loop
tape_normal_get_data_2_log_checksum:
lda PTR1
cmp PTR2
bne tape_normal_get_data_2_done // Carry already set
// Validate checksum
lda RIPRTY
cmp #$01 // sets Carry if checksum verification fails
// FALLTROUGH
tape_normal_get_data_2_done:
rts
load_cmp_log_MEMUSS:
ldx PTR2
lda STACK+0, x
cmp MEMUSS+0
bne !+
lda STACK+1, x
cmp MEMUSS+1
bne !+
// MEMUSS matches address from the log
inc PTR2
inc PTR2
lda #$00 // to set Zero flag
!:
rts
#endif
+53
View File
@@ -0,0 +1,53 @@
// #LAYOUT# STD * #TAKE
// #LAYOUT# M65 KERNAL_1 #TAKE
// #LAYOUT# * * #IGNORE
//
// Tape (normal) helper routine - marker reading
//
// Reeturns marker type in Carry flag, set = end of data (normal marker) or failure (marker while sync)
//
#if CONFIG_TAPE_NORMAL
// (L,M) - end of byte, (L,S) - end of data
tape_normal_get_marker:
jsr tape_common_get_pulse
cmp __pulse_threshold_ML
bcs tape_normal_get_marker // too short for a long pulse
// FALLTROUGH
tape_normal_get_marker_type:
jmp tape_common_get_pulse
!: // Not an entry point!!!
// XXX check for short pulses of turbo here
jsr tape_normal_calibrate_during_pilot // while sync use short pulses for calibration
// FALLTROUGH
tape_normal_get_marker_while_sync:
// (L,M) - end of byte, (L,S) - end of data
jsr tape_common_get_pulse
bcs !- // branch if short pulse
cmp __pulse_threshold_ML
bcs tape_normal_get_marker_while_sync // too short for a long pulse
bcc tape_normal_get_marker_type // branch always
#endif
+93
View File
@@ -0,0 +1,93 @@
// #LAYOUT# STD * #TAKE
// #LAYOUT# M65 KERNAL_1 #TAKE
// #LAYOUT# * * #IGNORE
//
// Tape (turbo) helper routine - handling the pilot
//
// Injest the pilot - series of short pulses. According to http://sidpreservation.6581.org/tape-format/
// it consist of the following number of pulses:
// - $6A00 for header
// - $1A00 for data and seq block header
// - $4F for repeated header/data
#if CONFIG_TAPE_NORMAL
tape_normal_get_pilot_header: // entry point, reset calibration, require 128x $40 pulses
// Reading the pilot header is the first action performed,
// thus start by setting default thresholds
lda #$91
sta __pulse_threshold
lda #$67
sta __pulse_threshold_ML
lda #$80
skip_2_bytes_trash_nvz
// FALLTROUGH
tape_normal_get_pilot_data: // entry point, require 4x $40 pulses
lda #$04
skip_2_bytes_trash_nvz
// FALLTROUGH
tape_normal_get_pilot_short: // entry point, require 1x $40 pulses
lda #$01
// FALLTROUGH
tape_normal_get_pilot_common:
sta FSBLK
lda #$0B
sta VIC_EXTCOL
// FALLTROUGH
tape_normal_get_pilot_common_restart:
lda FSBLK
sta ROPRTY
// FALLTROUGH
tape_normal_get_pilot_common_loop_outer:
ldy #$40
// FALLTROUGH
tape_normal_get_pilot_common_loop_inner:
jsr tape_common_get_pulse
bcc tape_normal_get_pilot_common_restart // not a pilot - try again
#if CONFIG_TAPE_AUTODETECT
// Try to distinguish turbo by cheecking for short signals
cmp #$B9 // see comment in tape_common_autodetect.s
bcs !+
#endif
jsr tape_normal_calibrate_during_pilot
dey
bne tape_normal_get_pilot_common_loop_inner
dec ROPRTY
bne tape_normal_get_pilot_common_loop_outer
clc
!:
rts
#endif
+45
View File
@@ -0,0 +1,45 @@
// #LAYOUT# STD * #TAKE
// #LAYOUT# M65 KERNAL_1 #TAKE
// #LAYOUT# * * #IGNORE
//
// Tape (turbo) helper routine - synchronization handling
//
// .Y should contain start value (either $89 or $09)
// Carry set = failed
#if CONFIG_TAPE_NORMAL
tape_normal_sync:
lda #$06
sta VIC_EXTCOL
// Injest bytes of decreasing values
jsr tape_normal_get_marker_while_sync
bcs tape_normal_sync_fail // branch if end of data marker
jsr tape_normal_get_byte
bcs tape_normal_sync_fail
cpy INBIT // INBIT contains same value as .A
bne tape_normal_sync_fail
dey
and #%01111110
bne tape_normal_sync // branch if not $80 and not $00
clc
rts
tape_normal_sync_fail:
sec
rts
#endif
@@ -0,0 +1,22 @@
// #LAYOUT# STD * #TAKE
// #LAYOUT# M65 KERNAL_1 #TAKE
// #LAYOUT# * * #IGNORE
//
// Tape (normal) helper routine - checksum calculation
//
#if CONFIG_TAPE_NORMAL
tape_normal_update_checksum:
lda INBIT
eor RIPRTY
sta RIPRTY
rts
#endif
+57
View File
@@ -0,0 +1,57 @@
// #LAYOUT# STD * #TAKE
// #LAYOUT# M65 KERNAL_1 #TAKE
// #LAYOUT# * * #IGNORE
//
// Tape (turbo) helper routine - storing byte uder I/O
//
// Has to preserve .A and .Y
//
// This helper routine is meant to be copied to the start of CPU stack.
// Original ROM tape loading routines uses this area to store information
// about bytes that did not read properly for the first time
// (see Mapping the C64, page 47); this mechanism is useless for turbo tape,
// but it means we can safely use this area for our purposes
#if CONFIG_TAPE_TURBO
#if ROM_LAYOUT_M65
.label __tape_turbo_bytestore_defmap = __tape_turbo_bytestore + 10
#else
.label __tape_turbo_bytestore_defmap = __tape_turbo_bytestore + 7
#endif
.label __tape_turbo_bytestore_size = __tape_turbo_bytestore_source_end - tape_turbo_bytestore_source
tape_turbo_bytestore_source:
#if ROM_LAYOUT_M65
jsr KERNAL_0.map_NORMAL
#endif
// Set all memory as RAM, tape motor ON
ldx #$00
stx CPU_R6510
// Store byte in memory
sta (MEMUSS), y
// Restore default memory layout
ldx #$00 // value will be determined later, offset from start: 7 bytes
stx CPU_R6510
#if ROM_LAYOUT_M65
// Restore default map and quit
jmp KERNAL_0.map_KERNAL_1
#else
// Go back
rts
#endif
__tape_turbo_bytestore_source_end:
#endif // CONFIG_TAPE_TURBO
+53
View File
@@ -0,0 +1,53 @@
// #LAYOUT# STD * #TAKE
// #LAYOUT# M65 KERNAL_1 #TAKE
// #LAYOUT# * * #IGNORE
//
// Tape (turbo) helper routine - bit reading
//
// Based on routine by enthusi/Onslaught, found here:
// - https://codebase64.pokefinder.org/doku.php?id=base:turbotape_loader_source
#if CONFIG_TAPE_TURBO
tape_turbo_get_bit:
jsr tape_common_get_pulse
bcs !+
clc
ror
sta __turbo_half_S // store half of the last measurement result for short pulse
lda #$01
#if CONFIG_MB_MEGA_65
sta SID_SIGVOL + __SID_R1_OFFSET
sta SID_SIGVOL + __SID_L1_OFFSET
#else
sta SID_SIGVOL
#endif
lda #$06
sta VIC_EXTCOL
sec
rts
!:
clc
ror
sta __turbo_half_L // store half of the last measurement result for long pulse
lda #$00
#if CONFIG_MB_MEGA_65
sta SID_SIGVOL + __SID_R1_OFFSET
sta SID_SIGVOL + __SID_L1_OFFSET
#else
sta SID_SIGVOL
#endif
sta VIC_EXTCOL
clc
rts
#endif // CONFIG_TAPE_TURBO
+60
View File
@@ -0,0 +1,60 @@
// #LAYOUT# STD * #TAKE
// #LAYOUT# M65 KERNAL_1 #TAKE
// #LAYOUT# * * #IGNORE
//
// Tape (turbo) helper routine - byte reading
//
// Returns byte in .A
//
// Based on routine by enthusi/Onslaught, found here:
// - https://codebase64.pokefinder.org/doku.php?id=base:turbotape_loader_source
#if CONFIG_TAPE_TURBO
tape_turbo_get_byte:
phx_trash_a
lda #$01
sta INBIT // init the to-be-read byte with 1 (canary bit to mark loop end)
!:
jsr tape_turbo_get_bit
rol INBIT
bcc !- // is the initial 1 shifted into carry already?
plx_trash_a
// Compensate for tape speed variations
lda __turbo_half_S // half of the last value for bit '0'
clc
adc __turbo_half_L // half of the last value for bit '1'
sec
sbc __pulse_threshold // now we have a diff between current threshold and calculated one
beq tape_turbo_get_byte_done // branch if threshold correction not needed
bpl !+
lda __pulse_threshold
cmp #($BF - 10)
beq tape_turbo_get_byte_done // do not decrease threshold too far no matter what
dec __pulse_threshold
bne tape_turbo_get_byte_done // branch always
!:
lda __pulse_threshold
cmp #($BF + 10)
beq tape_turbo_get_byte_done // do not increase threshold too far no matter what
inc __pulse_threshold
tape_turbo_get_byte_done:
lda INBIT
rts
#endif // CONFIG_TAPE_TURBO
+77
View File
@@ -0,0 +1,77 @@
// #LAYOUT# STD * #TAKE
// #LAYOUT# M65 KERNAL_1 #TAKE
// #LAYOUT# * * #IGNORE
//
// Tape (turbo) helper routine - synchronization handling
//
// Based on routine by enthusi/Onslaught, found here:
// - https://codebase64.pokefinder.org/doku.php?id=base:turbotape_loader_source
#if CONFIG_TAPE_TURBO
tape_turbo_sync_header:
// Initial pulse threshold
lda #$BF // measured 128 bits '0' and 128 bits '1' under VICE, calculated average
sta __pulse_threshold
// Synchronize with start of sync sequence
jsr tape_turbo_sync_first
#if CONFIG_TAPE_AUTODETECT
bcs tape_turbo_sync_done
#endif
// Perform synchronization, double loop, total $C0 * $04 iterations
ldx #$C0
!:
ldy #$04
!:
stx XSAV
jsr tape_turbo_get_byte
cmp #$02
bne tape_turbo_sync_header // branch if failure
dey
bne !-
ldx XSAV
dex
bne !--
// FALLTROUGH
tape_turbo_sync_payload:
jsr tape_turbo_sync_first
#if CONFIG_TAPE_AUTODETECT
bcs tape_turbo_sync_done // this shopuld not happen
#endif
!:
ldx #$09 // 9, 8, ...
!:
jsr tape_turbo_get_byte
cmp #$02
beq !-
ldy #$00
!:
cpx INBIT
bne tape_turbo_sync_payload
jsr tape_turbo_get_byte
dex
bne !-
#if CONFIG_TAPE_AUTODETECT
clc
#endif
// FALLTROUGH
tape_turbo_sync_done:
rts
#endif // CONFIG_TAPE_TURBO
+53
View File
@@ -0,0 +1,53 @@
// #LAYOUT# STD * #TAKE
// #LAYOUT# M65 KERNAL_1 #TAKE
// #LAYOUT# * * #IGNORE
//
// Tape (turbo) helper routine - syynchronize to first byte with value $02
//
#if CONFIG_TAPE_TURBO
tape_turbo_sync_first:
#if CONFIG_TAPE_AUTODETECT
ldy #$00
!:
jsr tape_turbo_get_bit
rol INBIT
lda INBIT
cmp #$FF
bne !+
iny
bpl !-
bmi tape_turbo_sync_first_fail // suspiciously many $FF bytes, probably not a turbo tape
!:
cmp #$02
bne tape_turbo_sync_first
clc
rts
tape_turbo_sync_first_fail:
sec
rts
#else // no CONFIG_TAPE_AUTODETECT
jsr tape_turbo_get_bit
rol INBIT
lda INBIT
cmp #$02
bne tape_turbo_sync_first
rts
#endif
#endif