From 982b287e92536f0f333ad785005d8ecfb300699d Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Fri, 1 Nov 2019 13:10:39 +0100 Subject: [PATCH] various LOAD improvements --- STATUS.md | 1 + c64/aliases/,aliases_ram_lowmem.s | 6 +- c64/kernal/assets/kernal_messages.s | 6 + c64/kernal/iec/iec_wait1ms.s | 12 +- c64/kernal/iec/load_iec.s | 4 +- c64/kernal/iostack/lvs_helpers.s | 16 +-- c64/kernal/tape/load_tape_turbo.s | 70 ++++++----- c64/kernal/tape/tape_common.s | 181 +++++++++++++++++++++++++--- 8 files changed, 232 insertions(+), 64 deletions(-) diff --git a/STATUS.md b/STATUS.md index 0c59df05..0d0b61d3 100644 --- a/STATUS.md +++ b/STATUS.md @@ -32,6 +32,7 @@ The following ROM features are currently missing: * BASIC expression parsing * floating point routines * tape (normal mode) support +* tape loading ignores secondary address * IEC support for SAVE * RS-232 support * NMI handling is incomplete diff --git a/c64/aliases/,aliases_ram_lowmem.s b/c64/aliases/,aliases_ram_lowmem.s index c7e03e0c..82341539 100644 --- a/c64/aliases/,aliases_ram_lowmem.s +++ b/c64/aliases/,aliases_ram_lowmem.s @@ -94,7 +94,11 @@ .label DFLTN = $99 // default input device .label DFLTO = $9A // default output device .label PRTY = $9B // tape storage for parity/checksum +#if !CONFIG_TAPE_NORMAL && !CONFIG_TAPE_TURBO .label DPSW = $9C // -- NOT IMPLEMENTED -- +#else + .label COLSTORE = $9C // [!] screen border storage for tape routines +#endif .label MSGFLG = $9D // bit 6 = error messages, bit 7 = control message .label PTR1 = $9E // -- NOT IMPLEMENTED -- .label PTR2 = $9F // -- NOT IMPLEMENTED -- @@ -277,6 +281,6 @@ // $314 $334-$33B -- UNUSED -- free for user software - .label TBUFFR = $33C // $33C-$3FB, -- NOT IMPLEMENTED --, tape buffer + .label TBUFFR = $33C // $33C-$3FB [!] tape buffer, our usage details differ // $3FC $3FC-$3FF -- UNUSED -- free for user software diff --git a/c64/kernal/assets/kernal_messages.s b/c64/kernal/assets/kernal_messages.s index 642ee2bd..3dd5d54e 100644 --- a/c64/kernal/assets/kernal_messages.s +++ b/c64/kernal/assets/kernal_messages.s @@ -17,6 +17,7 @@ #if CONFIG_TAPE_NORMAL || CONFIG_TAPE_TURBO .label __MSG_KERNAL_PRESS_PLAY = __msg_kernalplay - __msg_kernal_first +.label __MSG_KERNAL_FOUND = __msg_kernalfound - __msg_kernal_first #endif #if CONFIG_SHOW_PAL_NTSC @@ -70,6 +71,11 @@ __msg_kernalplay: .text "PRESS PLAY ON TAPE" .byte $80 + $0D // end of string mark + return +__msg_kernalfound: + .byte $0D + .text "FOUND" + .byte $80 + $20 // end of string mark + space + #endif #if CONFIG_SHOW_PAL_NTSC diff --git a/c64/kernal/iec/iec_wait1ms.s b/c64/kernal/iec/iec_wait1ms.s index d6a57218..464619c4 100644 --- a/c64/kernal/iec/iec_wait1ms.s +++ b/c64/kernal/iec/iec_wait1ms.s @@ -4,7 +4,7 @@ // // On NTSC this means 1023 cycles (slightly less on PAL, but we have to be sure). // We can't count on badlines, as the screen might be disabled. -// Delay here is implemeented using VIC-II raster register. Since one raster is +// Delay here is implemented using VIC-II raster register. Since one raster is // 63 cycles, we need at least 17 full rasters to be 100% sure we wait enough @@ -12,7 +12,15 @@ iec_wait1ms: + ldx #18 // we probably won't start with the beginning of raster + +#endif // CONFIG_IEC +#if CONFIG_IEC || CONFIG_TAPE_TURBO || CONFIG_TAPE_NORMAL + +wait_x_bars: // additional entry point for tape support + // has to preserve .Y and put .X to 0 + lda VIC_RASTER !: cmp VIC_RASTER @@ -24,4 +32,4 @@ iec_wait1ms: rts -#endif // CONFIG_IEC +#endif // CONFIG_IEC || CONFIG_TAPE_TURBO || CONFIG_TAPE_NORMAL diff --git a/c64/kernal/iec/load_iec.s b/c64/kernal/iec/load_iec.s index 340892ec..07bd6c26 100644 --- a/c64/kernal/iec/load_iec.s +++ b/c64/kernal/iec/load_iec.s @@ -90,9 +90,9 @@ iec_load_loop: jsr lvs_handle_byte_load_verify bcs load_iec_error - // Advance pointer to data + // Advance pointer to data; it is OK if it advances past $FFFF, + // one autostart technique does exactly this jsr lvs_advance_pointer - bcs_far lvs_wrap_around_error // Handle STOP key; it is probably an overkill to do it // with every byte, once per 32 bytes should be enough diff --git a/c64/kernal/iostack/lvs_helpers.s b/c64/kernal/iostack/lvs_helpers.s index 9298b6e3..ae19c7a9 100644 --- a/c64/kernal/iostack/lvs_helpers.s +++ b/c64/kernal/iostack/lvs_helpers.s @@ -79,16 +79,10 @@ lvs_handle_byte_verify: lvs_advance_pointer: // Advance pointer - inc STAL - beq !+ - jmp lvs_success_end -!: - inc STAL+1 - // If we wrap around to $0000, then this is bad. + inc STAL+0 bne !+ - jmp lvs_error_end + inc STAL+1 !: - clc rts @@ -155,12 +149,6 @@ lvs_display_done: ldx #__MSG_KERNAL_TO_HEX jmp !- -lvs_wrap_around_error: - - // This error is probably not even detected by C64 Kernal; - // report BASIC error code that looks the most sane - lda #B_ERR_OVERFLOW - lvs_error_end: sec diff --git a/c64/kernal/tape/load_tape_turbo.s b/c64/kernal/tape/load_tape_turbo.s index bf1cb7e0..e3ebfebf 100644 --- a/c64/kernal/tape/load_tape_turbo.s +++ b/c64/kernal/tape/load_tape_turbo.s @@ -7,66 +7,75 @@ // - https://codebase64.pokefinder.org/doku.php?id=base:turbotape_loader_source +// XXX use calibration bits to improve reading +// XXX handle load address from Kernal API +// XXX add name matching + + #if CONFIG_TAPE_TURBO load_tape_turbo: - // XXX prepare SID, store screen color somewhere, read header - jsr tape_ditch_verify // only LOAD is supported, no VERIFY - ldy #$00 - sty PRTY // initial checksum value - - sty CIA2_TIMAHI + lda #$00 + sta CIA2_TIMAHI lda #$FE // timer threshold for TurboTape sta CIA2_TIMALO jsr tape_ask_play + // FALLTROUGH + +load_tape_turbo_header: + // Read file header - ldy #$00 + jsr tape_turbo_sync - jsr tape_turbo_sync // .X gets set to 0 - - stx STAL+0 // instead of a later lda, sta - jsr tape_turbo_get_byte // important trick - save time/bytes by using y-indexing - tay + ldy #$15 !: - jsr tape_turbo_get_byte - sta STAL+1,x // .X still 0 - inx - cpx #$03 - bne !- + jsr tape_turbo_get_byte + sta (TAPE1), y + dey + bpl !- + + jsr tape_handle_header + bcs load_tape_turbo_header // if name does not match, look for other header + + // FALLTROUGH + +load_tape_turbo_payload: // Read file payload jsr tape_turbo_sync // .X gets set to 0 + ldy #$00 + sty PRTY // initial checksum value + // FALLTROUGH load_tape_turbo_loop: jsr tape_turbo_get_byte - dec CPU_R6510 // to load below i/o area! - - sta (STAL),y - eor PRTY - sta PRTY - + dec CPU_R6510 // to load below I/O area + sta (STAL),y inc CPU_R6510 - iny - bne !+ - inc STAL+1 -!: - cpy MEMUSS+0 + eor PRTY // handle checksum + sta PRTY + + jsr lvs_advance_pointer + lda STAL+1 - sbc MEMUSS+1 - bcc load_tape_turbo_loop + cmp EAL+1 + bne load_tape_turbo_loop + lda STAL+0 + cmp EAL+0 + bne load_tape_turbo_loop // Verify the checksum @@ -75,7 +84,6 @@ load_tape_turbo_loop: beq_far tape_load_success jmp tape_load_error - tape_turbo_get_byte: lda #$01 diff --git a/c64/kernal/tape/tape_common.s b/c64/kernal/tape/tape_common.s index 9e130f44..0a8f97e0 100644 --- a/c64/kernal/tape/tape_common.s +++ b/c64/kernal/tape/tape_common.s @@ -7,6 +7,10 @@ #if CONFIG_TAPE_NORMAL || CONFIG_TAPE_TURBO +// +// Check if VERIFY asked - if yes, terminate loading +// + tape_ditch_verify: lda VERCKK @@ -18,24 +22,52 @@ tape_ditch_verify: jmp lvs_device_not_found_error +// +// Handle tape deck motor +// + tape_motor_off: lda CPU_R6510 ora #$20 - sta CPU_R6510 - - rts - + bne !+ // branch always tape_motor_on: lda CPU_R6510 and #($FF - $20) +!: sta CPU_R6510 - rts +// +// Handle screen (visible/blanked) + tape deck motor (on/off), +// store/restore screen color +// + +tape_screen_show_motor_off: + + jsr tape_motor_off + + lda COLSTORE + sta VIC_EXTCOL + + jmp screen_show + +tape_screen_hide_motor_on: + lda VIC_EXTCOL + sta COLSTORE + + jsr screen_blank + jmp tape_motor_on + + +// +// Ask user to press PLAY on tape deck, +// Unless user cancelled loading, blank screen and start motor +// + tape_ask_play: sei // timing is critical for tape loading @@ -45,9 +77,18 @@ tape_ask_play: ldx #__MSG_KERNAL_PRESS_PLAY jsr print_kernal_message + // Clean the SID registers, we need it for sound effects + + lda #$00 + ldy #$1C +!: + sta __SID_BASE, y + dey + bpl !- + // FALLTROUGH -tape_wait_button_loop: +tape_wait_play_loop: jsr udtim_keyboard jsr STOP @@ -61,27 +102,139 @@ tape_wait_button_loop: !: lda CPU_R6510 and #$10 // check for pressed button - bne tape_wait_button_loop + bne tape_wait_play_loop - jsr screen_blank - jsr tape_motor_on + jmp tape_screen_hide_motor_on + +// +// Handle file header - display it, decide whether load the file or not, etc. +// + +tape_handle_header: + + jsr tape_screen_show_motor_off + + // 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 $0B (tape timing) contained at the time of saving XXX handle this + // 16 bytes - filename, padded with 0x20 + // + // Out tape buffer contains header in reversed order + + // Print FOUND + file name + + ldx #__MSG_KERNAL_FOUND + jsr print_kernal_message + + ldy #$10 +!: + lda (TAPE1), y + jsr JCHROUT + dey + bpl !- + jsr print_return + + // Header, wait for user decision + + jsr tape_header_get_decision + bcs tape_handle_header_skip + + // XXX Perform filename matching + + // Setup STAL and EAL + + ldy #$15 + lda (TAPE1), y + sta STAL+0 + + dey + lda (TAPE1), y + sta STAL+1 + + dey + lda (TAPE1), y + sta EAL+0 + + dey + lda (TAPE1), y + sta EAL+1 + + // Print LOADING + + jsr lvs_display_loading_verifying + + // Load the file + + jsr tape_screen_hide_motor_on + + clc + rts + +tape_handle_header_skip: + + // Skip this file + + jsr tape_screen_hide_motor_on + + sec rts +// +// 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 + + +// +// Report that file loading succeeded (or not) +// + tape_load_success: - jsr screen_show - jsr tape_motor_off + jsr tape_screen_show_motor_off + jsr lvs_display_done cli jmp lvs_success_end - tape_load_error: - jsr screen_show - jsr tape_motor_off + jsr tape_screen_show_motor_off cli jmp lvs_load_verify_error