diff --git a/skoolkit/bin2tap.py b/skoolkit/bin2tap.py index d0a2ef85..80359e38 100644 --- a/skoolkit/bin2tap.py +++ b/skoolkit/bin2tap.py @@ -223,28 +223,32 @@ def main(args): loader_addr = namespace.loader if loader_addr is None and clear is not None: loader_addr = clear + 1 + has_128k_options = out7ffd is not None and clear is not None and namespace.begin is not None if snapshot_reader.can_read(infile): org = 0 begin = namespace.begin or 16384 - end = namespace.end or 65536 - ram = snapshot_reader.get_snapshot(infile)[begin:end] - if out7ffd is not None and clear is not None: + if has_128k_options: snapshot = snapshot_reader.get_snapshot(infile, -1) if len(snapshot) == 0x20000: banks = {b: snapshot[b * 0x4000:(b + 1) * 0x4000] for b in (0, 1, 3, 4, 6, 7)} + end = namespace.end or 49152 + else: + end = namespace.end or 65536 + ram = snapshot_reader.get_snapshot(infile)[begin:end] else: snapshot = read_bin_file(infile, 0x20000) - if len(snapshot) == 0x20000 and out7ffd is not None and clear is not None: + if len(snapshot) == 0x20000 and has_128k_options: banks = {b: snapshot[b * 0x4000:(b + 1) * 0x4000] for b in range(8)} ram = list(banks.pop(5) + banks.pop(2)) + [0] * 16384 org = 16384 + end = namespace.end or 49152 elif snapshot: ram = snapshot[:49152] org = namespace.org or 65536 - len(ram) + end = namespace.end or org + len(ram) else: raise SkoolKitError(f'{infile} is empty') begin = namespace.begin or org - end = namespace.end or org + len(ram) ram = ram[begin - org:end - org] if not ram: raise SkoolKitError('Input is empty (ORG={}, BEGIN={}, END={})'.format(org, begin, end)) diff --git a/sphinx/source/commands.rst b/sphinx/source/commands.rst index 453f02d4..51c0725a 100644 --- a/sphinx/source/commands.rst +++ b/sphinx/source/commands.rst @@ -141,20 +141,20 @@ leaves the stack pointer alone, enabling the program to return to BASIC without crashing. The lowest usable address with the ``--clear`` option on a bare 48K Spectrum is 23952 (0x5D90). -To create a TAP file that loads a 128K game, use the ``--7ffd``, ``--begin``, -``--end`` and ``--clear`` options along with a 128K snapshot or a 128K binary -file as input, where: +To create a TAP file that loads a 128K game, use the ``--7ffd``, ``--begin`` +and ``--clear`` options along with a 128K snapshot or a 128K binary file as +input, where: * ``--7ffd`` specifies the value to write to port 0x7FFD after all the RAM banks have loaded and before starting the game -* ``--begin`` and ``--end`` specify the start and end addresses of the - code/data below 49152 (0xC000) to include on the tape -* ``--clear`` specifies the address of the CLEAR command in the BASIC loader; - by default, the 128K RAM bank loader is placed one above this address - -Use the ``--loader`` option to place the 128K RAM bank loader at an alternative -address. The lowest usable address with the ``--clear`` option on a bare 128K -Spectrum is 23977 (0x5DA9). +* ``--begin`` specifies the start address of the code/data below 49152 (0xC000) + to include on the tape +* ``--clear`` specifies the address of the CLEAR command in the BASIC loader + +By default, the 128K RAM bank loader (which is 45 bytes long) is placed one +above the CLEAR address. Use the ``--loader`` option to place it at an +alternative address. The lowest usable address with the ``--clear`` option on a +bare 128K Spectrum is 23977 (0x5DA9). +---------+-------------------------------------------------------------------+ | Version | Changes | diff --git a/sphinx/source/man/bin2tap.py.rst b/sphinx/source/man/bin2tap.py.rst index 17cf5009..e88ddd80 100644 --- a/sphinx/source/man/bin2tap.py.rst +++ b/sphinx/source/man/bin2tap.py.rst @@ -79,20 +79,20 @@ Spectrum is 23952 (0x5D90). 128K TAPES ========== -To create a TAP file that loads a 128K game, use the ``--7ffd``, ``--begin``, -``--end`` and ``--clear`` options along with a 128K snapshot or a 128K binary -file as input, where: +To create a TAP file that loads a 128K game, use the ``--7ffd``, ``--begin`` +and ``--clear`` options along with a 128K snapshot or a 128K binary file as +input, where: * ``--7ffd`` specifies the value to write to port 0x7FFD after all the RAM banks have loaded and before starting the game -* ``--begin`` and ``--end`` specify the start and end addresses of the - code/data below 49152 (0xC000) to include on the tape -* ``--clear`` specifies the address of the CLEAR command in the BASIC loader; - by default, the 128K RAM bank loader is placed one above this address - -Use the ``--loader`` option to place the 128K RAM bank loader at an alternative -address. The lowest usable address with the ``--clear`` option on a bare 128K -Spectrum is 23977 (0x5DA9). +* ``--begin`` specifies the start address of the code/data below 49152 (0xC000) + to include on the tape +* ``--clear`` specifies the address of the CLEAR command in the BASIC loader + +By default, the 128K RAM bank loader (which is 45 bytes long) is placed one +above the CLEAR address. Use the ``--loader`` option to place it at an +alternative address. The lowest usable address with the ``--clear`` option on a +bare 128K Spectrum is 23977 (0x5DA9). EXAMPLES ======== diff --git a/tests/test_bin2tap.py b/tests/test_bin2tap.py index 5396557b..ecdceb77 100644 --- a/tests/test_bin2tap.py +++ b/tests/test_bin2tap.py @@ -586,6 +586,54 @@ def test_option_7ffd_with_128k_binary_file(self): tap_data = self._run(f'-b {begin} -e {end} -c {clear} --7ffd {out7ffd} {binfile}') self._check_tap_with_ram_banks(tap_data, data, banks, out7ffd, binfile, clear, begin) + def test_option_7ffd_with_snapshot_and_no_end_option(self): + data = [200, 201, 202] + begin = 49152 - len(data) + clear = 32767 + out7ffd = 1 + ram = [0] * 49152 + ram[begin - 16384:begin - 16384 + len(data)] = data + sna_data = [0] * 27 + ram + sna_data.extend(( + 0, 0, # PC + out7ffd, # Port 0x7ffd + 0 # TR-DOS ROM + )) + banks = [] + for bank in (0, 1, 3, 4, 6, 7): + if bank == out7ffd % 8: + banks.append((bank, ram[32768:])) + else: + banks.append((bank, [bank] * 16384)) + sna_data.extend(banks[-1][1]) + sna = self.write_bin_file(sna_data, suffix='.sna') + tap_data = self._run(f'-b {begin} -c {clear} --7ffd {out7ffd} {sna}') + self._check_tap_with_ram_banks(tap_data, data, banks, out7ffd, sna, clear, begin) + + def test_option_7ffd_with_128k_binary_file_and_no_end_option(self): + data = [128, 129, 130] + begin = 49152 - len(data) + clear = 32767 + out7ffd = 7 + ram = [0] * 49152 + ram[begin - 16384:begin - 16384 + len(data)] = data + bin_data = [] + banks = [] + for bank in range(8): + if bank == 2: + bin_data += ram[16384:32768] + elif bank == 5: + bin_data += ram[:16384] + elif bank == out7ffd % 8: + banks.append((bank, ram[32768:])) + bin_data += banks[-1][1] + else: + banks.append((bank, [bank] * 16384)) + bin_data += banks[-1][1] + binfile = self.write_bin_file(bin_data, suffix='.bin') + tap_data = self._run(f'-b {begin} -c {clear} --7ffd {out7ffd} {binfile}') + self._check_tap_with_ram_banks(tap_data, data, banks, out7ffd, binfile, clear, begin) + def test_option_b(self): bin_data = range(30) binfile = self.write_bin_file(bin_data, suffix='.bin')