From c5f293954df9b10e51e9d1f34bbdef9667dd7a0f Mon Sep 17 00:00:00 2001 From: Robbbert Date: Mon, 29 Mar 2021 04:19:43 +1100 Subject: trs80m3: Added support for high-speed CAS files. --- src/lib/formats/trs_cas.cpp | 99 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 89 insertions(+), 10 deletions(-) diff --git a/src/lib/formats/trs_cas.cpp b/src/lib/formats/trs_cas.cpp index 0c17daaa493..17ce879eba7 100644 --- a/src/lib/formats/trs_cas.cpp +++ b/src/lib/formats/trs_cas.cpp @@ -15,7 +15,7 @@ Support for TRS80 .cas cassette images #define SMPHI 32767 -static int cas_size; // FIXME: global variable prevents multiple instances +static int cas_size = 0; // FIXME: global variable prevents multiple instances /******************************************************************* @@ -41,14 +41,11 @@ static inline int trs80l2_cas_cycle(int16_t *buffer, int sample_pos, bool bit) static int trs80l2_handle_cas(int16_t *buffer, const uint8_t *casdata) { int data_pos = 0, sample_count = 0; - bool a5sw = false; - - data_pos = 0; - sample_count = 0; + bool sw = false; while( data_pos < cas_size ) { - uint8_t data = casdata[data_pos]; + uint8_t data = casdata[data_pos]; for (uint8_t i = 0; i < 8; i++ ) { @@ -61,9 +58,9 @@ static int trs80l2_handle_cas(int16_t *buffer, const uint8_t *casdata) data <<= 1; } - if (!a5sw && (casdata[data_pos] == 0xA5)) + if (!sw && (casdata[data_pos] == 0xA5)) { - a5sw = true; + sw = true; // Need 1ms silence here while rom is busy sample_count += trs80l2_cas_cycle( buffer, sample_count, false ); } @@ -77,13 +74,92 @@ static int trs80l2_handle_cas(int16_t *buffer, const uint8_t *casdata) return sample_count; } +static inline int trs80m3_cas_cycle(int16_t *buffer, int sample_pos, bool bit) +{ + uint8_t i, counts = bit ? 8 : 16; + + if ( buffer ) + { + for (i = 0; i < counts; i++) + buffer[ sample_pos++ ] = SMPHI; + for (i = 0; i < counts; i++) + buffer[ sample_pos++ ] = SMPLO; + } + return counts*2; +} + + +static int trs80m3_handle_cas(int16_t *buffer, const uint8_t *casdata) +{ + int data_pos = 0, sample_count = 0; + uint8_t sw = 0, bitout = 0, byteout = 0; + + // Make sure this is a trs80m3 tape + // Should have ~256 0x55 then one 0x7f + while ((cas_size > data_pos) && (casdata[data_pos] == 0x55)) + data_pos++; + if (casdata[data_pos] != 0x7f) + return 0; + + data_pos = 0; + while( data_pos < cas_size ) + { + uint8_t data = casdata[data_pos]; + + for (uint8_t i = 0; i < 8; i++ ) + { + sample_count += trs80m3_cas_cycle( buffer, sample_count, data >> 7 ); + + // This paragraph unscrambles and prints the SYSTEM name. + // If the first character is U, type SYSTEM, then the next 6 characters; otherwise use CLOAD. + if ((sw == 1) && buffer) + { + if (bitout) + { + byteout = (byteout << 1) | (data >> 7); + if (bitout == 8) + { + if (byteout == 0) + sw = 2; + printf("%c",byteout); + byteout = 0; + bitout = 0; + } + else + bitout++; + } + else bitout++; + } + + data <<= 1; + } + + if (!sw && (casdata[data_pos] == 0x7F)) + { + sw = 1; + // This 1ms of silence isn't absolutely necessary, but the system writes it, so we may as emulate it. + sample_count += trs80l2_cas_cycle( buffer, sample_count, false ); + } + + data_pos++; + } + + // Specification requires a short silence to indicate EOF + sample_count += trs80l2_cas_cycle( buffer, sample_count, false ); + sample_count += trs80l2_cas_cycle( buffer, sample_count, false ); + return sample_count; +} + /******************************************************************* Generate samples for the tape image ********************************************************************/ static int trs80l2_cas_fill_wave(int16_t *buffer, int sample_count, uint8_t *bytes) { - return trs80l2_handle_cas( buffer, bytes ); + if (cas_size && (bytes[0] == 0x55)) + return trs80m3_handle_cas( buffer, bytes ); + else + return trs80l2_handle_cas( buffer, bytes ); } @@ -94,7 +170,10 @@ static int trs80l2_cas_to_wav_size(const uint8_t *casdata, int caslen) { cas_size = caslen; - return trs80l2_handle_cas( nullptr, casdata ); + if (cas_size && (casdata[0] == 0x55)) + return trs80m3_handle_cas( nullptr, casdata ); + else + return trs80l2_handle_cas( nullptr, casdata ); } static const cassette_image::LegacyWaveFiller trs80l2_cas_legacy_fill_wave = -- cgit v1.2.3