summaryrefslogtreecommitdiffstatshomepage
path: root/docs/source/techspecs
diff options
context:
space:
mode:
Diffstat (limited to 'docs/source/techspecs')
-rw-r--r--docs/source/techspecs/audio_effects.rst147
-rw-r--r--docs/source/techspecs/cpu_device.rst229
-rw-r--r--docs/source/techspecs/device_sound_interface.rst318
-rw-r--r--docs/source/techspecs/index.rst5
-rw-r--r--docs/source/techspecs/layout_files.rst18
-rw-r--r--docs/source/techspecs/layout_script.rst97
-rw-r--r--docs/source/techspecs/m6502.rst4
-rw-r--r--docs/source/techspecs/memory.rst156
-rw-r--r--docs/source/techspecs/osd_audio.rst348
-rw-r--r--docs/source/techspecs/uml_instructions.rst1582
10 files changed, 2888 insertions, 16 deletions
diff --git a/docs/source/techspecs/audio_effects.rst b/docs/source/techspecs/audio_effects.rst
new file mode 100644
index 00000000000..12228b97444
--- /dev/null
+++ b/docs/source/techspecs/audio_effects.rst
@@ -0,0 +1,147 @@
+Audio effects
+=============
+
+.. contents:: :local:
+
+
+1. Generalities
+---------------
+
+The audio effects are effects that are applied to the sound between
+the speaker devices and the actual sound output. In the current
+implementation the effect chain is fixed (but not the effect
+parameters), and the parameters are stored in the cfg files. They are
+honestly not really designed for extensibility yet, if ever.
+
+Adding an effect requires working on four parts:
+
+* audio_effects/aeffects.* for effect object creation and "publishing"
+* audio_effects/youreffect.* for the effect implementation
+* frontend/mame/ui/audioeffects.cpp to be able to instantiate the effect configuration menu
+* frontend/mame/ui/audioyoureffect.* to implement the effect configuration menu
+
+2. audio_effects/aeffects.*
+---------------------------
+
+The audio_effect class in the aeffect sources provides three things:
+
+* an enum value to designate the effect type and which must match its
+ position in the chain (iow, the effect chain follows the enum order),
+ in the .h
+* the effect name in the audio_effect::effect_names array in the .cpp
+* the creation of a correct effect object in audio_effect::create in the .cpp
+
+
+
+3. audio_effects/youreffect.*
+-----------------------------
+
+This is where you implement the effect. It takes the shape of an
+audio_effect_youreffect class which derives from audio_effect.
+
+The methods to implement are:
+
+.. code-block:: C++
+
+ audio_effect_youreffect(u32 sample_rate, audio_effect *def);
+
+ virtual int type() const override;
+ virtual void config_load(util::xml::data_node const *ef_node) override;
+ virtual void config_save(util::xml::data_node *ef_node) const override;
+ virtual void default_changed() override;
+ virtual u32 history_size() const; // optional
+
+The constructor must pass the parameters to ``audio_effect`` and
+initialize the effect parameters. ``type`` must return the enum value
+for the effect. ``config_load`` and ``config_save`` should load or
+save the effect parameters from/to the cfg file xml tree.
+``default_changed`` is called when the parameters in ``m_default`` are
+changed and the parameters may need to be updated. ``history_size``
+allows to tell how many samples should still be available of the
+previous input frame. Note that this number must not depend on the
+parameters and only on the sample rate.
+
+An effect has a number of parameters that can come from three sources:
+
+* fixed default value
+* equivalent effect object from the default effect chain
+* user setting through the UI
+
+The first two are recognized through the value of ``m_default`` which
+gets the value of ``def`` in the constructor. When it's nullptr, the
+value to use when not set by the user is the fixed one, otherwise it's
+the one in ``m_default``.
+
+At minimum an effect should have a parameter allowing to bypass it.
+
+Managing a parameter uses four methods:
+
+* ``type param() const;`` returns the current parameter value
+* ``void set_param(type value);`` sets the current parameter value and marks it as set by the user
+* ``bool isset_param() const;`` returns true is the parameter was set by the user
+* ``void reset_param();`` resets the parameter to the default value (from m_default or fixed) and marks it as not set by the user
+
+``config_save`` must only save the user-set parameters.
+``config_load`` must retrieve the parameters that are present and mark
+them as set by the user and reset all the others.
+
+Finally the actual implementation goes into the ``apply`` method:
+
+.. code-block:: C++
+
+ virtual void apply(const emu::detail::output_buffer_flat<sample_t> &src, emu::detail::output_buffer_flat<sample_t> &dest) override;
+
+That method takes two buffers with the same number of channels and has
+to apply the effect to ``src`` to produce ``dest``. The
+``output_buffer_flat`` is non-interleaved with independant per-channel
+buffers.
+
+To make bypassing easier, the ``copy(src, dest)`` method of
+audio_effect allows to copy the samples from ``src`` to ``dest``
+without changing them.
+
+The effect application part should looks like:
+
+.. code-block:: C++
+
+ u32 samples = src.available_samples();
+ dest.prepare_space(samples);
+ u32 channels = src.channels();
+
+ // generate channels * samples results and put them in dest
+
+ dest.commit(samples);
+
+To get pointers to the buffers, one uses:
+
+.. code-block:: C++
+
+ const sample_t *source = src.ptrs(channel, source_index); // source_index must be in [-history_size()..samples-1]
+ sample_t *destination = dest.ptrw(channel, destination_index); // destination_index must be in [0..samples-1]
+
+The samples pointed by source and destination are contiguous. The
+number of channels will not change from one apply call to another, the
+number of samples will vary though. Also the call happens in a
+different thread than the main thread and also in a different thread
+than the parameter setting calls are made from.
+
+
+
+
+4. frontend/mame/ui/audioeffects.cpp
+------------------------------------
+
+Here it suffices to add a creation of the menu
+menu_audio_effect_youreffect in menu_audio_effects::handle. The menu
+effect will pick the effect names from audio_effect (in aeffect.*).
+
+
+5. frontend/mame/ui/audioyoureffect.*
+-------------------------------------
+
+This is used to implement the configuration menu for the effect. It's
+a little complicated because it needs to generate the list of
+parameters and their values, set left or right arrow flags depending
+on the possible modifications, dim them (FLAG_INVERT) when not set by
+the user, and manage the arrows and clear keys to change them. Just
+copy an existing one and change it as needed.
diff --git a/docs/source/techspecs/cpu_device.rst b/docs/source/techspecs/cpu_device.rst
new file mode 100644
index 00000000000..c21a20a4fe7
--- /dev/null
+++ b/docs/source/techspecs/cpu_device.rst
@@ -0,0 +1,229 @@
+CPU devices
+===========
+
+.. contents:: :local:
+
+
+1. Overview
+-----------
+
+CPU devices derivatives are used, unsurprisingly, to implement the
+emulation of CPUs, MCUs and SOCs. A CPU device is first a combination
+of ``device_execute_interface``, ``device_memory_interface``,
+``device_state_interface`` and ``device_disasm_interface``. Refer to
+the associated documentations when they exist.
+
+Two more functionalities are specific to CPU devices which are the DRC
+and the interruptibility support.
+
+
+2. DRC
+------
+
+TODO.
+
+
+3. Interruptibility
+-------------------
+
+3.1 Definition
+~~~~~~~~~~~~~~
+
+An interruptible CPU is defined as a core which is able to suspend the
+execution of one instruction at any time, exit execute_run, then at
+the next call of ``execute_run`` keep going from where it was. This
+includes being able to abort an issued memory access, quit
+execute_run, then upon the next call of execute_run reissue the exact
+same access.
+
+
+3.2 Implementation requirements
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Memory accesses must be done with ``read_interruptible`` or
+``write_interruptible`` on a ``memory_access_specific`` or a
+``memory_access_cache``. The access must be done as bus width and bus
+alignment.
+
+After each access the core must test whether ``icount <= 0``. This
+test should be done after ``icount`` is decremented of the time taken
+by the access itself, to limit the number of tests. When ``icount``
+reaches 0 or less it means that the instruction emulation needs to be
+suspended.
+
+To know whether the access needs to be re-issued,
+``access_to_be_redone()`` needs to be called. If it returns true then
+the time taken by the access needs to be credited back, since it
+hasn't yet happened, and the access will need to be re-issued. The
+call to ``access_to_be_redone()`` clears the reissue flag. If you
+need to check the flag without clearing it use
+``access_to_be_redone_noclear()``.
+
+The core needs to do enough bookkeeping to eventually restart the
+instruction execution just before the access or just after the test,
+depending on the need of reissue.
+
+Finally, to indicate to the rest of the infrastructure the support, it
+must override cpu_is_interruptible() to return true.
+
+
+3.3 Example implementation with generators
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To ensure decent performance, the current implementations (h8, 6502
+and 68000) use a python generator to generate two versions of each
+instruction interpreter, one for the normal emulation, and one for
+restarting the instruction.
+
+The restarted version looks like that (for a 4-cycles per access cpu):
+
+.. code-block:: C++
+
+ void device::execute_inst_restarted()
+ {
+ switch(m_inst_substate) {
+ case 0:
+ [...]
+
+ m_address = [...];
+ m_mask = [...];
+ [[fallthrough]];
+ case 42:
+ m_result = specific.read_interruptible(m_address, m_mask);
+ m_icount -= 4;
+ if(m_icount <= 0) {
+ if(access_to_be_redone()) {
+ m_icount += 4;
+ m_inst_substate = 42;
+ } else
+ m_inst_substate = 43;
+ return;
+ }
+ [[fallthrough]];
+ case 43:
+ [...] = m_result;
+ [...]
+ }
+ m_inst_substate = 0;
+ return;
+ }
+
+The non-restarted version is the same thing with the switch and the
+final ``m_inst_substate`` clearing removed.
+
+.. code-block:: C++
+
+ void device::execute_inst_non_restarted()
+ {
+ [...]
+ m_address = [...];
+ m_mask = [...];
+ m_result = specific.read_interruptible(m_address, m_mask);
+ m_icount -= 4;
+ if(m_icount <= 0) {
+ if(access_to_be_redone()) {
+ m_icount += 4;
+ m_inst_substate = 42;
+ } else
+ m_inst_substate = 43;
+ return;
+ }
+ [...] = m_result;
+ [...]
+ return;
+ }
+
+The main loop then looks like this:
+
+.. code-block:: C++
+
+ void device::execute_run()
+ {
+ if(m_inst_substate)
+ call appropriate restarted instruction handler
+ while(m_icount > 0) {
+ debugger_instruction_hook(m_pc);
+ call appropriate non-restarted instruction handler
+ }
+ }
+
+The idea is thus that ``m_inst_substate`` indicates where in an
+instruction one is, but only when an interruption happens. It
+otherwise stays at 0 and is essentially never looked at. Having two
+versions of the interpretation allows to remove the overhead of the
+switch and the end-of-instruction substate clearing.
+
+It is not a requirement to use a generator-based that method, but a
+different one which does not have unacceptable performance
+implications has not yet been found.
+
+3.4 Bus contention cpu_device interface
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The main way to setup bus contention is through the memory maps.
+Lower-level access can be obtained through some methods on cpu_device
+though.
+
+.. code-block:: C++
+
+ bool cpu_device::access_before_time(u64 access_time, u64 current_time) noexcept;
+
+The method ``access_before_time`` allows to try to run an access at a
+given time in cpu cycles. It takes the current time
+(``total_cycles()``) and the expected time for the access. If there
+aren't enough cycles to reach that time the remaining cycles are eaten
+and the method returns true to tell not to do the access and call the
+method again eventually. Otherwise enough cycles are eaten to reach
+the access time and false is returned to tell to do the access.
+
+
+.. code-block:: C++
+
+ bool cpu_device::access_before_delay(u32 cycles, const void *tag) noexcept;
+
+The method ``access_before_delay`` allows to try to run an access
+after a given delay. The tag is an opaque, non-nullptr value used to
+characterize the source of the delay, so that the delay is not applied
+multiple times. Similarly to the previous method cycles are eaten and
+true is returned to abort the access, false to execute it.
+
+.. code-block:: C++
+
+ void cpu_device::access_after_delay(u32 cycles) noexcept;
+
+The method ``access_after_delay`` allows to add a delay after an
+access is done. There is no abort possible, hence no return boolean.
+
+.. code-block:: C++
+
+ void cpu_device::defer_access() noexcept;
+
+The method ``defer_access`` tells the cpu that we need to wait for an
+external event. It marks the access as to be redone, and eats all the
+remaining cycles of the timeslice. The idea is then that the access
+will be retried after time advances up to the next global system
+synchronisation event (sync, timer timeout or set_input_line). This
+is the method to use when for instance waiting on a magic latch for
+data expected from scsi transfers, which happen on timer timeouts.
+
+.. code-block:: C++
+
+ void cpu_device::retry_access() noexcept;
+
+The method ``retry_access`` tells the cpu that the access will need to
+be retried, and nothing else. This can easily reach a situation of
+livelock, so be careful. It is used for instance to simulate a wait
+line (for the z80 for instance) which is controlled through
+set_input_line. The idea is that the device setting wait does the
+set_input_line and a retry_access. The cpu core, as long as the wait
+line is set just eats cycles. Then, when the line is cleared the core
+will retry the access.
+
+
+3.5 Interaction with DRC
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+At this point, interruptibility and DRC are entirely incompatible. We
+do not have a method to quit the generated code before or after an
+access. It's theorically possible but definitely non-trivial.
+
diff --git a/docs/source/techspecs/device_sound_interface.rst b/docs/source/techspecs/device_sound_interface.rst
new file mode 100644
index 00000000000..8355781effc
--- /dev/null
+++ b/docs/source/techspecs/device_sound_interface.rst
@@ -0,0 +1,318 @@
+The device_sound_interface
+==========================
+
+.. contents:: :local:
+
+
+1. The sound system
+-------------------
+
+The device sound interface is the entry point for devices that handle
+sound input and/or output. The sound system is built on the concept
+of *streams* which connect devices together with resampling and mixing
+applied transparently as needed. Microphones (audio input) and
+speakers (audio output) are specific known devices which use the same
+interface.
+
+2. Devices using device_sound_interface
+---------------------------------------
+
+2.1 Initialisation
+~~~~~~~~~~~~~~~~~~
+
+Sound streams must be created in the device_start (or
+interface_pre_start) method.
+
+.. code-block:: C++
+
+ sound_stream *stream_alloc(int inputs, int outputs, int sample_rate, sound_stream_flags flags = STREAM_DEFAULT_FLAGS);
+
+A stream is created with ``stream_alloc``. It takes the number of
+input and output channels, the sample rate and optionally flags.
+
+The sample rate can be SAMPLE_RATE_INPUT_ADAPTIVE,
+SAMPLE_RATE_OUTPUT_ADAPTIVE or SAMPLE_RATE_ADAPTIVE. In that case the
+chosen sample rate is the highest one among the inputs, outputs or
+both respectively. In case of loop, the chosen sample rate is the
+configured global sample rate.
+
+The only available non-default flag is STREAM_SYNCHRONOUS. When set,
+the sound generation method will be called for every sample
+individually. It's necessary for DSPs that run a program on every
+sample. but on the other hand it's expensive, so only to be used when
+required.
+
+Devices can create multiple streams. It's rare though. Some Yamaha
+chips should but don't. Inputs and outputs are numbered from 0 and
+arrange all streams in the order they are created.
+
+
+2.2 Sound input/output
+~~~~~~~~~~~~~~~~~~~~~~
+
+.. code-block:: C++
+
+ virtual void sound_stream_update(sound_stream &stream);
+
+This method is required to be implemented to consume the input samples
+and/or compute the output ones. The stream to update for is passed as
+the parameter. See the streams section, specifically sample access,
+to see how to write the method.
+
+
+2.3 Stream information
+~~~~~~~~~~~~~~~~~~~~~~
+
+.. code-block:: C++
+
+ int inputs() const;
+ int outputs() const;
+ std::pair<sound_stream *, int> input_to_stream_input(int inputnum) const;
+ std::pair<sound_stream *, int> output_to_stream_output(int outputnum) const;
+
+The method ``inputs`` returns the total number of inputs in the
+streams created by the device. The method ``outputs`` similarly
+counts the outputs. The other two methods allow to grab the stream
+and channel number for the device corresponding to the global input or
+output number.
+
+
+2.4 Gain management
+~~~~~~~~~~~~~~~~~~~
+
+.. code-block:: C++
+
+ float input_gain(int inputnum) const;
+ float output_gain(int outputnum) const;
+ void set_input_gain(int inputnum, float gain);
+ void set_output_gain(int outputnum, float gain);
+ void set_route_gain(int source_channel, device_sound_interface *target, int target_channel, float gain);
+
+ float user_output_gain() const;
+ float user_output_gain(int outputnum) const;
+ void set_user_output_gain(float gain);
+ void set_user_output_gain(int outputnum, float gain);
+
+Those methods allow to set the gain on every step of the routes
+between streams. All gains are multipliers, with default value 1.0.
+The steps are, from samples output in ``sound_stream_update`` to
+samples read in the next device's ``sound_stream_update``:
+
+* Per-channel output gain
+* Per-channel user output gain
+* Per-device user output gain
+* Per-route gain
+* Per-channel input gain
+
+The user gains must not be set from the driver, they're for use by the
+user interface (the sliders) and are saved in the game configuration.
+The other gains are for driver/device use, and are saved in save
+states.
+
+
+2.5 Routing setup
+~~~~~~~~~~~~~~~~~
+
+.. code-block:: C++
+
+ device_sound_interface &add_route(u32 output, const device_finder<T, R> &target, double gain, u32 channel = 0)
+ device_sound_interface &add_route(u32 output, const char *target, double gain, u32 channel = 0);
+ device_sound_interface &add_route(u32 output, device_sound_interface &target, double gain, u32 channel = 0);
+
+ device_sound_interface &reset_routes();
+
+Routes between devices, e.g. between streams, are set at configuration
+time. The method ``add_route`` must be called on the source device
+and gives the channel on the source device, the target device, the
+gain, and optionally the channel on the target device. The constant
+``ALL_OUTPUTS`` can be used to add a route from every channel of the
+source to a given channel of the destination.
+
+The method ``reset_routes`` is used to remove all the routes setup on
+a given source device.
+
+
+.. code-block:: C++
+
+ u32 get_sound_requested_inputs() const;
+ u32 get_sound_requested_outputs() const;
+ u64 get_sound_requested_inputs_mask() const;
+ u64 get_sound_requested_outputs_mask() const;
+
+Those methods are useful for devices which want to behave differently
+depending on what routes are set up on them. You get either the max
+number of requested channel plus one (which is the number of channels
+when all channels are routed, but is more useful when there are gaps)
+or a mask of use for channels 0-63. Note that ``ALL_OUTPUTS`` does
+not register any specific output or output count.
+
+
+
+3. Streams
+----------
+
+3.1 Generalities
+~~~~~~~~~~~~~~~~
+
+Streams are endpoints associated with devices and, when connected
+together, ensure the transmission of audio data between them. A
+stream has a number of inputs (which can be zero) and outputs (same)
+and one sample rate which is common to all inputs and outputs. The
+connections are set up at the machine configuration level and the sound
+system ensures mixing and resampling is done transparently.
+
+Samples in streams are encoded as sample_t. In the current
+implementation, this is a float. Nominal values are between -1 and 1,
+but clamping at the device level is not recommended (unless that's
+what happens in hardware of course) because the gain values, volume
+and effects can easily avoid saturation.
+
+They are implemented in the class ``sound_stream``.
+
+
+3.2 Characteristics
+~~~~~~~~~~~~~~~~~~~
+
+.. code-block:: C++
+
+ device_t &device() const;
+ bool input_adaptive() const;
+ bool output_adaptive() const;
+ bool synchronous() const;
+ u32 input_count() const;
+ u32 output_count() const;
+ u32 sample_rate() const;
+ attotime sample_period() const;
+
+
+3.3 Sample access
+~~~~~~~~~~~~~~~~~
+
+.. code-block:: C++
+
+ s32 samples() const;
+
+ void put(s32 output, s32 index, sample_t sample);
+ void put_clamp(s32 output, s32 index, sample_t sample, sample_t clamp = 1.0);
+ void put_int(s32 output, s32 index, s32 sample, s32 max);
+ void put_int_clamp(s32 output, s32 index, s32 sample, s32 maxclamp);
+ void add(s32 output, s32 index, sample_t sample);
+ void add_int(s32 output, s32 index, s32 sample, s32 max);
+ void fill(s32 output, sample_t value, s32 start, s32 count);
+ void fill(s32 output, sample_t value, s32 start);
+ void fill(s32 output, sample_t value);
+ void copy(s32 output, s32 input, s32 start, s32 count);
+ void copy(s32 output, s32 input, s32 start);
+ void copy(s32 output, s32 input);
+ sample_t get(s32 input, s32 index) const;
+ sample_t get_output(s32 output, s32 index) const;
+
+Those are the methods used to implement ``sound_stream_update``.
+First ``samples`` tells how many samples to consume and/or generate.
+The to-generate samples, if any, are pre-cleared (e.g. set to zero).
+
+Input samples are retrieved with ``get``, where ``input`` is the
+stream channel number and ``index`` the sample number.
+
+Generated samples are written with the put variants. ``put`` sets a
+sample_t in channel ``output`` at position ``index``. ``put_clamp``
+does the same but first clamps the value to +/-``clamp``. ``put_int``
+does it with an integer ``sample`` but pre-divides it by ``max``.
+``put_int_clamp`` does the same but also pre-clamps within
+-``maxclamp`` and ``maxclamp``-1, which is the normal range for a
+2-complement value.
+
+``add`` and ``add_int`` are similar but add the value of the sample to
+what's there instead of replacing. ``get_output`` gets the currently
+stored output value.
+
+``fill`` sets a range of an output channel to a given ``value``.
+``start`` tells where to start (default index 0), ``count`` how many
+(default up to the end of the buffer).
+
+``copy`` does the same as fill but gets its value from the indentical
+position in an input channel.
+
+Note that clamping should not be used unless it actually happens in
+hardware. Between gains and effects there is a fair chance saturation
+can be avoided later in the chain.
+
+
+3.4 Timing
+~~~~~~~~~~
+
+.. code-block:: C++
+ u32 sample_rate() const;
+ attotime sample_period() const;
+
+ u64 start_index() const;
+ u64 end_index() const;
+ attotime start_time() const;
+ attotime end_time() const;
+
+ attotime sample_to_time(u64 index) const;
+
+``sample_rate`` gives the current sample rate of the stream and
+``sample_period`` the corresponding duration.
+
+Within a call to the update callback, ``start_index`` gives the number
+(starting at zero at system power on) and ``start_time`` the time of
+the first sample to compute in the update. ``end_index`` and
+``end_time`` correspondingly indicate one past the last sample to
+update, or in other words the first sample of the next update call.
+Outside of an update callback, they all point to the first sample of
+the next update call.
+
+Finally ``sample_to_time`` allows to convert from a sample number to a
+time.
+
+Note that in case of change of sample rate sample numbers are
+recalculated to end up as if the stream had had the new rate from the
+start. And the times will still be such that sample 0 is at time 0.
+
+
+3.5 Gain management
+~~~~~~~~~~~~~~~~~~~
+
+.. code-block:: C++
+
+ float user_output_gain() const;
+ void set_user_output_gain(float gain);
+ float user_output_gain(s32 output) const;
+ void set_user_output_gain(s32 output, float gain);
+
+ float input_gain(s32 input) const;
+ void set_input_gain(s32 input, float gain);
+ void apply_input_gain(s32 input, float gain);
+ float output_gain(s32 output) const;
+ void set_output_gain(s32 output, float gain);
+ void apply_output_gain(s32 output, float gain);
+
+
+This is similar to the device gain control, with a twist: apply
+multiplies the current gain by the given value.
+
+
+3.6 Misc. actions
+~~~~~~~~~~~~~~~~~
+
+.. code-block:: C++
+
+ void set_sample_rate(u32 sample_rate);
+ void update();
+
+The method ``set_sample_rate`` allows to change the sample rate of the
+stream. The method ``update`` triggers a call of
+``sound_stream_update`` on the stream and the ones it depends on to
+reach the current time in terms of samples.
+
+
+4. Devices using device_mixer_interface
+---------------------------------------
+
+The device mixer interface is used for devices that want to relay
+sound in the device tree without acting on it. It's very useful on
+for instance slot devices connectors, where the slot device may have
+an audio connection with the main system. They are routed like every
+other sound device, create the streams automatically and copy input to
+output. Nothing needs to be done in the device.
diff --git a/docs/source/techspecs/index.rst b/docs/source/techspecs/index.rst
index ee41de889d8..72c678b4ca6 100644
--- a/docs/source/techspecs/index.rst
+++ b/docs/source/techspecs/index.rst
@@ -15,8 +15,13 @@ MAME’s source or working on scripts that run within the MAME framework.
device_memory_interface
device_rom_interface
device_disasm_interface
+ device_sound_interface
memory
+ cpu_device
floppy
nscsi
m6502
+ uml_instructions
poly_manager
+ audio_effects
+ osd_audio
diff --git a/docs/source/techspecs/layout_files.rst b/docs/source/techspecs/layout_files.rst
index d9976faf00d..a014756a32b 100644
--- a/docs/source/techspecs/layout_files.rst
+++ b/docs/source/techspecs/layout_files.rst
@@ -690,6 +690,11 @@ element. This means a view can reference elements and groups that appear after
it in the file, and parameters from the enclosing scope will have their final
values from the end of the ``mamelayout`` element.
+A ``view`` element may have a ``showpointers`` attribute to set whether mouse
+and pen pointers should be shown for the view. If present, the value must be
+either ``yes`` or ``no``. If the ``showpointers`` attribute is not present, pen
+and mouse pointers are shown for views that contain items bound to I/O ports.
+
The following child elements are allowed inside a ``view`` element:
bounds
@@ -1188,7 +1193,7 @@ Clickable items
If a view item (``element`` or ``screen`` element) has ``inputtag`` and
``inputmask`` attribute values that correspond to a digital switch field in the
emulated system, clicking the element will activate the switch. The switch
-will remain active as long as the mouse button is held down and the pointer is
+will remain active as long as the primary button is held down and the pointer is
within the item’s current bounds. (Note that the bounds may change depending on
the item’s animation state, see :ref:`layfile-interact-itemanim`).
@@ -1197,6 +1202,12 @@ device that caused the layout file to be loaded. The ``inputmask`` attribute
must be an integer specifying the bits of the I/O port field that the item
should activate. This sample shows instantiation of clickable buttons:
+The ``clickthrough`` attribute controls whether clicks can pass through the view
+item to other view items drawn above it. The ``clickthrough`` attribute must be
+``yes`` or ``no`` if present. The default is ``no`` (clicks do not pass
+through) for view items with ``inputtag`` and ``inputmask`` attributes, and
+``yes`` (clicks pass through) for other view items.
+
.. code-block:: XML
<element ref="btn_3" inputtag="X2" inputmask="0x10">
@@ -1209,9 +1220,8 @@ should activate. This sample shows instantiation of clickable buttons:
<bounds x="1.775" y="5.375" width="1.0" height="1.0" />
</element>
-When handling mouse input, MAME treats all layout elements as being rectangular,
-and only activates the first clickable item whose area includes the location of
-the mouse pointer.
+When handling pointer input, MAME treats all layout elements as being
+rectangular.
.. _layfile-interact-elemstate:
diff --git a/docs/source/techspecs/layout_script.rst b/docs/source/techspecs/layout_script.rst
index be6166a7146..f3ff505c9df 100644
--- a/docs/source/techspecs/layout_script.rst
+++ b/docs/source/techspecs/layout_script.rst
@@ -495,8 +495,8 @@ providing what’s needed:
* ``emu.print_verbose``, ``emu.print_error``, ``emu.print_warning``,
``emu.print_info`` and ``emu.print_debug`` functions for diagnostic output.
* Standard Lua ``tonumber``, ``tostring``, ``pairs`` and ``ipairs`` functions,
- and ``table`` and ``string`` objects for manipulating strings, tables and
- other containers.
+ and ``math``, ``table`` and ``string`` objects for manipulating numbers,
+ strings, tables and other containers.
* Standard Lua ``print`` function for text output to the console.
@@ -563,6 +563,96 @@ Dimensions recomputed
The callback function has no return value and takes no parameters. Call
with ``nil`` as the argument to remove the event handler.
+Pointer updated
+ ``view:set_pointer_updated_callback(cb)``
+
+ Called when a pointer enters, moves or changes button state over the view.
+
+ The callback function is passed nine arguments:
+
+ * The pointer type as a string. This will be ``mouse``, ``pen``, ``touch``
+ or ``unknown``, and will not change for the lifetime of a pointer.
+ * The pointer ID. This will be a non-negative integer that will not change
+ for the lifetime of a pointer. Pointer ID values are recycled
+ aggressively.
+ * The device ID. This will be a non-negative integer that can be used to
+ group pointers for recognising multi-touch gestures.
+ * The horizontal position of the pointer in layout coordinates.
+ * The vertical position of the pointer in layout coordinates.
+ * A bit mask representing the currently pressed buttons. The primary button
+ is the least significant bit.
+ * A bit mask representing the buttons that were pressed in this update. The
+ primary button is the least significant bit.
+ * A bit mask representing the buttons that were released in this update.
+ The primary button is the least significant bit.
+ * The click count. This is positive for multi-click actions, or negative if
+ a click is turned into a hold or drag. This only applies to the primary
+ button.
+
+ The callback function has no return value. Call with ``nil`` as the
+ argument to remove the event handler.
+Pointer left
+ ``view:set_pointer_left_callback(cb)``
+
+ Called when a pointer leaves the view normally. After receiving this event,
+ the pointer ID may be reused for a new pointer.
+
+ The callback function is passed seven arguments:
+
+ * The pointer type as a string. This will be ``mouse``, ``pen``, ``touch``
+ or ``unknown``, and will not change for the lifetime of a pointer.
+ * The pointer ID. This will be a non-negative integer that will not change
+ for the lifetime of a pointer. Pointer ID values are recycled
+ aggressively.
+ * The device ID. This will be a non-negative integer that can be used to
+ group pointers for recognising multi-touch gestures.
+ * The horizontal position of the pointer in layout coordinates.
+ * The vertical position of the pointer in layout coordinates.
+ * A bit mask representing the buttons that were released in this update.
+ The primary button is the least significant bit.
+ * The click count. This is positive for multi-click actions, or negative if
+ a click is turned into a hold or drag. This only applies to the primary
+ button.
+
+ The callback function has no return value. Call with ``nil`` as the
+ argument to remove the event handler.
+Pointer aborted
+ ``view:set_pointer_aborted_callback(cb)``
+
+ Called when a pointer leaves the view abnormally. After receiving this
+ event, the pointer ID may be reused for a new pointer.
+
+ The callback function is passed seven arguments:
+
+ * The pointer type as a string. This will be ``mouse``, ``pen``, ``touch``
+ or ``unknown``, and will not change for the lifetime of a pointer.
+ * The pointer ID. This will be a non-negative integer that will not change
+ for the lifetime of a pointer. Pointer ID values are recycled
+ aggressively.
+ * The device ID. This will be a non-negative integer that can be used to
+ group pointers for recognising multi-touch gestures.
+ * The horizontal position of the pointer in layout coordinates.
+ * The vertical position of the pointer in layout coordinates.
+ * A bit mask representing the buttons that were released in this update.
+ The primary button is the least significant bit.
+ * The click count. This is positive for multi-click actions, or negative if
+ a click is turned into a hold or drag. This only applies to the primary
+ button.
+
+ The callback function has no return value. Call with ``nil`` as the
+ argument to remove the event handler.
+Forget pointers
+ ``view:set_forget_pointers_callback(cb)``
+
+ Called when the view should stop processing pointer input. This can happen
+ in a number of situations, including:
+
+ * The user activated a menu.
+ * The view configuration will change.
+ * The view will be deactivated.
+
+ The callback function has no return value and takes no parameters. Call
+ with ``nil`` as the argument to remove the event handler.
.. _layscript-events-item:
@@ -692,4 +782,5 @@ Draw
The callback is passed two arguments: the element state (an integer) and the
32-bit ARGB bitmap at the required size. The callback must not attempt to
- resize the bitmap.
+ resize the bitmap. Call with ``nil`` as the argument to remove the event
+ handler.
diff --git a/docs/source/techspecs/m6502.rst b/docs/source/techspecs/m6502.rst
index 7d67423abb8..f5d55fc9af4 100644
--- a/docs/source/techspecs/m6502.rst
+++ b/docs/source/techspecs/m6502.rst
@@ -92,7 +92,7 @@ At a minimum, the class must include a constructor and an enum picking up the co
If the CPU has its own dispatch table, the class must also include the declaration (but not definition) of **disasm_entries**, **do_exec_full** and **do_exec_partial**, the declaration and definition of **disasm_disassemble** (identical for all classes but refers to the class-specific **disasm_entries** array) and include the .inc file (which provides the missing definitions). Support for the generation must also be added to CPU.mak.
-If the CPU has in addition its own opcodes, their declaration must be done through a macro, see f.i. m65c02. The .inc file will provide the definitions.
+If the CPU has in addition its own opcodes, their declaration must be done through a macro, see e.g. m65c02. The .inc file will provide the definitions.
Dispatch tables
@@ -365,7 +365,7 @@ A negative icount means that the CPU won't be able to do anything for some time
Multi-dispatch variants
-----------------------
-Some variants currently in the process of being supported change instruction set depending on an internal flag, either switching to a 16-bits mode or changing some register accesses to memory accesses. This is handled by having multiple dispatch tables for the CPU, the d<CPU>.lst not being 257 entries anymore but 256*n+1. The variable **inst_state_base** must select which instruction table to use at a given time. It must be a multiple of 256, and is in fact simply OR-ed to the first instruction byte to get the dispatch table index (aka inst_state).
+Some variants currently in the process of being supported change instruction set depending on an internal flag, either switching to a 16-bit mode or changing some register accesses to memory accesses. This is handled by having multiple dispatch tables for the CPU, the d<CPU>.lst not being 257 entries anymore but 256*n+1. The variable **inst_state_base** must select which instruction table to use at a given time. It must be a multiple of 256, and is in fact simply OR-ed to the first instruction byte to get the dispatch table index (aka inst_state).
Current TO-DO:
--------------
diff --git a/docs/source/techspecs/memory.rst b/docs/source/techspecs/memory.rst
index ebdca9646d1..9f0a31758c7 100644
--- a/docs/source/techspecs/memory.rst
+++ b/docs/source/techspecs/memory.rst
@@ -276,6 +276,77 @@ or the view can be disabled using the ``disable`` method. A disabled
view can be re-enabled at any time.
+.. _3.5:
+
+3.5 Bus contention handling
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Some specific CPUs have been upgraded to be interruptible which allows
+to add bus contention and wait states capabitilites. Being
+interruptible means, in practice, that an instruction can be
+interrupted at any time and the execute_run method of the core exited.
+Other devices can then run, then eventually controls returns to the
+core and the instruction continues from the point it was started.
+Importantly, this can be triggered from a handler and even be used to
+interrupt just before the access that is currently done
+(e.g. continuation will redo the access).
+
+The CPUs supporting that declare their capability by overriding the
+method ``cpu_is_interruptible`` to return true.
+
+Three intermediate contention handlers can be added to accesses:
+
+* ``before_delay``: wait a number of cycles before doing the access.
+* ``after_delay``: wait a number of cycles after doing the access.
+* ``before_time``: wait for a given time before doing the access.
+
+For the delay handlers, a method or lambda is called which returns the
+number of cycles to wait (as a u32).
+
+The ``before_time`` is special. First, the time is compared to the
+current value of cpu->total_cycles(). That value is the number of
+cycles elapsed since the last reset of the cpu. It is passed as a
+parameter to the method as a u64 and must return the earliest time as
+a u64 when the access can be done, which can be equal to the passed-in
+time. From there two things can happen: either the running cpu has
+enough cycles left to consume to reach that time. In that case, the
+necessary number of cycles is consumed, and the access is done.
+Otherwise, when there isn't enough, the remaining cycles are consumed,
+the access aborted, scheduling happens, and eventually the access is
+redone. In that case the method is called again with the new current
+time, and must return the (probably same) earliest time again. This
+will happen until enough cycles to consume are available to directly
+do the access.
+
+This approach allows to for instance handle consecutive DMAs. A first
+DMA grabs the bus for a transfer. This shows up as the method
+answering for the earliest time for access the time of the end of the
+dma. If no timer happens until that time the access will then happen
+just after the dma finishes. But if a timer elapses before that and
+as a consequence another dma is queued while the first is running, the
+cycle will be aborted for lack of remaining time, and the method will
+eventually be called again. It will then give the time of when the
+second dma will finish, and all will be well.
+
+It can also allow to reduce said earlier time when circumstances
+require it. For instance a PIO latch that waits up to 64 cycles that
+data arrives can indicate that current time + 64 as a target (which
+will trigger a bus error for instance) but if a timer elapses and
+fills the latch meanwhile the method will be called again and that
+time can just return the current time to let the access pass though.
+Beware that if the timer elapsing did not fill the latch then the
+method must return the time it returned previously, e.g. the initial
+access time + 64, otherwise irrelevant timers happening or simply
+scheduling quantum effects will delay the timeout, possibly to
+infinity if the quantum is small enough.
+
+Contention handlers on the same address are taken into account in the
+``before_time``, ``before_delay`` then ``after_delay`` order.
+Contention handlers of the same type on the same address at
+last-one-wins. Installing any non-contention handler on a range where
+a contention handler was removes it.
+
+
4. Address maps API
-------------------
@@ -292,13 +363,14 @@ The general syntax for entries uses method chaining:
.. code-block:: C++
- map(start, end).handler(...).handler_qualifier(...).range_qualifier();
+ map(start, end).handler(...).handler_qualifier(...).range_qualifier().contention();
The values start and end define the range, the handler() block
determines how the access is handled, the handler_qualifier() block
-specifies some aspects of the handler (memory sharing for instance) and
-the range_qualifier() block refines the range (mirroring, masking, lane
-selection, etc.).
+specifies some aspects of the handler (memory sharing for instance)
+and the range_qualifier() block refines the range (mirroring, masking,
+lane selection, etc.). The contention methods handle bus contention
+and wait states for cpus supporting them.
The map follows a “last one wins” principle, where the handler specified
last is selected when multiple handlers match a given address.
@@ -607,7 +679,20 @@ behaviour. An example of use the i960 which marks burstable zones
that way (they have a specific hardware-level support).
-4.5 View setup
+4.5 Contention
+~~~~~~~~~~~~~~
+
+.. code-block:: C++
+
+ (...).before_time(method).(...)
+ (...).before_delay(method).(...)
+ (...).after_delay(method).(...)
+
+These three methods allow to add the contention methods to a handler.
+See section `3.5`_. Multiple methods can be handler to one handler.
+
+
+4.6 View setup
~~~~~~~~~~~~~~
.. code-block:: C++
@@ -641,6 +726,7 @@ can be installed only once. A view can also be part of “what was there
before”.
+
5. Address space dynamic mapping API
------------------------------------
@@ -803,8 +889,32 @@ with an optional mirror and flags.
Install a device address with an address map in a space. The
``unitmask``, ``cswidth`` and ``flags`` arguments are optional.
-5.9 View installation
-~~~~~~~~~~~~~~~~~~~~~
+5.9 Contention
+~~~~~~~~~~~~~~
+
+.. code-block:: C++
+
+ using ws_time_delegate = device_delegate<u64 (offs_t, u64)>;
+ using ws_delay_delegate = device_delegate<u32 (offs_t)>;
+
+ space.install_read_before_time(addrstart, addrend, addrmirror, ws_time_delegate)
+ space.install_write_before_time(addrstart, addrend, addrmirror, ws_time_delegate)
+ space.install_readwrite_before_time(addrstart, addrend, addrmirror, ws_time_delegate)
+
+ space.install_read_before_delay(addrstart, addrend, addrmirror, ws_delay_delegate)
+ space.install_write_before_delay(addrstart, addrend, addrmirror, ws_delay_delegate)
+ space.install_readwrite_before_delay(addrstart, addrend, addrmirror, ws_delay_delegate)
+
+ space.install_read_after_delay(addrstart, addrend, addrmirror, ws_delay_delegate)
+ space.install_write_after_delay(addrstart, addrend, addrmirror, ws_delay_delegate)
+ space.install_readwrite_after_delay(addrstart, addrend, addrmirror, ws_delay_delegate)
+
+Install a contention handler in the decode path. The addrmirror
+parameter is optional.
+
+
+5.10 View installation
+~~~~~~~~~~~~~~~~~~~~~~
.. code-block:: C++
@@ -820,3 +930,35 @@ by indexing to call a dynamic mapping method on it.
A view can be installed into a variant of another view without issues,
with only the usual constraint of single installation.
+
+5.11 Taps
+~~~~~~~~~
+
+.. code-block:: C++
+
+ using tap = std::function<void (offs_t offset, uNN &data, uNN mem_mask)
+
+ memory_passthrough_handler mph = space.install_read_tap(addrstart, addrend, name, read_tap, &mph);
+ memory_passthrough_handler mph = space.install_write_tap(addrstart, addrend, name, write_tap, &mph);
+ memory_passthrough_handler mph = space.install_readwrite_tap(addrstart, addrend, name, read_tap, write_tap, &mph);
+
+ mph.remove();
+
+A tap is a method that is be called when a specific range of addresses
+is accessed without overriding the actual access. Taps can change the
+data passed around. A write tap happens before the access, and can
+change the value to be written. A read tap happens after the access,
+and can change the value returned.
+
+Taps must be of the same width and alignement than the bus. Multiple
+taps can act over the same addresses.
+
+The ``memory_passthrough_handler`` object collates a number of taps
+and allow to remove them all in one call. The ``mph`` parameter is
+optional and a new one will be created if absent.
+
+Taps are lost when a new handler is installed at the same addresses
+(under the usual principle of last one wins). If they need to be
+preserved, one should install a change notifier on the address space,
+and remove + reinstall the taps when notified.
+
diff --git a/docs/source/techspecs/osd_audio.rst b/docs/source/techspecs/osd_audio.rst
new file mode 100644
index 00000000000..82e03d999ef
--- /dev/null
+++ b/docs/source/techspecs/osd_audio.rst
@@ -0,0 +1,348 @@
+OSD audio support
+=================
+
+Introduction
+------------
+
+The audio support in Mame tries to allow the user to freely map
+between the emulated system audio outputs (called speakers) and the
+host system audio. A part of it is the OSD support, where a
+host-specific module ensures the interface between Mame and the host.
+This is the documentation for that module.
+
+Note: this is currenty output-only, but input should follow.
+
+
+Capabitilies
+------------
+
+The OSD interface is designed to allow three levels of support,
+depending on what the API allows and the amount of effort to expend.
+Those are:
+
+* Level 1: One or more audio targets, only one stream allowed per target
+ (aka exclusive mode)
+* Level 2: One or more audio targets, multiple streams per target
+* Level 3: One or more audio targets, multiple streams per target, user-visible
+ per-stream-channel volume control
+
+In any case we support having the user use an external interface to
+change the target of a stream and, in level 3, change the volumes. By
+support we mean storing the information in the per-game configuration
+and keeping the internal UI in sync.
+
+
+Terminology
+-----------
+
+For this module, we use the terms:
+
+* node: some object we can send audio to. Can be physical, like speakers,
+ or virtual, like an effect system. It should have a unique, user-presentable
+ name for the UI.
+* port: a channel of a node, has a name (non-unique, like "front left") and a
+ 3D position
+* stream: a connection to a node with allows to send audio to it
+
+
+Reference documentation
+-----------------------
+
+Adding a module
+~~~~~~~~~~~~~~~
+
+Adding a module is done by adding a cpp file to src/osd/modules/sound
+which follows this structure,
+
+.. code-block:: C++
+
+ // License/copyright
+ #include "sound_module.h"
+ #include "modules/osdmodules.h"
+
+ #ifdef MODULE_SUPPORT_KEY
+
+ #include "modules/lib/osdobj_common.h"
+
+ // [...]
+ namespace osd {
+ namespace {
+
+ class sound_module_class : public osd_module, public sound_module
+ {
+ sound_module_class() : osd_module(OSD_SOUND_PROVIDER, "module_name"),
+ sound_module()
+ // ...
+ };
+
+ }
+ }
+ #else
+ namespace osd { namespace {
+ MODULE_NOT_SUPPORTED(sound_module_class, OSD_SOUND_PROVIDER, "module_name")
+ }}
+ #endif
+
+ MODULE_DEFINITION(SOUND_MODULE_KEY, osd::sound_module_class)
+
+In that code, four names must be chosen:
+
+* MODULE_SUPPORT_KEY some #define coming from the genie scripts to tell that
+ this particular module can be compiled (like NO_USE_PIPEWIRE or SDLMAME_MACOSX)
+* sound_module_class is the name of the class which makes up the module
+ (like sound_coreaudio)
+* module_name is the name to be used in -sound <xxx> to select that particular
+ module (like coreaudio)
+* SOUND_MODULE_KEY is a symbol that represents the module internally (like
+ SOUND_COREAUDIO)
+
+The file path needs to be added to scripts/src/osd/modules.lua in
+osdmodulesbuild() and the module reference to
+src/osd/modules/lib/osdobj_common.cpp in
+osd_common_t::register_options with the line:
+
+.. code-block:: C++
+
+ REGISTER_MODULE(m_mod_man, SOUND_MODULE_KEY);
+
+This should ensure that the module is reachable through -sound <xxx>
+on the appropriate hosts.
+
+
+Interface
+~~~~~~~~~
+
+The full interface is:
+
+.. code-block:: C++
+
+ virtual bool split_streams_per_source() const override;
+ virtual bool external_per_channel_volume() const override;
+
+ virtual int init(osd_interface &osd, osd_options const &options) override;
+ virtual void exit() override;
+
+ virtual uint32_t get_generation() override;
+ virtual osd::audio_info get_information() override;
+ virtual uint32_t stream_sink_open(uint32_t node, std::string name, uint32_t rate) override;
+ virtual uint32_t stream_source_open(uint32_t node, std::string name, uint32_t rate) override;
+ virtual void stream_set_volumes(uint32_t id, const std::vector<float> &db) override;
+ virtual void stream_close(uint32_t id) override;
+ virtual void stream_sink_update(uint32_t id, const int16_t *buffer, int samples_this_frame) override;
+ virtual void stream_source_update(uint32_t id, int16_t *buffer, int samples_this_frame) override;
+
+
+The class sound_module provides defaults for minimum capabilities: one
+stereo target and stream at default sample rate. To support that,
+only *init*, *exit* and *stream_update* need to be implemented.
+*init* is called at startup and *exit* when quitting and can do
+whatever they need to do. *stream_sink_update* will be called on a
+regular basis with a buffer of sample_this_frame * 2 * int16_t with the
+audio to play. From this point in the documentation we'll assume more
+than a single stereo channel is wanted.
+
+
+Capabilities
+~~~~~~~~~~~~
+
+Two methods are used by the module to indicate the level of capability
+of the module:
+
+* split_streams_per_source() should return true when having multiple streams
+ for one target is expected (e.g. Level 2 or 3)
+* external_per_channel_volume() should return true when the streams have
+ per-channel volume control that can be externally controlled (e.g. Level 3)
+
+
+Hardware information and generations
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The core runs on the assumption that the host hardware capabilities
+can change at any time (bluetooth devices coming and going, usb
+hot-plugging...) and that the module has some way to keep tabs on what
+is happening, possibly using multi-threading. To keep it
+lightweight-ish, we use the concept of a *generation* which is a
+32-bit number that is incremented by the module every time something
+changes. The core checks the current generation value at least once
+every update (once per frame, usually) and if it changed asks for the
+new state and detects and handles the differences. *generation*
+should be "eventually stable", e.g. it eventually stops changing when
+the user stops changing things all the time. A systematic increment
+every frame would be a bad idea.
+
+.. code-block:: C++
+
+ virtual uint32_t get_generation() override;
+
+That method returns the current generation number. It's called at a
+minimum once per update, which usually means per frame. It whould be
+reasonably lightweight when nothing special happens.
+
+.. code-block: C++
+
+ virtual osd::audio_info get_information() override;
+
+ struct audio_rate_range {
+ uint32_t m_default_rate;
+ uint32_t m_min_rate;
+ uint32_t m_max_rate;
+ };
+
+ struct audio_info {
+ struct node_info {
+ std::string m_name;
+ uint32_t m_id;
+ audio_rate_range m_rate;
+ std::vector<std::string> m_port_names;
+ std::vector<std::array<double, 3>> m_port_positions;
+ uint32_t m_sinks;
+ uint32_t m_sources;
+ };
+
+ struct stream_info {
+ uint32_t m_id;
+ uint32_t m_node;
+ std::vector<float> m_volumes;
+ };
+
+ uint32_t m_generation;
+ uint32_t m_default_sink;
+ uint32_t m_default_source;
+ std::vector<node_info> m_nodes;
+ std::vector<stream_info> m_streams;
+ };
+
+This method must provide all the information about the current state
+of the host and the module. This state is:
+
+* m_generation: The current generation number
+* m_nodes: The vector available nodes (*node_info*)
+
+ * m_name: The name of the node
+ * m_id: The numeric ID of the node
+ * m_rate: The minimum, maximum and preferred sample rate for the node
+ * m_port_names: The vector of port names
+ * m_port_positions: The vector of 3D position of the ports. Refer to
+ src/emu/speaker.h for the "standard" positions
+ * m_sinks: Number of sinks (inputs)
+ * m_sources: Number of sources (outputs)
+
+* m_default_sink: ID of the node that is the current "system default" for
+ audio output, 0 if there's no such concept
+* m_default_source: same for audio input (currently unused)
+* m_streams: The vector of active streams (*stream_info*)
+
+ * m_id: The numeric ID of the stream
+ * m_node: The target node of the stream
+ * m_volumes: empty if *external_per_channel_volume* is false, current volume
+ value per-channel otherwise
+
+IDs, for nodes and streams, are (independant) 32-bit unsigned non-zero
+values associated to respectively nodes and streams. IDs should not
+be reused. A node that goes away then comes back should get a new ID.
+A stream closing does not allow reuse of its ID.
+
+If a node has both sources and sinks, the sources are *monitors* of
+the sinks, e.g. they're loopbacks. They should have the same count in
+such a case.
+
+When external control exists, a module should change the value of
+*stream_info::m_node* when the user changes it, and same for
+*stream_info::m_volumes*. Generation number should be incremented
+when this happens, so that the core knows to look for changes.
+
+Volumes are floats in dB, where 0 means 100% and -96 means no sound.
+audio.h provides osd::db_to_linear and osd::linear_to_db if such a
+conversion is needed.
+
+There is an inherent race condition with this system, because things
+can change at any point after returning for the method. The idea is
+that the information returned must be internally consistent (a stream
+should not point to a node ID that does not exist in the structure,
+same for default sink) and that any external change from that state
+should increment the generation number, but that's it. Through the
+generation system the core will eventually be in sync with reality.
+
+
+Input and output streams
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code-block:: C++
+
+ virtual uint32_t stream_sink_open(uint32_t node, std::string name, uint32_t rate) override;
+ virtual uint32_t stream_source_open(uint32_t node, std::string name, uint32_t rate) override;
+ virtual void stream_set_volumes(uint32_t id, const std::vector<float> &db) override;
+ virtual void stream_close(uint32_t id) override;
+ virtual void stream_sink_update(uint32_t id, const int16_t *buffer, int samples_this_frame) override;
+ virtual void stream_source_update(uint32_t id, int16_t *buffer, int samples_this_frame) override;
+
+Streams are the concept used to send or receive audio from/to the host
+audio system. A stream is first opened through *stream_sink_open* for
+speakers and *stream_source_open* for microphones and targets a
+specific node at a specific sample rate. It is given a name for use
+by the host sound services for user UI purposes (currently the game
+name if split_streams_per_source is false, the
+speaker_device/microphone_device tag if true). The returned ID must
+be a non-zero, never-used-before for streams value in case of success.
+Failures, like when the node went away between the *get_information*
+call and the open one, should be silent and return zero.
+
+*stream_set_volumes* is used only when *external_per_channel_volume*
+is true and is used by the core to set the per-channel volume. The
+call should just be ignored if the stream ID does not exist (or is
+zero). Do not try to apply volumes in the module if the host API
+doesn't provide for it, let the core handle it.
+
+*stream_close* closes a stream, The call should just be ignored if the
+stream ID does not exist (or is zero).
+
+Opening a stream, closing a stream or changing the volume does not
+need to touch the generation number.
+
+*stream_sink_update* is the method used to send data to the node
+through a given stream. It provides a buffer of *samples_this_frame*
+* *node channel count* channel-interleaved int16_t values. The
+lifetime of the data in the buffer or the buffer pointer itself is
+undefined after return from the method call. The call should just be
+ignored if the stream ID does not exist (or is zero).
+
+*stream_source_update* is the equivalent to retrieve data from a node,
+writing to the buffer instead of reading from it. The constraints are
+identical.
+
+When a stream goes away because the target node is lost it should just
+be removed from the information, and the core will pick up the node
+departure and close the stream.
+
+Given the assumed raceness of the interface, all the methods should be
+tolerant of obsolete or zero IDs being used by the core, and that is
+why ID reuse must be avoided. Also the update methods and the
+open/close/volume ones may be called at the same time in different
+threads.
+
+
+Helper class *abuffer*
+~~~~~~~~~~~~~~~~~~~~~~
+
+.. code-block:: C++
+
+ class abuffer {
+ public:
+ abuffer(uint32_t channels);
+ void get(int16_t *data, uint32_t samples);
+ void push(const int16_t *data, uint32_t samples);
+ uint32_t channels() const;
+ };
+
+The class *abuffer* is a helper provided by *sound_module* to buffer
+audio input or output. It automatically drops data when there is
+an overflow and duplicates the last sample on underflow. It must
+first be initialized with the number of channels, which can be
+retrieved with *channels()* if needed. *push* sends
+*samples* * *channels* 16-bit samples in the buffer. *get* retrieves
+*samples* * *channels* 16-bit samples from the buffer, on a FIFO basis.
+
+It is not protected against multithreading, but uses no class
+variables. So just don't read and write from one specific abuffer
+instance at the same time. The system sound interface mandated
+locking should be enough to ensure that.
diff --git a/docs/source/techspecs/uml_instructions.rst b/docs/source/techspecs/uml_instructions.rst
new file mode 100644
index 00000000000..5d379dd1c60
--- /dev/null
+++ b/docs/source/techspecs/uml_instructions.rst
@@ -0,0 +1,1582 @@
+.. _umlinst:
+
+UML Instruction Reference
+=========================
+
+.. contents::
+ :local:
+ :depth: 2
+
+
+.. _umlinst-intro:
+
+Introduction
+------------
+
+UML is the instruction set used by MAME’s recompiler framework.
+Front-ends translate code running on the guest CPUs to UML instructions,
+and back-ends convert the UML instructions to a form that can be
+executed or interpreted on the host system.
+
+
+.. _umlinst-flow:
+
+Flow control
+------------
+
+.. _umlinst-comment:
+
+COMMENT
+~~~~~~~
+
+Insert a comment into logged UML code.
+
++--------------------+---------------------------------+
+| Disassembly | Usage |
++====================+=================================+
+| .. code-block:: | .. code-block:: C++ |
+| | |
+| comment string | UML_COMMENT(block, string); |
++--------------------+---------------------------------+
+
+Operands
+^^^^^^^^
+
+string
+ The comment text as a pointer to a NUL-terminated string. This must
+ remain valid until code is generated for the block.
+
+Flags
+^^^^^
+
++---------------+------------+
+| carry (C) | Unchanged. |
++---------------+------------+
+| overflow (V) | Unchanged. |
++---------------+------------+
+| zero (Z) | Unchanged. |
++---------------+------------+
+| sign (S) | Unchanged. |
++---------------+------------+
+| unordered (U) | Unchanged. |
++---------------+------------+
+
+.. _umlinst-nop:
+
+NOP
+~~~
+
+No operation.
+
++-----------------+---------------------+
+| Disassembly | Usage |
++=================+=====================+
+| .. code-block:: | .. code-block:: C++ |
+| | |
+| nop | UML_NOP(block); |
++-----------------+---------------------+
+
+Flags
+^^^^^
+
++---------------+------------+
+| carry (C) | Unchanged. |
++---------------+------------+
+| overflow (V) | Unchanged. |
++---------------+------------+
+| zero (Z) | Unchanged. |
++---------------+------------+
+| sign (S) | Unchanged. |
++---------------+------------+
+| unordered (U) | Unchanged. |
++---------------+------------+
+
+.. _umlinst-label:
+
+LABEL
+~~~~~
+
+Associate a location with a label number local to the current generated
+code block. Label numbers must not be reused within a generated code
+block. The :ref:`JMP <umlinst-jmp>` instruction may be used to transfer
+control to the location associated with a label number.
+
++-------------------+------------------------------+
+| Disassembly | Usage |
++===================+==============================+
+| .. code-block:: | .. code-block:: C++ |
+| | |
+| label label | UML_LABEL(block, label); |
++-------------------+------------------------------+
+
+Operands
+^^^^^^^^
+
+label (label number)
+ The label number to associate with the current location. A label
+ number must not be used more than once within a generated code
+ block.
+
+Flags
+^^^^^
+
++---------------+------------+
+| carry (C) | Unchanged. |
++---------------+------------+
+| overflow (V) | Unchanged. |
++---------------+------------+
+| zero (Z) | Unchanged. |
++---------------+------------+
+| sign (S) | Unchanged. |
++---------------+------------+
+| unordered (U) | Unchanged. |
++---------------+------------+
+
+.. _umlinst-handle:
+
+HANDLE
+~~~~~~
+
+Mark a location as an entry point of a subroutine. Subroutines may be
+called using the :ref:`CALLH <umlinst-callh>` and :ref:`EXH
+<umlinst-exh>` instructions, and also by the `HASHJMP <umlinst-hashjmp>`
+if no location is associated with the specified mode and emulated
+program counter.
+
++--------------------+--------------------------------+
+| Disassembly | Usage |
++====================+================================+
+| .. code-block:: | .. code-block:: C++ |
+| | |
+| handle handle | UML_HANDLE(block, handle); |
++--------------------+--------------------------------+
+
+Operands
+^^^^^^^^
+
+handle (code handle)
+ The code handle to bind to the current location. The handle must
+ already be allocated, and must not have been bound since the last
+ generated code reset (all handles are implicitly unbound when
+ resetting the generated code cache).
+
+Flags
+^^^^^
+
++---------------+------------+
+| carry (C) | Unchanged. |
++---------------+------------+
+| overflow (V) | Unchanged. |
++---------------+------------+
+| zero (Z) | Unchanged. |
++---------------+------------+
+| sign (S) | Unchanged. |
++---------------+------------+
+| unordered (U) | Unchanged. |
++---------------+------------+
+
+.. _umlinst-hash:
+
+HASH
+~~~~
+
+Associate a location with the specified mode and emulated program
+counter values. The :ref:`HASHJMP <umlinst-hashjmp>` instruction may be
+used to transfer control to the location associated with a mode and
+emulated program counter value.
+
+This is usually used to mark the location of the generated code for an
+emulated instruction or sequence of instructions.
+
++---------------------+------------------------------+
+| Disassembly | Usage |
++=====================+==============================+
+| .. code-block:: | .. code-block:: C++ |
+| | |
+| hash mode,pc | UML_HASH(block, mode, pc); |
++---------------------+------------------------------+
+
+Operands
+^^^^^^^^
+
+mode (32-bit – immediate, map variable)
+ The mode to associate with the current location in the generated
+ code. Must be greater than or equal to zero and less than the
+ number of modes specified when creating the recompiler context.
+pc (32-bit – immediate, map variable)
+ The emulated program counter value to associate with the current
+ location in the generated code.
+
+Flags
+^^^^^
+
++---------------+------------+
+| carry (C) | Unchanged. |
++---------------+------------+
+| overflow (V) | Unchanged. |
++---------------+------------+
+| zero (Z) | Unchanged. |
++---------------+------------+
+| sign (S) | Unchanged. |
++---------------+------------+
+| unordered (U) | Unchanged. |
++---------------+------------+
+
+.. _umlinst-jmp:
+
+JMP
+~~~
+
+Jump to the location associated with a label number within the current
+block.
+
++------------------------+-----------------------------------+
+| Disassembly | Usage |
++========================+===================================+
+| .. code-block:: | .. code-block:: C++ |
+| | |
+| jmp label | UML_JMP(block, label); |
+| jmp label,cond | UML_JMPc(block, cond, label); |
++------------------------+-----------------------------------+
+
+Operands
+^^^^^^^^
+
+label (label number)
+ The label number associated with the location to jump to in the
+ current generated code block. The label number must be associated
+ with a location in the generated code block before the block is
+ finalised.
+cond (condition)
+ If supplied, a condition that must be met to jump to the specified
+ label. If the condition is not met, execution will continue with
+ the following instruction.
+
+Flags
+^^^^^
+
++---------------+------------+
+| carry (C) | Unchanged. |
++---------------+------------+
+| overflow (V) | Unchanged. |
++---------------+------------+
+| zero (Z) | Unchanged. |
++---------------+------------+
+| sign (S) | Unchanged. |
++---------------+------------+
+| unordered (U) | Unchanged. |
++---------------+------------+
+
+.. _umlinst-callh:
+
+CALLH
+~~~~~
+
+Call the subroutine beginning at the specified code handle.
+
++-------------------------+--------------------------------------+
+| Disassembly | Usage |
++=========================+======================================+
+| .. code-block:: | .. code-block:: C++ |
+| | |
+| callh handle | UML_CALLH(block, handle); |
+| callh handle,cond | UML_CALLHc(block, handle, cond); |
++-------------------------+--------------------------------------+
+
+Operands
+^^^^^^^^
+
+handle (code handle)
+ Handle located at the entry point of the subroutine to call. The
+ handle must already be allocated but does not need to be bound until
+ the instruction is executed. Calling a handle that was unbound at
+ code generation time may produce less efficient code than calling a
+ handle that was already bound.
+cond (condition)
+ If supplied, a condition that must be met for the subroutine to be
+ called. If the condition is not met, the subroutine will not be
+ called.
+
+Flags
+^^^^^
+
++---------------+------------+
+| carry (C) | Unchanged. |
++---------------+------------+
+| overflow (V) | Unchanged. |
++---------------+------------+
+| zero (Z) | Unchanged. |
++---------------+------------+
+| sign (S) | Unchanged. |
++---------------+------------+
+| unordered (U) | Unchanged. |
++---------------+------------+
+
+.. _umlinst-exh:
+
+EXH
+~~~
+
+Set the ``EXP`` register and call the subroutine beginning at the
+specified code handle. The ``EXP`` register is a 32-bit special
+function register that may be retrieved with the :ref:`GETEXP
+<umlinst-getexp>` instruction.
+
++-----------------------------+-----------------------------------------+
+| Disassembly | Usage |
++=============================+=========================================+
+| .. code-block:: | .. code-block:: C++ |
+| | |
+| exh handle,arg | UML_EXH(block, handle, arg); |
+| exh handle,arg,cond | UML_EXHc(block, handle, arg, cond); |
++-----------------------------+-----------------------------------------+
+
+Operands
+^^^^^^^^
+
+handle (code handle)
+ Handle located at the entry point of the subroutine to call. The
+ handle must already be allocated but does not need to be bound until
+ the instruction is executed. Calling a handle that was unbound at
+ code generation time may produce less efficient code than calling a
+ handle that was already bound.
+arg (32-bit – memory, integer register, immediate, map variable)
+ Value to store in the ``EXP`` register.
+cond (condition)
+ If supplied, a condition that must be met for the subroutine to be
+ called. If the condition is not met, the subroutine will not be
+ called and the ``EXP`` register will not be modified.
+
+Flags
+^^^^^
+
++---------------+------------+
+| carry (C) | Unchanged. |
++---------------+------------+
+| overflow (V) | Unchanged. |
++---------------+------------+
+| zero (Z) | Unchanged. |
++---------------+------------+
+| sign (S) | Unchanged. |
++---------------+------------+
+| unordered (U) | Unchanged. |
++---------------+------------+
+
+Simplification rules
+^^^^^^^^^^^^^^^^^^^^
+
+* Immediate values for the ``arg`` operand are truncated to 32 bits.
+
+.. _umlinst-ret:
+
+RET
+~~~
+
+Return from a subroutine, transferring control to the instruction
+following the :ref:`CALLH <umlinst-callh>` or :ref:`EXH <umlinst-exh>`
+instruction used to call the subroutine. This instruction must only be
+used within generated code subroutines. The :ref:`EXIT <umlinst-exit>`
+instruction must be used to exit from the generated code.
+
++------------------+----------------------------+
+| Disassembly | Usage |
++==================+============================+
+| .. code-block:: | .. code-block:: C++ |
+| | |
+| ret | UML_RET(block); |
+| ret cond | UML_RETc(block, cond); |
++------------------+----------------------------+
+
+Operands
+^^^^^^^^
+
+cond (condition)
+ If supplied, a condition that must be met to return from the
+ subroutine. If the condition is not met, execution will continue
+ with the following instruction.
+
+Flags
+^^^^^
+
++---------------+------------+
+| carry (C) | Unchanged. |
++---------------+------------+
+| overflow (V) | Unchanged. |
++---------------+------------+
+| zero (Z) | Unchanged. |
++---------------+------------+
+| sign (S) | Unchanged. |
++---------------+------------+
+| unordered (U) | Unchanged. |
++---------------+------------+
+
+.. _umlinst-hashjmp:
+
+HASHJMP
+~~~~~~~
+
+Unwind all nested generated code subroutine frames and transfer control
+to the location associated with the specified mode and emulated program
+counter values. If no location is associated with the specified mode
+and program counter values, call the subroutine beginning at the
+specified code handle. Note that all nested generated code subroutine
+frames are unwound in either case.
+
+This is usually used to jump to the generated code corresponding to the
+emulated code at a particular address when it is not known to be in the
+current generated code block or when the mode changes.
+
++----------------------------+-----------------------------------------+
+| Disassembly | Usage |
++============================+=========================================+
+| .. code-block:: | .. code-block:: C++ |
+| | |
+| hashjmp mode,pc,handle | UML_HASHJMP(block, mode, pc, handle); |
++----------------------------+-----------------------------------------+
+
+Operands
+^^^^^^^^
+
+mode (32-bit – memory, integer register, immediate, map variable)
+ The mode associated with the location in the generated code to
+ transfer control to. Must be greater than or equal to zero and less
+ than the number of modes specified when creating the recompiler
+ context.
+pc (32-bit – memory, integer register, immediate, map variable)
+ The emulated program counter value associated with the location in
+ the generated code to transfer control to.
+handle (code handle)
+ Handle located at the entry point of the subroutine to call if no
+ location in the generated code is associated with the specified mode
+ and emulated program counter values. The handle must already be
+ allocated but does not need to be bound until the instruction is
+ executed. Calling a handle that was unbound at code generation time
+ may produce less efficient code than calling a handle that was
+ already bound.
+
+Flags
+^^^^^
+
++---------------+------------+
+| carry (C) | Undefined. |
++---------------+------------+
+| overflow (V) | Undefined. |
++---------------+------------+
+| zero (Z) | Undefined. |
++---------------+------------+
+| sign (S) | Undefined. |
++---------------+------------+
+| unordered (U) | Undefined. |
++---------------+------------+
+
+.. _umlinst-exit:
+
+EXIT
+~~~~
+
+Exit from the generated code, returning control to the caller. May be
+used from within any level of nested subroutine calls in the generated
+code.
+
++-----------------------+----------------------------------+
+| Disassembly | Usage |
++=======================+==================================+
+| .. code-block:: | .. code-block:: C++ |
+| | |
+| exit arg, | UML_EXIT(block, arg); |
+| exit arg,,cond | UML_EXITc(block, arg, cond); |
++-----------------------+----------------------------------+
+
+Operands
+^^^^^^^^
+
+arg (32-bit – memory, integer register, immediate, map variable)
+ The value to return to the caller.
+cond (condition)
+ If supplied, a condition that must be met to exit from the generated
+ code. If the condition is not met, execution will continue with the
+ following instruction.
+
+Flags
+^^^^^
+
++---------------+------------+
+| carry (C) | Unchanged. |
++---------------+------------+
+| overflow (V) | Unchanged. |
++---------------+------------+
+| zero (Z) | Unchanged. |
++---------------+------------+
+| sign (S) | Unchanged. |
++---------------+------------+
+| unordered (U) | Unchanged. |
++---------------+------------+
+
+Simplification rules
+^^^^^^^^^^^^^^^^^^^^
+
+* Immediate values for the ``arg`` operand are truncated to 32 bits.
+
+.. _umlinst-callc:
+
+CALLC
+~~~~~
+
+Call a C function with the signature ``void (*)(void *)``.
+
++---------------------------+-----------------------------------------+
+| Disassembly | Usage |
++===========================+=========================================+
+| .. code-block:: | .. code-block:: C++ |
+| | |
+| callc func,arg | UML_CALLC(block, func, arg); |
+| callc func,arg,cond | UML_CALLCc(block, func, arg, cond); |
++---------------------------+-----------------------------------------+
+
+Operands
+^^^^^^^^
+
+func (C function)
+ Function pointer to the function to call.
+arg (memory)
+ Argument to pass to the function.
+cond (condition)
+ If supplied, a condition that must be met for the function to be
+ called. If the condition is not met, the function will not be
+ called.
+
+Flags
+^^^^^
+
++---------------+------------+
+| carry (C) | Undefined. |
++---------------+------------+
+| overflow (V) | Undefined. |
++---------------+------------+
+| zero (Z) | Undefined. |
++---------------+------------+
+| sign (S) | Undefined. |
++---------------+------------+
+| unordered (U) | Undefined. |
++---------------+------------+
+
+.. _umlinst-debug:
+
+DEBUG
+~~~~~
+
+Call the debugger instruction hook function if appropriate.
+
+If the debugger is active, this should be executed before each emulated
+instruction. Any emulated CPU state kept in UML registers should be
+flushed to memory before executing this instruction and reloaded
+afterwards to ensure the debugger can display and modify values
+correctly.
+
++-----------------+---------------------------+
+| Disassembly | Usage |
++=================+===========================+
+| .. code-block:: | .. code-block:: C++ |
+| | |
+| debug pc | UML_DEBUG(block, pc); |
++-----------------+---------------------------+
+
+Operands
+^^^^^^^^
+
+pc (32-bit – memory, integer register, immediate, map variable)
+ The emulated program counter value to supply to the debugger
+ instruction hook function.
+
+Flags
+^^^^^
+
++---------------+------------+
+| carry (C) | Undefined. |
++---------------+------------+
+| overflow (V) | Undefined. |
++---------------+------------+
+| zero (Z) | Undefined. |
++---------------+------------+
+| sign (S) | Undefined. |
++---------------+------------+
+| unordered (U) | Undefined. |
++---------------+------------+
+
+Simplification rules
+^^^^^^^^^^^^^^^^^^^^
+
+* Immediate values for the ``pc`` operand are truncated to 32 bits.
+
+.. _umlinst-break:
+
+BREAK
+~~~~~
+
+Break into the host debugger if attached. Has no effect or crashes if
+no host debugger is attached depending on the host system and
+configuration. This is intended as a developer aid and should not be
+left in final code.
+
++-----------------+-----------------------+
+| Disassembly | Usage |
++=================+=======================+
+| .. code-block:: | .. code-block:: C++ |
+| | |
+| break | UML_BREAK(block); |
++-----------------+-----------------------+
+
+Flags
+^^^^^
+
++---------------+------------+
+| carry (C) | Undefined. |
++---------------+------------+
+| overflow (V) | Undefined. |
++---------------+------------+
+| zero (Z) | Undefined. |
++---------------+------------+
+| sign (S) | Undefined. |
++---------------+------------+
+| unordered (U) | Undefined. |
++---------------+------------+
+
+
+.. _umlinst-datamove:
+
+Data movement
+-------------
+
+.. _umlinst-mov:
+
+MOV
+~~~
+
+Copy an integer value.
+
++--------------------------+---------------------------------------+
+| Disassembly | Usage |
++==========================+=======================================+
+| .. code-block:: | .. code-block:: C++ |
+| | |
+| mov dst,src | UML_MOV(block, dst, src); |
+| mov dst,src,cond | UML_MOVc(block, cond, dst, src); |
+| dmov dst,src | UML_DMOV(block, dst, src); |
+| dmov dst,src,cond | UML_DMOVc(block, cond, dst, src); |
++--------------------------+---------------------------------------+
+
+Operands
+^^^^^^^^
+
+dst (32-bit or 64-bit – memory, integer register)
+ The destination where the value will be copied to.
+src (32-bit or 64-bit – memory, integer register, immediate, map variable)
+ The source value to copy.
+cond (condition)
+ If supplied, a condition that must be met to copy the value. If the
+ condition is not met, the instruction will have no effect.
+
+Flags
+^^^^^
+
++---------------+------------+
+| carry (C) | Unchanged. |
++---------------+------------+
+| overflow (V) | Unchanged. |
++---------------+------------+
+| zero (Z) | Unchanged. |
++---------------+------------+
+| sign (S) | Unchanged. |
++---------------+------------+
+| unordered (U) | Unchanged. |
++---------------+------------+
+
+Simplification rules
+^^^^^^^^^^^^^^^^^^^^
+
+* Immediate values for the ``src`` operand are truncated to the
+ instruction size.
+* Converted to :ref:`NOP <umlinst-nop>` if the ``src`` and ``dst``
+ operands refer to the same memory location or register and the
+ instruction size is no larger than the destination size.
+
+.. _umlinst-fmov:
+
+FMOV
+~~~~
+
+Copy a floating point value. The binary value will be preserved even if
+it is not a valid representation of a floating point number.
+
++--------------------------+----------------------------------------+
+| Disassembly | Usage |
++==========================+========================================+
+| .. code-block:: | .. code-block:: C++ |
+| | |
+| fsmov dst,src | UML_FSMOV(block, dst, src); |
+| fsmov dst,src,cond | UML_FSMOVc(block, cond, dst, src); |
+| fdmov dst,src | UML_FDMOV(block, dst, src); |
+| fdmov dst,src,cond | UML_FDMOVc(block, cond, dst, src); |
++--------------------------+----------------------------------------+
+
+Operands
+^^^^^^^^
+
+dst (32-bit or 64-bit – memory, floating point register)
+ The destination where the value will be copied to.
+src (32-bit or 64-bit – memory, floating point register)
+ The source value to copy.
+cond (condition)
+ If supplied, a condition that must be met to copy the value. If the
+ condition is not met, the instruction will have no effect.
+
+Flags
+^^^^^
+
++---------------+------------+
+| carry (C) | Unchanged. |
++---------------+------------+
+| overflow (V) | Unchanged. |
++---------------+------------+
+| zero (Z) | Unchanged. |
++---------------+------------+
+| sign (S) | Unchanged. |
++---------------+------------+
+| unordered (U) | Unchanged. |
++---------------+------------+
+
+Simplification rules
+^^^^^^^^^^^^^^^^^^^^
+
+* Converted to :ref:`NOP <umlinst-nop>` if the ``src`` and ``dst``
+ operands refer to the same memory location or register.
+
+.. _umlinst-fcopyi:
+
+FCOPYI
+~~~~~~
+
+Reinterpret an integer value as a floating point value. The binary
+value will be preserved even if it is not a valid representation of a
+floating point number.
+
++---------------------+-----------------------------------+
+| Disassembly | Usage |
++=====================+===================================+
+| .. code-block:: | .. code-block:: C++ |
+| | |
+| fscopyi dst,src | UML_FSCOPYI(block, dst, src); |
+| fdcopyi dst,src | UML_FDCOPYI(block, dst, src); |
++---------------------+-----------------------------------+
+
+Operands
+^^^^^^^^
+
+dst (32-bit or 64-bit – memory, floating point register)
+ The destination where the value will be copied to.
+src (32-bit or 64-bit – memory, integer register)
+ The source value to copy.
+
+Flags
+^^^^^
+
++---------------+------------+
+| carry (C) | Unchanged. |
++---------------+------------+
+| overflow (V) | Unchanged. |
++---------------+------------+
+| zero (Z) | Unchanged. |
++---------------+------------+
+| sign (S) | Unchanged. |
++---------------+------------+
+| unordered (U) | Unchanged. |
++---------------+------------+
+
+.. _umlinst-icopyf:
+
+ICOPYF
+~~~~~~
+
+Reinterpret a floating point value as an integer value. The binary
+value will be preserved even if it is not a valid representation of a
+floating point number.
+
++---------------------+-----------------------------------+
+| Disassembly | Usage |
++=====================+===================================+
+| .. code-block:: | .. code-block:: C++ |
+| | |
+| icopyfs dst,src | UML_ICOPYFS(block, dst, src); |
+| icopyfd dst,src | UML_ICOPYFD(block, dst, src); |
++---------------------+-----------------------------------+
+
+Operands
+^^^^^^^^
+
+dst (32-bit or 64-bit – memory, integer register)
+ The destination where the value will be copied to.
+src (32-bit or 64-bit – memory, floating point register)
+ The source value to copy.
+
+Flags
+^^^^^
+
++---------------+------------+
+| carry (C) | Unchanged. |
++---------------+------------+
+| overflow (V) | Unchanged. |
++---------------+------------+
+| zero (Z) | Unchanged. |
++---------------+------------+
+| sign (S) | Unchanged. |
++---------------+------------+
+| unordered (U) | Unchanged. |
++---------------+------------+
+
+.. _umlinst-load:
+
+LOAD
+~~~~
+
+Load an unsigned integer value from a memory location with variable
+displacement. The value is zero-extended to the size of the
+destination. Host system rules for integer alignment must be followed.
+
++---------------------------------------+------------------------------------------------------+
+| Disassembly | Usage |
++=======================================+======================================================+
+| .. code-block:: | .. code-block:: C++ |
+| | |
+| load dst,base,index,size_scale | UML_LOAD(block, dst, base, index, size, scale); |
+| dload dst,base,index,size_scale | UML_DLOAD(block, dst, base, index, size, scale); |
++---------------------------------------+------------------------------------------------------+
+
+Operands
+^^^^^^^^
+
+dst (32-bit or 64-bit – memory, integer register)
+ The destination where the value read from memory will be stored.
+base (memory)
+ The base address of the area of memory to read from.
+index (32-bit – memory, integer register, immediate, map variable)
+ The displacement value added to the base address to calculate the
+ address to read from. This value may be scaled by a factor of 1, 2,
+ 4 or 8 depending on the ``scale`` operand. Note that this is always
+ a 32-bit operand interpreted as a signed integer, irrespective of
+ the instruction size.
+size (access size)
+ The size of the value to read. Must be ``SIZE_BYTE`` (8-bit),
+ ``SIZE_WORD`` (16-bit), ``SIZE_DWORD`` (32-bit) or ``SIZE_QWORD``
+ (64-bit). Note that this operand controls the size of the value
+ read from memory while the instruction size sets the size of the
+ ``dst`` operand.
+scale (index scale)
+ The scale factor to apply to the ``index`` operand. Must be
+ ``SCALE_x1``, ``SCALE_x2``, ``SCALE_x4`` or ``SCALE_x8`` to multiply
+ by 1, 2, 4 or 8, respectively (shift left by 0, 1, 2 or 3 bits).
+
+Flags
+^^^^^
+
++---------------+------------+
+| carry (C) | Unchanged. |
++---------------+------------+
+| overflow (V) | Unchanged. |
++---------------+------------+
+| zero (Z) | Unchanged. |
++---------------+------------+
+| sign (S) | Unchanged. |
++---------------+------------+
+| unordered (U) | Unchanged. |
++---------------+------------+
+
+.. _umlinst-loads:
+
+LOADS
+~~~~~
+
+Load a signed integer value from a memory location with variable
+displacement. The value is sign-extended to the size of the
+destination. Host system rules for integer alignment must be followed.
+
++---------------------------------------+-------------------------------------------------------+
+| Disassembly | Usage |
++=======================================+=======================================================+
+| .. code-block:: | .. code-block:: C++ |
+| | |
+| loads dst,base,index,size_scale | UML_LOADS(block, dst, base, index, size, scale); |
+| dloads dst,base,index,size_scale | UML_DLOADS(block, dst, base, index, size, scale); |
++---------------------------------------+-------------------------------------------------------+
+
+Operands
+^^^^^^^^
+
+dst (32-bit or 64-bit – memory, integer register)
+ The destination where the value read from memory will be stored.
+base (memory)
+ The base address of the area of memory to read from.
+index (32-bit – memory, integer register, immediate, map variable)
+ The displacement value added to the base address to calculate the
+ address to read from. This value may be scaled by a factor of 1, 2,
+ 4 or 8 depending on the ``scale`` operand. Note that this is always
+ a 32-bit operand interpreted as a signed integer, irrespective of
+ the instruction size.
+size (access size)
+ The size of the value to read. Must be ``SIZE_BYTE`` (8-bit),
+ ``SIZE_WORD`` (16-bit), ``SIZE_DWORD`` (32-bit) or ``SIZE_QWORD``
+ (64-bit). Note that this operand controls the size of the value
+ read from memory while the instruction size sets the size of the
+ ``dst`` operand.
+scale (index scale)
+ The scale factor to apply to the ``index`` operand. Must be
+ ``SCALE_x1``, ``SCALE_x2``, ``SCALE_x4`` or ``SCALE_x8`` to multiply
+ by 1, 2, 4 or 8, respectively (shift left by 0, 1, 2 or 3 bits).
+
+Flags
+^^^^^
+
++---------------+------------+
+| carry (C) | Unchanged. |
++---------------+------------+
+| overflow (V) | Unchanged. |
++---------------+------------+
+| zero (Z) | Unchanged. |
++---------------+------------+
+| sign (S) | Unchanged. |
++---------------+------------+
+| unordered (U) | Unchanged. |
++---------------+------------+
+
+.. _umlinst-store:
+
+STORE
+~~~~~
+
+Store an integer value to a location in memory with variable
+displacement. Host system rules for integer alignment must be followed.
+
++---------------------------------------+-------------------------------------------------------+
+| Disassembly | Usage |
++=======================================+=======================================================+
+| .. code-block:: | .. code-block:: C++ |
+| | |
+| store base,index,src,size_scale | UML_STORE(block, base, index, src, size, scale); |
+| dstore base,index,src,size_scale | UML_DSTORE(block, base, index, src, size, scale); |
++---------------------------------------+-------------------------------------------------------+
+
+Operands
+^^^^^^^^
+
+base (memory)
+ The base address of the area of memory to write to.
+index (32-bit – memory, integer register, immediate, map variable)
+ The displacement value added to the base address to calculate the
+ address to write to. This value may be scaled by a factor of 1, 2,
+ 4 or 8 depending on the ``scale`` operand. Note that this is always
+ a 32-bit operand interpreted as a signed integer, irrespective of
+ the instruction size.
+src (32-bit or 64-bit – memory, integer register, immediate, map variable)
+ The value to write to memory.
+size (access size)
+ The size of the value to write. Must be ``SIZE_BYTE`` (8-bit),
+ ``SIZE_WORD`` (16-bit), ``SIZE_DWORD`` (32-bit) or ``SIZE_QWORD``
+ (64-bit). Note that this operand controls the size of the value
+ written to memory while the instruction size sets the size of the
+ ``src`` operand.
+scale (index scale)
+ The scale factor to apply to the ``index`` operand. Must be
+ ``SCALE_x1``, ``SCALE_x2``, ``SCALE_x4`` or ``SCALE_x8`` to multiply
+ by 1, 2, 4 or 8, respectively (shift left by 0, 1, 2 or 3 bits).
+
+Flags
+^^^^^
+
++---------------+------------+
+| carry (C) | Unchanged. |
++---------------+------------+
+| overflow (V) | Unchanged. |
++---------------+------------+
+| zero (Z) | Unchanged. |
++---------------+------------+
+| sign (S) | Unchanged. |
++---------------+------------+
+| unordered (U) | Unchanged. |
++---------------+------------+
+
+.. _umlinst-fload:
+
+FLOAD
+~~~~~
+
+Load a floating point value from a memory location with variable
+displacement. The binary value will be preserved even if it is not a
+valid representation of a floating point number. Host system rules for
+memory access alignment must be followed.
+
++----------------------------+------------------------------------------+
+| Disassembly | Usage |
++============================+==========================================+
+| .. code-block:: | .. code-block:: C++ |
+| | |
+| fsload dst,base,index | UML_FSLOAD(block, dst, base, index); |
+| fdload dst,base,index | UML_FDLOAD(block, dst, base, index); |
++----------------------------+------------------------------------------+
+
+Operands
+^^^^^^^^
+
+dst (32-bit or 64-bit – memory, floating point register)
+ The destination where the value read from memory will be stored.
+base (memory)
+ The base address of the area of memory to read from.
+index (32-bit – memory, integer register, immediate, map variable)
+ The displacement value added to the base address to calculate the
+ address to read from. This value will be scaled by the instruction
+ size (multiplied by 4 or 8). Note that this is always a 32-bit
+ operand interpreted as a signed integer, irrespective of the
+ instruction size.
+
+Flags
+^^^^^
+
++---------------+------------+
+| carry (C) | Unchanged. |
++---------------+------------+
+| overflow (V) | Unchanged. |
++---------------+------------+
+| zero (Z) | Unchanged. |
++---------------+------------+
+| sign (S) | Unchanged. |
++---------------+------------+
+| unordered (U) | Unchanged. |
++---------------+------------+
+
+.. _umlinst-fstore:
+
+FSTORE
+~~~~~~
+
+Store a floating point value to a memory location with variable
+displacement. The binary value will be preserved even if it is not a
+valid representation of a floating point number. Host system rules for
+memory access alignment must be followed.
+
++----------------------------+-------------------------------------------+
+| Disassembly | Usage |
++============================+===========================================+
+| .. code-block:: | .. code-block:: C++ |
+| | |
+| fsstore base,index,src | UML_FSSTORE(block, base, index, src); |
+| fdstore base,index,src | UML_FDSTORE(block, base, index, src); |
++----------------------------+-------------------------------------------+
+
+Operands
+^^^^^^^^
+
+base (memory)
+ The base address of the area of memory to write to.
+index (32-bit – memory, integer register, immediate, map variable)
+ The displacement value added to the base address to calculate the
+ address to write to. This value will be scaled by the instruction
+ size (multiplied by 4 or 8). Note that this is always a 32-bit
+ operand interpreted as a signed integer, irrespective of the
+ instruction size.
+src (32-bit or 64-bit – memory, floating point register)
+ The value to write to memory.
+
+Flags
+^^^^^
+
++---------------+------------+
+| carry (C) | Unchanged. |
++---------------+------------+
+| overflow (V) | Unchanged. |
++---------------+------------+
+| zero (Z) | Unchanged. |
++---------------+------------+
+| sign (S) | Unchanged. |
++---------------+------------+
+| unordered (U) | Unchanged. |
++---------------+------------+
+
+.. _umlinst-getexp:
+
+GETEXP
+~~~~~~
+
+Copy the value of the ``EXP`` register. The ``EXP`` register can be set
+using the :ref:`EXH <umlinst-exh>` instruction.
+
++-----------------+-----------------------------+
+| Disassembly | Usage |
++=================+=============================+
+| .. code-block:: | .. code-block:: C++ |
+| | |
+| getexp dst | UML_GETEXP(block, dst); |
++-----------------+-----------------------------+
+
+Operands
+^^^^^^^^
+
+dst (32-bit – memory, integer register)
+ The destination to copy the value of the ``EXP`` register to. Note
+ that the ``EXP`` register can only hold a 32-bit value.
+
+Flags
+^^^^^
+
++---------------+------------+
+| carry (C) | Unchanged. |
++---------------+------------+
+| overflow (V) | Unchanged. |
++---------------+------------+
+| zero (Z) | Unchanged. |
++---------------+------------+
+| sign (S) | Unchanged. |
++---------------+------------+
+| unordered (U) | Unchanged. |
++---------------+------------+
+
+.. _umlinst-mapvar:
+
+MAPVAR
+~~~~~~
+
+Set the value of a map variable starting at the current location in the
+current generated code block.
+
++--------------------------+---------------------------------------+
+| Disassembly | Usage |
++==========================+=======================================+
+| .. code-block:: | .. code-block:: C++ |
+| | |
+| mapvar mapvar,value | UML_MAPVAR(block, mapvar, value); |
++--------------------------+---------------------------------------+
+
+Operands
+^^^^^^^^
+
+mapvar (map variable)
+ The map variable to set the value of.
+value (32-bit – immediate, map variable)
+ The value to set the map variable to. Note that map variables can
+ only hold 32-bit values.
+
+Flags
+^^^^^
+
++---------------+------------+
+| carry (C) | Unchanged. |
++---------------+------------+
+| overflow (V) | Unchanged. |
++---------------+------------+
+| zero (Z) | Unchanged. |
++---------------+------------+
+| sign (S) | Unchanged. |
++---------------+------------+
+| unordered (U) | Unchanged. |
++---------------+------------+
+
+.. _umlinst-recover:
+
+RECOVER
+~~~~~~~
+
+Retrieve the value of a map variable at the location of the call
+instruction in the outermost generated code frame. This instruction
+should only be used from within a generated code subroutine. Results
+are undefined if this instruction is executed from outside any
+generated code subroutines.
+
++------------------------+--------------------------------------+
+| Disassembly | Usage |
++========================+======================================+
+| .. code-block:: | .. code-block:: C++ |
+| | |
+| recover dst,mapvar | UML_RECOVER(block, dst, mapvar); |
++------------------------+--------------------------------------+
+
+Operands
+^^^^^^^^
+
+dst (32-bit – memory, integer register)
+ The destination to copy the value of the map variable to. Note that
+ map variables can only hold 32-bit values.
+mapvar (map variable)
+ The map variable to retrieve the value of from the outermost
+ generated code frame.
+
+Flags
+^^^^^
+
++---------------+------------+
+| carry (C) | Undefined. |
++---------------+------------+
+| overflow (V) | Undefined. |
++---------------+------------+
+| zero (Z) | Undefined. |
++---------------+------------+
+| sign (S) | Undefined. |
++---------------+------------+
+| unordered (U) | Undefined. |
++---------------+------------+
+
+
+.. _umlinst-memaccess:
+
+Emulated memory access
+----------------------
+
+.. _umlinst-read:
+
+READ
+~~~~
+
+Read from an emulated address space. The access mask is implied to have
+all bits set.
+
++---------------------------------+-----------------------------------------------+
+| Disassembly | Usage |
++=================================+===============================================+
+| .. code-block:: | .. code-block:: C++ |
+| | |
+| read dst,addr,space_size | UML_READ(block, dst, addr, size, space); |
+| dread dst,addr,space_size | UML_DREAD(block, dst, addr, size, space); |
++---------------------------------+-----------------------------------------------+
+
+Operands
+^^^^^^^^
+
+dst (32-bit or 64-bit – memory, integer register)
+ The destination where the value read from the emulated address space
+ will be stored.
+addr (32-bit – memory, integer register, immediate, map variable)
+ The address to read from in the emulated address space. Note that
+ this is always a 32-bit operand, irrespective of the instruction
+ size.
+size (access size)
+ The size of the emulated memory access. Must be ``SIZE_BYTE``
+ (8-bit), ``SIZE_WORD`` (16-bit), ``SIZE_DWORD`` (32-bit) or
+ ``SIZE_QWORD`` (64-bit). Note that this operand controls the size
+ of the emulated memory access while the instruction size sets the
+ size of the ``dst`` operand.
+space (address space number)
+ An integer identifying the address space to read from. May be
+ ``SPACE_PROGRAM``, ``SPACE_DATA``, ``SPACE_IO`` or ``SPACE_OPCODES``
+ for one of the common CPU address spaces, or a non-negative integer
+ cast to ``memory_space``.
+
+Flags
+^^^^^
+
++---------------+------------+
+| carry (C) | Undefined. |
++---------------+------------+
+| overflow (V) | Undefined. |
++---------------+------------+
+| zero (Z) | Undefined. |
++---------------+------------+
+| sign (S) | Undefined. |
++---------------+------------+
+| unordered (U) | Undefined. |
++---------------+------------+
+
+Simplification rules
+^^^^^^^^^^^^^^^^^^^^
+
+* Immediate values for the ``addr`` operand are truncated to 32 bits.
+
+.. _umlinst-readm:
+
+READM
+~~~~~
+
+Read from an emulated address space with access mask specified.
+
++--------------------------------------+------------------------------------------------------+
+| Disassembly | Usage |
++======================================+======================================================+
+| .. code-block:: | .. code-block:: C++ |
+| | |
+| readm dst,addr,mask,space_size | UML_READM(block, dst, addr, mask, size, space); |
+| dreadm dst,addr,mask,space_size | UML_DREADM(block, dst, addr, mask, size, space); |
++--------------------------------------+------------------------------------------------------+
+
+Operands
+^^^^^^^^
+
+dst (32-bit or 64-bit – memory, integer register)
+ The destination where the value read from the emulated address space
+ will be stored.
+addr (32-bit – memory, integer register, immediate, map variable)
+ The address to read from in the emulated address space. Note that
+ this is always a 32-bit operand, irrespective of the instruction
+ size.
+mask (32-bit or 64-bit – memory, integer register, immediate, map variable)
+ The access mask for the emulated memory access.
+size (access size)
+ The size of the emulated memory access. Must be ``SIZE_BYTE``
+ (8-bit), ``SIZE_WORD`` (16-bit), ``SIZE_DWORD`` (32-bit) or
+ ``SIZE_QWORD`` (64-bit). Note that this operand controls the size
+ of the emulated memory access while the instruction size sets the
+ size of the ``dst`` and ``mask`` operands.
+space (address space number)
+ An integer identifying the address space to read from. May be
+ ``SPACE_PROGRAM``, ``SPACE_DATA``, ``SPACE_IO`` or ``SPACE_OPCODES``
+ for one of the common CPU address spaces, or a non-negative integer
+ cast to ``memory_space``.
+
+Flags
+^^^^^
+
++---------------+------------+
+| carry (C) | Undefined. |
++---------------+------------+
+| overflow (V) | Undefined. |
++---------------+------------+
+| zero (Z) | Undefined. |
++---------------+------------+
+| sign (S) | Undefined. |
++---------------+------------+
+| unordered (U) | Undefined. |
++---------------+------------+
+
+Simplification rules
+^^^^^^^^^^^^^^^^^^^^
+
+* Immediate values for the ``addr`` operand are truncated to 32 bits.
+* Immediate values for the ``mask`` operand are truncated to the access
+ size.
+* Converted to :ref:`READ <umlinst-read>` if the ``mask`` operand is an
+ immediate value with all bits set.
+
+.. _umlinst-write:
+
+WRITE
+~~~~~
+
+Write to an emulated address space. The access mask is implied to have
+all bits set.
+
++---------------------------------+------------------------------------------------+
+| Disassembly | Usage |
++=================================+================================================+
+| .. code-block:: | .. code-block:: C++ |
+| | |
+| write addr,src,space_size | UML_WRITE(block, addr, src, size, space); |
+| dwrite addr,src,space_size | UML_DWRITE(block, addr, src, size, space); |
++---------------------------------+------------------------------------------------+
+
+Operands
+^^^^^^^^
+
+addr (32-bit – memory, integer register, immediate, map variable)
+ The address to write to in the emulated address space. Note that
+ this is always a 32-bit operand, irrespective of the instruction
+ size.
+src (32-bit or 64-bit – memory, integer register, immediate, map variable)
+ The value to write to the emulated address space.
+size (access size)
+ The size of the emulated memory access. Must be ``SIZE_BYTE``
+ (8-bit), ``SIZE_WORD`` (16-bit), ``SIZE_DWORD`` (32-bit) or
+ ``SIZE_QWORD`` (64-bit). Note that this operand controls the size
+ of the emulated memory access while the instruction size sets the
+ size of the ``src`` operand.
+space (address space number)
+ An integer identifying the address space to read from. May be
+ ``SPACE_PROGRAM``, ``SPACE_DATA``, ``SPACE_IO`` or ``SPACE_OPCODES``
+ for one of the common CPU address spaces, or a non-negative integer
+ cast to ``memory_space``.
+
+Flags
+^^^^^
+
++---------------+------------+
+| carry (C) | Undefined. |
++---------------+------------+
+| overflow (V) | Undefined. |
++---------------+------------+
+| zero (Z) | Undefined. |
++---------------+------------+
+| sign (S) | Undefined. |
++---------------+------------+
+| unordered (U) | Undefined. |
++---------------+------------+
+
+Simplification rules
+^^^^^^^^^^^^^^^^^^^^
+
+* Immediate values for the ``addr`` operand are truncated to 32 bits.
+* Immediate values for the ``src`` operand are truncated to the access
+ size.
+
+.. _umlinst-writem:
+
+WRITEM
+~~~~~~
+
+Write to an emulated address space with access mask specified.
+
++--------------------------------------+-------------------------------------------------------+
+| Disassembly | Usage |
++======================================+=======================================================+
+| .. code-block:: | .. code-block:: C++ |
+| | |
+| writem addr,src,mask,space_size | UML_WRITEM(block, addr, src, mask, size, space); |
+| dwritem addr,src,mask,space_size | UML_DWRITEM(block, addr, src, mask, size, space); |
++--------------------------------------+-------------------------------------------------------+
+
+Operands
+^^^^^^^^
+
+addr (32-bit – memory, integer register, immediate, map variable)
+ The address to write to in the emulated address space. Note that
+ this is always a 32-bit operand, irrespective of the instruction
+ size.
+src (32-bit or 64-bit – memory, integer register, immediate, map variable)
+ The value to write to the emulated address space.
+mask (32-bit or 64-bit – memory, integer register, immediate, map variable)
+ The access mask for the emulated memory access.
+size (access size)
+ The size of the emulated memory access. Must be ``SIZE_BYTE``
+ (8-bit), ``SIZE_WORD`` (16-bit), ``SIZE_DWORD`` (32-bit) or
+ ``SIZE_QWORD`` (64-bit). Note that this operand controls the size
+ of the emulated memory access while the instruction size sets the
+ size of the ``src`` and ``mask`` operands.
+space (address space number)
+ An integer identifying the address space to read from. May be
+ ``SPACE_PROGRAM``, ``SPACE_DATA``, ``SPACE_IO`` or ``SPACE_OPCODES``
+ for one of the common CPU address spaces, or a non-negative integer
+ cast to ``memory_space``.
+
+Flags
+^^^^^
+
++---------------+------------+
+| carry (C) | Undefined. |
++---------------+------------+
+| overflow (V) | Undefined. |
++---------------+------------+
+| zero (Z) | Undefined. |
++---------------+------------+
+| sign (S) | Undefined. |
++---------------+------------+
+| unordered (U) | Undefined. |
++---------------+------------+
+
+Simplification rules
+^^^^^^^^^^^^^^^^^^^^
+
+* Immediate values for the ``addr`` operand are truncated to 32 bits.
+* Immediate values for the ``src`` and ``mask`` operands are truncated
+ to the access size.
+* Converted to :ref:`WRITE <umlinst-read>` if the ``mask`` operand is an
+ immediate value with all bits set.
+
+.. _umlinst-fread:
+
+FREAD
+~~~~~
+
+Read a floating point value from an emulated address space. The binary
+value will be preserved even if it is not a valid representation of a
+floating point number. The access mask is implied to have all bits set.
+
++---------------------------------+------------------------------------------+
+| Disassembly | Usage |
++=================================+==========================================+
+| .. code-block:: | .. code-block:: C++ |
+| | |
+| fsread dst,addr,space_size | UML_FSREAD(block, dst, addr, space); |
+| fdread dst,addr,space_size | UML_FDREAD(block, dst, addr, space); |
++---------------------------------+------------------------------------------+
+
+Operands
+^^^^^^^^
+
+dst (32-bit or 64-bit – memory, floating point register)
+ The destination where the value read from the emulated address space
+ will be stored.
+addr (32-bit – memory, integer register, immediate, map variable)
+ The address to read from in the emulated address space. Note that
+ this is always a 32-bit operand, irrespective of the instruction
+ size.
+space (address space number)
+ An integer identifying the address space to read from. May be
+ ``SPACE_PROGRAM``, ``SPACE_DATA``, ``SPACE_IO`` or ``SPACE_OPCODES``
+ for one of the common CPU address spaces, or a non-negative integer
+ cast to ``memory_space``.
+
+Flags
+^^^^^
+
++---------------+------------+
+| carry (C) | Undefined. |
++---------------+------------+
+| overflow (V) | Undefined. |
++---------------+------------+
+| zero (Z) | Undefined. |
++---------------+------------+
+| sign (S) | Undefined. |
++---------------+------------+
+| unordered (U) | Undefined. |
++---------------+------------+
+
+Simplification rules
+^^^^^^^^^^^^^^^^^^^^
+
+* Immediate values for the ``addr`` operand are truncated to 32 bits.
+
+.. _umlinst-fwrite:
+
+FWRITE
+~~~~~~
+
+Write a floating point value to an emulated address space. The binary
+value will be preserved even if it is not a valid representation of a
+floating point number. The access mask is implied to have all bits set.
+
++---------------------------------+-------------------------------------------+
+| Disassembly | Usage |
++=================================+===========================================+
+| .. code-block:: | .. code-block:: C++ |
+| | |
+| fswrite addr,src,space_size | UML_FSWRITE(block, addr, src, space); |
+| fdwrite addr,src,space_size | UML_FDWRITE(block, addr, src, space); |
++---------------------------------+-------------------------------------------+
+
+Operands
+^^^^^^^^
+
+addr (32-bit – memory, integer register, immediate, map variable)
+ The address to write to in the emulated address space. Note that
+ this is always a 32-bit operand, irrespective of the instruction
+ size.
+src (32-bit or 64-bit – memory, floating point register)
+ The value to write to the emulated address space.
+ will be stored.
+space (address space number)
+ An integer identifying the address space to read from. May be
+ ``SPACE_PROGRAM``, ``SPACE_DATA``, ``SPACE_IO`` or ``SPACE_OPCODES``
+ for one of the common CPU address spaces, or a non-negative integer
+ cast to ``memory_space``.
+
+Flags
+^^^^^
+
++---------------+------------+
+| carry (C) | Undefined. |
++---------------+------------+
+| overflow (V) | Undefined. |
++---------------+------------+
+| zero (Z) | Undefined. |
++---------------+------------+
+| sign (S) | Undefined. |
++---------------+------------+
+| unordered (U) | Undefined. |
++---------------+------------+
+
+Simplification rules
+^^^^^^^^^^^^^^^^^^^^
+
+* Immediate values for the ``addr`` operand are truncated to 32 bits.