diff --git a/skoolkit/tap2sna.py b/skoolkit/tap2sna.py index 3f1b4803..01da098a 100644 --- a/skoolkit/tap2sna.py +++ b/skoolkit/tap2sna.py @@ -238,7 +238,7 @@ class TapeError(Exception): pass class TapeBlockTimings: - def __init__(self, pilot_len=0, pilot=0, sync=(), zero=0, one=0, pause=0, used_bits=8): + def __init__(self, pilot_len=0, pilot=0, sync=(), zero=0, one=0, pause=0, used_bits=8, error=None): self.pilot_len = pilot_len self.pilot = pilot self.sync = sync @@ -246,6 +246,7 @@ def __init__(self, pilot_len=0, pilot=0, sync=(), zero=0, one=0, pause=0, used_b self.one = one self.pause = pause self.used_bits = used_bits + self.error = error def get_tape_block_timings(first_byte, pause=3500000): if first_byte == 0: @@ -611,17 +612,17 @@ def _get_tzx_block(data, i, sim): elif block_id == 21: # Direct recording block if sim: - raise TapeError("TZX Direct Recording (0x15) not supported") + timings = TapeBlockTimings(error="TZX Direct Recording (0x15) not supported") i += get_word3(data, i + 5) + 8 elif block_id == 24: # CSW recording block if sim: - raise TapeError("TZX CSW Recording (0x18) not supported") + timings = TapeBlockTimings(error="TZX CSW Recording (0x18) not supported") i += get_dword(data, i) + 4 elif block_id == 25: # Generalized data block if sim: - raise TapeError("TZX Generalized Data Block (0x19) not supported") + timings = TapeBlockTimings(error="TZX Generalized Data Block (0x19) not supported") i += get_dword(data, i) + 4 elif block_id == 32: # Pause (silence) or 'Stop the tape' command @@ -694,6 +695,8 @@ def _get_tzx_blocks(data, sim, start, stop, is48): break i, block_id, timings, tape_data = _get_tzx_block(data, i, sim) if block_num >= start: + if timings and timings.error: + raise TapeError(timings.error) if sim: if block_id == 0x20: if stop == 0 and timings.pause == 0: diff --git a/tests/test_tap2sna.py b/tests/test_tap2sna.py index b99aa9c8..58b465c8 100644 --- a/tests/test_tap2sna.py +++ b/tests/test_tap2sna.py @@ -1948,11 +1948,30 @@ def test_sim_load_with_tzx_block_type_0x15(self): self.assertEqual(self.out.getvalue(), '') self.assertEqual(self.err.getvalue(), '') + @patch.object(tap2sna, 'LoadTracer', MockLoadTracer) + @patch.object(tap2sna, '_write_snapshot', mock_write_snapshot) + def test_sim_load_can_ignore_tzx_block_type_0x15(self): + direct_recording_block = ( + 21, # Block ID + 79, 0, # T-states per sample + 0, 0, # Pause + 8, # Used bits in last byte + 3, 0, 0, # Data length + 1, 2, 3, # Data + ) + tzxfile = self._write_tzx(( + direct_recording_block, + create_tzx_header_block() + )) + output, error = self.run_tap2sna(f'--tape-start 2 {tzxfile}') + self.assertEqual(error, '') + self.assertEqual(len(load_tracer.blocks), 1) + @patch.object(tap2sna, '_write_snapshot', mock_write_snapshot) def test_sim_load_with_tzx_block_type_0x18(self): block = [ 24, # Block ID - 11, 0, 0, 0, # Block length + 10, 0, 0, 0, # Block length 0, 0, # Pause 68, 172, # Sampling rate 1, # Compression type @@ -1967,6 +1986,26 @@ def test_sim_load_with_tzx_block_type_0x18(self): self.assertEqual(self.out.getvalue(), '') self.assertEqual(self.err.getvalue(), '') + @patch.object(tap2sna, 'LoadTracer', MockLoadTracer) + @patch.object(tap2sna, '_write_snapshot', mock_write_snapshot) + def test_sim_load_can_ignore_tzx_block_type_0x18(self): + csw_recording_block = ( + 24, # Block ID + 10, 0, 0, 0, # Block length + 0, 0, # Pause + 68, 172, # Sampling rate + 1, # Compression type + 1, 0, 0, 0, # Number of stored pulses + 1, # CSW Data + ) + tzxfile = self._write_tzx(( + csw_recording_block, + create_tzx_header_block() + )) + output, error = self.run_tap2sna(f'--tape-start 2 {tzxfile}') + self.assertEqual(error, '') + self.assertEqual(len(load_tracer.blocks), 1) + @patch.object(tap2sna, '_write_snapshot', mock_write_snapshot) def test_sim_load_with_tzx_block_type_0x19(self): block = [ @@ -1988,6 +2027,28 @@ def test_sim_load_with_tzx_block_type_0x19(self): self.assertEqual(self.out.getvalue(), '') self.assertEqual(self.err.getvalue(), '') + @patch.object(tap2sna, 'LoadTracer', MockLoadTracer) + @patch.object(tap2sna, '_write_snapshot', mock_write_snapshot) + def test_sim_load_can_ignore_tzx_block_type_0x19(self): + generalized_data_block = ( + 25, # Block ID + 14, 0, 0, 0, # Block length + 0, 0, # Pause + 0, 0, 0, 0, # Number of symbols in pilot/sync block + 1, # Maximum number of pulses per pilot/sync symbol + 1, # Number of pilot/sync symbols in alphabet table + 0, 0, 0, 0, # Number of symbols in data stream + 1, # Maximum number of pulses per data symbol + 1, # Number of data symbols in alphabet table + ) + tzxfile = self._write_tzx(( + generalized_data_block, + create_tzx_header_block() + )) + output, error = self.run_tap2sna(f'--tape-start 2 {tzxfile}') + self.assertEqual(error, '') + self.assertEqual(len(load_tracer.blocks), 1) + @patch.object(tap2sna, '_write_snapshot', mock_write_snapshot) def test_sim_load_with_trace(self): basic_data = [