Skip to content

Commit

Permalink
Add the 'in-flags' simulated LOAD configuration parameter
Browse files Browse the repository at this point in the history
This replaces the 'contended-in' and 'read-in-r-c' configuration
parameters.
  • Loading branch information
skoolkid committed Oct 25, 2023
1 parent e917fd3 commit 330d43c
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 58 deletions.
48 changes: 21 additions & 27 deletions skoolkit/tap2sna.py
Original file line number Diff line number Diff line change
Expand Up @@ -283,15 +283,14 @@ def _ram_operations(snapshot, ram_ops, blocks=None):
def _set_sim_load_config(options):
options.accelerate_dec_a = 1
options.accelerator = 'auto'
options.contended_in = False
options.fast_load = True
options.finish_tape = False
options.first_edge = 0
options.in_flags = 0
options.load = None
options.machine = '48'
options.pause = True
options.polarity = 0
options.read_in_r_c = False
options.timeout = 900
options.trace = None
for spec in options.sim_load_config:
Expand All @@ -301,14 +300,14 @@ def _set_sim_load_config(options):
options.accelerate_dec_a = parse_int(value, options.accelerate_dec_a)
elif name == 'accelerator':
options.accelerator = value
elif name == 'contended-in':
options.contended_in = parse_int(value, options.contended_in)
elif name == 'fast-load':
options.fast_load = parse_int(value, options.fast_load)
elif name == 'finish-tape':
options.finish_tape = parse_int(value, options.finish_tape)
elif name == 'first-edge':
options.first_edge = parse_int(value, options.first_edge)
elif name == 'in-flags':
options.in_flags = parse_int(value, options.in_flags)
elif name == 'load':
options.load = value
elif name == 'machine':
Expand All @@ -317,8 +316,6 @@ def _set_sim_load_config(options):
options.pause = parse_int(value, options.pause)
elif name == 'polarity':
options.polarity = parse_int(value, options.polarity)
elif name == 'read-in-r-c':
options.read_in_r_c = parse_int(value, options.read_in_r_c)
elif name == 'timeout':
options.timeout = parse_int(value, options.timeout)
elif name == 'trace':
Expand Down Expand Up @@ -425,14 +422,16 @@ def sim_load(blocks, options, config):
if timeout <= 0:
write_line(f'Simulation stopped (timed out): PC={simulator.registers[PC]}')
elif not interrupted:
if options.contended_in:
if options.in_flags & 1:
in_min_addr = 0x4000
elif options.in_flags & 2:
in_min_addr = 0x10000
else:
in_min_addr = 0x8000
tracer = LoadTracer(simulator, blocks, accelerators, options.pause, options.first_edge,
options.polarity, options.finish_tape, in_min_addr, options.accelerate_dec_a,
list_accelerators, border, out7ffd, outfffd, ay, outfe)
simulator.set_tracer(tracer, options.read_in_r_c, False)
simulator.set_tracer(tracer, options.in_flags & 4, False)
try:
tracer.run(options.start, options.fast_load, timeout, tracefile, trace_line, prefix, byte_fmt, word_fmt)
_ram_operations(memory, options.ram_ops)
Expand Down Expand Up @@ -878,15 +877,14 @@ def _print_sim_load_config_help():
print(f"""
Usage: --sim-load-config accelerate-dec-a=0/1/2
--sim-load-config accelerator=NAME
--sim-load-config contended-in=0/1
--sim-load-config fast-load=0/1
--sim-load-config finish-tape=0/1
--sim-load-config first-edge=N
--sim-load-config in-flags=FLAGS
--sim-load-config load=KEYS
--sim-load-config machine=48/128
--sim-load-config pause=0/1
--sim-load-config polarity=0/1
--sim-load-config read-in-r-c=0/1
--sim-load-config timeout=N
--sim-load-config trace=FILE
Expand All @@ -907,13 +905,6 @@ def _print_sim_load_config_help():
{accelerators}
--sim-load-config contended-in=0/1
By default, 'IN A,($FE)' instructions in RAM are ignored (i.e. are not
interpreted as reading the tape) unless they are at address $8000 or above.
Set contended-in=1 to enable 'IN A,($FE)' instructions in the address range
$4000-$7FFF to read the tape as well.
--sim-load-config fast-load=0/1
By default, whenever the Spectrum ROM's load routine is called, a shortcut is
Expand All @@ -931,10 +922,19 @@ def _print_sim_load_config_help():
--sim-load-config first-edge=N
Set the time (in T-states) from the start of the tape at which to place the
leading edge of the first pulse (default: 0). Any pulses that occur before
time 0 are discarded. The EAR bit reading yielded by a pulse is 0 if the
0-based index of the pulse is even (i.e. first, third, fifth pulses etc.), or
1 otherwise.
leading edge of the first pulse (default: 0).
--sim-load-config in-flags=FLAGS
Specify how to handle 'IN' instructions. FLAGS is the sum of the following
values, chosen according to the desired behaviour:
1 - interpret 'IN A,($FE)' instructions in the address range $4000-$7FFF as
reading the tape (by default they are ignored)
2 - ignore 'IN' instructions in the address range $4000-$FFFF (i.e. in RAM)
that read port $FE
4 - yield a simulated port reading when executing an 'IN r,(C)' instruction
(by default such an instruction always yields the value $FF)
--sim-load-config load=KEYS
Expand Down Expand Up @@ -987,12 +987,6 @@ def _print_sim_load_config_help():
(polarity=0), and subsequent pulses give readings that alternate between 1
and 0. This works for most loaders, but some require polarity=1.
--sim-load-config read-in-r-c=0/1
By default, 'IN r,(C)' instructions yield a value of 0xFF, regardless of the
port being read. Set read-in-r-c=1 to enable 'IN r,(C)' instructions to yield
a simulated port reading (as 'IN A,(n)' instructions always do).
--sim-load-config timeout=N
Set the timeout to N seconds (default: 900). A simulated LOAD still in
Expand Down
6 changes: 3 additions & 3 deletions sphinx/source/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ Changelog
* Added the ``polarity`` simulated LOAD configuration parameter to
:ref:`tap2sna.py <tap2sna-sim-load>` (to specify the EAR bit reading produced
by the first pulse on the tape)
* Added the ``read-in-r-c`` simulated LOAD configuration parameter to
:ref:`tap2sna.py <tap2sna-sim-load>` (to specify whether to yield a simulated
port reading for 'IN r,(C)' instructions)
* Added the ``in-flags`` simulated LOAD configuration parameter to
:ref:`tap2sna.py <tap2sna-sim-load>` (to specify how to handle 'IN'
instructions)
* The output snapshot argument of :ref:`tap2sna.py` is now optional
* Added the ``DefaultSnapshotFormat`` configuration parameter for
:ref:`tap2sna.py <tap2sna-conf>` (to specify the default output snapshot
Expand Down
47 changes: 27 additions & 20 deletions sphinx/source/commands.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1392,8 +1392,6 @@ parameters are:
(``0``)
* ``accelerator`` - a comma-separated list of tape-sampling loop accelerators
to use (see :ref:`tap2sna-accelerators`)
* ``contended-in`` - interpret 'IN A,($FE)' instructions in the address range
$4000-$7FFF as reading the tape (``1``), or ignore them (``0``, the default)
* ``fast-load`` - enable fast loading (``1``, the default), or disable it
(``0``); fast loading significantly reduces the load time for many tapes, but
can also cause some loaders to fail
Expand All @@ -1403,6 +1401,8 @@ parameters are:
has finished (``0``, the default)
* ``first-edge`` - the time (in T-states) from the start of the tape at which
to place the leading edge of the first pulse (default: ``0``)
* ``in-flags`` - various flags specifying how to handle 'IN' instructions (see
below)
* ``load`` - a space-separated list of keys to press to build an alternative
command line to load the tape (see :ref:`tap2sna-load`)
* ``machine`` - the type of machine to simulate: a 48K Spectrum (``48``, the
Expand All @@ -1414,14 +1414,21 @@ parameters are:
* ``polarity`` - the EAR bit reading produced by the first pulse on the tape:
``0`` (the default) or ``1``; subsequent pulses give readings that alternate
between 0 and 1
* ``read-in-r-c`` - when executing an 'IN r,(C)' instruction, either yield a
simulated port reading (``1``), or always yield the value 0xFF (``0``, the
default)
* ``timeout`` - the number of seconds of Z80 CPU time after which to abort the
simulated LOAD if it's still in progress (default: 900)
* ``trace`` - the file to which to log all instructions executed during the
simulated LOAD (default: none)

The ``in-flags`` parameter is the sum of the following values, chosen according
to the desired behaviour:

* 1 - interpret 'IN A,($FE)' instructions in the address range $4000-$7FFF as
reading the tape (by default they are ignored)
* 2 - ignore 'IN' instructions in the address range $4000-$FFFF (i.e. in RAM)
that read port $FE
* 4 - yield a simulated port reading when executing an 'IN r,(C)' instruction
(by default such an instruction always yields the value $FF)

By default, the EAR bit reading produced by a pulse is 0 if the 0-based index
of the pulse is even (i.e. first, third, fifth pulses etc.), or 1 otherwise.
This can be reversed by setting ``polarity=1``. Run *tap2sna.py* with the
Expand Down Expand Up @@ -1611,7 +1618,7 @@ Configuration parameters may also be set on the command line by using the
+=========+===================================================================+
| 9.0 | A simulated LOAD is performed by default; an existing snapshot |
| | will be overwritten by default; added the ``load``, ``machine``, |
| | ``polarity`` and ``read-in-r-c`` simulated LOAD configuration |
| | ``polarity`` and ``in-flags`` simulated LOAD configuration |
| | parameters; the output snapshot argument is optional; added |
| | support for writing SZX snapshots; added the |
| | ``DefaultSnapshotFormat`` configuration parameter; added the |
Expand All @@ -1624,20 +1631,20 @@ Configuration parameters may also be set on the command line by using the
| 8.10 | Configuration is read from `skoolkit.ini` if present; added the |
| | ``--ini``, ``--show-config`` and ``--tape-analysis`` options; |
| | added the ``TraceLine`` and ``TraceOperand`` configuration |
| | parameters; added the ``accelerate-dec-a``, ``contended-in`` and |
| | ``finish-tape`` simulated LOAD configuration parameters; added |
| | the ``issue2`` hardware state attribute; added the special |
| | ``auto`` and ``list`` tape-sampling loop accelerator names, and |
| | the ability to specify multiple accelerators; added the |
| | ``alkatraz-05``, ``alkatraz-09``, ``alkatraz-0a``, |
| | ``alkatraz-0b``, ``alternative``, ``alternative2``, |
| | ``boguslaw-juza``, ``bulldog``, ``crl``, ``crl2``, ``crl3``, |
| | ``crl4``, ``cybexlab``, ``d-and-h``, ``delphine``, |
| | ``design-design``, ``gargoyle2``, ``gremlin2``, ``microprose``, |
| | ``micro-style``, ``mirrorsoft``, ``palas``, ``raxoft``, |
| | ``realtime``, ``silverbird``, ``software-projects``, |
| | ``sparklers``, ``suzy-soft``, ``suzy-soft2``, ``tiny``, |
| | ``us-gold`` and ``weird-science`` tape-sampling loop accelerators |
| | parameters; added the ``accelerate-dec-a`` and ``finish-tape`` |
| | simulated LOAD configuration parameters; added the ``issue2`` |
| | hardware state attribute; added the special ``auto`` and ``list`` |
| | tape-sampling loop accelerator names, and the ability to specify |
| | multiple accelerators; added the ``alkatraz-05``, |
| | ``alkatraz-09``, ``alkatraz-0a``, ``alkatraz-0b``, |
| | ``alternative``, ``alternative2``, ``boguslaw-juza``, |
| | ``bulldog``, ``crl``, ``crl2``, ``crl3``, ``crl4``, ``cybexlab``, |
| | ``d-and-h``, ``delphine``, ``design-design``, ``gargoyle2``, |
| | ``gremlin2``, ``microprose``, ``micro-style``, ``mirrorsoft``, |
| | ``palas``, ``raxoft``, ``realtime``, ``silverbird``, |
| | ``software-projects``, ``sparklers``, ``suzy-soft``, |
| | ``suzy-soft2``, ``tiny``, ``us-gold`` and ``weird-science`` |
| | tape-sampling loop accelerators |
+---------+-------------------------------------------------------------------+
| 8.9 | Added the ``--sim-load-config``, ``--tape-name``, |
| | ``--tape-start``, ``--tape-stop`` and ``--tape-sum`` options; |
Expand Down
17 changes: 12 additions & 5 deletions sphinx/source/man/tap2sna.py.rst
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,6 @@ parameters are:
(``0``)
* ``accelerator`` - a comma-separated list of tape-sampling loop accelerators
to use (see the ``ACCELERATORS`` section below)
* ``contended-in`` - interpret 'IN A,($FE)' instructions in the address range
$4000-$7FFF as reading the tape (``1``), or ignore them (``0``, the default)
* ``fast-load`` - enable fast loading (``1``, the default), or disable it
(``0``); fast loading significantly reduces the load time for many tapes, but
can also cause some loaders to fail
Expand All @@ -129,6 +127,8 @@ parameters are:
has finished (``0``, the default)
* ``first-edge`` - the time (in T-states) from the start of the tape at which
to place the leading edge of the first pulse (default: ``0``)
* ``in-flags`` - various flags specifying how to handle 'IN' instructions (see
below)
* ``load`` - a space-separated list of keys to press to build an alternative
command line to load the tape (see the ``LOAD COMMAND`` section below)
* ``machine`` - the type of machine to simulate: a 48K Spectrum (``48``, the
Expand All @@ -140,14 +140,21 @@ parameters are:
* ``polarity`` - the EAR bit reading produced by the first pulse on the tape:
``0`` (the default) or ``1``; subsequent pulses give readings that alternate
between 0 and 1
* ``read-in-r-c`` - when executing an 'IN r,(C)' instruction, either yield a
simulated port reading (``1``), or always yield the value 0xFF (``0``, the
default)
* ``timeout`` - the number of seconds of Z80 CPU time after which to abort the
simulated LOAD if it's still in progress (default: 900)
* ``trace`` - the file to which to log all instructions executed during the
simulated LOAD (default: none)

The ``in-flags`` parameter is the sum of the following values, chosen according
to the desired behaviour:

* 1 - interpret 'IN A,($FE)' instructions in the address range $4000-$7FFF as
reading the tape (by default they are ignored)
* 2 - ignore 'IN' instructions in the address range $4000-$FFFF (i.e. in RAM)
that read port $FE
* 4 - yield a simulated port reading when executing an 'IN r,(C)' instruction
(by default such an instruction always yields the value $FF)

By default, the EAR bit reading produced by a pulse is 0 if the 0-based index
of the pulse is even (i.e. first, third, fifth pulses etc.), or 1 otherwise.
This can be reversed by setting ``polarity=1``. Run ``tap2sna.py`` with the
Expand Down
3 changes: 3 additions & 0 deletions sphinx/source/migration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ longer supported.
In SkoolKit 8, the default value of the ``first-edge`` simulated LOAD
configuration parameter was -2168. In SkoolKit 9, the default value is 0.

The ``contended-in`` simulated LOAD configuration parameter is no longer
supported. Use ``in-flags=1`` instead.

The following tape-sampling loop accelerator names are not available in
SkoolKit 9:

Expand Down
42 changes: 39 additions & 3 deletions tests/test_tap2sna.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ def __init__(self, *args, **kwargs):

def set_tracer(self, tracer, *args, **kwargs):
self.tracer = tracer
self.set_tracer_args = args

def in_a_n(self):
self.tracer.read_port(self.registers, 0xFE)
Expand Down Expand Up @@ -2258,15 +2259,14 @@ def test_sim_load_config_parameters(self):
params = (
'accelerate-dec-a=2',
'accelerator=speedlock',
'contended-in=1',
'fast-load=0',
'finish-tape=1',
'first-edge=1234',
'in-flags=0',
'load=RUN',
'machine=128',
'pause=0',
'polarity=1',
'read-in-r-c=1',
'timeout=1000',
f'trace={trace_log}'
)
Expand All @@ -2288,7 +2288,7 @@ def test_sim_load_config_parameters(self):
self.assertEqual(load_tracer.first_edge, 1234)
self.assertEqual(load_tracer.polarity, 1)
self.assertEqual(load_tracer.finish_tape, 1)
self.assertEqual(load_tracer.in_min_addr, 0x4000)
self.assertEqual(load_tracer.in_min_addr, 0x8000)
self.assertEqual(load_tracer.accel_dec_a, 2)
self.assertFalse(load_tracer.list_accelerators)
self.assertEqual(load_tracer.border, kbtracer.border)
Expand All @@ -2306,6 +2306,42 @@ def test_sim_load_config_parameters(self):
self.assertEqual(load_tracer.byte_fmt, '02X')
self.assertEqual(load_tracer.word_fmt, '04X')

@patch.object(tap2sna, 'Simulator', MockSimulator)
@patch.object(tap2sna, 'LoadTracer', MockLoadTracer)
@patch.object(tap2sna, '_write_snapshot', mock_write_snapshot)
def test_in_flags_parameter_bit_0(self):
tapfile = self._write_tap([create_tap_data_block([0])])
output, error = self.run_tap2sna(f'-c in-flags=1 {tapfile}')
self.assertEqual(error, '')
self.assertEqual(load_tracer.in_min_addr, 0x4000)
set_tracer_args = load_tracer.simulator.set_tracer_args
self.assertFalse(set_tracer_args[0])
self.assertFalse(set_tracer_args[1])

@patch.object(tap2sna, 'Simulator', MockSimulator)
@patch.object(tap2sna, 'LoadTracer', MockLoadTracer)
@patch.object(tap2sna, '_write_snapshot', mock_write_snapshot)
def test_in_flags_parameter_bit_1(self):
tapfile = self._write_tap([create_tap_data_block([0])])
output, error = self.run_tap2sna(f'-c in-flags=2 {tapfile}')
self.assertEqual(error, '')
self.assertEqual(load_tracer.in_min_addr, 0x10000)
set_tracer_args = load_tracer.simulator.set_tracer_args
self.assertFalse(set_tracer_args[0])
self.assertFalse(set_tracer_args[1])

@patch.object(tap2sna, 'Simulator', MockSimulator)
@patch.object(tap2sna, 'LoadTracer', MockLoadTracer)
@patch.object(tap2sna, '_write_snapshot', mock_write_snapshot)
def test_in_flags_parameter_bit_2(self):
tapfile = self._write_tap([create_tap_data_block([0])])
output, error = self.run_tap2sna(f'-c in-flags=4 {tapfile}')
self.assertEqual(error, '')
self.assertEqual(load_tracer.in_min_addr, 0x8000)
set_tracer_args = load_tracer.simulator.set_tracer_args
self.assertTrue(set_tracer_args[0])
self.assertFalse(set_tracer_args[1])

@patch.object(tap2sna, 'KeyboardTracer', MockKeyboardTracer)
@patch.object(tap2sna, 'LoadTracer', MockLoadTracer)
@patch.object(tap2sna, '_write_snapshot', mock_write_snapshot)
Expand Down

0 comments on commit 330d43c

Please sign in to comment.