From 73e6b7b922ea7eb9bd36c39a87f053ff99a3f7d0 Mon Sep 17 00:00:00 2001 From: Richard Dymond Date: Mon, 18 Dec 2023 17:29:52 -0400 Subject: [PATCH] Enable {bin2sna,snapmod,tap2sna,trace}.py to POKE 128K RAM banks --- skoolkit/bin2sna.py | 4 +-- skoolkit/snapmod.py | 4 +-- skoolkit/snapshot.py | 18 +++++++++++-- skoolkit/tap2sna.py | 7 ++--- skoolkit/trace.py | 4 +-- sphinx/source/changelog.rst | 3 +++ sphinx/source/commands.rst | 40 ++++++++++++++++------------ sphinx/source/man/bin2sna.py.rst | 10 +++---- sphinx/source/man/snapmod.py.rst | 10 +++---- sphinx/source/man/tap2sna.py.rst | 7 +++-- sphinx/source/man/trace.py.rst | 10 +++---- tests/test_bin2sna.py | 21 +++++++++++++++ tests/test_snapmod.py | 42 +++++++++++++++++++++++++++++ tests/test_tap2sna.py | 39 ++++++++++++++++++++++++--- tests/test_trace.py | 45 ++++++++++++++++++++++++++++++++ 15 files changed, 216 insertions(+), 48 deletions(-) diff --git a/skoolkit/bin2sna.py b/skoolkit/bin2sna.py index 58244dd6..4745d3e0 100644 --- a/skoolkit/bin2sna.py +++ b/skoolkit/bin2sna.py @@ -94,8 +94,8 @@ def main(args): help="Specify the RAM bank (N=0-7) mapped to 49152 (0xC000) in the main input file. This option creates a 128K snapshot.") group.add_argument('-p', '--stack', dest='stack', metavar='STACK', type=integer, help="Set the stack pointer (default: ORG).") - group.add_argument('-P', '--poke', dest='pokes', metavar='a[-b[-c]],[^+]v', action='append', default=[], - help="POKE N,v for N in {a, a+c, a+2c..., b}. " + group.add_argument('-P', '--poke', dest='pokes', metavar='[p:]a[-b[-c]],[^+]v', action='append', default=[], + help="POKE N,v in RAM bank p for N in {a, a+c, a+2c..., b}. " "Prefix 'v' with '^' to perform an XOR operation, or '+' to perform an ADD operation. " "This option may be used multiple times.") group.add_argument('-r', '--reg', dest='reg', metavar='name=value', action='append', default=[], diff --git a/skoolkit/snapmod.py b/skoolkit/snapmod.py index c8cdf43c..0c1ca919 100644 --- a/skoolkit/snapmod.py +++ b/skoolkit/snapmod.py @@ -37,8 +37,8 @@ def main(args): group = parser.add_argument_group('Options') group.add_argument('-m', '--move', dest='moves', metavar='src,size,dest', action='append', default=[], help='Move a block of bytes of the given size from src to dest. This option may be used multiple times.') - group.add_argument('-p', '--poke', dest='pokes', metavar='a[-b[-c]],[^+]v', action='append', default=[], - help="POKE N,v for N in {a, a+c, a+2c..., b}. " + group.add_argument('-p', '--poke', dest='pokes', metavar='[p:]a[-b[-c]],[^+]v', action='append', default=[], + help="POKE N,v in RAM bank p for N in {a, a+c, a+2c..., b}. " "Prefix 'v' with '^' to perform an XOR operation, or '+' to perform an ADD operation. " "This option may be used multiple times.") group.add_argument('-r', '--reg', dest='reg', metavar='name=value', action='append', default=[], diff --git a/skoolkit/snapshot.py b/skoolkit/snapshot.py index 2e5596de..f6ce86c2 100644 --- a/skoolkit/snapshot.py +++ b/skoolkit/snapshot.py @@ -620,6 +620,14 @@ def poke(snapshot, param_str): addr, val = param_str.split(',', 1) except ValueError: raise SkoolKitError("Value missing in poke spec: {}".format(param_str)) + if ':' in addr: + page, addr = addr.split(':', 1) + try: + page = get_int_param(page) + except ValueError: + raise SkoolKitError(f'Invalid page number in poke spec: {param_str}') + else: + page = None try: if val.startswith('^'): value = get_int_param(val[1:], True) @@ -637,8 +645,14 @@ def poke(snapshot, param_str): except ValueError: raise SkoolKitError('Invalid address range in poke spec: {}'.format(param_str)) addr1, addr2, step = values + [values[0], 1][len(values) - 1:] - for a in range(addr1, addr2 + 1, step): - snapshot[a] = poke_f(snapshot[a]) + if page is None: + for a in range(addr1, addr2 + 1, step): + snapshot[a] = poke_f(snapshot[a]) + elif hasattr(snapshot, 'banks'): + bank = snapshot.banks[page % 8] + if bank: + for a in range(addr1, addr2 + 1, step): + bank[a % 0x4000] = poke_f(bank[a % 0x4000]) # API (SnapshotReader) class SnapshotError(SkoolKitError): diff --git a/skoolkit/tap2sna.py b/skoolkit/tap2sna.py index cc3a07c2..49d9d573 100644 --- a/skoolkit/tap2sna.py +++ b/skoolkit/tap2sna.py @@ -784,7 +784,7 @@ def _print_ram_help(): Usage: --ram call=[/path/to/moduledir:]module.function --ram load=[+]block[+],start[,length,step,offset,inc] --ram move=src,size,dest - --ram poke=a[-b[-c]],[^+]v + --ram poke=[p:]a[-b[-c]],[^+]v --ram sysvars Load data from a tape block, move a block of bytes from one location to @@ -844,10 +844,11 @@ def _print_ram_help(): --ram move=32512,256,32768 # Move 32512-32767 to 32768-33023 ---ram poke=a[-b[-c]],[^+]v +--ram poke=[p:]a[-b[-c]],[^+]v - Do POKE N,v for N in {a, a+c, a+2c..., b}. + Do POKE N,v in RAM bank p for N in {a, a+c, a+2c..., b}. + p - the RAM bank to POKE (0-7; 128K only) a - the first address to POKE b - the last address to POKE (optional; default=a) c - step (optional; default=1) diff --git a/skoolkit/trace.py b/skoolkit/trace.py index 5b3ea676..1209d226 100644 --- a/skoolkit/trace.py +++ b/skoolkit/trace.py @@ -300,8 +300,8 @@ def main(args): help="Don't execute interrupt routines.") group.add_argument('-o', '--org', metavar='ADDR', type=integer, help='Specify the origin address of a binary (raw memory) file (default: 65536 - length).') - group.add_argument('-p', '--poke', dest='pokes', metavar='a[-b[-c]],[^+]v', action='append', default=[], - help="POKE N,v for N in {a, a+c, a+2c..., b}. " + group.add_argument('-p', '--poke', dest='pokes', metavar='[p:]a[-b[-c]],[^+]v', action='append', default=[], + help="POKE N,v in RAM bank p for N in {a, a+c, a+2c..., b}. " "Prefix 'v' with '^' to perform an XOR operation, or '+' to perform an ADD operation. " "This option may be used multiple times.") group.add_argument('-r', '--reg', metavar='name=value', action='append', default=[], diff --git a/sphinx/source/changelog.rst b/sphinx/source/changelog.rst index 77b7a1ff..359587f7 100644 --- a/sphinx/source/changelog.rst +++ b/sphinx/source/changelog.rst @@ -9,6 +9,9 @@ Changelog ``--page`` and ``--bank`` options, or by providing a 128K input file) * Added support to :ref:`bin2tap.py` for writing 128K TAP files (by using the ``--7ffd``, ``--banks`` and ``--loader`` options) +* Added support to :ref:`bin2sna.py`, :ref:`snapmod.py`, :ref:`tap2sna.py` and + :ref:`trace.py` for modifying 128K RAM banks (via the ``--poke`` and + ``--ram poke`` options) * Added the :ref:`BANK` macro (for switching the RAM bank that is mapped to 49152-65535) * Added the :ref:`asm-bank` directive (for specifying the RAM bank that is diff --git a/sphinx/source/commands.rst b/sphinx/source/commands.rst index d5fec27b..49060620 100644 --- a/sphinx/source/commands.rst +++ b/sphinx/source/commands.rst @@ -42,11 +42,11 @@ Run `bin2sna.py` with no arguments to see the list of available options:: snapshot. -p STACK, --stack STACK Set the stack pointer (default: ORG). - -P a[-b[-c]],[^+]v, --poke a[-b[-c]],[^+]v - POKE N,v for N in {a, a+c, a+2c..., b}. Prefix 'v' - with '^' to perform an XOR operation, or '+' to - perform an ADD operation. This option may be used - multiple times. + -P [p:]a[-b[-c]],[^+]v, --poke [p:]a[-b[-c]],[^+]v + POKE N,v in RAM bank p for N in {a, a+c, a+2c..., b}. + Prefix 'v' with '^' to perform an XOR operation, or + '+' to perform an ADD operation. This option may be + used multiple times. -r name=value, --reg name=value Set the value of a register. Do '--reg help' for more information. This option may be used multiple times. @@ -63,7 +63,8 @@ Run `bin2sna.py` with no arguments to see the list of available options:: | Version | Changes | +=========+===================================================================+ | 9.1 | Added the ``--bank`` and ``--page`` options and support for | -| | writing 128K snapshots | +| | writing 128K snapshots; the ``--poke`` option can modify specific | +| | RAM banks | +---------+-------------------------------------------------------------------+ | 9.0 | Added support for writing SZX snapshots; added the ``fe`` | | | hardware state attribute | @@ -1287,11 +1288,11 @@ To list the options supported by `snapmod.py`, run it with no arguments:: -m src,size,dest, --move src,size,dest Move a block of bytes of the given size from src to dest. This option may be used multiple times. - -p a[-b[-c]],[^+]v, --poke a[-b[-c]],[^+]v - POKE N,v for N in {a, a+c, a+2c..., b}. Prefix 'v' - with '^' to perform an XOR operation, or '+' to - perform an ADD operation. This option may be used - multiple times. + -p [p:]a[-b[-c]],[^+]v, --poke [p:]a[-b[-c]],[^+]v + POKE N,v in RAM bank p for N in {a, a+c, a+2c..., b}. + Prefix 'v' with '^' to perform an XOR operation, or + '+' to perform an ADD operation. This option may be + used multiple times. -r name=value, --reg name=value Set the value of a register. Do '--reg help' for more information. This option may be used multiple times. @@ -1304,7 +1305,8 @@ To list the options supported by `snapmod.py`, run it with no arguments:: +---------+-------------------------------------------------------------------+ | Version | Changes | +=========+===================================================================+ -| 9.1 | Added support for modifying SZX snapshots and 128K snapshots | +| 9.1 | Added support for modifying SZX snapshots and 128K snapshots; the | +| | ``--poke`` option can modify specific RAM banks | +---------+-------------------------------------------------------------------+ | 8.10 | Added the ``issue2`` hardware state attribute | +---------+-------------------------------------------------------------------+ @@ -1668,6 +1670,8 @@ Configuration parameters may also be set on the command line by using the +---------+-------------------------------------------------------------------+ | Version | Changes | +=========+===================================================================+ +| 9.1 | The ``--ram poke`` option can modify specific RAM banks | ++---------+-------------------------------------------------------------------+ | 9.0 | A simulated LOAD is performed by default; an existing snapshot | | | will be overwritten by default; added the ``load``, ``machine``, | | | ``polarity`` and ``in-flags`` simulated LOAD configuration | @@ -1806,11 +1810,11 @@ To list the options supported by `trace.py`, run it with no arguments:: -n, --no-interrupts Don't execute interrupt routines. -o ADDR, --org ADDR Specify the origin address of a binary (raw memory) file (default: 65536 - length). - -p a[-b[-c]],[^+]v, --poke a[-b[-c]],[^+]v - POKE N,v for N in {a, a+c, a+2c..., b}. Prefix 'v' - with '^' to perform an XOR operation, or '+' to - perform an ADD operation. This option may be used - multiple times. + -p [p:]a[-b[-c]],[^+]v, --poke [p:]a[-b[-c]],[^+]v + POKE N,v in RAM bank p for N in {a, a+c, a+2c..., b}. + Prefix 'v' with '^' to perform an XOR operation, or + '+' to perform an ADD operation. This option may be + used multiple times. -r name=value, --reg name=value Set the value of a register. Do '--reg help' for more information. This option may be used multiple times. @@ -1894,6 +1898,8 @@ Configuration parameters may also be set on the command line by using the +---------+-------------------------------------------------------------------+ | Version | Changes | +=========+===================================================================+ +| 9.1 | The ``--poke`` option can modify specific RAM banks | ++---------+-------------------------------------------------------------------+ | 9.0 | Configuration is read from `skoolkit.ini` if present; added the | | | ``--ini``, ``--no-interrupts`` and ``--show-config`` options; | | | interrupt routines are executed by default; added support for | diff --git a/sphinx/source/man/bin2sna.py.rst b/sphinx/source/man/bin2sna.py.rst index dbbfa6ae..5ccff4a4 100644 --- a/sphinx/source/man/bin2sna.py.rst +++ b/sphinx/source/man/bin2sna.py.rst @@ -46,11 +46,11 @@ OPTIONS default value is `ORG`. `STACK` must be a decimal number, or a hexadecimal number prefixed by '0x'. --P, --poke `a[-b[-c]],[^+]v` - POKE N,v for N in {a, a+c, a+2c..., b}. Prefix 'v' with '^' to perform an - XOR operation, or '+' to perform an ADD operation. This option may be used - multiple times. 'a', 'b', 'c' and 'v' must each be a decimal number, or a - hexadecimal number prefixed by '0x'. +-P, --poke `[p:]a[-b[-c]],[^+]v` + POKE N,v in RAM bank p for N in {a, a+c, a+2c..., b}. Prefix 'v' with '^' to + perform an XOR operation, or '+' to perform an ADD operation. This option may + be used multiple times. 'a', 'b', 'c' and 'v' must each be a decimal number, + or a hexadecimal number prefixed by '0x'. -r, --reg `name=value` Set the value of a register. Do ``--reg help`` for more information, or see diff --git a/sphinx/source/man/snapmod.py.rst b/sphinx/source/man/snapmod.py.rst index 4754d081..47cd5aac 100644 --- a/sphinx/source/man/snapmod.py.rst +++ b/sphinx/source/man/snapmod.py.rst @@ -19,11 +19,11 @@ OPTIONS be used multiple times. 'src', 'size' and 'dest' must each be a decimal number, or a hexadecimal number prefixed by '0x'. --p, --poke `a[-b[-c]],[^+]v` - POKE N,v for N in {a, a+c, a+2c..., b}. Prefix 'v' with '^' to perform an - XOR operation, or '+' to perform an ADD operation. This option may be used - multiple times. 'a', 'b', 'c' and 'v' must each be a decimal number, or a - hexadecimal number prefixed by '0x'. +-p, --poke `[p:]a[-b[-c]],[^+]v` + POKE N,v in RAM bank p for N in {a, a+c, a+2c..., b}. Prefix 'v' with '^' to + perform an XOR operation, or '+' to perform an ADD operation. This option may + be used multiple times. 'a', 'b', 'c' and 'v' must each be a decimal number, + or a hexadecimal number prefixed by '0x'. -r, --reg `name=value` Set the value of a register. Do ``--reg help`` for more information, or see diff --git a/sphinx/source/man/tap2sna.py.rst b/sphinx/source/man/tap2sna.py.rst index 7449f6a3..6101f7f2 100644 --- a/sphinx/source/man/tap2sna.py.rst +++ b/sphinx/source/man/tap2sna.py.rst @@ -362,9 +362,12 @@ The ``--ram`` option can be used to POKE values into the snapshot before saving it. | -| ``--ram poke=A[-B[-C]],[^+]V`` +| ``--ram poke=[P:]A[-B[-C]],[^+]V`` -This does ``POKE N,V`` for ``N`` in ``{A, A+C, A+2C..., B}``, where: +This does ``POKE N,V`` in RAM bank ``P`` for ``N`` in ``{A, A+C, A+2C..., B}``, +where: + +``P`` is the RAM bank to POKE (0-7; 128K only) ``A`` is the first address to POKE diff --git a/sphinx/source/man/trace.py.rst b/sphinx/source/man/trace.py.rst index d482dc3b..c8c12e01 100644 --- a/sphinx/source/man/trace.py.rst +++ b/sphinx/source/man/trace.py.rst @@ -51,11 +51,11 @@ OPTIONS address is 65536 minus the length of the file. `ORG` must be a decimal number, or a hexadecimal number prefixed by '0x'. --p, --poke `a[-b[-c]],[^+]v` - POKE N,v for N in {a, a+c, a+2c..., b}. Prefix 'v' with '^' to perform an - XOR operation, or '+' to perform an ADD operation. This option may be used - multiple times. 'a', 'b', 'c' and 'v' must each be a decimal number, or a - hexadecimal number prefixed by '0x'. +-p, --poke `[p:]a[-b[-c]],[^+]v` + POKE N,v in RAM bank p for N in {a, a+c, a+2c..., b}. Prefix 'v' with '^' to + perform an XOR operation, or '+' to perform an ADD operation. This option may + be used multiple times. 'a', 'b', 'c' and 'v' must each be a decimal number, + or a hexadecimal number prefixed by '0x'. -r, --reg `name=value` Set the value of a register before execution begins. Do ``--reg help`` for diff --git a/tests/test_bin2sna.py b/tests/test_bin2sna.py index cb0a2f74..353c018a 100644 --- a/tests/test_bin2sna.py +++ b/tests/test_bin2sna.py @@ -383,6 +383,26 @@ def test_option_P_128k(self): exp_state = ['7ffd=7'] self._check_write_snapshot(args, exp_ram, exp_state) + @patch.object(bin2sna, 'write_snapshot', mock_write_snapshot) + def test_option_P_with_page_number(self): + exp_ram = [[0] * 0x4000 for i in range(8)] + args = ['--page 5'] + for page, addr, value in ( + (0, 0, 255), + (1, 16384, 254), + (2, 32768, 253), + (3, 49152, 252), + (4, 65535, 251), + (5, 49151, 250), + (6, 32767, 249), + (7, 16383, 248), + ): + exp_ram[page][addr % 0x4000] = value + args.append(f'-P {page}:{addr},{value}') + args.append(self.write_bin_file([0], suffix='.bin')) + exp_state = ['7ffd=5'] + self._check_write_snapshot(' '.join(args), exp_ram, exp_state) + @patch.object(bin2sna, 'write_snapshot', mock_write_snapshot) def test_option_P_with_128k_input_file(self): exp_ram = [] @@ -400,6 +420,7 @@ def test_option_P_with_128k_input_file(self): def test_option_P_invalid_values(self): self._test_bad_spec('-P 1', 'Value missing in poke spec: 1') self._test_bad_spec('-P q', 'Value missing in poke spec: q') + self._test_bad_spec('-P p:1,0', 'Invalid page number in poke spec: p:1,0') self._test_bad_spec('-P 1,x', 'Invalid value in poke spec: 1,x') self._test_bad_spec('-P x,1', 'Invalid address range in poke spec: x,1') self._test_bad_spec('-P 1-y,1', 'Invalid address range in poke spec: 1-y,1') diff --git a/tests/test_snapmod.py b/tests/test_snapmod.py index d42249da..1fcf9346 100644 --- a/tests/test_snapmod.py +++ b/tests/test_snapmod.py @@ -344,6 +344,27 @@ def test_option_p_z80v3_128k(self): options.append(f'--poke {addr},{value}') self._test_z80_128k(' '.join(options), header, exp_header, ram, exp_ram, 3) + def test_option_p_z80v3_with_page_number(self): + pokes = ( + (0, 0x0000, 0xFF), + (1, 0x4000, 0xFE), + (2, 0x8000, 0xFD), + (3, 0xC000, 0xFC), + (4, 0x3FFF, 0xFB), + (5, 0x7FFF, 0xFA), + (6, 0xBFFF, 0xF9), + (7, 0xFFFF, 0xF8), + ) + header = self._get_header(3, True) + exp_header = header[:] + ram = [0] * 0x20000 + exp_ram = ram[:] + options = [] + for bank, addr, value in pokes: + exp_ram[(bank * 0x4000) + (addr % 0x4000)] = value + options.append(f'--poke {bank}:{addr},{value}') + self._test_z80_128k(' '.join(options), header, exp_header, ram, exp_ram, 3) + def test_option_p_szx_16k(self): option = '-p 16384,255' exp_block_diffs = None @@ -372,6 +393,26 @@ def test_option_p_szx_128k(self): options.append(f'--poke {addr},{value}') self._test_szx(' '.join(options), exp_block_diffs, exp_ram_diffs, 128, ch7ffd=3) + def test_option_p_szx_with_page_number(self): + pokes = ( + (0, 0x0000, 0xFF), + (1, 0x4000, 0xFE), + (2, 0x8000, 0xFD), + (3, 0xC000, 0xFC), + (4, 0x3FFF, 0xFB), + (5, 0x7FFF, 0xFA), + (6, 0xBFFF, 0xF9), + (7, 0xFFFF, 0xF8), + ) + exp_block_diffs = None + exp_ram_diffs = {} + options = [] + for bank, addr, value in pokes: + exp_ram_diffs[bank] = [0] * 0x4000 + exp_ram_diffs[bank][addr % 0x4000] = value + options.append(f'--poke {bank}:{addr},{value}') + self._test_szx(' '.join(options), exp_block_diffs, exp_ram_diffs, 128) + def test_option_poke_multiple(self): pokes = ((24576, 1), (32768, 34), (49152, 205)) header = list(range(30)) @@ -413,6 +454,7 @@ def test_option_p_invalid_values(self): infile = self.write_z80_file([1] * 30, [0] * 49152, 1) self._test_bad_spec('-p 1', infile, 'Value missing in poke spec: 1') self._test_bad_spec('-p q', infile, 'Value missing in poke spec: q') + self._test_bad_spec('-p p:1,x', infile, 'Invalid page number in poke spec: p:1,x') self._test_bad_spec('-p 1,x', infile, 'Invalid value in poke spec: 1,x') self._test_bad_spec('-p x,1', infile, 'Invalid address range in poke spec: x,1') self._test_bad_spec('-p 1-y,1', infile, 'Invalid address range in poke spec: 1-y,1') diff --git a/tests/test_tap2sna.py b/tests/test_tap2sna.py index a7ee76a8..f160d452 100644 --- a/tests/test_tap2sna.py +++ b/tests/test_tap2sna.py @@ -189,20 +189,20 @@ def _write_basic_loader(self, start, data, write=True, program='simloadbas', cod return self._write_tap(blocks), basic_data return blocks, basic_data - def _get_snapshot(self, start=16384, data=None, options='', load_options=None, blocks=None, tzx=False): + def _get_snapshot(self, start=16384, data=None, options='', load_options=None, blocks=None, tzx=False, page=None): if blocks is None: blocks = [create_tap_data_block(data)] if tzx: tape_file = self._write_tzx(blocks) else: tape_file = self._write_tap(blocks) - z80file = '{}/out.z80'.format(self.make_directory()) + z80file = 'out.z80' if load_options is None: load_options = '--ram load=1,{}'.format(start) output, error = self.run_tap2sna(f'{load_options} {options} {tape_file} {z80file}') self.assertEqual(output, 'Writing {}\n'.format(z80file)) self.assertEqual(error, '') - return get_snapshot(z80file) + return get_snapshot(z80file, page) def _test_bad_spec(self, option, exp_error): tapfile = self._write_tap([create_tap_data_block([1])]) @@ -898,9 +898,42 @@ def test_ram_poke_0x_hex_values(self): snapshot = self._get_snapshot(16384, [2, 1, 2], '--ram poke=0x4000-0x4002-0x02,0x2a') self.assertEqual([42, 1, 42], snapshot[16384:16387]) + def test_ram_poke_with_page_number(self): + data = [0] + basic_data = [ + 0, 10, # Line 10 + 2, 0, # Line length + 234, # REM + 13 # ENTER + ] + blocks = [ + create_tap_header_block('basicprog', 10, len(basic_data), 0), + create_tap_data_block(basic_data) + ] + tapfile = self._write_tap(blocks) + z80file = 'out.z80' + pokes = ( + (0, 0x0000, 255), + (1, 0x4000, 254), + (2, 0x8000, 253), + (3, 0xC000, 252), + (4, 0x3FFF, 251), + (5, 0x7FFF, 250), + (6, 0xBFFF, 249), + (7, 0xFFFF, 248), + ) + poke_opts = ' '.join(f'--ram poke={p}:{a},{v}' for p, a, v in pokes) + output, error = self.run_tap2sna(f'-c machine=128 {poke_opts} {tapfile} {z80file}') + self.assertTrue(output.endswith(f'\nWriting {z80file}\n')) + self.assertEqual(error, '') + snapshot = get_snapshot(z80file, -1) + for p, a, v in pokes: + self.assertEqual(snapshot[p * 0x4000 + (a % 0x4000)], v) + def test_ram_poke_bad_value(self): self._test_bad_spec('--ram poke=1', 'Value missing in poke spec: 1') self._test_bad_spec('--ram poke=q', 'Value missing in poke spec: q') + self._test_bad_spec('--ram poke=p:1,1', 'Invalid page number in poke spec: p:1,1') self._test_bad_spec('--ram poke=1,x', 'Invalid value in poke spec: 1,x') self._test_bad_spec('--ram poke=x,1', 'Invalid address range in poke spec: x,1') self._test_bad_spec('--ram poke=1-y,1', 'Invalid address range in poke spec: 1-y,1') diff --git a/tests/test_trace.py b/tests/test_trace.py index 47f0a4a4..c23729cf 100644 --- a/tests/test_trace.py +++ b/tests/test_trace.py @@ -996,6 +996,51 @@ def test_option_poke(self): """ self.assertEqual(dedent(exp_output).strip(), output.rstrip()) + def test_option_poke_with_page_number(self): + data = [ + 0x16, 0x00, # $6000 LD D,$00 + 0x01, 0xFD, 0x7F, # $6002 LD BC,$7FFD + 0xED, 0x51, # $6005 OUT (C),D + 0x3A, 0x00, 0xC0, # $6007 LD A,($C000) + 0x14, # $600A INC D + 0xCB, 0x5A, # $600B BIT 3,D + 0x28, 0xF6, # $600D JR Z,$6005 + ] + sna = [0] * 131103 + start, stop = 0x6000, 0x600F + index = start + 27 - 16384 + sna[index:index + len(data)] = data + snafile = self.write_bin_file(sna, suffix='.sna') + ini = """ + [trace] + TraceLine=${pc:04X} {i:<15} Bank {r[d]}: A=${r[a]:02X} + """ + self.write_text_file(dedent(ini).strip(), 'skoolkit.ini') + pokes = ( + (0, 0x0000, 0xFF), + (1, 0x4000, 0xFE), + (2, 0x8000, 0xFD), + (3, 0xC000, 0xFC), + (4, 0x0000, 0xFB), + (5, 0x4000, 0xFA), + (6, 0x8000, 0xF9), + (7, 0xC000, 0xF8), + ) + poke_opts = ' '.join(f'--poke {p}:{a},{v}' for p, a, v in pokes) + output, error = self.run_trace(f'-s {start} -S {stop} -v {poke_opts} {snafile}') + self.assertEqual(error, '') + exp_output = [ + '$6007 LD A,($C000) Bank 0: A=$FF', + '$6007 LD A,($C000) Bank 1: A=$FE', + '$6007 LD A,($C000) Bank 2: A=$FD', + '$6007 LD A,($C000) Bank 3: A=$FC', + '$6007 LD A,($C000) Bank 4: A=$FB', + '$6007 LD A,($C000) Bank 5: A=$FA', + '$6007 LD A,($C000) Bank 6: A=$F9', + '$6007 LD A,($C000) Bank 7: A=$F8' + ] + self.assertEqual(exp_output, output.rstrip().split('\n')[3::5]) + def test_option_reg(self): data = [ 0x3C # INC A