<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-GB">
	<id>https://wiki.specnext.dev/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Ped7g</id>
	<title>SpecNext Wiki - User contributions [en-gb]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.specnext.dev/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Ped7g"/>
	<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/Special:Contributions/Ped7g"/>
	<updated>2026-05-31T20:14:47Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=Development_Tools:Linux_setup&amp;diff=41910</id>
		<title>Development Tools:Linux setup</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=Development_Tools:Linux_setup&amp;diff=41910"/>
		<updated>2026-04-29T18:19:21Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: adding more info about possible MAME config&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== General ==&lt;br /&gt;
&lt;br /&gt;
This page collects summaries of installation process of various tools related to ZX Spectrum Next software development for linux OS users.&lt;br /&gt;
&lt;br /&gt;
As usual with linux, most of the suggestions are in the form of command line command to be used from terminal.&lt;br /&gt;
&lt;br /&gt;
== sjasmplus assembler ==&lt;br /&gt;
&lt;br /&gt;
You can also check the [https://www.youtube.com/watch?v=c6I4kdErEwE video] of installing sjasmplus on freshly reinstalled KDE neon 5.20 linux, where is also extended info how to run the automated tests of sjasmplus, and opening it in KDevelop IDE to eventually write your own modifications.&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
On Debian based systems make sure you have these packages installed (git-cola and cmake are optional, but often handy):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install git build-essential g++ git-cola cmake&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Retrieving the sjasmplus source ===&lt;br /&gt;
&lt;br /&gt;
Use git to clone the [https://github.com/z00m128/sjasmplus z00m&#039;s sjasmplus repository]:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;git clone --recursive -j8 https://github.com/z00m128/sjasmplus.git&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To update already cloned repository, do inside the sjasmplus folder:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;git pull&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
- or use your favourite GIT client app to update the cloned repository.&lt;br /&gt;
&lt;br /&gt;
=== Building the executable binary ===&lt;br /&gt;
&lt;br /&gt;
The GNU make and common C++ compiler (gcc or clang) should be enough to build the binary:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;make clean &amp;amp;&amp;amp; make&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To verify the binary was built (&amp;quot;dot slash&amp;quot; prefix to force running of binary in current folder, not system one):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;./sjasmplus --version&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Installing the executable ===&lt;br /&gt;
&lt;br /&gt;
If you already have sjasmplus installed, use &amp;lt;code&amp;gt;which sjasmplus&amp;lt;/code&amp;gt; to see where the installed executable is (and which installed executable has precedence), you can use this command also after installing the new executable to verify it is being picked up by the system.&lt;br /&gt;
&lt;br /&gt;
Installing the binary in system-wide fashion:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo make install&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or you can install the binary only locally for your user (without root/sudo permissions):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;mkdir -p ~/.local/bin&lt;br /&gt;
make PREFIX=~/.local install&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
- then make sure you have &amp;lt;code&amp;gt;~/.local/bin&amp;lt;/code&amp;gt; in your user &amp;lt;code&amp;gt;PATH&amp;lt;/code&amp;gt; environment variable (on some distros there is already script in .profile to add this to PATH if the dir does exist, so you may need to only logout/restart after creating it to get it active).&lt;br /&gt;
&lt;br /&gt;
=== Checking if it all works ===&lt;br /&gt;
&lt;br /&gt;
Open your terminal and type (in any directory):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sjasmplus --version&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see version of the freshly built sjasmplus executable like this:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;SjASMPlus Z80 Cross-Assembler v1.17.0 (https://github.com/z00m128/sjasmplus)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== hdfmonkey tool ==&lt;br /&gt;
&lt;br /&gt;
The hdfmonkey tool can manipulate card-images, helping to write new builds of your project into NextZXOS card-image, to boot the emulators with full file system. (it&#039;s also possible to mount the images directly into linux by other means, to operate on them with regular file manager/etc, but hdfmonkey suits better use-case when the build script does update the image)&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
On Debian based systems make sure you have these packages installed:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install git build-essential g++ autoconf&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Retrieving the hdfmonkey source ===&lt;br /&gt;
&lt;br /&gt;
Use git to clone the [https://github.com/ped7g/hdfmonkey hdfmonkey repository with patched 0.5.7 &amp;lt;code&amp;gt;jjjs version&amp;lt;/code&amp;gt; sources]:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;git clone https://github.com/ped7g/hdfmonkey.git&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
(make sure you are on the default branch &amp;lt;code&amp;gt;&amp;quot;jjjs-variant&amp;quot;&amp;lt;/code&amp;gt; to build the improved version, it should be checked out by default after clone)&lt;br /&gt;
&lt;br /&gt;
* to update already cloned repository, do inside the hdfmonkey folder:&lt;br /&gt;
  &amp;lt;nowiki&amp;gt;git pull&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
* or use your favourite GIT client app to update the cloned repository.&lt;br /&gt;
* if you cloned original gasman&#039;s repository before, you may want to clone and rebuild here mentioned &amp;lt;code&amp;gt;jjjs version&amp;lt;/code&amp;gt; to get multiple fixes and convenience features.&lt;br /&gt;
&lt;br /&gt;
=== Building the executable binary ===&lt;br /&gt;
&lt;br /&gt;
The hdfmonkey is using autoconf/autotools to build final Makefile, check the hdfmonkey README for &amp;quot;from git&amp;quot; installation notes, at the moment of writing this page, the steps were:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;cd hdfmonkey&lt;br /&gt;
autoheader&lt;br /&gt;
aclocal&lt;br /&gt;
autoconf&lt;br /&gt;
automake -a&lt;br /&gt;
./configure&lt;br /&gt;
make&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To verify the binary was built:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;src/hdfmonkey help&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Installing the executable ===&lt;br /&gt;
&lt;br /&gt;
If you already have hdfmonkey installed, use &amp;lt;code&amp;gt;which hdfmonkey&amp;lt;/code&amp;gt; to see where the installed executable is (and which installed executable has precedence), you can use this command also after installing the new executable to verify it is being picked up by the system.&lt;br /&gt;
&lt;br /&gt;
Installing the binary in system-wide fashion:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo make install&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or you can install the binary only locally for your user (without root/sudo permissions):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;make prefix=~/.local install&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
- then make sure you have &amp;lt;code&amp;gt;~/.local/bin&amp;lt;/code&amp;gt; in your user &amp;lt;code&amp;gt;PATH&amp;lt;/code&amp;gt; environment variable.&lt;br /&gt;
&lt;br /&gt;
=== Checking if it all works ===&lt;br /&gt;
&lt;br /&gt;
Open your terminal and type (in any directory):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;hdfmonkey help&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see help of the freshly built hdfmonkey `jjjs version` executable like this:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;hdfmonkey: utility for manipulating HDF disk images v0.5.7 jjjs&lt;br /&gt;
&lt;br /&gt;
usage: hdfmonkey &amp;lt;command&amp;gt; [args]&lt;br /&gt;
...&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Extracting all files from the sd-card image ==&lt;br /&gt;
&lt;br /&gt;
7-zip is the most convenient tool to extract the the files from the existing image.&lt;br /&gt;
&lt;br /&gt;
To install 7-zip on a Debian system use &amp;lt;code&amp;gt;sudo apt install 7zip&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To extract all the files from an existing image &amp;lt;code&amp;gt;tbblue.img&amp;lt;/code&amp;gt; to a new subdirectory &amp;lt;code&amp;gt;myfiles&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;7z x tbblue.img -omyfiles&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Creating new sd-card image with hdfmonkey ==&lt;br /&gt;
&lt;br /&gt;
This example: &lt;br /&gt;
&lt;br /&gt;
* downloads the archive from the specnext.com&lt;br /&gt;
* unpacks it to the subdirectory &amp;lt;code&amp;gt;tmptb&amp;lt;/code&amp;gt;&lt;br /&gt;
* creates a new SD image (with the space for 2GB files) from all the files&lt;br /&gt;
* deletes the subdirectory &amp;lt;code&amp;gt;tmptb&amp;lt;/code&amp;gt;&lt;br /&gt;
* shows that the new image uses much less than 2GB&lt;br /&gt;
* starts listing the content of the newly created image&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
wget https://www.specnext.com/distro/24.11/sn-complete-24.11.zip&lt;br /&gt;
7z x sn-complete-24.11.zip -otmptb&lt;br /&gt;
hdfmonkey create tbblue.img 2GB&lt;br /&gt;
hdfmonkey putdir tbblue.img tmptb /  &lt;br /&gt;
rm -rf tmptb&lt;br /&gt;
du -h tbblue.img&lt;br /&gt;
7z l tbblue.img | more&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating new sd-card image without hdfmonkey ===&lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to use gnu coreutils and dosfstools to create card image without hdfmonkey, but depending on exact size of image these may be less compatible with various emulator, following example for 1GB card image works in MAME but fails in CSpect (while images created by hdfmonkey tool should work for both emulator, so using &#039;&#039;&#039;hdfmonkey is recommended&#039;&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
truncate -s 1G NextZXOS.img&lt;br /&gt;
parted NextZXOS.img mklabel msdos&lt;br /&gt;
parted NextZXOS.img mkpart primary fat32 2048s 100%&lt;br /&gt;
mkfs.fat -F 32 --offset=2048 NextZXOS.img&lt;br /&gt;
# and now to copy files to image you have to either mount it or use hdfmonkey:&lt;br /&gt;
# hdfmonkey putdir NextZXOS.img tmptb /&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mounting sd-card image directly ==&lt;br /&gt;
&lt;br /&gt;
Sometimes it may be useful to mount the card image directly, to be able to browse it and manipulate with common tools. But make sure you are not using mounted card image also in emulator at the same time, to prevent any data damage by parallel access.&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
On Debian based systems make sure you have these packages installed:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install fdisk mount&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Prepare empty directory to mount the card image into (let&#039;s call it &amp;quot;next-card&amp;quot;) and have the image file around (&amp;quot;tbblue.mmc&amp;quot; in following examples)&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;mkdir -p next-card&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Mounting the card image ===&lt;br /&gt;
&lt;br /&gt;
To mount the card image you need to know the exact byte-offset where the FAT partition starts, it&#039;s possible to read it from &amp;quot;fdisk&amp;quot; or &amp;quot;parted&amp;quot; tools outputs:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;fdisk -l -o Start tbblue.mmc&lt;br /&gt;
# prints value in sector units, like:&lt;br /&gt;
# Start&lt;br /&gt;
#    63&lt;br /&gt;
# This has to be multiplied by 512 to get byte offset: 63*512 = 32256&lt;br /&gt;
&lt;br /&gt;
# or&lt;br /&gt;
&lt;br /&gt;
parted tbblue.mmc unit B print&lt;br /&gt;
# prints values in bytes with &amp;quot;B&amp;quot; suffix in &amp;quot;Start&amp;quot; column&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
But the fdisk output can be incorporated directly into mount command, which needs root permissions, example with sudo:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo mount tbblue.mmc next-card/ -o loop,offset=$((`fdisk -l -o Start tbblue.mmc | tail -1` * 512)),user,uid=`id -u`,gid=`id -g`&lt;br /&gt;
&lt;br /&gt;
# or you can enter the offset yourself&lt;br /&gt;
&lt;br /&gt;
sudo mount tbblue.mmc next-card/ -o loop,offset=32256,user,uid=`id -u`,gid=`id -g`&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The uid and gid options will mount the filesystem under your regular user, so you can now browse it with file manager, text editors, etc.&lt;br /&gt;
&lt;br /&gt;
Do not run the emulator yet, before unmounting the image (after you are done manipulating the files)!&lt;br /&gt;
&lt;br /&gt;
=== Unmount the image before using it in emulator ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo umount next-card/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Check the result. If the unmounting fails (probably with &amp;quot;target is busy&amp;quot;), find which process is still accessing/viewing the files in the next-card directory, and try to unmount it again.&lt;br /&gt;
&lt;br /&gt;
== Mounting sd-card image with losetup ==&lt;br /&gt;
&lt;br /&gt;
Alternative using losetup to use local &amp;quot;loop&amp;quot; device for mounting the image. This method can automatically detect partitions inside the image and exposes them as loop devices.&lt;br /&gt;
&lt;br /&gt;
Prepare mounting dir and make sure you have &amp;lt;code&amp;gt;mount&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;losetup&amp;lt;/code&amp;gt; available, Ubuntu based systems packages:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install util-linux mount&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Use losetup to attach image and scan its partitions ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo losetup --partscan --show --find NextZXOS.img&lt;br /&gt;
# this will print new loop device and automatically create partition devices like /dev/loop0p1&lt;br /&gt;
# now mount the desired FAT32 partition:&lt;br /&gt;
sudo mount /dev/loop0p1 next-card/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Unmounting and cleanup of loop device ===&lt;br /&gt;
&lt;br /&gt;
When finished:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo umount next-card/&lt;br /&gt;
sudo losetup -d /dev/loop0&lt;br /&gt;
# or `sudo losetup -D` to detach *ALL* loop devices&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This detaches the loop device and frees all associated /dev/loop* entries.&lt;br /&gt;
&lt;br /&gt;
Notes and gotchas:&lt;br /&gt;
* Do not use the image in an emulator while it is mounted.&lt;br /&gt;
* If the image has no partition table, --partscan will not create /dev/loop0p1.&lt;br /&gt;
* If multiple loop devices are active, check &amp;lt;code&amp;gt;losetup -a&amp;lt;/code&amp;gt; to confirm which one is yours.&lt;br /&gt;
&lt;br /&gt;
== Mounting sd‑card image with udisksctl ==&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;udisksctl&amp;lt;/code&amp;gt; tool provides a desktop‑friendly way to attach loop devices and mount filesystems without manually calculating offsets or using &amp;lt;code&amp;gt;losetup&amp;lt;/code&amp;gt;. It integrates with system services such as UDisks2, and on many desktop Linux systems it allows non‑root users (who are in the correct group) to mount images safely.&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
On Debian‑based systems install the UDisks2 tools:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install udisks2&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To run &amp;lt;code&amp;gt;udisksctl&amp;lt;/code&amp;gt; without &amp;lt;code&amp;gt;sudo&amp;lt;/code&amp;gt;, your user must belong to the &#039;&#039;&#039;disk&#039;&#039;&#039;, &#039;&#039;&#039;storage&#039;&#039;&#039;, or &#039;&#039;&#039;udisks&#039;&#039;&#039; policy group (varies by distribution). If unsure, simply use &amp;lt;code&amp;gt;sudo&amp;lt;/code&amp;gt; in the examples below.&lt;br /&gt;
&lt;br /&gt;
=== Attaching the image as a loop device ===&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;code&amp;gt;udisksctl loop-setup&amp;lt;/code&amp;gt; to create a loop device for the image:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;udisksctl loop-setup --file NextZXOS.img&lt;br /&gt;
# prints something like:&lt;br /&gt;
# Mapped file NextZXOS.img as /dev/loop2.&lt;br /&gt;
# UDisks automatically scans the partition table and exposes partitions as:&lt;br /&gt;
# /dev/loop2p1&lt;br /&gt;
# /dev/loop2p2&lt;br /&gt;
# ...&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Mounting the FAT32 partition ===&lt;br /&gt;
&lt;br /&gt;
Mount the desired partition:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;udisksctl mount --block-device /dev/loop2p1&lt;br /&gt;
# This prints the mount point, for example:&lt;br /&gt;
# Mounted /dev/loop2p1 at /media/youruser/NextZXOS.&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can now browse and edit the filesystem normally using your file manager or command‑line tools.&lt;br /&gt;
&lt;br /&gt;
=== Unmounting and cleanup ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;udisksctl unmount --block-device /dev/loop2p1&lt;br /&gt;
udisksctl loop-delete --block-device /dev/loop2&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This cleanly detaches the loop device and removes all &amp;lt;code&amp;gt;/dev/loop*&amp;lt;/code&amp;gt; entries created for the image.&lt;br /&gt;
&lt;br /&gt;
=== Notes and gotchas ===&lt;br /&gt;
&lt;br /&gt;
* Do not use the image in an emulator while it is mounted, parallel access may corrupt data.&lt;br /&gt;
* If the image has no partition table, UDisks will not create &#039;&#039;&#039;/dev/loopXp1&#039;&#039;&#039; and you must mount manually using an offset.&lt;br /&gt;
* Mount points are created under &amp;lt;code&amp;gt;/media/$USER/&amp;lt;/code&amp;gt; unless overridden by system policy.&lt;br /&gt;
* UDisks may auto‑mount partitions immediately after &#039;&#039;&#039;loop‑setup&#039;&#039;&#039; depending on desktop environment settings.&lt;br /&gt;
&lt;br /&gt;
== MAME emulator ==&lt;br /&gt;
&lt;br /&gt;
MAME got Next emulation and it got improved a lot around end of 2025, turning it into probably most accurate and performant Next emulator currently available. But as that shift is quite recent, the developers community haven’t transitioned to it yet in large numbers and the tutorials and examples are non-existent. This section provides a basic Linux setup guide.&lt;br /&gt;
&lt;br /&gt;
This chapter focuses only on installing MAME from source code git repository, so you can update to latest work in progress or even contribute to the development yourself. The stable binary releases already contain decent Next emulation, but bug fixes and improvements are still coming often and stable releases trail a few weeks behind.&lt;br /&gt;
&lt;br /&gt;
At the moment, the primary developer working on Next emulation in MAME is Andrei Holub, so his fork repo will be used as default source.&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
You need C++17 compiler (GCC 10.3+ or clang 11+), GNU make and few more development tools and common libraries, for specific list for your distro and up to date information check [https://docs.mamedev.org/initialsetup/compilingmame.html Compiling MAME] web page from official docs.&lt;br /&gt;
&lt;br /&gt;
Keep this page around as the example here is quick hint and not meant as replacement for full documentation.&lt;br /&gt;
&lt;br /&gt;
=== Retrieving the MAME source ===&lt;br /&gt;
&lt;br /&gt;
Use git to clone the [https://github.com/holub/mame holub&#039;s MAME repository] and add the [https://github.com/mamedev/mame official MAME repository] as an additional remote:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;git clone --origin holubdev https://github.com/holub/mame.git&lt;br /&gt;
cd mame&lt;br /&gt;
git remote add -f --tags mamedev https://github.com/mamedev/mame.git&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To update already cloned repository checked out at master branch, do inside the mame folder (WARNING: this will drop any local changes in the repository, as MAME devs often rewrite already published commits and you need to reset your local clone to latest state - if you are developer working on MAME sources, you should know yourself how to work with git to preserve your changes and rebase/merge):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;git fetch --all --force&lt;br /&gt;
git reset --hard master&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
Or use your favourite GIT client app to update the cloned repository.&lt;br /&gt;
&lt;br /&gt;
=== Building the executable binary ===&lt;br /&gt;
&lt;br /&gt;
To &#039;&#039;&#039;rebuild&#039;&#039;&#039; &#039;&#039;&#039;only&#039;&#039;&#039; Next emulation (&#039;&#039;&amp;quot;tbblue&amp;quot;&#039;&#039; machine) and get executable named &amp;lt;code&amp;gt;tbblue&amp;lt;/code&amp;gt;, run &amp;lt;code&amp;gt;make&amp;lt;/code&amp;gt; like this:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# make sure there are no remnants from previous builds&lt;br /&gt;
make clean&lt;br /&gt;
# If you want to, you can change to TOOLS=1 to build also &amp;quot;various additional tools, such as chdman&amp;quot;&lt;br /&gt;
# The name of resulting binary is affected by SUBTARGET=tbblue, leave it out if you want &amp;quot;mame&amp;quot;&lt;br /&gt;
make REGENIE=1 EMULATOR=1 TOOLS=0 SOURCES=sinclair/next/specnext.cpp SUBTARGET=tbblue -j $(nproc)&lt;br /&gt;
# check the build output to confirm that compilation succeeded. To list binary:&lt;br /&gt;
ls -lh tbblue&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This may take a considerable amount of time depending on how powerful your PC is.&lt;br /&gt;
&lt;br /&gt;
If you are developing MAME yourself, you can do incremental build (after REGENIE=1 was used to &amp;quot;generate project files&amp;quot; in previous build and your source code changes don&#039;t require full rebuild) - this will be lot faster of course as usual:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;make SUBTARGET=tbblue -j $(nproc)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To rebuild full MAME including all other emulation targets (computers and arcade machines) - which will take even much longer - use:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;make clean &amp;amp;&amp;amp; make REGENIE=1 EMULATOR=1 TOOLS=0 -j $(nproc)&lt;br /&gt;
# check existence of new binary (the line above will produce default name &amp;quot;mame&amp;quot;)&lt;br /&gt;
ls -lh mame&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Installing the executable and configuration ===&lt;br /&gt;
&lt;br /&gt;
Linux MAME by default [https://docs.mamedev.org/commandline/commandline-all.html#mame-commandline-pathoptions looks for configuration file] in directories: &amp;lt;code&amp;gt;$HOME/.mame;.;ini&amp;lt;/code&amp;gt; (that is search the .mame directory in the current user&#039;s home directory, followed by the current working directory, and finally the directory ini in the current working directory)&lt;br /&gt;
&lt;br /&gt;
For most of the other paths like &amp;lt;code&amp;gt;roms, samples, artwork, ...&amp;lt;/code&amp;gt; it looks by default in current directory &amp;lt;code&amp;gt;.&amp;lt;/code&amp;gt;, but you can provide custom paths in the &amp;lt;code&amp;gt;mame.ini&amp;lt;/code&amp;gt; file.&lt;br /&gt;
&lt;br /&gt;
My (Ped7g) personal preference is to have all these helper directories in $HOME/.mame along the global mame.ini file, so I can launch the same configuration of MAME from any directory on the system and to keep the configuration and helper file outside of the git repository folder where I build the binary. To seed the ini file first time after building from source, you can use &amp;lt;code&amp;gt;mame -createconfig&amp;lt;/code&amp;gt; to get template of .ini file in desired directory (like $HOME/.mame). Then edit the fresh ini file to your liking, for example I modified these lines (diff view):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ diff mame.ini ~/.mame/mame.ini&lt;br /&gt;
10,22c10,22&lt;br /&gt;
&amp;lt; homepath                  .&lt;br /&gt;
&amp;lt; rompath                   roms&lt;br /&gt;
&amp;lt; hashpath                  hash&lt;br /&gt;
&amp;lt; samplepath                samples&lt;br /&gt;
&amp;lt; artpath                   artwork&lt;br /&gt;
&amp;lt; ctrlrpath                 ctrlr&lt;br /&gt;
&amp;lt; inipath                   $HOME/.mame;.;ini&lt;br /&gt;
&amp;lt; fontpath                  .&lt;br /&gt;
&amp;lt; cheatpath                 cheat&lt;br /&gt;
&amp;lt; crosshairpath             crosshair&lt;br /&gt;
&amp;lt; pluginspath               plugins&lt;br /&gt;
&amp;lt; languagepath              language&lt;br /&gt;
&amp;lt; swpath                    software&lt;br /&gt;
---&lt;br /&gt;
&amp;gt; inipath                   $HOME/.mame&lt;br /&gt;
&amp;gt; homepath                  $HOME/.mame/lua&lt;br /&gt;
&amp;gt; rompath                   $HOME/.mame/roms&lt;br /&gt;
&amp;gt; hashpath                  $HOME/.mame/hash&lt;br /&gt;
&amp;gt; samplepath                $HOME/.mame/samples&lt;br /&gt;
&amp;gt; artpath                   $HOME/.mame/artwork&lt;br /&gt;
&amp;gt; ctrlrpath                 $HOME/.mame/ctrlr&lt;br /&gt;
&amp;gt; fontpath                  $HOME/.mame&lt;br /&gt;
&amp;gt; cheatpath                 $HOME/.mame/cheat&lt;br /&gt;
&amp;gt; crosshairpath             $HOME/.mame/crosshair&lt;br /&gt;
&amp;gt; pluginspath               $HOME/.mame/plugins&lt;br /&gt;
&amp;gt; languagepath              $HOME/.mame/language&lt;br /&gt;
&amp;gt; swpath                    $HOME/.mame/software&lt;br /&gt;
27,34c27,34&lt;br /&gt;
&amp;lt; cfg_directory             cfg&lt;br /&gt;
&amp;lt; nvram_directory           nvram&lt;br /&gt;
&amp;lt; input_directory           inp&lt;br /&gt;
&amp;lt; state_directory           sta&lt;br /&gt;
&amp;lt; snapshot_directory        snap&lt;br /&gt;
&amp;lt; diff_directory            diff&lt;br /&gt;
&amp;lt; comment_directory         comments&lt;br /&gt;
&amp;lt; share_directory           share&lt;br /&gt;
---&lt;br /&gt;
&amp;gt; cfg_directory             $HOME/.mame/cfg&lt;br /&gt;
&amp;gt; nvram_directory           $HOME/.mame/nvram&lt;br /&gt;
&amp;gt; input_directory           $HOME/.mame/inp&lt;br /&gt;
&amp;gt; state_directory           $HOME/.mame/sta&lt;br /&gt;
&amp;gt; snapshot_directory        $HOME/.mame/snap&lt;br /&gt;
&amp;gt; diff_directory            $HOME/.mame/diff&lt;br /&gt;
&amp;gt; comment_directory         $HOME/.mame/comments&lt;br /&gt;
&amp;gt; share_directory           $HOME/.mame/share&lt;br /&gt;
349c348&lt;br /&gt;
&amp;lt; bgfx_path                 bgfx&lt;br /&gt;
---&lt;br /&gt;
&amp;gt; bgfx_path                 $HOME/.mame/bgfx&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And I set up the helper subfolders like this (some are real directories copied from git repo or created empty - where I expect the content to be modified by me, others are symlinks to cloned git repository where I expect content to be read-only):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
~/.mame$ ls -Aogh&lt;br /&gt;
total 32K&lt;br /&gt;
lrwxrwxrwx 1   41 Nov 17 13:43 artwork -&amp;gt; /git_repos/mame/artwork&lt;br /&gt;
lrwxrwxrwx 1   38 Nov 17 13:40 bgfx -&amp;gt; /git_repos/mame/bgfx&lt;br /&gt;
drwxrwxr-x 2 4.0K Nov 17 02:36 cfg&lt;br /&gt;
lrwxrwxrwx 1   39 Nov 17 13:44 ctrlr -&amp;gt; /git_repos/mame/ctrlr&lt;br /&gt;
lrwxrwxrwx 1   38 Nov 17 13:43 hash -&amp;gt; /git_repos/mame/hash&lt;br /&gt;
lrwxrwxrwx 1   42 Nov 17 13:44 language -&amp;gt; /git_repos/mame/language&lt;br /&gt;
-rw-rw-r-- 1 8.7K Nov 17 13:45 mame.ini&lt;br /&gt;
drwxrwxr-x 3 4.0K Nov 17 02:36 nvram&lt;br /&gt;
lrwxrwxrwx 1   41 Nov 17 13:40 plugins&lt;br /&gt;
drwxrwxr-x 2 4.0K Apr 22 23:47 roms&lt;br /&gt;
lrwxrwxrwx 1   41 Nov 17 13:43 samples -&amp;gt; /git_repos/mame/samples&lt;br /&gt;
drwxrwxr-x 3 4.0K Jan 16 13:30 snap&lt;br /&gt;
-rw-rw-r-- 1 2.0K Jan 17 22:50 ui.ini&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And my helper launch script is public in git repo [https://github.com/MrKWatkins/ZXSpectrumNextTests/blob/develop/Tools/mmcMame ZXSpectrumNextTests/Tools/mmcMame], the current content (to launch mame with particular mmc image file and further options):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
# personal script of Ped to launch MAME emulator with the &amp;quot;tbblue.mmc&amp;quot; (or first argument is image filename)&lt;br /&gt;
if [[ -s &amp;quot;$1&amp;quot; ]]; then&lt;br /&gt;
  MMCFILE=&amp;quot;$1&amp;quot;&lt;br /&gt;
  shift&lt;br /&gt;
else&lt;br /&gt;
  MMCFILE=tbblue.mmc&lt;br /&gt;
fi&lt;br /&gt;
mame tbblue -ui_active -nounevenstretch -aspect 2:1 -video bgfx -bgfx_screen_chains unfiltered -window -skip_gameinfo -mouse_device none -hard1 &amp;quot;$MMCFILE&amp;quot; &amp;quot;$@&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Checking if it all works ===&lt;br /&gt;
&lt;br /&gt;
TODO&lt;br /&gt;
&lt;br /&gt;
TODO: add chapter(s) about plugins, config of them, dezog, example of launch, ... once you actually make it work yourself :D&lt;br /&gt;
&lt;br /&gt;
== #CSpect emulator ==&lt;br /&gt;
&lt;br /&gt;
The #CSpect is Mike Dailly&#039;s ZX Spectrum Next emulator, written in C# making it cross-platform (sort of, where the mono framework is available). It is non-free (closed-source, custom license) project, but available for usage without any payment (it&#039;s possible to use it internally to develop also commercial titles, but you can not distribute/sell the emulator itself, not even packaged with your game - for such agreement contact the author first and get his permission).&lt;br /&gt;
&lt;br /&gt;
Currently it is most performant and user friendly emulator of ZX Spectrum Next, with good emulation accuracy (see [https://wiki.specnext.dev/CSpect:known_bugs CSpect:known_bugs] page for more detailed report).&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
On Debian based systems make sure you have these packages installed:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install mono-complete libopenal1 libsdl2-dev&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Retrieving the #CSpect package ===&lt;br /&gt;
&lt;br /&gt;
Use web browser to visit itch.io dedicated to CSpect project [https://mdf200.itch.io/cspect mdf200.itch.io/cspect] and download latest release.&lt;br /&gt;
&lt;br /&gt;
You may get warnings from your browser or antivirus about the page itself and about the zip/binary files. The #CSpect has long record of triggering false positives of AV engines due to the executable being not digitally signed and because of the code using features of OS which are normal for emulator, but may look wonky for AV heuristic. Whether you trust the executable is virus free is up to you, in the end.&lt;br /&gt;
&lt;br /&gt;
=== Installing the executable ===&lt;br /&gt;
&lt;br /&gt;
Unzip the retrieved zip file (I personally use KDE Dolphin file manager, the file context menu &#039;&#039;&amp;quot;Extract -&amp;gt; Extract archive here, autodetect subfolder&amp;quot;&#039;&#039;), and place the unzipped directory to target destination (&amp;lt;code&amp;gt;~/zx/emulators/CSpect/CSpect2_13_0&amp;lt;/code&amp;gt; in my case). I prefer to keep every version in its own directory, and have general symbolic link pointing to the one I want use by default:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;cd ~/zx/emulators/CSpect&lt;br /&gt;
ln -s CSpect2_13_0 CSpect_current&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then I create launcher bash-scripts in my &amp;lt;code&amp;gt;~/.local/bin&amp;lt;/code&amp;gt; like this (name of script &amp;lt;code&amp;gt;runCSpect&amp;lt;/code&amp;gt;):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;#!/bin/bash&lt;br /&gt;
# personal script of Ped to launch &amp;quot;#CSpect&amp;quot; emulator in &amp;quot;current directory&amp;quot; (with arguments like: &amp;quot;runCSpect file.nex&amp;quot;)&lt;br /&gt;
MONO_IOMAP=all mono ~/zx/emulators/CSpect/CSpect_current/CSpect.exe -tv -zxnext -s28 -w4 -mmc=./ &amp;quot;$@&amp;quot;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notes: I don&#039;t know any more what &amp;lt;code&amp;gt;MONO_IOMAP=all&amp;lt;/code&amp;gt; helps with, I believe it was suggested to help with any filesystem windows-like paths containing backslashes, you can try to do your own research. The &amp;lt;code&amp;gt;-tv&amp;lt;/code&amp;gt; switch will switch off &amp;quot;scanlines&amp;quot; shader effect and generally switch off any GPU shaders, which makes CSpect more compatible with graphics drivers (try it, if you get only black screen or instant crash during init). The &amp;lt;code&amp;gt;-w4&amp;lt;/code&amp;gt; will make the window quite large - 4x scale, the &amp;lt;code&amp;gt;-zxnext -s28&amp;lt;/code&amp;gt; switch #CSpect into ZX Next emulation mode and set 28Mhz speed of OS as default. And finally the &amp;lt;code&amp;gt;-mmc=./ &amp;quot;$@&amp;quot;&amp;lt;/code&amp;gt; will set &#039;&#039;current directory&#039;&#039; for esxdos emulation to the directory where you use the script to launch the emulator, and pass any remaining command line options entered by user, like the name of the SNA/NEX file. Other noteworthy options are &amp;lt;code&amp;gt;-debug -brk -map=file.map&amp;lt;/code&amp;gt;, the -debug entering the debugger just ahead of the first instruction, -brk enables CSpect specific two-byte tag 0xDD 0x01 to work as breakpoint and the -map option allows you to load into debugger the symbol table from your assembler (directive CSPECTMAP in sjasmplus), making labels visible in disassembly.&lt;br /&gt;
&lt;br /&gt;
=== Checking if it all works ===&lt;br /&gt;
&lt;br /&gt;
Go to some directory with SNA/SNX/NEX file (there are also some demo files right in the CSpect directory) and use the launcher script, like:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;runCSpect beast.nex&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see #CSpect emulator window running the beast.nex demo (or whatever else you did want to launch and entered as argument).&lt;br /&gt;
&lt;br /&gt;
[[File:Cspect_test_run.png|frameless|Running CSpect from directory with test snapshots]]&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=Development_Tools:Linux_setup&amp;diff=41904</id>
		<title>Development Tools:Linux setup</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=Development_Tools:Linux_setup&amp;diff=41904"/>
		<updated>2026-04-25T18:52:10Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: /* Installing the executable and configuration */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== General ==&lt;br /&gt;
&lt;br /&gt;
This page collects summaries of installation process of various tools related to ZX Spectrum Next software development for linux OS users.&lt;br /&gt;
&lt;br /&gt;
As usual with linux, most of the suggestions are in the form of command line command to be used from terminal.&lt;br /&gt;
&lt;br /&gt;
== sjasmplus assembler ==&lt;br /&gt;
&lt;br /&gt;
You can also check the [https://www.youtube.com/watch?v=c6I4kdErEwE video] of installing sjasmplus on freshly reinstalled KDE neon 5.20 linux, where is also extended info how to run the automated tests of sjasmplus, and opening it in KDevelop IDE to eventually write your own modifications.&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
On Debian based systems make sure you have these packages installed (git-cola and cmake are optional, but often handy):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install git build-essential g++ git-cola cmake&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Retrieving the sjasmplus source ===&lt;br /&gt;
&lt;br /&gt;
Use git to clone the [https://github.com/z00m128/sjasmplus z00m&#039;s sjasmplus repository]:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;git clone --recursive -j8 https://github.com/z00m128/sjasmplus.git&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To update already cloned repository, do inside the sjasmplus folder:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;git pull&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
- or use your favourite GIT client app to update the cloned repository.&lt;br /&gt;
&lt;br /&gt;
=== Building the executable binary ===&lt;br /&gt;
&lt;br /&gt;
The GNU make and common C++ compiler (gcc or clang) should be enough to build the binary:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;make clean &amp;amp;&amp;amp; make&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To verify the binary was built (&amp;quot;dot slash&amp;quot; prefix to force running of binary in current folder, not system one):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;./sjasmplus --version&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Installing the executable ===&lt;br /&gt;
&lt;br /&gt;
If you already have sjasmplus installed, use &amp;lt;code&amp;gt;which sjasmplus&amp;lt;/code&amp;gt; to see where the installed executable is (and which installed executable has precedence), you can use this command also after installing the new executable to verify it is being picked up by the system.&lt;br /&gt;
&lt;br /&gt;
Installing the binary in system-wide fashion:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo make install&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or you can install the binary only locally for your user (without root/sudo permissions):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;mkdir -p ~/.local/bin&lt;br /&gt;
make PREFIX=~/.local install&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
- then make sure you have &amp;lt;code&amp;gt;~/.local/bin&amp;lt;/code&amp;gt; in your user &amp;lt;code&amp;gt;PATH&amp;lt;/code&amp;gt; environment variable (on some distros there is already script in .profile to add this to PATH if the dir does exist, so you may need to only logout/restart after creating it to get it active).&lt;br /&gt;
&lt;br /&gt;
=== Checking if it all works ===&lt;br /&gt;
&lt;br /&gt;
Open your terminal and type (in any directory):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sjasmplus --version&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see version of the freshly built sjasmplus executable like this:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;SjASMPlus Z80 Cross-Assembler v1.17.0 (https://github.com/z00m128/sjasmplus)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== hdfmonkey tool ==&lt;br /&gt;
&lt;br /&gt;
The hdfmonkey tool can manipulate card-images, helping to write new builds of your project into NextZXOS card-image, to boot the emulators with full file system. (it&#039;s also possible to mount the images directly into linux by other means, to operate on them with regular file manager/etc, but hdfmonkey suits better use-case when the build script does update the image)&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
On Debian based systems make sure you have these packages installed:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install git build-essential g++ autoconf&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Retrieving the hdfmonkey source ===&lt;br /&gt;
&lt;br /&gt;
Use git to clone the [https://github.com/ped7g/hdfmonkey hdfmonkey repository with patched 0.5.7 &amp;lt;code&amp;gt;jjjs version&amp;lt;/code&amp;gt; sources]:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;git clone https://github.com/ped7g/hdfmonkey.git&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
(make sure you are on the default branch &amp;lt;code&amp;gt;&amp;quot;jjjs-variant&amp;quot;&amp;lt;/code&amp;gt; to build the improved version, it should be checked out by default after clone)&lt;br /&gt;
&lt;br /&gt;
* to update already cloned repository, do inside the hdfmonkey folder:&lt;br /&gt;
  &amp;lt;nowiki&amp;gt;git pull&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
* or use your favourite GIT client app to update the cloned repository.&lt;br /&gt;
* if you cloned original gasman&#039;s repository before, you may want to clone and rebuild here mentioned &amp;lt;code&amp;gt;jjjs version&amp;lt;/code&amp;gt; to get multiple fixes and convenience features.&lt;br /&gt;
&lt;br /&gt;
=== Building the executable binary ===&lt;br /&gt;
&lt;br /&gt;
The hdfmonkey is using autoconf/autotools to build final Makefile, check the hdfmonkey README for &amp;quot;from git&amp;quot; installation notes, at the moment of writing this page, the steps were:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;cd hdfmonkey&lt;br /&gt;
autoheader&lt;br /&gt;
aclocal&lt;br /&gt;
autoconf&lt;br /&gt;
automake -a&lt;br /&gt;
./configure&lt;br /&gt;
make&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To verify the binary was built:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;src/hdfmonkey help&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Installing the executable ===&lt;br /&gt;
&lt;br /&gt;
If you already have hdfmonkey installed, use &amp;lt;code&amp;gt;which hdfmonkey&amp;lt;/code&amp;gt; to see where the installed executable is (and which installed executable has precedence), you can use this command also after installing the new executable to verify it is being picked up by the system.&lt;br /&gt;
&lt;br /&gt;
Installing the binary in system-wide fashion:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo make install&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or you can install the binary only locally for your user (without root/sudo permissions):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;make prefix=~/.local install&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
- then make sure you have &amp;lt;code&amp;gt;~/.local/bin&amp;lt;/code&amp;gt; in your user &amp;lt;code&amp;gt;PATH&amp;lt;/code&amp;gt; environment variable.&lt;br /&gt;
&lt;br /&gt;
=== Checking if it all works ===&lt;br /&gt;
&lt;br /&gt;
Open your terminal and type (in any directory):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;hdfmonkey help&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see help of the freshly built hdfmonkey `jjjs version` executable like this:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;hdfmonkey: utility for manipulating HDF disk images v0.5.7 jjjs&lt;br /&gt;
&lt;br /&gt;
usage: hdfmonkey &amp;lt;command&amp;gt; [args]&lt;br /&gt;
...&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Extracting all files from the sd-card image ==&lt;br /&gt;
&lt;br /&gt;
7-zip is the most convenient tool to extract the the files from the existing image.&lt;br /&gt;
&lt;br /&gt;
To install 7-zip on a Debian system use &amp;lt;code&amp;gt;sudo apt install 7zip&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To extract all the files from an existing image &amp;lt;code&amp;gt;tbblue.img&amp;lt;/code&amp;gt; to a new subdirectory &amp;lt;code&amp;gt;myfiles&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;7z x tbblue.img -omyfiles&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Creating new sd-card image with hdfmonkey ==&lt;br /&gt;
&lt;br /&gt;
This example: &lt;br /&gt;
&lt;br /&gt;
* downloads the archive from the specnext.com&lt;br /&gt;
* unpacks it to the subdirectory &amp;lt;code&amp;gt;tmptb&amp;lt;/code&amp;gt;&lt;br /&gt;
* creates a new SD image (with the space for 2GB files) from all the files&lt;br /&gt;
* deletes the subdirectory &amp;lt;code&amp;gt;tmptb&amp;lt;/code&amp;gt;&lt;br /&gt;
* shows that the new image uses much less than 2GB&lt;br /&gt;
* starts listing the content of the newly created image&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
wget https://www.specnext.com/distro/24.11/sn-complete-24.11.zip&lt;br /&gt;
7z x sn-complete-24.11.zip -otmptb&lt;br /&gt;
hdfmonkey create tbblue.img 2GB&lt;br /&gt;
hdfmonkey putdir tbblue.img tmptb /  &lt;br /&gt;
rm -rf tmptb&lt;br /&gt;
du -h tbblue.img&lt;br /&gt;
7z l tbblue.img | more&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating new sd-card image without hdfmonkey ===&lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to use gnu coreutils and dosfstools to create card image without hdfmonkey, but depending on exact size of image these may be less compatible with various emulator, following example for 1GB card image works in MAME but fails in CSpect (while images created by hdfmonkey tool should work for both emulator, so using &#039;&#039;&#039;hdfmonkey is recommended&#039;&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
truncate -s 1G NextZXOS.img&lt;br /&gt;
parted NextZXOS.img mklabel msdos&lt;br /&gt;
parted NextZXOS.img mkpart primary fat32 2048s 100%&lt;br /&gt;
mkfs.fat -F 32 --offset=2048 NextZXOS.img&lt;br /&gt;
# and now to copy files to image you have to either mount it or use hdfmonkey:&lt;br /&gt;
# hdfmonkey putdir NextZXOS.img tmptb /&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mounting sd-card image directly ==&lt;br /&gt;
&lt;br /&gt;
Sometimes it may be useful to mount the card image directly, to be able to browse it and manipulate with common tools. But make sure you are not using mounted card image also in emulator at the same time, to prevent any data damage by parallel access.&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
On Debian based systems make sure you have these packages installed:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install fdisk mount&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Prepare empty directory to mount the card image into (let&#039;s call it &amp;quot;next-card&amp;quot;) and have the image file around (&amp;quot;tbblue.mmc&amp;quot; in following examples)&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;mkdir -p next-card&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Mounting the card image ===&lt;br /&gt;
&lt;br /&gt;
To mount the card image you need to know the exact byte-offset where the FAT partition starts, it&#039;s possible to read it from &amp;quot;fdisk&amp;quot; or &amp;quot;parted&amp;quot; tools outputs:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;fdisk -l -o Start tbblue.mmc&lt;br /&gt;
# prints value in sector units, like:&lt;br /&gt;
# Start&lt;br /&gt;
#    63&lt;br /&gt;
# This has to be multiplied by 512 to get byte offset: 63*512 = 32256&lt;br /&gt;
&lt;br /&gt;
# or&lt;br /&gt;
&lt;br /&gt;
parted tbblue.mmc unit B print&lt;br /&gt;
# prints values in bytes with &amp;quot;B&amp;quot; suffix in &amp;quot;Start&amp;quot; column&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
But the fdisk output can be incorporated directly into mount command, which needs root permissions, example with sudo:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo mount tbblue.mmc next-card/ -o loop,offset=$((`fdisk -l -o Start tbblue.mmc | tail -1` * 512)),user,uid=`id -u`,gid=`id -g`&lt;br /&gt;
&lt;br /&gt;
# or you can enter the offset yourself&lt;br /&gt;
&lt;br /&gt;
sudo mount tbblue.mmc next-card/ -o loop,offset=32256,user,uid=`id -u`,gid=`id -g`&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The uid and gid options will mount the filesystem under your regular user, so you can now browse it with file manager, text editors, etc.&lt;br /&gt;
&lt;br /&gt;
Do not run the emulator yet, before unmounting the image (after you are done manipulating the files)!&lt;br /&gt;
&lt;br /&gt;
=== Unmount the image before using it in emulator ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo umount next-card/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Check the result. If the unmounting fails (probably with &amp;quot;target is busy&amp;quot;), find which process is still accessing/viewing the files in the next-card directory, and try to unmount it again.&lt;br /&gt;
&lt;br /&gt;
== Mounting sd-card image with losetup ==&lt;br /&gt;
&lt;br /&gt;
Alternative using losetup to use local &amp;quot;loop&amp;quot; device for mounting the image. This method can automatically detect partitions inside the image and exposes them as loop devices.&lt;br /&gt;
&lt;br /&gt;
Prepare mounting dir and make sure you have &amp;lt;code&amp;gt;mount&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;losetup&amp;lt;/code&amp;gt; available, Ubuntu based systems packages:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install util-linux mount&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Use losetup to attach image and scan its partitions ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo losetup --partscan --show --find NextZXOS.img&lt;br /&gt;
# this will print new loop device and automatically create partition devices like /dev/loop0p1&lt;br /&gt;
# now mount the desired FAT32 partition:&lt;br /&gt;
sudo mount /dev/loop0p1 next-card/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Unmounting and cleanup of loop device ===&lt;br /&gt;
&lt;br /&gt;
When finished:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo umount next-card/&lt;br /&gt;
sudo losetup -d /dev/loop0&lt;br /&gt;
# or `sudo losetup -D` to detach *ALL* loop devices&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This detaches the loop device and frees all associated /dev/loop* entries.&lt;br /&gt;
&lt;br /&gt;
Notes and gotchas:&lt;br /&gt;
* Do not use the image in an emulator while it is mounted.&lt;br /&gt;
* If the image has no partition table, --partscan will not create /dev/loop0p1.&lt;br /&gt;
* If multiple loop devices are active, check &amp;lt;code&amp;gt;losetup -a&amp;lt;/code&amp;gt; to confirm which one is yours.&lt;br /&gt;
&lt;br /&gt;
== Mounting sd‑card image with udisksctl ==&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;udisksctl&amp;lt;/code&amp;gt; tool provides a desktop‑friendly way to attach loop devices and mount filesystems without manually calculating offsets or using &amp;lt;code&amp;gt;losetup&amp;lt;/code&amp;gt;. It integrates with system services such as UDisks2, and on many desktop Linux systems it allows non‑root users (who are in the correct group) to mount images safely.&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
On Debian‑based systems install the UDisks2 tools:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install udisks2&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To run &amp;lt;code&amp;gt;udisksctl&amp;lt;/code&amp;gt; without &amp;lt;code&amp;gt;sudo&amp;lt;/code&amp;gt;, your user must belong to the &#039;&#039;&#039;disk&#039;&#039;&#039;, &#039;&#039;&#039;storage&#039;&#039;&#039;, or &#039;&#039;&#039;udisks&#039;&#039;&#039; policy group (varies by distribution). If unsure, simply use &amp;lt;code&amp;gt;sudo&amp;lt;/code&amp;gt; in the examples below.&lt;br /&gt;
&lt;br /&gt;
=== Attaching the image as a loop device ===&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;code&amp;gt;udisksctl loop-setup&amp;lt;/code&amp;gt; to create a loop device for the image:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;udisksctl loop-setup --file NextZXOS.img&lt;br /&gt;
# prints something like:&lt;br /&gt;
# Mapped file NextZXOS.img as /dev/loop2.&lt;br /&gt;
# UDisks automatically scans the partition table and exposes partitions as:&lt;br /&gt;
# /dev/loop2p1&lt;br /&gt;
# /dev/loop2p2&lt;br /&gt;
# ...&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Mounting the FAT32 partition ===&lt;br /&gt;
&lt;br /&gt;
Mount the desired partition:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;udisksctl mount --block-device /dev/loop2p1&lt;br /&gt;
# This prints the mount point, for example:&lt;br /&gt;
# Mounted /dev/loop2p1 at /media/youruser/NextZXOS.&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can now browse and edit the filesystem normally using your file manager or command‑line tools.&lt;br /&gt;
&lt;br /&gt;
=== Unmounting and cleanup ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;udisksctl unmount --block-device /dev/loop2p1&lt;br /&gt;
udisksctl loop-delete --block-device /dev/loop2&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This cleanly detaches the loop device and removes all &amp;lt;code&amp;gt;/dev/loop*&amp;lt;/code&amp;gt; entries created for the image.&lt;br /&gt;
&lt;br /&gt;
=== Notes and gotchas ===&lt;br /&gt;
&lt;br /&gt;
* Do not use the image in an emulator while it is mounted, parallel access may corrupt data.&lt;br /&gt;
* If the image has no partition table, UDisks will not create &#039;&#039;&#039;/dev/loopXp1&#039;&#039;&#039; and you must mount manually using an offset.&lt;br /&gt;
* Mount points are created under &amp;lt;code&amp;gt;/media/$USER/&amp;lt;/code&amp;gt; unless overridden by system policy.&lt;br /&gt;
* UDisks may auto‑mount partitions immediately after &#039;&#039;&#039;loop‑setup&#039;&#039;&#039; depending on desktop environment settings.&lt;br /&gt;
&lt;br /&gt;
== MAME emulator ==&lt;br /&gt;
&lt;br /&gt;
MAME got Next emulation and it got improved a lot around end of 2025, turning it into probably most accurate and performant Next emulator currently available. But as that shift is quite recent, the developers community haven’t transitioned to it yet in large numbers and the tutorials and examples are non-existent. This section provides a basic Linux setup guide.&lt;br /&gt;
&lt;br /&gt;
This chapter focuses only on installing MAME from source code git repository, so you can update to latest work in progress or even contribute to the development yourself. The stable binary releases already contain decent Next emulation, but bug fixes and improvements are still coming often and stable releases trail a few weeks behind.&lt;br /&gt;
&lt;br /&gt;
At the moment, the primary developer working on Next emulation in MAME is Andrei Holub, so his fork repo will be used as default source.&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
You need C++17 compiler (GCC 10.3+ or clang 11+), GNU make and few more development tools and common libraries, for specific list for your distro and up to date information check [https://docs.mamedev.org/initialsetup/compilingmame.html Compiling MAME] web page from official docs.&lt;br /&gt;
&lt;br /&gt;
Keep this page around as the example here is quick hint and not meant as replacement for full documentation.&lt;br /&gt;
&lt;br /&gt;
=== Retrieving the MAME source ===&lt;br /&gt;
&lt;br /&gt;
Use git to clone the [https://github.com/holub/mame holub&#039;s MAME repository] and add the [https://github.com/mamedev/mame official MAME repository] as an additional remote:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;git clone --origin holubdev https://github.com/holub/mame.git&lt;br /&gt;
cd mame&lt;br /&gt;
git remote add -f --tags mamedev https://github.com/mamedev/mame.git&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To update already cloned repository checked out at master branch, do inside the mame folder (WARNING: this will drop any local changes in the repository, as MAME devs often rewrite already published commits and you need to reset your local clone to latest state - if you are developer working on MAME sources, you should know yourself how to work with git to preserve your changes and rebase/merge):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;git fetch --all --force&lt;br /&gt;
git reset --hard master&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
Or use your favourite GIT client app to update the cloned repository.&lt;br /&gt;
&lt;br /&gt;
=== Building the executable binary ===&lt;br /&gt;
&lt;br /&gt;
To &#039;&#039;&#039;rebuild&#039;&#039;&#039; &#039;&#039;&#039;only&#039;&#039;&#039; Next emulation (&#039;&#039;&amp;quot;tbblue&amp;quot;&#039;&#039; machine) and get executable named &amp;lt;code&amp;gt;tbblue&amp;lt;/code&amp;gt;, run &amp;lt;code&amp;gt;make&amp;lt;/code&amp;gt; like this:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# make sure there are no remnants from previous builds&lt;br /&gt;
make clean&lt;br /&gt;
# If you want to, you can change to TOOLS=1 to build also &amp;quot;various additional tools, such as chdman&amp;quot;&lt;br /&gt;
# The name of resulting binary is affected by SUBTARGET=tbblue, leave it out if you want &amp;quot;mame&amp;quot;&lt;br /&gt;
make REGENIE=1 EMULATOR=1 TOOLS=0 SOURCES=sinclair/next/specnext.cpp SUBTARGET=tbblue -j $(nproc)&lt;br /&gt;
# check the build output to confirm that compilation succeeded. To list binary:&lt;br /&gt;
ls -lh tbblue&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This may take a considerable amount of time depending on how powerful your PC is.&lt;br /&gt;
&lt;br /&gt;
If you are developing MAME yourself, you can do incremental build (after REGENIE=1 was used to &amp;quot;generate project files&amp;quot; in previous build and your source code changes don&#039;t require full rebuild) - this will be lot faster of course as usual:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;make SUBTARGET=tbblue -j $(nproc)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To rebuild full MAME including all other emulation targets (computers and arcade machines) - which will take even much longer - use:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;make clean &amp;amp;&amp;amp; make REGENIE=1 EMULATOR=1 TOOLS=0 -j $(nproc)&lt;br /&gt;
# check existence of new binary (the line above will produce default name &amp;quot;mame&amp;quot;)&lt;br /&gt;
ls -lh mame&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Installing the executable and configuration ===&lt;br /&gt;
&lt;br /&gt;
Linux MAME by default [https://docs.mamedev.org/commandline/commandline-all.html#mame-commandline-pathoptions looks for configuration file] in directories: &amp;lt;code&amp;gt;$HOME/.mame;.;ini&amp;lt;/code&amp;gt; (that is search the .mame directory in the current user&#039;s home directory, followed by the current working directory, and finally the directory ini in the current working directory)&lt;br /&gt;
&lt;br /&gt;
For most of the other paths like &amp;lt;code&amp;gt;roms, samples, artwork, ...&amp;lt;/code&amp;gt; it looks by default in current directory &amp;lt;code&amp;gt;.&amp;lt;/code&amp;gt;, but you can provide custom paths in the &amp;lt;code&amp;gt;mame.ini&amp;lt;/code&amp;gt; file.&lt;br /&gt;
&lt;br /&gt;
My (Ped7g) personal preference is to have all these helper directories in $HOME/.mame along the global mame.ini file, so I can launch the same configuration of MAME from any directory on the system and to keep the configuration and helper file outside of the git repository folder where I build the binary. To seed the ini file first time after building from source, you can use &amp;lt;code&amp;gt;mame -createconfig&amp;lt;/code&amp;gt; to get template of .ini file in desired directory (like $HOME/.mame). Then edit the fresh ini file to your liking, for example I added these lines:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# CORE CONFIGURATION OPTIONS&lt;br /&gt;
#&lt;br /&gt;
readconfig                1&lt;br /&gt;
writeconfig               0&lt;br /&gt;
&lt;br /&gt;
#&lt;br /&gt;
# CORE SEARCH PATH OPTIONS&lt;br /&gt;
#&lt;br /&gt;
inipath                   $HOME/.mame&lt;br /&gt;
homepath                  $HOME/.mame/lua&lt;br /&gt;
rompath                   $HOME/.mame/roms&lt;br /&gt;
hashpath                  $HOME/.mame/hash&lt;br /&gt;
samplepath                $HOME/.mame/samples&lt;br /&gt;
artpath                   $HOME/.mame/artwork&lt;br /&gt;
ctrlrpath                 $HOME/.mame/ctrlr&lt;br /&gt;
fontpath                  $HOME/.mame&lt;br /&gt;
cheatpath                 $HOME/.mame/cheat&lt;br /&gt;
crosshairpath             $HOME/.mame/crosshair&lt;br /&gt;
pluginspath               $HOME/.mame/plugins&lt;br /&gt;
languagepath              $HOME/.mame/language&lt;br /&gt;
swpath                    $HOME/.mame/software&lt;br /&gt;
&lt;br /&gt;
#&lt;br /&gt;
# CORE OUTPUT DIRECTORY OPTIONS&lt;br /&gt;
#&lt;br /&gt;
cfg_directory             $HOME/.mame/cfg&lt;br /&gt;
nvram_directory           $HOME/.mame/nvram&lt;br /&gt;
input_directory           $HOME/.mame/inp&lt;br /&gt;
state_directory           $HOME/.mame/sta&lt;br /&gt;
snapshot_directory        $HOME/.mame/snap&lt;br /&gt;
diff_directory            $HOME/.mame/diff&lt;br /&gt;
comment_directory         $HOME/.mame/comments&lt;br /&gt;
share_directory           $HOME/.mame/share&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
TODO&lt;br /&gt;
- explain how the helper subfolders are set (create vs symlinks)&lt;br /&gt;
- helper launcher&lt;br /&gt;
&lt;br /&gt;
=== Checking if it all works ===&lt;br /&gt;
&lt;br /&gt;
TODO&lt;br /&gt;
&lt;br /&gt;
== #CSpect emulator ==&lt;br /&gt;
&lt;br /&gt;
The #CSpect is Mike Dailly&#039;s ZX Spectrum Next emulator, written in C# making it cross-platform (sort of, where the mono framework is available). It is non-free (closed-source, custom license) project, but available for usage without any payment (it&#039;s possible to use it internally to develop also commercial titles, but you can not distribute/sell the emulator itself, not even packaged with your game - for such agreement contact the author first and get his permission).&lt;br /&gt;
&lt;br /&gt;
Currently it is most performant and user friendly emulator of ZX Spectrum Next, with good emulation accuracy (see [https://wiki.specnext.dev/CSpect:known_bugs CSpect:known_bugs] page for more detailed report).&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
On Debian based systems make sure you have these packages installed:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install mono-complete libopenal1 libsdl2-dev&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Retrieving the #CSpect package ===&lt;br /&gt;
&lt;br /&gt;
Use web browser to visit itch.io dedicated to CSpect project [https://mdf200.itch.io/cspect mdf200.itch.io/cspect] and download latest release.&lt;br /&gt;
&lt;br /&gt;
You may get warnings from your browser or antivirus about the page itself and about the zip/binary files. The #CSpect has long record of triggering false positives of AV engines due to the executable being not digitally signed and because of the code using features of OS which are normal for emulator, but may look wonky for AV heuristic. Whether you trust the executable is virus free is up to you, in the end.&lt;br /&gt;
&lt;br /&gt;
=== Installing the executable ===&lt;br /&gt;
&lt;br /&gt;
Unzip the retrieved zip file (I personally use KDE Dolphin file manager, the file context menu &#039;&#039;&amp;quot;Extract -&amp;gt; Extract archive here, autodetect subfolder&amp;quot;&#039;&#039;), and place the unzipped directory to target destination (&amp;lt;code&amp;gt;~/zx/emulators/CSpect/CSpect2_13_0&amp;lt;/code&amp;gt; in my case). I prefer to keep every version in its own directory, and have general symbolic link pointing to the one I want use by default:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;cd ~/zx/emulators/CSpect&lt;br /&gt;
ln -s CSpect2_13_0 CSpect_current&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then I create launcher bash-scripts in my &amp;lt;code&amp;gt;~/.local/bin&amp;lt;/code&amp;gt; like this (name of script &amp;lt;code&amp;gt;runCSpect&amp;lt;/code&amp;gt;):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;#!/bin/bash&lt;br /&gt;
# personal script of Ped to launch &amp;quot;#CSpect&amp;quot; emulator in &amp;quot;current directory&amp;quot; (with arguments like: &amp;quot;runCSpect file.nex&amp;quot;)&lt;br /&gt;
MONO_IOMAP=all mono ~/zx/emulators/CSpect/CSpect_current/CSpect.exe -tv -zxnext -s28 -w4 -mmc=./ &amp;quot;$@&amp;quot;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notes: I don&#039;t know any more what &amp;lt;code&amp;gt;MONO_IOMAP=all&amp;lt;/code&amp;gt; helps with, I believe it was suggested to help with any filesystem windows-like paths containing backslashes, you can try to do your own research. The &amp;lt;code&amp;gt;-tv&amp;lt;/code&amp;gt; switch will switch off &amp;quot;scanlines&amp;quot; shader effect and generally switch off any GPU shaders, which makes CSpect more compatible with graphics drivers (try it, if you get only black screen or instant crash during init). The &amp;lt;code&amp;gt;-w4&amp;lt;/code&amp;gt; will make the window quite large - 4x scale, the &amp;lt;code&amp;gt;-zxnext -s28&amp;lt;/code&amp;gt; switch #CSpect into ZX Next emulation mode and set 28Mhz speed of OS as default. And finally the &amp;lt;code&amp;gt;-mmc=./ &amp;quot;$@&amp;quot;&amp;lt;/code&amp;gt; will set &#039;&#039;current directory&#039;&#039; for esxdos emulation to the directory where you use the script to launch the emulator, and pass any remaining command line options entered by user, like the name of the SNA/NEX file. Other noteworthy options are &amp;lt;code&amp;gt;-debug -brk -map=file.map&amp;lt;/code&amp;gt;, the -debug entering the debugger just ahead of the first instruction, -brk enables CSpect specific two-byte tag 0xDD 0x01 to work as breakpoint and the -map option allows you to load into debugger the symbol table from your assembler (directive CSPECTMAP in sjasmplus), making labels visible in disassembly.&lt;br /&gt;
&lt;br /&gt;
=== Checking if it all works ===&lt;br /&gt;
&lt;br /&gt;
Go to some directory with SNA/SNX/NEX file (there are also some demo files right in the CSpect directory) and use the launcher script, like:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;runCSpect beast.nex&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see #CSpect emulator window running the beast.nex demo (or whatever else you did want to launch and entered as argument).&lt;br /&gt;
&lt;br /&gt;
[[File:Cspect_test_run.png|frameless|Running CSpect from directory with test snapshots]]&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=Assemblers&amp;diff=41903</id>
		<title>Assemblers</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=Assemblers&amp;diff=41903"/>
		<updated>2026-04-23T12:55:37Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: sjasmplus version bump&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Any Z80 assembler can produce code suitable for the Next. However the raw blocks of Z80 code may be not as convenient to use with Next or emulators, so a Next specific tools may be useful for creating one of the supported [[File Formats]].&lt;br /&gt;
&lt;br /&gt;
== Cross-platform tools (running on PC) ==&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[http://www.desdes.com/products/oldfiles/zeus.htm Zeus-ish]&#039;&#039; ===&lt;br /&gt;
: Provides a complete Z80 IDE and Macro assembler, scripted disassember plus an integrated Z80 emulator for a range of machines including partial Next support&lt;br /&gt;
: Supports the Next opcodes directly&lt;br /&gt;
: Supports remote debugging on the Next using ParaSys across a serial link&lt;br /&gt;
: Supports MMU paging in the integrated emulator&lt;br /&gt;
: Supports sprites (core versions prior to 2.00.26) in the integrated emulator&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[http://pasmo.speccy.org/ Pasmo]&#039;&#039; ===&lt;br /&gt;
: A long established Z80 assembler, but has been mostly out of development for a long time (0.5.4-beta2 released in 2008, 0.5.5 in 2022)&lt;br /&gt;
: Supports all currently known Next extension opcodes in the 0.5.4-beta2-based 2018 version of [https://github.com/spec-chum/pasmo Pasmo modified by Russ McNulty and Tony Thompson] (also producing .sna files which were at that time used by CSpect).&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;SNasm&#039;&#039; ===&lt;br /&gt;
: Included with the [https://mdf200.itch.io/cspect #CSpect] emulator&lt;br /&gt;
: Full macro assembler&lt;br /&gt;
: Full bank control via Segment management&lt;br /&gt;
: Supports the Next extension opcodes directly&lt;br /&gt;
: Generates full 24bit map files for use in CSpect&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;z80asm&#039;&#039; ===&lt;br /&gt;
: Part of [https://github.com/z88dk/z88dk Z88dk]&#039;&#039;&lt;br /&gt;
: Supports the Next extension opcodes directly, linking assembler with large z80 library, targets any memory configuration&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://github.com/z00m128/sjasmplus z00m&#039;s fork of sjasmplus]&#039;&#039; ===&lt;br /&gt;
: Supports all (core2.00.28) Next extension opcodes, ZXN memory model (8 memory slots with 8ki pages and 1.75MiB virtual device memory), SAVENEX to build NEX files directly from ASM source (NEX version V1.2 (and experimental extension &amp;quot;V1.3&amp;quot;)), MAP files for [https://mdf200.itch.io/cspect #CSpect] emulator, SLD tracing files for [https://github.com/maziac/DeZog DeZog] and [https://github.com/Ckirby101/NDS-NextDevSystem NDS-NextDevSystem] and it is under active development (feedback is welcome).&lt;br /&gt;
: Open source project (&amp;quot;BSD-3-Clause&amp;quot; license), &#039;&#039;&#039;windows executables available at [https://github.com/z00m128/sjasmplus/releases/latest releases]&#039;&#039;&#039;, mac and linux users are expected to simply build from source (both make and CMake are supported).&lt;br /&gt;
: [http://z00m128.github.io/sjasmplus/documentation.html Documentation], latest stable release v1.23.0 2026-04-23&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;zmac&#039;&#039; ===&lt;br /&gt;
&lt;br /&gt;
: [http://48k.ca/zmac.html zmac - Z-80 Macro Cross Assembler]&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://github.com/CatpainBlack/FantASM FantASM]&#039;&#039; ===&lt;br /&gt;
: FantASM is a two pass non optimising assembler for the Z80 processor by [https://github.com/CatpainBlack Guy &#039;CatpainBlack&#039; Black].&lt;br /&gt;
&lt;br /&gt;
:It supports all undocumented op-codes and the extended instruction set of the ZX Next and additional pseudo opcodes used by the CSpect emulator to control debugging.&lt;br /&gt;
&lt;br /&gt;
== Native tools (running on Next) ==&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://gitlab.com/next-tools/odin Odin]&#039;&#039; ===&lt;br /&gt;
&lt;br /&gt;
Work-in-progress Next-specific assembler written by Matt Davies, used also in video tutorials presented by Jim Bagley, the best way to acquire the binary is to join the official ZX Next discord server and check channel &amp;lt;code&amp;gt;#odin&amp;lt;/code&amp;gt; - pinned messages, where you can also discuss any issues and get how-to hints.&lt;br /&gt;
&lt;br /&gt;
: supports most of the undocumented opcodes, all official Z80 and Next-extended instructions&lt;br /&gt;
: supports nested includes and binary includes&lt;br /&gt;
: source is stored in tokenised form (smaller file), up to 48kiB of source in single file&lt;br /&gt;
: assembling can produce 32kiB of machine code (enough to produce simpler dot command)&lt;br /&gt;
: includes also editor and console modules (debugger is planned)&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://www.solarisite.com/spectrumnext.html Sol]&#039;&#039; ===&lt;br /&gt;
&lt;br /&gt;
Sol is an assembler and editor written by Solaris, that runs natively on the Next. Manual, assembler binary and assembler source can be downloaded [https://www.solarisite.com/spectrumnext.html here].&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://gitlab.com/thesmog358/tbblue/-/tree/master/tools/dev/Zeus ZEUS]&#039;&#039; ===&lt;br /&gt;
&lt;br /&gt;
Classic ZEUS native assembler by Simon Brattel, extended and included directly in the ZX Next distro.&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://gitlab.com/thesmog358/tbblue/-/tree/master/tools/dev/SPED SPED]&#039;&#039; ===&lt;br /&gt;
&lt;br /&gt;
Classic SPED assembler by César Hernández Bañó, included directly in the ZX Next distro, see [https://gitlab.com/thesmog358/tbblue/-/raw/master/docs/apps/dev/SPED53readme.txt README].&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://taylorza.itch.io/nextbasic-inline-assembler NextBASIC Inline Assembler]&#039;&#039;===&lt;br /&gt;
Enables you to write inline assembly code in your NextBASIC application. The assembler can be downloaded from [https://taylorza.itch.io/nextbasic-inline-assembler HERE] with documentation available [https://github.com/taylorza/zxn-inlineasm-doc/blob/main/README.md HERE]&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=MAME:Installing&amp;diff=41901</id>
		<title>MAME:Installing</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=MAME:Installing&amp;diff=41901"/>
		<updated>2026-04-22T22:12:51Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: fix urls to specnext.cpp&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[https://www.mamedev.org/ MAME] (formerly an acronym of Multiple Arcade Machine Emulator) is a free and open-source emulator designed to emulate the hardware of arcade games, later expanded to include video game consoles, old computers and other systems in software on modern personal computers and other platforms.&lt;br /&gt;
&lt;br /&gt;
MAME has supported the ZX Spectrum Next since version 0.267. The existing implementation is based on the v3.02.01 core and implements most of the features.&lt;br /&gt;
&lt;br /&gt;
= Installation =&lt;br /&gt;
&lt;br /&gt;
You will need to install MAME, provide it with the Next firmware (&#039;ROM&#039;), and get the NextZXOS image:&lt;br /&gt;
&lt;br /&gt;
=== 1. Get MAME ===&lt;br /&gt;
Start with these official MAME releases. If you encounter crashes or other bugs, try replacing the MAME executable with holub&#039;s latest Continuous Integration (CI) builds as described at the end of this article.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Windows:&#039;&#039;&#039; Download [https://www.mamedev.org/release.html MAME for Windows].&lt;br /&gt;
* &#039;&#039;&#039;macOS:&#039;&#039;&#039; Download [https://sdlmame.lngn.net/ MAME for macOS].&lt;br /&gt;
* &#039;&#039;&#039;Linux:&#039;&#039;&#039; Install MAME from the flatpak repositories by running:&lt;br /&gt;
&amp;lt;pre&amp;gt;sudo flatpak install org.mamedev.MAME&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that Windows and macOS will likely prevent you from launching MAME directly for security reasons. See below on how to solve this.&lt;br /&gt;
&lt;br /&gt;
Alternatively, for the MAME platform as a whole, you can also check your package manager, or [https://docs.mamedev.org/initialsetup/compilingmame.html build from sources].&lt;br /&gt;
&lt;br /&gt;
Git of official MAME: [https://github.com/mamedev/mame/ https://github.com/mamedev/mame/] [https://github.com/mamedev/mame/blob/master/src/mame/sinclair/next/specnext.cpp specnext.cpp]&lt;br /&gt;
&lt;br /&gt;
Git of holub&#039;s fork: [https://github.com/holub/mame https://github.com/holub/mame] [https://github.com/holub/mame/blob/master/src/mame/sinclair/next/specnext.cpp specnext.cpp] (may contain extra fixes and features before they are merged to official repository)&lt;br /&gt;
&lt;br /&gt;
=== 2. Get TBBLUE (the Next &#039;boot ROM&#039;) ===&lt;br /&gt;
Put the file  [https://github.com/Threetwosevensixseven/NexCreator/raw/master/bootroms/tbblue.zip tbblue.zip] into MAME&#039;s &amp;lt;code&amp;gt;roms&amp;lt;/code&amp;gt; folder. Don&#039;t extract it; MAME will look for the zip file when the &amp;quot;tbblue&amp;quot; machine is selected.&lt;br /&gt;
&lt;br /&gt;
Note: The ROMs in this zip are what is embedded inside the FPGA core on real Next hardware. They&#039;re different from any ZX Spectrum machine ROMs you may be used to using, that are on the distro, SD card or SD image file.&lt;br /&gt;
&lt;br /&gt;
=== 3. Get the NextZXOS Image ===&lt;br /&gt;
Get an SD card image file of [https://www.specnext.com/latestdistro/ NextZXOS]. Note that &#039;&#039;&#039;some disk images published  on the official SpecNext.com site do not work with some emulators currently&#039;&#039;&#039; (the &amp;lt;code&amp;gt;latestdistro&amp;lt;/code&amp;gt; link points to the official location where the latest distribution can be found), but &#039;&#039;&#039;all images from &amp;lt;code&amp;gt;https://zxnext.uk/hosted/&amp;lt;/code&amp;gt; work with both MAME and CSpect&#039;&#039;&#039;, like [https://zxnext.uk/hosted/index_files/hdfimages/cspect-next-2gb.zip this SD card image in the zip archive]. Extract the image &amp;lt;code&amp;gt;cspect-next-2gb.img&amp;lt;/code&amp;gt; from the archive to use it, then point MAME to this SD card image with the &amp;lt;code&amp;gt;-hard1&amp;lt;/code&amp;gt; option (or select that file from the menu inside MAME).&lt;br /&gt;
&lt;br /&gt;
= Usage =&lt;br /&gt;
MAME looks for its configuration and helper files in specific (configurable) folders. By default, these are relative to the current working directory (cwd), i.e., from where you launched the executable. The &amp;lt;code&amp;gt;mame.ini&amp;lt;/code&amp;gt; file and folders like &amp;lt;code&amp;gt;roms, bgfx, plugins, language, ...&amp;lt;/code&amp;gt; are expected there, unless the &amp;lt;code&amp;gt;mame.ini&amp;lt;/code&amp;gt; file specifies other paths. When launching through a desktop icon or menu, depending on the OS, the working directory is often defined by the properties of that launch shortcut. When launching MAME from the command line, the current directory is &amp;quot;cwd&amp;quot; (doh). On Linux, MAME will look for &amp;lt;code&amp;gt;mame.ini&amp;lt;/code&amp;gt; first in the &amp;lt;code&amp;gt;~/.mame&amp;lt;/code&amp;gt; folder. You can use the option &amp;lt;code&amp;gt;-inipath&amp;lt;/code&amp;gt; to point MAME to a different path for the &amp;lt;code&amp;gt;mame.ini&amp;lt;/code&amp;gt; file.&lt;br /&gt;
&lt;br /&gt;
However, the fastest way to run a machine with a desired configuration is from the command prompt, without requiring a &amp;lt;code&amp;gt;mame.ini&amp;lt;/code&amp;gt; file. Most of the features are also available through MAME&#039;s UI, although that takes more time to configure.&lt;br /&gt;
&lt;br /&gt;
As an example, this invocation enables the UI, uses &amp;quot;crisp pixels&amp;quot;, starts in a window, doesn&#039;t display the starting gameinfo window (it can still be displayed interactively from the UI), disables the mouse, confirms before exiting MAME, and specifies the disk image (remember to adjust the path to it):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;mame -ui_active -nounevenstretch -aspect 2:1 -video bgfx  -bgfx_screen_chains unfiltered -window -skip_gameinfo -mouse_device none -confirm_quit tbblue -hard1 /path/to/cspect-next-2gb.img&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let&#039;s cover some useful options:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Run inside a window and with no mouse support, until you get familiar with the UI keys:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; mame tbblue -window -mouse_device none -hard1 /path/to/next-distribution.img&amp;lt;/pre&amp;gt;&lt;br /&gt;
To launch the Linux flatpak version using the same options:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; flatpak run org.mamedev.MAME tbblue -window -mouse_device none -hard1 /path/to/next-distribution.img&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Activate UI keys on startup:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -ui_active&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Don&#039;t show the info popup on startup:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -skip_gameinfo&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;Run with debugger. If you don&#039;t request this on startup, you won&#039;t have access to it:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -debug&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;Use &amp;quot;crisp&amp;quot; pixels:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -nounevenstretch -aspect 2:1 -video bgfx -bgfx_screen_chains unfiltered&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;No joystick connected to PC (having this may slightly speed up MAME&#039;s startup, but &#039;&#039;remember to remove this part from the command line and the corresponding setting in the ini file if you do want to use a joystick&#039;&#039;):&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -joystickprovider none&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;Ask for confirmation when exiting MAME (otherwise it&#039;s easy to exit MAME accidentally by hitting ESC, especially when playing games or navigating menus):&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -confirm_quit&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Check the [https://docs.mamedev.org/commandline/commandline-all.html#mame-commandline-universal official MAME documentation] for more advanced usage.&lt;br /&gt;
&lt;br /&gt;
= Security: Allowing MAME to Run on Windows and macOS =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;On Windows,&#039;&#039;&#039; you will need to confirm that you want to launch MAME by clicking &amp;quot;Run Anyway&amp;quot; on first launch. &#039;&#039;(More details needed here.)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;On macOS,&#039;&#039;&#039; MAME will not open at first. Instead, a dialog will appear saying:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;“mame” Not Opened. Apple could not verify “mame” is free of malware that may harm your Mac or compromise your privacy.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Click “Done”. Then open &#039;&#039;&#039;System Settings -&amp;gt; Privacy &amp;amp; Security&#039;&#039;&#039;, and scroll down to the message &#039;&#039;mame was blocked to protect your Mac.&#039;&#039; Click “Allow Anyway”.&lt;br /&gt;
&lt;br /&gt;
Now launch MAME again. A dialog will ask once more if you want to open “mame”. Click “Open Anyway”, and enter your password or use Touch ID when prompted by macOS.&lt;br /&gt;
&lt;br /&gt;
From now on, you can launch this version of MAME without warnings. However, you &#039;&#039;&#039;will&#039;&#039;&#039; need to repeat this each time you update MAME.&lt;br /&gt;
&lt;br /&gt;
= Keys =&lt;br /&gt;
&lt;br /&gt;
Keys are emulated in two modes: either to control the MAME emulator or completely dedicated to the emulated system (the Next). You can toggle between these two keyboard modes with ScrLk (on Win and Linux) or fn+delete (on Mac).&lt;br /&gt;
&lt;br /&gt;
Some UI keys:&lt;br /&gt;
* F3 - soft reset&lt;br /&gt;
* Shift+F3 - hard reset&lt;br /&gt;
* F4 - sprites/tiles/font viewer (Enter, ], [)&lt;br /&gt;
* F5 - pause emulation&lt;br /&gt;
* F6 - save state&lt;br /&gt;
* F7 - load state&lt;br /&gt;
* Tab - emulator settings&lt;br /&gt;
* ~ - menu&lt;br /&gt;
* ` (backtick) - debugger (when enabled by starting MAME with &amp;lt;code&amp;gt;-debug&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;-d&amp;lt;/code&amp;gt; on the command line)&lt;br /&gt;
* PgDwn (Linux/Mac), fn-Downarrow (MacBooks) or Insert (Win) - hold down to fast-forward emulation at maximum speed, e.g., to speed up booting the Next&lt;br /&gt;
* Esc - exit (exits menus but also the entire emulator - see &amp;lt;code&amp;gt;-confirm_quit&amp;lt;/code&amp;gt; option above)&lt;br /&gt;
* F11 - DivMMC NMI&lt;br /&gt;
* F12 - Multiface NMI&lt;br /&gt;
&lt;br /&gt;
Check [https://docs.mamedev.org/usingmame/defaultkeys.html default keys documentation] for more.&lt;br /&gt;
&lt;br /&gt;
= Changing the UI toggle key =&lt;br /&gt;
&lt;br /&gt;
Some laptops don&#039;t have a Scroll Lock key, so you may not be able to exit MAME if you run it in full-screen mode. In these cases, you can change the UI toggle key as follows:&lt;br /&gt;
&lt;br /&gt;
* Run MAME without any command line arguments (except maybe -window) to open its GUI.&lt;br /&gt;
* Push TAB and enter the General Settings menu.&lt;br /&gt;
* Go to Input Assignments -&amp;gt; User Interface -&amp;gt; Toggle UI controls and select a new key. I use Right Alt / Alt GR.&lt;br /&gt;
* Return to the previous menu twice, then choose Save Settings&lt;br /&gt;
&lt;br /&gt;
= Creating and manipulating NextZXOS SD card image =&lt;br /&gt;
&lt;br /&gt;
Most users wanting to emulate the Next using MAME will be fine using a pre-built SD card image downloaded from the site hosting best pre-made images (currently, [https://zxnext.uk/hosted zxnext.uk/hosted] ) website. The following guide is provided for anyone wanting to create a NextZXOS SD card image from scratch.&lt;br /&gt;
&lt;br /&gt;
Download the [https://www.specnext.com/latestdistro/ latest NextZXOS distribution zip file] (named something like sn-complete-WX.YZ.zip) and extract it into a new, empty directory.&lt;br /&gt;
&lt;br /&gt;
== Creating and populating a SD card image using hdfmonkey jjjs build ==&lt;br /&gt;
&lt;br /&gt;
The [https://www.specnext.com/forum/viewtopic.php?t=2604 hdfmonkey &amp;quot;jjjs build&amp;quot;] is a variant of hdfmonkey tool which includes some unique features and its main archive (at the previously given link) also contains pre-built binaries for Windows x64, MacOS x64, MacOS Apple Silicon and Linux x64. (Alternatively, the process to build a local Linux version of the executable is described [[Development_Tools:Linux_setup#hdfmonkey_tool | here]] )&lt;br /&gt;
&lt;br /&gt;
If you extracted sn-complete-WX.YZ.zip into a subdirectory named &amp;lt;code&amp;gt;snWXYZ&amp;lt;/code&amp;gt;, and you want to create a 1GB image called &amp;lt;code&amp;gt;NextZXOS.img&amp;lt;/code&amp;gt; and you have a jjjs build&amp;quot; of hdfmonkey, then it&#039;s enough to do:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
hdfmonkey create NextZXOS.img 1G&lt;br /&gt;
hdfmonkey putdir NextZXOS.img snWXYZ /&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first line creates an empty 1GB image and formats it with the best FAT parameters suited to the size of the image.&lt;br /&gt;
&lt;br /&gt;
The second line recursively copies all the content of the directory &amp;lt;code&amp;gt;snWXYZ&amp;lt;/code&amp;gt; to the image, preserving the directory structure inside, starting from the &amp;lt;code&amp;gt;/&amp;lt;/code&amp;gt; in the image.&lt;br /&gt;
&lt;br /&gt;
One of the advantages of this method is that even if the image has a capacity of 1GB, it will use much less space on your hard drive until you fill up the image. On Linux or MacOS, a command &amp;lt;code&amp;gt;du -h NextZXOS.img&amp;lt;/code&amp;gt; shows the actual amount of disk space used by the image. On Windows the same information can be seen in the File Properties dialog.&lt;br /&gt;
&lt;br /&gt;
The fastest way to transfer a file or a directory (including its content, recursively) into an image is by using a single &amp;lt;code&amp;gt;put&amp;lt;/code&amp;gt; (or &amp;lt;code&amp;gt;putdir&amp;lt;/code&amp;gt;, if it&#039;s to transfer the directory file content to an existing directory) command of hdfmonkey.&lt;br /&gt;
&lt;br /&gt;
The most convenient tool to copy of all the content from the image to a folder outside of the image is 7-zip. On Windows, just use the 7-zip GUI. On MacOS and Linux, see: [[Development_Tools:Linux_setup#Extracting_all_files_from_the_sd-card_image]].&lt;br /&gt;
&lt;br /&gt;
=MAME Plugins and Scripts=&lt;br /&gt;
&lt;br /&gt;
Some MAME plugins and scripts that may be useful for Next developers and end users are listed [[MAME:Plugins_and_Scripts|here]]. They let you speed up the Next boot time, profile your NextBASIC or assembler code, and more.&lt;br /&gt;
&lt;br /&gt;
=Continuous Integration MAME Builds=&lt;br /&gt;
&lt;br /&gt;
MAME is updated on a release schedule, but due to the ongoing nature of development, including for the MAME Next machine, it can sometimes be useful to install a more recent build if it contains a new feature or bugfix you are interested in. Sometimes, this ongoing work is discussed on social media, such as the [https://discordapp.com/channels/556228195767156758/752197165891321886 Next Developer Discord].&lt;br /&gt;
&lt;br /&gt;
Continuous Integration (CI) builds are available from both the [https://github.com/mamedev/mame/actions primary MAME repo] and [https://github.com/holub/mame/actions holub&#039;s GitHub repo]. Both are considered bleeding-edge, with the primary MAME repo slightly less so. MAME CI builds are available for Windows, Linux, and macOS and are updated automatically whenever code is committed by a maintainer or pushed to the primary repo.&lt;br /&gt;
&lt;br /&gt;
To try out a CI build (more precisely, the resulting binary executable, which is a produced &amp;quot;artifact&amp;quot; of the build process) , first do a full MAME install from the [https://www.mamedev.org/release.html latest release] if you have not already done so. Then back up your main binary from its installation location - these are called something like &amp;lt;code&amp;gt;mame.exe&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;mame&amp;lt;/code&amp;gt;. You can always restore these if the CI build doesn&#039;t work, or if you don&#039;t like how it behaves.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;You need to be logged in to github&#039;&#039;&#039; to download CI artifacts, so [https://github.com/login sign in] or [https://github.com/signup sign up].&lt;br /&gt;
&lt;br /&gt;
Then visit one of the links above and find a workflow run item for your platform. Workflow items are the things in the list. The tags are flagged as &amp;lt;code&amp;gt;CI (Windows)&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CI (Linux)&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;CI (macOS)&amp;lt;/code&amp;gt; in the second row of each workflow item in the list (not the filter in the left hand nav menu). Click on a completed workfow item (only items with green checkmarks will have created downloadable binaries yet), find the Artifacts section at the bottom, then click the Download button. Unzip the downloaded file and find the main binary (with the same name as above). Copy the main binary to the install location, overwriting the original one, and run MAME the same way you were running it before. On Windows and macOS, you need to repeat the security steps above to trust the new MAME executable.&lt;br /&gt;
&lt;br /&gt;
= More MAME related links =&lt;br /&gt;
&lt;br /&gt;
MAME [https://docs.mamedev.org/ documentation].&lt;br /&gt;
&lt;br /&gt;
Report any issues with MAME on the [https://mametesters.org/ bugtracker].&lt;br /&gt;
&lt;br /&gt;
For &#039;&#039;&#039;Linux&#039;&#039;&#039; users there are more tips (how to compile MAME from source, how to configure it to not use CWD as starting path for resource directories, how to mount or create image file) at [[Development_Tools:Linux_setup]] page.&lt;br /&gt;
&lt;br /&gt;
[https://docs.mamedev.org/advanced/devicemap.html MAMEDEV.ORG MAME Stable Controller IDs].&lt;br /&gt;
By default, MAME does not assign stable numbers to input devices. For instance, a game pad controller may be assigned to “Joy 1” initially, but after restarting, the same game pad may be reassigned to “Joy 3”.&lt;br /&gt;
Here a some hints how to fixate MAME´s Joystick-Detection to specific Controllers: [https://www.youtube.com/watch?v=YmjfwLuZ_X0 Youtube - Mapping your controllers for stable IDs]&lt;br /&gt;
and: [https://forums.launchbox-app.com/topic/89296-stable-controller-ids-for-mame/ Stable Controller IDs for MAME]&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=Development_Tools:Linux_setup&amp;diff=41900</id>
		<title>Development Tools:Linux setup</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=Development_Tools:Linux_setup&amp;diff=41900"/>
		<updated>2026-04-22T22:11:53Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== General ==&lt;br /&gt;
&lt;br /&gt;
This page collects summaries of installation process of various tools related to ZX Spectrum Next software development for linux OS users.&lt;br /&gt;
&lt;br /&gt;
As usual with linux, most of the suggestions are in the form of command line command to be used from terminal.&lt;br /&gt;
&lt;br /&gt;
== sjasmplus assembler ==&lt;br /&gt;
&lt;br /&gt;
You can also check the [https://www.youtube.com/watch?v=c6I4kdErEwE video] of installing sjasmplus on freshly reinstalled KDE neon 5.20 linux, where is also extended info how to run the automated tests of sjasmplus, and opening it in KDevelop IDE to eventually write your own modifications.&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
On Debian based systems make sure you have these packages installed (git-cola and cmake are optional, but often handy):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install git build-essential g++ git-cola cmake&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Retrieving the sjasmplus source ===&lt;br /&gt;
&lt;br /&gt;
Use git to clone the [https://github.com/z00m128/sjasmplus z00m&#039;s sjasmplus repository]:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;git clone --recursive -j8 https://github.com/z00m128/sjasmplus.git&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To update already cloned repository, do inside the sjasmplus folder:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;git pull&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
- or use your favourite GIT client app to update the cloned repository.&lt;br /&gt;
&lt;br /&gt;
=== Building the executable binary ===&lt;br /&gt;
&lt;br /&gt;
The GNU make and common C++ compiler (gcc or clang) should be enough to build the binary:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;make clean &amp;amp;&amp;amp; make&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To verify the binary was built (&amp;quot;dot slash&amp;quot; prefix to force running of binary in current folder, not system one):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;./sjasmplus --version&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Installing the executable ===&lt;br /&gt;
&lt;br /&gt;
If you already have sjasmplus installed, use &amp;lt;code&amp;gt;which sjasmplus&amp;lt;/code&amp;gt; to see where the installed executable is (and which installed executable has precedence), you can use this command also after installing the new executable to verify it is being picked up by the system.&lt;br /&gt;
&lt;br /&gt;
Installing the binary in system-wide fashion:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo make install&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or you can install the binary only locally for your user (without root/sudo permissions):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;mkdir -p ~/.local/bin&lt;br /&gt;
make PREFIX=~/.local install&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
- then make sure you have &amp;lt;code&amp;gt;~/.local/bin&amp;lt;/code&amp;gt; in your user &amp;lt;code&amp;gt;PATH&amp;lt;/code&amp;gt; environment variable (on some distros there is already script in .profile to add this to PATH if the dir does exist, so you may need to only logout/restart after creating it to get it active).&lt;br /&gt;
&lt;br /&gt;
=== Checking if it all works ===&lt;br /&gt;
&lt;br /&gt;
Open your terminal and type (in any directory):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sjasmplus --version&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see version of the freshly built sjasmplus executable like this:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;SjASMPlus Z80 Cross-Assembler v1.17.0 (https://github.com/z00m128/sjasmplus)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== hdfmonkey tool ==&lt;br /&gt;
&lt;br /&gt;
The hdfmonkey tool can manipulate card-images, helping to write new builds of your project into NextZXOS card-image, to boot the emulators with full file system. (it&#039;s also possible to mount the images directly into linux by other means, to operate on them with regular file manager/etc, but hdfmonkey suits better use-case when the build script does update the image)&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
On Debian based systems make sure you have these packages installed:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install git build-essential g++ autoconf&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Retrieving the hdfmonkey source ===&lt;br /&gt;
&lt;br /&gt;
Use git to clone the [https://github.com/ped7g/hdfmonkey hdfmonkey repository with patched 0.5.7 &amp;lt;code&amp;gt;jjjs version&amp;lt;/code&amp;gt; sources]:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;git clone https://github.com/ped7g/hdfmonkey.git&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
(make sure you are on the default branch &amp;lt;code&amp;gt;&amp;quot;jjjs-variant&amp;quot;&amp;lt;/code&amp;gt; to build the improved version, it should be checked out by default after clone)&lt;br /&gt;
&lt;br /&gt;
* to update already cloned repository, do inside the hdfmonkey folder:&lt;br /&gt;
  &amp;lt;nowiki&amp;gt;git pull&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
* or use your favourite GIT client app to update the cloned repository.&lt;br /&gt;
* if you cloned original gasman&#039;s repository before, you may want to clone and rebuild here mentioned &amp;lt;code&amp;gt;jjjs version&amp;lt;/code&amp;gt; to get multiple fixes and convenience features.&lt;br /&gt;
&lt;br /&gt;
=== Building the executable binary ===&lt;br /&gt;
&lt;br /&gt;
The hdfmonkey is using autoconf/autotools to build final Makefile, check the hdfmonkey README for &amp;quot;from git&amp;quot; installation notes, at the moment of writing this page, the steps were:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;cd hdfmonkey&lt;br /&gt;
autoheader&lt;br /&gt;
aclocal&lt;br /&gt;
autoconf&lt;br /&gt;
automake -a&lt;br /&gt;
./configure&lt;br /&gt;
make&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To verify the binary was built:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;src/hdfmonkey help&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Installing the executable ===&lt;br /&gt;
&lt;br /&gt;
If you already have hdfmonkey installed, use &amp;lt;code&amp;gt;which hdfmonkey&amp;lt;/code&amp;gt; to see where the installed executable is (and which installed executable has precedence), you can use this command also after installing the new executable to verify it is being picked up by the system.&lt;br /&gt;
&lt;br /&gt;
Installing the binary in system-wide fashion:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo make install&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or you can install the binary only locally for your user (without root/sudo permissions):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;make prefix=~/.local install&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
- then make sure you have &amp;lt;code&amp;gt;~/.local/bin&amp;lt;/code&amp;gt; in your user &amp;lt;code&amp;gt;PATH&amp;lt;/code&amp;gt; environment variable.&lt;br /&gt;
&lt;br /&gt;
=== Checking if it all works ===&lt;br /&gt;
&lt;br /&gt;
Open your terminal and type (in any directory):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;hdfmonkey help&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see help of the freshly built hdfmonkey `jjjs version` executable like this:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;hdfmonkey: utility for manipulating HDF disk images v0.5.7 jjjs&lt;br /&gt;
&lt;br /&gt;
usage: hdfmonkey &amp;lt;command&amp;gt; [args]&lt;br /&gt;
...&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Extracting all files from the sd-card image ==&lt;br /&gt;
&lt;br /&gt;
7-zip is the most convenient tool to extract the the files from the existing image.&lt;br /&gt;
&lt;br /&gt;
To install 7-zip on a Debian system use &amp;lt;code&amp;gt;sudo apt install 7zip&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To extract all the files from an existing image &amp;lt;code&amp;gt;tbblue.img&amp;lt;/code&amp;gt; to a new subdirectory &amp;lt;code&amp;gt;myfiles&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;7z x tbblue.img -omyfiles&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Creating new sd-card image with hdfmonkey ==&lt;br /&gt;
&lt;br /&gt;
This example: &lt;br /&gt;
&lt;br /&gt;
* downloads the archive from the specnext.com&lt;br /&gt;
* unpacks it to the subdirectory &amp;lt;code&amp;gt;tmptb&amp;lt;/code&amp;gt;&lt;br /&gt;
* creates a new SD image (with the space for 2GB files) from all the files&lt;br /&gt;
* deletes the subdirectory &amp;lt;code&amp;gt;tmptb&amp;lt;/code&amp;gt;&lt;br /&gt;
* shows that the new image uses much less than 2GB&lt;br /&gt;
* starts listing the content of the newly created image&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
wget https://www.specnext.com/distro/24.11/sn-complete-24.11.zip&lt;br /&gt;
7z x sn-complete-24.11.zip -otmptb&lt;br /&gt;
hdfmonkey create tbblue.img 2GB&lt;br /&gt;
hdfmonkey putdir tbblue.img tmptb /  &lt;br /&gt;
rm -rf tmptb&lt;br /&gt;
du -h tbblue.img&lt;br /&gt;
7z l tbblue.img | more&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating new sd-card image without hdfmonkey ===&lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to use gnu coreutils and dosfstools to create card image without hdfmonkey, but depending on exact size of image these may be less compatible with various emulator, following example for 1GB card image works in MAME but fails in CSpect (while images created by hdfmonkey tool should work for both emulator, so using &#039;&#039;&#039;hdfmonkey is recommended&#039;&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
truncate -s 1G NextZXOS.img&lt;br /&gt;
parted NextZXOS.img mklabel msdos&lt;br /&gt;
parted NextZXOS.img mkpart primary fat32 2048s 100%&lt;br /&gt;
mkfs.fat -F 32 --offset=2048 NextZXOS.img&lt;br /&gt;
# and now to copy files to image you have to either mount it or use hdfmonkey:&lt;br /&gt;
# hdfmonkey putdir NextZXOS.img tmptb /&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mounting sd-card image directly ==&lt;br /&gt;
&lt;br /&gt;
Sometimes it may be useful to mount the card image directly, to be able to browse it and manipulate with common tools. But make sure you are not using mounted card image also in emulator at the same time, to prevent any data damage by parallel access.&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
On Debian based systems make sure you have these packages installed:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install fdisk mount&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Prepare empty directory to mount the card image into (let&#039;s call it &amp;quot;next-card&amp;quot;) and have the image file around (&amp;quot;tbblue.mmc&amp;quot; in following examples)&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;mkdir -p next-card&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Mounting the card image ===&lt;br /&gt;
&lt;br /&gt;
To mount the card image you need to know the exact byte-offset where the FAT partition starts, it&#039;s possible to read it from &amp;quot;fdisk&amp;quot; or &amp;quot;parted&amp;quot; tools outputs:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;fdisk -l -o Start tbblue.mmc&lt;br /&gt;
# prints value in sector units, like:&lt;br /&gt;
# Start&lt;br /&gt;
#    63&lt;br /&gt;
# This has to be multiplied by 512 to get byte offset: 63*512 = 32256&lt;br /&gt;
&lt;br /&gt;
# or&lt;br /&gt;
&lt;br /&gt;
parted tbblue.mmc unit B print&lt;br /&gt;
# prints values in bytes with &amp;quot;B&amp;quot; suffix in &amp;quot;Start&amp;quot; column&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
But the fdisk output can be incorporated directly into mount command, which needs root permissions, example with sudo:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo mount tbblue.mmc next-card/ -o loop,offset=$((`fdisk -l -o Start tbblue.mmc | tail -1` * 512)),user,uid=`id -u`,gid=`id -g`&lt;br /&gt;
&lt;br /&gt;
# or you can enter the offset yourself&lt;br /&gt;
&lt;br /&gt;
sudo mount tbblue.mmc next-card/ -o loop,offset=32256,user,uid=`id -u`,gid=`id -g`&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The uid and gid options will mount the filesystem under your regular user, so you can now browse it with file manager, text editors, etc.&lt;br /&gt;
&lt;br /&gt;
Do not run the emulator yet, before unmounting the image (after you are done manipulating the files)!&lt;br /&gt;
&lt;br /&gt;
=== Unmount the image before using it in emulator ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo umount next-card/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Check the result. If the unmounting fails (probably with &amp;quot;target is busy&amp;quot;), find which process is still accessing/viewing the files in the next-card directory, and try to unmount it again.&lt;br /&gt;
&lt;br /&gt;
== Mounting sd-card image with losetup ==&lt;br /&gt;
&lt;br /&gt;
Alternative using losetup to use local &amp;quot;loop&amp;quot; device for mounting the image. This method can automatically detect partitions inside the image and exposes them as loop devices.&lt;br /&gt;
&lt;br /&gt;
Prepare mounting dir and make sure you have &amp;lt;code&amp;gt;mount&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;losetup&amp;lt;/code&amp;gt; available, Ubuntu based systems packages:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install util-linux mount&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Use losetup to attach image and scan its partitions ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo losetup --partscan --show --find NextZXOS.img&lt;br /&gt;
# this will print new loop device and automatically create partition devices like /dev/loop0p1&lt;br /&gt;
# now mount the desired FAT32 partition:&lt;br /&gt;
sudo mount /dev/loop0p1 next-card/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Unmounting and cleanup of loop device ===&lt;br /&gt;
&lt;br /&gt;
When finished:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo umount next-card/&lt;br /&gt;
sudo losetup -d /dev/loop0&lt;br /&gt;
# or `sudo losetup -D` to detach *ALL* loop devices&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This detaches the loop device and frees all associated /dev/loop* entries.&lt;br /&gt;
&lt;br /&gt;
Notes and gotchas:&lt;br /&gt;
* Do not use the image in an emulator while it is mounted.&lt;br /&gt;
* If the image has no partition table, --partscan will not create /dev/loop0p1.&lt;br /&gt;
* If multiple loop devices are active, check &amp;lt;code&amp;gt;losetup -a&amp;lt;/code&amp;gt; to confirm which one is yours.&lt;br /&gt;
&lt;br /&gt;
== Mounting sd‑card image with udisksctl ==&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;udisksctl&amp;lt;/code&amp;gt; tool provides a desktop‑friendly way to attach loop devices and mount filesystems without manually calculating offsets or using &amp;lt;code&amp;gt;losetup&amp;lt;/code&amp;gt;. It integrates with system services such as UDisks2, and on many desktop Linux systems it allows non‑root users (who are in the correct group) to mount images safely.&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
On Debian‑based systems install the UDisks2 tools:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install udisks2&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To run &amp;lt;code&amp;gt;udisksctl&amp;lt;/code&amp;gt; without &amp;lt;code&amp;gt;sudo&amp;lt;/code&amp;gt;, your user must belong to the &#039;&#039;&#039;disk&#039;&#039;&#039;, &#039;&#039;&#039;storage&#039;&#039;&#039;, or &#039;&#039;&#039;udisks&#039;&#039;&#039; policy group (varies by distribution). If unsure, simply use &amp;lt;code&amp;gt;sudo&amp;lt;/code&amp;gt; in the examples below.&lt;br /&gt;
&lt;br /&gt;
=== Attaching the image as a loop device ===&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;code&amp;gt;udisksctl loop-setup&amp;lt;/code&amp;gt; to create a loop device for the image:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;udisksctl loop-setup --file NextZXOS.img&lt;br /&gt;
# prints something like:&lt;br /&gt;
# Mapped file NextZXOS.img as /dev/loop2.&lt;br /&gt;
# UDisks automatically scans the partition table and exposes partitions as:&lt;br /&gt;
# /dev/loop2p1&lt;br /&gt;
# /dev/loop2p2&lt;br /&gt;
# ...&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Mounting the FAT32 partition ===&lt;br /&gt;
&lt;br /&gt;
Mount the desired partition:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;udisksctl mount --block-device /dev/loop2p1&lt;br /&gt;
# This prints the mount point, for example:&lt;br /&gt;
# Mounted /dev/loop2p1 at /media/youruser/NextZXOS.&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can now browse and edit the filesystem normally using your file manager or command‑line tools.&lt;br /&gt;
&lt;br /&gt;
=== Unmounting and cleanup ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;udisksctl unmount --block-device /dev/loop2p1&lt;br /&gt;
udisksctl loop-delete --block-device /dev/loop2&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This cleanly detaches the loop device and removes all &amp;lt;code&amp;gt;/dev/loop*&amp;lt;/code&amp;gt; entries created for the image.&lt;br /&gt;
&lt;br /&gt;
=== Notes and gotchas ===&lt;br /&gt;
&lt;br /&gt;
* Do not use the image in an emulator while it is mounted, parallel access may corrupt data.&lt;br /&gt;
* If the image has no partition table, UDisks will not create &#039;&#039;&#039;/dev/loopXp1&#039;&#039;&#039; and you must mount manually using an offset.&lt;br /&gt;
* Mount points are created under &amp;lt;code&amp;gt;/media/$USER/&amp;lt;/code&amp;gt; unless overridden by system policy.&lt;br /&gt;
* UDisks may auto‑mount partitions immediately after &#039;&#039;&#039;loop‑setup&#039;&#039;&#039; depending on desktop environment settings.&lt;br /&gt;
&lt;br /&gt;
== MAME emulator ==&lt;br /&gt;
&lt;br /&gt;
MAME got Next emulation and it got improved a lot around end of 2025, turning it into probably most accurate and performant Next emulator currently available. But as that shift is quite recent, the developers community haven’t transitioned to it yet in large numbers and the tutorials and examples are non-existent. This section provides a basic Linux setup guide.&lt;br /&gt;
&lt;br /&gt;
This chapter focuses only on installing MAME from source code git repository, so you can update to latest work in progress or even contribute to the development yourself. The stable binary releases already contain decent Next emulation, but bug fixes and improvements are still coming often and stable releases trail a few weeks behind.&lt;br /&gt;
&lt;br /&gt;
At the moment, the primary developer working on Next emulation in MAME is Andrei Holub, so his fork repo will be used as default source.&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
You need C++17 compiler (GCC 10.3+ or clang 11+), GNU make and few more development tools and common libraries, for specific list for your distro and up to date information check [https://docs.mamedev.org/initialsetup/compilingmame.html Compiling MAME] web page from official docs.&lt;br /&gt;
&lt;br /&gt;
Keep this page around as the example here is quick hint and not meant as replacement for full documentation.&lt;br /&gt;
&lt;br /&gt;
=== Retrieving the MAME source ===&lt;br /&gt;
&lt;br /&gt;
Use git to clone the [https://github.com/holub/mame holub&#039;s MAME repository] and add the [https://github.com/mamedev/mame official MAME repository] as an additional remote:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;git clone --origin holubdev https://github.com/holub/mame.git&lt;br /&gt;
cd mame&lt;br /&gt;
git remote add -f --tags mamedev https://github.com/mamedev/mame.git&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To update already cloned repository checked out at master branch, do inside the mame folder (WARNING: this will drop any local changes in the repository, as MAME devs often rewrite already published commits and you need to reset your local clone to latest state - if you are developer working on MAME sources, you should know yourself how to work with git to preserve your changes and rebase/merge):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;git fetch --all --force&lt;br /&gt;
git reset --hard master&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
Or use your favourite GIT client app to update the cloned repository.&lt;br /&gt;
&lt;br /&gt;
=== Building the executable binary ===&lt;br /&gt;
&lt;br /&gt;
To &#039;&#039;&#039;rebuild&#039;&#039;&#039; &#039;&#039;&#039;only&#039;&#039;&#039; Next emulation (&#039;&#039;&amp;quot;tbblue&amp;quot;&#039;&#039; machine) and get executable named &amp;lt;code&amp;gt;tbblue&amp;lt;/code&amp;gt;, run &amp;lt;code&amp;gt;make&amp;lt;/code&amp;gt; like this:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# make sure there are no remnants from previous builds&lt;br /&gt;
make clean&lt;br /&gt;
# If you want to, you can change to TOOLS=1 to build also &amp;quot;various additional tools, such as chdman&amp;quot;&lt;br /&gt;
# The name of resulting binary is affected by SUBTARGET=tbblue, leave it out if you want &amp;quot;mame&amp;quot;&lt;br /&gt;
make REGENIE=1 EMULATOR=1 TOOLS=0 SOURCES=sinclair/next/specnext.cpp SUBTARGET=tbblue -j $(nproc)&lt;br /&gt;
# check the build output to confirm that compilation succeeded. To list binary:&lt;br /&gt;
ls -lh tbblue&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This may take a considerable amount of time depending on how powerful your PC is.&lt;br /&gt;
&lt;br /&gt;
If you are developing MAME yourself, you can do incremental build (after REGENIE=1 was used to &amp;quot;generate project files&amp;quot; in previous build and your source code changes don&#039;t require full rebuild) - this will be lot faster of course as usual:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;make SUBTARGET=tbblue -j $(nproc)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To rebuild full MAME including all other emulation targets (computers and arcade machines) - which will take even much longer - use:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;make clean &amp;amp;&amp;amp; make REGENIE=1 EMULATOR=1 TOOLS=0 -j $(nproc)&lt;br /&gt;
# check existence of new binary (the line above will produce default name &amp;quot;mame&amp;quot;)&lt;br /&gt;
ls -lh mame&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Installing the executable and configuration ===&lt;br /&gt;
&lt;br /&gt;
TODO&lt;br /&gt;
&lt;br /&gt;
=== Checking if it all works ===&lt;br /&gt;
&lt;br /&gt;
TODO&lt;br /&gt;
&lt;br /&gt;
== #CSpect emulator ==&lt;br /&gt;
&lt;br /&gt;
The #CSpect is Mike Dailly&#039;s ZX Spectrum Next emulator, written in C# making it cross-platform (sort of, where the mono framework is available). It is non-free (closed-source, custom license) project, but available for usage without any payment (it&#039;s possible to use it internally to develop also commercial titles, but you can not distribute/sell the emulator itself, not even packaged with your game - for such agreement contact the author first and get his permission).&lt;br /&gt;
&lt;br /&gt;
Currently it is most performant and user friendly emulator of ZX Spectrum Next, with good emulation accuracy (see [https://wiki.specnext.dev/CSpect:known_bugs CSpect:known_bugs] page for more detailed report).&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
On Debian based systems make sure you have these packages installed:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install mono-complete libopenal1 libsdl2-dev&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Retrieving the #CSpect package ===&lt;br /&gt;
&lt;br /&gt;
Use web browser to visit itch.io dedicated to CSpect project [https://mdf200.itch.io/cspect mdf200.itch.io/cspect] and download latest release.&lt;br /&gt;
&lt;br /&gt;
You may get warnings from your browser or antivirus about the page itself and about the zip/binary files. The #CSpect has long record of triggering false positives of AV engines due to the executable being not digitally signed and because of the code using features of OS which are normal for emulator, but may look wonky for AV heuristic. Whether you trust the executable is virus free is up to you, in the end.&lt;br /&gt;
&lt;br /&gt;
=== Installing the executable ===&lt;br /&gt;
&lt;br /&gt;
Unzip the retrieved zip file (I personally use KDE Dolphin file manager, the file context menu &#039;&#039;&amp;quot;Extract -&amp;gt; Extract archive here, autodetect subfolder&amp;quot;&#039;&#039;), and place the unzipped directory to target destination (&amp;lt;code&amp;gt;~/zx/emulators/CSpect/CSpect2_13_0&amp;lt;/code&amp;gt; in my case). I prefer to keep every version in its own directory, and have general symbolic link pointing to the one I want use by default:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;cd ~/zx/emulators/CSpect&lt;br /&gt;
ln -s CSpect2_13_0 CSpect_current&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then I create launcher bash-scripts in my &amp;lt;code&amp;gt;~/.local/bin&amp;lt;/code&amp;gt; like this (name of script &amp;lt;code&amp;gt;runCSpect&amp;lt;/code&amp;gt;):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;#!/bin/bash&lt;br /&gt;
# personal script of Ped to launch &amp;quot;#CSpect&amp;quot; emulator in &amp;quot;current directory&amp;quot; (with arguments like: &amp;quot;runCSpect file.nex&amp;quot;)&lt;br /&gt;
MONO_IOMAP=all mono ~/zx/emulators/CSpect/CSpect_current/CSpect.exe -tv -zxnext -s28 -w4 -mmc=./ &amp;quot;$@&amp;quot;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notes: I don&#039;t know any more what &amp;lt;code&amp;gt;MONO_IOMAP=all&amp;lt;/code&amp;gt; helps with, I believe it was suggested to help with any filesystem windows-like paths containing backslashes, you can try to do your own research. The &amp;lt;code&amp;gt;-tv&amp;lt;/code&amp;gt; switch will switch off &amp;quot;scanlines&amp;quot; shader effect and generally switch off any GPU shaders, which makes CSpect more compatible with graphics drivers (try it, if you get only black screen or instant crash during init). The &amp;lt;code&amp;gt;-w4&amp;lt;/code&amp;gt; will make the window quite large - 4x scale, the &amp;lt;code&amp;gt;-zxnext -s28&amp;lt;/code&amp;gt; switch #CSpect into ZX Next emulation mode and set 28Mhz speed of OS as default. And finally the &amp;lt;code&amp;gt;-mmc=./ &amp;quot;$@&amp;quot;&amp;lt;/code&amp;gt; will set &#039;&#039;current directory&#039;&#039; for esxdos emulation to the directory where you use the script to launch the emulator, and pass any remaining command line options entered by user, like the name of the SNA/NEX file. Other noteworthy options are &amp;lt;code&amp;gt;-debug -brk -map=file.map&amp;lt;/code&amp;gt;, the -debug entering the debugger just ahead of the first instruction, -brk enables CSpect specific two-byte tag 0xDD 0x01 to work as breakpoint and the -map option allows you to load into debugger the symbol table from your assembler (directive CSPECTMAP in sjasmplus), making labels visible in disassembly.&lt;br /&gt;
&lt;br /&gt;
=== Checking if it all works ===&lt;br /&gt;
&lt;br /&gt;
Go to some directory with SNA/SNX/NEX file (there are also some demo files right in the CSpect directory) and use the launcher script, like:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;runCSpect beast.nex&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see #CSpect emulator window running the beast.nex demo (or whatever else you did want to launch and entered as argument).&lt;br /&gt;
&lt;br /&gt;
[[File:Cspect_test_run.png|frameless|Running CSpect from directory with test snapshots]]&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=Fallback_Colour_Register&amp;diff=41881</id>
		<title>Fallback Colour Register</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=Fallback_Colour_Register&amp;diff=41881"/>
		<updated>2026-04-05T18:58:08Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: fix default value description&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{NextRegister&lt;br /&gt;
|Number=$4A&lt;br /&gt;
|Readable=Yes&lt;br /&gt;
|Writable=Yes&lt;br /&gt;
|ShortDesc=8-bit colour to be used when all layers contain transparent pixel.&lt;br /&gt;
}}&lt;br /&gt;
Colour format is RRRGGGBB, like {{NextRegNo|$41}} uses.&lt;br /&gt;
&lt;br /&gt;
Value is set to 0xE3 by core upon soft reset, but I (Ped7g) think the NextZXOS sets it to 0 (black colour) upon finishing boot.&lt;br /&gt;
&lt;br /&gt;
This colour is also used for PAPER and BORDER when ULANext mode is enabled, and &amp;quot;full ink&amp;quot; (ink mask = 255) mode is selected.&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=DMA&amp;diff=41879</id>
		<title>DMA</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=DMA&amp;diff=41879"/>
		<updated>2026-03-30T14:13:17Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: Note about command A7 and Zilog docs vs Next FPGA implementation&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
The ZX Spectrum Next DMA (zxnDMA) is a single channel DMA device that implements a subset of the Z80 DMA functionality. The subset is large enough to be compatible with common uses of the similar Datagear interface available for standard ZX Spectrum computers and compatibles. It also adds a burst mode capability that can deliver audio at programmable sample rates to the DAC device.&lt;br /&gt;
&lt;br /&gt;
== Accessing the zxnDMA ==&lt;br /&gt;
&amp;lt;del&amp;gt;The zxnDMA is mapped to a single Read/Write IO Port 0x6B which is the same one used by the Datagear but unlike the Datagear it doesn&#039;t also map itself to a second port 0x0B similar to the MB-02 interface.&amp;lt;/del&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since core 3.1.2 the zxnDMA is mapped to {{PortNo|$xx6B}}, and Zilog-DMA mode is mapped to {{PortNo|$xx0B}}.&lt;br /&gt;
&lt;br /&gt;
== Description  ==&lt;br /&gt;
The normal Z80 DMA (Z8410) chip is a pipelined device and because of that it has numerous off-by-one idiosyncrasies and requirements on the order that certain commands should be carried out. These issues are not duplicated in the zxnDMA. You can continue to program the zxnDMA as if it is were a Z8410 DMA device but it can also be programmed in a simpler manner.&lt;br /&gt;
&lt;br /&gt;
The single channel of the zxnDMA chip consists of two ports named A and B. Transfers can occur in either direction between ports A and B, each port can describe a target in memory or IO, and each can be configured to autoincrement, autodecrement or stay fixed after a byte is transferred.&lt;br /&gt;
&lt;br /&gt;
A special feature of the zxnDMA can force each byte transfer to take a fixed amount of time so that the zxnDMA can be used to deliver sampled audio.&lt;br /&gt;
&lt;br /&gt;
== Modes of Operation ==&lt;br /&gt;
The zxnDMA can operate in a z80-DMA compatibility mode.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;REMOVED in core 3.1.2:&#039;&#039;&#039; &amp;lt;del&amp;gt;The z80-DMA compatibility mode is selected by setting bit 6 of nextreg 0x06. In this mode, all transfers involve length+1 bytes which is the same behaviour as the z80-DMA chip. In zxn-DMA mode, the transfer length is exactly the number of bytes programmed. This mode is mainly present to accommodate existing spectrum software that uses the z80-DMA and for cp/m programs that may have a z80-DMA option.&amp;lt;/del&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Since core 3.1.2:&#039;&#039;&#039; the DMA mode is selected by port number, the {{PortNo|$xx6B}} works in zxnDMA mode, {{PortNo|$xx0B}} works in Zilog mode. The bit 6 in {{NextRegNo|$06}} is not DMA related any more and will be reused for something different.&lt;br /&gt;
&lt;br /&gt;
The zxnDMA can also operate in either burst or continuous modes.&lt;br /&gt;
&lt;br /&gt;
Continuous mode means the DMA chip runs to completion without allowing the CPU to run. When the CPU starts the DMA, the DMA operation will complete before the CPU executes its next instruction.&lt;br /&gt;
&lt;br /&gt;
Burst mode nominally means the DMA lets the CPU run if either port is not ready. This condition can&#039;t happen in the zxnDMA chip except when operated in the special fixed time transfer mode. In this mode, the zxnDMA will let the CPU run while it waits for the fixed time to expire between bytes transferred.&lt;br /&gt;
&lt;br /&gt;
Note that there is no byte transfer mode as in the Z80 DMA.&lt;br /&gt;
&lt;br /&gt;
== Programming the zxnDMA ==&lt;br /&gt;
Like the Z80 DMA chip, the zxnDMA has seven write registers named WR0-WR6 that control the device. Each register WR0-WR6 can have zero or more parameters associated with it.&lt;br /&gt;
&lt;br /&gt;
In a first write to the zxnDMA port, the write value is compared against a bitmask to determine which of the WR0-WR6 is the target. Remaining bits in the written value can contain data as well as a list of associated parameter bits. The parameter bits determine if further writes are expected to deliver parameter values. If there are multiple parameter bits set, the expected order of parameter values written is determined by parameter bit position from right to left (bit 0 through bit 7). Once all parameters are written, the zxnDMA again expects a regular register write selecting WR0-WR6.&lt;br /&gt;
&lt;br /&gt;
The table below describes the registers and the bitmask required to select them on the zxnDMA.&lt;br /&gt;
&lt;br /&gt;
{| &lt;br /&gt;
! Register Group&lt;br /&gt;
! Register Function Description&lt;br /&gt;
! Bitmask&lt;br /&gt;
! Notes&lt;br /&gt;
|- &lt;br /&gt;
| WR0&lt;br /&gt;
| Direction, Operation and Port A configuration&lt;br /&gt;
| &amp;lt;pre&amp;gt;0XXXXXAA&amp;lt;/pre&amp;gt;&lt;br /&gt;
| AA must NOT be 00&lt;br /&gt;
|- &lt;br /&gt;
| WR1&lt;br /&gt;
| Port A configuration&lt;br /&gt;
| &amp;lt;pre&amp;gt;0XXXX100&amp;lt;/pre&amp;gt;&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| WR2&lt;br /&gt;
| Port B configuration&lt;br /&gt;
| &amp;lt;pre&amp;gt;0XXXX000&amp;lt;/pre&amp;gt;&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| WR3&lt;br /&gt;
| Activation&lt;br /&gt;
| &amp;lt;pre&amp;gt;1XXXXX00&amp;lt;/pre&amp;gt;&lt;br /&gt;
| It’s best to use WR6&lt;br /&gt;
|- &lt;br /&gt;
| WR4&lt;br /&gt;
| Port B, Timing and Interrupt configuration&lt;br /&gt;
| &amp;lt;pre&amp;gt;1XXXXX01&amp;lt;/pre&amp;gt;&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| WR5&lt;br /&gt;
| Ready and Stop configuration&lt;br /&gt;
| &amp;lt;pre&amp;gt;10XXX010&amp;lt;/pre&amp;gt;&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| WR6&lt;br /&gt;
| Command Register&lt;br /&gt;
| &amp;lt;pre&amp;gt;1XXXXX11&amp;lt;/pre&amp;gt;&lt;br /&gt;
| &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== zxnDMA Registers ==&lt;br /&gt;
These are described below following the same convention used by Zilog for its DMA chip:&lt;br /&gt;
&lt;br /&gt;
=== WR0 – Write Register Group 0 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;D7  D6  D5  D4  D3  D2  D1  D0  BASE REGISTER BYTE&lt;br /&gt;
 0   |   |   |   |   |   |   |&lt;br /&gt;
     |   |   |   |   |   0   0  Do not use&lt;br /&gt;
     |   |   |   |   |   0   1  Transfer (Prefer this for Z80 DMA compatibility)&lt;br /&gt;
     |   |   |   |   |   1   0  Do not use (Behaves like Transfer, Search on Z80 DMA)&lt;br /&gt;
     |   |   |   |   |                       &lt;br /&gt;
     |   |   |   |   |   1   1  Do not use (Behaves like Transfer, Search/Transfer on Z80 DMA)&lt;br /&gt;
     |   |   |   |   |                      &lt;br /&gt;
     |   |   |   |   0 = Port B -&amp;amp;gt; Port A (Byte transfer direction)&lt;br /&gt;
     |   |   |   |   1 = Port A -&amp;amp;gt; Port B&lt;br /&gt;
     |   |   |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  PORT A STARTING ADDRESS (LOW BYTE)&lt;br /&gt;
     |   |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  PORT A STARTING ADDRESS (HIGH BYTE)&lt;br /&gt;
     |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  BLOCK LENGTH (LOW BYTE)&lt;br /&gt;
     V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  BLOCK LENGTH (HIGH BYTE)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Several registers are accessible from WR0. The first write to WR0 is to the base register byte. Bits D6:D3 are optionally set to indicate that associated registers in this group will be written next. The order the writes come in are from D3 to D6 (right to left). For example, if bits D6 and D3 are set, the next two writes will be directed to PORT A STARTING ADDRESS LOW followed by BLOCK LENGTH HIGH.&lt;br /&gt;
&lt;br /&gt;
=== WR1 – Write Register Group 1 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;D7  D6  D5  D4  D3  D2  D1  D0  BASE REGISTER BYTE&lt;br /&gt;
 0   |   |   |   |   1   0   0&lt;br /&gt;
     |   |   |   |&lt;br /&gt;
     |   |   |   0 = Port A is memory&lt;br /&gt;
     |   |   |   1 = Port A is IO&lt;br /&gt;
     |   |   |&lt;br /&gt;
     |   0   0 = Port A address decrements&lt;br /&gt;
     |   0   1 = Port A address increments&lt;br /&gt;
     |   1   0 = Port A address is fixed&lt;br /&gt;
     |   1   1 = Port A address is fixed&lt;br /&gt;
     |&lt;br /&gt;
     V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  PORT A VARIABLE TIMING BYTE&lt;br /&gt;
 0   0   0   0   0   0   |   |&lt;br /&gt;
                         0   0 = Cycle Length = 4&lt;br /&gt;
                         0   1 = Cycle Length = 3&lt;br /&gt;
                         1   0 = Cycle Length = 2&lt;br /&gt;
                         1   1 = Do not use&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The cycle length is the number of cycles used in a read or write operation. The first cycle asserts signals and the last cycle releases them. There is no half cycle timing for the control signals.&lt;br /&gt;
&lt;br /&gt;
=== WR2 – Write Register Group 2 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;D7  D6  D5  D4  D3  D2  D1  D0  BASE REGISTER BYTE&lt;br /&gt;
 0   |   |   |   |   0   0   0&lt;br /&gt;
     |   |   |   |&lt;br /&gt;
     |   |   |   0 = Port B is memory&lt;br /&gt;
     |   |   |   1 = Port B is IO&lt;br /&gt;
     |   |   |&lt;br /&gt;
     |   0   0 = Port B address decrements&lt;br /&gt;
     |   0   1 = Port B address increments&lt;br /&gt;
     |   1   0 = Port B address is fixed&lt;br /&gt;
     |   1   1 = Port B address is fixed&lt;br /&gt;
     |&lt;br /&gt;
     V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  PORT B VARIABLE TIMING BYTE&lt;br /&gt;
 0   0   |   0   0   0   |   |&lt;br /&gt;
         |               0   0 = Cycle Length = 4&lt;br /&gt;
         |               0   1 = Cycle Length = 3&lt;br /&gt;
         |               1   0 = Cycle Length = 2&lt;br /&gt;
         |               1   1 = Do not use&lt;br /&gt;
         |&lt;br /&gt;
         V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  ZXN PRESCALAR (FIXED TIME TRANSFER)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The ZXN PRESCALAR is a feature of the zxnDMA implementation. If non-zero, a delay will be inserted after each byte is transferred such that the total time needed for each transfer is determined by the prescalar. This works in both the continuous mode and the burst mode. If the DMA is operated in burst mode, the DMA will give up any waiting time to the CPU so that the CPU can run while the DMA is idle.&lt;br /&gt;
&lt;br /&gt;
The rate of transfer is given by the formula “Frate = 875kHz / prescalar” or, rearranged, “prescalar = 875kHz / Frate”. The formula is framed in terms of a sample rate (Frate) but Frate can be inverted to set a transfer time for each byte instead. The 875kHz constant is a nominal value assuming a 28MHz system clock; the system clock actually varies from this depending on the video timing selected by the user (HDMI, VGA0-6) so for complete accuracy the constant should be prorated according to documentation for nextreg 0x11.&lt;br /&gt;
&lt;br /&gt;
In a DMA audio setting, selecting a sample rate of 16kHz would mean setting the prescalar value to 55. This sample period is constant across changes in CPU speed.&lt;br /&gt;
&lt;br /&gt;
=== WR3 – Write Register Group 3 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;D7  D6  D5  D4  D3  D2  D1  D0  BASE REGISTER BYTE&lt;br /&gt;
 1   |   0   0   0   0   0   0&lt;br /&gt;
     |&lt;br /&gt;
     1 = DMA Enable&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The Z80 DMA defines more fields but they are ignored by the zxnDMA. The two other registers defined by the Z80 DMA in this group on D4 and D3 are implemented by the zxnDMA but they do nothing.&lt;br /&gt;
&lt;br /&gt;
It is preferred to start the DMA by writing an &#039;Enable DMA&#039; command to WR6.&lt;br /&gt;
&lt;br /&gt;
=== WR4 – Write Register Group 4 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;D7  D6  D5  D4  D3  D2  D1  D0  BASE REGISTER BYTE&lt;br /&gt;
 1   |   |   0   |   |   0   1&lt;br /&gt;
     |   |       |   |&lt;br /&gt;
     0   0 = Do not use (Behaves like Continuous mode, Byte mode on Z80 DMA)&lt;br /&gt;
     0   1 = Continuous mode&lt;br /&gt;
     1   0 = Burst mode&lt;br /&gt;
     1   1 = Do not use&lt;br /&gt;
                 |   |&lt;br /&gt;
                 |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  PORT B STARTING ADDRESS (LOW BYTE)&lt;br /&gt;
                 |&lt;br /&gt;
                 V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  PORT B STARTING ADDRESS (HIGH BYTE)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The Z80 DMA defines three more registers in this group through D4 that define interrupt behaviour. Interrups and pulse generation are not implemented in the zxnDMA nor are these registers available for writing.&lt;br /&gt;
&lt;br /&gt;
=== WR5 – Write Register Group 5 ===&lt;br /&gt;
&amp;lt;pre&amp;gt;D7  D6  D5  D4  D3  D2  D1  D0  BASE REGISTER BYTE&lt;br /&gt;
 1   0   |   |   0   0   1   0&lt;br /&gt;
         |   |&lt;br /&gt;
         |   0 = /ce only&lt;br /&gt;
         |   1 = /ce &amp;amp; /wait multiplexed&lt;br /&gt;
         |&lt;br /&gt;
         0 = Stop on end of block&lt;br /&gt;
         1 = Auto restart on end of block&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The /ce &amp;amp; /wait mode is implemented in the zxnDMA but is not currently used. This mode has an external device using the DMA&#039;s /ce pin to insert wait states during the DMA&#039;s transfer.&lt;br /&gt;
&lt;br /&gt;
The auto restart feature causes the DMA to automatically reload its source and destination addresses and reset its byte counter to zero to repeat the last transfer when a previous one is finished.&lt;br /&gt;
&lt;br /&gt;
=== WR6 – Command Register ===&lt;br /&gt;
&amp;lt;pre&amp;gt;D7  D6  D5  D4  D3  D2  D1  D0  BASE REGISTER BYTE&lt;br /&gt;
 1   ?   ?   ?   ?   ?   1   1&lt;br /&gt;
     |   |   |   |   |&lt;br /&gt;
     1   0   0   0   0 = 0xC3 = Reset&lt;br /&gt;
     1   0   0   0   1 = 0xC7 = Reset Port A Timing&lt;br /&gt;
     1   0   0   1   0 = 0xCB = Reset Port B Timing&lt;br /&gt;
     0   1   1   0   0 = 0xB3 = Force Ready (irrelevant for zxnDMA)&lt;br /&gt;
     0   1   1   1   1 = 0xBF = Read Status Byte&lt;br /&gt;
     0   0   0   1   0 = 0x8B = Reinitialize Status Byte&lt;br /&gt;
     0   1   0   0   1 = 0xA7 = Initialize Read Sequence&lt;br /&gt;
     1   0   0   1   1 = 0xCF = Load&lt;br /&gt;
     1   0   1   0   0 = 0xD3 = Continue&lt;br /&gt;
     0   0   0   0   1 = 0x87 = Enable DMA&lt;br /&gt;
     0   0   0   0   0 = 0x83 = Disable DMA&lt;br /&gt;
 +-- 0   1   1   1   0 = 0xBB = Read Mask Follows&lt;br /&gt;
 |&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  READ MASK&lt;br /&gt;
 0   |   |   |   |   |   |   |&lt;br /&gt;
     |   |   |   |   |   |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  Status Byte&lt;br /&gt;
     |   |   |   |   |   |&lt;br /&gt;
     |   |   |   |   |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  Byte Counter Low (&amp;quot;High&amp;quot; with core 3.0.5 = bug in core)&lt;br /&gt;
     |   |   |   |   |&lt;br /&gt;
     |   |   |   |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  Byte Counter High (&amp;quot;Low&amp;quot; with core 3.0.5 = bug in core)&lt;br /&gt;
     |   |   |   |&lt;br /&gt;
     |   |   |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  Port A Address Low&lt;br /&gt;
     |   |   |&lt;br /&gt;
     |   |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  Port A Address High&lt;br /&gt;
     |   |&lt;br /&gt;
     |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  Port B Address Low&lt;br /&gt;
     |&lt;br /&gt;
     V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  Port B Address High&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Unimplemented Z80 DMA commands are ignored.&lt;br /&gt;
&lt;br /&gt;
Prior to starting the DMA transfer, a LOAD command must be issued to copy the Port A and Port B addresses into the DMA&#039;s internal pointers. Then an &#039;Enable DMA&#039; command is issued to start the DMA. The last LOAD command before ENABLE must be done with correct transfer direction set.&lt;br /&gt;
&lt;br /&gt;
The &#039;Continue&#039; command resets the DMA&#039;s byte counter so that a following &#039;Enable DMA&#039; allows the DMA to repeat the last transfer but using the current internal address pointers. I.e. it continues from where the last copy operation left off.&lt;br /&gt;
&lt;br /&gt;
Reset and Reset Port A/B Timing commands on zxnDMA do reset also prescalar value.&lt;br /&gt;
&lt;br /&gt;
Registers can be read via an IO read from the DMA port after setting the read mask. (At power up the read mask is set to 0x7f). Register values are the current internal DMA counter values. So &#039;Port Address A Low&#039; is the lower 8-bits of Port A’s next transfer address. Once the end of the read mask is reached, further reads loop around to the first one.&lt;br /&gt;
&lt;br /&gt;
The format of the DMA status byte is as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;00E1101T&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
E is set to 0 if the total block length has been transferred at least once.&lt;br /&gt;
&lt;br /&gt;
T is set to 1 if at least one byte has been transferred.&lt;br /&gt;
&lt;br /&gt;
== Operating speed ==&lt;br /&gt;
The zxnDMA operates at the same speed as the CPU, that is 3.5MHz, 7MHz, 14MHz or 28Mhz. This is a contended clock that is modified by the ULA and the auto-slowdown by [[Layer 2|Layer2]] (which only occurred in Next core&#039;s 1 and 2, the limitation was lifted in core 3.0).&lt;br /&gt;
&lt;br /&gt;
The (pre-core 3.0) auto-slowdown occurs without user intervention if speed exceeds 7Mhz and the active Layer2 display is being generated (higher speed operation resumes when the active Layer2 display is not generated). Programmers do NOT need to account for speed differences regarding DMA transfers as this happens automatically.&lt;br /&gt;
&lt;br /&gt;
Because of this, the cycle lengths for Ports A and B can be set to their minimum values without ill effects. The cycle lengths specified for Ports A and B are intended to selectively slow down read or write cycles for hardware that cannot operate at the DMA&#039;s full speed.&lt;br /&gt;
&lt;br /&gt;
== The DMA and Interrupts ==&lt;br /&gt;
The zxnDMA cannot currently generate [[Interrupts|interrupts]].&lt;br /&gt;
&lt;br /&gt;
The other side of this is that while the DMA controls the bus, the Z80 cannot respond to interrupts. On the Z80, the NMI interrupt is edge triggered so if an NMI occurs the fact that it occurred is stored internally in the Z80 so that it will respond when it is woken up. On the other hand, maskable interrupts are level triggered. That is, the Z80 must be active to regularly sample the /INT line to determine if a maskable interrupt is occurring. On the Spectrum and the ZX Next, the ULA (and line interrupt) are only asserted for a fixed amount of time ~30 cycles at 3.5MHz. If the DMA is executing a transfer while the interrupt is asserted, the CPU will not be able to see this and it will most likely miss the interrupt. In burst mode, with large-enough prescalar value, the CPU will never miss these interrupts, although this may change if multiple channels are implemented.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Since core 3.1.8:&#039;&#039;&#039; the ability to interrupt DMA transfers was added, this is opt-in mechanism and must be configured through {{NextRegNo|$CC}}, {{NextRegNo|$CD}} and {{NextRegNo|$CE}} and requires &amp;quot;hw im2 mode&amp;quot; interrupts being set. Because interrupts are only sampled at the end of an instruction by the Z80, each time the dma is interrupted one instruction of progress is made in the main program (before the interrupt handler code is entered).&lt;br /&gt;
&lt;br /&gt;
This means after starting the DMA transfer with last `out` instruction you must follow it by N instructions which don&#039;t affect the transfer (don&#039;t remap source data memory, select different sprite/copper/... index if that&#039;s target of transfer, don&#039;t write anything to zxnDMA port), either doing different kind of work with CPU or adding block of `nop` instructions, to have non-interfering block of code available to fire N interrupts during transfer. Chose N to accommodate for worst case scenario of how many times you will interrupt the running DMA transfer. Or you can read state of zxnDMA to see if transfer did finish, but (IMHO by ped7g) in most cases it will be performance-cheaper to just add block of nop instructions or do other work on CPU not interfering with transfer.&lt;br /&gt;
&lt;br /&gt;
== Programming examples ==&lt;br /&gt;
A simple way to program the DMA is to walk down the list of registers WR0-WR5, sending desired settings to each. Then start the DMA by sending a LOAD command followed by an ENABLE_DMA command to WR6. Once more familiar with the DMA, you will discover that the amount of information sent can be reduced to what changes between transfers.&lt;br /&gt;
&lt;br /&gt;
=== Assembly ===&lt;br /&gt;
Short example program to DMA memory to the screen, then DMA a sprite image from memory to sprite RAM, and then showing said sprite scrolling across the screen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;;------------------------------------------------------------------------------&lt;br /&gt;
    ; sjasmplus extra options to enable Z80N, stricter syntax and Next device&lt;br /&gt;
    opt --zxnext --syntax=abf : device zxspectrumnext&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
;     DEFINE testing        ; uncomment to produce NEX file (instead of DOT)&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; DMA (Register 6)&lt;br /&gt;
;&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
;zxnDMA programming example&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
;(c) Jim Bagley&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
DMA_RESET                      equ $c3&lt;br /&gt;
DMA_RESET_PORT_A_TIMING        equ $c7&lt;br /&gt;
DMA_RESET_PORT_B_TIMING        equ $cb&lt;br /&gt;
DMA_LOAD                       equ $cf ; %11001111&lt;br /&gt;
DMA_CONTINUE                   equ $d3&lt;br /&gt;
DMA_DISABLE_INTERUPTS          equ $af&lt;br /&gt;
DMA_ENABLE_INTERUPTS           equ $ab&lt;br /&gt;
DMA_RESET_DISABLE_INTERUPTS    equ $a3&lt;br /&gt;
DMA_ENABLE_AFTER_RETI          equ $b7&lt;br /&gt;
DMA_READ_STATUS_BYTE           equ $bf&lt;br /&gt;
DMA_REINIT_STATUS_BYTE         equ $8b&lt;br /&gt;
DMA_START_READ_SEQUENCE        equ $a7&lt;br /&gt;
DMA_FORCE_READY                equ $b3&lt;br /&gt;
DMA_DISABLE                    equ $83&lt;br /&gt;
DMA_ENABLE                     equ $87&lt;br /&gt;
DMA_WRITE_REGISTER_COMMAND     equ $bb&lt;br /&gt;
DMA_BURST                      equ %11001101&lt;br /&gt;
DMA_CONTINUOUS                 equ %10101101&lt;br /&gt;
ZXN_DMA_PORT                   equ $6b&lt;br /&gt;
SPRITE_STATUS_SLOT_SELECT      equ $303B&lt;br /&gt;
SPRITE_IMAGE_PORT              equ $5b&lt;br /&gt;
SPRITE_INFO_PORT               equ $57&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
    IFDEF testing&lt;br /&gt;
        org $5800&lt;br /&gt;
        block 32*24, $38              ; default ULA attributes&lt;br /&gt;
        org $6000&lt;br /&gt;
    ELSE&lt;br /&gt;
        org $2000&lt;br /&gt;
    ENDIF&lt;br /&gt;
&lt;br /&gt;
start&lt;br /&gt;
    ld   hl,$0000&lt;br /&gt;
    ld   de,$4000&lt;br /&gt;
    ld   bc,$800&lt;br /&gt;
    call TransferDMA                  ; copy some random data to the screen pointing&lt;br /&gt;
                                      ; to ROM for now, for the purpose of showing &lt;br /&gt;
                                      ; how to do a DMA copy.&lt;br /&gt;
    ld   a,0                          ; sprite image number we want to update&lt;br /&gt;
    ld   bc,SPRITE_STATUS_SLOT_SELECT&lt;br /&gt;
    out  (c),a                        ; set the sprite image number&lt;br /&gt;
    ld   bc,1*256                     ; number to transfer (1)&lt;br /&gt;
    ld   hl,testsprite                ; from &lt;br /&gt;
    call TransferDMASprite            ; transfer to sprite ram&lt;br /&gt;
&lt;br /&gt;
    nextreg 21,1                      ; turn sprite on. for more info on this check &lt;br /&gt;
                                      ; out https://www.specnext.com/tbblue-io-port-system/&lt;br /&gt;
    ld   de,0&lt;br /&gt;
    ld   (xpos),de                    ; set initial X position ( doesn&#039;t need it for&lt;br /&gt;
                                      ; this demo, but if you run the .loop again it&lt;br /&gt;
                                      ; will continue from where it was&lt;br /&gt;
    ld   a,$20&lt;br /&gt;
    ld   (ypos),a                     ; set initial Y position&lt;br /&gt;
&lt;br /&gt;
.loop&lt;br /&gt;
    ld   a,0                          ; sprite number we want to position&lt;br /&gt;
    ld   bc,SPRITE_STATUS_SLOT_SELECT&lt;br /&gt;
    out  (c),a&lt;br /&gt;
    ld   de,(xpos)&lt;br /&gt;
    ld   hl,(ypos)                    ; ignores H so doing this rather than &lt;br /&gt;
                                      ; ld a,(ypos):ld l,a&lt;br /&gt;
    ld   bc,(image)                   ; not flipped or palette shifted&lt;br /&gt;
    call SetSprite&lt;br /&gt;
&lt;br /&gt;
    halt&lt;br /&gt;
&lt;br /&gt;
    ld   de,(xpos)&lt;br /&gt;
    inc  de&lt;br /&gt;
    ld   (xpos),de&lt;br /&gt;
    ld   a,d&lt;br /&gt;
    cp   $01&lt;br /&gt;
    jr   nz,.loop                     ; if high byte of xpos is not 1 (right of &lt;br /&gt;
                                      ; screen )&lt;br /&gt;
    ld   a,e&lt;br /&gt;
    cp   $20+1&lt;br /&gt;
    jr   nz,.loop                     ; if low byte is not $21 just off the right of&lt;br /&gt;
                                      ; the screen, $20 is off screen but as the &lt;br /&gt;
                                      ; INC DE is just above and not updated sprite&lt;br /&gt;
                                      ; after it, it needs to be $21&lt;br /&gt;
    xor  a&lt;br /&gt;
    ret                               ; return back to basic with OK&lt;br /&gt;
&lt;br /&gt;
xpos dw 0                             ; x position&lt;br /&gt;
ypos db 0                             ; y position&lt;br /&gt;
                                      ; these next two BITS and IMAGE are swapped &lt;br /&gt;
                                      ; as bits needs to go into B register&lt;br /&gt;
image db 0+$80                        ; use image 0 (for the image we transfered)&lt;br /&gt;
                                      ; +$80 to set the sprite to active&lt;br /&gt;
bits db 0                             ; not flipped or palette shifted&lt;br /&gt;
&lt;br /&gt;
c1 = %11100000&lt;br /&gt;
c2 = %11000000&lt;br /&gt;
c3 = %10100000&lt;br /&gt;
c4 = %10000000&lt;br /&gt;
c5 = %01100000&lt;br /&gt;
c6 = %01000000&lt;br /&gt;
c7 = %00100000&lt;br /&gt;
c8 = %00000000&lt;br /&gt;
&lt;br /&gt;
testsprite&lt;br /&gt;
    db c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1&lt;br /&gt;
    db c1,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c1&lt;br /&gt;
    db c1,c2,c3,c3,c3,c3,c3,c3,c3,c3,c3,c3,c3,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c4,c4,c4,c4,c4,c4,c4,c4,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c5,c5,c5,c5,c5,c5,c5,c5,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c5,c6,c6,c6,c6,c6,c6,c5,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c5,c6,c7,c7,c7,c7,c6,c5,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c5,c6,c7,c8,c8,c7,c6,c5,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c5,c6,c7,c8,c8,c7,c6,c5,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c5,c6,c7,c7,c7,c7,c6,c5,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c5,c6,c6,c6,c6,c6,c6,c5,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c5,c5,c5,c5,c5,c5,c5,c5,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c4,c4,c4,c4,c4,c4,c4,c4,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c3,c3,c3,c3,c3,c3,c3,c3,c3,c3,c3,c2,c1&lt;br /&gt;
    db c1,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c1&lt;br /&gt;
    db c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1&lt;br /&gt;
&lt;br /&gt;
;-------------------------------------------------&lt;br /&gt;
; de = X&lt;br /&gt;
; l = Y&lt;br /&gt;
; b = bits&lt;br /&gt;
; c = sprite image&lt;br /&gt;
SetSprite&lt;br /&gt;
    push bc&lt;br /&gt;
    ld bc,SPRITE_INFO_PORT&lt;br /&gt;
    out (c),e ; Xpos&lt;br /&gt;
    out (c),l ; Ypos&lt;br /&gt;
    pop hl&lt;br /&gt;
    ld a,d&lt;br /&gt;
    and 1&lt;br /&gt;
    or h&lt;br /&gt;
    out (c),a&lt;br /&gt;
    ld a,l:or $80&lt;br /&gt;
    out (c),a ; image&lt;br /&gt;
    ret&lt;br /&gt;
&lt;br /&gt;
;--------------------------------&lt;br /&gt;
; hl = source&lt;br /&gt;
; de = destination&lt;br /&gt;
; bc = length&lt;br /&gt;
;--------------------------------&lt;br /&gt;
TransferDMA&lt;br /&gt;
    di&lt;br /&gt;
    ld (DMASource),hl&lt;br /&gt;
    ld (DMADest),de&lt;br /&gt;
    ld (DMALength),bc&lt;br /&gt;
    ld hl,DMACode&lt;br /&gt;
    ld b,DMACode_Len&lt;br /&gt;
    ld c,ZXN_DMA_PORT&lt;br /&gt;
    otir&lt;br /&gt;
    ei&lt;br /&gt;
    ret&lt;br /&gt;
&lt;br /&gt;
DMACode db DMA_DISABLE&lt;br /&gt;
        db %01111101                  ; R0-Transfer mode, A -&amp;gt; B, write adress &lt;br /&gt;
                                      ; + block length&lt;br /&gt;
DMASource dw 0                        ; R0-Port A, Start address &lt;br /&gt;
                                      ; (source address)&lt;br /&gt;
DMALength dw 0                        ; R0-Block length (length in bytes)&lt;br /&gt;
        db %01010100                  ; R1-write A time byte, increment, to &lt;br /&gt;
                                      ; memory, bitmask&lt;br /&gt;
        db %00000010                  ; 2t&lt;br /&gt;
        db %01010000                  ; R2-write B time byte, increment, to &lt;br /&gt;
                                      ; memory, bitmask&lt;br /&gt;
        db %00000010                  ; R2-Cycle length port B&lt;br /&gt;
        db DMA_CONTINUOUS             ; R4-Continuous mode (use this for block &lt;br /&gt;
                                      ; transfer), write dest adress&lt;br /&gt;
DMADest dw 0                          ; R4-Dest address (destination address)&lt;br /&gt;
        db %10000010                  ; R5-Restart on end of block, RDY active &lt;br /&gt;
                                      ; LOW&lt;br /&gt;
        db DMA_LOAD                   ; R6-Load&lt;br /&gt;
        db DMA_ENABLE                 ; R6-Enable DMA&lt;br /&gt;
        &lt;br /&gt;
DMACode_Len                    equ $-DMACode&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; hl = source&lt;br /&gt;
; bc = length&lt;br /&gt;
; set port to write to with TBBLUE_REGISTER_SELECT&lt;br /&gt;
; prior to call&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
TransferDMAPort&lt;br /&gt;
    di&lt;br /&gt;
    ld (DMASourceP),hl&lt;br /&gt;
    ld (DMALengthP),bc&lt;br /&gt;
    ld hl,DMACodeP&lt;br /&gt;
    ld b,DMACode_LenP&lt;br /&gt;
    ld c,ZXN_DMA_PORT&lt;br /&gt;
    otir&lt;br /&gt;
    ei&lt;br /&gt;
    ret&lt;br /&gt;
&lt;br /&gt;
DMACodeP db DMA_DISABLE&lt;br /&gt;
        db %01111101                  ; R0-Transfer mode, A -&amp;gt; B, write adress &lt;br /&gt;
                                      ; + block length&lt;br /&gt;
DMASourceP dw 0                       ; R0-Port A, Start address (source address)&lt;br /&gt;
DMALengthP dw 0                       ; R0-Block length (length in bytes)&lt;br /&gt;
        db %01010100                  ; R1-read A time byte, increment, to &lt;br /&gt;
                                      ; memory, bitmask&lt;br /&gt;
        db %00000010                  ; R1-Cycle length port A&lt;br /&gt;
        db %01101000                  ; R2-write B time byte, increment, to &lt;br /&gt;
                                      ; memory, bitmask&lt;br /&gt;
        db %00000010                  ; R2-Cycle length port B&lt;br /&gt;
        db %10101101                  ; R4-Continuous mode (use this for block &lt;br /&gt;
                                      ; transfer), write dest adress&lt;br /&gt;
        dw $253b                      ; R4-Dest address (destination address)&lt;br /&gt;
        db %10000010                  ; R5-Restart on end of block, RDY active&lt;br /&gt;
                                      ; LOW&lt;br /&gt;
        db DMA_LOAD                   ; R6-Load&lt;br /&gt;
        db DMA_ENABLE                 ; R6-Enable DMA&lt;br /&gt;
        &lt;br /&gt;
DMACode_LenP                   equ $-DMACodeP&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; hl = source&lt;br /&gt;
; bc = length&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
TransferDMASprite&lt;br /&gt;
    di&lt;br /&gt;
    ld (DMASourceS),hl&lt;br /&gt;
    ld (DMALengthS),bc&lt;br /&gt;
    ld hl,DMACodeS&lt;br /&gt;
    ld b,DMACode_LenS&lt;br /&gt;
    ld c,ZXN_DMA_PORT&lt;br /&gt;
    otir&lt;br /&gt;
    ei&lt;br /&gt;
    ret&lt;br /&gt;
&lt;br /&gt;
DMACodeS db DMA_DISABLE&lt;br /&gt;
        db %01111101                   ; R0-Transfer mode, A -&amp;gt; B, write adress &lt;br /&gt;
                                       ; + block length&lt;br /&gt;
DMASourceS dw 0                        ; R0-Port A, Start address (source address)&lt;br /&gt;
DMALengthS dw 0                        ; R0-Block length (length in bytes)&lt;br /&gt;
        db %01010100                   ; R1-read A time byte, increment, to &lt;br /&gt;
                                       ; memory, bitmask&lt;br /&gt;
        db %00000010                   ; R1-Cycle length port A&lt;br /&gt;
        db %01101000                   ; R2-write B time byte, increment, to &lt;br /&gt;
                                       ; memory, bitmask&lt;br /&gt;
        db %00000010                   ; R2-Cycle length port B&lt;br /&gt;
        db %10101101                   ; R4-Continuous mode (use this for block&lt;br /&gt;
                                       ; transfer), write dest adress&lt;br /&gt;
        dw SPRITE_IMAGE_PORT           ; R4-Dest address (destination address)&lt;br /&gt;
        db %10000010                   ; R5-Restart on end of block, RDY active&lt;br /&gt;
                                       ; LOW&lt;br /&gt;
        db DMA_LOAD                    ; R6-Load&lt;br /&gt;
        db DMA_ENABLE                  ; R6-Enable DMA&lt;br /&gt;
DMACode_LenS                   equ $-DMACodeS&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; de = dest, a = fill value, bc = lenth&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
DMAFill&lt;br /&gt;
    di&lt;br /&gt;
    ld (FillValue),a&lt;br /&gt;
    ld (DMACDest),de&lt;br /&gt;
    ld (DMACLength),bc&lt;br /&gt;
    ld hl,DMACCode&lt;br /&gt;
    ld b,DMACCode_Len&lt;br /&gt;
    ld c,ZXN_DMA_PORT&lt;br /&gt;
    otir&lt;br /&gt;
    ei&lt;br /&gt;
    ret&lt;br /&gt;
&lt;br /&gt;
FillValue db 22&lt;br /&gt;
DMACCode db DMA_DISABLE&lt;br /&gt;
        db %01111101&lt;br /&gt;
DMACSource dw FillValue&lt;br /&gt;
DMACLength dw 0&lt;br /&gt;
        db %00100100,%00010000,%10101101&lt;br /&gt;
DMACDest dw 0&lt;br /&gt;
        db DMA_LOAD,DMA_ENABLE&lt;br /&gt;
DMACCode_Len equ $-DMACCode&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; End of file&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
    IFDEF testing&lt;br /&gt;
        savenex open &amp;quot;DMAtest.nex&amp;quot;, start, $FF00&lt;br /&gt;
        savenex bank 5&lt;br /&gt;
    ELSE&lt;br /&gt;
fin&lt;br /&gt;
        savebin &amp;quot;DMATEST&amp;quot;,start,fin-start&lt;br /&gt;
    ENDIF&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Based on original text by: Allen Albright &amp;amp; Mike Dailly with input by Jim Bagley, Lyndon J Sharp and Phoebus R. Dokos&lt;br /&gt;
&lt;br /&gt;
== Technical details (core 3.1.3+)  ==&lt;br /&gt;
&lt;br /&gt;
The Zilog/zxnDMA mode is now selected by using the particular I/O port number ({{PortNo|$xx6B}} for zxnDMA mode, {{PortNo|$xx0B}} for Zilog mode). The bit 6 in {{NextRegNo|$06}} is not DMA related any more and will be reused for something different.&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;counter&amp;quot; RR1-RR2 read back after transfer has correct byte order since core 3.1.4.&lt;br /&gt;
&lt;br /&gt;
Other differences described below in &amp;quot;3.0.5&amp;quot; remains (but from practical point of view the Zilog DMA emulation in 3.1.4 is near-perfect, all the remaining differences are very minor).&lt;br /&gt;
&lt;br /&gt;
== Technical details (core 3.0.5)  ==&lt;br /&gt;
&lt;br /&gt;
=== Zilog DMA compatibility mode ===&lt;br /&gt;
In Zilog DMA compatibility mode (bit 6 of {{NextRegNo|$06}}) the zxnDMA will mostly work as expected, but there are few differences in behaviour which may eventually throw off some rare SW, here is the list of the known differences (most of them describe also how the zxnDMA mode works):&lt;br /&gt;
&lt;br /&gt;
The LOAD command must be issued with correct transfer direction, loading addresses in opposite direction and flipping direction afterward will mismatch the source/destination address data (Zilog/UA858D DMA chips are also sensitive to direction flip after LOAD, but the resulting transfer quirks in different way, reading source data byte after write, offsetting whole transfer by one and damaging start/end of sequence).&lt;br /&gt;
(does apply also to zxnDMA mode)&lt;br /&gt;
&lt;br /&gt;
The LOAD command will NOT destroy the already issued &amp;quot;Initialize Read Sequence&amp;quot; - this is how even the original Zilog documentation describes the DMA chip operation, but the real Zilog DMA and UA858D (clone chip) both destroy read sequence upon LOAD command (zxnDMA is better).&lt;br /&gt;
(does apply also to zxnDMA mode)&lt;br /&gt;
&lt;br /&gt;
The content of registers read back after finished transfer differs: the counter has swapped LSB with MSB byte, and both addresses will be adjusted length+1 times (Zilog/UA858D will return destination address adjusted only length-many times).&lt;br /&gt;
(does apply also to zxnDMA mode, except addresses are adjusted only &amp;quot;length&amp;quot; times of course, counter has still swapped bytes)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;del&amp;gt;Any read of zxnDMA port without pending read request (commands &amp;quot;Read Status Byte&amp;quot; or &amp;quot;Initialize Read Sequence&amp;quot;) will return status byte (Zilog will return random value vaguely similar to status byte, but incorrect, UA858D will return zero).&lt;br /&gt;
(does apply also to zxnDMA mode)&amp;lt;/del&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
2026-03-30: any read of zxnDMA port without pending read request will return next byte in read sequence, the default read mask is 0x7F after power on (based on reading the VHDL, needs to verify with HW).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;del&amp;gt;Status byte doesn&#039;t have bit 0 set (the &amp;quot;T&amp;quot; bit in description above).&lt;br /&gt;
(does apply also to zxnDMA mode)&amp;lt;/del&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
2026-03-30: going by [https://gitlab.com/SpectrumNext/ZX%20Spectrum%20Next%20FPGA/-/blob/master/cores/zxnext/src/device/dma.vhd?ref%20type=heads VHDL source] this seems to be now fixed, needs to verify with HW and guess in which version of core this was fixed&lt;br /&gt;
&lt;br /&gt;
The command 0xBB setting read mask will cause implicit 0xA7 Initialize Read Sequence.&lt;br /&gt;
(does apply also to zxnDMA mode)&lt;br /&gt;
&lt;br /&gt;
The command 0xA7 does initialize read sequence even when the previous sequence was only partially read (ZX Next FPGA implementation for both zxnDMA and Zilog-DMA) and there were more bytes pending. According to Zilog documentation the original Zilog DMA is claimed to ignore 0xA7 command in such case. Needs verification on HW to be fully confirmed, especially the original Zilog chip, this looks a bit unlikely, it would make lot more sense to abort current sequence and reset it.&lt;br /&gt;
&lt;br /&gt;
Be aware that both custom timing cycles count, and prescalar values are preserved in zxnDMA even when future write to WR1/WR2 does skip these particular bytes. To reset prescalar or cycles timing, write explicitly zero into prescalar register or use commands reset/reset-port-timing.&lt;br /&gt;
(does apply also to zxnDMA mode, the prescalar works only in zxnDMA mode)&lt;br /&gt;
&lt;br /&gt;
The destination port address is LOAD-ed even when it is &amp;quot;fixed&amp;quot; type (Contrary to Zilog DMA, which requires you to load such port as &amp;quot;source&amp;quot;, flip the direction after and re-LOAD again with correct direction. UA858D chip does also load destination port address in any case, just like zxnDMA).&lt;br /&gt;
(does apply also to zxnDMA mode)&lt;br /&gt;
&lt;br /&gt;
=== zxnDMA mode vs Zilog mode ===&lt;br /&gt;
&lt;br /&gt;
In zxnDMA mode length of transfer is equal to the length written to WR0 register, port addresses are adjusted also only length-times.&lt;br /&gt;
&lt;br /&gt;
Prescalar value will affect speed of transfer (use zero to switch prescalar off) (in burst mode during the extra idle time the CPU receives control back and can execute further instructions, in continuous mode the transfer will keep blocking CPU even when &amp;quot;slow&amp;quot; transfer is being done).&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=DMA&amp;diff=41878</id>
		<title>DMA</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=DMA&amp;diff=41878"/>
		<updated>2026-03-30T12:16:56Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: formatting + note&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
The ZX Spectrum Next DMA (zxnDMA) is a single channel DMA device that implements a subset of the Z80 DMA functionality. The subset is large enough to be compatible with common uses of the similar Datagear interface available for standard ZX Spectrum computers and compatibles. It also adds a burst mode capability that can deliver audio at programmable sample rates to the DAC device.&lt;br /&gt;
&lt;br /&gt;
== Accessing the zxnDMA ==&lt;br /&gt;
&amp;lt;del&amp;gt;The zxnDMA is mapped to a single Read/Write IO Port 0x6B which is the same one used by the Datagear but unlike the Datagear it doesn&#039;t also map itself to a second port 0x0B similar to the MB-02 interface.&amp;lt;/del&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since core 3.1.2 the zxnDMA is mapped to {{PortNo|$xx6B}}, and Zilog-DMA mode is mapped to {{PortNo|$xx0B}}.&lt;br /&gt;
&lt;br /&gt;
== Description  ==&lt;br /&gt;
The normal Z80 DMA (Z8410) chip is a pipelined device and because of that it has numerous off-by-one idiosyncrasies and requirements on the order that certain commands should be carried out. These issues are not duplicated in the zxnDMA. You can continue to program the zxnDMA as if it is were a Z8410 DMA device but it can also be programmed in a simpler manner.&lt;br /&gt;
&lt;br /&gt;
The single channel of the zxnDMA chip consists of two ports named A and B. Transfers can occur in either direction between ports A and B, each port can describe a target in memory or IO, and each can be configured to autoincrement, autodecrement or stay fixed after a byte is transferred.&lt;br /&gt;
&lt;br /&gt;
A special feature of the zxnDMA can force each byte transfer to take a fixed amount of time so that the zxnDMA can be used to deliver sampled audio.&lt;br /&gt;
&lt;br /&gt;
== Modes of Operation ==&lt;br /&gt;
The zxnDMA can operate in a z80-DMA compatibility mode.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;REMOVED in core 3.1.2:&#039;&#039;&#039; &amp;lt;del&amp;gt;The z80-DMA compatibility mode is selected by setting bit 6 of nextreg 0x06. In this mode, all transfers involve length+1 bytes which is the same behaviour as the z80-DMA chip. In zxn-DMA mode, the transfer length is exactly the number of bytes programmed. This mode is mainly present to accommodate existing spectrum software that uses the z80-DMA and for cp/m programs that may have a z80-DMA option.&amp;lt;/del&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Since core 3.1.2:&#039;&#039;&#039; the DMA mode is selected by port number, the {{PortNo|$xx6B}} works in zxnDMA mode, {{PortNo|$xx0B}} works in Zilog mode. The bit 6 in {{NextRegNo|$06}} is not DMA related any more and will be reused for something different.&lt;br /&gt;
&lt;br /&gt;
The zxnDMA can also operate in either burst or continuous modes.&lt;br /&gt;
&lt;br /&gt;
Continuous mode means the DMA chip runs to completion without allowing the CPU to run. When the CPU starts the DMA, the DMA operation will complete before the CPU executes its next instruction.&lt;br /&gt;
&lt;br /&gt;
Burst mode nominally means the DMA lets the CPU run if either port is not ready. This condition can&#039;t happen in the zxnDMA chip except when operated in the special fixed time transfer mode. In this mode, the zxnDMA will let the CPU run while it waits for the fixed time to expire between bytes transferred.&lt;br /&gt;
&lt;br /&gt;
Note that there is no byte transfer mode as in the Z80 DMA.&lt;br /&gt;
&lt;br /&gt;
== Programming the zxnDMA ==&lt;br /&gt;
Like the Z80 DMA chip, the zxnDMA has seven write registers named WR0-WR6 that control the device. Each register WR0-WR6 can have zero or more parameters associated with it.&lt;br /&gt;
&lt;br /&gt;
In a first write to the zxnDMA port, the write value is compared against a bitmask to determine which of the WR0-WR6 is the target. Remaining bits in the written value can contain data as well as a list of associated parameter bits. The parameter bits determine if further writes are expected to deliver parameter values. If there are multiple parameter bits set, the expected order of parameter values written is determined by parameter bit position from right to left (bit 0 through bit 7). Once all parameters are written, the zxnDMA again expects a regular register write selecting WR0-WR6.&lt;br /&gt;
&lt;br /&gt;
The table below describes the registers and the bitmask required to select them on the zxnDMA.&lt;br /&gt;
&lt;br /&gt;
{| &lt;br /&gt;
! Register Group&lt;br /&gt;
! Register Function Description&lt;br /&gt;
! Bitmask&lt;br /&gt;
! Notes&lt;br /&gt;
|- &lt;br /&gt;
| WR0&lt;br /&gt;
| Direction, Operation and Port A configuration&lt;br /&gt;
| &amp;lt;pre&amp;gt;0XXXXXAA&amp;lt;/pre&amp;gt;&lt;br /&gt;
| AA must NOT be 00&lt;br /&gt;
|- &lt;br /&gt;
| WR1&lt;br /&gt;
| Port A configuration&lt;br /&gt;
| &amp;lt;pre&amp;gt;0XXXX100&amp;lt;/pre&amp;gt;&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| WR2&lt;br /&gt;
| Port B configuration&lt;br /&gt;
| &amp;lt;pre&amp;gt;0XXXX000&amp;lt;/pre&amp;gt;&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| WR3&lt;br /&gt;
| Activation&lt;br /&gt;
| &amp;lt;pre&amp;gt;1XXXXX00&amp;lt;/pre&amp;gt;&lt;br /&gt;
| It’s best to use WR6&lt;br /&gt;
|- &lt;br /&gt;
| WR4&lt;br /&gt;
| Port B, Timing and Interrupt configuration&lt;br /&gt;
| &amp;lt;pre&amp;gt;1XXXXX01&amp;lt;/pre&amp;gt;&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| WR5&lt;br /&gt;
| Ready and Stop configuration&lt;br /&gt;
| &amp;lt;pre&amp;gt;10XXX010&amp;lt;/pre&amp;gt;&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| WR6&lt;br /&gt;
| Command Register&lt;br /&gt;
| &amp;lt;pre&amp;gt;1XXXXX11&amp;lt;/pre&amp;gt;&lt;br /&gt;
| &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== zxnDMA Registers ==&lt;br /&gt;
These are described below following the same convention used by Zilog for its DMA chip:&lt;br /&gt;
&lt;br /&gt;
=== WR0 – Write Register Group 0 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;D7  D6  D5  D4  D3  D2  D1  D0  BASE REGISTER BYTE&lt;br /&gt;
 0   |   |   |   |   |   |   |&lt;br /&gt;
     |   |   |   |   |   0   0  Do not use&lt;br /&gt;
     |   |   |   |   |   0   1  Transfer (Prefer this for Z80 DMA compatibility)&lt;br /&gt;
     |   |   |   |   |   1   0  Do not use (Behaves like Transfer, Search on Z80 DMA)&lt;br /&gt;
     |   |   |   |   |                       &lt;br /&gt;
     |   |   |   |   |   1   1  Do not use (Behaves like Transfer, Search/Transfer on Z80 DMA)&lt;br /&gt;
     |   |   |   |   |                      &lt;br /&gt;
     |   |   |   |   0 = Port B -&amp;amp;gt; Port A (Byte transfer direction)&lt;br /&gt;
     |   |   |   |   1 = Port A -&amp;amp;gt; Port B&lt;br /&gt;
     |   |   |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  PORT A STARTING ADDRESS (LOW BYTE)&lt;br /&gt;
     |   |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  PORT A STARTING ADDRESS (HIGH BYTE)&lt;br /&gt;
     |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  BLOCK LENGTH (LOW BYTE)&lt;br /&gt;
     V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  BLOCK LENGTH (HIGH BYTE)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Several registers are accessible from WR0. The first write to WR0 is to the base register byte. Bits D6:D3 are optionally set to indicate that associated registers in this group will be written next. The order the writes come in are from D3 to D6 (right to left). For example, if bits D6 and D3 are set, the next two writes will be directed to PORT A STARTING ADDRESS LOW followed by BLOCK LENGTH HIGH.&lt;br /&gt;
&lt;br /&gt;
=== WR1 – Write Register Group 1 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;D7  D6  D5  D4  D3  D2  D1  D0  BASE REGISTER BYTE&lt;br /&gt;
 0   |   |   |   |   1   0   0&lt;br /&gt;
     |   |   |   |&lt;br /&gt;
     |   |   |   0 = Port A is memory&lt;br /&gt;
     |   |   |   1 = Port A is IO&lt;br /&gt;
     |   |   |&lt;br /&gt;
     |   0   0 = Port A address decrements&lt;br /&gt;
     |   0   1 = Port A address increments&lt;br /&gt;
     |   1   0 = Port A address is fixed&lt;br /&gt;
     |   1   1 = Port A address is fixed&lt;br /&gt;
     |&lt;br /&gt;
     V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  PORT A VARIABLE TIMING BYTE&lt;br /&gt;
 0   0   0   0   0   0   |   |&lt;br /&gt;
                         0   0 = Cycle Length = 4&lt;br /&gt;
                         0   1 = Cycle Length = 3&lt;br /&gt;
                         1   0 = Cycle Length = 2&lt;br /&gt;
                         1   1 = Do not use&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The cycle length is the number of cycles used in a read or write operation. The first cycle asserts signals and the last cycle releases them. There is no half cycle timing for the control signals.&lt;br /&gt;
&lt;br /&gt;
=== WR2 – Write Register Group 2 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;D7  D6  D5  D4  D3  D2  D1  D0  BASE REGISTER BYTE&lt;br /&gt;
 0   |   |   |   |   0   0   0&lt;br /&gt;
     |   |   |   |&lt;br /&gt;
     |   |   |   0 = Port B is memory&lt;br /&gt;
     |   |   |   1 = Port B is IO&lt;br /&gt;
     |   |   |&lt;br /&gt;
     |   0   0 = Port B address decrements&lt;br /&gt;
     |   0   1 = Port B address increments&lt;br /&gt;
     |   1   0 = Port B address is fixed&lt;br /&gt;
     |   1   1 = Port B address is fixed&lt;br /&gt;
     |&lt;br /&gt;
     V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  PORT B VARIABLE TIMING BYTE&lt;br /&gt;
 0   0   |   0   0   0   |   |&lt;br /&gt;
         |               0   0 = Cycle Length = 4&lt;br /&gt;
         |               0   1 = Cycle Length = 3&lt;br /&gt;
         |               1   0 = Cycle Length = 2&lt;br /&gt;
         |               1   1 = Do not use&lt;br /&gt;
         |&lt;br /&gt;
         V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  ZXN PRESCALAR (FIXED TIME TRANSFER)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The ZXN PRESCALAR is a feature of the zxnDMA implementation. If non-zero, a delay will be inserted after each byte is transferred such that the total time needed for each transfer is determined by the prescalar. This works in both the continuous mode and the burst mode. If the DMA is operated in burst mode, the DMA will give up any waiting time to the CPU so that the CPU can run while the DMA is idle.&lt;br /&gt;
&lt;br /&gt;
The rate of transfer is given by the formula “Frate = 875kHz / prescalar” or, rearranged, “prescalar = 875kHz / Frate”. The formula is framed in terms of a sample rate (Frate) but Frate can be inverted to set a transfer time for each byte instead. The 875kHz constant is a nominal value assuming a 28MHz system clock; the system clock actually varies from this depending on the video timing selected by the user (HDMI, VGA0-6) so for complete accuracy the constant should be prorated according to documentation for nextreg 0x11.&lt;br /&gt;
&lt;br /&gt;
In a DMA audio setting, selecting a sample rate of 16kHz would mean setting the prescalar value to 55. This sample period is constant across changes in CPU speed.&lt;br /&gt;
&lt;br /&gt;
=== WR3 – Write Register Group 3 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;D7  D6  D5  D4  D3  D2  D1  D0  BASE REGISTER BYTE&lt;br /&gt;
 1   |   0   0   0   0   0   0&lt;br /&gt;
     |&lt;br /&gt;
     1 = DMA Enable&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The Z80 DMA defines more fields but they are ignored by the zxnDMA. The two other registers defined by the Z80 DMA in this group on D4 and D3 are implemented by the zxnDMA but they do nothing.&lt;br /&gt;
&lt;br /&gt;
It is preferred to start the DMA by writing an &#039;Enable DMA&#039; command to WR6.&lt;br /&gt;
&lt;br /&gt;
=== WR4 – Write Register Group 4 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;D7  D6  D5  D4  D3  D2  D1  D0  BASE REGISTER BYTE&lt;br /&gt;
 1   |   |   0   |   |   0   1&lt;br /&gt;
     |   |       |   |&lt;br /&gt;
     0   0 = Do not use (Behaves like Continuous mode, Byte mode on Z80 DMA)&lt;br /&gt;
     0   1 = Continuous mode&lt;br /&gt;
     1   0 = Burst mode&lt;br /&gt;
     1   1 = Do not use&lt;br /&gt;
                 |   |&lt;br /&gt;
                 |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  PORT B STARTING ADDRESS (LOW BYTE)&lt;br /&gt;
                 |&lt;br /&gt;
                 V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  PORT B STARTING ADDRESS (HIGH BYTE)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The Z80 DMA defines three more registers in this group through D4 that define interrupt behaviour. Interrups and pulse generation are not implemented in the zxnDMA nor are these registers available for writing.&lt;br /&gt;
&lt;br /&gt;
=== WR5 – Write Register Group 5 ===&lt;br /&gt;
&amp;lt;pre&amp;gt;D7  D6  D5  D4  D3  D2  D1  D0  BASE REGISTER BYTE&lt;br /&gt;
 1   0   |   |   0   0   1   0&lt;br /&gt;
         |   |&lt;br /&gt;
         |   0 = /ce only&lt;br /&gt;
         |   1 = /ce &amp;amp; /wait multiplexed&lt;br /&gt;
         |&lt;br /&gt;
         0 = Stop on end of block&lt;br /&gt;
         1 = Auto restart on end of block&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The /ce &amp;amp; /wait mode is implemented in the zxnDMA but is not currently used. This mode has an external device using the DMA&#039;s /ce pin to insert wait states during the DMA&#039;s transfer.&lt;br /&gt;
&lt;br /&gt;
The auto restart feature causes the DMA to automatically reload its source and destination addresses and reset its byte counter to zero to repeat the last transfer when a previous one is finished.&lt;br /&gt;
&lt;br /&gt;
=== WR6 – Command Register ===&lt;br /&gt;
&amp;lt;pre&amp;gt;D7  D6  D5  D4  D3  D2  D1  D0  BASE REGISTER BYTE&lt;br /&gt;
 1   ?   ?   ?   ?   ?   1   1&lt;br /&gt;
     |   |   |   |   |&lt;br /&gt;
     1   0   0   0   0 = 0xC3 = Reset&lt;br /&gt;
     1   0   0   0   1 = 0xC7 = Reset Port A Timing&lt;br /&gt;
     1   0   0   1   0 = 0xCB = Reset Port B Timing&lt;br /&gt;
     0   1   1   0   0 = 0xB3 = Force Ready (irrelevant for zxnDMA)&lt;br /&gt;
     0   1   1   1   1 = 0xBF = Read Status Byte&lt;br /&gt;
     0   0   0   1   0 = 0x8B = Reinitialize Status Byte&lt;br /&gt;
     0   1   0   0   1 = 0xA7 = Initialize Read Sequence&lt;br /&gt;
     1   0   0   1   1 = 0xCF = Load&lt;br /&gt;
     1   0   1   0   0 = 0xD3 = Continue&lt;br /&gt;
     0   0   0   0   1 = 0x87 = Enable DMA&lt;br /&gt;
     0   0   0   0   0 = 0x83 = Disable DMA&lt;br /&gt;
 +-- 0   1   1   1   0 = 0xBB = Read Mask Follows&lt;br /&gt;
 |&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  READ MASK&lt;br /&gt;
 0   |   |   |   |   |   |   |&lt;br /&gt;
     |   |   |   |   |   |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  Status Byte&lt;br /&gt;
     |   |   |   |   |   |&lt;br /&gt;
     |   |   |   |   |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  Byte Counter Low (&amp;quot;High&amp;quot; with core 3.0.5 = bug in core)&lt;br /&gt;
     |   |   |   |   |&lt;br /&gt;
     |   |   |   |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  Byte Counter High (&amp;quot;Low&amp;quot; with core 3.0.5 = bug in core)&lt;br /&gt;
     |   |   |   |&lt;br /&gt;
     |   |   |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  Port A Address Low&lt;br /&gt;
     |   |   |&lt;br /&gt;
     |   |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  Port A Address High&lt;br /&gt;
     |   |&lt;br /&gt;
     |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  Port B Address Low&lt;br /&gt;
     |&lt;br /&gt;
     V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  Port B Address High&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Unimplemented Z80 DMA commands are ignored.&lt;br /&gt;
&lt;br /&gt;
Prior to starting the DMA transfer, a LOAD command must be issued to copy the Port A and Port B addresses into the DMA&#039;s internal pointers. Then an &#039;Enable DMA&#039; command is issued to start the DMA. The last LOAD command before ENABLE must be done with correct transfer direction set.&lt;br /&gt;
&lt;br /&gt;
The &#039;Continue&#039; command resets the DMA&#039;s byte counter so that a following &#039;Enable DMA&#039; allows the DMA to repeat the last transfer but using the current internal address pointers. I.e. it continues from where the last copy operation left off.&lt;br /&gt;
&lt;br /&gt;
Reset and Reset Port A/B Timing commands on zxnDMA do reset also prescalar value.&lt;br /&gt;
&lt;br /&gt;
Registers can be read via an IO read from the DMA port after setting the read mask. (At power up the read mask is set to 0x7f). Register values are the current internal DMA counter values. So &#039;Port Address A Low&#039; is the lower 8-bits of Port A’s next transfer address. Once the end of the read mask is reached, further reads loop around to the first one.&lt;br /&gt;
&lt;br /&gt;
The format of the DMA status byte is as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;00E1101T&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
E is set to 0 if the total block length has been transferred at least once.&lt;br /&gt;
&lt;br /&gt;
T is set to 1 if at least one byte has been transferred.&lt;br /&gt;
&lt;br /&gt;
== Operating speed ==&lt;br /&gt;
The zxnDMA operates at the same speed as the CPU, that is 3.5MHz, 7MHz, 14MHz or 28Mhz. This is a contended clock that is modified by the ULA and the auto-slowdown by [[Layer 2|Layer2]] (which only occurred in Next core&#039;s 1 and 2, the limitation was lifted in core 3.0).&lt;br /&gt;
&lt;br /&gt;
The (pre-core 3.0) auto-slowdown occurs without user intervention if speed exceeds 7Mhz and the active Layer2 display is being generated (higher speed operation resumes when the active Layer2 display is not generated). Programmers do NOT need to account for speed differences regarding DMA transfers as this happens automatically.&lt;br /&gt;
&lt;br /&gt;
Because of this, the cycle lengths for Ports A and B can be set to their minimum values without ill effects. The cycle lengths specified for Ports A and B are intended to selectively slow down read or write cycles for hardware that cannot operate at the DMA&#039;s full speed.&lt;br /&gt;
&lt;br /&gt;
== The DMA and Interrupts ==&lt;br /&gt;
The zxnDMA cannot currently generate [[Interrupts|interrupts]].&lt;br /&gt;
&lt;br /&gt;
The other side of this is that while the DMA controls the bus, the Z80 cannot respond to interrupts. On the Z80, the NMI interrupt is edge triggered so if an NMI occurs the fact that it occurred is stored internally in the Z80 so that it will respond when it is woken up. On the other hand, maskable interrupts are level triggered. That is, the Z80 must be active to regularly sample the /INT line to determine if a maskable interrupt is occurring. On the Spectrum and the ZX Next, the ULA (and line interrupt) are only asserted for a fixed amount of time ~30 cycles at 3.5MHz. If the DMA is executing a transfer while the interrupt is asserted, the CPU will not be able to see this and it will most likely miss the interrupt. In burst mode, with large-enough prescalar value, the CPU will never miss these interrupts, although this may change if multiple channels are implemented.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Since core 3.1.8:&#039;&#039;&#039; the ability to interrupt DMA transfers was added, this is opt-in mechanism and must be configured through {{NextRegNo|$CC}}, {{NextRegNo|$CD}} and {{NextRegNo|$CE}} and requires &amp;quot;hw im2 mode&amp;quot; interrupts being set. Because interrupts are only sampled at the end of an instruction by the Z80, each time the dma is interrupted one instruction of progress is made in the main program (before the interrupt handler code is entered).&lt;br /&gt;
&lt;br /&gt;
This means after starting the DMA transfer with last `out` instruction you must follow it by N instructions which don&#039;t affect the transfer (don&#039;t remap source data memory, select different sprite/copper/... index if that&#039;s target of transfer, don&#039;t write anything to zxnDMA port), either doing different kind of work with CPU or adding block of `nop` instructions, to have non-interfering block of code available to fire N interrupts during transfer. Chose N to accommodate for worst case scenario of how many times you will interrupt the running DMA transfer. Or you can read state of zxnDMA to see if transfer did finish, but (IMHO by ped7g) in most cases it will be performance-cheaper to just add block of nop instructions or do other work on CPU not interfering with transfer.&lt;br /&gt;
&lt;br /&gt;
== Programming examples ==&lt;br /&gt;
A simple way to program the DMA is to walk down the list of registers WR0-WR5, sending desired settings to each. Then start the DMA by sending a LOAD command followed by an ENABLE_DMA command to WR6. Once more familiar with the DMA, you will discover that the amount of information sent can be reduced to what changes between transfers.&lt;br /&gt;
&lt;br /&gt;
=== Assembly ===&lt;br /&gt;
Short example program to DMA memory to the screen, then DMA a sprite image from memory to sprite RAM, and then showing said sprite scrolling across the screen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;;------------------------------------------------------------------------------&lt;br /&gt;
    ; sjasmplus extra options to enable Z80N, stricter syntax and Next device&lt;br /&gt;
    opt --zxnext --syntax=abf : device zxspectrumnext&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
;     DEFINE testing        ; uncomment to produce NEX file (instead of DOT)&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; DMA (Register 6)&lt;br /&gt;
;&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
;zxnDMA programming example&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
;(c) Jim Bagley&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
DMA_RESET                      equ $c3&lt;br /&gt;
DMA_RESET_PORT_A_TIMING        equ $c7&lt;br /&gt;
DMA_RESET_PORT_B_TIMING        equ $cb&lt;br /&gt;
DMA_LOAD                       equ $cf ; %11001111&lt;br /&gt;
DMA_CONTINUE                   equ $d3&lt;br /&gt;
DMA_DISABLE_INTERUPTS          equ $af&lt;br /&gt;
DMA_ENABLE_INTERUPTS           equ $ab&lt;br /&gt;
DMA_RESET_DISABLE_INTERUPTS    equ $a3&lt;br /&gt;
DMA_ENABLE_AFTER_RETI          equ $b7&lt;br /&gt;
DMA_READ_STATUS_BYTE           equ $bf&lt;br /&gt;
DMA_REINIT_STATUS_BYTE         equ $8b&lt;br /&gt;
DMA_START_READ_SEQUENCE        equ $a7&lt;br /&gt;
DMA_FORCE_READY                equ $b3&lt;br /&gt;
DMA_DISABLE                    equ $83&lt;br /&gt;
DMA_ENABLE                     equ $87&lt;br /&gt;
DMA_WRITE_REGISTER_COMMAND     equ $bb&lt;br /&gt;
DMA_BURST                      equ %11001101&lt;br /&gt;
DMA_CONTINUOUS                 equ %10101101&lt;br /&gt;
ZXN_DMA_PORT                   equ $6b&lt;br /&gt;
SPRITE_STATUS_SLOT_SELECT      equ $303B&lt;br /&gt;
SPRITE_IMAGE_PORT              equ $5b&lt;br /&gt;
SPRITE_INFO_PORT               equ $57&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
    IFDEF testing&lt;br /&gt;
        org $5800&lt;br /&gt;
        block 32*24, $38              ; default ULA attributes&lt;br /&gt;
        org $6000&lt;br /&gt;
    ELSE&lt;br /&gt;
        org $2000&lt;br /&gt;
    ENDIF&lt;br /&gt;
&lt;br /&gt;
start&lt;br /&gt;
    ld   hl,$0000&lt;br /&gt;
    ld   de,$4000&lt;br /&gt;
    ld   bc,$800&lt;br /&gt;
    call TransferDMA                  ; copy some random data to the screen pointing&lt;br /&gt;
                                      ; to ROM for now, for the purpose of showing &lt;br /&gt;
                                      ; how to do a DMA copy.&lt;br /&gt;
    ld   a,0                          ; sprite image number we want to update&lt;br /&gt;
    ld   bc,SPRITE_STATUS_SLOT_SELECT&lt;br /&gt;
    out  (c),a                        ; set the sprite image number&lt;br /&gt;
    ld   bc,1*256                     ; number to transfer (1)&lt;br /&gt;
    ld   hl,testsprite                ; from &lt;br /&gt;
    call TransferDMASprite            ; transfer to sprite ram&lt;br /&gt;
&lt;br /&gt;
    nextreg 21,1                      ; turn sprite on. for more info on this check &lt;br /&gt;
                                      ; out https://www.specnext.com/tbblue-io-port-system/&lt;br /&gt;
    ld   de,0&lt;br /&gt;
    ld   (xpos),de                    ; set initial X position ( doesn&#039;t need it for&lt;br /&gt;
                                      ; this demo, but if you run the .loop again it&lt;br /&gt;
                                      ; will continue from where it was&lt;br /&gt;
    ld   a,$20&lt;br /&gt;
    ld   (ypos),a                     ; set initial Y position&lt;br /&gt;
&lt;br /&gt;
.loop&lt;br /&gt;
    ld   a,0                          ; sprite number we want to position&lt;br /&gt;
    ld   bc,SPRITE_STATUS_SLOT_SELECT&lt;br /&gt;
    out  (c),a&lt;br /&gt;
    ld   de,(xpos)&lt;br /&gt;
    ld   hl,(ypos)                    ; ignores H so doing this rather than &lt;br /&gt;
                                      ; ld a,(ypos):ld l,a&lt;br /&gt;
    ld   bc,(image)                   ; not flipped or palette shifted&lt;br /&gt;
    call SetSprite&lt;br /&gt;
&lt;br /&gt;
    halt&lt;br /&gt;
&lt;br /&gt;
    ld   de,(xpos)&lt;br /&gt;
    inc  de&lt;br /&gt;
    ld   (xpos),de&lt;br /&gt;
    ld   a,d&lt;br /&gt;
    cp   $01&lt;br /&gt;
    jr   nz,.loop                     ; if high byte of xpos is not 1 (right of &lt;br /&gt;
                                      ; screen )&lt;br /&gt;
    ld   a,e&lt;br /&gt;
    cp   $20+1&lt;br /&gt;
    jr   nz,.loop                     ; if low byte is not $21 just off the right of&lt;br /&gt;
                                      ; the screen, $20 is off screen but as the &lt;br /&gt;
                                      ; INC DE is just above and not updated sprite&lt;br /&gt;
                                      ; after it, it needs to be $21&lt;br /&gt;
    xor  a&lt;br /&gt;
    ret                               ; return back to basic with OK&lt;br /&gt;
&lt;br /&gt;
xpos dw 0                             ; x position&lt;br /&gt;
ypos db 0                             ; y position&lt;br /&gt;
                                      ; these next two BITS and IMAGE are swapped &lt;br /&gt;
                                      ; as bits needs to go into B register&lt;br /&gt;
image db 0+$80                        ; use image 0 (for the image we transfered)&lt;br /&gt;
                                      ; +$80 to set the sprite to active&lt;br /&gt;
bits db 0                             ; not flipped or palette shifted&lt;br /&gt;
&lt;br /&gt;
c1 = %11100000&lt;br /&gt;
c2 = %11000000&lt;br /&gt;
c3 = %10100000&lt;br /&gt;
c4 = %10000000&lt;br /&gt;
c5 = %01100000&lt;br /&gt;
c6 = %01000000&lt;br /&gt;
c7 = %00100000&lt;br /&gt;
c8 = %00000000&lt;br /&gt;
&lt;br /&gt;
testsprite&lt;br /&gt;
    db c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1&lt;br /&gt;
    db c1,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c1&lt;br /&gt;
    db c1,c2,c3,c3,c3,c3,c3,c3,c3,c3,c3,c3,c3,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c4,c4,c4,c4,c4,c4,c4,c4,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c5,c5,c5,c5,c5,c5,c5,c5,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c5,c6,c6,c6,c6,c6,c6,c5,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c5,c6,c7,c7,c7,c7,c6,c5,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c5,c6,c7,c8,c8,c7,c6,c5,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c5,c6,c7,c8,c8,c7,c6,c5,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c5,c6,c7,c7,c7,c7,c6,c5,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c5,c6,c6,c6,c6,c6,c6,c5,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c5,c5,c5,c5,c5,c5,c5,c5,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c4,c4,c4,c4,c4,c4,c4,c4,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c3,c3,c3,c3,c3,c3,c3,c3,c3,c3,c3,c2,c1&lt;br /&gt;
    db c1,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c1&lt;br /&gt;
    db c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1&lt;br /&gt;
&lt;br /&gt;
;-------------------------------------------------&lt;br /&gt;
; de = X&lt;br /&gt;
; l = Y&lt;br /&gt;
; b = bits&lt;br /&gt;
; c = sprite image&lt;br /&gt;
SetSprite&lt;br /&gt;
    push bc&lt;br /&gt;
    ld bc,SPRITE_INFO_PORT&lt;br /&gt;
    out (c),e ; Xpos&lt;br /&gt;
    out (c),l ; Ypos&lt;br /&gt;
    pop hl&lt;br /&gt;
    ld a,d&lt;br /&gt;
    and 1&lt;br /&gt;
    or h&lt;br /&gt;
    out (c),a&lt;br /&gt;
    ld a,l:or $80&lt;br /&gt;
    out (c),a ; image&lt;br /&gt;
    ret&lt;br /&gt;
&lt;br /&gt;
;--------------------------------&lt;br /&gt;
; hl = source&lt;br /&gt;
; de = destination&lt;br /&gt;
; bc = length&lt;br /&gt;
;--------------------------------&lt;br /&gt;
TransferDMA&lt;br /&gt;
    di&lt;br /&gt;
    ld (DMASource),hl&lt;br /&gt;
    ld (DMADest),de&lt;br /&gt;
    ld (DMALength),bc&lt;br /&gt;
    ld hl,DMACode&lt;br /&gt;
    ld b,DMACode_Len&lt;br /&gt;
    ld c,ZXN_DMA_PORT&lt;br /&gt;
    otir&lt;br /&gt;
    ei&lt;br /&gt;
    ret&lt;br /&gt;
&lt;br /&gt;
DMACode db DMA_DISABLE&lt;br /&gt;
        db %01111101                  ; R0-Transfer mode, A -&amp;gt; B, write adress &lt;br /&gt;
                                      ; + block length&lt;br /&gt;
DMASource dw 0                        ; R0-Port A, Start address &lt;br /&gt;
                                      ; (source address)&lt;br /&gt;
DMALength dw 0                        ; R0-Block length (length in bytes)&lt;br /&gt;
        db %01010100                  ; R1-write A time byte, increment, to &lt;br /&gt;
                                      ; memory, bitmask&lt;br /&gt;
        db %00000010                  ; 2t&lt;br /&gt;
        db %01010000                  ; R2-write B time byte, increment, to &lt;br /&gt;
                                      ; memory, bitmask&lt;br /&gt;
        db %00000010                  ; R2-Cycle length port B&lt;br /&gt;
        db DMA_CONTINUOUS             ; R4-Continuous mode (use this for block &lt;br /&gt;
                                      ; transfer), write dest adress&lt;br /&gt;
DMADest dw 0                          ; R4-Dest address (destination address)&lt;br /&gt;
        db %10000010                  ; R5-Restart on end of block, RDY active &lt;br /&gt;
                                      ; LOW&lt;br /&gt;
        db DMA_LOAD                   ; R6-Load&lt;br /&gt;
        db DMA_ENABLE                 ; R6-Enable DMA&lt;br /&gt;
        &lt;br /&gt;
DMACode_Len                    equ $-DMACode&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; hl = source&lt;br /&gt;
; bc = length&lt;br /&gt;
; set port to write to with TBBLUE_REGISTER_SELECT&lt;br /&gt;
; prior to call&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
TransferDMAPort&lt;br /&gt;
    di&lt;br /&gt;
    ld (DMASourceP),hl&lt;br /&gt;
    ld (DMALengthP),bc&lt;br /&gt;
    ld hl,DMACodeP&lt;br /&gt;
    ld b,DMACode_LenP&lt;br /&gt;
    ld c,ZXN_DMA_PORT&lt;br /&gt;
    otir&lt;br /&gt;
    ei&lt;br /&gt;
    ret&lt;br /&gt;
&lt;br /&gt;
DMACodeP db DMA_DISABLE&lt;br /&gt;
        db %01111101                  ; R0-Transfer mode, A -&amp;gt; B, write adress &lt;br /&gt;
                                      ; + block length&lt;br /&gt;
DMASourceP dw 0                       ; R0-Port A, Start address (source address)&lt;br /&gt;
DMALengthP dw 0                       ; R0-Block length (length in bytes)&lt;br /&gt;
        db %01010100                  ; R1-read A time byte, increment, to &lt;br /&gt;
                                      ; memory, bitmask&lt;br /&gt;
        db %00000010                  ; R1-Cycle length port A&lt;br /&gt;
        db %01101000                  ; R2-write B time byte, increment, to &lt;br /&gt;
                                      ; memory, bitmask&lt;br /&gt;
        db %00000010                  ; R2-Cycle length port B&lt;br /&gt;
        db %10101101                  ; R4-Continuous mode (use this for block &lt;br /&gt;
                                      ; transfer), write dest adress&lt;br /&gt;
        dw $253b                      ; R4-Dest address (destination address)&lt;br /&gt;
        db %10000010                  ; R5-Restart on end of block, RDY active&lt;br /&gt;
                                      ; LOW&lt;br /&gt;
        db DMA_LOAD                   ; R6-Load&lt;br /&gt;
        db DMA_ENABLE                 ; R6-Enable DMA&lt;br /&gt;
        &lt;br /&gt;
DMACode_LenP                   equ $-DMACodeP&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; hl = source&lt;br /&gt;
; bc = length&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
TransferDMASprite&lt;br /&gt;
    di&lt;br /&gt;
    ld (DMASourceS),hl&lt;br /&gt;
    ld (DMALengthS),bc&lt;br /&gt;
    ld hl,DMACodeS&lt;br /&gt;
    ld b,DMACode_LenS&lt;br /&gt;
    ld c,ZXN_DMA_PORT&lt;br /&gt;
    otir&lt;br /&gt;
    ei&lt;br /&gt;
    ret&lt;br /&gt;
&lt;br /&gt;
DMACodeS db DMA_DISABLE&lt;br /&gt;
        db %01111101                   ; R0-Transfer mode, A -&amp;gt; B, write adress &lt;br /&gt;
                                       ; + block length&lt;br /&gt;
DMASourceS dw 0                        ; R0-Port A, Start address (source address)&lt;br /&gt;
DMALengthS dw 0                        ; R0-Block length (length in bytes)&lt;br /&gt;
        db %01010100                   ; R1-read A time byte, increment, to &lt;br /&gt;
                                       ; memory, bitmask&lt;br /&gt;
        db %00000010                   ; R1-Cycle length port A&lt;br /&gt;
        db %01101000                   ; R2-write B time byte, increment, to &lt;br /&gt;
                                       ; memory, bitmask&lt;br /&gt;
        db %00000010                   ; R2-Cycle length port B&lt;br /&gt;
        db %10101101                   ; R4-Continuous mode (use this for block&lt;br /&gt;
                                       ; transfer), write dest adress&lt;br /&gt;
        dw SPRITE_IMAGE_PORT           ; R4-Dest address (destination address)&lt;br /&gt;
        db %10000010                   ; R5-Restart on end of block, RDY active&lt;br /&gt;
                                       ; LOW&lt;br /&gt;
        db DMA_LOAD                    ; R6-Load&lt;br /&gt;
        db DMA_ENABLE                  ; R6-Enable DMA&lt;br /&gt;
DMACode_LenS                   equ $-DMACodeS&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; de = dest, a = fill value, bc = lenth&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
DMAFill&lt;br /&gt;
    di&lt;br /&gt;
    ld (FillValue),a&lt;br /&gt;
    ld (DMACDest),de&lt;br /&gt;
    ld (DMACLength),bc&lt;br /&gt;
    ld hl,DMACCode&lt;br /&gt;
    ld b,DMACCode_Len&lt;br /&gt;
    ld c,ZXN_DMA_PORT&lt;br /&gt;
    otir&lt;br /&gt;
    ei&lt;br /&gt;
    ret&lt;br /&gt;
&lt;br /&gt;
FillValue db 22&lt;br /&gt;
DMACCode db DMA_DISABLE&lt;br /&gt;
        db %01111101&lt;br /&gt;
DMACSource dw FillValue&lt;br /&gt;
DMACLength dw 0&lt;br /&gt;
        db %00100100,%00010000,%10101101&lt;br /&gt;
DMACDest dw 0&lt;br /&gt;
        db DMA_LOAD,DMA_ENABLE&lt;br /&gt;
DMACCode_Len equ $-DMACCode&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; End of file&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
    IFDEF testing&lt;br /&gt;
        savenex open &amp;quot;DMAtest.nex&amp;quot;, start, $FF00&lt;br /&gt;
        savenex bank 5&lt;br /&gt;
    ELSE&lt;br /&gt;
fin&lt;br /&gt;
        savebin &amp;quot;DMATEST&amp;quot;,start,fin-start&lt;br /&gt;
    ENDIF&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Based on original text by: Allen Albright &amp;amp; Mike Dailly with input by Jim Bagley, Lyndon J Sharp and Phoebus R. Dokos&lt;br /&gt;
&lt;br /&gt;
== Technical details (core 3.1.3+)  ==&lt;br /&gt;
&lt;br /&gt;
The Zilog/zxnDMA mode is now selected by using the particular I/O port number ({{PortNo|$xx6B}} for zxnDMA mode, {{PortNo|$xx0B}} for Zilog mode). The bit 6 in {{NextRegNo|$06}} is not DMA related any more and will be reused for something different.&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;counter&amp;quot; RR1-RR2 read back after transfer has correct byte order since core 3.1.4.&lt;br /&gt;
&lt;br /&gt;
Other differences described below in &amp;quot;3.0.5&amp;quot; remains (but from practical point of view the Zilog DMA emulation in 3.1.4 is near-perfect, all the remaining differences are very minor).&lt;br /&gt;
&lt;br /&gt;
== Technical details (core 3.0.5)  ==&lt;br /&gt;
&lt;br /&gt;
=== Zilog DMA compatibility mode ===&lt;br /&gt;
In Zilog DMA compatibility mode (bit 6 of {{NextRegNo|$06}}) the zxnDMA will mostly work as expected, but there are few differences in behaviour which may eventually throw off some rare SW, here is the list of the known differences (most of them describe also how the zxnDMA mode works):&lt;br /&gt;
&lt;br /&gt;
The LOAD command must be issued with correct transfer direction, loading addresses in opposite direction and flipping direction afterward will mismatch the source/destination address data (Zilog/UA858D DMA chips are also sensitive to direction flip after LOAD, but the resulting transfer quirks in different way, reading source data byte after write, offsetting whole transfer by one and damaging start/end of sequence).&lt;br /&gt;
(does apply also to zxnDMA mode)&lt;br /&gt;
&lt;br /&gt;
The LOAD command will NOT destroy the already issued &amp;quot;Initialize Read Sequence&amp;quot; - this is how even the original Zilog documentation describes the DMA chip operation, but the real Zilog DMA and UA858D (clone chip) both destroy read sequence upon LOAD command (zxnDMA is better).&lt;br /&gt;
(does apply also to zxnDMA mode)&lt;br /&gt;
&lt;br /&gt;
The content of registers read back after finished transfer differs: the counter has swapped LSB with MSB byte, and both addresses will be adjusted length+1 times (Zilog/UA858D will return destination address adjusted only length-many times).&lt;br /&gt;
(does apply also to zxnDMA mode, except addresses are adjusted only &amp;quot;length&amp;quot; times of course, counter has still swapped bytes)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;del&amp;gt;Any read of zxnDMA port without pending read request (commands &amp;quot;Read Status Byte&amp;quot; or &amp;quot;Initialize Read Sequence&amp;quot;) will return status byte (Zilog will return random value vaguely similar to status byte, but incorrect, UA858D will return zero).&lt;br /&gt;
(does apply also to zxnDMA mode)&amp;lt;/del&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
2026-03-30: any read of zxnDMA port without pending read request will return next byte in read sequence, the default read mask is 0x7F after power on (based on reading the VHDL, needs to verify with HW).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;del&amp;gt;Status byte doesn&#039;t have bit 0 set (the &amp;quot;T&amp;quot; bit in description above).&lt;br /&gt;
(does apply also to zxnDMA mode)&amp;lt;/del&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
2026-03-30: going by [https://gitlab.com/SpectrumNext/ZX%20Spectrum%20Next%20FPGA/-/blob/master/cores/zxnext/src/device/dma.vhd?ref%20type=heads VHDL source] this seems to be now fixed, needs to verify with HW and guess in which version of core this was fixed&lt;br /&gt;
&lt;br /&gt;
The command 0xBB setting read mask will cause implicit 0xA7 Initialize Read Sequence.&lt;br /&gt;
(does apply also to zxnDMA mode)&lt;br /&gt;
&lt;br /&gt;
Be aware that both custom timing cycles count, and prescalar values are preserved in zxnDMA even when future write to WR1/WR2 does skip these particular bytes. To reset prescalar or cycles timing, write explicitly zero into prescalar register or use commands reset/reset-port-timing.&lt;br /&gt;
(does apply also to zxnDMA mode, the prescalar works only in zxnDMA mode)&lt;br /&gt;
&lt;br /&gt;
The destination port address is LOAD-ed even when it is &amp;quot;fixed&amp;quot; type (Contrary to Zilog DMA, which requires you to load such port as &amp;quot;source&amp;quot;, flip the direction after and re-LOAD again with correct direction. UA858D chip does also load destination port address in any case, just like zxnDMA).&lt;br /&gt;
(does apply also to zxnDMA mode)&lt;br /&gt;
&lt;br /&gt;
=== zxnDMA mode vs Zilog mode ===&lt;br /&gt;
&lt;br /&gt;
In zxnDMA mode length of transfer is equal to the length written to WR0 register, port addresses are adjusted also only length-times.&lt;br /&gt;
&lt;br /&gt;
Prescalar value will affect speed of transfer (use zero to switch prescalar off) (in burst mode during the extra idle time the CPU receives control back and can execute further instructions, in continuous mode the transfer will keep blocking CPU even when &amp;quot;slow&amp;quot; transfer is being done).&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=DMA&amp;diff=41877</id>
		<title>DMA</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=DMA&amp;diff=41877"/>
		<updated>2026-03-30T12:14:20Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: adding more notes about reading-status of zxnDMA, figured out while reading VHDL and debugging Mike&amp;#039;s mod player init.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
The ZX Spectrum Next DMA (zxnDMA) is a single channel DMA device that implements a subset of the Z80 DMA functionality. The subset is large enough to be compatible with common uses of the similar Datagear interface available for standard ZX Spectrum computers and compatibles. It also adds a burst mode capability that can deliver audio at programmable sample rates to the DAC device.&lt;br /&gt;
&lt;br /&gt;
== Accessing the zxnDMA ==&lt;br /&gt;
&amp;lt;del&amp;gt;The zxnDMA is mapped to a single Read/Write IO Port 0x6B which is the same one used by the Datagear but unlike the Datagear it doesn&#039;t also map itself to a second port 0x0B similar to the MB-02 interface.&amp;lt;/del&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since core 3.1.2 the zxnDMA is mapped to {{PortNo|$xx6B}}, and Zilog-DMA mode is mapped to {{PortNo|$xx0B}}.&lt;br /&gt;
&lt;br /&gt;
== Description  ==&lt;br /&gt;
The normal Z80 DMA (Z8410) chip is a pipelined device and because of that it has numerous off-by-one idiosyncrasies and requirements on the order that certain commands should be carried out. These issues are not duplicated in the zxnDMA. You can continue to program the zxnDMA as if it is were a Z8410 DMA device but it can also be programmed in a simpler manner.&lt;br /&gt;
&lt;br /&gt;
The single channel of the zxnDMA chip consists of two ports named A and B. Transfers can occur in either direction between ports A and B, each port can describe a target in memory or IO, and each can be configured to autoincrement, autodecrement or stay fixed after a byte is transferred.&lt;br /&gt;
&lt;br /&gt;
A special feature of the zxnDMA can force each byte transfer to take a fixed amount of time so that the zxnDMA can be used to deliver sampled audio.&lt;br /&gt;
&lt;br /&gt;
== Modes of Operation ==&lt;br /&gt;
The zxnDMA can operate in a z80-DMA compatibility mode.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;REMOVED in core 3.1.2:&#039;&#039;&#039; &amp;lt;del&amp;gt;The z80-DMA compatibility mode is selected by setting bit 6 of nextreg 0x06. In this mode, all transfers involve length+1 bytes which is the same behaviour as the z80-DMA chip. In zxn-DMA mode, the transfer length is exactly the number of bytes programmed. This mode is mainly present to accommodate existing spectrum software that uses the z80-DMA and for cp/m programs that may have a z80-DMA option.&amp;lt;/del&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Since core 3.1.2:&#039;&#039;&#039; the DMA mode is selected by port number, the {{PortNo|$xx6B}} works in zxnDMA mode, {{PortNo|$xx0B}} works in Zilog mode. The bit 6 in {{NextRegNo|$06}} is not DMA related any more and will be reused for something different.&lt;br /&gt;
&lt;br /&gt;
The zxnDMA can also operate in either burst or continuous modes.&lt;br /&gt;
&lt;br /&gt;
Continuous mode means the DMA chip runs to completion without allowing the CPU to run. When the CPU starts the DMA, the DMA operation will complete before the CPU executes its next instruction.&lt;br /&gt;
&lt;br /&gt;
Burst mode nominally means the DMA lets the CPU run if either port is not ready. This condition can&#039;t happen in the zxnDMA chip except when operated in the special fixed time transfer mode. In this mode, the zxnDMA will let the CPU run while it waits for the fixed time to expire between bytes transferred.&lt;br /&gt;
&lt;br /&gt;
Note that there is no byte transfer mode as in the Z80 DMA.&lt;br /&gt;
&lt;br /&gt;
== Programming the zxnDMA ==&lt;br /&gt;
Like the Z80 DMA chip, the zxnDMA has seven write registers named WR0-WR6 that control the device. Each register WR0-WR6 can have zero or more parameters associated with it.&lt;br /&gt;
&lt;br /&gt;
In a first write to the zxnDMA port, the write value is compared against a bitmask to determine which of the WR0-WR6 is the target. Remaining bits in the written value can contain data as well as a list of associated parameter bits. The parameter bits determine if further writes are expected to deliver parameter values. If there are multiple parameter bits set, the expected order of parameter values written is determined by parameter bit position from right to left (bit 0 through bit 7). Once all parameters are written, the zxnDMA again expects a regular register write selecting WR0-WR6.&lt;br /&gt;
&lt;br /&gt;
The table below describes the registers and the bitmask required to select them on the zxnDMA.&lt;br /&gt;
&lt;br /&gt;
{| &lt;br /&gt;
! Register Group&lt;br /&gt;
! Register Function Description&lt;br /&gt;
! Bitmask&lt;br /&gt;
! Notes&lt;br /&gt;
|- &lt;br /&gt;
| WR0&lt;br /&gt;
| Direction, Operation and Port A configuration&lt;br /&gt;
| &amp;lt;pre&amp;gt;0XXXXXAA&amp;lt;/pre&amp;gt;&lt;br /&gt;
| AA must NOT be 00&lt;br /&gt;
|- &lt;br /&gt;
| WR1&lt;br /&gt;
| Port A configuration&lt;br /&gt;
| &amp;lt;pre&amp;gt;0XXXX100&amp;lt;/pre&amp;gt;&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| WR2&lt;br /&gt;
| Port B configuration&lt;br /&gt;
| &amp;lt;pre&amp;gt;0XXXX000&amp;lt;/pre&amp;gt;&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| WR3&lt;br /&gt;
| Activation&lt;br /&gt;
| &amp;lt;pre&amp;gt;1XXXXX00&amp;lt;/pre&amp;gt;&lt;br /&gt;
| It’s best to use WR6&lt;br /&gt;
|- &lt;br /&gt;
| WR4&lt;br /&gt;
| Port B, Timing and Interrupt configuration&lt;br /&gt;
| &amp;lt;pre&amp;gt;1XXXXX01&amp;lt;/pre&amp;gt;&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| WR5&lt;br /&gt;
| Ready and Stop configuration&lt;br /&gt;
| &amp;lt;pre&amp;gt;10XXX010&amp;lt;/pre&amp;gt;&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| WR6&lt;br /&gt;
| Command Register&lt;br /&gt;
| &amp;lt;pre&amp;gt;1XXXXX11&amp;lt;/pre&amp;gt;&lt;br /&gt;
| &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== zxnDMA Registers ==&lt;br /&gt;
These are described below following the same convention used by Zilog for its DMA chip:&lt;br /&gt;
&lt;br /&gt;
=== WR0 – Write Register Group 0 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;D7  D6  D5  D4  D3  D2  D1  D0  BASE REGISTER BYTE&lt;br /&gt;
 0   |   |   |   |   |   |   |&lt;br /&gt;
     |   |   |   |   |   0   0  Do not use&lt;br /&gt;
     |   |   |   |   |   0   1  Transfer (Prefer this for Z80 DMA compatibility)&lt;br /&gt;
     |   |   |   |   |   1   0  Do not use (Behaves like Transfer, Search on Z80 DMA)&lt;br /&gt;
     |   |   |   |   |                       &lt;br /&gt;
     |   |   |   |   |   1   1  Do not use (Behaves like Transfer, Search/Transfer on Z80 DMA)&lt;br /&gt;
     |   |   |   |   |                      &lt;br /&gt;
     |   |   |   |   0 = Port B -&amp;amp;gt; Port A (Byte transfer direction)&lt;br /&gt;
     |   |   |   |   1 = Port A -&amp;amp;gt; Port B&lt;br /&gt;
     |   |   |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  PORT A STARTING ADDRESS (LOW BYTE)&lt;br /&gt;
     |   |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  PORT A STARTING ADDRESS (HIGH BYTE)&lt;br /&gt;
     |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  BLOCK LENGTH (LOW BYTE)&lt;br /&gt;
     V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  BLOCK LENGTH (HIGH BYTE)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Several registers are accessible from WR0. The first write to WR0 is to the base register byte. Bits D6:D3 are optionally set to indicate that associated registers in this group will be written next. The order the writes come in are from D3 to D6 (right to left). For example, if bits D6 and D3 are set, the next two writes will be directed to PORT A STARTING ADDRESS LOW followed by BLOCK LENGTH HIGH.&lt;br /&gt;
&lt;br /&gt;
=== WR1 – Write Register Group 1 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;D7  D6  D5  D4  D3  D2  D1  D0  BASE REGISTER BYTE&lt;br /&gt;
 0   |   |   |   |   1   0   0&lt;br /&gt;
     |   |   |   |&lt;br /&gt;
     |   |   |   0 = Port A is memory&lt;br /&gt;
     |   |   |   1 = Port A is IO&lt;br /&gt;
     |   |   |&lt;br /&gt;
     |   0   0 = Port A address decrements&lt;br /&gt;
     |   0   1 = Port A address increments&lt;br /&gt;
     |   1   0 = Port A address is fixed&lt;br /&gt;
     |   1   1 = Port A address is fixed&lt;br /&gt;
     |&lt;br /&gt;
     V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  PORT A VARIABLE TIMING BYTE&lt;br /&gt;
 0   0   0   0   0   0   |   |&lt;br /&gt;
                         0   0 = Cycle Length = 4&lt;br /&gt;
                         0   1 = Cycle Length = 3&lt;br /&gt;
                         1   0 = Cycle Length = 2&lt;br /&gt;
                         1   1 = Do not use&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The cycle length is the number of cycles used in a read or write operation. The first cycle asserts signals and the last cycle releases them. There is no half cycle timing for the control signals.&lt;br /&gt;
&lt;br /&gt;
=== WR2 – Write Register Group 2 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;D7  D6  D5  D4  D3  D2  D1  D0  BASE REGISTER BYTE&lt;br /&gt;
 0   |   |   |   |   0   0   0&lt;br /&gt;
     |   |   |   |&lt;br /&gt;
     |   |   |   0 = Port B is memory&lt;br /&gt;
     |   |   |   1 = Port B is IO&lt;br /&gt;
     |   |   |&lt;br /&gt;
     |   0   0 = Port B address decrements&lt;br /&gt;
     |   0   1 = Port B address increments&lt;br /&gt;
     |   1   0 = Port B address is fixed&lt;br /&gt;
     |   1   1 = Port B address is fixed&lt;br /&gt;
     |&lt;br /&gt;
     V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  PORT B VARIABLE TIMING BYTE&lt;br /&gt;
 0   0   |   0   0   0   |   |&lt;br /&gt;
         |               0   0 = Cycle Length = 4&lt;br /&gt;
         |               0   1 = Cycle Length = 3&lt;br /&gt;
         |               1   0 = Cycle Length = 2&lt;br /&gt;
         |               1   1 = Do not use&lt;br /&gt;
         |&lt;br /&gt;
         V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  ZXN PRESCALAR (FIXED TIME TRANSFER)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The ZXN PRESCALAR is a feature of the zxnDMA implementation. If non-zero, a delay will be inserted after each byte is transferred such that the total time needed for each transfer is determined by the prescalar. This works in both the continuous mode and the burst mode. If the DMA is operated in burst mode, the DMA will give up any waiting time to the CPU so that the CPU can run while the DMA is idle.&lt;br /&gt;
&lt;br /&gt;
The rate of transfer is given by the formula “Frate = 875kHz / prescalar” or, rearranged, “prescalar = 875kHz / Frate”. The formula is framed in terms of a sample rate (Frate) but Frate can be inverted to set a transfer time for each byte instead. The 875kHz constant is a nominal value assuming a 28MHz system clock; the system clock actually varies from this depending on the video timing selected by the user (HDMI, VGA0-6) so for complete accuracy the constant should be prorated according to documentation for nextreg 0x11.&lt;br /&gt;
&lt;br /&gt;
In a DMA audio setting, selecting a sample rate of 16kHz would mean setting the prescalar value to 55. This sample period is constant across changes in CPU speed.&lt;br /&gt;
&lt;br /&gt;
=== WR3 – Write Register Group 3 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;D7  D6  D5  D4  D3  D2  D1  D0  BASE REGISTER BYTE&lt;br /&gt;
 1   |   0   0   0   0   0   0&lt;br /&gt;
     |&lt;br /&gt;
     1 = DMA Enable&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The Z80 DMA defines more fields but they are ignored by the zxnDMA. The two other registers defined by the Z80 DMA in this group on D4 and D3 are implemented by the zxnDMA but they do nothing.&lt;br /&gt;
&lt;br /&gt;
It is preferred to start the DMA by writing an &#039;Enable DMA&#039; command to WR6.&lt;br /&gt;
&lt;br /&gt;
=== WR4 – Write Register Group 4 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;D7  D6  D5  D4  D3  D2  D1  D0  BASE REGISTER BYTE&lt;br /&gt;
 1   |   |   0   |   |   0   1&lt;br /&gt;
     |   |       |   |&lt;br /&gt;
     0   0 = Do not use (Behaves like Continuous mode, Byte mode on Z80 DMA)&lt;br /&gt;
     0   1 = Continuous mode&lt;br /&gt;
     1   0 = Burst mode&lt;br /&gt;
     1   1 = Do not use&lt;br /&gt;
                 |   |&lt;br /&gt;
                 |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  PORT B STARTING ADDRESS (LOW BYTE)&lt;br /&gt;
                 |&lt;br /&gt;
                 V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  PORT B STARTING ADDRESS (HIGH BYTE)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The Z80 DMA defines three more registers in this group through D4 that define interrupt behaviour. Interrups and pulse generation are not implemented in the zxnDMA nor are these registers available for writing.&lt;br /&gt;
&lt;br /&gt;
=== WR5 – Write Register Group 5 ===&lt;br /&gt;
&amp;lt;pre&amp;gt;D7  D6  D5  D4  D3  D2  D1  D0  BASE REGISTER BYTE&lt;br /&gt;
 1   0   |   |   0   0   1   0&lt;br /&gt;
         |   |&lt;br /&gt;
         |   0 = /ce only&lt;br /&gt;
         |   1 = /ce &amp;amp; /wait multiplexed&lt;br /&gt;
         |&lt;br /&gt;
         0 = Stop on end of block&lt;br /&gt;
         1 = Auto restart on end of block&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The /ce &amp;amp; /wait mode is implemented in the zxnDMA but is not currently used. This mode has an external device using the DMA&#039;s /ce pin to insert wait states during the DMA&#039;s transfer.&lt;br /&gt;
&lt;br /&gt;
The auto restart feature causes the DMA to automatically reload its source and destination addresses and reset its byte counter to zero to repeat the last transfer when a previous one is finished.&lt;br /&gt;
&lt;br /&gt;
=== WR6 – Command Register ===&lt;br /&gt;
&amp;lt;pre&amp;gt;D7  D6  D5  D4  D3  D2  D1  D0  BASE REGISTER BYTE&lt;br /&gt;
 1   ?   ?   ?   ?   ?   1   1&lt;br /&gt;
     |   |   |   |   |&lt;br /&gt;
     1   0   0   0   0 = 0xC3 = Reset&lt;br /&gt;
     1   0   0   0   1 = 0xC7 = Reset Port A Timing&lt;br /&gt;
     1   0   0   1   0 = 0xCB = Reset Port B Timing&lt;br /&gt;
     0   1   1   0   0 = 0xB3 = Force Ready (irrelevant for zxnDMA)&lt;br /&gt;
     0   1   1   1   1 = 0xBF = Read Status Byte&lt;br /&gt;
     0   0   0   1   0 = 0x8B = Reinitialize Status Byte&lt;br /&gt;
     0   1   0   0   1 = 0xA7 = Initialize Read Sequence&lt;br /&gt;
     1   0   0   1   1 = 0xCF = Load&lt;br /&gt;
     1   0   1   0   0 = 0xD3 = Continue&lt;br /&gt;
     0   0   0   0   1 = 0x87 = Enable DMA&lt;br /&gt;
     0   0   0   0   0 = 0x83 = Disable DMA&lt;br /&gt;
 +-- 0   1   1   1   0 = 0xBB = Read Mask Follows&lt;br /&gt;
 |&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  READ MASK&lt;br /&gt;
 0   |   |   |   |   |   |   |&lt;br /&gt;
     |   |   |   |   |   |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  Status Byte&lt;br /&gt;
     |   |   |   |   |   |&lt;br /&gt;
     |   |   |   |   |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  Byte Counter Low (&amp;quot;High&amp;quot; with core 3.0.5 = bug in core)&lt;br /&gt;
     |   |   |   |   |&lt;br /&gt;
     |   |   |   |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  Byte Counter High (&amp;quot;Low&amp;quot; with core 3.0.5 = bug in core)&lt;br /&gt;
     |   |   |   |&lt;br /&gt;
     |   |   |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  Port A Address Low&lt;br /&gt;
     |   |   |&lt;br /&gt;
     |   |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  Port A Address High&lt;br /&gt;
     |   |&lt;br /&gt;
     |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  Port B Address Low&lt;br /&gt;
     |&lt;br /&gt;
     V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  Port B Address High&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Unimplemented Z80 DMA commands are ignored.&lt;br /&gt;
&lt;br /&gt;
Prior to starting the DMA transfer, a LOAD command must be issued to copy the Port A and Port B addresses into the DMA&#039;s internal pointers. Then an &#039;Enable DMA&#039; command is issued to start the DMA. The last LOAD command before ENABLE must be done with correct transfer direction set.&lt;br /&gt;
&lt;br /&gt;
The &#039;Continue&#039; command resets the DMA&#039;s byte counter so that a following &#039;Enable DMA&#039; allows the DMA to repeat the last transfer but using the current internal address pointers. I.e. it continues from where the last copy operation left off.&lt;br /&gt;
&lt;br /&gt;
Reset and Reset Port A/B Timing commands on zxnDMA do reset also prescalar value.&lt;br /&gt;
&lt;br /&gt;
Registers can be read via an IO read from the DMA port after setting the read mask. (At power up the read mask is set to 0x7f). Register values are the current internal DMA counter values. So &#039;Port Address A Low&#039; is the lower 8-bits of Port A’s next transfer address. Once the end of the read mask is reached, further reads loop around to the first one.&lt;br /&gt;
&lt;br /&gt;
The format of the DMA status byte is as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;00E1101T&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
E is set to 0 if the total block length has been transferred at least once.&lt;br /&gt;
&lt;br /&gt;
T is set to 1 if at least one byte has been transferred.&lt;br /&gt;
&lt;br /&gt;
== Operating speed ==&lt;br /&gt;
The zxnDMA operates at the same speed as the CPU, that is 3.5MHz, 7MHz, 14MHz or 28Mhz. This is a contended clock that is modified by the ULA and the auto-slowdown by [[Layer 2|Layer2]] (which only occurred in Next core&#039;s 1 and 2, the limitation was lifted in core 3.0).&lt;br /&gt;
&lt;br /&gt;
The (pre-core 3.0) auto-slowdown occurs without user intervention if speed exceeds 7Mhz and the active Layer2 display is being generated (higher speed operation resumes when the active Layer2 display is not generated). Programmers do NOT need to account for speed differences regarding DMA transfers as this happens automatically.&lt;br /&gt;
&lt;br /&gt;
Because of this, the cycle lengths for Ports A and B can be set to their minimum values without ill effects. The cycle lengths specified for Ports A and B are intended to selectively slow down read or write cycles for hardware that cannot operate at the DMA&#039;s full speed.&lt;br /&gt;
&lt;br /&gt;
== The DMA and Interrupts ==&lt;br /&gt;
The zxnDMA cannot currently generate [[Interrupts|interrupts]].&lt;br /&gt;
&lt;br /&gt;
The other side of this is that while the DMA controls the bus, the Z80 cannot respond to interrupts. On the Z80, the NMI interrupt is edge triggered so if an NMI occurs the fact that it occurred is stored internally in the Z80 so that it will respond when it is woken up. On the other hand, maskable interrupts are level triggered. That is, the Z80 must be active to regularly sample the /INT line to determine if a maskable interrupt is occurring. On the Spectrum and the ZX Next, the ULA (and line interrupt) are only asserted for a fixed amount of time ~30 cycles at 3.5MHz. If the DMA is executing a transfer while the interrupt is asserted, the CPU will not be able to see this and it will most likely miss the interrupt. In burst mode, with large-enough prescalar value, the CPU will never miss these interrupts, although this may change if multiple channels are implemented.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Since core 3.1.8:&#039;&#039;&#039; the ability to interrupt DMA transfers was added, this is opt-in mechanism and must be configured through {{NextRegNo|$CC}}, {{NextRegNo|$CD}} and {{NextRegNo|$CE}} and requires &amp;quot;hw im2 mode&amp;quot; interrupts being set. Because interrupts are only sampled at the end of an instruction by the Z80, each time the dma is interrupted one instruction of progress is made in the main program (before the interrupt handler code is entered).&lt;br /&gt;
&lt;br /&gt;
This means after starting the DMA transfer with last `out` instruction you must follow it by N instructions which don&#039;t affect the transfer (don&#039;t remap source data memory, select different sprite/copper/... index if that&#039;s target of transfer, don&#039;t write anything to zxnDMA port), either doing different kind of work with CPU or adding block of `nop` instructions, to have non-interfering block of code available to fire N interrupts during transfer. Chose N to accommodate for worst case scenario of how many times you will interrupt the running DMA transfer. Or you can read state of zxnDMA to see if transfer did finish, but (IMHO by ped7g) in most cases it will be performance-cheaper to just add block of nop instructions or do other work on CPU not interfering with transfer.&lt;br /&gt;
&lt;br /&gt;
== Programming examples ==&lt;br /&gt;
A simple way to program the DMA is to walk down the list of registers WR0-WR5, sending desired settings to each. Then start the DMA by sending a LOAD command followed by an ENABLE_DMA command to WR6. Once more familiar with the DMA, you will discover that the amount of information sent can be reduced to what changes between transfers.&lt;br /&gt;
&lt;br /&gt;
=== Assembly ===&lt;br /&gt;
Short example program to DMA memory to the screen, then DMA a sprite image from memory to sprite RAM, and then showing said sprite scrolling across the screen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;;------------------------------------------------------------------------------&lt;br /&gt;
    ; sjasmplus extra options to enable Z80N, stricter syntax and Next device&lt;br /&gt;
    opt --zxnext --syntax=abf : device zxspectrumnext&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
;     DEFINE testing        ; uncomment to produce NEX file (instead of DOT)&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; DMA (Register 6)&lt;br /&gt;
;&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
;zxnDMA programming example&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
;(c) Jim Bagley&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
DMA_RESET                      equ $c3&lt;br /&gt;
DMA_RESET_PORT_A_TIMING        equ $c7&lt;br /&gt;
DMA_RESET_PORT_B_TIMING        equ $cb&lt;br /&gt;
DMA_LOAD                       equ $cf ; %11001111&lt;br /&gt;
DMA_CONTINUE                   equ $d3&lt;br /&gt;
DMA_DISABLE_INTERUPTS          equ $af&lt;br /&gt;
DMA_ENABLE_INTERUPTS           equ $ab&lt;br /&gt;
DMA_RESET_DISABLE_INTERUPTS    equ $a3&lt;br /&gt;
DMA_ENABLE_AFTER_RETI          equ $b7&lt;br /&gt;
DMA_READ_STATUS_BYTE           equ $bf&lt;br /&gt;
DMA_REINIT_STATUS_BYTE         equ $8b&lt;br /&gt;
DMA_START_READ_SEQUENCE        equ $a7&lt;br /&gt;
DMA_FORCE_READY                equ $b3&lt;br /&gt;
DMA_DISABLE                    equ $83&lt;br /&gt;
DMA_ENABLE                     equ $87&lt;br /&gt;
DMA_WRITE_REGISTER_COMMAND     equ $bb&lt;br /&gt;
DMA_BURST                      equ %11001101&lt;br /&gt;
DMA_CONTINUOUS                 equ %10101101&lt;br /&gt;
ZXN_DMA_PORT                   equ $6b&lt;br /&gt;
SPRITE_STATUS_SLOT_SELECT      equ $303B&lt;br /&gt;
SPRITE_IMAGE_PORT              equ $5b&lt;br /&gt;
SPRITE_INFO_PORT               equ $57&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
    IFDEF testing&lt;br /&gt;
        org $5800&lt;br /&gt;
        block 32*24, $38              ; default ULA attributes&lt;br /&gt;
        org $6000&lt;br /&gt;
    ELSE&lt;br /&gt;
        org $2000&lt;br /&gt;
    ENDIF&lt;br /&gt;
&lt;br /&gt;
start&lt;br /&gt;
    ld   hl,$0000&lt;br /&gt;
    ld   de,$4000&lt;br /&gt;
    ld   bc,$800&lt;br /&gt;
    call TransferDMA                  ; copy some random data to the screen pointing&lt;br /&gt;
                                      ; to ROM for now, for the purpose of showing &lt;br /&gt;
                                      ; how to do a DMA copy.&lt;br /&gt;
    ld   a,0                          ; sprite image number we want to update&lt;br /&gt;
    ld   bc,SPRITE_STATUS_SLOT_SELECT&lt;br /&gt;
    out  (c),a                        ; set the sprite image number&lt;br /&gt;
    ld   bc,1*256                     ; number to transfer (1)&lt;br /&gt;
    ld   hl,testsprite                ; from &lt;br /&gt;
    call TransferDMASprite            ; transfer to sprite ram&lt;br /&gt;
&lt;br /&gt;
    nextreg 21,1                      ; turn sprite on. for more info on this check &lt;br /&gt;
                                      ; out https://www.specnext.com/tbblue-io-port-system/&lt;br /&gt;
    ld   de,0&lt;br /&gt;
    ld   (xpos),de                    ; set initial X position ( doesn&#039;t need it for&lt;br /&gt;
                                      ; this demo, but if you run the .loop again it&lt;br /&gt;
                                      ; will continue from where it was&lt;br /&gt;
    ld   a,$20&lt;br /&gt;
    ld   (ypos),a                     ; set initial Y position&lt;br /&gt;
&lt;br /&gt;
.loop&lt;br /&gt;
    ld   a,0                          ; sprite number we want to position&lt;br /&gt;
    ld   bc,SPRITE_STATUS_SLOT_SELECT&lt;br /&gt;
    out  (c),a&lt;br /&gt;
    ld   de,(xpos)&lt;br /&gt;
    ld   hl,(ypos)                    ; ignores H so doing this rather than &lt;br /&gt;
                                      ; ld a,(ypos):ld l,a&lt;br /&gt;
    ld   bc,(image)                   ; not flipped or palette shifted&lt;br /&gt;
    call SetSprite&lt;br /&gt;
&lt;br /&gt;
    halt&lt;br /&gt;
&lt;br /&gt;
    ld   de,(xpos)&lt;br /&gt;
    inc  de&lt;br /&gt;
    ld   (xpos),de&lt;br /&gt;
    ld   a,d&lt;br /&gt;
    cp   $01&lt;br /&gt;
    jr   nz,.loop                     ; if high byte of xpos is not 1 (right of &lt;br /&gt;
                                      ; screen )&lt;br /&gt;
    ld   a,e&lt;br /&gt;
    cp   $20+1&lt;br /&gt;
    jr   nz,.loop                     ; if low byte is not $21 just off the right of&lt;br /&gt;
                                      ; the screen, $20 is off screen but as the &lt;br /&gt;
                                      ; INC DE is just above and not updated sprite&lt;br /&gt;
                                      ; after it, it needs to be $21&lt;br /&gt;
    xor  a&lt;br /&gt;
    ret                               ; return back to basic with OK&lt;br /&gt;
&lt;br /&gt;
xpos dw 0                             ; x position&lt;br /&gt;
ypos db 0                             ; y position&lt;br /&gt;
                                      ; these next two BITS and IMAGE are swapped &lt;br /&gt;
                                      ; as bits needs to go into B register&lt;br /&gt;
image db 0+$80                        ; use image 0 (for the image we transfered)&lt;br /&gt;
                                      ; +$80 to set the sprite to active&lt;br /&gt;
bits db 0                             ; not flipped or palette shifted&lt;br /&gt;
&lt;br /&gt;
c1 = %11100000&lt;br /&gt;
c2 = %11000000&lt;br /&gt;
c3 = %10100000&lt;br /&gt;
c4 = %10000000&lt;br /&gt;
c5 = %01100000&lt;br /&gt;
c6 = %01000000&lt;br /&gt;
c7 = %00100000&lt;br /&gt;
c8 = %00000000&lt;br /&gt;
&lt;br /&gt;
testsprite&lt;br /&gt;
    db c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1&lt;br /&gt;
    db c1,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c1&lt;br /&gt;
    db c1,c2,c3,c3,c3,c3,c3,c3,c3,c3,c3,c3,c3,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c4,c4,c4,c4,c4,c4,c4,c4,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c5,c5,c5,c5,c5,c5,c5,c5,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c5,c6,c6,c6,c6,c6,c6,c5,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c5,c6,c7,c7,c7,c7,c6,c5,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c5,c6,c7,c8,c8,c7,c6,c5,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c5,c6,c7,c8,c8,c7,c6,c5,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c5,c6,c7,c7,c7,c7,c6,c5,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c5,c6,c6,c6,c6,c6,c6,c5,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c5,c5,c5,c5,c5,c5,c5,c5,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c4,c4,c4,c4,c4,c4,c4,c4,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c3,c3,c3,c3,c3,c3,c3,c3,c3,c3,c3,c2,c1&lt;br /&gt;
    db c1,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c1&lt;br /&gt;
    db c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1&lt;br /&gt;
&lt;br /&gt;
;-------------------------------------------------&lt;br /&gt;
; de = X&lt;br /&gt;
; l = Y&lt;br /&gt;
; b = bits&lt;br /&gt;
; c = sprite image&lt;br /&gt;
SetSprite&lt;br /&gt;
    push bc&lt;br /&gt;
    ld bc,SPRITE_INFO_PORT&lt;br /&gt;
    out (c),e ; Xpos&lt;br /&gt;
    out (c),l ; Ypos&lt;br /&gt;
    pop hl&lt;br /&gt;
    ld a,d&lt;br /&gt;
    and 1&lt;br /&gt;
    or h&lt;br /&gt;
    out (c),a&lt;br /&gt;
    ld a,l:or $80&lt;br /&gt;
    out (c),a ; image&lt;br /&gt;
    ret&lt;br /&gt;
&lt;br /&gt;
;--------------------------------&lt;br /&gt;
; hl = source&lt;br /&gt;
; de = destination&lt;br /&gt;
; bc = length&lt;br /&gt;
;--------------------------------&lt;br /&gt;
TransferDMA&lt;br /&gt;
    di&lt;br /&gt;
    ld (DMASource),hl&lt;br /&gt;
    ld (DMADest),de&lt;br /&gt;
    ld (DMALength),bc&lt;br /&gt;
    ld hl,DMACode&lt;br /&gt;
    ld b,DMACode_Len&lt;br /&gt;
    ld c,ZXN_DMA_PORT&lt;br /&gt;
    otir&lt;br /&gt;
    ei&lt;br /&gt;
    ret&lt;br /&gt;
&lt;br /&gt;
DMACode db DMA_DISABLE&lt;br /&gt;
        db %01111101                  ; R0-Transfer mode, A -&amp;gt; B, write adress &lt;br /&gt;
                                      ; + block length&lt;br /&gt;
DMASource dw 0                        ; R0-Port A, Start address &lt;br /&gt;
                                      ; (source address)&lt;br /&gt;
DMALength dw 0                        ; R0-Block length (length in bytes)&lt;br /&gt;
        db %01010100                  ; R1-write A time byte, increment, to &lt;br /&gt;
                                      ; memory, bitmask&lt;br /&gt;
        db %00000010                  ; 2t&lt;br /&gt;
        db %01010000                  ; R2-write B time byte, increment, to &lt;br /&gt;
                                      ; memory, bitmask&lt;br /&gt;
        db %00000010                  ; R2-Cycle length port B&lt;br /&gt;
        db DMA_CONTINUOUS             ; R4-Continuous mode (use this for block &lt;br /&gt;
                                      ; transfer), write dest adress&lt;br /&gt;
DMADest dw 0                          ; R4-Dest address (destination address)&lt;br /&gt;
        db %10000010                  ; R5-Restart on end of block, RDY active &lt;br /&gt;
                                      ; LOW&lt;br /&gt;
        db DMA_LOAD                   ; R6-Load&lt;br /&gt;
        db DMA_ENABLE                 ; R6-Enable DMA&lt;br /&gt;
        &lt;br /&gt;
DMACode_Len                    equ $-DMACode&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; hl = source&lt;br /&gt;
; bc = length&lt;br /&gt;
; set port to write to with TBBLUE_REGISTER_SELECT&lt;br /&gt;
; prior to call&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
TransferDMAPort&lt;br /&gt;
    di&lt;br /&gt;
    ld (DMASourceP),hl&lt;br /&gt;
    ld (DMALengthP),bc&lt;br /&gt;
    ld hl,DMACodeP&lt;br /&gt;
    ld b,DMACode_LenP&lt;br /&gt;
    ld c,ZXN_DMA_PORT&lt;br /&gt;
    otir&lt;br /&gt;
    ei&lt;br /&gt;
    ret&lt;br /&gt;
&lt;br /&gt;
DMACodeP db DMA_DISABLE&lt;br /&gt;
        db %01111101                  ; R0-Transfer mode, A -&amp;gt; B, write adress &lt;br /&gt;
                                      ; + block length&lt;br /&gt;
DMASourceP dw 0                       ; R0-Port A, Start address (source address)&lt;br /&gt;
DMALengthP dw 0                       ; R0-Block length (length in bytes)&lt;br /&gt;
        db %01010100                  ; R1-read A time byte, increment, to &lt;br /&gt;
                                      ; memory, bitmask&lt;br /&gt;
        db %00000010                  ; R1-Cycle length port A&lt;br /&gt;
        db %01101000                  ; R2-write B time byte, increment, to &lt;br /&gt;
                                      ; memory, bitmask&lt;br /&gt;
        db %00000010                  ; R2-Cycle length port B&lt;br /&gt;
        db %10101101                  ; R4-Continuous mode (use this for block &lt;br /&gt;
                                      ; transfer), write dest adress&lt;br /&gt;
        dw $253b                      ; R4-Dest address (destination address)&lt;br /&gt;
        db %10000010                  ; R5-Restart on end of block, RDY active&lt;br /&gt;
                                      ; LOW&lt;br /&gt;
        db DMA_LOAD                   ; R6-Load&lt;br /&gt;
        db DMA_ENABLE                 ; R6-Enable DMA&lt;br /&gt;
        &lt;br /&gt;
DMACode_LenP                   equ $-DMACodeP&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; hl = source&lt;br /&gt;
; bc = length&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
TransferDMASprite&lt;br /&gt;
    di&lt;br /&gt;
    ld (DMASourceS),hl&lt;br /&gt;
    ld (DMALengthS),bc&lt;br /&gt;
    ld hl,DMACodeS&lt;br /&gt;
    ld b,DMACode_LenS&lt;br /&gt;
    ld c,ZXN_DMA_PORT&lt;br /&gt;
    otir&lt;br /&gt;
    ei&lt;br /&gt;
    ret&lt;br /&gt;
&lt;br /&gt;
DMACodeS db DMA_DISABLE&lt;br /&gt;
        db %01111101                   ; R0-Transfer mode, A -&amp;gt; B, write adress &lt;br /&gt;
                                       ; + block length&lt;br /&gt;
DMASourceS dw 0                        ; R0-Port A, Start address (source address)&lt;br /&gt;
DMALengthS dw 0                        ; R0-Block length (length in bytes)&lt;br /&gt;
        db %01010100                   ; R1-read A time byte, increment, to &lt;br /&gt;
                                       ; memory, bitmask&lt;br /&gt;
        db %00000010                   ; R1-Cycle length port A&lt;br /&gt;
        db %01101000                   ; R2-write B time byte, increment, to &lt;br /&gt;
                                       ; memory, bitmask&lt;br /&gt;
        db %00000010                   ; R2-Cycle length port B&lt;br /&gt;
        db %10101101                   ; R4-Continuous mode (use this for block&lt;br /&gt;
                                       ; transfer), write dest adress&lt;br /&gt;
        dw SPRITE_IMAGE_PORT           ; R4-Dest address (destination address)&lt;br /&gt;
        db %10000010                   ; R5-Restart on end of block, RDY active&lt;br /&gt;
                                       ; LOW&lt;br /&gt;
        db DMA_LOAD                    ; R6-Load&lt;br /&gt;
        db DMA_ENABLE                  ; R6-Enable DMA&lt;br /&gt;
DMACode_LenS                   equ $-DMACodeS&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; de = dest, a = fill value, bc = lenth&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
DMAFill&lt;br /&gt;
    di&lt;br /&gt;
    ld (FillValue),a&lt;br /&gt;
    ld (DMACDest),de&lt;br /&gt;
    ld (DMACLength),bc&lt;br /&gt;
    ld hl,DMACCode&lt;br /&gt;
    ld b,DMACCode_Len&lt;br /&gt;
    ld c,ZXN_DMA_PORT&lt;br /&gt;
    otir&lt;br /&gt;
    ei&lt;br /&gt;
    ret&lt;br /&gt;
&lt;br /&gt;
FillValue db 22&lt;br /&gt;
DMACCode db DMA_DISABLE&lt;br /&gt;
        db %01111101&lt;br /&gt;
DMACSource dw FillValue&lt;br /&gt;
DMACLength dw 0&lt;br /&gt;
        db %00100100,%00010000,%10101101&lt;br /&gt;
DMACDest dw 0&lt;br /&gt;
        db DMA_LOAD,DMA_ENABLE&lt;br /&gt;
DMACCode_Len equ $-DMACCode&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; End of file&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
    IFDEF testing&lt;br /&gt;
        savenex open &amp;quot;DMAtest.nex&amp;quot;, start, $FF00&lt;br /&gt;
        savenex bank 5&lt;br /&gt;
    ELSE&lt;br /&gt;
fin&lt;br /&gt;
        savebin &amp;quot;DMATEST&amp;quot;,start,fin-start&lt;br /&gt;
    ENDIF&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Based on original text by: Allen Albright &amp;amp; Mike Dailly with input by Jim Bagley, Lyndon J Sharp and Phoebus R. Dokos&lt;br /&gt;
&lt;br /&gt;
== Technical details (core 3.1.3+)  ==&lt;br /&gt;
&lt;br /&gt;
The Zilog/zxnDMA mode is now selected by using the particular I/O port number ({{PortNo|$xx6B}} for zxnDMA mode, {{PortNo|$xx0B}} for Zilog mode). The bit 6 in {{NextRegNo|$06}} is not DMA related any more and will be reused for something different.&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;counter&amp;quot; RR1-RR2 read back after transfer has correct byte order since core 3.1.4.&lt;br /&gt;
&lt;br /&gt;
Other differences described below in &amp;quot;3.0.5&amp;quot; remains (but from practical point of view the Zilog DMA emulation in 3.1.4 is near-perfect, all the remaining differences are very minor).&lt;br /&gt;
&lt;br /&gt;
== Technical details (core 3.0.5)  ==&lt;br /&gt;
&lt;br /&gt;
=== Zilog DMA compatibility mode ===&lt;br /&gt;
In Zilog DMA compatibility mode (bit 6 of {{NextRegNo|$06}}) the zxnDMA will mostly work as expected, but there are few differences in behaviour which may eventually throw off some rare SW, here is the list of the known differences (most of them describe also how the zxnDMA mode works):&lt;br /&gt;
&lt;br /&gt;
The LOAD command must be issued with correct transfer direction, loading addresses in opposite direction and flipping direction afterward will mismatch the source/destination address data (Zilog/UA858D DMA chips are also sensitive to direction flip after LOAD, but the resulting transfer quirks in different way, reading source data byte after write, offsetting whole transfer by one and damaging start/end of sequence).&lt;br /&gt;
(does apply also to zxnDMA mode)&lt;br /&gt;
&lt;br /&gt;
The LOAD command will NOT destroy the already issued &amp;quot;Initialize Read Sequence&amp;quot; - this is how even the original Zilog documentation describes the DMA chip operation, but the real Zilog DMA and UA858D (clone chip) both destroy read sequence upon LOAD command (zxnDMA is better).&lt;br /&gt;
(does apply also to zxnDMA mode)&lt;br /&gt;
&lt;br /&gt;
The content of registers read back after finished transfer differs: the counter has swapped LSB with MSB byte, and both addresses will be adjusted length+1 times (Zilog/UA858D will return destination address adjusted only length-many times).&lt;br /&gt;
(does apply also to zxnDMA mode, except addresses are adjusted only &amp;quot;length&amp;quot; times of course, counter has still swapped bytes)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;del&amp;gt;Any read of zxnDMA port without pending read request (commands &amp;quot;Read Status Byte&amp;quot; or &amp;quot;Initialize Read Sequence&amp;quot;) will return status byte (Zilog will return random value vaguely similar to status byte, but incorrect, UA858D will return zero).&lt;br /&gt;
(does apply also to zxnDMA mode)&amp;lt;/del&amp;gt;&lt;br /&gt;
2026-03-30: any read of zxnDMA port without pending read request will return next byte in read sequence, the default read mask is 0x7F after power on (based on reading the VHDL, needs to verify with HW).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;del&amp;gt;Status byte doesn&#039;t have bit 0 set (the &amp;quot;T&amp;quot; bit in description above).&lt;br /&gt;
(does apply also to zxnDMA mode)&amp;lt;/del&amp;gt;&lt;br /&gt;
2026-03-30: going by [https://gitlab.com/SpectrumNext/ZX%20Spectrum%20Next%20FPGA/-/blob/master/cores/zxnext/src/device/dma.vhd?ref%20type=heads VHDL source] this seems to be now fixed, needs to verify with HW and guess in which version of core this was fixed&lt;br /&gt;
&lt;br /&gt;
The command 0xBB setting read mask will cause implicit 0xA7 Initialize Read Sequence.&lt;br /&gt;
&lt;br /&gt;
Be aware that both custom timing cycles count, and prescalar values are preserved in zxnDMA even when future write to WR1/WR2 does skip these particular bytes. To reset prescalar or cycles timing, write explicitly zero into prescalar register or use commands reset/reset-port-timing.&lt;br /&gt;
(does apply also to zxnDMA mode, the prescalar works only in zxnDMA mode)&lt;br /&gt;
&lt;br /&gt;
The destination port address is LOAD-ed even when it is &amp;quot;fixed&amp;quot; type (Contrary to Zilog DMA, which requires you to load such port as &amp;quot;source&amp;quot;, flip the direction after and re-LOAD again with correct direction. UA858D chip does also load destination port address in any case, just like zxnDMA).&lt;br /&gt;
(does apply also to zxnDMA mode)&lt;br /&gt;
&lt;br /&gt;
=== zxnDMA mode vs Zilog mode ===&lt;br /&gt;
&lt;br /&gt;
In zxnDMA mode length of transfer is equal to the length written to WR0 register, port addresses are adjusted also only length-times.&lt;br /&gt;
&lt;br /&gt;
Prescalar value will affect speed of transfer (use zero to switch prescalar off) (in burst mode during the extra idle time the CPU receives control back and can execute further instructions, in continuous mode the transfer will keep blocking CPU even when &amp;quot;slow&amp;quot; transfer is being done).&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=Assemblers&amp;diff=41860</id>
		<title>Assemblers</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=Assemblers&amp;diff=41860"/>
		<updated>2026-03-16T21:41:57Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: sjasmplus version bump&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Any Z80 assembler can produce code suitable for the Next. However the raw blocks of Z80 code may be not as convenient to use with Next or emulators, so a Next specific tools may be useful for creating one of the supported [[File Formats]].&lt;br /&gt;
&lt;br /&gt;
== Cross-platform tools (running on PC) ==&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[http://www.desdes.com/products/oldfiles/zeus.htm Zeus-ish]&#039;&#039; ===&lt;br /&gt;
: Provides a complete Z80 IDE and Macro assembler, scripted disassember plus an integrated Z80 emulator for a range of machines including partial Next support&lt;br /&gt;
: Supports the Next opcodes directly&lt;br /&gt;
: Supports remote debugging on the Next using ParaSys across a serial link&lt;br /&gt;
: Supports MMU paging in the integrated emulator&lt;br /&gt;
: Supports sprites (core versions prior to 2.00.26) in the integrated emulator&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[http://pasmo.speccy.org/ Pasmo]&#039;&#039; ===&lt;br /&gt;
: A long established Z80 assembler, but has been out of development for a long time&lt;br /&gt;
: Supports all currently known Next extension opcodes through this [https://www.facebook.com/groups/specnext/512169722473686/ modified Pasmo from Russ McNulty and Tony Thompson] and also now supports outputting .sna files to use with CSpect, thanks to Russ McNulty&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;SNasm&#039;&#039; ===&lt;br /&gt;
: Included with the [https://mdf200.itch.io/cspect #CSpect] emulator&lt;br /&gt;
: Full macro assembler&lt;br /&gt;
: Full bank control via Segment management&lt;br /&gt;
: Supports the Next extension opcodes directly&lt;br /&gt;
: Generates full 24bit map files for use in CSpect&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;z80asm&#039;&#039; ===&lt;br /&gt;
: Part of [https://github.com/z88dk/z88dk Z88dk]&#039;&#039;&lt;br /&gt;
: Supports the Next extension opcodes directly, linking assembler with large z80 library, targets any memory configuration&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://github.com/z00m128/sjasmplus z00m&#039;s fork of sjasmplus]&#039;&#039; ===&lt;br /&gt;
: Supports all (core2.00.28) Next extension opcodes, ZXN memory model (8 memory slots with 8ki pages and 1.75MiB virtual device memory), SAVENEX to build NEX files directly from ASM source (NEX version V1.2 (and experimental extension &amp;quot;V1.3&amp;quot;)), MAP files for [https://mdf200.itch.io/cspect #CSpect] emulator, SLD tracing files for [https://github.com/maziac/DeZog DeZog] and [https://github.com/Ckirby101/NDS-NextDevSystem NDS-NextDevSystem] and it is under active development (feedback is welcome).&lt;br /&gt;
: Open source project (&amp;quot;BSD-3-Clause&amp;quot; license), &#039;&#039;&#039;windows executables available at [https://github.com/z00m128/sjasmplus/releases/latest releases]&#039;&#039;&#039;, mac and linux users are expected to simply build from source (both make and CMake are supported).&lt;br /&gt;
: [http://z00m128.github.io/sjasmplus/documentation.html Documentation], latest stable release v1.22.0 2026-03-15&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;zmac&#039;&#039; ===&lt;br /&gt;
&lt;br /&gt;
: [http://48k.ca/zmac.html zmac - Z-80 Macro Cross Assembler]&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://github.com/CatpainBlack/FantASM FantASM]&#039;&#039; ===&lt;br /&gt;
: FantASM is a two pass non optimising assembler for the Z80 processor by [https://github.com/CatpainBlack Guy &#039;CatpainBlack&#039; Black].&lt;br /&gt;
&lt;br /&gt;
:It supports all undocumented op-codes and the extended instruction set of the ZX Next and additional pseudo opcodes used by the CSpect emulator to control debugging.&lt;br /&gt;
&lt;br /&gt;
== Native tools (running on Next) ==&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://gitlab.com/next-tools/odin Odin]&#039;&#039; ===&lt;br /&gt;
&lt;br /&gt;
Work-in-progress Next-specific assembler written by Matt Davies, used also in video tutorials presented by Jim Bagley, the best way to acquire the binary is to join the official ZX Next discord server and check channel &amp;lt;code&amp;gt;#odin&amp;lt;/code&amp;gt; - pinned messages, where you can also discuss any issues and get how-to hints.&lt;br /&gt;
&lt;br /&gt;
: supports most of the undocumented opcodes, all official Z80 and Next-extended instructions&lt;br /&gt;
: supports nested includes and binary includes&lt;br /&gt;
: source is stored in tokenised form (smaller file), up to 48kiB of source in single file&lt;br /&gt;
: assembling can produce 32kiB of machine code (enough to produce simpler dot command)&lt;br /&gt;
: includes also editor and console modules (debugger is planned)&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://www.solarisite.com/spectrumnext.html Sol]&#039;&#039; ===&lt;br /&gt;
&lt;br /&gt;
Sol is an assembler and editor written by Solaris, that runs natively on the Next. Manual, assembler binary and assembler source can be downloaded [https://www.solarisite.com/spectrumnext.html here].&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://gitlab.com/thesmog358/tbblue/-/tree/master/tools/dev/Zeus ZEUS]&#039;&#039; ===&lt;br /&gt;
&lt;br /&gt;
Classic ZEUS native assembler by Simon Brattel, extended and included directly in the ZX Next distro.&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://gitlab.com/thesmog358/tbblue/-/tree/master/tools/dev/SPED SPED]&#039;&#039; ===&lt;br /&gt;
&lt;br /&gt;
Classic SPED assembler by César Hernández Bañó, included directly in the ZX Next distro, see [https://gitlab.com/thesmog358/tbblue/-/raw/master/docs/apps/dev/SPED53readme.txt README].&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://taylorza.itch.io/nextbasic-inline-assembler NextBASIC Inline Assembler]&#039;&#039;===&lt;br /&gt;
Enables you to write inline assembly code in your NextBASIC application. The assembler can be downloaded from [https://taylorza.itch.io/nextbasic-inline-assembler HERE] with documentation available [https://github.com/taylorza/zxn-inlineasm-doc/blob/main/README.md HERE]&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=Audio_/_Music&amp;diff=41784</id>
		<title>Audio / Music</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=Audio_/_Music&amp;diff=41784"/>
		<updated>2026-01-23T00:41:12Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: Adding link to Jamie&amp;#039;s tutorial&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Music trackers, players and related tools =&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
! Tool !! Description !! Platform / Notes !! Links&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;[https://www.julien-nevo.com/arkostracker/ Arkos Tracker 3]&#039;&#039;&#039; &lt;br /&gt;
| Cross-platform modern chiptune/sampled music tracker with support for 9-channel AY tracking and various player routines (also for the Next).&lt;br /&gt;
| Win / Linux / Mac || &lt;br /&gt;
[https://www.julien-nevo.com/arkostracker/index.php/player-availability/ Player Routines]&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;[https://zx.remysharp.com/audio AYFX Editor and Driver]&#039;&#039;&#039; &lt;br /&gt;
| Web-based AY sound effect editor based on [https://shiru.untergrund.net/files/ayfxedit.zip Shiru&#039;s AYFX Editor (Windows only)]. Works fully offline, export effects for use in NextBASIC via AYFX driver.&lt;br /&gt;
| Web || &lt;br /&gt;
[https://zx.remysharp.com/audio Link] &lt;br /&gt;
[https://github.com/Threetwosevensixseven/ayfxedit-improved Assembly routines]&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;[https://nextdaw.biasillo.com/ NextDAW]&#039;&#039;&#039; &lt;br /&gt;
| Modern DAW-style interface for the ZX Spectrum Next supporting 3 AY chips (9 channels), piano roll, arranger, and realtime recording. &lt;br /&gt;
| ZX Spectrum Next (mouse required) || &lt;br /&gt;
[https://nextdaw.biasillo.com/ Link]&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;[https://volutar.myds.me/vortextracker/ Vortex Tracker]&#039;&#039;&#039; &lt;br /&gt;
| Multi-AY capable tracker for Windows. Can export in ProTracker format for Next playback. Supports 1, 2 or 3 AYs&lt;br /&gt;
| Windows || &lt;br /&gt;
[https://github.com/Volutar/vortextracker/tree/TS3/ GitHub]&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;[https://www.pouet.net/prod.php?which=105234 AYT Sound Format]&#039;&#039;&#039; &lt;br /&gt;
| AYT (AY Turbo) is a format for Sound Player for AY 8910/8912 and YM2149 chipsets.&amp;lt;br&amp;gt;AYT files are produced from YM files (dump of AY registry values), but are substantially smaller, players are very fast and have constant time of execution.&lt;br /&gt;
| Z80A players&amp;lt;br&amp;gt;PC/web tools || &lt;br /&gt;
[https://github.com/Logon-System Format definition and tools]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://amstrad.neocities.org/menuayt Web tools]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://blog.logonsystem.eu/welcome-to-ayters-eng/ More info]&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;[https://github.com/mikedailly/mod_player/ MOD Player]&#039;&#039;&#039; &lt;br /&gt;
| 4-channel MOD player for ZX Spectrum Next (Z80) by Mike Dailly. Compose with any Amiga tracker. Limited effect support (No CIA, only effects 1xx,2xx,Axx,Cxx,Dxx &amp;amp; Fxx). Updates once per interrupt filling a buffer that is played back via the DMA so could be used in game.&lt;br /&gt;
| ZX Spectrum Next || &lt;br /&gt;
[https://github.com/mikedailly/mod_player/ GitHub]&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;[https://github.com/em00k/NXModPlayer NXModPlayer]&#039;&#039;&#039; &lt;br /&gt;
| 4-channel MOD player for ZX Spectrum Next (Z80) by njoi. Mod engine by 9bitcolor, interface by em00k. Full MOD support, all effects CIA timings. 4 Channel Stereo. Takes more processing time but results match that of the Amiga. Included on the official distro&lt;br /&gt;
| ZX Spectrum Next || &lt;br /&gt;
[https://github.com/em00k/NXMod-src GitHub engine source]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Resources, tutorials and other links =&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
! Related tool !! Type of resource !! Resource itself and description&lt;br /&gt;
|-&lt;br /&gt;
| Vortex Tracker || Youtube video || &#039;&#039;&#039;[https://www.youtube.com/watch?v=L4KV1V3Hul0 How I Make Spectrum Next Video Game Music With Vortex Tracker]&#039;&#039;&#039; by Jamie Mallender&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=Development_Tools:Linux_setup&amp;diff=41783</id>
		<title>Development Tools:Linux setup</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=Development_Tools:Linux_setup&amp;diff=41783"/>
		<updated>2026-01-21T21:48:36Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: Adding MAME source retrieval and compilation notes&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== General ==&lt;br /&gt;
&lt;br /&gt;
This page collects summaries of installation process of various tools related to ZX Spectrum Next software development for linux OS users.&lt;br /&gt;
&lt;br /&gt;
As usual with linux, most of the suggestions are in the form of command line command to be used from terminal.&lt;br /&gt;
&lt;br /&gt;
== sjasmplus assembler ==&lt;br /&gt;
&lt;br /&gt;
You can also check the [https://www.youtube.com/watch?v=c6I4kdErEwE video] of installing sjasmplus on freshly reinstalled KDE neon 5.20 linux, where is also extended info how to run the automated tests of sjasmplus, and opening it in KDevelop IDE to eventually write your own modifications.&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
On Debian based systems make sure you have these packages installed (git-cola and cmake are optional, but often handy):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install git build-essential g++ git-cola cmake&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Retrieving the sjasmplus source ===&lt;br /&gt;
&lt;br /&gt;
Use git to clone the [https://github.com/z00m128/sjasmplus z00m&#039;s sjasmplus repository]:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;git clone --recursive -j8 https://github.com/z00m128/sjasmplus.git&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To update already cloned repository, do inside the sjasmplus folder:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;git pull&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
- or use your favourite GIT client app to update the cloned repository.&lt;br /&gt;
&lt;br /&gt;
=== Building the executable binary ===&lt;br /&gt;
&lt;br /&gt;
The GNU make and common C++ compiler (gcc or clang) should be enough to build the binary:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;make clean &amp;amp;&amp;amp; make&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To verify the binary was built (&amp;quot;dot slash&amp;quot; prefix to force running of binary in current folder, not system one):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;./sjasmplus --version&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Installing the executable ===&lt;br /&gt;
&lt;br /&gt;
If you already have sjasmplus installed, use &amp;lt;code&amp;gt;which sjasmplus&amp;lt;/code&amp;gt; to see where the installed executable is (and which installed executable has precedence), you can use this command also after installing the new executable to verify it is being picked up by the system.&lt;br /&gt;
&lt;br /&gt;
Installing the binary in system-wide fashion:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo make install&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or you can install the binary only locally for your user (without root/sudo permissions):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;mkdir -p ~/.local/bin&lt;br /&gt;
make PREFIX=~/.local install&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
- then make sure you have &amp;lt;code&amp;gt;~/.local/bin&amp;lt;/code&amp;gt; in your user &amp;lt;code&amp;gt;PATH&amp;lt;/code&amp;gt; environment variable (on some distros there is already script in .profile to add this to PATH if the dir does exist, so you may need to only logout/restart after creating it to get it active).&lt;br /&gt;
&lt;br /&gt;
=== Checking if it all works ===&lt;br /&gt;
&lt;br /&gt;
Open your terminal and type (in any directory):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sjasmplus --version&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see version of the freshly built sjasmplus executable like this:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;SjASMPlus Z80 Cross-Assembler v1.17.0 (https://github.com/z00m128/sjasmplus)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== hdfmonkey tool ==&lt;br /&gt;
&lt;br /&gt;
The hdfmonkey tool can manipulate card-images, helping to write new builds of your project into NextZXOS card-image, to boot the emulators with full file system. (it&#039;s also possible to mount the images directly into linux by other means, to operate on them with regular file manager/etc, but hdfmonkey suits better use-case when the build script does update the image)&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
On Debian based systems make sure you have these packages installed:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install git build-essential g++ autoconf&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Retrieving the hdfmonkey source ===&lt;br /&gt;
&lt;br /&gt;
Use git to clone the [https://github.com/ped7g/hdfmonkey hdfmonkey repository with patched 0.5.7 &amp;lt;code&amp;gt;jjjs version&amp;lt;/code&amp;gt; sources]:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;git clone https://github.com/ped7g/hdfmonkey.git&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
(make sure you are on the default branch &amp;lt;code&amp;gt;&amp;quot;jjjs-variant&amp;quot;&amp;lt;/code&amp;gt; to build the improved version, it should be checked out by default after clone)&lt;br /&gt;
&lt;br /&gt;
* to update already cloned repository, do inside the hdfmonkey folder:&lt;br /&gt;
  &amp;lt;nowiki&amp;gt;git pull&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
* or use your favourite GIT client app to update the cloned repository.&lt;br /&gt;
* if you cloned original gasman&#039;s repository before, you may want to clone and rebuild here mentioned &amp;lt;code&amp;gt;jjjs version&amp;lt;/code&amp;gt; to get multiple fixes and convenience features.&lt;br /&gt;
&lt;br /&gt;
=== Building the executable binary ===&lt;br /&gt;
&lt;br /&gt;
The hdfmonkey is using autoconf/autotools to build final Makefile, check the hdfmonkey README for &amp;quot;from git&amp;quot; installation notes, at the moment of writing this page, the steps were:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;cd hdfmonkey&lt;br /&gt;
autoheader&lt;br /&gt;
aclocal&lt;br /&gt;
autoconf&lt;br /&gt;
automake -a&lt;br /&gt;
./configure&lt;br /&gt;
make&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To verify the binary was built:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;src/hdfmonkey help&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Installing the executable ===&lt;br /&gt;
&lt;br /&gt;
If you already have hdfmonkey installed, use &amp;lt;code&amp;gt;which hdfmonkey&amp;lt;/code&amp;gt; to see where the installed executable is (and which installed executable has precedence), you can use this command also after installing the new executable to verify it is being picked up by the system.&lt;br /&gt;
&lt;br /&gt;
Installing the binary in system-wide fashion:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo make install&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or you can install the binary only locally for your user (without root/sudo permissions):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;make prefix=~/.local install&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
- then make sure you have &amp;lt;code&amp;gt;~/.local/bin&amp;lt;/code&amp;gt; in your user &amp;lt;code&amp;gt;PATH&amp;lt;/code&amp;gt; environment variable.&lt;br /&gt;
&lt;br /&gt;
=== Checking if it all works ===&lt;br /&gt;
&lt;br /&gt;
Open your terminal and type (in any directory):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;hdfmonkey help&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see help of the freshly built hdfmonkey `jjjs version` executable like this:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;hdfmonkey: utility for manipulating HDF disk images v0.5.7 jjjs&lt;br /&gt;
&lt;br /&gt;
usage: hdfmonkey &amp;lt;command&amp;gt; [args]&lt;br /&gt;
...&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Extracting all files from the sd-card image ==&lt;br /&gt;
&lt;br /&gt;
7-zip is the most convenient tool to extract the the files from the existing image.&lt;br /&gt;
&lt;br /&gt;
To install 7-zip on a Debian system use &amp;lt;code&amp;gt;sudo apt install 7zip&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To extract all the files from an existing image &amp;lt;code&amp;gt;tbblue.img&amp;lt;/code&amp;gt; to a new subdirectory &amp;lt;code&amp;gt;myfiles&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;7z x tbblue.img -omyfiles&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Creating new sd-card image with hdfmonkey ==&lt;br /&gt;
&lt;br /&gt;
This example: &lt;br /&gt;
&lt;br /&gt;
* downloads the archive from the specnext.com&lt;br /&gt;
* unpacks it to the subdirectory &amp;lt;code&amp;gt;tmptb&amp;lt;/code&amp;gt;&lt;br /&gt;
* creates a new SD image (with the space for 2GB files) from all the files&lt;br /&gt;
* deletes the subdirectory &amp;lt;code&amp;gt;tmptb&amp;lt;/code&amp;gt;&lt;br /&gt;
* shows that the new image uses much less than 2GB&lt;br /&gt;
* starts listing the content of the newly created image&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
wget https://www.specnext.com/distro/24.11/sn-complete-24.11.zip&lt;br /&gt;
7z x sn-complete-24.11.zip -otmptb&lt;br /&gt;
hdfmonkey create tbblue.img 2GB&lt;br /&gt;
hdfmonkey putdir tbblue.img tmptb /  &lt;br /&gt;
rm -rf tmptb&lt;br /&gt;
du -h tbblue.img&lt;br /&gt;
7z l tbblue.img | more&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating new sd-card image without hdfmonkey ===&lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to use gnu coreutils and dosfstools to create card image without hdfmonkey, but depending on exact size of image these may be less compatible with various emulator, following example for 1GB card image works in MAME but fails in CSpect (while images created by hdfmonkey tool should work for both emulator, so using &#039;&#039;&#039;hdfmonkey is recommended&#039;&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
truncate -s 1G NextZXOS.img&lt;br /&gt;
parted NextZXOS.img mklabel msdos&lt;br /&gt;
parted NextZXOS.img mkpart primary fat32 2048s 100%&lt;br /&gt;
mkfs.fat -F 32 --offset=2048 NextZXOS.img&lt;br /&gt;
# and now to copy files to image you have to either mount it or use hdfmonkey:&lt;br /&gt;
# hdfmonkey putdir NextZXOS.img tmptb /&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mounting sd-card image directly ==&lt;br /&gt;
&lt;br /&gt;
Sometimes it may be useful to mount the card image directly, to be able to browse it and manipulate with common tools. But make sure you are not using mounted card image also in emulator at the same time, to prevent any data damage by parallel access.&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
On Debian based systems make sure you have these packages installed:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install fdisk mount&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Prepare empty directory to mount the card image into (let&#039;s call it &amp;quot;next-card&amp;quot;) and have the image file around (&amp;quot;tbblue.mmc&amp;quot; in following examples)&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;mkdir -p next-card&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Mounting the card image ===&lt;br /&gt;
&lt;br /&gt;
To mount the card image you need to know the exact byte-offset where the FAT partition starts, it&#039;s possible to read it from &amp;quot;fdisk&amp;quot; or &amp;quot;parted&amp;quot; tools outputs:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;fdisk -l -o Start tbblue.mmc&lt;br /&gt;
# prints value in sector units, like:&lt;br /&gt;
# Start&lt;br /&gt;
#    63&lt;br /&gt;
# This has to be multiplied by 512 to get byte offset: 63*512 = 32256&lt;br /&gt;
&lt;br /&gt;
# or&lt;br /&gt;
&lt;br /&gt;
parted tbblue.mmc unit B print&lt;br /&gt;
# prints values in bytes with &amp;quot;B&amp;quot; suffix in &amp;quot;Start&amp;quot; column&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
But the fdisk output can be incorporated directly into mount command, which needs root permissions, example with sudo:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo mount tbblue.mmc next-card/ -o loop,offset=$((`fdisk -l -o Start tbblue.mmc | tail -1` * 512)),user,uid=`id -u`,gid=`id -g`&lt;br /&gt;
&lt;br /&gt;
# or you can enter the offset yourself&lt;br /&gt;
&lt;br /&gt;
sudo mount tbblue.mmc next-card/ -o loop,offset=32256,user,uid=`id -u`,gid=`id -g`&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The uid and gid options will mount the filesystem under your regular user, so you can now browse it with file manager, text editors, etc.&lt;br /&gt;
&lt;br /&gt;
Do not run the emulator yet, before unmounting the image (after you are done manipulating the files)!&lt;br /&gt;
&lt;br /&gt;
=== Unmount the image before using it in emulator ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo umount next-card/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Check the result. If the unmounting fails (probably with &amp;quot;target is busy&amp;quot;), find which process is still accessing/viewing the files in the next-card directory, and try to unmount it again.&lt;br /&gt;
&lt;br /&gt;
== Mounting sd-card image with losetup ==&lt;br /&gt;
&lt;br /&gt;
Alternative using losetup to use local &amp;quot;loop&amp;quot; device for mounting the image. This method can automatically detect partitions inside the image and exposes them as loop devices.&lt;br /&gt;
&lt;br /&gt;
Prepare mounting dir and make sure you have &amp;lt;code&amp;gt;mount&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;losetup&amp;lt;/code&amp;gt; available, Ubuntu based systems packages:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install util-linux mount&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Use losetup to attach image and scan its partitions ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo losetup --partscan --show --find NextZXOS.img&lt;br /&gt;
# this will print new loop device and automatically create partition devices like /dev/loop0p1&lt;br /&gt;
# now mount the desired FAT32 partition:&lt;br /&gt;
sudo mount /dev/loop0p1 next-card/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Unmounting and cleanup of loop device ===&lt;br /&gt;
&lt;br /&gt;
When finished:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo umount next-card/&lt;br /&gt;
sudo losetup -d /dev/loop0&lt;br /&gt;
# or `sudo losetup -D` to detach *ALL* loop devices&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This detaches the loop device and frees all associated /dev/loop* entries.&lt;br /&gt;
&lt;br /&gt;
Notes and gotchas:&lt;br /&gt;
* Do not use the image in an emulator while it is mounted.&lt;br /&gt;
* If the image has no partition table, --partscan will not create /dev/loop0p1.&lt;br /&gt;
* If multiple loop devices are active, check &amp;lt;code&amp;gt;losetup -a&amp;lt;/code&amp;gt; to confirm which one is yours.&lt;br /&gt;
&lt;br /&gt;
== Mounting sd‑card image with udisksctl ==&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;udisksctl&amp;lt;/code&amp;gt; tool provides a desktop‑friendly way to attach loop devices and mount filesystems without manually calculating offsets or using &amp;lt;code&amp;gt;losetup&amp;lt;/code&amp;gt;. It integrates with system services such as UDisks2, and on many desktop Linux systems it allows non‑root users (who are in the correct group) to mount images safely.&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
On Debian‑based systems install the UDisks2 tools:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install udisks2&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To run &amp;lt;code&amp;gt;udisksctl&amp;lt;/code&amp;gt; without &amp;lt;code&amp;gt;sudo&amp;lt;/code&amp;gt;, your user must belong to the &#039;&#039;&#039;disk&#039;&#039;&#039;, &#039;&#039;&#039;storage&#039;&#039;&#039;, or &#039;&#039;&#039;udisks&#039;&#039;&#039; policy group (varies by distribution). If unsure, simply use &amp;lt;code&amp;gt;sudo&amp;lt;/code&amp;gt; in the examples below.&lt;br /&gt;
&lt;br /&gt;
=== Attaching the image as a loop device ===&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;code&amp;gt;udisksctl loop-setup&amp;lt;/code&amp;gt; to create a loop device for the image:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;udisksctl loop-setup --file NextZXOS.img&lt;br /&gt;
# prints something like:&lt;br /&gt;
# Mapped file NextZXOS.img as /dev/loop2.&lt;br /&gt;
# UDisks automatically scans the partition table and exposes partitions as:&lt;br /&gt;
# /dev/loop2p1&lt;br /&gt;
# /dev/loop2p2&lt;br /&gt;
# ...&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Mounting the FAT32 partition ===&lt;br /&gt;
&lt;br /&gt;
Mount the desired partition:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;udisksctl mount --block-device /dev/loop2p1&lt;br /&gt;
# This prints the mount point, for example:&lt;br /&gt;
# Mounted /dev/loop2p1 at /media/youruser/NextZXOS.&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can now browse and edit the filesystem normally using your file manager or command‑line tools.&lt;br /&gt;
&lt;br /&gt;
=== Unmounting and cleanup ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;udisksctl unmount --block-device /dev/loop2p1&lt;br /&gt;
udisksctl loop-delete --block-device /dev/loop2&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This cleanly detaches the loop device and removes all &amp;lt;code&amp;gt;/dev/loop*&amp;lt;/code&amp;gt; entries created for the image.&lt;br /&gt;
&lt;br /&gt;
=== Notes and gotchas ===&lt;br /&gt;
&lt;br /&gt;
* Do not use the image in an emulator while it is mounted, parallel access may corrupt data.&lt;br /&gt;
* If the image has no partition table, UDisks will not create &#039;&#039;&#039;/dev/loopXp1&#039;&#039;&#039; and you must mount manually using an offset.&lt;br /&gt;
* Mount points are created under &amp;lt;code&amp;gt;/media/$USER/&amp;lt;/code&amp;gt; unless overridden by system policy.&lt;br /&gt;
* UDisks may auto‑mount partitions immediately after &#039;&#039;&#039;loop‑setup&#039;&#039;&#039; depending on desktop environment settings.&lt;br /&gt;
&lt;br /&gt;
== MAME emulator ==&lt;br /&gt;
&lt;br /&gt;
MAME got Next emulation and it got improved a lot around end of 2025, turning it into probably most accurate and performant Next emulator currently available. But as that shift is quite recent, the developers community haven’t transitioned to it yet in large numbers and the tutorials and examples are non-existent. This section provides a basic Linux setup guide.&lt;br /&gt;
&lt;br /&gt;
This chapter focuses only on installing MAME from source code git repository, so you can update to latest work in progress or even contribute to the development yourself. The stable binary releases already contain decent Next emulation, but bug fixes and improvements are still coming often and stable releases trail a few weeks behind.&lt;br /&gt;
&lt;br /&gt;
At the moment, the primary developer working on Next emulation in MAME is Andrei Holub, so his fork repo will be used as default source.&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
You need C++17 compiler (GCC 10.3+ or clang 11+), GNU make and few more development tools and common libraries, for specific list for your distro and up to date information check [https://docs.mamedev.org/initialsetup/compilingmame.html Compiling MAME] web page from official docs.&lt;br /&gt;
&lt;br /&gt;
Keep this page around as the example here is quick hint and not meant as replacement for full documentation.&lt;br /&gt;
&lt;br /&gt;
=== Retrieving the MAME source ===&lt;br /&gt;
&lt;br /&gt;
Use git to clone the [https://github.com/holub/mame holub&#039;s MAME repository] and add the [https://github.com/mamedev/mame official MAME repository] as an additional remote:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;git clone --origin holubdev https://github.com/holub/mame.git&lt;br /&gt;
cd mame&lt;br /&gt;
git remote add -f --tags mamedev https://github.com/mamedev/mame.git&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To update already cloned repository checked out at master branch, do inside the mame folder (WARNING: this will drop any local changes in the repository, as MAME devs often rewrite already published commits and you need to reset your local clone to latest state - if you are developer working on MAME sources, you should know yourself how to work with git to preserve your changes and rebase/merge):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;git fetch --all --force&lt;br /&gt;
git reset --hard master&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
Or use your favourite GIT client app to update the cloned repository.&lt;br /&gt;
&lt;br /&gt;
=== Building the executable binary ===&lt;br /&gt;
&lt;br /&gt;
To &#039;&#039;&#039;rebuild&#039;&#039;&#039; &#039;&#039;&#039;only&#039;&#039;&#039; Next emulation (&#039;&#039;&amp;quot;tbblue&amp;quot;&#039;&#039; machine) and get executable named &amp;lt;code&amp;gt;tbblue&amp;lt;/code&amp;gt;, run &amp;lt;code&amp;gt;make&amp;lt;/code&amp;gt; like this:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# make sure there are no remnants from previous builds&lt;br /&gt;
make clean&lt;br /&gt;
# If you want to, you can change to TOOLS=1 to build also &amp;quot;various additional tools, such as chdman&amp;quot;&lt;br /&gt;
# The name of resulting binary is affected by SUBTARGET=tbblue, leave it out if you want &amp;quot;mame&amp;quot;&lt;br /&gt;
make REGENIE=1 EMULATOR=1 TOOLS=0 SOURCES=sinclair/specnext.cpp SUBTARGET=tbblue -j $(nproc)&lt;br /&gt;
# check the build output to confirm that compilation succeeded. To list binary:&lt;br /&gt;
ls -lh tbblue&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This may take a considerable amount of time depending on how powerful your PC is.&lt;br /&gt;
&lt;br /&gt;
If you are developing MAME yourself, you can do incremental build (after REGENIE=1 was used to &amp;quot;generate project files&amp;quot; in previous build and your source code changes don&#039;t require full rebuild) - this will be lot faster of course as usual:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;make SUBTARGET=tbblue -j $(nproc)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To rebuild full MAME including all other emulation targets (computers and arcade machines) - which will take even much longer - use:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;make clean &amp;amp;&amp;amp; make REGENIE=1 EMULATOR=1 TOOLS=0 -j $(nproc)&lt;br /&gt;
# check existence of new binary (the line above will produce default name &amp;quot;mame&amp;quot;)&lt;br /&gt;
ls -lh mame&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Installing the executable and configuration ===&lt;br /&gt;
&lt;br /&gt;
TODO&lt;br /&gt;
&lt;br /&gt;
=== Checking if it all works ===&lt;br /&gt;
&lt;br /&gt;
TODO&lt;br /&gt;
&lt;br /&gt;
== #CSpect emulator ==&lt;br /&gt;
&lt;br /&gt;
The #CSpect is Mike Dailly&#039;s ZX Spectrum Next emulator, written in C# making it cross-platform (sort of, where the mono framework is available). It is non-free (closed-source, custom license) project, but available for usage without any payment (it&#039;s possible to use it internally to develop also commercial titles, but you can not distribute/sell the emulator itself, not even packaged with your game - for such agreement contact the author first and get his permission).&lt;br /&gt;
&lt;br /&gt;
Currently it is most performant and user friendly emulator of ZX Spectrum Next, with good emulation accuracy (see [https://wiki.specnext.dev/CSpect:known_bugs CSpect:known_bugs] page for more detailed report).&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
On Debian based systems make sure you have these packages installed:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install mono-complete libopenal1 libsdl2-dev&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Retrieving the #CSpect package ===&lt;br /&gt;
&lt;br /&gt;
Use web browser to visit itch.io dedicated to CSpect project [https://mdf200.itch.io/cspect mdf200.itch.io/cspect] and download latest release.&lt;br /&gt;
&lt;br /&gt;
You may get warnings from your browser or antivirus about the page itself and about the zip/binary files. The #CSpect has long record of triggering false positives of AV engines due to the executable being not digitally signed and because of the code using features of OS which are normal for emulator, but may look wonky for AV heuristic. Whether you trust the executable is virus free is up to you, in the end.&lt;br /&gt;
&lt;br /&gt;
=== Installing the executable ===&lt;br /&gt;
&lt;br /&gt;
Unzip the retrieved zip file (I personally use KDE Dolphin file manager, the file context menu &#039;&#039;&amp;quot;Extract -&amp;gt; Extract archive here, autodetect subfolder&amp;quot;&#039;&#039;), and place the unzipped directory to target destination (&amp;lt;code&amp;gt;~/zx/emulators/CSpect/CSpect2_13_0&amp;lt;/code&amp;gt; in my case). I prefer to keep every version in its own directory, and have general symbolic link pointing to the one I want use by default:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;cd ~/zx/emulators/CSpect&lt;br /&gt;
ln -s CSpect2_13_0 CSpect_current&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then I create launcher bash-scripts in my &amp;lt;code&amp;gt;~/.local/bin&amp;lt;/code&amp;gt; like this (name of script &amp;lt;code&amp;gt;runCSpect&amp;lt;/code&amp;gt;):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;#!/bin/bash&lt;br /&gt;
# personal script of Ped to launch &amp;quot;#CSpect&amp;quot; emulator in &amp;quot;current directory&amp;quot; (with arguments like: &amp;quot;runCSpect file.nex&amp;quot;)&lt;br /&gt;
MONO_IOMAP=all mono ~/zx/emulators/CSpect/CSpect_current/CSpect.exe -tv -zxnext -s28 -w4 -mmc=./ &amp;quot;$@&amp;quot;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notes: I don&#039;t know any more what &amp;lt;code&amp;gt;MONO_IOMAP=all&amp;lt;/code&amp;gt; helps with, I believe it was suggested to help with any filesystem windows-like paths containing backslashes, you can try to do your own research. The &amp;lt;code&amp;gt;-tv&amp;lt;/code&amp;gt; switch will switch off &amp;quot;scanlines&amp;quot; shader effect and generally switch off any GPU shaders, which makes CSpect more compatible with graphics drivers (try it, if you get only black screen or instant crash during init). The &amp;lt;code&amp;gt;-w4&amp;lt;/code&amp;gt; will make the window quite large - 4x scale, the &amp;lt;code&amp;gt;-zxnext -s28&amp;lt;/code&amp;gt; switch #CSpect into ZX Next emulation mode and set 28Mhz speed of OS as default. And finally the &amp;lt;code&amp;gt;-mmc=./ &amp;quot;$@&amp;quot;&amp;lt;/code&amp;gt; will set &#039;&#039;current directory&#039;&#039; for esxdos emulation to the directory where you use the script to launch the emulator, and pass any remaining command line options entered by user, like the name of the SNA/NEX file. Other noteworthy options are &amp;lt;code&amp;gt;-debug -brk -map=file.map&amp;lt;/code&amp;gt;, the -debug entering the debugger just ahead of the first instruction, -brk enables CSpect specific two-byte tag 0xDD 0x01 to work as breakpoint and the -map option allows you to load into debugger the symbol table from your assembler (directive CSPECTMAP in sjasmplus), making labels visible in disassembly.&lt;br /&gt;
&lt;br /&gt;
=== Checking if it all works ===&lt;br /&gt;
&lt;br /&gt;
Go to some directory with SNA/SNX/NEX file (there are also some demo files right in the CSpect directory) and use the launcher script, like:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;runCSpect beast.nex&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see #CSpect emulator window running the beast.nex demo (or whatever else you did want to launch and entered as argument).&lt;br /&gt;
&lt;br /&gt;
[[File:Cspect_test_run.png|frameless|Running CSpect from directory with test snapshots]]&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=MAME:Installing&amp;diff=41782</id>
		<title>MAME:Installing</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=MAME:Installing&amp;diff=41782"/>
		<updated>2026-01-21T16:55:33Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: Moving Linux related mounting details to dev tools page, making this article simpler and less technical (especially for Win/Mac users)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[https://www.mamedev.org/ MAME] (formerly an acronym of Multiple Arcade Machine Emulator) is a free and open-source emulator designed to emulate the hardware of arcade games, later expanded to include video game consoles, old computers and other systems in software on modern personal computers and other platforms.&lt;br /&gt;
&lt;br /&gt;
MAME has supported the ZX Spectrum Next since version 0.267. The existing implementation is based on the v3.02.01 core and implements most of the features.&lt;br /&gt;
&lt;br /&gt;
= Installation =&lt;br /&gt;
&lt;br /&gt;
You will need to install MAME, provide it with the Next firmware (&#039;ROM&#039;), and get the NextZXOS image:&lt;br /&gt;
&lt;br /&gt;
=== 1. Get MAME ===&lt;br /&gt;
Start with these official MAME releases. If you encounter crashes or other bugs, try replacing the MAME executable with holub&#039;s latest Continuous Integration (CI) builds as described at the end of this article.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Windows:&#039;&#039;&#039; Download [https://www.mamedev.org/release.html MAME for Windows].&lt;br /&gt;
* &#039;&#039;&#039;macOS:&#039;&#039;&#039; Download [https://sdlmame.lngn.net/ MAME for macOS].&lt;br /&gt;
* &#039;&#039;&#039;Linux:&#039;&#039;&#039; Install MAME from the flatpak repositories by running:&lt;br /&gt;
&amp;lt;pre&amp;gt;sudo flatpak install org.mamedev.MAME&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that Windows and macOS will likely prevent you from launching MAME directly for security reasons. See below on how to solve this.&lt;br /&gt;
&lt;br /&gt;
Alternatively, for the MAME platform as a whole, you can also check your package manager, or [https://docs.mamedev.org/initialsetup/compilingmame.html build from sources].&lt;br /&gt;
&lt;br /&gt;
Git of official MAME: [https://github.com/mamedev/mame/ https://github.com/mamedev/mame/] [https://github.com/mamedev/mame/blob/master/src/mame/sinclair/specnext.cpp specnext.cpp]&lt;br /&gt;
&lt;br /&gt;
Git of holub&#039;s fork: [https://github.com/holub/mame https://github.com/holub/mame] [https://github.com/holub/mame/blob/master/src/mame/sinclair/specnext.cpp specnext.cpp] (may contain extra fixes and features before they are merged to official repository)&lt;br /&gt;
&lt;br /&gt;
=== 2. Get TBBLUE (the Next &#039;boot ROM&#039;) ===&lt;br /&gt;
Put the file  [https://github.com/Threetwosevensixseven/NexCreator/raw/master/bootroms/tbblue.zip tbblue.zip] into MAME&#039;s &amp;lt;code&amp;gt;roms&amp;lt;/code&amp;gt; folder. Don&#039;t extract it; MAME will look for the zip file when the &amp;quot;tbblue&amp;quot; machine is selected.&lt;br /&gt;
&lt;br /&gt;
Note: The ROMs in this zip are what is embedded inside the FPGA core on real Next hardware. They&#039;re different from any ZX Spectrum machine ROMs you may be used to using, that are on the distro, SD card or SD image file.&lt;br /&gt;
&lt;br /&gt;
=== 3. Get the NextZXOS Image ===&lt;br /&gt;
Get an SD card image file of [https://www.specnext.com/latestdistro/ NextZXOS]. Note that currently some published disk images on the official SpecNext.com site (the &amp;lt;code&amp;gt;latestdistro&amp;lt;/code&amp;gt; link points to the official location where the latest distribution can be found) do not work with some emulators, but all images from &amp;lt;code&amp;gt;https://zxnext.uk/hosted/&amp;lt;/code&amp;gt; work with both MAME and CSpect, like [https://zxnext.uk/hosted/index_files/hdfimages/cspect-next-2gb.zip this SD card image in the zip archive]. Extract the image &amp;lt;code&amp;gt;cspect-next-2gb.img&amp;lt;/code&amp;gt; from the archive to use it, then point MAME to this SD card image with the &amp;lt;code&amp;gt;-hard1&amp;lt;/code&amp;gt; option (or select that file from the menu inside MAME).&lt;br /&gt;
&lt;br /&gt;
= Usage =&lt;br /&gt;
MAME looks for its configuration and helper files in specific (configurable) folders. By default, these are relative to the current working directory (cwd), i.e., from where you launched the executable. The &amp;lt;code&amp;gt;mame.ini&amp;lt;/code&amp;gt; file and folders like &amp;lt;code&amp;gt;roms, bgfx, plugins, language, ...&amp;lt;/code&amp;gt; are expected there, unless the &amp;lt;code&amp;gt;mame.ini&amp;lt;/code&amp;gt; file specifies other paths. When launching through a desktop icon or menu, depending on the OS, the working directory is often defined by the properties of that launch shortcut. When launching MAME from the command line, the current directory is &amp;quot;cwd&amp;quot; (doh). On Linux, MAME will look for &amp;lt;code&amp;gt;mame.ini&amp;lt;/code&amp;gt; first in the &amp;lt;code&amp;gt;~/.mame&amp;lt;/code&amp;gt; folder. You can use the option &amp;lt;code&amp;gt;-inipath&amp;lt;/code&amp;gt; to point MAME to a different path for the &amp;lt;code&amp;gt;mame.ini&amp;lt;/code&amp;gt; file.&lt;br /&gt;
&lt;br /&gt;
However, the fastest way to run a machine with a desired configuration is from the command prompt, without requiring a &amp;lt;code&amp;gt;mame.ini&amp;lt;/code&amp;gt; file. Most of the features are also available through MAME&#039;s UI, although that takes more time to configure.&lt;br /&gt;
&lt;br /&gt;
As an example, this invocation enables the UI, uses &amp;quot;crisp pixels&amp;quot;, starts in a window, doesn&#039;t display the starting gameinfo window (it can still be displayed interactively from the UI), disables the mouse, confirms before exiting MAME, and specifies the disk image (remember to adjust the path to it):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;mame -ui_active -nounevenstretch -aspect 2:1 -video bgfx  -bgfx_screen_chains unfiltered -window -skip_gameinfo -mouse_device none -confirm_quit tbblue -hard1 /path/to/cspect-next-2gb.img&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let&#039;s cover some useful options:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Run inside a window and with no mouse support, until you get familiar with the UI keys:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; mame tbblue -window -mouse_device none -hard1 /path/to/next-distribution.img&amp;lt;/pre&amp;gt;&lt;br /&gt;
To launch the Linux flatpak version using the same options:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; flatpak run org.mamedev.MAME tbblue -window -mouse_device none -hard1 /path/to/next-distribution.img&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Activate UI keys on startup:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -ui_active&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Don&#039;t show the info popup on startup:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -skip_gameinfo&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;Run with debugger. If you don&#039;t request this on startup, you won&#039;t have access to it:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -debug&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;Use &amp;quot;crisp&amp;quot; pixels:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -nounevenstretch -aspect 2:1 -video bgfx -bgfx_screen_chains unfiltered&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;No joystick connected to PC (having this may slightly speed up MAME&#039;s startup, but &#039;&#039;remember to remove this part from the command line and the corresponding setting in the ini file if you do want to use a joystick&#039;&#039;):&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -joystickprovider none&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;Ask for confirmation when exiting MAME (otherwise it&#039;s easy to exit MAME accidentally by hitting ESC, especially when playing games or navigating menus):&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -confirm_quit&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Check the [https://docs.mamedev.org/commandline/commandline-all.html#mame-commandline-universal official MAME documentation] for more advanced usage.&lt;br /&gt;
&lt;br /&gt;
= Security: Allowing MAME to Run on Windows and macOS =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;On Windows,&#039;&#039;&#039; you will need to confirm that you want to launch MAME by clicking &amp;quot;Run Anyway&amp;quot; on first launch. &#039;&#039;(More details needed here.)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;On macOS,&#039;&#039;&#039; MAME will not open at first. Instead, a dialog will appear saying:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;“mame” Not Opened. Apple could not verify “mame” is free of malware that may harm your Mac or compromise your privacy.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Click “Done”. Then open &#039;&#039;&#039;System Settings -&amp;gt; Privacy &amp;amp; Security&#039;&#039;&#039;, and scroll down to the message &#039;&#039;mame was blocked to protect your Mac.&#039;&#039; Click “Allow Anyway”.&lt;br /&gt;
&lt;br /&gt;
Now launch MAME again. A dialog will ask once more if you want to open “mame”. Click “Open Anyway”, and enter your password or use Touch ID when prompted by macOS.&lt;br /&gt;
&lt;br /&gt;
From now on, you can launch this version of MAME without warnings. However, you &#039;&#039;&#039;will&#039;&#039;&#039; need to repeat this each time you update MAME.&lt;br /&gt;
&lt;br /&gt;
= Keys =&lt;br /&gt;
&lt;br /&gt;
Keys are emulated in two modes: either to control the MAME emulator or completely dedicated to the emulated system (the Next). You can toggle between these two keyboard modes with ScrLk (on Win and Linux) or fn+delete (on Mac).&lt;br /&gt;
&lt;br /&gt;
Some UI keys:&lt;br /&gt;
* F3 - soft reset&lt;br /&gt;
* Shift+F3 - hard reset&lt;br /&gt;
* F4 - sprites/tiles/font viewer (Enter, ], [)&lt;br /&gt;
* F5 - pause emulation&lt;br /&gt;
* F6 - save state&lt;br /&gt;
* F7 - load state&lt;br /&gt;
* Tab - emulator settings&lt;br /&gt;
* ~ - menu&lt;br /&gt;
* ` (backtick) - debugger (when enabled by starting MAME with &amp;lt;code&amp;gt;-debug&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;-d&amp;lt;/code&amp;gt; on the command line)&lt;br /&gt;
* PgDwn (Linux/Mac), fn-Downarrow (MacBooks) or Insert (Win) - hold down to fast-forward emulation at maximum speed, e.g., to speed up booting the Next&lt;br /&gt;
* Esc - exit (exits menus but also the entire emulator - see &amp;lt;code&amp;gt;-confirm_quit&amp;lt;/code&amp;gt; option above)&lt;br /&gt;
* F11 - DivMMC NMI&lt;br /&gt;
* F12 - Multiface NMI&lt;br /&gt;
&lt;br /&gt;
Check [https://docs.mamedev.org/usingmame/defaultkeys.html default keys documentation] for more.&lt;br /&gt;
&lt;br /&gt;
= Changing the UI toggle key =&lt;br /&gt;
&lt;br /&gt;
Some laptops don&#039;t have a Scroll Lock key, so you may not be able to exit MAME if you run it in full-screen mode. In these cases, you can change the UI toggle key as follows:&lt;br /&gt;
&lt;br /&gt;
* Run MAME without any command line arguments (except maybe -window) to open its GUI.&lt;br /&gt;
* Push TAB and enter the General Settings menu.&lt;br /&gt;
* Go to Input Assignments -&amp;gt; User Interface -&amp;gt; Toggle UI controls and select a new key. I use Right Alt / Alt GR.&lt;br /&gt;
* Return to the previous menu twice, then choose Save Settings&lt;br /&gt;
&lt;br /&gt;
= Creating and manipulating NextZXOS SD card image =&lt;br /&gt;
&lt;br /&gt;
Most users wanting to emulate the Next using MAME will be fine using a pre-built SD card image downloaded from the specnext website. The following guide is provided for anyone wanting to create a NextZXOS SD card image from scratch.&lt;br /&gt;
&lt;br /&gt;
Download the [https://www.specnext.com/latestdistro/ latest NextZXOS distribution zip file] (named something like sn-complete-WX.YZ.zip) and extract it into a new, empty directory.&lt;br /&gt;
&lt;br /&gt;
== Creating and populating a SD card image using hdfmonkey jjjs build ==&lt;br /&gt;
&lt;br /&gt;
The [https://www.specnext.com/forum/viewtopic.php?t=2604 hdfmonkey &amp;quot;jjjs build&amp;quot;] is a variant of hdfmonkey tool which includes some unique features and its main archive (at the previously given link) also contains pre-built binaries for Windows x64, MacOS x64, MacOS Apple Silicon and Linux x64. (Alternatively, the process to build a local Linux version of the executable is described [[Development_Tools:Linux_setup#hdfmonkey_tool | here]] )&lt;br /&gt;
&lt;br /&gt;
If you extracted sn-complete-WX.YZ.zip into a subdirectory named &amp;lt;code&amp;gt;snWXYZ&amp;lt;/code&amp;gt;, and you want to create a 1GB image called &amp;lt;code&amp;gt;NextZXOS.img&amp;lt;/code&amp;gt; and you have a jjjs build&amp;quot; of hdfmonkey, then it&#039;s enough to do:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
hdfmonkey create NextZXOS.img 1G&lt;br /&gt;
hdfmonkey putdir NextZXOS.img snWXYZ /&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first line creates an empty 1GB image and formats it with the best FAT parameters suited to the size of the image.&lt;br /&gt;
&lt;br /&gt;
The second line recursively copies all the content of the directory &amp;lt;code&amp;gt;snWXYZ&amp;lt;/code&amp;gt; to the image, preserving the directory structure inside, starting from the &amp;lt;code&amp;gt;/&amp;lt;/code&amp;gt; in the image.&lt;br /&gt;
&lt;br /&gt;
One of the advantages of this method is that even if the image has a capacity of 1GB, it will use much less space on your hard drive until you fill up the image. On Linux or MacOS, a command &amp;lt;code&amp;gt;du -h NextZXOS.img&amp;lt;/code&amp;gt; shows the actual amount of disk space used by the image. On Windows the same information can be seen in the File Properties dialog.&lt;br /&gt;
&lt;br /&gt;
The fastest way to transfer a file or a directory (including its content, recursively) into an image is by using a single &amp;lt;code&amp;gt;put&amp;lt;/code&amp;gt; (or &amp;lt;code&amp;gt;putdir&amp;lt;/code&amp;gt;, if it&#039;s to transfer the directory file content to an existing directory) command of hdfmonkey.&lt;br /&gt;
&lt;br /&gt;
The most convenient tool to copy of all the content from the image to a folder outside of the image is 7-zip. On Windows, just use the 7-zip GUI. On MacOS and Linux, see: [[Development_Tools:Linux_setup#Extracting_all_files_from_the_sd-card_image]].&lt;br /&gt;
&lt;br /&gt;
=MAME Plugins and Scripts=&lt;br /&gt;
&lt;br /&gt;
Some MAME plugins and scripts that may be useful for Next developers and end users are listed [[MAME:Plugins_and_Scripts|here]]. They let you speed up the Next boot time, profile your NextBASIC or assembler code, and more.&lt;br /&gt;
&lt;br /&gt;
=Continuous Integration MAME Builds=&lt;br /&gt;
&lt;br /&gt;
MAME is updated on a release schedule, but due to the ongoing nature of development, including for the MAME Next machine, it can sometimes be useful to install a more recent build if it contains a new feature or bugfix you are interested in. Sometimes, this ongoing work is discussed on social media, such as the [https://discordapp.com/channels/556228195767156758/752197165891321886 Next Developer Discord].&lt;br /&gt;
&lt;br /&gt;
Continuous Integration (CI) builds are available from both the [https://github.com/mamedev/mame/actions primary MAME repo] and [https://github.com/holub/mame/actions holub&#039;s GitHub repo]. Both are considered bleeding-edge, with the primary MAME repo slightly less so. MAME CI builds are available for Windows, Linux, and macOS and are updated automatically whenever code is committed by a maintainer or pushed to the primary repo.&lt;br /&gt;
&lt;br /&gt;
To try out a CI build (more precisely, the resulting binary executable, which is a produced &amp;quot;artifact&amp;quot; of the build process) , first do a full MAME install from the [https://www.mamedev.org/release.html latest release] if you have not already done so. Then back up your main binary from its installation location - these are called something like &amp;lt;code&amp;gt;mame.exe&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;mame&amp;lt;/code&amp;gt;. You can always restore these if the CI build doesn&#039;t work, or if you don&#039;t like how it behaves.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;You need to be logged in to github&#039;&#039;&#039; to download CI artifacts, so [https://github.com/login sign in] or [https://github.com/signup sign up].&lt;br /&gt;
&lt;br /&gt;
Then visit one of the links above and find a workflow run item for your platform. Workflow items are the things in the list. The tags are flagged as &amp;lt;code&amp;gt;CI (Windows)&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CI (Linux)&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;CI (macOS)&amp;lt;/code&amp;gt; in the second row of each workflow item in the list (not the filter in the left hand nav menu). Click on a completed workfow item (only items with green checkmarks will have created downloadable binaries yet), find the Artifacts section at the bottom, then click the Download button. Unzip the downloaded file and find the main binary (with the same name as above). Copy the main binary to the install location, overwriting the original one, and run MAME the same way you were running it before. On Windows and macOS, you need to repeat the security steps above to trust the new MAME executable.&lt;br /&gt;
&lt;br /&gt;
= More MAME related links =&lt;br /&gt;
&lt;br /&gt;
MAME [https://docs.mamedev.org/ documentation].&lt;br /&gt;
&lt;br /&gt;
Report any issues with MAME on the [https://mametesters.org/ bugtracker].&lt;br /&gt;
&lt;br /&gt;
For &#039;&#039;&#039;Linux&#039;&#039;&#039; users there are more tips (how to compile MAME from source, how to configure it to not use CWD as starting path for resource directories, how to mount or create image file) at [[Development_Tools:Linux_setup]] page.&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=Development_Tools:Linux_setup&amp;diff=41781</id>
		<title>Development Tools:Linux setup</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=Development_Tools:Linux_setup&amp;diff=41781"/>
		<updated>2026-01-21T16:46:26Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: add placeholder for MAME lore&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== General ==&lt;br /&gt;
&lt;br /&gt;
This page collects summaries of installation process of various tools related to ZX Spectrum Next software development for linux OS users.&lt;br /&gt;
&lt;br /&gt;
As usual with linux, most of the suggestions are in the form of command line command to be used from terminal.&lt;br /&gt;
&lt;br /&gt;
== sjasmplus assembler ==&lt;br /&gt;
&lt;br /&gt;
You can also check the [https://www.youtube.com/watch?v=c6I4kdErEwE video] of installing sjasmplus on freshly reinstalled KDE neon 5.20 linux, where is also extended info how to run the automated tests of sjasmplus, and opening it in KDevelop IDE to eventually write your own modifications.&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
On Debian based systems make sure you have these packages installed (git-cola and cmake are optional, but often handy):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install git build-essential g++ git-cola cmake&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Retrieving the sjasmplus source ===&lt;br /&gt;
&lt;br /&gt;
Use git to clone the [https://github.com/z00m128/sjasmplus z00m&#039;s sjasmplus repository]:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;git clone --recursive -j8 https://github.com/z00m128/sjasmplus.git&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To update already cloned repository, do inside the sjasmplus folder:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;git pull&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
- or use your favourite GIT client app to update the cloned repository.&lt;br /&gt;
&lt;br /&gt;
=== Building the executable binary ===&lt;br /&gt;
&lt;br /&gt;
The GNU make and common C++ compiler (gcc or clang) should be enough to build the binary:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;make clean &amp;amp;&amp;amp; make&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To verify the binary was built (&amp;quot;dot slash&amp;quot; prefix to force running of binary in current folder, not system one):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;./sjasmplus --version&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Installing the executable ===&lt;br /&gt;
&lt;br /&gt;
If you already have sjasmplus installed, use &amp;lt;code&amp;gt;which sjasmplus&amp;lt;/code&amp;gt; to see where the installed executable is (and which installed executable has precedence), you can use this command also after installing the new executable to verify it is being picked up by the system.&lt;br /&gt;
&lt;br /&gt;
Installing the binary in system-wide fashion:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo make install&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or you can install the binary only locally for your user (without root/sudo permissions):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;mkdir -p ~/.local/bin&lt;br /&gt;
make PREFIX=~/.local install&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
- then make sure you have &amp;lt;code&amp;gt;~/.local/bin&amp;lt;/code&amp;gt; in your user &amp;lt;code&amp;gt;PATH&amp;lt;/code&amp;gt; environment variable (on some distros there is already script in .profile to add this to PATH if the dir does exist, so you may need to only logout/restart after creating it to get it active).&lt;br /&gt;
&lt;br /&gt;
=== Checking if it all works ===&lt;br /&gt;
&lt;br /&gt;
Open your terminal and type (in any directory):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sjasmplus --version&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see version of the freshly built sjasmplus executable like this:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;SjASMPlus Z80 Cross-Assembler v1.17.0 (https://github.com/z00m128/sjasmplus)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== hdfmonkey tool ==&lt;br /&gt;
&lt;br /&gt;
The hdfmonkey tool can manipulate card-images, helping to write new builds of your project into NextZXOS card-image, to boot the emulators with full file system. (it&#039;s also possible to mount the images directly into linux by other means, to operate on them with regular file manager/etc, but hdfmonkey suits better use-case when the build script does update the image)&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
On Debian based systems make sure you have these packages installed:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install git build-essential g++ autoconf&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Retrieving the hdfmonkey source ===&lt;br /&gt;
&lt;br /&gt;
Use git to clone the [https://github.com/ped7g/hdfmonkey hdfmonkey repository with patched 0.5.7 &amp;lt;code&amp;gt;jjjs version&amp;lt;/code&amp;gt; sources]:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;git clone https://github.com/ped7g/hdfmonkey.git&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
(make sure you are on the default branch &amp;lt;code&amp;gt;&amp;quot;jjjs-variant&amp;quot;&amp;lt;/code&amp;gt; to build the improved version, it should be checked out by default after clone)&lt;br /&gt;
&lt;br /&gt;
* to update already cloned repository, do inside the hdfmonkey folder:&lt;br /&gt;
  &amp;lt;nowiki&amp;gt;git pull&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
* or use your favourite GIT client app to update the cloned repository.&lt;br /&gt;
* if you cloned original gasman&#039;s repository before, you may want to clone and rebuild here mentioned &amp;lt;code&amp;gt;jjjs version&amp;lt;/code&amp;gt; to get multiple fixes and convenience features.&lt;br /&gt;
&lt;br /&gt;
=== Building the executable binary ===&lt;br /&gt;
&lt;br /&gt;
The hdfmonkey is using autoconf/autotools to build final Makefile, check the hdfmonkey README for &amp;quot;from git&amp;quot; installation notes, at the moment of writing this page, the steps were:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;cd hdfmonkey&lt;br /&gt;
autoheader&lt;br /&gt;
aclocal&lt;br /&gt;
autoconf&lt;br /&gt;
automake -a&lt;br /&gt;
./configure&lt;br /&gt;
make&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To verify the binary was built:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;src/hdfmonkey help&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Installing the executable ===&lt;br /&gt;
&lt;br /&gt;
If you already have hdfmonkey installed, use &amp;lt;code&amp;gt;which hdfmonkey&amp;lt;/code&amp;gt; to see where the installed executable is (and which installed executable has precedence), you can use this command also after installing the new executable to verify it is being picked up by the system.&lt;br /&gt;
&lt;br /&gt;
Installing the binary in system-wide fashion:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo make install&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or you can install the binary only locally for your user (without root/sudo permissions):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;make prefix=~/.local install&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
- then make sure you have &amp;lt;code&amp;gt;~/.local/bin&amp;lt;/code&amp;gt; in your user &amp;lt;code&amp;gt;PATH&amp;lt;/code&amp;gt; environment variable.&lt;br /&gt;
&lt;br /&gt;
=== Checking if it all works ===&lt;br /&gt;
&lt;br /&gt;
Open your terminal and type (in any directory):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;hdfmonkey help&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see help of the freshly built hdfmonkey `jjjs version` executable like this:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;hdfmonkey: utility for manipulating HDF disk images v0.5.7 jjjs&lt;br /&gt;
&lt;br /&gt;
usage: hdfmonkey &amp;lt;command&amp;gt; [args]&lt;br /&gt;
...&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Extracting all files from the sd-card image ==&lt;br /&gt;
&lt;br /&gt;
7-zip is the most convenient tool to extract the the files from the existing image.&lt;br /&gt;
&lt;br /&gt;
To install 7-zip on a Debian system use &amp;lt;code&amp;gt;sudo apt install 7zip&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To extract all the files from an existing image &amp;lt;code&amp;gt;tbblue.img&amp;lt;/code&amp;gt; to a new subdirectory &amp;lt;code&amp;gt;myfiles&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;7z x tbblue.img -omyfiles&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Creating new sd-card image with hdfmonkey ==&lt;br /&gt;
&lt;br /&gt;
This example: &lt;br /&gt;
&lt;br /&gt;
* downloads the archive from the specnext.com&lt;br /&gt;
* unpacks it to the subdirectory &amp;lt;code&amp;gt;tmptb&amp;lt;/code&amp;gt;&lt;br /&gt;
* creates a new SD image (with the space for 2GB files) from all the files&lt;br /&gt;
* deletes the subdirectory &amp;lt;code&amp;gt;tmptb&amp;lt;/code&amp;gt;&lt;br /&gt;
* shows that the new image uses much less than 2GB&lt;br /&gt;
* starts listing the content of the newly created image&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
wget https://www.specnext.com/distro/24.11/sn-complete-24.11.zip&lt;br /&gt;
7z x sn-complete-24.11.zip -otmptb&lt;br /&gt;
hdfmonkey create tbblue.img 2GB&lt;br /&gt;
hdfmonkey putdir tbblue.img tmptb /  &lt;br /&gt;
rm -rf tmptb&lt;br /&gt;
du -h tbblue.img&lt;br /&gt;
7z l tbblue.img | more&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating new sd-card image without hdfmonkey ===&lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to use gnu coreutils and dosfstools to create card image without hdfmonkey, but depending on exact size of image these may be less compatible with various emulator, following example for 1GB card image works in MAME but fails in CSpect (while images created by hdfmonkey tool should work for both emulator, so using &#039;&#039;&#039;hdfmonkey is recommended&#039;&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
truncate -s 1G NextZXOS.img&lt;br /&gt;
parted NextZXOS.img mklabel msdos&lt;br /&gt;
parted NextZXOS.img mkpart primary fat32 2048s 100%&lt;br /&gt;
mkfs.fat -F 32 --offset=2048 NextZXOS.img&lt;br /&gt;
# and now to copy files to image you have to either mount it or use hdfmonkey:&lt;br /&gt;
# hdfmonkey putdir NextZXOS.img tmptb /&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mounting sd-card image directly ==&lt;br /&gt;
&lt;br /&gt;
Sometimes it may be useful to mount the card image directly, to be able to browse it and manipulate with common tools. But make sure you are not using mounted card image also in emulator at the same time, to prevent any data damage by parallel access.&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
On Debian based systems make sure you have these packages installed:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install fdisk mount&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Prepare empty directory to mount the card image into (let&#039;s call it &amp;quot;next-card&amp;quot;) and have the image file around (&amp;quot;tbblue.mmc&amp;quot; in following examples)&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;mkdir -p next-card&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Mounting the card image ===&lt;br /&gt;
&lt;br /&gt;
To mount the card image you need to know the exact byte-offset where the FAT partition starts, it&#039;s possible to read it from &amp;quot;fdisk&amp;quot; or &amp;quot;parted&amp;quot; tools outputs:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;fdisk -l -o Start tbblue.mmc&lt;br /&gt;
# prints value in sector units, like:&lt;br /&gt;
# Start&lt;br /&gt;
#    63&lt;br /&gt;
# This has to be multiplied by 512 to get byte offset: 63*512 = 32256&lt;br /&gt;
&lt;br /&gt;
# or&lt;br /&gt;
&lt;br /&gt;
parted tbblue.mmc unit B print&lt;br /&gt;
# prints values in bytes with &amp;quot;B&amp;quot; suffix in &amp;quot;Start&amp;quot; column&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
But the fdisk output can be incorporated directly into mount command, which needs root permissions, example with sudo:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo mount tbblue.mmc next-card/ -o loop,offset=$((`fdisk -l -o Start tbblue.mmc | tail -1` * 512)),user,uid=`id -u`,gid=`id -g`&lt;br /&gt;
&lt;br /&gt;
# or you can enter the offset yourself&lt;br /&gt;
&lt;br /&gt;
sudo mount tbblue.mmc next-card/ -o loop,offset=32256,user,uid=`id -u`,gid=`id -g`&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The uid and gid options will mount the filesystem under your regular user, so you can now browse it with file manager, text editors, etc.&lt;br /&gt;
&lt;br /&gt;
Do not run the emulator yet, before unmounting the image (after you are done manipulating the files)!&lt;br /&gt;
&lt;br /&gt;
=== Unmount the image before using it in emulator ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo umount next-card/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Check the result. If the unmounting fails (probably with &amp;quot;target is busy&amp;quot;), find which process is still accessing/viewing the files in the next-card directory, and try to unmount it again.&lt;br /&gt;
&lt;br /&gt;
== Mounting sd-card image with losetup ==&lt;br /&gt;
&lt;br /&gt;
Alternative using losetup to use local &amp;quot;loop&amp;quot; device for mounting the image. This method can automatically detect partitions inside the image and exposes them as loop devices.&lt;br /&gt;
&lt;br /&gt;
Prepare mounting dir and make sure you have &amp;lt;code&amp;gt;mount&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;losetup&amp;lt;/code&amp;gt; available, Ubuntu based systems packages:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install util-linux mount&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Use losetup to attach image and scan its partitions ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo losetup --partscan --show --find NextZXOS.img&lt;br /&gt;
# this will print new loop device and automatically create partition devices like /dev/loop0p1&lt;br /&gt;
# now mount the desired FAT32 partition:&lt;br /&gt;
sudo mount /dev/loop0p1 next-card/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Unmounting and cleanup of loop device ===&lt;br /&gt;
&lt;br /&gt;
When finished:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo umount next-card/&lt;br /&gt;
sudo losetup -d /dev/loop0&lt;br /&gt;
# or `sudo losetup -D` to detach *ALL* loop devices&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This detaches the loop device and frees all associated /dev/loop* entries.&lt;br /&gt;
&lt;br /&gt;
Notes and gotchas:&lt;br /&gt;
* Do not use the image in an emulator while it is mounted.&lt;br /&gt;
* If the image has no partition table, --partscan will not create /dev/loop0p1.&lt;br /&gt;
* If multiple loop devices are active, check &amp;lt;code&amp;gt;losetup -a&amp;lt;/code&amp;gt; to confirm which one is yours.&lt;br /&gt;
&lt;br /&gt;
== Mounting sd‑card image with udisksctl ==&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;udisksctl&amp;lt;/code&amp;gt; tool provides a desktop‑friendly way to attach loop devices and mount filesystems without manually calculating offsets or using &amp;lt;code&amp;gt;losetup&amp;lt;/code&amp;gt;. It integrates with system services such as UDisks2, and on many desktop Linux systems it allows non‑root users (who are in the correct group) to mount images safely.&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
On Debian‑based systems install the UDisks2 tools:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install udisks2&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To run &amp;lt;code&amp;gt;udisksctl&amp;lt;/code&amp;gt; without &amp;lt;code&amp;gt;sudo&amp;lt;/code&amp;gt;, your user must belong to the &#039;&#039;&#039;disk&#039;&#039;&#039;, &#039;&#039;&#039;storage&#039;&#039;&#039;, or &#039;&#039;&#039;udisks&#039;&#039;&#039; policy group (varies by distribution). If unsure, simply use &amp;lt;code&amp;gt;sudo&amp;lt;/code&amp;gt; in the examples below.&lt;br /&gt;
&lt;br /&gt;
=== Attaching the image as a loop device ===&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;code&amp;gt;udisksctl loop-setup&amp;lt;/code&amp;gt; to create a loop device for the image:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;udisksctl loop-setup --file NextZXOS.img&lt;br /&gt;
# prints something like:&lt;br /&gt;
# Mapped file NextZXOS.img as /dev/loop2.&lt;br /&gt;
# UDisks automatically scans the partition table and exposes partitions as:&lt;br /&gt;
# /dev/loop2p1&lt;br /&gt;
# /dev/loop2p2&lt;br /&gt;
# ...&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Mounting the FAT32 partition ===&lt;br /&gt;
&lt;br /&gt;
Mount the desired partition:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;udisksctl mount --block-device /dev/loop2p1&lt;br /&gt;
# This prints the mount point, for example:&lt;br /&gt;
# Mounted /dev/loop2p1 at /media/youruser/NextZXOS.&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can now browse and edit the filesystem normally using your file manager or command‑line tools.&lt;br /&gt;
&lt;br /&gt;
=== Unmounting and cleanup ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;udisksctl unmount --block-device /dev/loop2p1&lt;br /&gt;
udisksctl loop-delete --block-device /dev/loop2&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This cleanly detaches the loop device and removes all &amp;lt;code&amp;gt;/dev/loop*&amp;lt;/code&amp;gt; entries created for the image.&lt;br /&gt;
&lt;br /&gt;
=== Notes and gotchas ===&lt;br /&gt;
&lt;br /&gt;
* Do not use the image in an emulator while it is mounted, parallel access may corrupt data.&lt;br /&gt;
* If the image has no partition table, UDisks will not create &#039;&#039;&#039;/dev/loopXp1&#039;&#039;&#039; and you must mount manually using an offset.&lt;br /&gt;
* Mount points are created under &amp;lt;code&amp;gt;/media/$USER/&amp;lt;/code&amp;gt; unless overridden by system policy.&lt;br /&gt;
* UDisks may auto‑mount partitions immediately after &#039;&#039;&#039;loop‑setup&#039;&#039;&#039; depending on desktop environment settings.&lt;br /&gt;
&lt;br /&gt;
== MAME emulator ==&lt;br /&gt;
&lt;br /&gt;
TODO: placeholder for compilation and setup notes, to be added hopefully soon by Ped7g&lt;br /&gt;
&lt;br /&gt;
== #CSpect emulator ==&lt;br /&gt;
&lt;br /&gt;
The #CSpect is Mike Dailly&#039;s ZX Spectrum Next emulator, written in C# making it cross-platform (sort of, where the mono framework is available). It is non-free (closed-source, custom license) project, but available for usage without any payment (it&#039;s possible to use it internally to develop also commercial titles, but you can not distribute/sell the emulator itself, not even packaged with your game - for such agreement contact the author first and get his permission).&lt;br /&gt;
&lt;br /&gt;
Currently it is most performant and user friendly emulator of ZX Spectrum Next, with good emulation accuracy (see [https://wiki.specnext.dev/CSpect:known_bugs CSpect:known_bugs] page for more detailed report).&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
On Debian based systems make sure you have these packages installed:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install mono-complete libopenal1 libsdl2-dev&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Retrieving the #CSpect package ===&lt;br /&gt;
&lt;br /&gt;
Use web browser to visit itch.io dedicated to CSpect project [https://mdf200.itch.io/cspect mdf200.itch.io/cspect] and download latest release.&lt;br /&gt;
&lt;br /&gt;
You may get warnings from your browser or antivirus about the page itself and about the zip/binary files. The #CSpect has long record of triggering false positives of AV engines due to the executable being not digitally signed and because of the code using features of OS which are normal for emulator, but may look wonky for AV heuristic. Whether you trust the executable is virus free is up to you, in the end.&lt;br /&gt;
&lt;br /&gt;
=== Installing the executable ===&lt;br /&gt;
&lt;br /&gt;
Unzip the retrieved zip file (I personally use KDE Dolphin file manager, the file context menu &#039;&#039;&amp;quot;Extract -&amp;gt; Extract archive here, autodetect subfolder&amp;quot;&#039;&#039;), and place the unzipped directory to target destination (&amp;lt;code&amp;gt;~/zx/emulators/CSpect/CSpect2_13_0&amp;lt;/code&amp;gt; in my case). I prefer to keep every version in its own directory, and have general symbolic link pointing to the one I want use by default:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;cd ~/zx/emulators/CSpect&lt;br /&gt;
ln -s CSpect2_13_0 CSpect_current&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then I create launcher bash-scripts in my &amp;lt;code&amp;gt;~/.local/bin&amp;lt;/code&amp;gt; like this (name of script &amp;lt;code&amp;gt;runCSpect&amp;lt;/code&amp;gt;):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;#!/bin/bash&lt;br /&gt;
# personal script of Ped to launch &amp;quot;#CSpect&amp;quot; emulator in &amp;quot;current directory&amp;quot; (with arguments like: &amp;quot;runCSpect file.nex&amp;quot;)&lt;br /&gt;
MONO_IOMAP=all mono ~/zx/emulators/CSpect/CSpect_current/CSpect.exe -tv -zxnext -s28 -w4 -mmc=./ &amp;quot;$@&amp;quot;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notes: I don&#039;t know any more what &amp;lt;code&amp;gt;MONO_IOMAP=all&amp;lt;/code&amp;gt; helps with, I believe it was suggested to help with any filesystem windows-like paths containing backslashes, you can try to do your own research. The &amp;lt;code&amp;gt;-tv&amp;lt;/code&amp;gt; switch will switch off &amp;quot;scanlines&amp;quot; shader effect and generally switch off any GPU shaders, which makes CSpect more compatible with graphics drivers (try it, if you get only black screen or instant crash during init). The &amp;lt;code&amp;gt;-w4&amp;lt;/code&amp;gt; will make the window quite large - 4x scale, the &amp;lt;code&amp;gt;-zxnext -s28&amp;lt;/code&amp;gt; switch #CSpect into ZX Next emulation mode and set 28Mhz speed of OS as default. And finally the &amp;lt;code&amp;gt;-mmc=./ &amp;quot;$@&amp;quot;&amp;lt;/code&amp;gt; will set &#039;&#039;current directory&#039;&#039; for esxdos emulation to the directory where you use the script to launch the emulator, and pass any remaining command line options entered by user, like the name of the SNA/NEX file. Other noteworthy options are &amp;lt;code&amp;gt;-debug -brk -map=file.map&amp;lt;/code&amp;gt;, the -debug entering the debugger just ahead of the first instruction, -brk enables CSpect specific two-byte tag 0xDD 0x01 to work as breakpoint and the -map option allows you to load into debugger the symbol table from your assembler (directive CSPECTMAP in sjasmplus), making labels visible in disassembly.&lt;br /&gt;
&lt;br /&gt;
=== Checking if it all works ===&lt;br /&gt;
&lt;br /&gt;
Go to some directory with SNA/SNX/NEX file (there are also some demo files right in the CSpect directory) and use the launcher script, like:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;runCSpect beast.nex&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see #CSpect emulator window running the beast.nex demo (or whatever else you did want to launch and entered as argument).&lt;br /&gt;
&lt;br /&gt;
[[File:Cspect_test_run.png|frameless|Running CSpect from directory with test snapshots]]&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=Development_Tools:Linux_setup&amp;diff=41780</id>
		<title>Development Tools:Linux setup</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=Development_Tools:Linux_setup&amp;diff=41780"/>
		<updated>2026-01-21T16:32:41Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: adding mount card with udisksctl and change losetup -D advice&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== General ==&lt;br /&gt;
&lt;br /&gt;
This page collects summaries of installation process of various tools related to ZX Spectrum Next software development for linux OS users.&lt;br /&gt;
&lt;br /&gt;
As usual with linux, most of the suggestions are in the form of command line command to be used from terminal.&lt;br /&gt;
&lt;br /&gt;
== sjasmplus assembler ==&lt;br /&gt;
&lt;br /&gt;
You can also check the [https://www.youtube.com/watch?v=c6I4kdErEwE video] of installing sjasmplus on freshly reinstalled KDE neon 5.20 linux, where is also extended info how to run the automated tests of sjasmplus, and opening it in KDevelop IDE to eventually write your own modifications.&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
On Debian based systems make sure you have these packages installed (git-cola and cmake are optional, but often handy):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install git build-essential g++ git-cola cmake&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Retrieving the sjasmplus source ===&lt;br /&gt;
&lt;br /&gt;
Use git to clone the [https://github.com/z00m128/sjasmplus z00m&#039;s sjasmplus repository]:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;git clone --recursive -j8 https://github.com/z00m128/sjasmplus.git&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To update already cloned repository, do inside the sjasmplus folder:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;git pull&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
- or use your favourite GIT client app to update the cloned repository.&lt;br /&gt;
&lt;br /&gt;
=== Building the executable binary ===&lt;br /&gt;
&lt;br /&gt;
The GNU make and common C++ compiler (gcc or clang) should be enough to build the binary:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;make clean &amp;amp;&amp;amp; make&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To verify the binary was built (&amp;quot;dot slash&amp;quot; prefix to force running of binary in current folder, not system one):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;./sjasmplus --version&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Installing the executable ===&lt;br /&gt;
&lt;br /&gt;
If you already have sjasmplus installed, use &amp;lt;code&amp;gt;which sjasmplus&amp;lt;/code&amp;gt; to see where the installed executable is (and which installed executable has precedence), you can use this command also after installing the new executable to verify it is being picked up by the system.&lt;br /&gt;
&lt;br /&gt;
Installing the binary in system-wide fashion:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo make install&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or you can install the binary only locally for your user (without root/sudo permissions):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;mkdir -p ~/.local/bin&lt;br /&gt;
make PREFIX=~/.local install&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
- then make sure you have &amp;lt;code&amp;gt;~/.local/bin&amp;lt;/code&amp;gt; in your user &amp;lt;code&amp;gt;PATH&amp;lt;/code&amp;gt; environment variable (on some distros there is already script in .profile to add this to PATH if the dir does exist, so you may need to only logout/restart after creating it to get it active).&lt;br /&gt;
&lt;br /&gt;
=== Checking if it all works ===&lt;br /&gt;
&lt;br /&gt;
Open your terminal and type (in any directory):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sjasmplus --version&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see version of the freshly built sjasmplus executable like this:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;SjASMPlus Z80 Cross-Assembler v1.17.0 (https://github.com/z00m128/sjasmplus)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== hdfmonkey tool ==&lt;br /&gt;
&lt;br /&gt;
The hdfmonkey tool can manipulate card-images, helping to write new builds of your project into NextZXOS card-image, to boot the emulators with full file system. (it&#039;s also possible to mount the images directly into linux by other means, to operate on them with regular file manager/etc, but hdfmonkey suits better use-case when the build script does update the image)&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
On Debian based systems make sure you have these packages installed:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install git build-essential g++ autoconf&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Retrieving the hdfmonkey source ===&lt;br /&gt;
&lt;br /&gt;
Use git to clone the [https://github.com/ped7g/hdfmonkey hdfmonkey repository with patched 0.5.7 &amp;lt;code&amp;gt;jjjs version&amp;lt;/code&amp;gt; sources]:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;git clone https://github.com/ped7g/hdfmonkey.git&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
(make sure you are on the default branch &amp;lt;code&amp;gt;&amp;quot;jjjs-variant&amp;quot;&amp;lt;/code&amp;gt; to build the improved version, it should be checked out by default after clone)&lt;br /&gt;
&lt;br /&gt;
* to update already cloned repository, do inside the hdfmonkey folder:&lt;br /&gt;
  &amp;lt;nowiki&amp;gt;git pull&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
* or use your favourite GIT client app to update the cloned repository.&lt;br /&gt;
* if you cloned original gasman&#039;s repository before, you may want to clone and rebuild here mentioned &amp;lt;code&amp;gt;jjjs version&amp;lt;/code&amp;gt; to get multiple fixes and convenience features.&lt;br /&gt;
&lt;br /&gt;
=== Building the executable binary ===&lt;br /&gt;
&lt;br /&gt;
The hdfmonkey is using autoconf/autotools to build final Makefile, check the hdfmonkey README for &amp;quot;from git&amp;quot; installation notes, at the moment of writing this page, the steps were:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;cd hdfmonkey&lt;br /&gt;
autoheader&lt;br /&gt;
aclocal&lt;br /&gt;
autoconf&lt;br /&gt;
automake -a&lt;br /&gt;
./configure&lt;br /&gt;
make&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To verify the binary was built:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;src/hdfmonkey help&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Installing the executable ===&lt;br /&gt;
&lt;br /&gt;
If you already have hdfmonkey installed, use &amp;lt;code&amp;gt;which hdfmonkey&amp;lt;/code&amp;gt; to see where the installed executable is (and which installed executable has precedence), you can use this command also after installing the new executable to verify it is being picked up by the system.&lt;br /&gt;
&lt;br /&gt;
Installing the binary in system-wide fashion:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo make install&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or you can install the binary only locally for your user (without root/sudo permissions):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;make prefix=~/.local install&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
- then make sure you have &amp;lt;code&amp;gt;~/.local/bin&amp;lt;/code&amp;gt; in your user &amp;lt;code&amp;gt;PATH&amp;lt;/code&amp;gt; environment variable.&lt;br /&gt;
&lt;br /&gt;
=== Checking if it all works ===&lt;br /&gt;
&lt;br /&gt;
Open your terminal and type (in any directory):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;hdfmonkey help&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see help of the freshly built hdfmonkey `jjjs version` executable like this:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;hdfmonkey: utility for manipulating HDF disk images v0.5.7 jjjs&lt;br /&gt;
&lt;br /&gt;
usage: hdfmonkey &amp;lt;command&amp;gt; [args]&lt;br /&gt;
...&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Extracting all files from the sd-card image ==&lt;br /&gt;
&lt;br /&gt;
7-zip is the most convenient tool to extract the the files from the existing image.&lt;br /&gt;
&lt;br /&gt;
To install 7-zip on a Debian system use &amp;lt;code&amp;gt;sudo apt install 7zip&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To extract all the files from an existing image &amp;lt;code&amp;gt;tbblue.img&amp;lt;/code&amp;gt; to a new subdirectory &amp;lt;code&amp;gt;myfiles&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;7z x tbblue.img -omyfiles&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Creating new sd-card image with hdfmonkey ==&lt;br /&gt;
&lt;br /&gt;
This example: &lt;br /&gt;
&lt;br /&gt;
* downloads the archive from the specnext.com&lt;br /&gt;
* unpacks it to the subdirectory &amp;lt;code&amp;gt;tmptb&amp;lt;/code&amp;gt;&lt;br /&gt;
* creates a new SD image (with the space for 2GB files) from all the files&lt;br /&gt;
* deletes the subdirectory &amp;lt;code&amp;gt;tmptb&amp;lt;/code&amp;gt;&lt;br /&gt;
* shows that the new image uses much less than 2GB&lt;br /&gt;
* starts listing the content of the newly created image&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
wget https://www.specnext.com/distro/24.11/sn-complete-24.11.zip&lt;br /&gt;
7z x sn-complete-24.11.zip -otmptb&lt;br /&gt;
hdfmonkey create tbblue.img 2GB&lt;br /&gt;
hdfmonkey putdir tbblue.img tmptb /  &lt;br /&gt;
rm -rf tmptb&lt;br /&gt;
du -h tbblue.img&lt;br /&gt;
7z l tbblue.img | more&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating new sd-card image without hdfmonkey ===&lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to use gnu coreutils and dosfstools to create card image without hdfmonkey, but depending on exact size of image these may be less compatible with various emulator, following example for 1GB card image works in MAME but fails in CSpect (while images created by hdfmonkey tool should work for both emulator, so using &#039;&#039;&#039;hdfmonkey is recommended&#039;&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
truncate -s 1G NextZXOS.img&lt;br /&gt;
parted NextZXOS.img mklabel msdos&lt;br /&gt;
parted NextZXOS.img mkpart primary fat32 2048s 100%&lt;br /&gt;
mkfs.fat -F 32 --offset=2048 NextZXOS.img&lt;br /&gt;
# and now to copy files to image you have to either mount it or use hdfmonkey:&lt;br /&gt;
# hdfmonkey putdir NextZXOS.img tmptb /&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mounting sd-card image directly ==&lt;br /&gt;
&lt;br /&gt;
Sometimes it may be useful to mount the card image directly, to be able to browse it and manipulate with common tools. But make sure you are not using mounted card image also in emulator at the same time, to prevent any data damage by parallel access.&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
On Debian based systems make sure you have these packages installed:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install fdisk mount&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Prepare empty directory to mount the card image into (let&#039;s call it &amp;quot;next-card&amp;quot;) and have the image file around (&amp;quot;tbblue.mmc&amp;quot; in following examples)&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;mkdir -p next-card&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Mounting the card image ===&lt;br /&gt;
&lt;br /&gt;
To mount the card image you need to know the exact byte-offset where the FAT partition starts, it&#039;s possible to read it from &amp;quot;fdisk&amp;quot; or &amp;quot;parted&amp;quot; tools outputs:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;fdisk -l -o Start tbblue.mmc&lt;br /&gt;
# prints value in sector units, like:&lt;br /&gt;
# Start&lt;br /&gt;
#    63&lt;br /&gt;
# This has to be multiplied by 512 to get byte offset: 63*512 = 32256&lt;br /&gt;
&lt;br /&gt;
# or&lt;br /&gt;
&lt;br /&gt;
parted tbblue.mmc unit B print&lt;br /&gt;
# prints values in bytes with &amp;quot;B&amp;quot; suffix in &amp;quot;Start&amp;quot; column&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
But the fdisk output can be incorporated directly into mount command, which needs root permissions, example with sudo:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo mount tbblue.mmc next-card/ -o loop,offset=$((`fdisk -l -o Start tbblue.mmc | tail -1` * 512)),user,uid=`id -u`,gid=`id -g`&lt;br /&gt;
&lt;br /&gt;
# or you can enter the offset yourself&lt;br /&gt;
&lt;br /&gt;
sudo mount tbblue.mmc next-card/ -o loop,offset=32256,user,uid=`id -u`,gid=`id -g`&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The uid and gid options will mount the filesystem under your regular user, so you can now browse it with file manager, text editors, etc.&lt;br /&gt;
&lt;br /&gt;
Do not run the emulator yet, before unmounting the image (after you are done manipulating the files)!&lt;br /&gt;
&lt;br /&gt;
=== Unmount the image before using it in emulator ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo umount next-card/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Check the result. If the unmounting fails (probably with &amp;quot;target is busy&amp;quot;), find which process is still accessing/viewing the files in the next-card directory, and try to unmount it again.&lt;br /&gt;
&lt;br /&gt;
== Mounting sd-card image with losetup ==&lt;br /&gt;
&lt;br /&gt;
Alternative using losetup to use local &amp;quot;loop&amp;quot; device for mounting the image. This method can automatically detect partitions inside the image and exposes them as loop devices.&lt;br /&gt;
&lt;br /&gt;
Prepare mounting dir and make sure you have &amp;lt;code&amp;gt;mount&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;losetup&amp;lt;/code&amp;gt; available, Ubuntu based systems packages:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install util-linux mount&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Use losetup to attach image and scan its partitions ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo losetup --partscan --show --find NextZXOS.img&lt;br /&gt;
# this will print new loop device and automatically create partition devices like /dev/loop0p1&lt;br /&gt;
# now mount the desired FAT32 partition:&lt;br /&gt;
sudo mount /dev/loop0p1 next-card/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Unmounting and cleanup of loop device ===&lt;br /&gt;
&lt;br /&gt;
When finished:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo umount next-card/&lt;br /&gt;
sudo losetup -d /dev/loop0&lt;br /&gt;
# or `sudo losetup -D` to detach *ALL* loop devices&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This detaches the loop device and frees all associated /dev/loop* entries.&lt;br /&gt;
&lt;br /&gt;
Notes and gotchas:&lt;br /&gt;
* Do not use the image in an emulator while it is mounted.&lt;br /&gt;
* If the image has no partition table, --partscan will not create /dev/loop0p1.&lt;br /&gt;
* If multiple loop devices are active, check &amp;lt;code&amp;gt;losetup -a&amp;lt;/code&amp;gt; to confirm which one is yours.&lt;br /&gt;
&lt;br /&gt;
== Mounting sd‑card image with udisksctl ==&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;udisksctl&amp;lt;/code&amp;gt; tool provides a desktop‑friendly way to attach loop devices and mount filesystems without manually calculating offsets or using &amp;lt;code&amp;gt;losetup&amp;lt;/code&amp;gt;. It integrates with system services such as UDisks2, and on many desktop Linux systems it allows non‑root users (who are in the correct group) to mount images safely.&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
On Debian‑based systems install the UDisks2 tools:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install udisks2&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To run &amp;lt;code&amp;gt;udisksctl&amp;lt;/code&amp;gt; without &amp;lt;code&amp;gt;sudo&amp;lt;/code&amp;gt;, your user must belong to the &#039;&#039;&#039;disk&#039;&#039;&#039;, &#039;&#039;&#039;storage&#039;&#039;&#039;, or &#039;&#039;&#039;udisks&#039;&#039;&#039; policy group (varies by distribution). If unsure, simply use &amp;lt;code&amp;gt;sudo&amp;lt;/code&amp;gt; in the examples below.&lt;br /&gt;
&lt;br /&gt;
=== Attaching the image as a loop device ===&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;code&amp;gt;udisksctl loop-setup&amp;lt;/code&amp;gt; to create a loop device for the image:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;udisksctl loop-setup --file NextZXOS.img&lt;br /&gt;
# prints something like:&lt;br /&gt;
# Mapped file NextZXOS.img as /dev/loop2.&lt;br /&gt;
# UDisks automatically scans the partition table and exposes partitions as:&lt;br /&gt;
# /dev/loop2p1&lt;br /&gt;
# /dev/loop2p2&lt;br /&gt;
# ...&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Mounting the FAT32 partition ===&lt;br /&gt;
&lt;br /&gt;
Mount the desired partition:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;udisksctl mount --block-device /dev/loop2p1&lt;br /&gt;
# This prints the mount point, for example:&lt;br /&gt;
# Mounted /dev/loop2p1 at /media/youruser/NextZXOS.&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can now browse and edit the filesystem normally using your file manager or command‑line tools.&lt;br /&gt;
&lt;br /&gt;
=== Unmounting and cleanup ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;udisksctl unmount --block-device /dev/loop2p1&lt;br /&gt;
udisksctl loop-delete --block-device /dev/loop2&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This cleanly detaches the loop device and removes all &amp;lt;code&amp;gt;/dev/loop*&amp;lt;/code&amp;gt; entries created for the image.&lt;br /&gt;
&lt;br /&gt;
=== Notes and gotchas ===&lt;br /&gt;
&lt;br /&gt;
* Do not use the image in an emulator while it is mounted, parallel access may corrupt data.&lt;br /&gt;
* If the image has no partition table, UDisks will not create &#039;&#039;&#039;/dev/loopXp1&#039;&#039;&#039; and you must mount manually using an offset.&lt;br /&gt;
* Mount points are created under &amp;lt;code&amp;gt;/media/$USER/&amp;lt;/code&amp;gt; unless overridden by system policy.&lt;br /&gt;
* UDisks may auto‑mount partitions immediately after &#039;&#039;&#039;loop‑setup&#039;&#039;&#039; depending on desktop environment settings.&lt;br /&gt;
&lt;br /&gt;
== #CSpect emulator ==&lt;br /&gt;
&lt;br /&gt;
The #CSpect is Mike Dailly&#039;s ZX Spectrum Next emulator, written in C# making it cross-platform (sort of, where the mono framework is available). It is non-free (closed-source, custom license) project, but available for usage without any payment (it&#039;s possible to use it internally to develop also commercial titles, but you can not distribute/sell the emulator itself, not even packaged with your game - for such agreement contact the author first and get his permission).&lt;br /&gt;
&lt;br /&gt;
Currently it is most performant and user friendly emulator of ZX Spectrum Next, with good emulation accuracy (see [https://wiki.specnext.dev/CSpect:known_bugs CSpect:known_bugs] page for more detailed report).&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
On Debian based systems make sure you have these packages installed:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install mono-complete libopenal1 libsdl2-dev&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Retrieving the #CSpect package ===&lt;br /&gt;
&lt;br /&gt;
Use web browser to visit itch.io dedicated to CSpect project [https://mdf200.itch.io/cspect mdf200.itch.io/cspect] and download latest release.&lt;br /&gt;
&lt;br /&gt;
You may get warnings from your browser or antivirus about the page itself and about the zip/binary files. The #CSpect has long record of triggering false positives of AV engines due to the executable being not digitally signed and because of the code using features of OS which are normal for emulator, but may look wonky for AV heuristic. Whether you trust the executable is virus free is up to you, in the end.&lt;br /&gt;
&lt;br /&gt;
=== Installing the executable ===&lt;br /&gt;
&lt;br /&gt;
Unzip the retrieved zip file (I personally use KDE Dolphin file manager, the file context menu &#039;&#039;&amp;quot;Extract -&amp;gt; Extract archive here, autodetect subfolder&amp;quot;&#039;&#039;), and place the unzipped directory to target destination (&amp;lt;code&amp;gt;~/zx/emulators/CSpect/CSpect2_13_0&amp;lt;/code&amp;gt; in my case). I prefer to keep every version in its own directory, and have general symbolic link pointing to the one I want use by default:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;cd ~/zx/emulators/CSpect&lt;br /&gt;
ln -s CSpect2_13_0 CSpect_current&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then I create launcher bash-scripts in my &amp;lt;code&amp;gt;~/.local/bin&amp;lt;/code&amp;gt; like this (name of script &amp;lt;code&amp;gt;runCSpect&amp;lt;/code&amp;gt;):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;#!/bin/bash&lt;br /&gt;
# personal script of Ped to launch &amp;quot;#CSpect&amp;quot; emulator in &amp;quot;current directory&amp;quot; (with arguments like: &amp;quot;runCSpect file.nex&amp;quot;)&lt;br /&gt;
MONO_IOMAP=all mono ~/zx/emulators/CSpect/CSpect_current/CSpect.exe -tv -zxnext -s28 -w4 -mmc=./ &amp;quot;$@&amp;quot;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notes: I don&#039;t know any more what &amp;lt;code&amp;gt;MONO_IOMAP=all&amp;lt;/code&amp;gt; helps with, I believe it was suggested to help with any filesystem windows-like paths containing backslashes, you can try to do your own research. The &amp;lt;code&amp;gt;-tv&amp;lt;/code&amp;gt; switch will switch off &amp;quot;scanlines&amp;quot; shader effect and generally switch off any GPU shaders, which makes CSpect more compatible with graphics drivers (try it, if you get only black screen or instant crash during init). The &amp;lt;code&amp;gt;-w4&amp;lt;/code&amp;gt; will make the window quite large - 4x scale, the &amp;lt;code&amp;gt;-zxnext -s28&amp;lt;/code&amp;gt; switch #CSpect into ZX Next emulation mode and set 28Mhz speed of OS as default. And finally the &amp;lt;code&amp;gt;-mmc=./ &amp;quot;$@&amp;quot;&amp;lt;/code&amp;gt; will set &#039;&#039;current directory&#039;&#039; for esxdos emulation to the directory where you use the script to launch the emulator, and pass any remaining command line options entered by user, like the name of the SNA/NEX file. Other noteworthy options are &amp;lt;code&amp;gt;-debug -brk -map=file.map&amp;lt;/code&amp;gt;, the -debug entering the debugger just ahead of the first instruction, -brk enables CSpect specific two-byte tag 0xDD 0x01 to work as breakpoint and the -map option allows you to load into debugger the symbol table from your assembler (directive CSPECTMAP in sjasmplus), making labels visible in disassembly.&lt;br /&gt;
&lt;br /&gt;
=== Checking if it all works ===&lt;br /&gt;
&lt;br /&gt;
Go to some directory with SNA/SNX/NEX file (there are also some demo files right in the CSpect directory) and use the launcher script, like:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;runCSpect beast.nex&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see #CSpect emulator window running the beast.nex demo (or whatever else you did want to launch and entered as argument).&lt;br /&gt;
&lt;br /&gt;
[[File:Cspect_test_run.png|frameless|Running CSpect from directory with test snapshots]]&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=Development_Tools:Linux_setup&amp;diff=41779</id>
		<title>Development Tools:Linux setup</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=Development_Tools:Linux_setup&amp;diff=41779"/>
		<updated>2026-01-21T15:59:28Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: adding mount card with losetup&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== General ==&lt;br /&gt;
&lt;br /&gt;
This page collects summaries of installation process of various tools related to ZX Spectrum Next software development for linux OS users.&lt;br /&gt;
&lt;br /&gt;
As usual with linux, most of the suggestions are in the form of command line command to be used from terminal.&lt;br /&gt;
&lt;br /&gt;
== sjasmplus assembler ==&lt;br /&gt;
&lt;br /&gt;
You can also check the [https://www.youtube.com/watch?v=c6I4kdErEwE video] of installing sjasmplus on freshly reinstalled KDE neon 5.20 linux, where is also extended info how to run the automated tests of sjasmplus, and opening it in KDevelop IDE to eventually write your own modifications.&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
On Debian based systems make sure you have these packages installed (git-cola and cmake are optional, but often handy):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install git build-essential g++ git-cola cmake&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Retrieving the sjasmplus source ===&lt;br /&gt;
&lt;br /&gt;
Use git to clone the [https://github.com/z00m128/sjasmplus z00m&#039;s sjasmplus repository]:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;git clone --recursive -j8 https://github.com/z00m128/sjasmplus.git&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To update already cloned repository, do inside the sjasmplus folder:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;git pull&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
- or use your favourite GIT client app to update the cloned repository.&lt;br /&gt;
&lt;br /&gt;
=== Building the executable binary ===&lt;br /&gt;
&lt;br /&gt;
The GNU make and common C++ compiler (gcc or clang) should be enough to build the binary:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;make clean &amp;amp;&amp;amp; make&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To verify the binary was built (&amp;quot;dot slash&amp;quot; prefix to force running of binary in current folder, not system one):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;./sjasmplus --version&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Installing the executable ===&lt;br /&gt;
&lt;br /&gt;
If you already have sjasmplus installed, use &amp;lt;code&amp;gt;which sjasmplus&amp;lt;/code&amp;gt; to see where the installed executable is (and which installed executable has precedence), you can use this command also after installing the new executable to verify it is being picked up by the system.&lt;br /&gt;
&lt;br /&gt;
Installing the binary in system-wide fashion:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo make install&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or you can install the binary only locally for your user (without root/sudo permissions):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;mkdir -p ~/.local/bin&lt;br /&gt;
make PREFIX=~/.local install&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
- then make sure you have &amp;lt;code&amp;gt;~/.local/bin&amp;lt;/code&amp;gt; in your user &amp;lt;code&amp;gt;PATH&amp;lt;/code&amp;gt; environment variable (on some distros there is already script in .profile to add this to PATH if the dir does exist, so you may need to only logout/restart after creating it to get it active).&lt;br /&gt;
&lt;br /&gt;
=== Checking if it all works ===&lt;br /&gt;
&lt;br /&gt;
Open your terminal and type (in any directory):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sjasmplus --version&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see version of the freshly built sjasmplus executable like this:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;SjASMPlus Z80 Cross-Assembler v1.17.0 (https://github.com/z00m128/sjasmplus)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== hdfmonkey tool ==&lt;br /&gt;
&lt;br /&gt;
The hdfmonkey tool can manipulate card-images, helping to write new builds of your project into NextZXOS card-image, to boot the emulators with full file system. (it&#039;s also possible to mount the images directly into linux by other means, to operate on them with regular file manager/etc, but hdfmonkey suits better use-case when the build script does update the image)&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
On Debian based systems make sure you have these packages installed:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install git build-essential g++ autoconf&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Retrieving the hdfmonkey source ===&lt;br /&gt;
&lt;br /&gt;
Use git to clone the [https://github.com/ped7g/hdfmonkey hdfmonkey repository with patched 0.5.7 &amp;lt;code&amp;gt;jjjs version&amp;lt;/code&amp;gt; sources]:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;git clone https://github.com/ped7g/hdfmonkey.git&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
(make sure you are on the default branch &amp;lt;code&amp;gt;&amp;quot;jjjs-variant&amp;quot;&amp;lt;/code&amp;gt; to build the improved version, it should be checked out by default after clone)&lt;br /&gt;
&lt;br /&gt;
* to update already cloned repository, do inside the hdfmonkey folder:&lt;br /&gt;
  &amp;lt;nowiki&amp;gt;git pull&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
* or use your favourite GIT client app to update the cloned repository.&lt;br /&gt;
* if you cloned original gasman&#039;s repository before, you may want to clone and rebuild here mentioned &amp;lt;code&amp;gt;jjjs version&amp;lt;/code&amp;gt; to get multiple fixes and convenience features.&lt;br /&gt;
&lt;br /&gt;
=== Building the executable binary ===&lt;br /&gt;
&lt;br /&gt;
The hdfmonkey is using autoconf/autotools to build final Makefile, check the hdfmonkey README for &amp;quot;from git&amp;quot; installation notes, at the moment of writing this page, the steps were:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;cd hdfmonkey&lt;br /&gt;
autoheader&lt;br /&gt;
aclocal&lt;br /&gt;
autoconf&lt;br /&gt;
automake -a&lt;br /&gt;
./configure&lt;br /&gt;
make&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To verify the binary was built:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;src/hdfmonkey help&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Installing the executable ===&lt;br /&gt;
&lt;br /&gt;
If you already have hdfmonkey installed, use &amp;lt;code&amp;gt;which hdfmonkey&amp;lt;/code&amp;gt; to see where the installed executable is (and which installed executable has precedence), you can use this command also after installing the new executable to verify it is being picked up by the system.&lt;br /&gt;
&lt;br /&gt;
Installing the binary in system-wide fashion:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo make install&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or you can install the binary only locally for your user (without root/sudo permissions):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;make prefix=~/.local install&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
- then make sure you have &amp;lt;code&amp;gt;~/.local/bin&amp;lt;/code&amp;gt; in your user &amp;lt;code&amp;gt;PATH&amp;lt;/code&amp;gt; environment variable.&lt;br /&gt;
&lt;br /&gt;
=== Checking if it all works ===&lt;br /&gt;
&lt;br /&gt;
Open your terminal and type (in any directory):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;hdfmonkey help&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see help of the freshly built hdfmonkey `jjjs version` executable like this:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;hdfmonkey: utility for manipulating HDF disk images v0.5.7 jjjs&lt;br /&gt;
&lt;br /&gt;
usage: hdfmonkey &amp;lt;command&amp;gt; [args]&lt;br /&gt;
...&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Extracting all files from the sd-card image ==&lt;br /&gt;
&lt;br /&gt;
7-zip is the most convenient tool to extract the the files from the existing image.&lt;br /&gt;
&lt;br /&gt;
To install 7-zip on a Debian system use &amp;lt;code&amp;gt;sudo apt install 7zip&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To extract all the files from an existing image &amp;lt;code&amp;gt;tbblue.img&amp;lt;/code&amp;gt; to a new subdirectory &amp;lt;code&amp;gt;myfiles&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;7z x tbblue.img -omyfiles&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Creating new sd-card image with hdfmonkey ==&lt;br /&gt;
&lt;br /&gt;
This example: &lt;br /&gt;
&lt;br /&gt;
* downloads the archive from the specnext.com&lt;br /&gt;
* unpacks it to the subdirectory &amp;lt;code&amp;gt;tmptb&amp;lt;/code&amp;gt;&lt;br /&gt;
* creates a new SD image (with the space for 2GB files) from all the files&lt;br /&gt;
* deletes the subdirectory &amp;lt;code&amp;gt;tmptb&amp;lt;/code&amp;gt;&lt;br /&gt;
* shows that the new image uses much less than 2GB&lt;br /&gt;
* starts listing the content of the newly created image&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
wget https://www.specnext.com/distro/24.11/sn-complete-24.11.zip&lt;br /&gt;
7z x sn-complete-24.11.zip -otmptb&lt;br /&gt;
hdfmonkey create tbblue.img 2GB&lt;br /&gt;
hdfmonkey putdir tbblue.img tmptb /  &lt;br /&gt;
rm -rf tmptb&lt;br /&gt;
du -h tbblue.img&lt;br /&gt;
7z l tbblue.img | more&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating new sd-card image without hdfmonkey ===&lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to use gnu coreutils and dosfstools to create card image without hdfmonkey, but depending on exact size of image these may be less compatible with various emulator, following example for 1GB card image works in MAME but fails in CSpect (while images created by hdfmonkey tool should work for both emulator, so using &#039;&#039;&#039;hdfmonkey is recommended&#039;&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
truncate -s 1G NextZXOS.img&lt;br /&gt;
parted NextZXOS.img mklabel msdos&lt;br /&gt;
parted NextZXOS.img mkpart primary fat32 2048s 100%&lt;br /&gt;
mkfs.fat -F 32 --offset=2048 NextZXOS.img&lt;br /&gt;
# and now to copy files to image you have to either mount it or use hdfmonkey:&lt;br /&gt;
# hdfmonkey putdir NextZXOS.img tmptb /&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mounting sd-card image directly ==&lt;br /&gt;
&lt;br /&gt;
Sometimes it may be useful to mount the card image directly, to be able to browse it and manipulate with common tools. But make sure you are not using mounted card image also in emulator at the same time, to prevent any data damage by parallel access.&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
On Debian based systems make sure you have these packages installed:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install fdisk mount&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Prepare empty directory to mount the card image into (let&#039;s call it &amp;quot;next-card&amp;quot;) and have the image file around (&amp;quot;tbblue.mmc&amp;quot; in following examples)&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;mkdir -p next-card&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Mounting the card image ===&lt;br /&gt;
&lt;br /&gt;
To mount the card image you need to know the exact byte-offset where the FAT partition starts, it&#039;s possible to read it from &amp;quot;fdisk&amp;quot; or &amp;quot;parted&amp;quot; tools outputs:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;fdisk -l -o Start tbblue.mmc&lt;br /&gt;
# prints value in sector units, like:&lt;br /&gt;
# Start&lt;br /&gt;
#    63&lt;br /&gt;
# This has to be multiplied by 512 to get byte offset: 63*512 = 32256&lt;br /&gt;
&lt;br /&gt;
# or&lt;br /&gt;
&lt;br /&gt;
parted tbblue.mmc unit B print&lt;br /&gt;
# prints values in bytes with &amp;quot;B&amp;quot; suffix in &amp;quot;Start&amp;quot; column&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
But the fdisk output can be incorporated directly into mount command, which needs root permissions, example with sudo:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo mount tbblue.mmc next-card/ -o loop,offset=$((`fdisk -l -o Start tbblue.mmc | tail -1` * 512)),user,uid=`id -u`,gid=`id -g`&lt;br /&gt;
&lt;br /&gt;
# or you can enter the offset yourself&lt;br /&gt;
&lt;br /&gt;
sudo mount tbblue.mmc next-card/ -o loop,offset=32256,user,uid=`id -u`,gid=`id -g`&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The uid and gid options will mount the filesystem under your regular user, so you can now browse it with file manager, text editors, etc.&lt;br /&gt;
&lt;br /&gt;
Do not run the emulator yet, before unmounting the image (after you are done manipulating the files)!&lt;br /&gt;
&lt;br /&gt;
=== Unmount the image before using it in emulator ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo umount next-card/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Check the result. If the unmounting fails (probably with &amp;quot;target is busy&amp;quot;), find which process is still accessing/viewing the files in the next-card directory, and try to unmount it again.&lt;br /&gt;
&lt;br /&gt;
== Mounting sd-card image with losetup ==&lt;br /&gt;
&lt;br /&gt;
Alternative using losetup to use local &amp;quot;loop&amp;quot; device for mounting the image. This method can automatically detect partitions inside the image and exposes them as loop devices.&lt;br /&gt;
&lt;br /&gt;
Prepare mounting dir and make sure you have &amp;lt;code&amp;gt;mount&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;losetup&amp;lt;/code&amp;gt; available, Ubuntu based systems packages:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install util-linux mount&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Use losetup to attach image and scan its partitions ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo losetup --partscan --show --find NextZXOS.img&lt;br /&gt;
# this will print new loop device and automatically create partition devices like /dev/loop0p1&lt;br /&gt;
# now mount the desired FAT32 partition:&lt;br /&gt;
sudo mount /dev/loop0p1 next-card/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Unmounting and cleanup of loop device ===&lt;br /&gt;
&lt;br /&gt;
When finished:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo umount next-card/&lt;br /&gt;
sudo losetup -D&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This detaches the loop device and frees all associated /dev/loop* entries.&lt;br /&gt;
&lt;br /&gt;
Notes and gotchas:&lt;br /&gt;
* Do not use the image in an emulator while it is mounted.&lt;br /&gt;
* If the image has no partition table, --partscan will not create /dev/loop0p1.&lt;br /&gt;
* If multiple loop devices are active, check losetup -a to confirm which one is yours.&lt;br /&gt;
&lt;br /&gt;
=== TODO: udiskctl loop device mounting option ===&lt;br /&gt;
&lt;br /&gt;
From discord: &amp;quot;udisksctl loop-setup --file ~/spec/SpectrumNext/tbblue/image/tbblue.mmc&amp;quot;&lt;br /&gt;
&lt;br /&gt;
TODO: describe this solution and check possible gotchas/CLI options (like user must be in udiskctl group to run this without sudo, etc).&lt;br /&gt;
&lt;br /&gt;
== #CSpect emulator ==&lt;br /&gt;
&lt;br /&gt;
The #CSpect is Mike Dailly&#039;s ZX Spectrum Next emulator, written in C# making it cross-platform (sort of, where the mono framework is available). It is non-free (closed-source, custom license) project, but available for usage without any payment (it&#039;s possible to use it internally to develop also commercial titles, but you can not distribute/sell the emulator itself, not even packaged with your game - for such agreement contact the author first and get his permission).&lt;br /&gt;
&lt;br /&gt;
Currently it is most performant and user friendly emulator of ZX Spectrum Next, with good emulation accuracy (see [https://wiki.specnext.dev/CSpect:known_bugs CSpect:known_bugs] page for more detailed report).&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
On Debian based systems make sure you have these packages installed:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install mono-complete libopenal1 libsdl2-dev&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Retrieving the #CSpect package ===&lt;br /&gt;
&lt;br /&gt;
Use web browser to visit itch.io dedicated to CSpect project [https://mdf200.itch.io/cspect mdf200.itch.io/cspect] and download latest release.&lt;br /&gt;
&lt;br /&gt;
You may get warnings from your browser or antivirus about the page itself and about the zip/binary files. The #CSpect has long record of triggering false positives of AV engines due to the executable being not digitally signed and because of the code using features of OS which are normal for emulator, but may look wonky for AV heuristic. Whether you trust the executable is virus free is up to you, in the end.&lt;br /&gt;
&lt;br /&gt;
=== Installing the executable ===&lt;br /&gt;
&lt;br /&gt;
Unzip the retrieved zip file (I personally use KDE Dolphin file manager, the file context menu &#039;&#039;&amp;quot;Extract -&amp;gt; Extract archive here, autodetect subfolder&amp;quot;&#039;&#039;), and place the unzipped directory to target destination (&amp;lt;code&amp;gt;~/zx/emulators/CSpect/CSpect2_13_0&amp;lt;/code&amp;gt; in my case). I prefer to keep every version in its own directory, and have general symbolic link pointing to the one I want use by default:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;cd ~/zx/emulators/CSpect&lt;br /&gt;
ln -s CSpect2_13_0 CSpect_current&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then I create launcher bash-scripts in my &amp;lt;code&amp;gt;~/.local/bin&amp;lt;/code&amp;gt; like this (name of script &amp;lt;code&amp;gt;runCSpect&amp;lt;/code&amp;gt;):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;#!/bin/bash&lt;br /&gt;
# personal script of Ped to launch &amp;quot;#CSpect&amp;quot; emulator in &amp;quot;current directory&amp;quot; (with arguments like: &amp;quot;runCSpect file.nex&amp;quot;)&lt;br /&gt;
MONO_IOMAP=all mono ~/zx/emulators/CSpect/CSpect_current/CSpect.exe -tv -zxnext -s28 -w4 -mmc=./ &amp;quot;$@&amp;quot;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notes: I don&#039;t know any more what &amp;lt;code&amp;gt;MONO_IOMAP=all&amp;lt;/code&amp;gt; helps with, I believe it was suggested to help with any filesystem windows-like paths containing backslashes, you can try to do your own research. The &amp;lt;code&amp;gt;-tv&amp;lt;/code&amp;gt; switch will switch off &amp;quot;scanlines&amp;quot; shader effect and generally switch off any GPU shaders, which makes CSpect more compatible with graphics drivers (try it, if you get only black screen or instant crash during init). The &amp;lt;code&amp;gt;-w4&amp;lt;/code&amp;gt; will make the window quite large - 4x scale, the &amp;lt;code&amp;gt;-zxnext -s28&amp;lt;/code&amp;gt; switch #CSpect into ZX Next emulation mode and set 28Mhz speed of OS as default. And finally the &amp;lt;code&amp;gt;-mmc=./ &amp;quot;$@&amp;quot;&amp;lt;/code&amp;gt; will set &#039;&#039;current directory&#039;&#039; for esxdos emulation to the directory where you use the script to launch the emulator, and pass any remaining command line options entered by user, like the name of the SNA/NEX file. Other noteworthy options are &amp;lt;code&amp;gt;-debug -brk -map=file.map&amp;lt;/code&amp;gt;, the -debug entering the debugger just ahead of the first instruction, -brk enables CSpect specific two-byte tag 0xDD 0x01 to work as breakpoint and the -map option allows you to load into debugger the symbol table from your assembler (directive CSPECTMAP in sjasmplus), making labels visible in disassembly.&lt;br /&gt;
&lt;br /&gt;
=== Checking if it all works ===&lt;br /&gt;
&lt;br /&gt;
Go to some directory with SNA/SNX/NEX file (there are also some demo files right in the CSpect directory) and use the launcher script, like:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;runCSpect beast.nex&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see #CSpect emulator window running the beast.nex demo (or whatever else you did want to launch and entered as argument).&lt;br /&gt;
&lt;br /&gt;
[[File:Cspect_test_run.png|frameless|Running CSpect from directory with test snapshots]]&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=Development_Tools:Linux_setup&amp;diff=41778</id>
		<title>Development Tools:Linux setup</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=Development_Tools:Linux_setup&amp;diff=41778"/>
		<updated>2026-01-21T00:00:13Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: adding alternative way to create card image documenting compatibility caveat&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== General ==&lt;br /&gt;
&lt;br /&gt;
This page collects summaries of installation process of various tools related to ZX Spectrum Next software development for linux OS users.&lt;br /&gt;
&lt;br /&gt;
As usual with linux, most of the suggestions are in the form of command line command to be used from terminal.&lt;br /&gt;
&lt;br /&gt;
== sjasmplus assembler ==&lt;br /&gt;
&lt;br /&gt;
You can also check the [https://www.youtube.com/watch?v=c6I4kdErEwE video] of installing sjasmplus on freshly reinstalled KDE neon 5.20 linux, where is also extended info how to run the automated tests of sjasmplus, and opening it in KDevelop IDE to eventually write your own modifications.&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
On Debian based systems make sure you have these packages installed (git-cola and cmake are optional, but often handy):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install git build-essential g++ git-cola cmake&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Retrieving the sjasmplus source ===&lt;br /&gt;
&lt;br /&gt;
Use git to clone the [https://github.com/z00m128/sjasmplus z00m&#039;s sjasmplus repository]:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;git clone --recursive -j8 https://github.com/z00m128/sjasmplus.git&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To update already cloned repository, do inside the sjasmplus folder:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;git pull&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
- or use your favourite GIT client app to update the cloned repository.&lt;br /&gt;
&lt;br /&gt;
=== Building the executable binary ===&lt;br /&gt;
&lt;br /&gt;
The GNU make and common C++ compiler (gcc or clang) should be enough to build the binary:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;make clean &amp;amp;&amp;amp; make&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To verify the binary was built (&amp;quot;dot slash&amp;quot; prefix to force running of binary in current folder, not system one):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;./sjasmplus --version&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Installing the executable ===&lt;br /&gt;
&lt;br /&gt;
If you already have sjasmplus installed, use &amp;lt;code&amp;gt;which sjasmplus&amp;lt;/code&amp;gt; to see where the installed executable is (and which installed executable has precedence), you can use this command also after installing the new executable to verify it is being picked up by the system.&lt;br /&gt;
&lt;br /&gt;
Installing the binary in system-wide fashion:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo make install&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or you can install the binary only locally for your user (without root/sudo permissions):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;mkdir -p ~/.local/bin&lt;br /&gt;
make PREFIX=~/.local install&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
- then make sure you have &amp;lt;code&amp;gt;~/.local/bin&amp;lt;/code&amp;gt; in your user &amp;lt;code&amp;gt;PATH&amp;lt;/code&amp;gt; environment variable (on some distros there is already script in .profile to add this to PATH if the dir does exist, so you may need to only logout/restart after creating it to get it active).&lt;br /&gt;
&lt;br /&gt;
=== Checking if it all works ===&lt;br /&gt;
&lt;br /&gt;
Open your terminal and type (in any directory):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sjasmplus --version&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see version of the freshly built sjasmplus executable like this:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;SjASMPlus Z80 Cross-Assembler v1.17.0 (https://github.com/z00m128/sjasmplus)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== hdfmonkey tool ==&lt;br /&gt;
&lt;br /&gt;
The hdfmonkey tool can manipulate card-images, helping to write new builds of your project into NextZXOS card-image, to boot the emulators with full file system. (it&#039;s also possible to mount the images directly into linux by other means, to operate on them with regular file manager/etc, but hdfmonkey suits better use-case when the build script does update the image)&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
On Debian based systems make sure you have these packages installed:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install git build-essential g++ autoconf&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Retrieving the hdfmonkey source ===&lt;br /&gt;
&lt;br /&gt;
Use git to clone the [https://github.com/ped7g/hdfmonkey hdfmonkey repository with patched 0.5.7 &amp;lt;code&amp;gt;jjjs version&amp;lt;/code&amp;gt; sources]:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;git clone https://github.com/ped7g/hdfmonkey.git&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
(make sure you are on the default branch &amp;lt;code&amp;gt;&amp;quot;jjjs-variant&amp;quot;&amp;lt;/code&amp;gt; to build the improved version, it should be checked out by default after clone)&lt;br /&gt;
&lt;br /&gt;
* to update already cloned repository, do inside the hdfmonkey folder:&lt;br /&gt;
  &amp;lt;nowiki&amp;gt;git pull&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
* or use your favourite GIT client app to update the cloned repository.&lt;br /&gt;
* if you cloned original gasman&#039;s repository before, you may want to clone and rebuild here mentioned &amp;lt;code&amp;gt;jjjs version&amp;lt;/code&amp;gt; to get multiple fixes and convenience features.&lt;br /&gt;
&lt;br /&gt;
=== Building the executable binary ===&lt;br /&gt;
&lt;br /&gt;
The hdfmonkey is using autoconf/autotools to build final Makefile, check the hdfmonkey README for &amp;quot;from git&amp;quot; installation notes, at the moment of writing this page, the steps were:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;cd hdfmonkey&lt;br /&gt;
autoheader&lt;br /&gt;
aclocal&lt;br /&gt;
autoconf&lt;br /&gt;
automake -a&lt;br /&gt;
./configure&lt;br /&gt;
make&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To verify the binary was built:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;src/hdfmonkey help&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Installing the executable ===&lt;br /&gt;
&lt;br /&gt;
If you already have hdfmonkey installed, use &amp;lt;code&amp;gt;which hdfmonkey&amp;lt;/code&amp;gt; to see where the installed executable is (and which installed executable has precedence), you can use this command also after installing the new executable to verify it is being picked up by the system.&lt;br /&gt;
&lt;br /&gt;
Installing the binary in system-wide fashion:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo make install&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or you can install the binary only locally for your user (without root/sudo permissions):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;make prefix=~/.local install&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
- then make sure you have &amp;lt;code&amp;gt;~/.local/bin&amp;lt;/code&amp;gt; in your user &amp;lt;code&amp;gt;PATH&amp;lt;/code&amp;gt; environment variable.&lt;br /&gt;
&lt;br /&gt;
=== Checking if it all works ===&lt;br /&gt;
&lt;br /&gt;
Open your terminal and type (in any directory):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;hdfmonkey help&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see help of the freshly built hdfmonkey `jjjs version` executable like this:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;hdfmonkey: utility for manipulating HDF disk images v0.5.7 jjjs&lt;br /&gt;
&lt;br /&gt;
usage: hdfmonkey &amp;lt;command&amp;gt; [args]&lt;br /&gt;
...&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Extracting all files from the sd-card image ==&lt;br /&gt;
&lt;br /&gt;
7-zip is the most convenient tool to extract the the files from the existing image.&lt;br /&gt;
&lt;br /&gt;
To install 7-zip on a Debian system use &amp;lt;code&amp;gt;sudo apt install 7zip&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To extract all the files from an existing image &amp;lt;code&amp;gt;tbblue.img&amp;lt;/code&amp;gt; to a new subdirectory &amp;lt;code&amp;gt;myfiles&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;7z x tbblue.img -omyfiles&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Creating new sd-card image with hdfmonkey ==&lt;br /&gt;
&lt;br /&gt;
This example: &lt;br /&gt;
&lt;br /&gt;
* downloads the archive from the specnext.com&lt;br /&gt;
* unpacks it to the subdirectory &amp;lt;code&amp;gt;tmptb&amp;lt;/code&amp;gt;&lt;br /&gt;
* creates a new SD image (with the space for 2GB files) from all the files&lt;br /&gt;
* deletes the subdirectory &amp;lt;code&amp;gt;tmptb&amp;lt;/code&amp;gt;&lt;br /&gt;
* shows that the new image uses much less than 2GB&lt;br /&gt;
* starts listing the content of the newly created image&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
wget https://www.specnext.com/distro/24.11/sn-complete-24.11.zip&lt;br /&gt;
7z x sn-complete-24.11.zip -otmptb&lt;br /&gt;
hdfmonkey create tbblue.img 2GB&lt;br /&gt;
hdfmonkey putdir tbblue.img tmptb /  &lt;br /&gt;
rm -rf tmptb&lt;br /&gt;
du -h tbblue.img&lt;br /&gt;
7z l tbblue.img | more&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating new sd-card image without hdfmonkey ===&lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to use gnu coreutils and dosfstools to create card image without hdfmonkey, but depending on exact size of image these may be less compatible with various emulator, following example for 1GB card image works in MAME but fails in CSpect (while images created by hdfmonkey tool should work for both emulator, so using &#039;&#039;&#039;hdfmonkey is recommended&#039;&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
truncate -s 1G NextZXOS.img&lt;br /&gt;
parted NextZXOS.img mklabel msdos&lt;br /&gt;
parted NextZXOS.img mkpart primary fat32 2048s 100%&lt;br /&gt;
mkfs.fat -F 32 --offset=2048 NextZXOS.img&lt;br /&gt;
# and now to copy files to image you have to either mount it or use hdfmonkey:&lt;br /&gt;
# hdfmonkey putdir NextZXOS.img tmptb /&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mounting sd-card image directly ==&lt;br /&gt;
&lt;br /&gt;
Sometimes it may be useful to mount the card image directly, to be able to browse it and manipulate with common tools. But make sure you are not using mounted card image also in emulator at the same time, to prevent any data damage by parallel access.&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
On Debian based systems make sure you have these packages installed:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install fdisk mount&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Prepare empty directory to mount the card image into (let&#039;s call it &amp;quot;next-card&amp;quot;) and have the image file around (&amp;quot;tbblue.mmc&amp;quot; in following examples)&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;mkdir -p next-card&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Mounting the card image ===&lt;br /&gt;
&lt;br /&gt;
To mount the card image you need to know the exact byte-offset where the FAT partition starts, it&#039;s possible to read it from &amp;quot;fdisk&amp;quot; or &amp;quot;parted&amp;quot; tools outputs:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;fdisk -l -o Start tbblue.mmc&lt;br /&gt;
# prints value in sector units, like:&lt;br /&gt;
# Start&lt;br /&gt;
#    63&lt;br /&gt;
# This has to be multiplied by 512 to get byte offset: 63*512 = 32256&lt;br /&gt;
&lt;br /&gt;
# or&lt;br /&gt;
&lt;br /&gt;
parted tbblue.mmc unit B print&lt;br /&gt;
# prints values in bytes with &amp;quot;B&amp;quot; suffix in &amp;quot;Start&amp;quot; column&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
But the fdisk output can be incorporated directly into mount command, which needs root permissions, example with sudo:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo mount tbblue.mmc next-card/ -o loop,offset=$((`fdisk -l -o Start tbblue.mmc | tail -1` * 512)),user,uid=`id -u`,gid=`id -g`&lt;br /&gt;
&lt;br /&gt;
# or you can enter the offset yourself&lt;br /&gt;
&lt;br /&gt;
sudo mount tbblue.mmc next-card/ -o loop,offset=32256,user,uid=`id -u`,gid=`id -g`&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The uid and gid options will mount the filesystem under your regular user, so you can now browse it with file manager, text editors, etc.&lt;br /&gt;
&lt;br /&gt;
Do not run the emulator yet, before unmounting the image (after you are done manipulating the files)!&lt;br /&gt;
&lt;br /&gt;
=== Unmount the image before using it in emulator ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo umount next-card/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Check the result. If the unmounting fails (probably with &amp;quot;target is busy&amp;quot;), find which process is still accessing/viewing the files in the next-card directory, and try to unmount it again.&lt;br /&gt;
&lt;br /&gt;
=== TODO: udiskctl loop device mounting option ===&lt;br /&gt;
&lt;br /&gt;
From discord: &amp;quot;udisksctl loop-setup --file ~/spec/SpectrumNext/tbblue/image/tbblue.mmc&amp;quot;&lt;br /&gt;
&lt;br /&gt;
TODO: describe this solution and check possible gotchas/CLI options (like user must be in udiskctl group to run this without sudo, etc).&lt;br /&gt;
&lt;br /&gt;
== #CSpect emulator ==&lt;br /&gt;
&lt;br /&gt;
The #CSpect is Mike Dailly&#039;s ZX Spectrum Next emulator, written in C# making it cross-platform (sort of, where the mono framework is available). It is non-free (closed-source, custom license) project, but available for usage without any payment (it&#039;s possible to use it internally to develop also commercial titles, but you can not distribute/sell the emulator itself, not even packaged with your game - for such agreement contact the author first and get his permission).&lt;br /&gt;
&lt;br /&gt;
Currently it is most performant and user friendly emulator of ZX Spectrum Next, with good emulation accuracy (see [https://wiki.specnext.dev/CSpect:known_bugs CSpect:known_bugs] page for more detailed report).&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
On Debian based systems make sure you have these packages installed:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install mono-complete libopenal1 libsdl2-dev&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Retrieving the #CSpect package ===&lt;br /&gt;
&lt;br /&gt;
Use web browser to visit itch.io dedicated to CSpect project [https://mdf200.itch.io/cspect mdf200.itch.io/cspect] and download latest release.&lt;br /&gt;
&lt;br /&gt;
You may get warnings from your browser or antivirus about the page itself and about the zip/binary files. The #CSpect has long record of triggering false positives of AV engines due to the executable being not digitally signed and because of the code using features of OS which are normal for emulator, but may look wonky for AV heuristic. Whether you trust the executable is virus free is up to you, in the end.&lt;br /&gt;
&lt;br /&gt;
=== Installing the executable ===&lt;br /&gt;
&lt;br /&gt;
Unzip the retrieved zip file (I personally use KDE Dolphin file manager, the file context menu &#039;&#039;&amp;quot;Extract -&amp;gt; Extract archive here, autodetect subfolder&amp;quot;&#039;&#039;), and place the unzipped directory to target destination (&amp;lt;code&amp;gt;~/zx/emulators/CSpect/CSpect2_13_0&amp;lt;/code&amp;gt; in my case). I prefer to keep every version in its own directory, and have general symbolic link pointing to the one I want use by default:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;cd ~/zx/emulators/CSpect&lt;br /&gt;
ln -s CSpect2_13_0 CSpect_current&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then I create launcher bash-scripts in my &amp;lt;code&amp;gt;~/.local/bin&amp;lt;/code&amp;gt; like this (name of script &amp;lt;code&amp;gt;runCSpect&amp;lt;/code&amp;gt;):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;#!/bin/bash&lt;br /&gt;
# personal script of Ped to launch &amp;quot;#CSpect&amp;quot; emulator in &amp;quot;current directory&amp;quot; (with arguments like: &amp;quot;runCSpect file.nex&amp;quot;)&lt;br /&gt;
MONO_IOMAP=all mono ~/zx/emulators/CSpect/CSpect_current/CSpect.exe -tv -zxnext -s28 -w4 -mmc=./ &amp;quot;$@&amp;quot;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notes: I don&#039;t know any more what &amp;lt;code&amp;gt;MONO_IOMAP=all&amp;lt;/code&amp;gt; helps with, I believe it was suggested to help with any filesystem windows-like paths containing backslashes, you can try to do your own research. The &amp;lt;code&amp;gt;-tv&amp;lt;/code&amp;gt; switch will switch off &amp;quot;scanlines&amp;quot; shader effect and generally switch off any GPU shaders, which makes CSpect more compatible with graphics drivers (try it, if you get only black screen or instant crash during init). The &amp;lt;code&amp;gt;-w4&amp;lt;/code&amp;gt; will make the window quite large - 4x scale, the &amp;lt;code&amp;gt;-zxnext -s28&amp;lt;/code&amp;gt; switch #CSpect into ZX Next emulation mode and set 28Mhz speed of OS as default. And finally the &amp;lt;code&amp;gt;-mmc=./ &amp;quot;$@&amp;quot;&amp;lt;/code&amp;gt; will set &#039;&#039;current directory&#039;&#039; for esxdos emulation to the directory where you use the script to launch the emulator, and pass any remaining command line options entered by user, like the name of the SNA/NEX file. Other noteworthy options are &amp;lt;code&amp;gt;-debug -brk -map=file.map&amp;lt;/code&amp;gt;, the -debug entering the debugger just ahead of the first instruction, -brk enables CSpect specific two-byte tag 0xDD 0x01 to work as breakpoint and the -map option allows you to load into debugger the symbol table from your assembler (directive CSPECTMAP in sjasmplus), making labels visible in disassembly.&lt;br /&gt;
&lt;br /&gt;
=== Checking if it all works ===&lt;br /&gt;
&lt;br /&gt;
Go to some directory with SNA/SNX/NEX file (there are also some demo files right in the CSpect directory) and use the launcher script, like:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;runCSpect beast.nex&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see #CSpect emulator window running the beast.nex demo (or whatever else you did want to launch and entered as argument).&lt;br /&gt;
&lt;br /&gt;
[[File:Cspect_test_run.png|frameless|Running CSpect from directory with test snapshots]]&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=Assemblers&amp;diff=41776</id>
		<title>Assemblers</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=Assemblers&amp;diff=41776"/>
		<updated>2026-01-16T19:57:30Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: bump sj stable version&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Any Z80 assembler can produce code suitable for the Next. However the raw blocks of Z80 code may be not as convenient to use with Next or emulators, so a Next specific tools may be useful for creating one of the supported [[File Formats]].&lt;br /&gt;
&lt;br /&gt;
== Cross-platform tools (running on PC) ==&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[http://www.desdes.com/products/oldfiles/zeus.htm Zeus-ish]&#039;&#039; ===&lt;br /&gt;
: Provides a complete Z80 IDE and Macro assembler, scripted disassember plus an integrated Z80 emulator for a range of machines including partial Next support&lt;br /&gt;
: Supports the Next opcodes directly&lt;br /&gt;
: Supports remote debugging on the Next using ParaSys across a serial link&lt;br /&gt;
: Supports MMU paging in the integrated emulator&lt;br /&gt;
: Supports sprites (core versions prior to 2.00.26) in the integrated emulator&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[http://pasmo.speccy.org/ Pasmo]&#039;&#039; ===&lt;br /&gt;
: A long established Z80 assembler, but has been out of development for a long time&lt;br /&gt;
: Supports all currently known Next extension opcodes through this [https://www.facebook.com/groups/specnext/512169722473686/ modified Pasmo from Russ McNulty and Tony Thompson] and also now supports outputting .sna files to use with CSpect, thanks to Russ McNulty&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;SNasm&#039;&#039; ===&lt;br /&gt;
Included with the [https://mdf200.itch.io/cspect #CSpect] emulator&lt;br /&gt;
: Full macro assembler&lt;br /&gt;
: Full bank control via Segment management&lt;br /&gt;
: Supports the Next extension opcodes directly&lt;br /&gt;
: Generates full 24bit map files for use in CSpect&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;z80asm&#039;&#039; ===&lt;br /&gt;
Part of [https://github.com/z88dk/z88dk Z88dk]&#039;&#039;&lt;br /&gt;
: Supports the Next extension opcodes directly, linking assembler with large z80 library, targets any memory configuration&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://github.com/z00m128/sjasmplus z00m&#039;s fork of sjasmplus]&#039;&#039; ===&lt;br /&gt;
: Supports all (core2.00.28) Next extension opcodes, ZXN memory model (8 memory slots with 8ki pages and 1.75MiB virtual device memory), SAVENEX to build NEX files directly from ASM source (NEX version V1.2 (and experimental extension &amp;quot;V1.3&amp;quot;)), MAP files for [https://mdf200.itch.io/cspect #CSpect] emulator, SLD tracing files for [https://github.com/maziac/DeZog DeZog] and [https://github.com/Ckirby101/NDS-NextDevSystem NDS-NextDevSystem] and it is under active development (feedback is welcome).&lt;br /&gt;
: Open source project (&amp;quot;BSD-3-Clause&amp;quot; license), &#039;&#039;&#039;windows executables available at [https://github.com/z00m128/sjasmplus/releases/latest releases]&#039;&#039;&#039;, mac and linux users are expected to simply build from source (both make and CMake are supported).&lt;br /&gt;
: [http://z00m128.github.io/sjasmplus/documentation.html Documentation], latest stable release v1.21.1 2026-01-16&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://github.com/CatpainBlack/FantASM FantASM]&#039;&#039; ===&lt;br /&gt;
FantASM is a two pass non optimising assembler for the Z80 processor by [https://github.com/CatpainBlack Guy &#039;CatpainBlack&#039; Black].&lt;br /&gt;
&lt;br /&gt;
It supports all undocumented op-codes and the extended instruction set of the ZX Next and additional pseudo opcodes used by the CSpect emulator to control debugging.&lt;br /&gt;
&lt;br /&gt;
== Native tools (running on Next) ==&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://gitlab.com/next-tools/odin Odin]&#039;&#039; ===&lt;br /&gt;
&lt;br /&gt;
Work-in-progress Next-specific assembler written by Matt Davies, used also in video tutorials presented by Jim Bagley, the best way to acquire the binary is to join the official ZX Next discord server and check channel &amp;lt;code&amp;gt;#odin&amp;lt;/code&amp;gt; - pinned messages, where you can also discuss any issues and get how-to hints.&lt;br /&gt;
&lt;br /&gt;
: supports most of the undocumented opcodes, all official Z80 and Next-extended instructions&lt;br /&gt;
: supports nested includes and binary includes&lt;br /&gt;
: source is stored in tokenised form (smaller file), up to 48kiB of source in single file&lt;br /&gt;
: assembling can produce 32kiB of machine code (enough to produce simpler dot command)&lt;br /&gt;
: includes also editor and console modules (debugger is planned)&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://www.solarisite.com/spectrumnext.html Sol]&#039;&#039; ===&lt;br /&gt;
&lt;br /&gt;
Sol is an assembler and editor written by Solaris, that runs natively on the Next. Manual, assembler binary and assembler source can be downloaded [https://www.solarisite.com/spectrumnext.html here].&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://gitlab.com/thesmog358/tbblue/-/tree/master/tools/dev/Zeus ZEUS]&#039;&#039; ===&lt;br /&gt;
&lt;br /&gt;
Classic ZEUS native assembler by Simon Brattel, extended and included directly in the ZX Next distro.&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://gitlab.com/thesmog358/tbblue/-/tree/master/tools/dev/SPED SPED]&#039;&#039; ===&lt;br /&gt;
&lt;br /&gt;
Classic SPED assembler by César Hernández Bañó, included directly in the ZX Next distro, see [https://gitlab.com/thesmog358/tbblue/-/raw/master/docs/apps/dev/SPED53readme.txt README].&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://taylorza.itch.io/nextbasic-inline-assembler NextBASIC Inline Assembler]&#039;&#039;===&lt;br /&gt;
Enables you to write inline assembly code in your NextBASIC application. The assembler can be downloaded from [https://taylorza.itch.io/nextbasic-inline-assembler HERE] with documentation available [https://github.com/taylorza/zxn-inlineasm-doc/blob/main/README.md HERE]&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=Audio_/_Music&amp;diff=41770</id>
		<title>Audio / Music</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=Audio_/_Music&amp;diff=41770"/>
		<updated>2025-12-30T09:35:54Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: pruning Arkos Tracker urls&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
! Tool !! Description !! Platform / Notes !! Links&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;[https://www.julien-nevo.com/arkostracker/ Arkos Tracker 3]&#039;&#039;&#039; &lt;br /&gt;
| Cross-platform modern chiptune/sampled music tracker with support for 9-channel AY tracking and various player routines (also for the Next).&lt;br /&gt;
| Win / Linux / Mac || &lt;br /&gt;
[https://www.julien-nevo.com/arkostracker/index.php/player-availability/ Player Routines]&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;[https://zx.remysharp.com/audio AYFX Editor and Driver]&#039;&#039;&#039; &lt;br /&gt;
| Web-based AY sound effect editor based on [https://shiru.untergrund.net/files/ayfxedit.zip Shiru&#039;s AYFX Editor (Windows only)]. Works fully offline, export effects for use in NextBASIC via AYFX driver.&lt;br /&gt;
| Web || &lt;br /&gt;
[https://zx.remysharp.com/audio Link] &lt;br /&gt;
[https://github.com/Threetwosevensixseven/ayfxedit-improved Assembly routines]&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;[https://nextdaw.biasillo.com/ NextDAW]&#039;&#039;&#039; &lt;br /&gt;
| Modern DAW-style interface for the ZX Spectrum Next supporting 3 AY chips (9 channels), piano roll, arranger, and realtime recording. &lt;br /&gt;
| ZX Spectrum Next (mouse required) || &lt;br /&gt;
[https://nextdaw.biasillo.com/ Link]&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;[https://volutar.myds.me/vortextracker/ Vortex Tracker]&#039;&#039;&#039; &lt;br /&gt;
| Multi-AY capable tracker for Windows. Can export in ProTracker format for Next playback. Supports 1, 2 or 3 AYs&lt;br /&gt;
| Windows || &lt;br /&gt;
[https://github.com/Volutar/vortextracker/tree/TS3/ GitHub]&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;[https://www.pouet.net/prod.php?which=105234 AYT Sound Format]&#039;&#039;&#039; &lt;br /&gt;
| AYT (AY Turbo) is a format for Sound Player for AY 8910/8912 and YM2149 chipsets.&amp;lt;br&amp;gt;AYT files are produced from YM files (dump of AY registry values), but are substantially smaller, players are very fast and have constant time of execution.&lt;br /&gt;
| Z80A players&amp;lt;br&amp;gt;PC/web tools || &lt;br /&gt;
[https://github.com/Logon-System Format definition and tools]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://amstrad.neocities.org/menuayt Web tools]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://blog.logonsystem.eu/welcome-to-ayters-eng/ More info]&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;[https://github.com/mikedailly/mod_player/ MOD Player]&#039;&#039;&#039; &lt;br /&gt;
| 4-channel MOD player for ZX Spectrum Next (Z80) by Mike Dailly. Compose with any Amiga tracker. Limited effect support (No CIA, only effects 1xx,2xx,Axx,Cxx,Dxx &amp;amp; Fxx). Updates once per interrupt filling a buffer that is played back via the DMA so could be used in game.&lt;br /&gt;
| ZX Spectrum Next || &lt;br /&gt;
[https://github.com/mikedailly/mod_player/ GitHub]&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;[https://github.com/em00k/NXModPlayer NXModPlayer]&#039;&#039;&#039; &lt;br /&gt;
| 4-channel MOD player for ZX Spectrum Next (Z80) by njoi. Mod engine by 9bitcolor, interface by em00k. Full MOD support, all effects CIA timings. 4 Channel Stereo. Takes more processing time but results match that of the Amiga. Included on the official distro&lt;br /&gt;
| ZX Spectrum Next || &lt;br /&gt;
[https://github.com/em00k/NXMod-src GitHub engine source]&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=Audio_/_Music&amp;diff=41579</id>
		<title>Audio / Music</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=Audio_/_Music&amp;diff=41579"/>
		<updated>2025-12-22T22:58:10Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: Adding AYT format info&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
! Tool !! Description !! Platform / Notes !! Links&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;[https://www.julien-nevo.com/arkostracker/ Arkos Tracker 2]&#039;&#039;&#039; &lt;br /&gt;
| Cross-platform modern chiptune/sampled music tracker with support for 9-channel AY tracking and various player routines for the Next.&lt;br /&gt;
| Win / Linux / Mac || &lt;br /&gt;
[http://www.julien-nevo.com/arkostracker/index.php/the-players/ Player Routines], &lt;br /&gt;
&amp;lt;s&amp;gt;[http://ped.7gods.org/ZX_Spectrum_Next.aks ZX Next Template (.aks)]&amp;lt;/s&amp;gt;,&lt;br /&gt;
&amp;lt;s&amp;gt;[http://ped.7gods.org/song_properties.jpg Song Properties]&amp;lt;/s&amp;gt;,&lt;br /&gt;
&amp;lt;s&amp;gt;[http://ped.7gods.org/psg_settings.jpg PSG Settings]&amp;lt;/s&amp;gt;&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;[https://zx.remysharp.com/audio AYFX Editor and Driver]&#039;&#039;&#039; &lt;br /&gt;
| Web-based AY sound effect editor based on [https://shiru.untergrund.net/files/ayfxedit.zip Shiru&#039;s AYFX Editor (Windows only)]. Works fully offline, export effects for use in NextBASIC via AYFX driver.&lt;br /&gt;
| Web || &lt;br /&gt;
[https://zx.remysharp.com/audio Link] &lt;br /&gt;
[https://github.com/Threetwosevensixseven/ayfxedit-improved Assembly routines]&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;[https://nextdaw.biasillo.com/ NextDAW]&#039;&#039;&#039; &lt;br /&gt;
| Modern DAW-style interface for the ZX Spectrum Next supporting 3 AY chips (9 channels), piano roll, arranger, and realtime recording. &lt;br /&gt;
| ZX Spectrum Next (mouse required) || &lt;br /&gt;
[https://nextdaw.biasillo.com/ Link]&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;[https://volutar.myds.me/vortextracker/ Vortex Tracker]&#039;&#039;&#039; &lt;br /&gt;
| Multi-AY capable tracker for Windows. Can export in ProTracker format for Next playback. Supports 1, 2 or 3 AYs&lt;br /&gt;
| Windows || &lt;br /&gt;
[https://volutar.myds.me/vortextracker/ GitHub]&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;[https://www.pouet.net/prod.php?which=105234 AYT Sound Format]&#039;&#039;&#039; &lt;br /&gt;
| AYT (AY Turbo) is a format for Sound Player for AY 8910/8912 and YM2149 chipsets.&amp;lt;br&amp;gt;AYT files are produced from YM files (dump of AY registry values), but are substantially smaller, players are very fast and have constant time of execution.&lt;br /&gt;
| Z80A players&amp;lt;br&amp;gt;PC/web tools || &lt;br /&gt;
[https://github.com/Logon-System Format definition and tools]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://amstrad.neocities.org/menuayt Web tools]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://blog.logonsystem.eu/welcome-to-ayters-eng/ More info]&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;[https://github.com/mikedailly/mod_player/ MOD Player]&#039;&#039;&#039; &lt;br /&gt;
| 4-channel MOD player for ZX Spectrum Next (Z80) by Mike Dailly. Compose with any Amiga tracker. Limited effect support (No CIA, only effects 1xx,2xx,Axx,Cxx,Dxx &amp;amp; Fxx). Updates once per interrupt filling a buffer that is played back via the DMA so could be used in game.&lt;br /&gt;
| ZX Spectrum Next || &lt;br /&gt;
[https://github.com/mikedailly/mod_player/ GitHub]&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;[https://github.com/em00k/NXModPlayer NXModPlayer]&#039;&#039;&#039; &lt;br /&gt;
| 4-channel MOD player for ZX Spectrum Next (Z80) by njoi. Mod engine by 9bitcolor, interface by em00k. Full MOD support, all effects CIA timings. 4 Channel Stereo. Takes more processing time but results match that of the Amiga. Included on the official distro&lt;br /&gt;
| ZX Spectrum Next || &lt;br /&gt;
[https://github.com/em00k/NXMod-src GitHub engine source]&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=MAME:Installing&amp;diff=41578</id>
		<title>MAME:Installing</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=MAME:Installing&amp;diff=41578"/>
		<updated>2025-12-22T20:09:04Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: change url anchor to follow edits&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[https://www.mamedev.org/ MAME] (formerly an acronym of Multiple Arcade Machine Emulator) is a free and open-source emulator designed to emulate the hardware of arcade games, later expanded to include video game consoles, old computers and other systems in software on modern personal computers and other platforms.&lt;br /&gt;
&lt;br /&gt;
MAME has supported the ZX Spectrum Next since version 0.267. The existing implementation is based on the v3.02.01 core and implements most of the features.&lt;br /&gt;
&lt;br /&gt;
= Installation =&lt;br /&gt;
&lt;br /&gt;
You will need to install MAME, provide it with the Next firmware (&#039;ROM&#039;), and get the NextZXOS image:&lt;br /&gt;
&lt;br /&gt;
=== 1. Get MAME ===&lt;br /&gt;
Start with these official MAME releases. If you encounter crashes or other bugs, try replacing the MAME executable with holub&#039;s latest Continuous Integration (CI) builds as described at the end of this article.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Windows:&#039;&#039;&#039; Download [https://www.mamedev.org/release.html MAME for Windows].&lt;br /&gt;
* &#039;&#039;&#039;macOS:&#039;&#039;&#039; Download [https://sdlmame.lngn.net/ MAME for macOS].&lt;br /&gt;
* &#039;&#039;&#039;Linux:&#039;&#039;&#039; Install MAME from the flatpak repositories by running:&lt;br /&gt;
&amp;lt;pre&amp;gt;sudo flatpak install org.mamedev.MAME&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that Windows and macOS will likely prevent you from launching MAME directly for security reasons. See below on how to solve this.&lt;br /&gt;
&lt;br /&gt;
Alternatively, for the MAME platform as a whole, you can also check your package manager, or [https://docs.mamedev.org/initialsetup/compilingmame.html build from sources].&lt;br /&gt;
&lt;br /&gt;
Git of official MAME: [https://github.com/mamedev/mame/ https://github.com/mamedev/mame/] [https://github.com/mamedev/mame/blob/master/src/mame/sinclair/specnext.cpp specnext.cpp]&lt;br /&gt;
&lt;br /&gt;
Git of holub&#039;s fork: [https://github.com/holub/mame https://github.com/holub/mame] [https://github.com/holub/mame/blob/master/src/mame/sinclair/specnext.cpp specnext.cpp] (may contain extra fixes and features before they are merged to official repository)&lt;br /&gt;
&lt;br /&gt;
=== 2. Get TBBLUE (the Next &#039;boot ROM&#039;) ===&lt;br /&gt;
Put the file  [https://github.com/Threetwosevensixseven/NexCreator/raw/master/bootroms/tbblue.zip tbblue.zip] into MAME&#039;s &amp;lt;code&amp;gt;roms&amp;lt;/code&amp;gt; folder. Don&#039;t extract it; MAME will look for the zip file when the &amp;quot;tbblue&amp;quot; machine is selected.&lt;br /&gt;
&lt;br /&gt;
Note: The ROMs in this zip are what is embedded inside the FPGA core on real Next hardware. They&#039;re different from any ZX Spectrum machine ROMs you may be used to using, that are on the distro, SD card or SD image file.&lt;br /&gt;
&lt;br /&gt;
=== 3. Get the NextZXOS Image ===&lt;br /&gt;
Get an SD card image file of [https://www.specnext.com/latestdistro/ NextZXOS]. Note that currently some published disk images on the official SpecNext.com site (the &amp;lt;code&amp;gt;latestdistro&amp;lt;/code&amp;gt; link points to the official location where the latest distribution can be found) do not work with some emulators, but all images from &amp;lt;code&amp;gt;https://zxnext.uk/hosted/&amp;lt;/code&amp;gt; work with both MAME and CSpect, like [https://zxnext.uk/hosted/index_files/hdfimages/cspect-next-2gb.zip this SD card image in the zip archive]. Extract the image &amp;lt;code&amp;gt;cspect-next-2gb.img&amp;lt;/code&amp;gt; from the archive to use it, then point MAME to this SD card image with the &amp;lt;code&amp;gt;-hard1&amp;lt;/code&amp;gt; option (or select that file from the menu inside MAME).&lt;br /&gt;
&lt;br /&gt;
= Usage =&lt;br /&gt;
MAME looks for its configuration and helper files in specific (configurable) folders. By default, these are relative to the current working directory (cwd), i.e., from where you launched the executable. The &amp;lt;code&amp;gt;mame.ini&amp;lt;/code&amp;gt; file and folders like &amp;lt;code&amp;gt;roms, bgfx, plugins, language, ...&amp;lt;/code&amp;gt; are expected there, unless the &amp;lt;code&amp;gt;mame.ini&amp;lt;/code&amp;gt; file specifies other paths. When launching through a desktop icon or menu, depending on the OS, the working directory is often defined by the properties of that launch shortcut. When launching MAME from the command line, the current directory is &amp;quot;cwd&amp;quot; (doh). On Linux, MAME will look for &amp;lt;code&amp;gt;mame.ini&amp;lt;/code&amp;gt; first in the &amp;lt;code&amp;gt;~/.mame&amp;lt;/code&amp;gt; folder. You can use the option &amp;lt;code&amp;gt;-inipath&amp;lt;/code&amp;gt; to point MAME to a different path for the &amp;lt;code&amp;gt;mame.ini&amp;lt;/code&amp;gt; file.&lt;br /&gt;
&lt;br /&gt;
However, the fastest way to run a machine with a desired configuration is from the command prompt, without requiring a &amp;lt;code&amp;gt;mame.ini&amp;lt;/code&amp;gt; file. Most of the features are also available through MAME&#039;s UI, although that takes more time to configure.&lt;br /&gt;
&lt;br /&gt;
As an example, this invocation enables the UI, uses &amp;quot;crisp pixels&amp;quot;, starts in a window, doesn&#039;t display the starting gameinfo window (it can still be displayed interactively from the UI), disables the mouse, confirms before exiting MAME, and specifies the disk image (remember to adjust the path to it):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;mame -ui_active -nounevenstretch -aspect 2:1 -video bgfx  -bgfx_screen_chains unfiltered -window -skip_gameinfo -mouse_device none -confirm_quit tbblue -hard1 /path/to/cspect-next-2gb.img&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let&#039;s cover some useful options:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Run inside a window and with no mouse support, until you get familiar with the UI keys:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; mame tbblue -window -mouse_device none -hard1 /path/to/next-distribution.img&amp;lt;/pre&amp;gt;&lt;br /&gt;
To launch the Linux flatpak version using the same options:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; flatpak run org.mamedev.MAME tbblue -window -mouse_device none -hard1 /path/to/next-distribution.img&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Activate UI keys on startup:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -ui_active&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Don&#039;t show the info popup on startup:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -skip_gameinfo&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;Run with debugger. If you don&#039;t request this on startup, you won&#039;t have access to it:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -debug&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;Use &amp;quot;crisp&amp;quot; pixels:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -nounevenstretch -aspect 2:1 -video bgfx -bgfx_screen_chains unfiltered&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;No joystick connected to PC (having this may slightly speed up MAME&#039;s startup, but &#039;&#039;remember to remove this part from the command line and the corresponding setting in the ini file if you do want to use a joystick&#039;&#039;):&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -joystickprovider none&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;Ask for confirmation when exiting MAME (otherwise it&#039;s easy to exit MAME accidentally by hitting ESC, especially when playing games or navigating menus):&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -confirm_quit&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Check the [https://docs.mamedev.org/commandline/commandline-all.html#mame-commandline-universal official MAME documentation] for more advanced usage.&lt;br /&gt;
&lt;br /&gt;
= Security: Allowing MAME to Run on Windows and macOS =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;On Windows,&#039;&#039;&#039; you will need to confirm that you want to launch MAME by clicking &amp;quot;Run Anyway&amp;quot; on first launch. &#039;&#039;(More details needed here.)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;On macOS,&#039;&#039;&#039; MAME will not open at first. Instead, a dialog will appear saying:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;“mame” Not Opened. Apple could not verify “mame” is free of malware that may harm your Mac or compromise your privacy.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Click “Done”. Then open &#039;&#039;&#039;System Settings -&amp;gt; Privacy &amp;amp; Security&#039;&#039;&#039;, and scroll down to the message &#039;&#039;mame was blocked to protect your Mac.&#039;&#039; Click “Allow Anyway”.&lt;br /&gt;
&lt;br /&gt;
Now launch MAME again. A dialog will ask once more if you want to open “mame”. Click “Open Anyway”, and enter your password or use Touch ID when prompted by macOS.&lt;br /&gt;
&lt;br /&gt;
From now on, you can launch this version of MAME without warnings. However, you &#039;&#039;&#039;will&#039;&#039;&#039; need to repeat this each time you update MAME.&lt;br /&gt;
&lt;br /&gt;
= Keys =&lt;br /&gt;
&lt;br /&gt;
Keys are emulated in two modes: either to control the MAME emulator or completely dedicated to the emulated system (the Next). You can toggle between these two keyboard modes with ScrLk (on Win and Linux) or fn+delete (on Mac).&lt;br /&gt;
&lt;br /&gt;
Some UI keys:&lt;br /&gt;
* F3 - soft reset&lt;br /&gt;
* Shift+F3 - hard reset&lt;br /&gt;
* F4 - sprites/tiles/font viewer (Enter, ], [)&lt;br /&gt;
* F5 - pause emulation&lt;br /&gt;
* F6 - save state&lt;br /&gt;
* F7 - load state&lt;br /&gt;
* Tab - emulator settings&lt;br /&gt;
* ~ - menu&lt;br /&gt;
* ` (backtick) - debugger (when enabled by starting MAME with &amp;lt;code&amp;gt;-debug&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;-d&amp;lt;/code&amp;gt; on the command line)&lt;br /&gt;
* PgDwn (Linux/Mac), fn-Downarrow (MacBooks) or Insert (Win) - hold down to fast-forward emulation at maximum speed, e.g., to speed up booting the Next&lt;br /&gt;
* Esc - exit (exits menus but also the entire emulator - see &amp;lt;code&amp;gt;-confirm_quit&amp;lt;/code&amp;gt; option above)&lt;br /&gt;
* F11 - DivMMC NMI&lt;br /&gt;
* F12 - Multiface NMI&lt;br /&gt;
&lt;br /&gt;
Check [https://docs.mamedev.org/usingmame/defaultkeys.html default keys documentation] for more.&lt;br /&gt;
&lt;br /&gt;
= Changing the UI toggle key =&lt;br /&gt;
&lt;br /&gt;
Some laptops don&#039;t have a Scroll Lock key, so you may not be able to exit MAME if you run it in full-screen mode. In these cases, you can change the UI toggle key as follows:&lt;br /&gt;
&lt;br /&gt;
* Run MAME without any command line arguments (except maybe -window) to open its GUI.&lt;br /&gt;
* Push TAB and enter the General Settings menu.&lt;br /&gt;
* Go to Input Assignments -&amp;gt; User Interface -&amp;gt; Toggle UI controls and select a new key. I use Right Alt / Alt GR.&lt;br /&gt;
* Return to the previous menu twice, then choose Save Settings&lt;br /&gt;
&lt;br /&gt;
= Creating a NextZXOS SD card image =&lt;br /&gt;
&lt;br /&gt;
Most users wanting to emulate the Next using MAME will be fine using a pre-built SD card image downloaded from the specnext website. The following guide is provided for anyone wanting to create a NextZXOS SD card image from scratch.&lt;br /&gt;
&lt;br /&gt;
Download the [https://www.specnext.com/latestdistro/ latest NextZXOS distribution zip file] (named something like sn-complete-WX.YZ.zip) and extract it into a new, empty directory.&lt;br /&gt;
&lt;br /&gt;
== Creating and populating a SD card image using hdfmonkey jjjs build ==&lt;br /&gt;
&lt;br /&gt;
The [[https://www.specnext.com/forum/viewtopic.php?t=2604 | &amp;lt;code&amp;gt;hdfmonkey &amp;quot;jjjs build&amp;quot;&amp;lt;/code&amp;gt;]] is a variant of hdfmonkey tool which includes some unique features and its main archive (at the previously given link) also contains pre-built binaries for Windows x64, MacOS x64, MacOS Apple Silicon and Linux x64. (Alternatively, the process to build a local Linux version of the executable is described [[Development_Tools:Linux_setup#Building_the_executable_binary_2 | here]] )&lt;br /&gt;
&lt;br /&gt;
If you extracted sn-complete-WX.YZ.zip into a subdirectory named &amp;lt;code&amp;gt;snWXYZ&amp;lt;/code&amp;gt;, and you want to create a 1GB image called &amp;lt;code&amp;gt;NextZXOS.img&amp;lt;/code&amp;gt; and you have a jjjs build&amp;quot; of hdfmonkey, then it&#039;s enough to do:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
hdfmonkey create NextZXOS.img 1G&lt;br /&gt;
hdfmonkey putdir NextZXOS.img snWXYZ /&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first line creates an empty 1GB image and formats it with the best FAT parameters suited to the size of the image.&lt;br /&gt;
&lt;br /&gt;
The second line recursively copies all the content of the directory &amp;lt;code&amp;gt;snWXYZ&amp;lt;/code&amp;gt; to the image, preserving the directory structure inside, starting from the &amp;lt;code&amp;gt;/&amp;lt;/code&amp;gt; in the image.&lt;br /&gt;
&lt;br /&gt;
One of the advantages of this method is that even if the image has a capacity of 1GB, it will use much less space on your hard drive until you fill up the image. On Linux or MacOS, a command &amp;lt;code&amp;gt;du -h NextZXOS.img&amp;lt;/code&amp;gt; shows the actual amount of disk space used by the image. On Windows the same information can be seen in the File Properties dialog.&lt;br /&gt;
&lt;br /&gt;
The fastest way to transfer a file or a directory (including its content, recursively) into an image is by using a single &amp;lt;code&amp;gt;put&amp;lt;/code&amp;gt; (or &amp;lt;code&amp;gt;putdir&amp;lt;/code&amp;gt;, if it&#039;s to transfer the directory file content to an existing directory) command of hdfmonkey.&lt;br /&gt;
&lt;br /&gt;
The most convenient tool to copy of all the content from the image to a folder outside of the image is 7-zip. On Windows, just use the 7-zip GUI. On MacOS and Linux, see: [[Development_Tools:Linux_setup#Extracting_all_files_from_the_sd-card_image]].&lt;br /&gt;
&lt;br /&gt;
== Creating and populating a SD card image using Linux ==&lt;br /&gt;
&lt;br /&gt;
While using hdfmonkey jjjs build works on Linux and the pre-built binary for Intel x64 exists, and using it creates an image which will have high compatibility, it is also possible to use more common Linux tools to create a SD image. Note however that the resulting image of this method, if the parameters of different steps aren&#039;t carefully chosen and matched, could be out of the official FAT specifications and/or the expectations of some of the existing programs or systems. This method creates an image which is incompatible with the current (as of 2025-12-13) CSpect version, at least for some sizes of the image:&lt;br /&gt;
&lt;br /&gt;
Create a disk image of at least 256 MB. The current complete NextZXOS distro requires at least 130 MB of disk space. This command will create a 256 MB SD card image; change the &amp;lt;code&amp;gt;count&amp;lt;/code&amp;gt; value to make the image file as big as you want in megabytes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;dd if=/dev/zero of=NextZXOS.img bs=1M count=256&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The rest of the commands in this guide must be run as the root user or using sudo.&lt;br /&gt;
&lt;br /&gt;
You will need to install the dosfstools and parted packages if they are not already installed. Debian and Ubuntu Linux users can install these using this apt command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;apt install dosfstools parted&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mount the SD card image loopback device:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;losetup --partscan --show --find NextZXOS.img&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Create a FAT32 partition:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;parted /dev/loop0 mklabel msdos&lt;br /&gt;
parted /dev/loop0 mkpart primary fat32 1MB 100%&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Format and mount the partition under /mnt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;mkfs.vfat -F 32 /dev/loop0p1&lt;br /&gt;
mount /dev/loop0p1 /mnt&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can now copy all of the files you extracted from sn-complete-WX.YZ.zip into /mnt.&lt;br /&gt;
&lt;br /&gt;
After copying the files, unmount and detach the loopback device (the SD card image):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;umount /mnt/&lt;br /&gt;
losetup -D&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Mounting SD card images under Linux =&lt;br /&gt;
&lt;br /&gt;
Under Linux, you can use &amp;lt;code&amp;gt;losetup&amp;lt;/code&amp;gt; to mount SD card images as loop devices. This lets you copy files to and from the image and perform other file management tasks as you would using any other filesystem.&lt;br /&gt;
&lt;br /&gt;
Run the following commands as the root user to mount an image called sn-emulator-22.10a.img under the /mnt directory:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;losetup --partscan --show --find cspect-next-2gb.img&lt;br /&gt;
mount /dev/loop0p1 /mnt/&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After you are finished modifying the SD card image, cd out of /mnt, then unmount and detach the loopback device:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;umount /mnt/&lt;br /&gt;
losetup -D&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=MAME Plugins and Scripts=&lt;br /&gt;
&lt;br /&gt;
Some MAME plugins and scripts that may be useful for Next developers and end users are listed [[MAME:Plugins_and_Scripts|here]]. They let you speed up the Next boot time, profile your NextBASIC or assembler code, and more.&lt;br /&gt;
&lt;br /&gt;
=Continuous Integration MAME Builds=&lt;br /&gt;
&lt;br /&gt;
MAME is updated on a release schedule, but due to the ongoing nature of development, including for the MAME Next machine, it can sometimes be useful to install a more recent build if it contains a new feature or bugfix you are interested in. Sometimes, this ongoing work is discussed on social media, such as the [https://discordapp.com/channels/556228195767156758/752197165891321886 Next Developer Discord].&lt;br /&gt;
&lt;br /&gt;
Continuous Integration (CI) builds are available from both the [https://github.com/mamedev/mame/actions primary MAME repo] and [https://github.com/holub/mame/actions holub&#039;s GitHub repo]. Both are considered bleeding-edge, with the primary MAME repo slightly less so. MAME CI builds are available for Windows, Linux, and macOS and are updated automatically whenever code is committed by a maintainer or pushed to the primary repo.&lt;br /&gt;
&lt;br /&gt;
To try out a CI build (more precisely, the resulting binary executable, which is a produced &amp;quot;artifact&amp;quot; of the build process) , first do a full MAME install from the [https://www.mamedev.org/release.html latest release] if you have not already done so. Then back up your main binary from its installation location - these are called something like &amp;lt;code&amp;gt;mame.exe&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;mame&amp;lt;/code&amp;gt;. You can always restore these if the CI build doesn&#039;t work, or if you don&#039;t like how it behaves.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;You need to be logged in to github&#039;&#039;&#039; to download CI artifacts, so [https://github.com/login sign in] or [https://github.com/signup sign up].&lt;br /&gt;
&lt;br /&gt;
Then visit one of the links above and find a workflow run item for your platform. Workflow items are the things in the list. The tags are flagged as &amp;lt;code&amp;gt;CI (Windows)&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CI (Linux)&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;CI (macOS)&amp;lt;/code&amp;gt; in the second row of each workflow item in the list (not the filter in the left hand nav menu). Click on a completed workfow item (only items with green checkmarks will have created downloadable binaries yet), find the Artifacts section at the bottom, then click the Download button. Unzip the downloaded file and find the main binary (with the same name as above). Copy the main binary to the install location, overwriting the original one, and run MAME the same way you were running it before. On Windows and macOS, you need to repeat the security steps above to trust the new MAME executable.&lt;br /&gt;
&lt;br /&gt;
= More MAME links =&lt;br /&gt;
&lt;br /&gt;
MAME [https://docs.mamedev.org/ documentation].&lt;br /&gt;
&lt;br /&gt;
Report any issues with MAME on the [https://mametesters.org/ bugtracker].&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=Development_Tools:Linux_setup&amp;diff=41577</id>
		<title>Development Tools:Linux setup</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=Development_Tools:Linux_setup&amp;diff=41577"/>
		<updated>2025-12-22T20:05:19Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: unifying usage of tags and terms in main titles&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== General ==&lt;br /&gt;
&lt;br /&gt;
This page collects summaries of installation process of various tools related to ZX Spectrum Next software development for linux OS users.&lt;br /&gt;
&lt;br /&gt;
As usual with linux, most of the suggestions are in the form of command line command to be used from terminal.&lt;br /&gt;
&lt;br /&gt;
== sjasmplus assembler ==&lt;br /&gt;
&lt;br /&gt;
You can also check the [https://www.youtube.com/watch?v=c6I4kdErEwE video] of installing sjasmplus on freshly reinstalled KDE neon 5.20 linux, where is also extended info how to run the automated tests of sjasmplus, and opening it in KDevelop IDE to eventually write your own modifications.&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
On Debian based systems make sure you have these packages installed (git-cola and cmake are optional, but often handy):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install git build-essential g++ git-cola cmake&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Retrieving the sjasmplus source ===&lt;br /&gt;
&lt;br /&gt;
Use git to clone the [https://github.com/z00m128/sjasmplus z00m&#039;s sjasmplus repository]:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;git clone --recursive -j8 https://github.com/z00m128/sjasmplus.git&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To update already cloned repository, do inside the sjasmplus folder:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;git pull&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
- or use your favourite GIT client app to update the cloned repository.&lt;br /&gt;
&lt;br /&gt;
=== Building the executable binary ===&lt;br /&gt;
&lt;br /&gt;
The GNU make and common C++ compiler (gcc or clang) should be enough to build the binary:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;make clean &amp;amp;&amp;amp; make&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To verify the binary was built (&amp;quot;dot slash&amp;quot; prefix to force running of binary in current folder, not system one):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;./sjasmplus --version&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Installing the executable ===&lt;br /&gt;
&lt;br /&gt;
If you already have sjasmplus installed, use &amp;lt;code&amp;gt;which sjasmplus&amp;lt;/code&amp;gt; to see where the installed executable is (and which installed executable has precedence), you can use this command also after installing the new executable to verify it is being picked up by the system.&lt;br /&gt;
&lt;br /&gt;
Installing the binary in system-wide fashion:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo make install&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or you can install the binary only locally for your user (without root/sudo permissions):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;mkdir -p ~/.local/bin&lt;br /&gt;
make PREFIX=~/.local install&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
- then make sure you have &amp;lt;code&amp;gt;~/.local/bin&amp;lt;/code&amp;gt; in your user &amp;lt;code&amp;gt;PATH&amp;lt;/code&amp;gt; environment variable (on some distros there is already script in .profile to add this to PATH if the dir does exist, so you may need to only logout/restart after creating it to get it active).&lt;br /&gt;
&lt;br /&gt;
=== Checking if it all works ===&lt;br /&gt;
&lt;br /&gt;
Open your terminal and type (in any directory):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sjasmplus --version&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see version of the freshly built sjasmplus executable like this:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;SjASMPlus Z80 Cross-Assembler v1.17.0 (https://github.com/z00m128/sjasmplus)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== hdfmonkey tool ==&lt;br /&gt;
&lt;br /&gt;
The hdfmonkey tool can manipulate card-images, helping to write new builds of your project into NextZXOS card-image, to boot the emulators with full file system. (it&#039;s also possible to mount the images directly into linux by other means, to operate on them with regular file manager/etc, but hdfmonkey suits better use-case when the build script does update the image)&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
On Debian based systems make sure you have these packages installed:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install git build-essential g++ autoconf&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Retrieving the hdfmonkey source ===&lt;br /&gt;
&lt;br /&gt;
Use git to clone the [https://github.com/ped7g/hdfmonkey hdfmonkey repository with patched 0.5.7 &amp;lt;code&amp;gt;jjjs version&amp;lt;/code&amp;gt; sources]:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;git clone https://github.com/ped7g/hdfmonkey.git&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
(make sure you are on the default branch &amp;lt;code&amp;gt;&amp;quot;jjjs-variant&amp;quot;&amp;lt;/code&amp;gt; to build the improved version, it should be checked out by default after clone)&lt;br /&gt;
&lt;br /&gt;
* to update already cloned repository, do inside the hdfmonkey folder:&lt;br /&gt;
  &amp;lt;nowiki&amp;gt;git pull&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
* or use your favourite GIT client app to update the cloned repository.&lt;br /&gt;
* if you cloned original gasman&#039;s repository before, you may want to clone and rebuild here mentioned &amp;lt;code&amp;gt;jjjs version&amp;lt;/code&amp;gt; to get multiple fixes and convenience features.&lt;br /&gt;
&lt;br /&gt;
=== Building the executable binary ===&lt;br /&gt;
&lt;br /&gt;
The hdfmonkey is using autoconf/autotools to build final Makefile, check the hdfmonkey README for &amp;quot;from git&amp;quot; installation notes, at the moment of writing this page, the steps were:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;cd hdfmonkey&lt;br /&gt;
autoheader&lt;br /&gt;
aclocal&lt;br /&gt;
autoconf&lt;br /&gt;
automake -a&lt;br /&gt;
./configure&lt;br /&gt;
make&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To verify the binary was built:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;src/hdfmonkey help&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Installing the executable ===&lt;br /&gt;
&lt;br /&gt;
If you already have hdfmonkey installed, use &amp;lt;code&amp;gt;which hdfmonkey&amp;lt;/code&amp;gt; to see where the installed executable is (and which installed executable has precedence), you can use this command also after installing the new executable to verify it is being picked up by the system.&lt;br /&gt;
&lt;br /&gt;
Installing the binary in system-wide fashion:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo make install&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or you can install the binary only locally for your user (without root/sudo permissions):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;make prefix=~/.local install&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
- then make sure you have &amp;lt;code&amp;gt;~/.local/bin&amp;lt;/code&amp;gt; in your user &amp;lt;code&amp;gt;PATH&amp;lt;/code&amp;gt; environment variable.&lt;br /&gt;
&lt;br /&gt;
=== Checking if it all works ===&lt;br /&gt;
&lt;br /&gt;
Open your terminal and type (in any directory):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;hdfmonkey help&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see help of the freshly built hdfmonkey `jjjs version` executable like this:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;hdfmonkey: utility for manipulating HDF disk images v0.5.7 jjjs&lt;br /&gt;
&lt;br /&gt;
usage: hdfmonkey &amp;lt;command&amp;gt; [args]&lt;br /&gt;
...&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Extracting all files from the sd-card image ==&lt;br /&gt;
&lt;br /&gt;
7-zip is the most convenient tool to extract the the files from the existing image.&lt;br /&gt;
&lt;br /&gt;
To install 7-zip on a Debian system use &amp;lt;code&amp;gt;sudo apt install 7zip&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To extract all the files from an existing image &amp;lt;code&amp;gt;tbblue.img&amp;lt;/code&amp;gt; to a new subdirectory &amp;lt;code&amp;gt;myfiles&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;7z x tbblue.img -omyfiles&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Creating new sd-card image with hdfmonkey ==&lt;br /&gt;
&lt;br /&gt;
This example: &lt;br /&gt;
&lt;br /&gt;
* downloads the archive from the specnext.com&lt;br /&gt;
* unpacks it to the subdirectory &amp;lt;code&amp;gt;tmptb&amp;lt;/code&amp;gt;&lt;br /&gt;
* creates a new SD image (with the space for 2GB files) from all the files&lt;br /&gt;
* deletes the subdirectory &amp;lt;code&amp;gt;tmptb&amp;lt;/code&amp;gt;&lt;br /&gt;
* shows that the new image uses much less than 2GB&lt;br /&gt;
* starts listing the content of the newly created image&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
wget https://www.specnext.com/distro/24.11/sn-complete-24.11.zip&lt;br /&gt;
7z x sn-complete-24.11.zip -otmptb&lt;br /&gt;
hdfmonkey create tbblue.img 2GB&lt;br /&gt;
hdfmonkey putdir tbblue.img tmptb /  &lt;br /&gt;
rm -rf tmptb&lt;br /&gt;
du -h tbblue.img&lt;br /&gt;
7z l tbblue.img | more&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mounting sd-card image directly ==&lt;br /&gt;
&lt;br /&gt;
Sometimes it may be useful to mount the card image directly, to be able to browse it and manipulate with common tools. But make sure you are not using mounted card image also in emulator at the same time, to prevent any data damage by parallel access.&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
On Debian based systems make sure you have these packages installed:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install fdisk mount&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Prepare empty directory to mount the card image into (let&#039;s call it &amp;quot;next-card&amp;quot;) and have the image file around (&amp;quot;tbblue.mmc&amp;quot; in following examples)&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;mkdir -p next-card&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Mounting the card image ===&lt;br /&gt;
&lt;br /&gt;
To mount the card image you need to know the exact byte-offset where the FAT partition starts, it&#039;s possible to read it from &amp;quot;fdisk&amp;quot; or &amp;quot;parted&amp;quot; tools outputs:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;fdisk -l -o Start tbblue.mmc&lt;br /&gt;
# prints value in sector units, like:&lt;br /&gt;
# Start&lt;br /&gt;
#    63&lt;br /&gt;
# This has to be multiplied by 512 to get byte offset: 63*512 = 32256&lt;br /&gt;
&lt;br /&gt;
# or&lt;br /&gt;
&lt;br /&gt;
parted tbblue.mmc unit B print&lt;br /&gt;
# prints values in bytes with &amp;quot;B&amp;quot; suffix in &amp;quot;Start&amp;quot; column&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
But the fdisk output can be incorporated directly into mount command, which needs root permissions, example with sudo:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo mount tbblue.mmc next-card/ -o loop,offset=$((`fdisk -l -o Start tbblue.mmc | tail -1` * 512)),user,uid=`id -u`,gid=`id -g`&lt;br /&gt;
&lt;br /&gt;
# or you can enter the offset yourself&lt;br /&gt;
&lt;br /&gt;
sudo mount tbblue.mmc next-card/ -o loop,offset=32256,user,uid=`id -u`,gid=`id -g`&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The uid and gid options will mount the filesystem under your regular user, so you can now browse it with file manager, text editors, etc.&lt;br /&gt;
&lt;br /&gt;
Do not run the emulator yet, before unmounting the image (after you are done manipulating the files)!&lt;br /&gt;
&lt;br /&gt;
=== Unmount the image before using it in emulator ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo umount next-card/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Check the result. If the unmounting fails (probably with &amp;quot;target is busy&amp;quot;), find which process is still accessing/viewing the files in the next-card directory, and try to unmount it again.&lt;br /&gt;
&lt;br /&gt;
=== TODO: udiskctl loop device mounting option ===&lt;br /&gt;
&lt;br /&gt;
From discord: &amp;quot;udisksctl loop-setup --file ~/spec/SpectrumNext/tbblue/image/tbblue.mmc&amp;quot;&lt;br /&gt;
&lt;br /&gt;
TODO: describe this solution and check possible gotchas/CLI options (like user must be in udiskctl group to run this without sudo, etc).&lt;br /&gt;
&lt;br /&gt;
== #CSpect emulator ==&lt;br /&gt;
&lt;br /&gt;
The #CSpect is Mike Dailly&#039;s ZX Spectrum Next emulator, written in C# making it cross-platform (sort of, where the mono framework is available). It is non-free (closed-source, custom license) project, but available for usage without any payment (it&#039;s possible to use it internally to develop also commercial titles, but you can not distribute/sell the emulator itself, not even packaged with your game - for such agreement contact the author first and get his permission).&lt;br /&gt;
&lt;br /&gt;
Currently it is most performant and user friendly emulator of ZX Spectrum Next, with good emulation accuracy (see [https://wiki.specnext.dev/CSpect:known_bugs CSpect:known_bugs] page for more detailed report).&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
On Debian based systems make sure you have these packages installed:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install mono-complete libopenal1 libsdl2-dev&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Retrieving the #CSpect package ===&lt;br /&gt;
&lt;br /&gt;
Use web browser to visit itch.io dedicated to CSpect project [https://mdf200.itch.io/cspect mdf200.itch.io/cspect] and download latest release.&lt;br /&gt;
&lt;br /&gt;
You may get warnings from your browser or antivirus about the page itself and about the zip/binary files. The #CSpect has long record of triggering false positives of AV engines due to the executable being not digitally signed and because of the code using features of OS which are normal for emulator, but may look wonky for AV heuristic. Whether you trust the executable is virus free is up to you, in the end.&lt;br /&gt;
&lt;br /&gt;
=== Installing the executable ===&lt;br /&gt;
&lt;br /&gt;
Unzip the retrieved zip file (I personally use KDE Dolphin file manager, the file context menu &#039;&#039;&amp;quot;Extract -&amp;gt; Extract archive here, autodetect subfolder&amp;quot;&#039;&#039;), and place the unzipped directory to target destination (&amp;lt;code&amp;gt;~/zx/emulators/CSpect/CSpect2_13_0&amp;lt;/code&amp;gt; in my case). I prefer to keep every version in its own directory, and have general symbolic link pointing to the one I want use by default:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;cd ~/zx/emulators/CSpect&lt;br /&gt;
ln -s CSpect2_13_0 CSpect_current&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then I create launcher bash-scripts in my &amp;lt;code&amp;gt;~/.local/bin&amp;lt;/code&amp;gt; like this (name of script &amp;lt;code&amp;gt;runCSpect&amp;lt;/code&amp;gt;):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;#!/bin/bash&lt;br /&gt;
# personal script of Ped to launch &amp;quot;#CSpect&amp;quot; emulator in &amp;quot;current directory&amp;quot; (with arguments like: &amp;quot;runCSpect file.nex&amp;quot;)&lt;br /&gt;
MONO_IOMAP=all mono ~/zx/emulators/CSpect/CSpect_current/CSpect.exe -tv -zxnext -s28 -w4 -mmc=./ &amp;quot;$@&amp;quot;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notes: I don&#039;t know any more what &amp;lt;code&amp;gt;MONO_IOMAP=all&amp;lt;/code&amp;gt; helps with, I believe it was suggested to help with any filesystem windows-like paths containing backslashes, you can try to do your own research. The &amp;lt;code&amp;gt;-tv&amp;lt;/code&amp;gt; switch will switch off &amp;quot;scanlines&amp;quot; shader effect and generally switch off any GPU shaders, which makes CSpect more compatible with graphics drivers (try it, if you get only black screen or instant crash during init). The &amp;lt;code&amp;gt;-w4&amp;lt;/code&amp;gt; will make the window quite large - 4x scale, the &amp;lt;code&amp;gt;-zxnext -s28&amp;lt;/code&amp;gt; switch #CSpect into ZX Next emulation mode and set 28Mhz speed of OS as default. And finally the &amp;lt;code&amp;gt;-mmc=./ &amp;quot;$@&amp;quot;&amp;lt;/code&amp;gt; will set &#039;&#039;current directory&#039;&#039; for esxdos emulation to the directory where you use the script to launch the emulator, and pass any remaining command line options entered by user, like the name of the SNA/NEX file. Other noteworthy options are &amp;lt;code&amp;gt;-debug -brk -map=file.map&amp;lt;/code&amp;gt;, the -debug entering the debugger just ahead of the first instruction, -brk enables CSpect specific two-byte tag 0xDD 0x01 to work as breakpoint and the -map option allows you to load into debugger the symbol table from your assembler (directive CSPECTMAP in sjasmplus), making labels visible in disassembly.&lt;br /&gt;
&lt;br /&gt;
=== Checking if it all works ===&lt;br /&gt;
&lt;br /&gt;
Go to some directory with SNA/SNX/NEX file (there are also some demo files right in the CSpect directory) and use the launcher script, like:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;runCSpect beast.nex&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see #CSpect emulator window running the beast.nex demo (or whatever else you did want to launch and entered as argument).&lt;br /&gt;
&lt;br /&gt;
[[File:Cspect_test_run.png|frameless|Running CSpect from directory with test snapshots]]&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=Sprites&amp;diff=41576</id>
		<title>Sprites</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=Sprites&amp;diff=41576"/>
		<updated>2025-12-22T17:33:51Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: Refresh info about incomplete sprite rendering&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The Spectrum Next has a hardware sprite system with the following characteristics:&lt;br /&gt;
&lt;br /&gt;
* Total of 128 sprites&lt;br /&gt;
* Display surface is 320×256 overlapping the ULA screen by 32 pixels on each side&lt;br /&gt;
* Minimum of 100 sprites per scanline&amp;lt;sup&amp;gt;&amp;amp;dagger;&amp;lt;/sup&amp;gt;&lt;br /&gt;
* Choice of 512 colours for each pixel&lt;br /&gt;
* Size of each sprite is 16×16 pixels but sprites can be magnified 2x, 4x or 8x horizontally and vertically&lt;br /&gt;
* Sprites can be mirrored and rotated&lt;br /&gt;
* Sprites can be grouped together to form larger sprites under the control of a single anchor&lt;br /&gt;
* A 16K pattern memory can contain 64 8-bit sprite images or 128 4-bit sprite images and combinations in-between&lt;br /&gt;
* A per sprite palette offset allows sprites to share images but colour them differently&lt;br /&gt;
* A nextreg interface allows the copper to move sprites during the video frame&lt;br /&gt;
&lt;br /&gt;
&amp;amp;dagger; A minimum of 100 16×16 (at 1x scale) sprites is guaranteed to be displayed in any scanline. &amp;lt;s&amp;gt;Any additional sprites will not be displayed with the hardware ensuring sprites are not partially plotted.&amp;lt;/s&amp;gt; Since core 3.02.02 the HW keeps drawing until full pixel bandwidth is exhausted including incomplete span of sprite. Before core 3.02.02 there was bug in the code preventing incomplete draws, causing less than 100 sprites being shown per line.&lt;br /&gt;
&lt;br /&gt;
The actual limit is determined by how many 28MHz clock cycles there are in a scanline. The sprite hardware is able to plot one pixel cycle and uses one cycle to qualify each sprite. Since the number of cycles there are in a scanline varies with video timing (HDMI, VGA), the number of pixels that can be plotted also varies but the minimum will be 1600 pixels per line including overhead cycles needed to qualify 100 sprites. Since sprites magnified horizontally involve plotting more pixels, x2 x4 x8 sprites will take more cycles to plot and the presence of these sprites in a line will reduce the total number of sprites that can be plotted.&lt;br /&gt;
&lt;br /&gt;
== Sprite Patterns ==&lt;br /&gt;
Sprite patterns are the images that each sprite can take on. The images are stored in a 16K memory internal to the FPGA and are identified by pattern number. A particular sprite chooses a pattern by storing a pattern number in its attributes.&lt;br /&gt;
&lt;br /&gt;
All sprites are 16×16 pixels in size but the come in two flavours: 4-bit and 8-bit. The bit width describes how many bits are used to code the colour of each pixel.&lt;br /&gt;
&lt;br /&gt;
An 8-bit sprite uses a full byte to colour each of its pixels so that each pixel can be one of 256 colours. In this case, a 16×16 sprite requires 256 bytes of pattern memory to store its image.&lt;br /&gt;
&lt;br /&gt;
A 4-bit sprite uses a nibble to colour each of its pixels so that each pixel can be one of 16 colours. In this case, a 16×16 sprite requires just 128 bytes of pattern memory to store its image.&lt;br /&gt;
&lt;br /&gt;
The 16K pattern memory can contain any combination of these images, whether they are 128 bytes or 256 bytes and their locations in the pattern memory are described by a pattern number. This pattern number is 7 bits with bits named as follows:&lt;br /&gt;
&lt;br /&gt;
=== Pattern Number ===&lt;br /&gt;
&amp;lt;pre&amp;gt;N5 N4 N3 N2 N1 N0 N6&lt;br /&gt;
N6, despite the name, is the least significant bit.&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This 7-bit pattern number can identify 128 patterns in the 16k pattern memory, each of which are 128 bytes in size. The full 7-bits are therefore used for 4-bit sprites.&lt;br /&gt;
&lt;br /&gt;
For 8-bit sprites, N6=0 always. The remaining 6 bits can identify 64 patterns, each of which is 256 bytes in size.&lt;br /&gt;
&lt;br /&gt;
The N5:N0,N6 bits are stored in a particular sprite’s attributes to identify which image a sprite uses.&lt;br /&gt;
&lt;br /&gt;
=== 8-Bit Sprite Patterns ===&lt;br /&gt;
The 16×16 pixel image uses 8-bits for each pixel so that each pixel can be one of 256 colours. One colour indicates transparency and this is programmed into the Sprite Transparency Index register (nextreg 0x4B). By default the transparent index is 0xE3.&lt;br /&gt;
&lt;br /&gt;
As an example of an 8-bit sprite, let’s have a look at the sprite below:&lt;br /&gt;
&lt;br /&gt;
[[File:Sprite_1.png|frame|center|Pattern example]]&lt;br /&gt;
&lt;br /&gt;
Using the default palette, which is initialised with RGB332 colours from 0-255, the hexadecimal values for this pattern arranged in a 16×16 array are shown below:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;04040404040404E3E3E3E3E3E3E3E3E3&lt;br /&gt;
04FFFFFFFFFF04E3E3E3E3E3E3E3E3E3&lt;br /&gt;
04FFFBFBFBFF04E3E3E3E3E3E3E3E3E3&lt;br /&gt;
04FFFBF5F5FBFF04E3E3E3E3E3E3E3E3&lt;br /&gt;
04FFFBF5A8A8FBFF04E3E3E3E3E3E3E3&lt;br /&gt;
04FFFFFBA844A8FBFF04E3E3E3E3E3E3&lt;br /&gt;
040404FFFBA844A8FBFF04E3E3E3E3E3&lt;br /&gt;
E3E3E304FFFBA84444FBFF04E304E3E3&lt;br /&gt;
E3E3E3E304FFFB444444FBFF044D04E3&lt;br /&gt;
E3E3E3E3E304FFFB44444444FA4D04E3&lt;br /&gt;
E3E3E3E3E3E304FFFB44FFF54404E3E3&lt;br /&gt;
E3E3E3E3E3E3E304FF44F5A804E3E3E3&lt;br /&gt;
E3E3E3E3E3E3E3E304FA4404A804E3E3&lt;br /&gt;
E3E3E3E3E3E3E3044D4D04E304F504E3&lt;br /&gt;
E3E3E3E3E3E3E3E30404E3E3E304FA04&lt;br /&gt;
E3E3E3E3E3E3E3E3E3E3E3E3E3E30404&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here 0xE3 is used as the transparent index.&lt;br /&gt;
&lt;br /&gt;
These 256 bytes would be stored in pattern memory in left to right, top to bottom order.&lt;br /&gt;
&lt;br /&gt;
=== 4-Bit Sprite Patterns ===&lt;br /&gt;
The 16×16 pixel image uses 4-bits for each pixel so that each pixel can be one of 16 colours. One colour indicates transparency and this is programmed into the lower 4-bits of the Sprite Transparency Index register (nextreg 0x4B). By default the transparency value is 0x3. Note that the same register is shared with 8-bit patterns to identify the transparent index.&lt;br /&gt;
&lt;br /&gt;
Since each pixel only occupies 4-bits, two pixels are stored in each byte. The leftmost pixel is stored in the upper 4-bits and the rightmost pixel is stored in the lower 4-bits.&lt;br /&gt;
&lt;br /&gt;
As an example we will use the same sprite image as was given in the 8-bit pattern example. Here only the lower 4 bits of each pixel is retained to confine each pixel’s colour to 4-bits:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;4444444333333333&lt;br /&gt;
4FFFFF4333333333&lt;br /&gt;
4FBBBF4333333333&lt;br /&gt;
4FB55BF433333333&lt;br /&gt;
4FB588BF43333333&lt;br /&gt;
4FFB848BF4333333&lt;br /&gt;
444FB848BF433333&lt;br /&gt;
3334FB844BF43433&lt;br /&gt;
33334FB444BF4D43&lt;br /&gt;
333334FB4444AD43&lt;br /&gt;
3333334FB4F54433&lt;br /&gt;
33333334F4584333&lt;br /&gt;
333333334A448433&lt;br /&gt;
33333334DD434543&lt;br /&gt;
33333333443334A4&lt;br /&gt;
3333333333333344&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
0x3 is used as the transparent index.&lt;br /&gt;
&lt;br /&gt;
These 128 bytes would be stored in pattern memory in left to right, top to bottom order.&lt;br /&gt;
&lt;br /&gt;
The actual colour that will appear on screen will depend on the palette, described below. The default palette will not likely generate suitable colours for 4-bit sprites.&lt;br /&gt;
&lt;br /&gt;
=== Sprite Palette ===&lt;br /&gt;
Each pixel of a sprite image is 8-bit for 8-bit patterns or 4-bit for 4-bit patterns. The pixel value is known as a pixel colour index. This colour index is combined with the sprite’s palette offset. The palette offset is a 4-bit value added to the top 4-bits of the pixel colour index. The purpose of the palette offset is to allow a sprite to change the colour of an image.&lt;br /&gt;
&lt;br /&gt;
The final sprite colour index generated by the sprite hardware is then the sum of the pixel index and the 4-bit palette offset. In pictures using binary math:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;8-bit Sprite&lt;br /&gt;
  PPPP0000&lt;br /&gt;
+ IIIIIIII&lt;br /&gt;
----------&lt;br /&gt;
  SSSSSSSS&lt;br /&gt;
&lt;br /&gt;
4-bit Sprite&lt;br /&gt;
  PPPP0000&lt;br /&gt;
+ 0000IIII&lt;br /&gt;
----------&lt;br /&gt;
  SSSSSSSS = PPPPIIII&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Where “PPPP” is the 4-bit palette offset from the sprite’s attributes and the “I”s represent the pixel value from the sprite pattern. The final sprite index is represented by the 8-bit value “SSSSSSSS”.&lt;br /&gt;
&lt;br /&gt;
For 4-bit sprites the palette offset can be thought of as selecting one of 16 different 16-colour palettes.&lt;br /&gt;
&lt;br /&gt;
This final 8-bit sprite index is then passed through the sprite palette which acts like a lookup table that returns the 9-bit RGB333 colour associated with the sprite index.&lt;br /&gt;
&lt;br /&gt;
At power up, the sprite palette is initialized such that the sprite index passes through unchanged and is therefore interpreted as an RGB332 colour. The missing third blue bit is generated as the logical OR of the two other blue bits. In short, for 8-bit sprites, the sprite index also acts like the colour when using the default palette.&lt;br /&gt;
&lt;br /&gt;
=== Sprite Attributes ===&lt;br /&gt;
A sprite’s attributes is a list of properties that determine how and where the sprite is drawn.&lt;br /&gt;
&lt;br /&gt;
Each sprite is described by either 4 or 5 attribute bytes listed below:&lt;br /&gt;
&lt;br /&gt;
==== Sprite Attribute 0 ====&lt;br /&gt;
&amp;lt;pre&amp;gt;X X X X X X X X&amp;lt;/pre&amp;gt;&lt;br /&gt;
The least significant eight bits of the sprite’s X coordinate. The ninth bit is found in sprite attribute 2.&lt;br /&gt;
&lt;br /&gt;
==== Sprite Attribute 1 ====&lt;br /&gt;
&amp;lt;pre&amp;gt;Y Y Y Y Y Y Y Y&amp;lt;/pre&amp;gt;&lt;br /&gt;
The least significant eight bits of the sprite’s Y coordinate. The ninth bit is optional and is found in attribute 4.&lt;br /&gt;
&lt;br /&gt;
==== Sprite Attribute 2 ====&lt;br /&gt;
&amp;lt;pre&amp;gt;P P P P XM YM R X8/PR&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
P = 4-bit Palette Offset&amp;lt;br /&amp;gt;&lt;br /&gt;
XM = 1 to mirror the sprite image horizontally&amp;lt;br /&amp;gt;&lt;br /&gt;
YM = 1 to mirror the sprite image vertically&amp;lt;br /&amp;gt;&lt;br /&gt;
R = 1 to rotate the sprite image 90 degrees clockwise&amp;lt;br /&amp;gt;&lt;br /&gt;
X8 = Ninth bit of the sprite’s X coordinate&amp;lt;br /&amp;gt;&lt;br /&gt;
PR = 1 to indicate P is relative to the anchor’s palette offset (relative sprites only)&lt;br /&gt;
&lt;br /&gt;
Rotation is applied before mirroring.&amp;lt;br /&amp;gt;&lt;br /&gt;
Relative sprites, described below, replace X8 with PR.&lt;br /&gt;
&lt;br /&gt;
[[File:Sprite_flags.png|frame|center|All possibilities of Rotate, Mirror X and Mirror Y flags.]]&lt;br /&gt;
&lt;br /&gt;
==== Sprite Attribute 3 ====&lt;br /&gt;
&amp;lt;pre&amp;gt;V E N5 N4 N3 N2 N1 N0&amp;lt;/pre&amp;gt;&lt;br /&gt;
V = 1 to make the sprite visible&amp;lt;br /&amp;gt;&lt;br /&gt;
E = 1 to enable attribute byte 4&amp;lt;br /&amp;gt;&lt;br /&gt;
N = Sprite pattern to use 0-63&lt;br /&gt;
&lt;br /&gt;
If E=0, the sprite is fully described by sprite attributes 0-3. The sprite pattern is an 8-bit one identified by pattern N=0-63. The sprite is an anchor and cannot be made relative. The sprite is displayed as if sprite attribute 4 is zero.&lt;br /&gt;
&lt;br /&gt;
If E=1, the sprite is further described by sprite attribute 4.&lt;br /&gt;
&lt;br /&gt;
==== Sprite Attribute 4 ====&lt;br /&gt;
===== A. Extended Anchor Sprite =====&lt;br /&gt;
&amp;lt;pre&amp;gt;H N6 T X X Y Y Y8&amp;lt;/pre&amp;gt;&lt;br /&gt;
H = 1 if the sprite pattern is 4-bit&amp;lt;br /&amp;gt;&lt;br /&gt;
N6 = 7th pattern bit if the sprite pattern is 4-bit&amp;lt;br /&amp;gt;&lt;br /&gt;
T = 0 if relative sprites are composite type else 1 for unified type&amp;lt;br /&amp;gt;&lt;br /&gt;
XX = Magnification in the X direction (00 = 1x, 01 = 2x, 10 = 4x, 11 = 8x)&amp;lt;br /&amp;gt;&lt;br /&gt;
YY = Magnification in the Y direction (00 = 1x, 01 = 2x, 10 = 4x, 11 = 8x)&amp;lt;br /&amp;gt;&lt;br /&gt;
Y8 = Ninth bit of the sprite’s Y coordinate&lt;br /&gt;
&lt;br /&gt;
{H,N6} must not equal {0,1} as this combination is used to indicate a relative sprite.&lt;br /&gt;
&lt;br /&gt;
===== B. Relative Sprite, Composite Type =====&lt;br /&gt;
&amp;lt;pre&amp;gt;0 1 N6 X X Y Y PO&amp;lt;/pre&amp;gt;&lt;br /&gt;
N6 = 7th pattern bit if the sprite pattern is 4-bit&amp;lt;br /&amp;gt;&lt;br /&gt;
XX = Magnification in the X direction (00 = 1x, 01 = 2x, 10 = 4x, 11 = 8x)&amp;lt;br /&amp;gt;&lt;br /&gt;
YY = Magnification in the Y direction (00 = 1x, 01 = 2x, 10 = 4x, 11 = 8x)&amp;lt;br /&amp;gt;&lt;br /&gt;
PO = 1 to indicate the sprite pattern number is relative to the anchor’s&lt;br /&gt;
&lt;br /&gt;
===== C. Relative Sprite, Unified Type =====&lt;br /&gt;
&amp;lt;pre&amp;gt;0 1 N6 0 0 0 0 PO&amp;lt;/pre&amp;gt;&lt;br /&gt;
N6 = 7th pattern bit if the sprite pattern is 4-bit&amp;lt;br /&amp;gt;&lt;br /&gt;
PO = 1 to indicate the sprite pattern number is relative to the anchor’s&lt;br /&gt;
&lt;br /&gt;
The display surface for sprites is 320×256. The X coordinate of the sprite is nine bits, ranging over 0-511, and the Y coordinate is optionally nine bits again ranging over 0-511 or is eight bits ranging over 0-255. The full extent 0-511 wraps on both axes, meaning a sprite 16 pixels wide plotted at X coordinate 511 would see its first pixel not displayed (coordinate 511) and the following pixels displayed in coordinates 0-14.&lt;br /&gt;
&lt;br /&gt;
The full display area is visible in VGA. However, the HDMI display is vertically shorter so the top eight pixel rows (Y = 0-7) and the bottom eight pixel rows (Y = 248-255) will not be visible on an HDMI display.&lt;br /&gt;
&lt;br /&gt;
Sprites can be fully described by sprite attributes 0-3 if the E bit in sprite attribute 3 is zero. These sprites are compatible with the original sprite module from core versions prior to 2.00.26.&lt;br /&gt;
&lt;br /&gt;
If the E bit is set then a fifth sprite attribute, sprite attribute 4, becomes active. This attribute introduces scaling, 4-bit patterns, and relative sprites. Scaling is self-explanatory and 4-bit patterns were described in the last section. Relative sprites are described in the next section.&lt;br /&gt;
&lt;br /&gt;
=== Relative Sprites ===&lt;br /&gt;
Normal sprites (sprites that are not relative) are known as anchor sprites. As the sprite module draws sprites in the order 0-127 (there are 128 sprites), it internally stores characteristics of the last anchor sprite seen. If following sprites are relative, they inherit some of these characteristics, which allows relative sprites to have, among other things, coordinates relative to the anchor. This means moving the anchor sprite also causes its relatives to move with it.&lt;br /&gt;
&lt;br /&gt;
There are two types of relative sprites supported known as “Composite Sprites” and “Unified Sprites”. The type is determined by the anchor in the T bit of sprite attribute 4.&lt;br /&gt;
&lt;br /&gt;
==== A. Composite Sprites ====&lt;br /&gt;
The sprite module records the following information from the anchor:&lt;br /&gt;
&lt;br /&gt;
* Anchor.visible&lt;br /&gt;
* Anchor.X&lt;br /&gt;
* Anchor.Y&lt;br /&gt;
* Anchor.palette_offset&lt;br /&gt;
* Anchor.N (pattern number)&lt;br /&gt;
* Anchor.H (indicates if the sprite uses 4-bit patterns)&lt;br /&gt;
&lt;br /&gt;
These recorded items are not used by composite sprites:&lt;br /&gt;
&lt;br /&gt;
* Anchor.rotate&lt;br /&gt;
* Anchor.xmirror&lt;br /&gt;
* Anchor.ymirror&lt;br /&gt;
* Anchor.xscale&lt;br /&gt;
* Anchor.yscale&lt;br /&gt;
&lt;br /&gt;
The anchor determines if all its relative sprites use 4-bit patterns or not.&lt;br /&gt;
&lt;br /&gt;
The visibility of a particular relative sprite is the result of ANDing the anchor’s visibility with the relative sprite’s visibility. In other words, if the anchor is invisible then so are all its relatives.&lt;br /&gt;
&lt;br /&gt;
Relative sprites only have 8-bit X and Y coordinates (the ninth bits are taken for other purposes). These are signed offsets from the anchor’s X,Y coordinate. Moving the anchor moves all its relatives along with it.&lt;br /&gt;
&lt;br /&gt;
If the relative sprite has its PR bit set in sprite attribute 2, then the anchor’s palette offset is added to the relative sprite’s to determine the active palette offset for the relative sprite. Otherwise the relative sprite uses its own palette offset as usual.&lt;br /&gt;
&lt;br /&gt;
If the relative sprite has its PO bit set in sprite attribute 4, then the anchor’s pattern number is added to the relative sprite’s to determine the pattern used for display. Otherwise the relative sprite uses its own pattern number as usual. The intention is to supply a method to easily animate a large sprite by manipulating the pattern number in the anchor.&lt;br /&gt;
&lt;br /&gt;
A composite sprite is like a collection of independent sprites tied to an anchor.&lt;br /&gt;
&lt;br /&gt;
==== B. Unified Sprites ====&lt;br /&gt;
Unified sprites are a further extension of the composite type. The same information is recorded from the anchor and the same behaviour as described under composite sprites applies.&lt;br /&gt;
&lt;br /&gt;
The difference is the collection of anchor and relatives is treated as if it were a single 16×16 sprite. The anchor’s rotation, mirror, and scaling bits apply to all its relatives. Rotating the anchor causes all the relatives to rotate around the anchor. Mirroring the anchor causes the relatives to mirror around the anchor. The sprite hardware will automatically adjust X,Y coords and rotation, scaling and mirror bits of all relatives according to settings in the anchor.&lt;br /&gt;
&lt;br /&gt;
Unified sprites should be defined as if all its parts are 16×16 in size with the anchor controlling the look of the whole.&lt;br /&gt;
&lt;br /&gt;
A unified sprite is like a big version of an individual 16×16 sprite controlled by the anchor.&lt;br /&gt;
&lt;br /&gt;
=== Programming Sprites ===&lt;br /&gt;
Sprites are created via three I/O ports and a nextreg interface.&lt;br /&gt;
&lt;br /&gt;
{{PortNo|$303B}} (W)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;X S S S S S S S&lt;br /&gt;
N6 X N N N N N N&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A write to this port has two effects.&lt;br /&gt;
&lt;br /&gt;
One is it selects one of 128 sprites for writing sprite attributes via port 0x57.&lt;br /&gt;
&lt;br /&gt;
The other is it selects one of 128 4-bit patterns in pattern memory for writing sprite patterns via port 0x5B. The N6 bit shown is the least significant in the 7-bit pattern number and should always be zero when selecting one of 64 8-bit patterns indicated by N.&lt;br /&gt;
&lt;br /&gt;
{{PortNo|$xx57}} (W)&lt;br /&gt;
&lt;br /&gt;
Once a sprite is selected via port 0x303B, its attributes can be written to this port one byte after another. Sprites can have either four or five attribute bytes and the internal attribute pointer will move onto the next sprite after those four or five attribute bytes are written. This means you can select a sprite via port 0x303B and write attributes for as many sequential sprites as desired. The attribute pointer will roll over from sprite 127 to sprite 0.&lt;br /&gt;
&lt;br /&gt;
{{PortNo|$xx5B}} (W)&lt;br /&gt;
&lt;br /&gt;
Once a pattern number is selected via port 0x303B, the 256-byte or 128-byte pattern can be written to this port. The internal pattern pointer auto-increments after each write so as many sequential patterns as desired can be written. The internal pattern pointer will roll over from pattern 127 to pattern 0 (4-bit patterns) or from pattern 63 to pattern 0 (8-bit patterns) automatically.&lt;br /&gt;
&lt;br /&gt;
{{PortNo|$303B}} (R)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;0 0 0 0 0 0 M C&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
M = 1 if the maximum number of sprites per line was exceeded&amp;lt;br /&amp;gt;&lt;br /&gt;
C = 1 if any two displayed sprites collide on screen&lt;br /&gt;
&lt;br /&gt;
Reading this port automatically resets the M and C bits.&lt;br /&gt;
&lt;br /&gt;
Besides the i/o interface, there is a nextreg interface to sprite attributes. The nextreg interface allows the copper to manipulate sprites and grants the program random access to a sprite’s individual attribute bytes.&lt;br /&gt;
&lt;br /&gt;
(R/W) 0x34 (52) =&amp;gt; Sprite Number&amp;lt;br /&amp;gt;&lt;br /&gt;
If the sprite number is in lockstep with io port 0x303B (nextreg 0x09 bit 4 is set)&amp;lt;br /&amp;gt;&lt;br /&gt;
bits 7 = Pattern address offset (Add 128 to pattern address)&amp;lt;br /&amp;gt;&lt;br /&gt;
bits 6-0 = Sprite number 0-127, Pattern number 0-63&amp;lt;br /&amp;gt;&lt;br /&gt;
Selects which sprite has its attributes connected to the following registers.&amp;lt;br /&amp;gt;&lt;br /&gt;
Effectively performs an out to port 0x303B with the same value&amp;lt;br /&amp;gt;&lt;br /&gt;
Otherwise&amp;lt;br /&amp;gt;&lt;br /&gt;
bit 7 = Ignored&amp;lt;br /&amp;gt;&lt;br /&gt;
bits 6-0 = Sprite number 0-127&amp;lt;br /&amp;gt;&lt;br /&gt;
Selects which sprite has its attributes connected to the following registers.&amp;lt;br /&amp;gt;&lt;br /&gt;
Bit 7 always reads back as zero.&lt;br /&gt;
&lt;br /&gt;
This nextreg can operate in two modes.&lt;br /&gt;
&lt;br /&gt;
If nextreg 0x09 bit 4 is set, then this register is kept in lockstep with i/o port 0x303B. A write to this nextreg is equivalent to a write to port 0x303B and vice versa. In this mode, the i/o interface and nextreg interface are exactly equivalent.&lt;br /&gt;
&lt;br /&gt;
If nextreg 0x09 bit 4 is reset, then the nextreg interface is decoupled from i/o port 0x303B. This nextreg is used to select a particular sprite 0-127 and this is completely independent from the sprite selected for the i/o interface. This independence allows the copper, for example, to manipulate different sprites than the cpu using the i/o interface.&lt;br /&gt;
&lt;br /&gt;
(W) 0x35 (53) =&amp;gt; Sprite Attribute 0&amp;lt;br /&amp;gt;&lt;br /&gt;
(W) 0x75 (117) =&amp;gt; Sprite Attribute 0 with automatic post increment of Sprite Number&amp;lt;br /&amp;gt;&lt;br /&gt;
bits 7-0 = LSB of X coordinate&lt;br /&gt;
&lt;br /&gt;
A write to nextreg 0x75 also increases the selected sprite in nextreg 0x34.&lt;br /&gt;
&lt;br /&gt;
(W) 0x36 (54) =&amp;gt; Sprite Attribute 1&amp;lt;br /&amp;gt;&lt;br /&gt;
(W) 0x76 (118) =&amp;gt; Sprite Attribute 1 with automatic post increment of Sprite Number&amp;lt;br /&amp;gt;&lt;br /&gt;
bits 7-0 = LSB of Y coordinate&lt;br /&gt;
&lt;br /&gt;
A write to nextreg 0x76 also increases the selected sprite in nextreg 0x34.&lt;br /&gt;
&lt;br /&gt;
(W) 0x37 (55) =&amp;gt; Sprite Attribute 2&amp;lt;br /&amp;gt;&lt;br /&gt;
(W) 0x77 (119) =&amp;gt; Sprite Attribute 2 with automatic post increment of Sprite Number&amp;lt;br /&amp;gt;&lt;br /&gt;
bits 7-4 = Palette offset added to top 4 bits of sprite colour index&amp;lt;br /&amp;gt;&lt;br /&gt;
bit 3 = X mirror&amp;lt;br /&amp;gt;&lt;br /&gt;
bit 2 = Y mirror&amp;lt;br /&amp;gt;&lt;br /&gt;
bit 1 = Rotate&amp;lt;br /&amp;gt;&lt;br /&gt;
bit 0 = MSB of X coordinate&lt;br /&gt;
&lt;br /&gt;
A write to nextreg 0x77 also increases the selected sprite in nextreg 0x34.&lt;br /&gt;
&lt;br /&gt;
(W) 0x38 (56) =&amp;gt; Sprite Attribute 3&amp;lt;br /&amp;gt;&lt;br /&gt;
(W) 0x78 (120) =&amp;gt; Sprite Attribute 3 with automatic post increment of Sprite Number&amp;lt;br /&amp;gt;&lt;br /&gt;
bit 7 = Visible flag (1 = displayed)&amp;lt;br /&amp;gt;&lt;br /&gt;
bit 6 = Extended attribute (1 = Sprite Attribute 4 is active)&amp;lt;br /&amp;gt;&lt;br /&gt;
bits 5-0 = Pattern used by sprite (0-63)&lt;br /&gt;
&lt;br /&gt;
A write to nextreg 0x78 also increases the selected sprite in nextreg 0x34.&lt;br /&gt;
&lt;br /&gt;
(W) 0x39 (57) =&amp;gt; Sprite Attribute 4&amp;lt;br /&amp;gt;&lt;br /&gt;
(W) 0x79 (121) =&amp;gt; Sprite Attribute 4 with automatic post increment of Sprite Number&amp;lt;br /&amp;gt;&lt;br /&gt;
4-bit Sprites&amp;lt;br /&amp;gt;&lt;br /&gt;
bit 7 = H (1 = sprite uses 4-bit patterns)&amp;lt;br /&amp;gt;&lt;br /&gt;
bit 6 = N6 (0 = use the first 128 bytes of the pattern else use the last 128 bytes)&amp;lt;br /&amp;gt;&lt;br /&gt;
bit 5 = 1 if relative sprites are composite, 0 if relative sprites are unified&amp;lt;br /&amp;gt;&lt;br /&gt;
Scaling&amp;lt;br /&amp;gt;&lt;br /&gt;
bits 4-3 = X scaling (00 = 1x, 01 = 2x, 10 = 4x, 11 = 8x)&amp;lt;br /&amp;gt;&lt;br /&gt;
bits 2-1 = Y scaling (00 = 1x, 01 = 2x, 10 = 4x, 11 = 8x)&amp;lt;br /&amp;gt;&lt;br /&gt;
bit 0 = MSB of Y coordinate&amp;lt;br /&amp;gt;&lt;br /&gt;
A relative mode is enabled if H,N6 = 01. The byte format for relative sprites is described above.&lt;br /&gt;
&lt;br /&gt;
A write to nextreg 0x79 also increases the selected sprite in nextreg 0x34.&lt;br /&gt;
&lt;br /&gt;
=== Global Control of Sprites ===&lt;br /&gt;
The following nextreg are also of interest for sprites.&lt;br /&gt;
&lt;br /&gt;
{{NextRegNo|$09}} (09)&amp;lt;br /&amp;gt;&lt;br /&gt;
bit 7 = Mono setting for AY 2 (1 = mono, 0 default)&amp;lt;br /&amp;gt;&lt;br /&gt;
bit 6 = Mono setting for AY 1 (1 = mono, 0 default)&amp;lt;br /&amp;gt;&lt;br /&gt;
bit 5 = Mono setting for AY 0 (1 = mono, 0 default)&amp;lt;br /&amp;gt;&lt;br /&gt;
bit 4 = Sprite id lockstep (1 = Nextreg 0x34 and IO Port 0x303B are in lockstep, 0 default)&amp;lt;br /&amp;gt;&lt;br /&gt;
bit 3 = Disables Kempston port ($DF) if set&amp;lt;br /&amp;gt;&lt;br /&gt;
bit 2 = Disables divMMC ports ($E3, $E7, $EB) if set&amp;lt;br /&amp;gt;&lt;br /&gt;
bits 1-0 = scanlines (0 after a PoR or Hard-reset)&amp;lt;br /&amp;gt;&lt;br /&gt;
00 = scanlines off&amp;lt;br /&amp;gt;&lt;br /&gt;
01 = scanlines 75%&amp;lt;br /&amp;gt;&lt;br /&gt;
10 = scanlines 50%&amp;lt;br /&amp;gt;&lt;br /&gt;
11 = scanlines 25%&lt;br /&gt;
&lt;br /&gt;
Bit 4 determines if the i/o interface and nextreg interface operate in lockstep.&lt;br /&gt;
&lt;br /&gt;
{{NextRegNo|$15}} (21)&amp;lt;br /&amp;gt;&lt;br /&gt;
bit 7 = LoRes mode, 128 x 96 x 256 colours (1 = enabled)&amp;lt;br /&amp;gt;&lt;br /&gt;
bit 6 = Sprite priority (1 = sprite 0 on top, 0 = sprite 127 on top)&amp;lt;br /&amp;gt;&lt;br /&gt;
bit 5 = Enable sprite clipping in over border mode (1 = enabled)&amp;lt;br /&amp;gt;&lt;br /&gt;
bits 4-2 = set layers priorities:&amp;lt;br /&amp;gt;&lt;br /&gt;
Reset default is 000, sprites over the Layer 2, over the ULA graphics&amp;lt;br /&amp;gt;&lt;br /&gt;
000 – S L U&amp;lt;br /&amp;gt;&lt;br /&gt;
001 – L S U&amp;lt;br /&amp;gt;&lt;br /&gt;
010 – S U L&amp;lt;br /&amp;gt;&lt;br /&gt;
011 – L U S&amp;lt;br /&amp;gt;&lt;br /&gt;
100 – U S L&amp;lt;br /&amp;gt;&lt;br /&gt;
101 – U L S&amp;lt;br /&amp;gt;&lt;br /&gt;
110 – S(U+L) ULA and Layer 2 combined, colours clamped to 7&amp;lt;br /&amp;gt;&lt;br /&gt;
111 – S(U+L-5) ULA and Layer 2 combined, colours clamped to [0,7]&amp;lt;br /&amp;gt;&lt;br /&gt;
bit 1 = Over border (1 = yes) (Back to 0 after a reset)&amp;lt;br /&amp;gt;&lt;br /&gt;
bit 0 = Sprites visible (1 = visible) (Back to 0 after a reset)&lt;br /&gt;
&lt;br /&gt;
Bit 0 must be set for sprites to be visible.&lt;br /&gt;
&lt;br /&gt;
Bit 1 set allows sprites to be visible in the border area. When this bit is reset, sprites will not display outside the 256×192 area of the ULA display.&lt;br /&gt;
&lt;br /&gt;
Bit 5 set enables clipping when sprites are visible in the border area. If reset, no clipping is applied and sprites will be visible in the full 320×256 space.&lt;br /&gt;
&lt;br /&gt;
The sprite module draws sprites in the order 0-127 in each scanline. Bit 6 determines whether sprite 0 is topmost or sprite 127 is topmost.&lt;br /&gt;
&lt;br /&gt;
Bits 4:2 determine layer priority and how sprites overlay or are obscured by other layers.&lt;br /&gt;
&lt;br /&gt;
{{NextRegNo|$19}} (25)&amp;lt;br /&amp;gt;&lt;br /&gt;
bits 7-0 = Coord. of the clip window&amp;lt;br /&amp;gt;&lt;br /&gt;
1st write – X1 position&amp;lt;br /&amp;gt;&lt;br /&gt;
2nd write – X2 position&amp;lt;br /&amp;gt;&lt;br /&gt;
3rd write – Y1 position&amp;lt;br /&amp;gt;&lt;br /&gt;
4rd write – Y2 position&amp;lt;br /&amp;gt;&lt;br /&gt;
The values are 0,255,0,191 after a Reset&amp;lt;br /&amp;gt;&lt;br /&gt;
Reads do not advance the clip position&amp;lt;br /&amp;gt;&lt;br /&gt;
When the clip window is enabled for sprites in “over border” mode, the X coords are internally doubled and the clip window origin is moved to the sprite origin inside the border.&lt;br /&gt;
&lt;br /&gt;
Sprites will only be visible inside the clipping window. When not in over-border mode (bit 1 of nextreg 0x15) the clipping window is given in ULA screen coordinates with 0,0 corresponding to the top left corner of the ULA screen. In over-border mode, the clipping window’s origin is moved to the sprite coordinate origin 32 pixels to the left and 32 pixels above the ULA screen origin.&lt;br /&gt;
&lt;br /&gt;
Regardless, sprite position is always in sprite coordinates with 32,32 corresponding to the top left corner of the ULA screen.&lt;br /&gt;
&lt;br /&gt;
{{NextRegNo|$1C}} (28) (W)&amp;lt;br /&amp;gt;&lt;br /&gt;
bits 7-4 = Reserved, must be 0&amp;lt;br /&amp;gt;&lt;br /&gt;
bit 3 – reset the tilemap clip index&amp;lt;br /&amp;gt;&lt;br /&gt;
bit 2 – reset the ULA/LoRes clip index.&amp;lt;br /&amp;gt;&lt;br /&gt;
bit 1 – reset the sprite clip index.&amp;lt;br /&amp;gt;&lt;br /&gt;
bit 0 – reset the Layer 2 clip index.&lt;br /&gt;
&lt;br /&gt;
Can be used to reset nextreg 0x19.&lt;br /&gt;
&lt;br /&gt;
{{NextRegNo|$43}} (67)&amp;lt;br /&amp;gt;&lt;br /&gt;
bit 7 = ‘1’ to disable palette write auto-increment.&amp;lt;br /&amp;gt;&lt;br /&gt;
bits 6-4 = Select palette for reading or writing:&amp;lt;br /&amp;gt;&lt;br /&gt;
000 = ULA first palette&amp;lt;br /&amp;gt;&lt;br /&gt;
100 = ULA second palette&amp;lt;br /&amp;gt;&lt;br /&gt;
001 = Layer 2 first palette&amp;lt;br /&amp;gt;&lt;br /&gt;
101 = Layer 2 second palette&amp;lt;br /&amp;gt;&lt;br /&gt;
010 = Sprites first palette&amp;lt;br /&amp;gt;&lt;br /&gt;
110 = Sprites second palette&amp;lt;br /&amp;gt;&lt;br /&gt;
011 = Tilemap first palette&amp;lt;br /&amp;gt;&lt;br /&gt;
111 = Tilemap second palette&amp;lt;br /&amp;gt;&lt;br /&gt;
bit 3 = Select Sprites palette (0 = first palette, 1 = second palette)&amp;lt;br /&amp;gt;&lt;br /&gt;
bit 2 = Select Layer 2 palette (0 = first palette, 1 = second palette)&amp;lt;br /&amp;gt;&lt;br /&gt;
bit 1 = Select ULA palette (0 = first palette, 1 = second palette)&amp;lt;br /&amp;gt;&lt;br /&gt;
bit 0 = Enable ULANext mode if 1. (0 after a reset)&lt;br /&gt;
&lt;br /&gt;
Sprites have two associated palettes which can be selected in this nextreg.&lt;br /&gt;
&lt;br /&gt;
{{NextRegNo|$40}} (64)&amp;lt;br /&amp;gt;&lt;br /&gt;
bits 7-0 = Select the palette index to change the associated colour.&amp;lt;br /&amp;gt;&lt;br /&gt;
For the ULA only, INKs are mapped to indices 0-7, Bright INKS to indices 8-15, PAPERs to indices 16-23 and Bright PAPERs to indices 24-31.&lt;br /&gt;
In ULANext mode, INKs come from a subset of indices 0-127 and PAPERs come from&lt;br /&gt;
a subset of indices 128-255. The number of active indices depends on the number&lt;br /&gt;
of attribute bits assigned to INK and PAPER out of the attribute byte.&lt;br /&gt;
The ULA always takes border colour from paper.&lt;br /&gt;
&lt;br /&gt;
Select the starting palette index if writing the sprite palette.&lt;br /&gt;
&lt;br /&gt;
Palette values can be written in either 8-bit or 9-bit form:&lt;br /&gt;
&lt;br /&gt;
{{NextRegNo|$41}} (65)&amp;lt;br /&amp;gt;&lt;br /&gt;
bits 7-0 = Colour for the palette index selected by the register 0x40.&amp;lt;br /&amp;gt;&lt;br /&gt;
(Format is RRRGGGBB – the lower blue bit of the 9-bit colour will be a logical OR of blue bits 1 and 0 of this 8-bit value.)&lt;br /&gt;
After the write, the palette index is auto-incremented to the next index if the auto-increment is enabled at reg 0x43. Reads do not auto-increment.&lt;br /&gt;
&lt;br /&gt;
{{NextRegNo|$44}} (68)&amp;lt;br /&amp;gt;&lt;br /&gt;
Two consecutive writes are needed to write the 9 bit colour&amp;lt;br /&amp;gt;&lt;br /&gt;
1st write:&amp;lt;br /&amp;gt;&lt;br /&gt;
bits 7-0 = RRRGGGBB&amp;lt;br /&amp;gt;&lt;br /&gt;
2nd write.&amp;lt;br /&amp;gt;&lt;br /&gt;
If writing a L2 palette&amp;lt;br /&amp;gt;&lt;br /&gt;
———————————————————————–&amp;lt;br /&amp;gt;&lt;br /&gt;
bit 7 = 1 for L2 priority colour, 0 for normal&amp;lt;br /&amp;gt;&lt;br /&gt;
Priority colour will always be on top even on an SLU priority arrangement. If you need the exact same colour on priority and non priority locations you will need to program the same colour twice changing bit 7 to 0 for the second colour&amp;lt;br /&amp;gt;&lt;br /&gt;
bits 6-1 = Reserved, must be 0&amp;lt;br /&amp;gt;&lt;br /&gt;
bit 0 = lsb B&lt;br /&gt;
&lt;br /&gt;
If writing another palette&amp;lt;br /&amp;gt;&lt;br /&gt;
———————————————————————–&amp;lt;br /&amp;gt;&lt;br /&gt;
bits 7-1 = Reserved, must be 0&amp;lt;br /&amp;gt;&lt;br /&gt;
bit 0 = lsb B&lt;br /&gt;
&lt;br /&gt;
After the two consecutive writes the palette index is auto-incremented if the auto-increment is enabled by reg 0x43.&lt;br /&gt;
&lt;br /&gt;
Reads only return the 2nd byte and do not auto-increment.&lt;br /&gt;
&lt;br /&gt;
{{NextRegNo|$4B}} (75)&amp;lt;br /&amp;gt;&lt;br /&gt;
bits 7-0 = Set the index value (0xE3 after reset)&amp;lt;br /&amp;gt;&lt;br /&gt;
For 4-bit sprites only the bottom 4-bits are relevant.&lt;br /&gt;
&lt;br /&gt;
Determines the transparent colour index used for sprites.&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=MAME:Installing&amp;diff=41546</id>
		<title>MAME:Installing</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=MAME:Installing&amp;diff=41546"/>
		<updated>2025-12-22T01:50:11Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: Adding url to MAME docs with default keys&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[https://www.mamedev.org/ MAME] (formerly an acronym of Multiple Arcade Machine Emulator) is a free and open-source emulator designed to emulate the hardware of arcade games, later expanded to include video game consoles, old computers and other systems in software on modern personal computers and other platforms.&lt;br /&gt;
&lt;br /&gt;
MAME has supported the ZX Spectrum Next since version 0.267. The existing implementation is based on the v3.02.01 core and implements most of the features.&lt;br /&gt;
&lt;br /&gt;
= Installation =&lt;br /&gt;
&lt;br /&gt;
You will need to install MAME, provide it with the Next firmware (&#039;ROM&#039;), and get the NextZXOS image:&lt;br /&gt;
&lt;br /&gt;
=== 1. Get MAME ===&lt;br /&gt;
Start with these official MAME releases. If you encounter crashes or other bugs, try replacing the MAME executable with holub&#039;s latest Continuous Integration (CI) builds as described at the end of this article.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Windows:&#039;&#039;&#039; Download [https://www.mamedev.org/release.html MAME for Windows].&lt;br /&gt;
* &#039;&#039;&#039;macOS:&#039;&#039;&#039; Download [https://sdlmame.lngn.net/ MAME for macOS].&lt;br /&gt;
* &#039;&#039;&#039;Linux:&#039;&#039;&#039; Install MAME from the flatpak repositories by running:&lt;br /&gt;
&amp;lt;pre&amp;gt;sudo flatpak install org.mamedev.MAME&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that Windows and macOS will likely prevent you from launching MAME directly for security reasons. See below on how to solve this.&lt;br /&gt;
&lt;br /&gt;
Alternatively, for the MAME platform as a whole, you can also check your package manager, or [https://docs.mamedev.org/initialsetup/compilingmame.html build from sources].&lt;br /&gt;
&lt;br /&gt;
Git of official MAME: [https://github.com/mamedev/mame/ https://github.com/mamedev/mame/] [https://github.com/mamedev/mame/blob/master/src/mame/sinclair/specnext.cpp specnext.cpp]&lt;br /&gt;
&lt;br /&gt;
Git of holub&#039;s fork: [https://github.com/holub/mame https://github.com/holub/mame] [https://github.com/holub/mame/blob/master/src/mame/sinclair/specnext.cpp specnext.cpp] (may contain extra fixes and features before they are merged to official repository)&lt;br /&gt;
&lt;br /&gt;
=== 2. Get TBBLUE (the Next &#039;boot ROM&#039;) ===&lt;br /&gt;
Put the file  [https://github.com/Threetwosevensixseven/NexCreator/raw/master/bootroms/tbblue.zip tbblue.zip] into MAME&#039;s &amp;lt;code&amp;gt;roms&amp;lt;/code&amp;gt; folder. Don&#039;t extract it; MAME will look for the zip file when the &amp;quot;tbblue&amp;quot; machine is selected.&lt;br /&gt;
&lt;br /&gt;
Note: The ROMs in this zip are what is embedded inside the FPGA core on real Next hardware. They&#039;re different from any ZX Spectrum machine ROMs you may be used to using, that are on the distro, SD card or SD image file.&lt;br /&gt;
&lt;br /&gt;
=== 3. Get the NextZXOS Image ===&lt;br /&gt;
Get an SD card image file of [https://www.specnext.com/latestdistro/ NextZXOS]. Note that currently some published disk images on the official SpecNext.com site (the &amp;lt;code&amp;gt;latestdistro&amp;lt;/code&amp;gt; link points to the official location where the latest distribution can be found) do not work with some emulators, but all images from &amp;lt;code&amp;gt;https://zxnext.uk/hosted/&amp;lt;/code&amp;gt; work with both MAME and CSpect, like [https://zxnext.uk/hosted/index_files/hdfimages/cspect-next-2gb.zip this SD card image in the zip archive]. Extract the image &amp;lt;code&amp;gt;cspect-next-2gb.img&amp;lt;/code&amp;gt; from the archive to use it, then point MAME to this SD card image with the &amp;lt;code&amp;gt;-hard1&amp;lt;/code&amp;gt; option (or select that file from the menu inside MAME).&lt;br /&gt;
&lt;br /&gt;
= Usage =&lt;br /&gt;
MAME looks for its configuration and helper files in specific (configurable) folders. By default, these are relative to the current working directory (cwd), i.e., from where you launched the executable. The &amp;lt;code&amp;gt;mame.ini&amp;lt;/code&amp;gt; file and folders like &amp;lt;code&amp;gt;roms, bgfx, plugins, language, ...&amp;lt;/code&amp;gt; are expected there, unless the &amp;lt;code&amp;gt;mame.ini&amp;lt;/code&amp;gt; file specifies other paths. When launching through a desktop icon or menu, depending on the OS, the working directory is often defined by the properties of that launch shortcut. When launching MAME from the command line, the current directory is &amp;quot;cwd&amp;quot; (doh). On Linux, MAME will look for &amp;lt;code&amp;gt;mame.ini&amp;lt;/code&amp;gt; first in the &amp;lt;code&amp;gt;~/.mame&amp;lt;/code&amp;gt; folder. You can use the option &amp;lt;code&amp;gt;-inipath&amp;lt;/code&amp;gt; to point MAME to a different path for the &amp;lt;code&amp;gt;mame.ini&amp;lt;/code&amp;gt; file.&lt;br /&gt;
&lt;br /&gt;
However, the fastest way to run a machine with a desired configuration is from the command prompt, without requiring a &amp;lt;code&amp;gt;mame.ini&amp;lt;/code&amp;gt; file. Most of the features are also available through MAME&#039;s UI, although that takes more time to configure.&lt;br /&gt;
&lt;br /&gt;
As an example, this invocation enables the UI, uses &amp;quot;crisp pixels&amp;quot;, starts in a window, doesn&#039;t display the starting gameinfo window (it can still be displayed interactively from the UI), disables the mouse, confirms before exiting MAME, and specifies the disk image (remember to adjust the path to it):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;mame -ui_active -nounevenstretch -aspect 2:1 -video bgfx  -bgfx_screen_chains unfiltered -window -skip_gameinfo -mouse_device none -confirm_quit tbblue -hard1 /path/to/cspect-next-2gb.img&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let&#039;s cover some useful options:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Run inside a window and with no mouse support, until you get familiar with the UI keys:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; mame tbblue -window -mouse_device none -hard1 /path/to/next-distribution.img&amp;lt;/pre&amp;gt;&lt;br /&gt;
To launch the Linux flatpak version using the same options:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; flatpak run org.mamedev.MAME tbblue -window -mouse_device none -hard1 /path/to/next-distribution.img&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Activate UI keys on startup:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -ui_active&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Don&#039;t show the info popup on startup:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -skip_gameinfo&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;Run with debugger. If you don&#039;t request this on startup, you won&#039;t have access to it:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -debug&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;Use &amp;quot;crisp&amp;quot; pixels:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -nounevenstretch -aspect 2:1 -video bgfx -bgfx_screen_chains unfiltered&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;No joystick connected to PC (having this may slightly speed up MAME&#039;s startup, but &#039;&#039;remember to remove this part from the command line and the corresponding setting in the ini file if you do want to use a joystick&#039;&#039;):&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -joystickprovider none&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;Ask for confirmation when exiting MAME (otherwise it&#039;s easy to exit MAME accidentally by hitting ESC, especially when playing games or navigating menus):&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -confirm_quit&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Check the [https://docs.mamedev.org/commandline/commandline-all.html#mame-commandline-universal official MAME documentation] for more advanced usage.&lt;br /&gt;
&lt;br /&gt;
= Security: Allowing MAME to Run on Windows and macOS =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;On Windows,&#039;&#039;&#039; you will need to confirm that you want to launch MAME by clicking &amp;quot;Run Anyway&amp;quot; on first launch. &#039;&#039;(More details needed here.)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;On macOS,&#039;&#039;&#039; MAME will not open at first. Instead, a dialog will appear saying:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;“mame” Not Opened. Apple could not verify “mame” is free of malware that may harm your Mac or compromise your privacy.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Click “Done”. Then open &#039;&#039;&#039;System Settings -&amp;gt; Privacy &amp;amp; Security&#039;&#039;&#039;, and scroll down to the message &#039;&#039;mame was blocked to protect your Mac.&#039;&#039; Click “Allow Anyway”.&lt;br /&gt;
&lt;br /&gt;
Now launch MAME again. A dialog will ask once more if you want to open “mame”. Click “Open Anyway”, and enter your password or use Touch ID when prompted by macOS.&lt;br /&gt;
&lt;br /&gt;
From now on, you can launch this version of MAME without warnings. However, you &#039;&#039;&#039;will&#039;&#039;&#039; need to repeat this each time you update MAME.&lt;br /&gt;
&lt;br /&gt;
= Keys =&lt;br /&gt;
&lt;br /&gt;
Keys are emulated in two modes: either to control the MAME emulator or completely dedicated to the emulated system (the Next). You can toggle between these two keyboard modes with ScrLk (on Win and Linux) or fn+delete (on Mac).&lt;br /&gt;
&lt;br /&gt;
Some UI keys:&lt;br /&gt;
* F3 - soft reset&lt;br /&gt;
* Shift+F3 - hard reset&lt;br /&gt;
* F4 - sprites/tiles/font viewer (Enter, ], [)&lt;br /&gt;
* F5 - pause emulation&lt;br /&gt;
* F6 - save state&lt;br /&gt;
* F7 - load state&lt;br /&gt;
* Tab - emulator settings&lt;br /&gt;
* ~ - menu&lt;br /&gt;
* ` (backtick) - debugger (when enabled by starting MAME with &amp;lt;code&amp;gt;-debug&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;-d&amp;lt;/code&amp;gt; on the command line)&lt;br /&gt;
* PgDwn (Linux/Mac), fn-Downarrow (MacBooks) or Insert (Win) - hold down to fast-forward emulation at maximum speed, e.g., to speed up booting the Next&lt;br /&gt;
* Esc - exit (exits menus but also the entire emulator - see &amp;lt;code&amp;gt;-confirm_quit&amp;lt;/code&amp;gt; option above)&lt;br /&gt;
* F11 - DivMMC NMI&lt;br /&gt;
* F12 - Multiface NMI&lt;br /&gt;
&lt;br /&gt;
Check [https://docs.mamedev.org/usingmame/defaultkeys.html default keys documentation] for more.&lt;br /&gt;
&lt;br /&gt;
= Changing the UI toggle key =&lt;br /&gt;
&lt;br /&gt;
Some laptops don&#039;t have a Scroll Lock key, so you may not be able to exit MAME if you run it in full-screen mode. In these cases, you can change the UI toggle key as follows:&lt;br /&gt;
&lt;br /&gt;
* Run MAME without any command line arguments (except maybe -window) to open its GUI.&lt;br /&gt;
* Push TAB and enter the General Settings menu.&lt;br /&gt;
* Go to Input Assignments -&amp;gt; User Interface -&amp;gt; Toggle UI controls and select a new key. I use Right Alt / Alt GR.&lt;br /&gt;
* Return to the previous menu twice, then choose Save Settings&lt;br /&gt;
&lt;br /&gt;
= Creating a NextZXOS SD card image =&lt;br /&gt;
&lt;br /&gt;
Most users wanting to emulate the Next using MAME will be fine using a pre-built SD card image downloaded from the specnext website. The following guide is provided for anyone wanting to create a NextZXOS SD card image from scratch.&lt;br /&gt;
&lt;br /&gt;
Download the [https://www.specnext.com/latestdistro/ latest NextZXOS distribution zip file] (named something like sn-complete-WX.YZ.zip) and extract it into a new, empty directory.&lt;br /&gt;
&lt;br /&gt;
== Creating and populating a SD card image using hdfmonkey jjjs build ==&lt;br /&gt;
&lt;br /&gt;
The [[https://www.specnext.com/forum/viewtopic.php?t=2604 | &amp;lt;code&amp;gt;hdfmonkey &amp;quot;jjjs build&amp;quot;&amp;lt;/code&amp;gt;]] is a variant of hdfmonkey tool which includes some unique features and its main archive (at the previously given link) also contains pre-built binaries for Windows x64, MacOS x64, MacOS Apple Silicon and Linux x64. (Alternatively, the process to build a local Linux version of the executable is described [[Development_Tools:Linux_setup#Building_the_executable_binary_2 | here]] )&lt;br /&gt;
&lt;br /&gt;
If you extracted sn-complete-WX.YZ.zip into a subdirectory named &amp;lt;code&amp;gt;snWXYZ&amp;lt;/code&amp;gt;, and you want to create a 1GB image called &amp;lt;code&amp;gt;NextZXOS.img&amp;lt;/code&amp;gt; and you have a jjjs build&amp;quot; of hdfmonkey, then it&#039;s enough to do:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
hdfmonkey create NextZXOS.img 1G&lt;br /&gt;
hdfmonkey putdir NextZXOS.img snWXYZ /&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first line creates an empty 1GB image and formats it with the best FAT parameters suited to the size of the image.&lt;br /&gt;
&lt;br /&gt;
The second line recursively copies all the content of the directory &amp;lt;code&amp;gt;snWXYZ&amp;lt;/code&amp;gt; to the image, preserving the directory structure inside, starting from the &amp;lt;code&amp;gt;/&amp;lt;/code&amp;gt; in the image.&lt;br /&gt;
&lt;br /&gt;
One of the advantages of this method is that even if the image has a capacity of 1GB, it will use much less space on your hard drive until you fill up the image. On Linux or MacOS, a command &amp;lt;code&amp;gt;du -h NextZXOS.img&amp;lt;/code&amp;gt; shows the actual amount of disk space used by the image. On Windows the same information can be seen in the File Properties dialog.&lt;br /&gt;
&lt;br /&gt;
The fastest way to transfer a file or a directory (including its content, recursively) into an image is by using a single &amp;lt;code&amp;gt;put&amp;lt;/code&amp;gt; (or &amp;lt;code&amp;gt;putdir&amp;lt;/code&amp;gt;, if it&#039;s to transfer the directory file content to an existing directory) command of hdfmonkey.&lt;br /&gt;
&lt;br /&gt;
The most convenient tool to copy of all the content from the image to a folder outside of the image is 7-zip. On Windows, just use the 7-zip GUI. On MacOS and Linux, see: [[Development_Tools:Linux_setup#Extracting_all_files_from_the_SD_image]].&lt;br /&gt;
&lt;br /&gt;
== Creating and populating a SD card image using Linux ==&lt;br /&gt;
&lt;br /&gt;
While using hdfmonkey jjjs build works on Linux and the pre-built binary for Intel x64 exists, and using it creates an image which will have high compatibility, it is also possible to use more common Linux tools to create a SD image. Note however that the resulting image of this method, if the parameters of different steps aren&#039;t carefully chosen and matched, could be out of the official FAT specifications and/or the expectations of some of the existing programs or systems. This method creates an image which is incompatible with the current (as of 2025-12-13) CSpect version, at least for some sizes of the image:&lt;br /&gt;
&lt;br /&gt;
Create a disk image of at least 256 MB. The current complete NextZXOS distro requires at least 130 MB of disk space. This command will create a 256 MB SD card image; change the &amp;lt;code&amp;gt;count&amp;lt;/code&amp;gt; value to make the image file as big as you want in megabytes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;dd if=/dev/zero of=NextZXOS.img bs=1M count=256&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The rest of the commands in this guide must be run as the root user or using sudo.&lt;br /&gt;
&lt;br /&gt;
You will need to install the dosfstools and parted packages if they are not already installed. Debian and Ubuntu Linux users can install these using this apt command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;apt install dosfstools parted&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mount the SD card image loopback device:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;losetup --partscan --show --find NextZXOS.img&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Create a FAT32 partition:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;parted /dev/loop0 mklabel msdos&lt;br /&gt;
parted /dev/loop0 mkpart primary fat32 1MB 100%&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Format and mount the partition under /mnt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;mkfs.vfat -F 32 /dev/loop0p1&lt;br /&gt;
mount /dev/loop0p1 /mnt&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can now copy all of the files you extracted from sn-complete-WX.YZ.zip into /mnt.&lt;br /&gt;
&lt;br /&gt;
After copying the files, unmount and detach the loopback device (the SD card image):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;umount /mnt/&lt;br /&gt;
losetup -D&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Mounting SD card images under Linux =&lt;br /&gt;
&lt;br /&gt;
Under Linux, you can use &amp;lt;code&amp;gt;losetup&amp;lt;/code&amp;gt; to mount SD card images as loop devices. This lets you copy files to and from the image and perform other file management tasks as you would using any other filesystem.&lt;br /&gt;
&lt;br /&gt;
Run the following commands as the root user to mount an image called sn-emulator-22.10a.img under the /mnt directory:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;losetup --partscan --show --find cspect-next-2gb.img&lt;br /&gt;
mount /dev/loop0p1 /mnt/&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After you are finished modifying the SD card image, cd out of /mnt, then unmount and detach the loopback device:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;umount /mnt/&lt;br /&gt;
losetup -D&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=MAME Plugins and Scripts=&lt;br /&gt;
&lt;br /&gt;
Some MAME plugins and scripts that may be useful for Next developers and end users are listed [[MAME:Plugins_and_Scripts|here]]. They let you speed up the Next boot time, profile your NextBASIC or assembler code, and more.&lt;br /&gt;
&lt;br /&gt;
=Continuous Integration MAME Builds=&lt;br /&gt;
&lt;br /&gt;
MAME is updated on a release schedule, but due to the ongoing nature of development, including for the MAME Next machine, it can sometimes be useful to install a more recent build if it contains a new feature or bugfix you are interested in. Sometimes, this ongoing work is discussed on social media, such as the [https://discordapp.com/channels/556228195767156758/752197165891321886 Next Developer Discord].&lt;br /&gt;
&lt;br /&gt;
Continuous Integration (CI) builds are available from both the [https://github.com/mamedev/mame/actions primary MAME repo] and [https://github.com/holub/mame/actions holub&#039;s GitHub repo]. Both are considered bleeding-edge, with the primary MAME repo slightly less so. MAME CI builds are available for Windows, Linux, and macOS and are updated automatically whenever code is committed by a maintainer or pushed to the primary repo.&lt;br /&gt;
&lt;br /&gt;
To try out a CI build (more precisely, the resulting binary executable, which is a produced &amp;quot;artifact&amp;quot; of the build process) , first do a full MAME install from the [https://www.mamedev.org/release.html latest release] if you have not already done so. Then back up your main binary from its installation location - these are called something like &amp;lt;code&amp;gt;mame.exe&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;mame&amp;lt;/code&amp;gt;. You can always restore these if the CI build doesn&#039;t work, or if you don&#039;t like how it behaves.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;You need to be logged in to github&#039;&#039;&#039; to download CI artifacts, so [https://github.com/login sign in] or [https://github.com/signup sign up].&lt;br /&gt;
&lt;br /&gt;
Then visit one of the links above and find a workflow run item for your platform. Workflow items are the things in the list. The tags are flagged as &amp;lt;code&amp;gt;CI (Windows)&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CI (Linux)&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;CI (macOS)&amp;lt;/code&amp;gt; in the second row of each workflow item in the list (not the filter in the left hand nav menu). Click on a completed workfow item (only items with green checkmarks will have created downloadable binaries yet), find the Artifacts section at the bottom, then click the Download button. Unzip the downloaded file and find the main binary (with the same name as above). Copy the main binary to the install location, overwriting the original one, and run MAME the same way you were running it before. On Windows and macOS, you need to repeat the security steps above to trust the new MAME executable.&lt;br /&gt;
&lt;br /&gt;
= More MAME links =&lt;br /&gt;
&lt;br /&gt;
MAME [https://docs.mamedev.org/ documentation].&lt;br /&gt;
&lt;br /&gt;
Report any issues with MAME on the [https://mametesters.org/ bugtracker].&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=MAME:Installing&amp;diff=41545</id>
		<title>MAME:Installing</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=MAME:Installing&amp;diff=41545"/>
		<updated>2025-12-22T01:45:51Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: moving full usage example to top of the section, the individual options explanations can follow after&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[https://www.mamedev.org/ MAME] (formerly an acronym of Multiple Arcade Machine Emulator) is a free and open-source emulator designed to emulate the hardware of arcade games, later expanded to include video game consoles, old computers and other systems in software on modern personal computers and other platforms.&lt;br /&gt;
&lt;br /&gt;
MAME has supported the ZX Spectrum Next since version 0.267. The existing implementation is based on the v3.02.01 core and implements most of the features.&lt;br /&gt;
&lt;br /&gt;
= Installation =&lt;br /&gt;
&lt;br /&gt;
You will need to install MAME, provide it with the Next firmware (&#039;ROM&#039;), and get the NextZXOS image:&lt;br /&gt;
&lt;br /&gt;
=== 1. Get MAME ===&lt;br /&gt;
Start with these official MAME releases. If you encounter crashes or other bugs, try replacing the MAME executable with holub&#039;s latest Continuous Integration (CI) builds as described at the end of this article.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Windows:&#039;&#039;&#039; Download [https://www.mamedev.org/release.html MAME for Windows].&lt;br /&gt;
* &#039;&#039;&#039;macOS:&#039;&#039;&#039; Download [https://sdlmame.lngn.net/ MAME for macOS].&lt;br /&gt;
* &#039;&#039;&#039;Linux:&#039;&#039;&#039; Install MAME from the flatpak repositories by running:&lt;br /&gt;
&amp;lt;pre&amp;gt;sudo flatpak install org.mamedev.MAME&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that Windows and macOS will likely prevent you from launching MAME directly for security reasons. See below on how to solve this.&lt;br /&gt;
&lt;br /&gt;
Alternatively, for the MAME platform as a whole, you can also check your package manager, or [https://docs.mamedev.org/initialsetup/compilingmame.html build from sources].&lt;br /&gt;
&lt;br /&gt;
Git of official MAME: [https://github.com/mamedev/mame/ https://github.com/mamedev/mame/] [https://github.com/mamedev/mame/blob/master/src/mame/sinclair/specnext.cpp specnext.cpp]&lt;br /&gt;
&lt;br /&gt;
Git of holub&#039;s fork: [https://github.com/holub/mame https://github.com/holub/mame] [https://github.com/holub/mame/blob/master/src/mame/sinclair/specnext.cpp specnext.cpp] (may contain extra fixes and features before they are merged to official repository)&lt;br /&gt;
&lt;br /&gt;
=== 2. Get TBBLUE (the Next &#039;boot ROM&#039;) ===&lt;br /&gt;
Put the file  [https://github.com/Threetwosevensixseven/NexCreator/raw/master/bootroms/tbblue.zip tbblue.zip] into MAME&#039;s &amp;lt;code&amp;gt;roms&amp;lt;/code&amp;gt; folder. Don&#039;t extract it; MAME will look for the zip file when the &amp;quot;tbblue&amp;quot; machine is selected.&lt;br /&gt;
&lt;br /&gt;
Note: The ROMs in this zip are what is embedded inside the FPGA core on real Next hardware. They&#039;re different from any ZX Spectrum machine ROMs you may be used to using, that are on the distro, SD card or SD image file.&lt;br /&gt;
&lt;br /&gt;
=== 3. Get the NextZXOS Image ===&lt;br /&gt;
Get an SD card image file of [https://www.specnext.com/latestdistro/ NextZXOS]. Note that currently some published disk images on the official SpecNext.com site (the &amp;lt;code&amp;gt;latestdistro&amp;lt;/code&amp;gt; link points to the official location where the latest distribution can be found) do not work with some emulators, but all images from &amp;lt;code&amp;gt;https://zxnext.uk/hosted/&amp;lt;/code&amp;gt; work with both MAME and CSpect, like [https://zxnext.uk/hosted/index_files/hdfimages/cspect-next-2gb.zip this SD card image in the zip archive]. Extract the image &amp;lt;code&amp;gt;cspect-next-2gb.img&amp;lt;/code&amp;gt; from the archive to use it, then point MAME to this SD card image with the &amp;lt;code&amp;gt;-hard1&amp;lt;/code&amp;gt; option (or select that file from the menu inside MAME).&lt;br /&gt;
&lt;br /&gt;
= Usage =&lt;br /&gt;
MAME looks for its configuration and helper files in specific (configurable) folders. By default, these are relative to the current working directory (cwd), i.e., from where you launched the executable. The &amp;lt;code&amp;gt;mame.ini&amp;lt;/code&amp;gt; file and folders like &amp;lt;code&amp;gt;roms, bgfx, plugins, language, ...&amp;lt;/code&amp;gt; are expected there, unless the &amp;lt;code&amp;gt;mame.ini&amp;lt;/code&amp;gt; file specifies other paths. When launching through a desktop icon or menu, depending on the OS, the working directory is often defined by the properties of that launch shortcut. When launching MAME from the command line, the current directory is &amp;quot;cwd&amp;quot; (doh). On Linux, MAME will look for &amp;lt;code&amp;gt;mame.ini&amp;lt;/code&amp;gt; first in the &amp;lt;code&amp;gt;~/.mame&amp;lt;/code&amp;gt; folder. You can use the option &amp;lt;code&amp;gt;-inipath&amp;lt;/code&amp;gt; to point MAME to a different path for the &amp;lt;code&amp;gt;mame.ini&amp;lt;/code&amp;gt; file.&lt;br /&gt;
&lt;br /&gt;
However, the fastest way to run a machine with a desired configuration is from the command prompt, without requiring a &amp;lt;code&amp;gt;mame.ini&amp;lt;/code&amp;gt; file. Most of the features are also available through MAME&#039;s UI, although that takes more time to configure.&lt;br /&gt;
&lt;br /&gt;
As an example, this invocation enables the UI, uses &amp;quot;crisp pixels&amp;quot;, starts in a window, doesn&#039;t display the starting gameinfo window (it can still be displayed interactively from the UI), disables the mouse, confirms before exiting MAME, and specifies the disk image (remember to adjust the path to it):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;mame -ui_active -nounevenstretch -aspect 2:1 -video bgfx  -bgfx_screen_chains unfiltered -window -skip_gameinfo -mouse_device none -confirm_quit tbblue -hard1 /path/to/cspect-next-2gb.img&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let&#039;s cover some useful options:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Run inside a window and with no mouse support, until you get familiar with the UI keys:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; mame tbblue -window -mouse_device none -hard1 /path/to/next-distribution.img&amp;lt;/pre&amp;gt;&lt;br /&gt;
To launch the Linux flatpak version using the same options:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; flatpak run org.mamedev.MAME tbblue -window -mouse_device none -hard1 /path/to/next-distribution.img&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Activate UI keys on startup:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -ui_active&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Don&#039;t show the info popup on startup:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -skip_gameinfo&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;Run with debugger. If you don&#039;t request this on startup, you won&#039;t have access to it:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -debug&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;Use &amp;quot;crisp&amp;quot; pixels:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -nounevenstretch -aspect 2:1 -video bgfx -bgfx_screen_chains unfiltered&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;No joystick connected to PC (having this may slightly speed up MAME&#039;s startup, but &#039;&#039;remember to remove this part from the command line and the corresponding setting in the ini file if you do want to use a joystick&#039;&#039;):&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -joystickprovider none&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;Ask for confirmation when exiting MAME (otherwise it&#039;s easy to exit MAME accidentally by hitting ESC, especially when playing games or navigating menus):&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -confirm_quit&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Check the [https://docs.mamedev.org/commandline/commandline-all.html#mame-commandline-universal official MAME documentation] for more advanced usage.&lt;br /&gt;
&lt;br /&gt;
= Security: Allowing MAME to Run on Windows and macOS =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;On Windows,&#039;&#039;&#039; you will need to confirm that you want to launch MAME by clicking &amp;quot;Run Anyway&amp;quot; on first launch. &#039;&#039;(More details needed here.)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;On macOS,&#039;&#039;&#039; MAME will not open at first. Instead, a dialog will appear saying:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;“mame” Not Opened. Apple could not verify “mame” is free of malware that may harm your Mac or compromise your privacy.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Click “Done”. Then open &#039;&#039;&#039;System Settings -&amp;gt; Privacy &amp;amp; Security&#039;&#039;&#039;, and scroll down to the message &#039;&#039;mame was blocked to protect your Mac.&#039;&#039; Click “Allow Anyway”.&lt;br /&gt;
&lt;br /&gt;
Now launch MAME again. A dialog will ask once more if you want to open “mame”. Click “Open Anyway”, and enter your password or use Touch ID when prompted by macOS.&lt;br /&gt;
&lt;br /&gt;
From now on, you can launch this version of MAME without warnings. However, you &#039;&#039;&#039;will&#039;&#039;&#039; need to repeat this each time you update MAME.&lt;br /&gt;
&lt;br /&gt;
= Keys =&lt;br /&gt;
&lt;br /&gt;
Keys are emulated in two modes: either to control the MAME emulator or completely dedicated to the emulated system (the Next). You can toggle between these two keyboard modes with ScrLk (on Win and Linux) or fn+delete (on Mac).&lt;br /&gt;
&lt;br /&gt;
Some UI keys:&lt;br /&gt;
* F3 - soft reset&lt;br /&gt;
* Shift+F3 - hard reset&lt;br /&gt;
* F4 - sprites/tiles/font viewer (Enter, ], [)&lt;br /&gt;
* F5 - pause emulation&lt;br /&gt;
* F6 - save state&lt;br /&gt;
* F7 - load state&lt;br /&gt;
* Tab - emulator settings&lt;br /&gt;
* ~ - menu&lt;br /&gt;
* ` (backtick) - debugger (when enabled by starting MAME with &amp;lt;code&amp;gt;-debug&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;-d&amp;lt;/code&amp;gt; on the command line)&lt;br /&gt;
* PgDwn (Linux/Mac), fn-Downarrow (MacBooks) or Insert (Win) - hold down to fast-forward emulation at maximum speed, e.g., to speed up booting the Next&lt;br /&gt;
* Esc - exit (exits menus but also the entire emulator - see &amp;lt;code&amp;gt;-confirm_quit&amp;lt;/code&amp;gt; option above)&lt;br /&gt;
* F11 - DivMMC NMI&lt;br /&gt;
* F12 - Multiface NMI&lt;br /&gt;
&lt;br /&gt;
= Changing the UI toggle key =&lt;br /&gt;
&lt;br /&gt;
Some laptops don&#039;t have a Scroll Lock key, so you may not be able to exit MAME if you run it in full-screen mode. In these cases, you can change the UI toggle key as follows:&lt;br /&gt;
&lt;br /&gt;
* Run MAME without any command line arguments (except maybe -window) to open its GUI.&lt;br /&gt;
* Push TAB and enter the General Settings menu.&lt;br /&gt;
* Go to Input Assignments -&amp;gt; User Interface -&amp;gt; Toggle UI controls and select a new key. I use Right Alt / Alt GR.&lt;br /&gt;
* Return to the previous menu twice, then choose Save Settings&lt;br /&gt;
&lt;br /&gt;
= Creating a NextZXOS SD card image =&lt;br /&gt;
&lt;br /&gt;
Most users wanting to emulate the Next using MAME will be fine using a pre-built SD card image downloaded from the specnext website. The following guide is provided for anyone wanting to create a NextZXOS SD card image from scratch.&lt;br /&gt;
&lt;br /&gt;
Download the [https://www.specnext.com/latestdistro/ latest NextZXOS distribution zip file] (named something like sn-complete-WX.YZ.zip) and extract it into a new, empty directory.&lt;br /&gt;
&lt;br /&gt;
== Creating and populating a SD card image using hdfmonkey jjjs build ==&lt;br /&gt;
&lt;br /&gt;
The [[https://www.specnext.com/forum/viewtopic.php?t=2604 | &amp;lt;code&amp;gt;hdfmonkey &amp;quot;jjjs build&amp;quot;&amp;lt;/code&amp;gt;]] is a variant of hdfmonkey tool which includes some unique features and its main archive (at the previously given link) also contains pre-built binaries for Windows x64, MacOS x64, MacOS Apple Silicon and Linux x64. (Alternatively, the process to build a local Linux version of the executable is described [[Development_Tools:Linux_setup#Building_the_executable_binary_2 | here]] )&lt;br /&gt;
&lt;br /&gt;
If you extracted sn-complete-WX.YZ.zip into a subdirectory named &amp;lt;code&amp;gt;snWXYZ&amp;lt;/code&amp;gt;, and you want to create a 1GB image called &amp;lt;code&amp;gt;NextZXOS.img&amp;lt;/code&amp;gt; and you have a jjjs build&amp;quot; of hdfmonkey, then it&#039;s enough to do:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
hdfmonkey create NextZXOS.img 1G&lt;br /&gt;
hdfmonkey putdir NextZXOS.img snWXYZ /&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first line creates an empty 1GB image and formats it with the best FAT parameters suited to the size of the image.&lt;br /&gt;
&lt;br /&gt;
The second line recursively copies all the content of the directory &amp;lt;code&amp;gt;snWXYZ&amp;lt;/code&amp;gt; to the image, preserving the directory structure inside, starting from the &amp;lt;code&amp;gt;/&amp;lt;/code&amp;gt; in the image.&lt;br /&gt;
&lt;br /&gt;
One of the advantages of this method is that even if the image has a capacity of 1GB, it will use much less space on your hard drive until you fill up the image. On Linux or MacOS, a command &amp;lt;code&amp;gt;du -h NextZXOS.img&amp;lt;/code&amp;gt; shows the actual amount of disk space used by the image. On Windows the same information can be seen in the File Properties dialog.&lt;br /&gt;
&lt;br /&gt;
The fastest way to transfer a file or a directory (including its content, recursively) into an image is by using a single &amp;lt;code&amp;gt;put&amp;lt;/code&amp;gt; (or &amp;lt;code&amp;gt;putdir&amp;lt;/code&amp;gt;, if it&#039;s to transfer the directory file content to an existing directory) command of hdfmonkey.&lt;br /&gt;
&lt;br /&gt;
The most convenient tool to copy of all the content from the image to a folder outside of the image is 7-zip. On Windows, just use the 7-zip GUI. On MacOS and Linux, see: [[Development_Tools:Linux_setup#Extracting_all_files_from_the_SD_image]].&lt;br /&gt;
&lt;br /&gt;
== Creating and populating a SD card image using Linux ==&lt;br /&gt;
&lt;br /&gt;
While using hdfmonkey jjjs build works on Linux and the pre-built binary for Intel x64 exists, and using it creates an image which will have high compatibility, it is also possible to use more common Linux tools to create a SD image. Note however that the resulting image of this method, if the parameters of different steps aren&#039;t carefully chosen and matched, could be out of the official FAT specifications and/or the expectations of some of the existing programs or systems. This method creates an image which is incompatible with the current (as of 2025-12-13) CSpect version, at least for some sizes of the image:&lt;br /&gt;
&lt;br /&gt;
Create a disk image of at least 256 MB. The current complete NextZXOS distro requires at least 130 MB of disk space. This command will create a 256 MB SD card image; change the &amp;lt;code&amp;gt;count&amp;lt;/code&amp;gt; value to make the image file as big as you want in megabytes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;dd if=/dev/zero of=NextZXOS.img bs=1M count=256&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The rest of the commands in this guide must be run as the root user or using sudo.&lt;br /&gt;
&lt;br /&gt;
You will need to install the dosfstools and parted packages if they are not already installed. Debian and Ubuntu Linux users can install these using this apt command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;apt install dosfstools parted&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mount the SD card image loopback device:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;losetup --partscan --show --find NextZXOS.img&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Create a FAT32 partition:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;parted /dev/loop0 mklabel msdos&lt;br /&gt;
parted /dev/loop0 mkpart primary fat32 1MB 100%&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Format and mount the partition under /mnt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;mkfs.vfat -F 32 /dev/loop0p1&lt;br /&gt;
mount /dev/loop0p1 /mnt&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can now copy all of the files you extracted from sn-complete-WX.YZ.zip into /mnt.&lt;br /&gt;
&lt;br /&gt;
After copying the files, unmount and detach the loopback device (the SD card image):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;umount /mnt/&lt;br /&gt;
losetup -D&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Mounting SD card images under Linux =&lt;br /&gt;
&lt;br /&gt;
Under Linux, you can use &amp;lt;code&amp;gt;losetup&amp;lt;/code&amp;gt; to mount SD card images as loop devices. This lets you copy files to and from the image and perform other file management tasks as you would using any other filesystem.&lt;br /&gt;
&lt;br /&gt;
Run the following commands as the root user to mount an image called sn-emulator-22.10a.img under the /mnt directory:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;losetup --partscan --show --find cspect-next-2gb.img&lt;br /&gt;
mount /dev/loop0p1 /mnt/&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After you are finished modifying the SD card image, cd out of /mnt, then unmount and detach the loopback device:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;umount /mnt/&lt;br /&gt;
losetup -D&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=MAME Plugins and Scripts=&lt;br /&gt;
&lt;br /&gt;
Some MAME plugins and scripts that may be useful for Next developers and end users are listed [[MAME:Plugins_and_Scripts|here]]. They let you speed up the Next boot time, profile your NextBASIC or assembler code, and more.&lt;br /&gt;
&lt;br /&gt;
=Continuous Integration MAME Builds=&lt;br /&gt;
&lt;br /&gt;
MAME is updated on a release schedule, but due to the ongoing nature of development, including for the MAME Next machine, it can sometimes be useful to install a more recent build if it contains a new feature or bugfix you are interested in. Sometimes, this ongoing work is discussed on social media, such as the [https://discordapp.com/channels/556228195767156758/752197165891321886 Next Developer Discord].&lt;br /&gt;
&lt;br /&gt;
Continuous Integration (CI) builds are available from both the [https://github.com/mamedev/mame/actions primary MAME repo] and [https://github.com/holub/mame/actions holub&#039;s GitHub repo]. Both are considered bleeding-edge, with the primary MAME repo slightly less so. MAME CI builds are available for Windows, Linux, and macOS and are updated automatically whenever code is committed by a maintainer or pushed to the primary repo.&lt;br /&gt;
&lt;br /&gt;
To try out a CI build (more precisely, the resulting binary executable, which is a produced &amp;quot;artifact&amp;quot; of the build process) , first do a full MAME install from the [https://www.mamedev.org/release.html latest release] if you have not already done so. Then back up your main binary from its installation location - these are called something like &amp;lt;code&amp;gt;mame.exe&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;mame&amp;lt;/code&amp;gt;. You can always restore these if the CI build doesn&#039;t work, or if you don&#039;t like how it behaves.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;You need to be logged in to github&#039;&#039;&#039; to download CI artifacts, so [https://github.com/login sign in] or [https://github.com/signup sign up].&lt;br /&gt;
&lt;br /&gt;
Then visit one of the links above and find a workflow run item for your platform. Workflow items are the things in the list. The tags are flagged as &amp;lt;code&amp;gt;CI (Windows)&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CI (Linux)&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;CI (macOS)&amp;lt;/code&amp;gt; in the second row of each workflow item in the list (not the filter in the left hand nav menu). Click on a completed workfow item (only items with green checkmarks will have created downloadable binaries yet), find the Artifacts section at the bottom, then click the Download button. Unzip the downloaded file and find the main binary (with the same name as above). Copy the main binary to the install location, overwriting the original one, and run MAME the same way you were running it before. On Windows and macOS, you need to repeat the security steps above to trust the new MAME executable.&lt;br /&gt;
&lt;br /&gt;
= More MAME links =&lt;br /&gt;
&lt;br /&gt;
MAME [https://docs.mamedev.org/ documentation].&lt;br /&gt;
&lt;br /&gt;
Report any issues with MAME on the [https://mametesters.org/ bugtracker].&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=MAME:Installing&amp;diff=41544</id>
		<title>MAME:Installing</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=MAME:Installing&amp;diff=41544"/>
		<updated>2025-12-22T01:42:22Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: Moving git urls also to &amp;quot;1. Get MAME&amp;quot; section, I want them here to find them quickly&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[https://www.mamedev.org/ MAME] (formerly an acronym of Multiple Arcade Machine Emulator) is a free and open-source emulator designed to emulate the hardware of arcade games, later expanded to include video game consoles, old computers and other systems in software on modern personal computers and other platforms.&lt;br /&gt;
&lt;br /&gt;
MAME has supported the ZX Spectrum Next since version 0.267. The existing implementation is based on the v3.02.01 core and implements most of the features.&lt;br /&gt;
&lt;br /&gt;
= Installation =&lt;br /&gt;
&lt;br /&gt;
You will need to install MAME, provide it with the Next firmware (&#039;ROM&#039;), and get the NextZXOS image:&lt;br /&gt;
&lt;br /&gt;
=== 1. Get MAME ===&lt;br /&gt;
Start with these official MAME releases. If you encounter crashes or other bugs, try replacing the MAME executable with holub&#039;s latest Continuous Integration (CI) builds as described at the end of this article.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Windows:&#039;&#039;&#039; Download [https://www.mamedev.org/release.html MAME for Windows].&lt;br /&gt;
* &#039;&#039;&#039;macOS:&#039;&#039;&#039; Download [https://sdlmame.lngn.net/ MAME for macOS].&lt;br /&gt;
* &#039;&#039;&#039;Linux:&#039;&#039;&#039; Install MAME from the flatpak repositories by running:&lt;br /&gt;
&amp;lt;pre&amp;gt;sudo flatpak install org.mamedev.MAME&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that Windows and macOS will likely prevent you from launching MAME directly for security reasons. See below on how to solve this.&lt;br /&gt;
&lt;br /&gt;
Alternatively, for the MAME platform as a whole, you can also check your package manager, or [https://docs.mamedev.org/initialsetup/compilingmame.html build from sources].&lt;br /&gt;
&lt;br /&gt;
Git of official MAME: [https://github.com/mamedev/mame/ https://github.com/mamedev/mame/] [https://github.com/mamedev/mame/blob/master/src/mame/sinclair/specnext.cpp specnext.cpp]&lt;br /&gt;
&lt;br /&gt;
Git of holub&#039;s fork: [https://github.com/holub/mame https://github.com/holub/mame] [https://github.com/holub/mame/blob/master/src/mame/sinclair/specnext.cpp specnext.cpp] (may contain extra fixes and features before they are merged to official repository)&lt;br /&gt;
&lt;br /&gt;
=== 2. Get TBBLUE (the Next &#039;boot ROM&#039;) ===&lt;br /&gt;
Put the file  [https://github.com/Threetwosevensixseven/NexCreator/raw/master/bootroms/tbblue.zip tbblue.zip] into MAME&#039;s &amp;lt;code&amp;gt;roms&amp;lt;/code&amp;gt; folder. Don&#039;t extract it; MAME will look for the zip file when the &amp;quot;tbblue&amp;quot; machine is selected.&lt;br /&gt;
&lt;br /&gt;
Note: The ROMs in this zip are what is embedded inside the FPGA core on real Next hardware. They&#039;re different from any ZX Spectrum machine ROMs you may be used to using, that are on the distro, SD card or SD image file.&lt;br /&gt;
&lt;br /&gt;
=== 3. Get the NextZXOS Image ===&lt;br /&gt;
Get an SD card image file of [https://www.specnext.com/latestdistro/ NextZXOS]. Note that currently some published disk images on the official SpecNext.com site (the &amp;lt;code&amp;gt;latestdistro&amp;lt;/code&amp;gt; link points to the official location where the latest distribution can be found) do not work with some emulators, but all images from &amp;lt;code&amp;gt;https://zxnext.uk/hosted/&amp;lt;/code&amp;gt; work with both MAME and CSpect, like [https://zxnext.uk/hosted/index_files/hdfimages/cspect-next-2gb.zip this SD card image in the zip archive]. Extract the image &amp;lt;code&amp;gt;cspect-next-2gb.img&amp;lt;/code&amp;gt; from the archive to use it, then point MAME to this SD card image with the &amp;lt;code&amp;gt;-hard1&amp;lt;/code&amp;gt; option (or select that file from the menu inside MAME).&lt;br /&gt;
&lt;br /&gt;
= Usage =&lt;br /&gt;
MAME looks for its configuration and helper files in specific (configurable) folders. By default, these are relative to the current working directory (cwd), i.e., from where you launched the executable. The &amp;lt;code&amp;gt;mame.ini&amp;lt;/code&amp;gt; file and folders like &amp;lt;code&amp;gt;roms, bgfx, plugins, language, ...&amp;lt;/code&amp;gt; are expected there, unless the &amp;lt;code&amp;gt;mame.ini&amp;lt;/code&amp;gt; file specifies other paths. When launching through a desktop icon or menu, depending on the OS, the working directory is often defined by the properties of that launch shortcut. When launching MAME from the command line, the current directory is &amp;quot;cwd&amp;quot; (doh). On Linux, MAME will look for &amp;lt;code&amp;gt;mame.ini&amp;lt;/code&amp;gt; first in the &amp;lt;code&amp;gt;~/.mame&amp;lt;/code&amp;gt; folder. You can use the option &amp;lt;code&amp;gt;-inipath&amp;lt;/code&amp;gt; to point MAME to a different path for the &amp;lt;code&amp;gt;mame.ini&amp;lt;/code&amp;gt; file.&lt;br /&gt;
&lt;br /&gt;
However, the fastest way to run a machine with a desired configuration is from the command prompt, without requiring a &amp;lt;code&amp;gt;mame.ini&amp;lt;/code&amp;gt; file. Most of the features are also available through MAME&#039;s UI, although that takes more time to configure.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s cover some useful options:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Run inside a window and with no mouse support, until you get familiar with the UI keys:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; mame tbblue -window -mouse_device none -hard1 /path/to/next-distribution.img&amp;lt;/pre&amp;gt;&lt;br /&gt;
To launch the Linux flatpak version using the same options:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; flatpak run org.mamedev.MAME tbblue -window -mouse_device none -hard1 /path/to/next-distribution.img&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Activate UI keys on startup:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -ui_active&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Don&#039;t show the info popup on startup:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -skip_gameinfo&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;Run with debugger. If you don&#039;t request this on startup, you won&#039;t have access to it:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -debug&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;Use &amp;quot;crisp&amp;quot; pixels:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -nounevenstretch -aspect 2:1 -video bgfx -bgfx_screen_chains unfiltered&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;No joystick connected to PC (having this may slightly speed up MAME&#039;s startup, but &#039;&#039;remember to remove this part from the command line and the corresponding setting in the ini file if you do want to use a joystick&#039;&#039;):&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -joystickprovider none&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;Ask for confirmation when exiting MAME (otherwise it&#039;s easy to exit MAME accidentally by hitting ESC, especially when playing games or navigating menus):&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -confirm_quit&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Check the [https://docs.mamedev.org/commandline/commandline-all.html#mame-commandline-universal official MAME documentation] for more advanced usage.&lt;br /&gt;
&lt;br /&gt;
As an example, this invocation enables the UI, uses &amp;quot;crisp pixels&amp;quot;, starts in a window, doesn&#039;t display the starting gameinfo window (it can still be displayed interactively from the UI), disables the mouse, confirms before exiting MAME, and specifies the disk image (remember to adjust the path to it):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;mame -ui_active -nounevenstretch -aspect 2:1 -video bgfx  -bgfx_screen_chains unfiltered -window -skip_gameinfo -mouse_device none -confirm_quit tbblue -hard1 /path/to/cspect-next-2gb.img&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Security: Allowing MAME to Run on Windows and macOS =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;On Windows,&#039;&#039;&#039; you will need to confirm that you want to launch MAME by clicking &amp;quot;Run Anyway&amp;quot; on first launch. &#039;&#039;(More details needed here.)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;On macOS,&#039;&#039;&#039; MAME will not open at first. Instead, a dialog will appear saying:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;“mame” Not Opened. Apple could not verify “mame” is free of malware that may harm your Mac or compromise your privacy.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Click “Done”. Then open &#039;&#039;&#039;System Settings -&amp;gt; Privacy &amp;amp; Security&#039;&#039;&#039;, and scroll down to the message &#039;&#039;mame was blocked to protect your Mac.&#039;&#039; Click “Allow Anyway”.&lt;br /&gt;
&lt;br /&gt;
Now launch MAME again. A dialog will ask once more if you want to open “mame”. Click “Open Anyway”, and enter your password or use Touch ID when prompted by macOS.&lt;br /&gt;
&lt;br /&gt;
From now on, you can launch this version of MAME without warnings. However, you &#039;&#039;&#039;will&#039;&#039;&#039; need to repeat this each time you update MAME.&lt;br /&gt;
&lt;br /&gt;
= Keys =&lt;br /&gt;
&lt;br /&gt;
Keys are emulated in two modes: either to control the MAME emulator or completely dedicated to the emulated system (the Next). You can toggle between these two keyboard modes with ScrLk (on Win and Linux) or fn+delete (on Mac).&lt;br /&gt;
&lt;br /&gt;
Some UI keys:&lt;br /&gt;
* F3 - soft reset&lt;br /&gt;
* Shift+F3 - hard reset&lt;br /&gt;
* F4 - sprites/tiles/font viewer (Enter, ], [)&lt;br /&gt;
* F5 - pause emulation&lt;br /&gt;
* F6 - save state&lt;br /&gt;
* F7 - load state&lt;br /&gt;
* Tab - emulator settings&lt;br /&gt;
* ~ - menu&lt;br /&gt;
* ` (backtick) - debugger (when enabled by starting MAME with &amp;lt;code&amp;gt;-debug&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;-d&amp;lt;/code&amp;gt; on the command line)&lt;br /&gt;
* PgDwn (Linux/Mac), fn-Downarrow (MacBooks) or Insert (Win) - hold down to fast-forward emulation at maximum speed, e.g., to speed up booting the Next&lt;br /&gt;
* Esc - exit (exits menus but also the entire emulator - see &amp;lt;code&amp;gt;-confirm_quit&amp;lt;/code&amp;gt; option above)&lt;br /&gt;
* F11 - DivMMC NMI&lt;br /&gt;
* F12 - Multiface NMI&lt;br /&gt;
&lt;br /&gt;
= Changing the UI toggle key =&lt;br /&gt;
&lt;br /&gt;
Some laptops don&#039;t have a Scroll Lock key, so you may not be able to exit MAME if you run it in full-screen mode. In these cases, you can change the UI toggle key as follows:&lt;br /&gt;
&lt;br /&gt;
* Run MAME without any command line arguments (except maybe -window) to open its GUI.&lt;br /&gt;
* Push TAB and enter the General Settings menu.&lt;br /&gt;
* Go to Input Assignments -&amp;gt; User Interface -&amp;gt; Toggle UI controls and select a new key. I use Right Alt / Alt GR.&lt;br /&gt;
* Return to the previous menu twice, then choose Save Settings&lt;br /&gt;
&lt;br /&gt;
= Creating a NextZXOS SD card image =&lt;br /&gt;
&lt;br /&gt;
Most users wanting to emulate the Next using MAME will be fine using a pre-built SD card image downloaded from the specnext website. The following guide is provided for anyone wanting to create a NextZXOS SD card image from scratch.&lt;br /&gt;
&lt;br /&gt;
Download the [https://www.specnext.com/latestdistro/ latest NextZXOS distribution zip file] (named something like sn-complete-WX.YZ.zip) and extract it into a new, empty directory.&lt;br /&gt;
&lt;br /&gt;
== Creating and populating a SD card image using hdfmonkey jjjs build ==&lt;br /&gt;
&lt;br /&gt;
The [[https://www.specnext.com/forum/viewtopic.php?t=2604 | &amp;lt;code&amp;gt;hdfmonkey &amp;quot;jjjs build&amp;quot;&amp;lt;/code&amp;gt;]] is a variant of hdfmonkey tool which includes some unique features and its main archive (at the previously given link) also contains pre-built binaries for Windows x64, MacOS x64, MacOS Apple Silicon and Linux x64. (Alternatively, the process to build a local Linux version of the executable is described [[Development_Tools:Linux_setup#Building_the_executable_binary_2 | here]] )&lt;br /&gt;
&lt;br /&gt;
If you extracted sn-complete-WX.YZ.zip into a subdirectory named &amp;lt;code&amp;gt;snWXYZ&amp;lt;/code&amp;gt;, and you want to create a 1GB image called &amp;lt;code&amp;gt;NextZXOS.img&amp;lt;/code&amp;gt; and you have a jjjs build&amp;quot; of hdfmonkey, then it&#039;s enough to do:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
hdfmonkey create NextZXOS.img 1G&lt;br /&gt;
hdfmonkey putdir NextZXOS.img snWXYZ /&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first line creates an empty 1GB image and formats it with the best FAT parameters suited to the size of the image.&lt;br /&gt;
&lt;br /&gt;
The second line recursively copies all the content of the directory &amp;lt;code&amp;gt;snWXYZ&amp;lt;/code&amp;gt; to the image, preserving the directory structure inside, starting from the &amp;lt;code&amp;gt;/&amp;lt;/code&amp;gt; in the image.&lt;br /&gt;
&lt;br /&gt;
One of the advantages of this method is that even if the image has a capacity of 1GB, it will use much less space on your hard drive until you fill up the image. On Linux or MacOS, a command &amp;lt;code&amp;gt;du -h NextZXOS.img&amp;lt;/code&amp;gt; shows the actual amount of disk space used by the image. On Windows the same information can be seen in the File Properties dialog.&lt;br /&gt;
&lt;br /&gt;
The fastest way to transfer a file or a directory (including its content, recursively) into an image is by using a single &amp;lt;code&amp;gt;put&amp;lt;/code&amp;gt; (or &amp;lt;code&amp;gt;putdir&amp;lt;/code&amp;gt;, if it&#039;s to transfer the directory file content to an existing directory) command of hdfmonkey.&lt;br /&gt;
&lt;br /&gt;
The most convenient tool to copy of all the content from the image to a folder outside of the image is 7-zip. On Windows, just use the 7-zip GUI. On MacOS and Linux, see: [[Development_Tools:Linux_setup#Extracting_all_files_from_the_SD_image]].&lt;br /&gt;
&lt;br /&gt;
== Creating and populating a SD card image using Linux ==&lt;br /&gt;
&lt;br /&gt;
While using hdfmonkey jjjs build works on Linux and the pre-built binary for Intel x64 exists, and using it creates an image which will have high compatibility, it is also possible to use more common Linux tools to create a SD image. Note however that the resulting image of this method, if the parameters of different steps aren&#039;t carefully chosen and matched, could be out of the official FAT specifications and/or the expectations of some of the existing programs or systems. This method creates an image which is incompatible with the current (as of 2025-12-13) CSpect version, at least for some sizes of the image:&lt;br /&gt;
&lt;br /&gt;
Create a disk image of at least 256 MB. The current complete NextZXOS distro requires at least 130 MB of disk space. This command will create a 256 MB SD card image; change the &amp;lt;code&amp;gt;count&amp;lt;/code&amp;gt; value to make the image file as big as you want in megabytes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;dd if=/dev/zero of=NextZXOS.img bs=1M count=256&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The rest of the commands in this guide must be run as the root user or using sudo.&lt;br /&gt;
&lt;br /&gt;
You will need to install the dosfstools and parted packages if they are not already installed. Debian and Ubuntu Linux users can install these using this apt command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;apt install dosfstools parted&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mount the SD card image loopback device:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;losetup --partscan --show --find NextZXOS.img&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Create a FAT32 partition:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;parted /dev/loop0 mklabel msdos&lt;br /&gt;
parted /dev/loop0 mkpart primary fat32 1MB 100%&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Format and mount the partition under /mnt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;mkfs.vfat -F 32 /dev/loop0p1&lt;br /&gt;
mount /dev/loop0p1 /mnt&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can now copy all of the files you extracted from sn-complete-WX.YZ.zip into /mnt.&lt;br /&gt;
&lt;br /&gt;
After copying the files, unmount and detach the loopback device (the SD card image):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;umount /mnt/&lt;br /&gt;
losetup -D&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Mounting SD card images under Linux =&lt;br /&gt;
&lt;br /&gt;
Under Linux, you can use &amp;lt;code&amp;gt;losetup&amp;lt;/code&amp;gt; to mount SD card images as loop devices. This lets you copy files to and from the image and perform other file management tasks as you would using any other filesystem.&lt;br /&gt;
&lt;br /&gt;
Run the following commands as the root user to mount an image called sn-emulator-22.10a.img under the /mnt directory:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;losetup --partscan --show --find cspect-next-2gb.img&lt;br /&gt;
mount /dev/loop0p1 /mnt/&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After you are finished modifying the SD card image, cd out of /mnt, then unmount and detach the loopback device:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;umount /mnt/&lt;br /&gt;
losetup -D&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=MAME Plugins and Scripts=&lt;br /&gt;
&lt;br /&gt;
Some MAME plugins and scripts that may be useful for Next developers and end users are listed [[MAME:Plugins_and_Scripts|here]]. They let you speed up the Next boot time, profile your NextBASIC or assembler code, and more.&lt;br /&gt;
&lt;br /&gt;
=Continuous Integration MAME Builds=&lt;br /&gt;
&lt;br /&gt;
MAME is updated on a release schedule, but due to the ongoing nature of development, including for the MAME Next machine, it can sometimes be useful to install a more recent build if it contains a new feature or bugfix you are interested in. Sometimes, this ongoing work is discussed on social media, such as the [https://discordapp.com/channels/556228195767156758/752197165891321886 Next Developer Discord].&lt;br /&gt;
&lt;br /&gt;
Continuous Integration (CI) builds are available from both the [https://github.com/mamedev/mame/actions primary MAME repo] and [https://github.com/holub/mame/actions holub&#039;s GitHub repo]. Both are considered bleeding-edge, with the primary MAME repo slightly less so. MAME CI builds are available for Windows, Linux, and macOS and are updated automatically whenever code is committed by a maintainer or pushed to the primary repo.&lt;br /&gt;
&lt;br /&gt;
To try out a CI build (more precisely, the resulting binary executable, which is a produced &amp;quot;artifact&amp;quot; of the build process) , first do a full MAME install from the [https://www.mamedev.org/release.html latest release] if you have not already done so. Then back up your main binary from its installation location - these are called something like &amp;lt;code&amp;gt;mame.exe&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;mame&amp;lt;/code&amp;gt;. You can always restore these if the CI build doesn&#039;t work, or if you don&#039;t like how it behaves.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;You need to be logged in to github&#039;&#039;&#039; to download CI artifacts, so [https://github.com/login sign in] or [https://github.com/signup sign up].&lt;br /&gt;
&lt;br /&gt;
Then visit one of the links above and find a workflow run item for your platform. Workflow items are the things in the list. The tags are flagged as &amp;lt;code&amp;gt;CI (Windows)&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CI (Linux)&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;CI (macOS)&amp;lt;/code&amp;gt; in the second row of each workflow item in the list (not the filter in the left hand nav menu). Click on a completed workfow item (only items with green checkmarks will have created downloadable binaries yet), find the Artifacts section at the bottom, then click the Download button. Unzip the downloaded file and find the main binary (with the same name as above). Copy the main binary to the install location, overwriting the original one, and run MAME the same way you were running it before. On Windows and macOS, you need to repeat the security steps above to trust the new MAME executable.&lt;br /&gt;
&lt;br /&gt;
= More MAME links =&lt;br /&gt;
&lt;br /&gt;
MAME [https://docs.mamedev.org/ documentation].&lt;br /&gt;
&lt;br /&gt;
Report any issues with MAME on the [https://mametesters.org/ bugtracker].&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=ULA_Palette_Control_Register&amp;diff=41478</id>
		<title>ULA Palette Control Register</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=ULA_Palette_Control_Register&amp;diff=41478"/>
		<updated>2025-12-11T08:38:02Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: Add reference to Tilemap control reg for tilemap palette select.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{NextRegister&lt;br /&gt;
|Number=$43&lt;br /&gt;
|Readable=Yes&lt;br /&gt;
|Writable=Yes&lt;br /&gt;
|ShortDesc=Enables or disables Enhanced ULA interpretation of attribute values and toggles active palette.&lt;br /&gt;
}}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Bit !! Function&lt;br /&gt;
|-&lt;br /&gt;
| 7 || 1 to disable palette index write auto-increment&lt;br /&gt;
|-&lt;br /&gt;
| 6-4 || Select palette for reading or writing&lt;br /&gt;
|-&lt;br /&gt;
| 3 || Select Sprites palette (0 = first palette, 1 = second palette)&lt;br /&gt;
|-&lt;br /&gt;
| 2 || Select Layer 2 palette (0 = first palette, 1 = second palette)&lt;br /&gt;
|-&lt;br /&gt;
| 1 || Select ULA palette (0 = first palette, 1 = second palette)&lt;br /&gt;
|-&lt;br /&gt;
| 0 || Enable ULANext mode if 1. (0 after a reset)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
n.b. Bits 6-4 select palette for reading or writing whereas bits 3-1 select the palette for the display signal generator.&lt;br /&gt;
&lt;br /&gt;
Possible bits 6-4 for palette select (bit 6 selects first/second, 5-4 select type):&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Bits 6-4 !! selects&lt;br /&gt;
|-&lt;br /&gt;
| %000 || ULA first palette&lt;br /&gt;
|-&lt;br /&gt;
| %100 || ULA second palette&lt;br /&gt;
|-&lt;br /&gt;
| %001 || Layer 2 first palette&lt;br /&gt;
|-&lt;br /&gt;
| %101 || Layer 2 second palette&lt;br /&gt;
|-&lt;br /&gt;
| %010 || Sprites first palette&lt;br /&gt;
|-&lt;br /&gt;
| %110 || Sprites second palette&lt;br /&gt;
|-&lt;br /&gt;
| %011 || Tilemap first palette&lt;br /&gt;
|-&lt;br /&gt;
| %111 || Tilemap second palette&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Write will also reset the index of {{NextRegNo|$44}}, so the next write there will be considered as first byte of colour.&lt;br /&gt;
&lt;br /&gt;
To select Tilemap active palette use {{NextRegNo|$6B}}.&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=DMA&amp;diff=41471</id>
		<title>DMA</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=DMA&amp;diff=41471"/>
		<updated>2025-12-06T22:25:50Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: adding info about hw im2 mode interrupts executing extra instructions on &amp;quot;main thread&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
The ZX Spectrum Next DMA (zxnDMA) is a single channel DMA device that implements a subset of the Z80 DMA functionality. The subset is large enough to be compatible with common uses of the similar Datagear interface available for standard ZX Spectrum computers and compatibles. It also adds a burst mode capability that can deliver audio at programmable sample rates to the DAC device.&lt;br /&gt;
&lt;br /&gt;
== Accessing the zxnDMA ==&lt;br /&gt;
&amp;lt;del&amp;gt;The zxnDMA is mapped to a single Read/Write IO Port 0x6B which is the same one used by the Datagear but unlike the Datagear it doesn&#039;t also map itself to a second port 0x0B similar to the MB-02 interface.&amp;lt;/del&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since core 3.1.2 the zxnDMA is mapped to {{PortNo|$xx6B}}, and Zilog-DMA mode is mapped to {{PortNo|$xx0B}}.&lt;br /&gt;
&lt;br /&gt;
== Description  ==&lt;br /&gt;
The normal Z80 DMA (Z8410) chip is a pipelined device and because of that it has numerous off-by-one idiosyncrasies and requirements on the order that certain commands should be carried out. These issues are not duplicated in the zxnDMA. You can continue to program the zxnDMA as if it is were a Z8410 DMA device but it can also be programmed in a simpler manner.&lt;br /&gt;
&lt;br /&gt;
The single channel of the zxnDMA chip consists of two ports named A and B. Transfers can occur in either direction between ports A and B, each port can describe a target in memory or IO, and each can be configured to autoincrement, autodecrement or stay fixed after a byte is transferred.&lt;br /&gt;
&lt;br /&gt;
A special feature of the zxnDMA can force each byte transfer to take a fixed amount of time so that the zxnDMA can be used to deliver sampled audio.&lt;br /&gt;
&lt;br /&gt;
== Modes of Operation ==&lt;br /&gt;
The zxnDMA can operate in a z80-DMA compatibility mode.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;REMOVED in core 3.1.2:&#039;&#039;&#039; &amp;lt;del&amp;gt;The z80-DMA compatibility mode is selected by setting bit 6 of nextreg 0x06. In this mode, all transfers involve length+1 bytes which is the same behaviour as the z80-DMA chip. In zxn-DMA mode, the transfer length is exactly the number of bytes programmed. This mode is mainly present to accommodate existing spectrum software that uses the z80-DMA and for cp/m programs that may have a z80-DMA option.&amp;lt;/del&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Since core 3.1.2:&#039;&#039;&#039; the DMA mode is selected by port number, the {{PortNo|$xx6B}} works in zxnDMA mode, {{PortNo|$xx0B}} works in Zilog mode. The bit 6 in {{NextRegNo|$06}} is not DMA related any more and will be reused for something different.&lt;br /&gt;
&lt;br /&gt;
The zxnDMA can also operate in either burst or continuous modes.&lt;br /&gt;
&lt;br /&gt;
Continuous mode means the DMA chip runs to completion without allowing the CPU to run. When the CPU starts the DMA, the DMA operation will complete before the CPU executes its next instruction.&lt;br /&gt;
&lt;br /&gt;
Burst mode nominally means the DMA lets the CPU run if either port is not ready. This condition can&#039;t happen in the zxnDMA chip except when operated in the special fixed time transfer mode. In this mode, the zxnDMA will let the CPU run while it waits for the fixed time to expire between bytes transferred.&lt;br /&gt;
&lt;br /&gt;
Note that there is no byte transfer mode as in the Z80 DMA.&lt;br /&gt;
&lt;br /&gt;
== Programming the zxnDMA ==&lt;br /&gt;
Like the Z80 DMA chip, the zxnDMA has seven write registers named WR0-WR6 that control the device. Each register WR0-WR6 can have zero or more parameters associated with it.&lt;br /&gt;
&lt;br /&gt;
In a first write to the zxnDMA port, the write value is compared against a bitmask to determine which of the WR0-WR6 is the target. Remaining bits in the written value can contain data as well as a list of associated parameter bits. The parameter bits determine if further writes are expected to deliver parameter values. If there are multiple parameter bits set, the expected order of parameter values written is determined by parameter bit position from right to left (bit 0 through bit 7). Once all parameters are written, the zxnDMA again expects a regular register write selecting WR0-WR6.&lt;br /&gt;
&lt;br /&gt;
The table below describes the registers and the bitmask required to select them on the zxnDMA.&lt;br /&gt;
&lt;br /&gt;
{| &lt;br /&gt;
! Register Group&lt;br /&gt;
! Register Function Description&lt;br /&gt;
! Bitmask&lt;br /&gt;
! Notes&lt;br /&gt;
|- &lt;br /&gt;
| WR0&lt;br /&gt;
| Direction, Operation and Port A configuration&lt;br /&gt;
| &amp;lt;pre&amp;gt;0XXXXXAA&amp;lt;/pre&amp;gt;&lt;br /&gt;
| AA must NOT be 00&lt;br /&gt;
|- &lt;br /&gt;
| WR1&lt;br /&gt;
| Port A configuration&lt;br /&gt;
| &amp;lt;pre&amp;gt;0XXXX100&amp;lt;/pre&amp;gt;&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| WR2&lt;br /&gt;
| Port B configuration&lt;br /&gt;
| &amp;lt;pre&amp;gt;0XXXX000&amp;lt;/pre&amp;gt;&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| WR3&lt;br /&gt;
| Activation&lt;br /&gt;
| &amp;lt;pre&amp;gt;1XXXXX00&amp;lt;/pre&amp;gt;&lt;br /&gt;
| It’s best to use WR6&lt;br /&gt;
|- &lt;br /&gt;
| WR4&lt;br /&gt;
| Port B, Timing and Interrupt configuration&lt;br /&gt;
| &amp;lt;pre&amp;gt;1XXXXX01&amp;lt;/pre&amp;gt;&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| WR5&lt;br /&gt;
| Ready and Stop configuration&lt;br /&gt;
| &amp;lt;pre&amp;gt;10XXX010&amp;lt;/pre&amp;gt;&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| WR6&lt;br /&gt;
| Command Register&lt;br /&gt;
| &amp;lt;pre&amp;gt;1XXXXX11&amp;lt;/pre&amp;gt;&lt;br /&gt;
| &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== zxnDMA Registers ==&lt;br /&gt;
These are described below following the same convention used by Zilog for its DMA chip:&lt;br /&gt;
&lt;br /&gt;
=== WR0 – Write Register Group 0 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;D7  D6  D5  D4  D3  D2  D1  D0  BASE REGISTER BYTE&lt;br /&gt;
 0   |   |   |   |   |   |   |&lt;br /&gt;
     |   |   |   |   |   0   0  Do not use&lt;br /&gt;
     |   |   |   |   |   0   1  Transfer (Prefer this for Z80 DMA compatibility)&lt;br /&gt;
     |   |   |   |   |   1   0  Do not use (Behaves like Transfer, Search on Z80 DMA)&lt;br /&gt;
     |   |   |   |   |                       &lt;br /&gt;
     |   |   |   |   |   1   1  Do not use (Behaves like Transfer, Search/Transfer on Z80 DMA)&lt;br /&gt;
     |   |   |   |   |                      &lt;br /&gt;
     |   |   |   |   0 = Port B -&amp;amp;gt; Port A (Byte transfer direction)&lt;br /&gt;
     |   |   |   |   1 = Port A -&amp;amp;gt; Port B&lt;br /&gt;
     |   |   |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  PORT A STARTING ADDRESS (LOW BYTE)&lt;br /&gt;
     |   |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  PORT A STARTING ADDRESS (HIGH BYTE)&lt;br /&gt;
     |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  BLOCK LENGTH (LOW BYTE)&lt;br /&gt;
     V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  BLOCK LENGTH (HIGH BYTE)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Several registers are accessible from WR0. The first write to WR0 is to the base register byte. Bits D6:D3 are optionally set to indicate that associated registers in this group will be written next. The order the writes come in are from D3 to D6 (right to left). For example, if bits D6 and D3 are set, the next two writes will be directed to PORT A STARTING ADDRESS LOW followed by BLOCK LENGTH HIGH.&lt;br /&gt;
&lt;br /&gt;
=== WR1 – Write Register Group 1 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;D7  D6  D5  D4  D3  D2  D1  D0  BASE REGISTER BYTE&lt;br /&gt;
 0   |   |   |   |   1   0   0&lt;br /&gt;
     |   |   |   |&lt;br /&gt;
     |   |   |   0 = Port A is memory&lt;br /&gt;
     |   |   |   1 = Port A is IO&lt;br /&gt;
     |   |   |&lt;br /&gt;
     |   0   0 = Port A address decrements&lt;br /&gt;
     |   0   1 = Port A address increments&lt;br /&gt;
     |   1   0 = Port A address is fixed&lt;br /&gt;
     |   1   1 = Port A address is fixed&lt;br /&gt;
     |&lt;br /&gt;
     V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  PORT A VARIABLE TIMING BYTE&lt;br /&gt;
 0   0   0   0   0   0   |   |&lt;br /&gt;
                         0   0 = Cycle Length = 4&lt;br /&gt;
                         0   1 = Cycle Length = 3&lt;br /&gt;
                         1   0 = Cycle Length = 2&lt;br /&gt;
                         1   1 = Do not use&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The cycle length is the number of cycles used in a read or write operation. The first cycle asserts signals and the last cycle releases them. There is no half cycle timing for the control signals.&lt;br /&gt;
&lt;br /&gt;
=== WR2 – Write Register Group 2 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;D7  D6  D5  D4  D3  D2  D1  D0  BASE REGISTER BYTE&lt;br /&gt;
 0   |   |   |   |   0   0   0&lt;br /&gt;
     |   |   |   |&lt;br /&gt;
     |   |   |   0 = Port B is memory&lt;br /&gt;
     |   |   |   1 = Port B is IO&lt;br /&gt;
     |   |   |&lt;br /&gt;
     |   0   0 = Port B address decrements&lt;br /&gt;
     |   0   1 = Port B address increments&lt;br /&gt;
     |   1   0 = Port B address is fixed&lt;br /&gt;
     |   1   1 = Port B address is fixed&lt;br /&gt;
     |&lt;br /&gt;
     V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  PORT B VARIABLE TIMING BYTE&lt;br /&gt;
 0   0   |   0   0   0   |   |&lt;br /&gt;
         |               0   0 = Cycle Length = 4&lt;br /&gt;
         |               0   1 = Cycle Length = 3&lt;br /&gt;
         |               1   0 = Cycle Length = 2&lt;br /&gt;
         |               1   1 = Do not use&lt;br /&gt;
         |&lt;br /&gt;
         V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  ZXN PRESCALAR (FIXED TIME TRANSFER)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The ZXN PRESCALAR is a feature of the zxnDMA implementation. If non-zero, a delay will be inserted after each byte is transferred such that the total time needed for each transfer is determined by the prescalar. This works in both the continuous mode and the burst mode. If the DMA is operated in burst mode, the DMA will give up any waiting time to the CPU so that the CPU can run while the DMA is idle.&lt;br /&gt;
&lt;br /&gt;
The rate of transfer is given by the formula “Frate = 875kHz / prescalar” or, rearranged, “prescalar = 875kHz / Frate”. The formula is framed in terms of a sample rate (Frate) but Frate can be inverted to set a transfer time for each byte instead. The 875kHz constant is a nominal value assuming a 28MHz system clock; the system clock actually varies from this depending on the video timing selected by the user (HDMI, VGA0-6) so for complete accuracy the constant should be prorated according to documentation for nextreg 0x11.&lt;br /&gt;
&lt;br /&gt;
In a DMA audio setting, selecting a sample rate of 16kHz would mean setting the prescalar value to 55. This sample period is constant across changes in CPU speed.&lt;br /&gt;
&lt;br /&gt;
=== WR3 – Write Register Group 3 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;D7  D6  D5  D4  D3  D2  D1  D0  BASE REGISTER BYTE&lt;br /&gt;
 1   |   0   0   0   0   0   0&lt;br /&gt;
     |&lt;br /&gt;
     1 = DMA Enable&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The Z80 DMA defines more fields but they are ignored by the zxnDMA. The two other registers defined by the Z80 DMA in this group on D4 and D3 are implemented by the zxnDMA but they do nothing.&lt;br /&gt;
&lt;br /&gt;
It is preferred to start the DMA by writing an &#039;Enable DMA&#039; command to WR6.&lt;br /&gt;
&lt;br /&gt;
=== WR4 – Write Register Group 4 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;D7  D6  D5  D4  D3  D2  D1  D0  BASE REGISTER BYTE&lt;br /&gt;
 1   |   |   0   |   |   0   1&lt;br /&gt;
     |   |       |   |&lt;br /&gt;
     0   0 = Do not use (Behaves like Continuous mode, Byte mode on Z80 DMA)&lt;br /&gt;
     0   1 = Continuous mode&lt;br /&gt;
     1   0 = Burst mode&lt;br /&gt;
     1   1 = Do not use&lt;br /&gt;
                 |   |&lt;br /&gt;
                 |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  PORT B STARTING ADDRESS (LOW BYTE)&lt;br /&gt;
                 |&lt;br /&gt;
                 V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  PORT B STARTING ADDRESS (HIGH BYTE)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The Z80 DMA defines three more registers in this group through D4 that define interrupt behaviour. Interrups and pulse generation are not implemented in the zxnDMA nor are these registers available for writing.&lt;br /&gt;
&lt;br /&gt;
=== WR5 – Write Register Group 5 ===&lt;br /&gt;
&amp;lt;pre&amp;gt;D7  D6  D5  D4  D3  D2  D1  D0  BASE REGISTER BYTE&lt;br /&gt;
 1   0   |   |   0   0   1   0&lt;br /&gt;
         |   |&lt;br /&gt;
         |   0 = /ce only&lt;br /&gt;
         |   1 = /ce &amp;amp; /wait multiplexed&lt;br /&gt;
         |&lt;br /&gt;
         0 = Stop on end of block&lt;br /&gt;
         1 = Auto restart on end of block&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The /ce &amp;amp; /wait mode is implemented in the zxnDMA but is not currently used. This mode has an external device using the DMA&#039;s /ce pin to insert wait states during the DMA&#039;s transfer.&lt;br /&gt;
&lt;br /&gt;
The auto restart feature causes the DMA to automatically reload its source and destination addresses and reset its byte counter to zero to repeat the last transfer when a previous one is finished.&lt;br /&gt;
&lt;br /&gt;
=== WR6 – Command Register ===&lt;br /&gt;
&amp;lt;pre&amp;gt;D7  D6  D5  D4  D3  D2  D1  D0  BASE REGISTER BYTE&lt;br /&gt;
 1   ?   ?   ?   ?   ?   1   1&lt;br /&gt;
     |   |   |   |   |&lt;br /&gt;
     1   0   0   0   0 = 0xC3 = Reset&lt;br /&gt;
     1   0   0   0   1 = 0xC7 = Reset Port A Timing&lt;br /&gt;
     1   0   0   1   0 = 0xCB = Reset Port B Timing&lt;br /&gt;
     0   1   1   0   0 = 0xB3 = Force Ready (irrelevant for zxnDMA)&lt;br /&gt;
     0   1   1   1   1 = 0xBF = Read Status Byte&lt;br /&gt;
     0   0   0   1   0 = 0x8B = Reinitialize Status Byte&lt;br /&gt;
     0   1   0   0   1 = 0xA7 = Initialize Read Sequence&lt;br /&gt;
     1   0   0   1   1 = 0xCF = Load&lt;br /&gt;
     1   0   1   0   0 = 0xD3 = Continue&lt;br /&gt;
     0   0   0   0   1 = 0x87 = Enable DMA&lt;br /&gt;
     0   0   0   0   0 = 0x83 = Disable DMA&lt;br /&gt;
 +-- 0   1   1   1   0 = 0xBB = Read Mask Follows&lt;br /&gt;
 |&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  READ MASK&lt;br /&gt;
 0   |   |   |   |   |   |   |&lt;br /&gt;
     |   |   |   |   |   |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  Status Byte&lt;br /&gt;
     |   |   |   |   |   |&lt;br /&gt;
     |   |   |   |   |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  Byte Counter Low (&amp;quot;High&amp;quot; with core 3.0.5 = bug in core)&lt;br /&gt;
     |   |   |   |   |&lt;br /&gt;
     |   |   |   |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  Byte Counter High (&amp;quot;Low&amp;quot; with core 3.0.5 = bug in core)&lt;br /&gt;
     |   |   |   |&lt;br /&gt;
     |   |   |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  Port A Address Low&lt;br /&gt;
     |   |   |&lt;br /&gt;
     |   |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  Port A Address High&lt;br /&gt;
     |   |&lt;br /&gt;
     |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  Port B Address Low&lt;br /&gt;
     |&lt;br /&gt;
     V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  Port B Address High&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Unimplemented Z80 DMA commands are ignored.&lt;br /&gt;
&lt;br /&gt;
Prior to starting the DMA transfer, a LOAD command must be issued to copy the Port A and Port B addresses into the DMA&#039;s internal pointers. Then an &#039;Enable DMA&#039; command is issued to start the DMA. The last LOAD command before ENABLE must be done with correct transfer direction set.&lt;br /&gt;
&lt;br /&gt;
The &#039;Continue&#039; command resets the DMA&#039;s byte counter so that a following &#039;Enable DMA&#039; allows the DMA to repeat the last transfer but using the current internal address pointers. I.e. it continues from where the last copy operation left off.&lt;br /&gt;
&lt;br /&gt;
Reset and Reset Port A/B Timing commands on zxnDMA do reset also prescalar value.&lt;br /&gt;
&lt;br /&gt;
Registers can be read via an IO read from the DMA port after setting the read mask. (At power up the read mask is set to 0x7f). Register values are the current internal DMA counter values. So &#039;Port Address A Low&#039; is the lower 8-bits of Port A’s next transfer address. Once the end of the read mask is reached, further reads loop around to the first one.&lt;br /&gt;
&lt;br /&gt;
The format of the DMA status byte is as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;00E1101T&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
E is set to 0 if the total block length has been transferred at least once.&lt;br /&gt;
&lt;br /&gt;
T is set to 1 if at least one byte has been transferred.&lt;br /&gt;
&lt;br /&gt;
== Operating speed ==&lt;br /&gt;
The zxnDMA operates at the same speed as the CPU, that is 3.5MHz, 7MHz, 14MHz or 28Mhz. This is a contended clock that is modified by the ULA and the auto-slowdown by [[Layer 2|Layer2]] (which only occurred in Next core&#039;s 1 and 2, the limitation was lifted in core 3.0).&lt;br /&gt;
&lt;br /&gt;
The (pre-core 3.0) auto-slowdown occurs without user intervention if speed exceeds 7Mhz and the active Layer2 display is being generated (higher speed operation resumes when the active Layer2 display is not generated). Programmers do NOT need to account for speed differences regarding DMA transfers as this happens automatically.&lt;br /&gt;
&lt;br /&gt;
Because of this, the cycle lengths for Ports A and B can be set to their minimum values without ill effects. The cycle lengths specified for Ports A and B are intended to selectively slow down read or write cycles for hardware that cannot operate at the DMA&#039;s full speed.&lt;br /&gt;
&lt;br /&gt;
== The DMA and Interrupts ==&lt;br /&gt;
The zxnDMA cannot currently generate [[Interrupts|interrupts]].&lt;br /&gt;
&lt;br /&gt;
The other side of this is that while the DMA controls the bus, the Z80 cannot respond to interrupts. On the Z80, the NMI interrupt is edge triggered so if an NMI occurs the fact that it occurred is stored internally in the Z80 so that it will respond when it is woken up. On the other hand, maskable interrupts are level triggered. That is, the Z80 must be active to regularly sample the /INT line to determine if a maskable interrupt is occurring. On the Spectrum and the ZX Next, the ULA (and line interrupt) are only asserted for a fixed amount of time ~30 cycles at 3.5MHz. If the DMA is executing a transfer while the interrupt is asserted, the CPU will not be able to see this and it will most likely miss the interrupt. In burst mode, with large-enough prescalar value, the CPU will never miss these interrupts, although this may change if multiple channels are implemented.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Since core 3.1.8:&#039;&#039;&#039; the ability to interrupt DMA transfers was added, this is opt-in mechanism and must be configured through {{NextRegNo|$CC}}, {{NextRegNo|$CD}} and {{NextRegNo|$CE}} and requires &amp;quot;hw im2 mode&amp;quot; interrupts being set. Because interrupts are only sampled at the end of an instruction by the Z80, each time the dma is interrupted one instruction of progress is made in the main program (before the interrupt handler code is entered).&lt;br /&gt;
&lt;br /&gt;
This means after starting the DMA transfer with last `out` instruction you must follow it by N instructions which don&#039;t affect the transfer (don&#039;t remap source data memory, select different sprite/copper/... index if that&#039;s target of transfer, don&#039;t write anything to zxnDMA port), either doing different kind of work with CPU or adding block of `nop` instructions, to have non-interfering block of code available to fire N interrupts during transfer. Chose N to accommodate for worst case scenario of how many times you will interrupt the running DMA transfer. Or you can read state of zxnDMA to see if transfer did finish, but (IMHO by ped7g) in most cases it will be performance-cheaper to just add block of nop instructions or do other work on CPU not interfering with transfer.&lt;br /&gt;
&lt;br /&gt;
== Programming examples ==&lt;br /&gt;
A simple way to program the DMA is to walk down the list of registers WR0-WR5, sending desired settings to each. Then start the DMA by sending a LOAD command followed by an ENABLE_DMA command to WR6. Once more familiar with the DMA, you will discover that the amount of information sent can be reduced to what changes between transfers.&lt;br /&gt;
&lt;br /&gt;
=== Assembly ===&lt;br /&gt;
Short example program to DMA memory to the screen, then DMA a sprite image from memory to sprite RAM, and then showing said sprite scrolling across the screen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;;------------------------------------------------------------------------------&lt;br /&gt;
    ; sjasmplus extra options to enable Z80N, stricter syntax and Next device&lt;br /&gt;
    opt --zxnext --syntax=abf : device zxspectrumnext&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
;     DEFINE testing        ; uncomment to produce NEX file (instead of DOT)&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; DMA (Register 6)&lt;br /&gt;
;&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
;zxnDMA programming example&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
;(c) Jim Bagley&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
DMA_RESET                      equ $c3&lt;br /&gt;
DMA_RESET_PORT_A_TIMING        equ $c7&lt;br /&gt;
DMA_RESET_PORT_B_TIMING        equ $cb&lt;br /&gt;
DMA_LOAD                       equ $cf ; %11001111&lt;br /&gt;
DMA_CONTINUE                   equ $d3&lt;br /&gt;
DMA_DISABLE_INTERUPTS          equ $af&lt;br /&gt;
DMA_ENABLE_INTERUPTS           equ $ab&lt;br /&gt;
DMA_RESET_DISABLE_INTERUPTS    equ $a3&lt;br /&gt;
DMA_ENABLE_AFTER_RETI          equ $b7&lt;br /&gt;
DMA_READ_STATUS_BYTE           equ $bf&lt;br /&gt;
DMA_REINIT_STATUS_BYTE         equ $8b&lt;br /&gt;
DMA_START_READ_SEQUENCE        equ $a7&lt;br /&gt;
DMA_FORCE_READY                equ $b3&lt;br /&gt;
DMA_DISABLE                    equ $83&lt;br /&gt;
DMA_ENABLE                     equ $87&lt;br /&gt;
DMA_WRITE_REGISTER_COMMAND     equ $bb&lt;br /&gt;
DMA_BURST                      equ %11001101&lt;br /&gt;
DMA_CONTINUOUS                 equ %10101101&lt;br /&gt;
ZXN_DMA_PORT                   equ $6b&lt;br /&gt;
SPRITE_STATUS_SLOT_SELECT      equ $303B&lt;br /&gt;
SPRITE_IMAGE_PORT              equ $5b&lt;br /&gt;
SPRITE_INFO_PORT               equ $57&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
    IFDEF testing&lt;br /&gt;
        org $5800&lt;br /&gt;
        block 32*24, $38              ; default ULA attributes&lt;br /&gt;
        org $6000&lt;br /&gt;
    ELSE&lt;br /&gt;
        org $2000&lt;br /&gt;
    ENDIF&lt;br /&gt;
&lt;br /&gt;
start&lt;br /&gt;
    ld   hl,$0000&lt;br /&gt;
    ld   de,$4000&lt;br /&gt;
    ld   bc,$800&lt;br /&gt;
    call TransferDMA                  ; copy some random data to the screen pointing&lt;br /&gt;
                                      ; to ROM for now, for the purpose of showing &lt;br /&gt;
                                      ; how to do a DMA copy.&lt;br /&gt;
    ld   a,0                          ; sprite image number we want to update&lt;br /&gt;
    ld   bc,SPRITE_STATUS_SLOT_SELECT&lt;br /&gt;
    out  (c),a                        ; set the sprite image number&lt;br /&gt;
    ld   bc,1*256                     ; number to transfer (1)&lt;br /&gt;
    ld   hl,testsprite                ; from &lt;br /&gt;
    call TransferDMASprite            ; transfer to sprite ram&lt;br /&gt;
&lt;br /&gt;
    nextreg 21,1                      ; turn sprite on. for more info on this check &lt;br /&gt;
                                      ; out https://www.specnext.com/tbblue-io-port-system/&lt;br /&gt;
    ld   de,0&lt;br /&gt;
    ld   (xpos),de                    ; set initial X position ( doesn&#039;t need it for&lt;br /&gt;
                                      ; this demo, but if you run the .loop again it&lt;br /&gt;
                                      ; will continue from where it was&lt;br /&gt;
    ld   a,$20&lt;br /&gt;
    ld   (ypos),a                     ; set initial Y position&lt;br /&gt;
&lt;br /&gt;
.loop&lt;br /&gt;
    ld   a,0                          ; sprite number we want to position&lt;br /&gt;
    ld   bc,SPRITE_STATUS_SLOT_SELECT&lt;br /&gt;
    out  (c),a&lt;br /&gt;
    ld   de,(xpos)&lt;br /&gt;
    ld   hl,(ypos)                    ; ignores H so doing this rather than &lt;br /&gt;
                                      ; ld a,(ypos):ld l,a&lt;br /&gt;
    ld   bc,(image)                   ; not flipped or palette shifted&lt;br /&gt;
    call SetSprite&lt;br /&gt;
&lt;br /&gt;
    halt&lt;br /&gt;
&lt;br /&gt;
    ld   de,(xpos)&lt;br /&gt;
    inc  de&lt;br /&gt;
    ld   (xpos),de&lt;br /&gt;
    ld   a,d&lt;br /&gt;
    cp   $01&lt;br /&gt;
    jr   nz,.loop                     ; if high byte of xpos is not 1 (right of &lt;br /&gt;
                                      ; screen )&lt;br /&gt;
    ld   a,e&lt;br /&gt;
    cp   $20+1&lt;br /&gt;
    jr   nz,.loop                     ; if low byte is not $21 just off the right of&lt;br /&gt;
                                      ; the screen, $20 is off screen but as the &lt;br /&gt;
                                      ; INC DE is just above and not updated sprite&lt;br /&gt;
                                      ; after it, it needs to be $21&lt;br /&gt;
    xor  a&lt;br /&gt;
    ret                               ; return back to basic with OK&lt;br /&gt;
&lt;br /&gt;
xpos dw 0                             ; x position&lt;br /&gt;
ypos db 0                             ; y position&lt;br /&gt;
                                      ; these next two BITS and IMAGE are swapped &lt;br /&gt;
                                      ; as bits needs to go into B register&lt;br /&gt;
image db 0+$80                        ; use image 0 (for the image we transfered)&lt;br /&gt;
                                      ; +$80 to set the sprite to active&lt;br /&gt;
bits db 0                             ; not flipped or palette shifted&lt;br /&gt;
&lt;br /&gt;
c1 = %11100000&lt;br /&gt;
c2 = %11000000&lt;br /&gt;
c3 = %10100000&lt;br /&gt;
c4 = %10000000&lt;br /&gt;
c5 = %01100000&lt;br /&gt;
c6 = %01000000&lt;br /&gt;
c7 = %00100000&lt;br /&gt;
c8 = %00000000&lt;br /&gt;
&lt;br /&gt;
testsprite&lt;br /&gt;
    db c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1&lt;br /&gt;
    db c1,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c1&lt;br /&gt;
    db c1,c2,c3,c3,c3,c3,c3,c3,c3,c3,c3,c3,c3,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c4,c4,c4,c4,c4,c4,c4,c4,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c5,c5,c5,c5,c5,c5,c5,c5,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c5,c6,c6,c6,c6,c6,c6,c5,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c5,c6,c7,c7,c7,c7,c6,c5,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c5,c6,c7,c8,c8,c7,c6,c5,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c5,c6,c7,c8,c8,c7,c6,c5,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c5,c6,c7,c7,c7,c7,c6,c5,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c5,c6,c6,c6,c6,c6,c6,c5,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c5,c5,c5,c5,c5,c5,c5,c5,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c4,c4,c4,c4,c4,c4,c4,c4,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c3,c3,c3,c3,c3,c3,c3,c3,c3,c3,c3,c2,c1&lt;br /&gt;
    db c1,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c1&lt;br /&gt;
    db c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1&lt;br /&gt;
&lt;br /&gt;
;-------------------------------------------------&lt;br /&gt;
; de = X&lt;br /&gt;
; l = Y&lt;br /&gt;
; b = bits&lt;br /&gt;
; c = sprite image&lt;br /&gt;
SetSprite&lt;br /&gt;
    push bc&lt;br /&gt;
    ld bc,SPRITE_INFO_PORT&lt;br /&gt;
    out (c),e ; Xpos&lt;br /&gt;
    out (c),l ; Ypos&lt;br /&gt;
    pop hl&lt;br /&gt;
    ld a,d&lt;br /&gt;
    and 1&lt;br /&gt;
    or h&lt;br /&gt;
    out (c),a&lt;br /&gt;
    ld a,l:or $80&lt;br /&gt;
    out (c),a ; image&lt;br /&gt;
    ret&lt;br /&gt;
&lt;br /&gt;
;--------------------------------&lt;br /&gt;
; hl = source&lt;br /&gt;
; de = destination&lt;br /&gt;
; bc = length&lt;br /&gt;
;--------------------------------&lt;br /&gt;
TransferDMA&lt;br /&gt;
    di&lt;br /&gt;
    ld (DMASource),hl&lt;br /&gt;
    ld (DMADest),de&lt;br /&gt;
    ld (DMALength),bc&lt;br /&gt;
    ld hl,DMACode&lt;br /&gt;
    ld b,DMACode_Len&lt;br /&gt;
    ld c,ZXN_DMA_PORT&lt;br /&gt;
    otir&lt;br /&gt;
    ei&lt;br /&gt;
    ret&lt;br /&gt;
&lt;br /&gt;
DMACode db DMA_DISABLE&lt;br /&gt;
        db %01111101                  ; R0-Transfer mode, A -&amp;gt; B, write adress &lt;br /&gt;
                                      ; + block length&lt;br /&gt;
DMASource dw 0                        ; R0-Port A, Start address &lt;br /&gt;
                                      ; (source address)&lt;br /&gt;
DMALength dw 0                        ; R0-Block length (length in bytes)&lt;br /&gt;
        db %01010100                  ; R1-write A time byte, increment, to &lt;br /&gt;
                                      ; memory, bitmask&lt;br /&gt;
        db %00000010                  ; 2t&lt;br /&gt;
        db %01010000                  ; R2-write B time byte, increment, to &lt;br /&gt;
                                      ; memory, bitmask&lt;br /&gt;
        db %00000010                  ; R2-Cycle length port B&lt;br /&gt;
        db DMA_CONTINUOUS             ; R4-Continuous mode (use this for block &lt;br /&gt;
                                      ; transfer), write dest adress&lt;br /&gt;
DMADest dw 0                          ; R4-Dest address (destination address)&lt;br /&gt;
        db %10000010                  ; R5-Restart on end of block, RDY active &lt;br /&gt;
                                      ; LOW&lt;br /&gt;
        db DMA_LOAD                   ; R6-Load&lt;br /&gt;
        db DMA_ENABLE                 ; R6-Enable DMA&lt;br /&gt;
        &lt;br /&gt;
DMACode_Len                    equ $-DMACode&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; hl = source&lt;br /&gt;
; bc = length&lt;br /&gt;
; set port to write to with TBBLUE_REGISTER_SELECT&lt;br /&gt;
; prior to call&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
TransferDMAPort&lt;br /&gt;
    di&lt;br /&gt;
    ld (DMASourceP),hl&lt;br /&gt;
    ld (DMALengthP),bc&lt;br /&gt;
    ld hl,DMACodeP&lt;br /&gt;
    ld b,DMACode_LenP&lt;br /&gt;
    ld c,ZXN_DMA_PORT&lt;br /&gt;
    otir&lt;br /&gt;
    ei&lt;br /&gt;
    ret&lt;br /&gt;
&lt;br /&gt;
DMACodeP db DMA_DISABLE&lt;br /&gt;
        db %01111101                  ; R0-Transfer mode, A -&amp;gt; B, write adress &lt;br /&gt;
                                      ; + block length&lt;br /&gt;
DMASourceP dw 0                       ; R0-Port A, Start address (source address)&lt;br /&gt;
DMALengthP dw 0                       ; R0-Block length (length in bytes)&lt;br /&gt;
        db %01010100                  ; R1-read A time byte, increment, to &lt;br /&gt;
                                      ; memory, bitmask&lt;br /&gt;
        db %00000010                  ; R1-Cycle length port A&lt;br /&gt;
        db %01101000                  ; R2-write B time byte, increment, to &lt;br /&gt;
                                      ; memory, bitmask&lt;br /&gt;
        db %00000010                  ; R2-Cycle length port B&lt;br /&gt;
        db %10101101                  ; R4-Continuous mode (use this for block &lt;br /&gt;
                                      ; transfer), write dest adress&lt;br /&gt;
        dw $253b                      ; R4-Dest address (destination address)&lt;br /&gt;
        db %10000010                  ; R5-Restart on end of block, RDY active&lt;br /&gt;
                                      ; LOW&lt;br /&gt;
        db DMA_LOAD                   ; R6-Load&lt;br /&gt;
        db DMA_ENABLE                 ; R6-Enable DMA&lt;br /&gt;
        &lt;br /&gt;
DMACode_LenP                   equ $-DMACodeP&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; hl = source&lt;br /&gt;
; bc = length&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
TransferDMASprite&lt;br /&gt;
    di&lt;br /&gt;
    ld (DMASourceS),hl&lt;br /&gt;
    ld (DMALengthS),bc&lt;br /&gt;
    ld hl,DMACodeS&lt;br /&gt;
    ld b,DMACode_LenS&lt;br /&gt;
    ld c,ZXN_DMA_PORT&lt;br /&gt;
    otir&lt;br /&gt;
    ei&lt;br /&gt;
    ret&lt;br /&gt;
&lt;br /&gt;
DMACodeS db DMA_DISABLE&lt;br /&gt;
        db %01111101                   ; R0-Transfer mode, A -&amp;gt; B, write adress &lt;br /&gt;
                                       ; + block length&lt;br /&gt;
DMASourceS dw 0                        ; R0-Port A, Start address (source address)&lt;br /&gt;
DMALengthS dw 0                        ; R0-Block length (length in bytes)&lt;br /&gt;
        db %01010100                   ; R1-read A time byte, increment, to &lt;br /&gt;
                                       ; memory, bitmask&lt;br /&gt;
        db %00000010                   ; R1-Cycle length port A&lt;br /&gt;
        db %01101000                   ; R2-write B time byte, increment, to &lt;br /&gt;
                                       ; memory, bitmask&lt;br /&gt;
        db %00000010                   ; R2-Cycle length port B&lt;br /&gt;
        db %10101101                   ; R4-Continuous mode (use this for block&lt;br /&gt;
                                       ; transfer), write dest adress&lt;br /&gt;
        dw SPRITE_IMAGE_PORT           ; R4-Dest address (destination address)&lt;br /&gt;
        db %10000010                   ; R5-Restart on end of block, RDY active&lt;br /&gt;
                                       ; LOW&lt;br /&gt;
        db DMA_LOAD                    ; R6-Load&lt;br /&gt;
        db DMA_ENABLE                  ; R6-Enable DMA&lt;br /&gt;
DMACode_LenS                   equ $-DMACodeS&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; de = dest, a = fill value, bc = lenth&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
DMAFill&lt;br /&gt;
    di&lt;br /&gt;
    ld (FillValue),a&lt;br /&gt;
    ld (DMACDest),de&lt;br /&gt;
    ld (DMACLength),bc&lt;br /&gt;
    ld hl,DMACCode&lt;br /&gt;
    ld b,DMACCode_Len&lt;br /&gt;
    ld c,ZXN_DMA_PORT&lt;br /&gt;
    otir&lt;br /&gt;
    ei&lt;br /&gt;
    ret&lt;br /&gt;
&lt;br /&gt;
FillValue db 22&lt;br /&gt;
DMACCode db DMA_DISABLE&lt;br /&gt;
        db %01111101&lt;br /&gt;
DMACSource dw FillValue&lt;br /&gt;
DMACLength dw 0&lt;br /&gt;
        db %00100100,%00010000,%10101101&lt;br /&gt;
DMACDest dw 0&lt;br /&gt;
        db DMA_LOAD,DMA_ENABLE&lt;br /&gt;
DMACCode_Len equ $-DMACCode&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; End of file&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
    IFDEF testing&lt;br /&gt;
        savenex open &amp;quot;DMAtest.nex&amp;quot;, start, $FF00&lt;br /&gt;
        savenex bank 5&lt;br /&gt;
    ELSE&lt;br /&gt;
fin&lt;br /&gt;
        savebin &amp;quot;DMATEST&amp;quot;,start,fin-start&lt;br /&gt;
    ENDIF&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Based on original text by: Allen Albright &amp;amp; Mike Dailly with input by Jim Bagley, Lyndon J Sharp and Phoebus R. Dokos&lt;br /&gt;
&lt;br /&gt;
== Technical details (core 3.1.3+)  ==&lt;br /&gt;
&lt;br /&gt;
The Zilog/zxnDMA mode is now selected by using the particular I/O port number ({{PortNo|$xx6B}} for zxnDMA mode, {{PortNo|$xx0B}} for Zilog mode). The bit 6 in {{NextRegNo|$06}} is not DMA related any more and will be reused for something different.&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;counter&amp;quot; RR1-RR2 read back after transfer has correct byte order since core 3.1.4.&lt;br /&gt;
&lt;br /&gt;
Other differences described below in &amp;quot;3.0.5&amp;quot; remains (but from practical point of view the Zilog DMA emulation in 3.1.4 is near-perfect, all the remaining differences are very minor).&lt;br /&gt;
&lt;br /&gt;
== Technical details (core 3.0.5)  ==&lt;br /&gt;
&lt;br /&gt;
=== Zilog DMA compatibility mode ===&lt;br /&gt;
In Zilog DMA compatibility mode (bit 6 of {{NextRegNo|$06}}) the zxnDMA will mostly work as expected, but there are few differences in behaviour which may eventually throw off some rare SW, here is the list of the known differences (most of them describe also how the zxnDMA mode works):&lt;br /&gt;
&lt;br /&gt;
The LOAD command must be issued with correct transfer direction, loading addresses in opposite direction and flipping direction afterward will mismatch the source/destination address data (Zilog/UA858D DMA chips are also sensitive to direction flip after LOAD, but the resulting transfer quirks in different way, reading source data byte after write, offsetting whole transfer by one and damaging start/end of sequence).&lt;br /&gt;
(does apply also to zxnDMA mode)&lt;br /&gt;
&lt;br /&gt;
The LOAD command will NOT destroy the already issued &amp;quot;Initialize Read Sequence&amp;quot; - this is how even the original Zilog documentation describes the DMA chip operation, but the real Zilog DMA and UA858D (clone chip) both destroy read sequence upon LOAD command (zxnDMA is better).&lt;br /&gt;
(does apply also to zxnDMA mode)&lt;br /&gt;
&lt;br /&gt;
The content of registers read back after finished transfer differs: the counter has swapped LSB with MSB byte, and both addresses will be adjusted length+1 times (Zilog/UA858D will return destination address adjusted only length-many times).&lt;br /&gt;
(does apply also to zxnDMA mode, except addresses are adjusted only &amp;quot;length&amp;quot; times of course, counter has still swapped bytes)&lt;br /&gt;
&lt;br /&gt;
Any read of zxnDMA port without pending read request (commands &amp;quot;Read Status Byte&amp;quot; or &amp;quot;Initialize Read Sequence&amp;quot;) will return status byte (Zilog will return random value vaguely similar to status byte, but incorrect, UA858D will return zero).&lt;br /&gt;
(does apply also to zxnDMA mode)&lt;br /&gt;
&lt;br /&gt;
Status byte doesn&#039;t have bit 0 set (the &amp;quot;T&amp;quot; bit in description above).&lt;br /&gt;
(does apply also to zxnDMA mode)&lt;br /&gt;
&lt;br /&gt;
Be aware that both custom timing cycles count, and prescalar values are preserved in zxnDMA even when future write to WR1/WR2 does skip these particular bytes. To reset prescalar or cycles timing, write explicitly zero into prescalar register or use commands reset/reset-port-timing.&lt;br /&gt;
(does apply also to zxnDMA mode, the prescalar works only in zxnDMA mode)&lt;br /&gt;
&lt;br /&gt;
The destination port address is LOAD-ed even when it is &amp;quot;fixed&amp;quot; type (Contrary to Zilog DMA, which requires you to load such port as &amp;quot;source&amp;quot;, flip the direction after and re-LOAD again with correct direction. UA858D chip does also load destination port address in any case, just like zxnDMA).&lt;br /&gt;
(does apply also to zxnDMA mode)&lt;br /&gt;
&lt;br /&gt;
=== zxnDMA mode vs Zilog mode ===&lt;br /&gt;
&lt;br /&gt;
In zxnDMA mode length of transfer is equal to the length written to WR0 register, port addresses are adjusted also only length-times.&lt;br /&gt;
&lt;br /&gt;
Prescalar value will affect speed of transfer (use zero to switch prescalar off) (in burst mode during the extra idle time the CPU receives control back and can execute further instructions, in continuous mode the transfer will keep blocking CPU even when &amp;quot;slow&amp;quot; transfer is being done).&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=DMA&amp;diff=41435</id>
		<title>DMA</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=DMA&amp;diff=41435"/>
		<updated>2025-12-02T09:36:40Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: Adding one more note about prescalar being reset by reset commands to make it easier to find.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
The ZX Spectrum Next DMA (zxnDMA) is a single channel DMA device that implements a subset of the Z80 DMA functionality. The subset is large enough to be compatible with common uses of the similar Datagear interface available for standard ZX Spectrum computers and compatibles. It also adds a burst mode capability that can deliver audio at programmable sample rates to the DAC device.&lt;br /&gt;
&lt;br /&gt;
== Accessing the zxnDMA ==&lt;br /&gt;
&amp;lt;del&amp;gt;The zxnDMA is mapped to a single Read/Write IO Port 0x6B which is the same one used by the Datagear but unlike the Datagear it doesn&#039;t also map itself to a second port 0x0B similar to the MB-02 interface.&amp;lt;/del&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since core 3.1.2 the zxnDMA is mapped to {{PortNo|$xx6B}}, and Zilog-DMA mode is mapped to {{PortNo|$xx0B}}.&lt;br /&gt;
&lt;br /&gt;
== Description  ==&lt;br /&gt;
The normal Z80 DMA (Z8410) chip is a pipelined device and because of that it has numerous off-by-one idiosyncrasies and requirements on the order that certain commands should be carried out. These issues are not duplicated in the zxnDMA. You can continue to program the zxnDMA as if it is were a Z8410 DMA device but it can also be programmed in a simpler manner.&lt;br /&gt;
&lt;br /&gt;
The single channel of the zxnDMA chip consists of two ports named A and B. Transfers can occur in either direction between ports A and B, each port can describe a target in memory or IO, and each can be configured to autoincrement, autodecrement or stay fixed after a byte is transferred.&lt;br /&gt;
&lt;br /&gt;
A special feature of the zxnDMA can force each byte transfer to take a fixed amount of time so that the zxnDMA can be used to deliver sampled audio.&lt;br /&gt;
&lt;br /&gt;
== Modes of Operation ==&lt;br /&gt;
The zxnDMA can operate in a z80-DMA compatibility mode.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;REMOVED in core 3.1.2:&#039;&#039;&#039; &amp;lt;del&amp;gt;The z80-DMA compatibility mode is selected by setting bit 6 of nextreg 0x06. In this mode, all transfers involve length+1 bytes which is the same behaviour as the z80-DMA chip. In zxn-DMA mode, the transfer length is exactly the number of bytes programmed. This mode is mainly present to accommodate existing spectrum software that uses the z80-DMA and for cp/m programs that may have a z80-DMA option.&amp;lt;/del&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Since core 3.1.2:&#039;&#039;&#039; the DMA mode is selected by port number, the {{PortNo|$xx6B}} works in zxnDMA mode, {{PortNo|$xx0B}} works in Zilog mode. The bit 6 in {{NextRegNo|$06}} is not DMA related any more and will be reused for something different.&lt;br /&gt;
&lt;br /&gt;
The zxnDMA can also operate in either burst or continuous modes.&lt;br /&gt;
&lt;br /&gt;
Continuous mode means the DMA chip runs to completion without allowing the CPU to run. When the CPU starts the DMA, the DMA operation will complete before the CPU executes its next instruction.&lt;br /&gt;
&lt;br /&gt;
Burst mode nominally means the DMA lets the CPU run if either port is not ready. This condition can&#039;t happen in the zxnDMA chip except when operated in the special fixed time transfer mode. In this mode, the zxnDMA will let the CPU run while it waits for the fixed time to expire between bytes transferred.&lt;br /&gt;
&lt;br /&gt;
Note that there is no byte transfer mode as in the Z80 DMA.&lt;br /&gt;
&lt;br /&gt;
== Programming the zxnDMA ==&lt;br /&gt;
Like the Z80 DMA chip, the zxnDMA has seven write registers named WR0-WR6 that control the device. Each register WR0-WR6 can have zero or more parameters associated with it.&lt;br /&gt;
&lt;br /&gt;
In a first write to the zxnDMA port, the write value is compared against a bitmask to determine which of the WR0-WR6 is the target. Remaining bits in the written value can contain data as well as a list of associated parameter bits. The parameter bits determine if further writes are expected to deliver parameter values. If there are multiple parameter bits set, the expected order of parameter values written is determined by parameter bit position from right to left (bit 0 through bit 7). Once all parameters are written, the zxnDMA again expects a regular register write selecting WR0-WR6.&lt;br /&gt;
&lt;br /&gt;
The table below describes the registers and the bitmask required to select them on the zxnDMA.&lt;br /&gt;
&lt;br /&gt;
{| &lt;br /&gt;
! Register Group&lt;br /&gt;
! Register Function Description&lt;br /&gt;
! Bitmask&lt;br /&gt;
! Notes&lt;br /&gt;
|- &lt;br /&gt;
| WR0&lt;br /&gt;
| Direction, Operation and Port A configuration&lt;br /&gt;
| &amp;lt;pre&amp;gt;0XXXXXAA&amp;lt;/pre&amp;gt;&lt;br /&gt;
| AA must NOT be 00&lt;br /&gt;
|- &lt;br /&gt;
| WR1&lt;br /&gt;
| Port A configuration&lt;br /&gt;
| &amp;lt;pre&amp;gt;0XXXX100&amp;lt;/pre&amp;gt;&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| WR2&lt;br /&gt;
| Port B configuration&lt;br /&gt;
| &amp;lt;pre&amp;gt;0XXXX000&amp;lt;/pre&amp;gt;&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| WR3&lt;br /&gt;
| Activation&lt;br /&gt;
| &amp;lt;pre&amp;gt;1XXXXX00&amp;lt;/pre&amp;gt;&lt;br /&gt;
| It’s best to use WR6&lt;br /&gt;
|- &lt;br /&gt;
| WR4&lt;br /&gt;
| Port B, Timing and Interrupt configuration&lt;br /&gt;
| &amp;lt;pre&amp;gt;1XXXXX01&amp;lt;/pre&amp;gt;&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| WR5&lt;br /&gt;
| Ready and Stop configuration&lt;br /&gt;
| &amp;lt;pre&amp;gt;10XXX010&amp;lt;/pre&amp;gt;&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| WR6&lt;br /&gt;
| Command Register&lt;br /&gt;
| &amp;lt;pre&amp;gt;1XXXXX11&amp;lt;/pre&amp;gt;&lt;br /&gt;
| &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== zxnDMA Registers ==&lt;br /&gt;
These are described below following the same convention used by Zilog for its DMA chip:&lt;br /&gt;
&lt;br /&gt;
=== WR0 – Write Register Group 0 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;D7  D6  D5  D4  D3  D2  D1  D0  BASE REGISTER BYTE&lt;br /&gt;
 0   |   |   |   |   |   |   |&lt;br /&gt;
     |   |   |   |   |   0   0  Do not use&lt;br /&gt;
     |   |   |   |   |   0   1  Transfer (Prefer this for Z80 DMA compatibility)&lt;br /&gt;
     |   |   |   |   |   1   0  Do not use (Behaves like Transfer, Search on Z80 DMA)&lt;br /&gt;
     |   |   |   |   |                       &lt;br /&gt;
     |   |   |   |   |   1   1  Do not use (Behaves like Transfer, Search/Transfer on Z80 DMA)&lt;br /&gt;
     |   |   |   |   |                      &lt;br /&gt;
     |   |   |   |   0 = Port B -&amp;amp;gt; Port A (Byte transfer direction)&lt;br /&gt;
     |   |   |   |   1 = Port A -&amp;amp;gt; Port B&lt;br /&gt;
     |   |   |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  PORT A STARTING ADDRESS (LOW BYTE)&lt;br /&gt;
     |   |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  PORT A STARTING ADDRESS (HIGH BYTE)&lt;br /&gt;
     |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  BLOCK LENGTH (LOW BYTE)&lt;br /&gt;
     V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  BLOCK LENGTH (HIGH BYTE)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Several registers are accessible from WR0. The first write to WR0 is to the base register byte. Bits D6:D3 are optionally set to indicate that associated registers in this group will be written next. The order the writes come in are from D3 to D6 (right to left). For example, if bits D6 and D3 are set, the next two writes will be directed to PORT A STARTING ADDRESS LOW followed by BLOCK LENGTH HIGH.&lt;br /&gt;
&lt;br /&gt;
=== WR1 – Write Register Group 1 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;D7  D6  D5  D4  D3  D2  D1  D0  BASE REGISTER BYTE&lt;br /&gt;
 0   |   |   |   |   1   0   0&lt;br /&gt;
     |   |   |   |&lt;br /&gt;
     |   |   |   0 = Port A is memory&lt;br /&gt;
     |   |   |   1 = Port A is IO&lt;br /&gt;
     |   |   |&lt;br /&gt;
     |   0   0 = Port A address decrements&lt;br /&gt;
     |   0   1 = Port A address increments&lt;br /&gt;
     |   1   0 = Port A address is fixed&lt;br /&gt;
     |   1   1 = Port A address is fixed&lt;br /&gt;
     |&lt;br /&gt;
     V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  PORT A VARIABLE TIMING BYTE&lt;br /&gt;
 0   0   0   0   0   0   |   |&lt;br /&gt;
                         0   0 = Cycle Length = 4&lt;br /&gt;
                         0   1 = Cycle Length = 3&lt;br /&gt;
                         1   0 = Cycle Length = 2&lt;br /&gt;
                         1   1 = Do not use&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The cycle length is the number of cycles used in a read or write operation. The first cycle asserts signals and the last cycle releases them. There is no half cycle timing for the control signals.&lt;br /&gt;
&lt;br /&gt;
=== WR2 – Write Register Group 2 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;D7  D6  D5  D4  D3  D2  D1  D0  BASE REGISTER BYTE&lt;br /&gt;
 0   |   |   |   |   0   0   0&lt;br /&gt;
     |   |   |   |&lt;br /&gt;
     |   |   |   0 = Port B is memory&lt;br /&gt;
     |   |   |   1 = Port B is IO&lt;br /&gt;
     |   |   |&lt;br /&gt;
     |   0   0 = Port B address decrements&lt;br /&gt;
     |   0   1 = Port B address increments&lt;br /&gt;
     |   1   0 = Port B address is fixed&lt;br /&gt;
     |   1   1 = Port B address is fixed&lt;br /&gt;
     |&lt;br /&gt;
     V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  PORT B VARIABLE TIMING BYTE&lt;br /&gt;
 0   0   |   0   0   0   |   |&lt;br /&gt;
         |               0   0 = Cycle Length = 4&lt;br /&gt;
         |               0   1 = Cycle Length = 3&lt;br /&gt;
         |               1   0 = Cycle Length = 2&lt;br /&gt;
         |               1   1 = Do not use&lt;br /&gt;
         |&lt;br /&gt;
         V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  ZXN PRESCALAR (FIXED TIME TRANSFER)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The ZXN PRESCALAR is a feature of the zxnDMA implementation. If non-zero, a delay will be inserted after each byte is transferred such that the total time needed for each transfer is determined by the prescalar. This works in both the continuous mode and the burst mode. If the DMA is operated in burst mode, the DMA will give up any waiting time to the CPU so that the CPU can run while the DMA is idle.&lt;br /&gt;
&lt;br /&gt;
The rate of transfer is given by the formula “Frate = 875kHz / prescalar” or, rearranged, “prescalar = 875kHz / Frate”. The formula is framed in terms of a sample rate (Frate) but Frate can be inverted to set a transfer time for each byte instead. The 875kHz constant is a nominal value assuming a 28MHz system clock; the system clock actually varies from this depending on the video timing selected by the user (HDMI, VGA0-6) so for complete accuracy the constant should be prorated according to documentation for nextreg 0x11.&lt;br /&gt;
&lt;br /&gt;
In a DMA audio setting, selecting a sample rate of 16kHz would mean setting the prescalar value to 55. This sample period is constant across changes in CPU speed.&lt;br /&gt;
&lt;br /&gt;
=== WR3 – Write Register Group 3 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;D7  D6  D5  D4  D3  D2  D1  D0  BASE REGISTER BYTE&lt;br /&gt;
 1   |   0   0   0   0   0   0&lt;br /&gt;
     |&lt;br /&gt;
     1 = DMA Enable&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The Z80 DMA defines more fields but they are ignored by the zxnDMA. The two other registers defined by the Z80 DMA in this group on D4 and D3 are implemented by the zxnDMA but they do nothing.&lt;br /&gt;
&lt;br /&gt;
It is preferred to start the DMA by writing an &#039;Enable DMA&#039; command to WR6.&lt;br /&gt;
&lt;br /&gt;
=== WR4 – Write Register Group 4 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;D7  D6  D5  D4  D3  D2  D1  D0  BASE REGISTER BYTE&lt;br /&gt;
 1   |   |   0   |   |   0   1&lt;br /&gt;
     |   |       |   |&lt;br /&gt;
     0   0 = Do not use (Behaves like Continuous mode, Byte mode on Z80 DMA)&lt;br /&gt;
     0   1 = Continuous mode&lt;br /&gt;
     1   0 = Burst mode&lt;br /&gt;
     1   1 = Do not use&lt;br /&gt;
                 |   |&lt;br /&gt;
                 |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  PORT B STARTING ADDRESS (LOW BYTE)&lt;br /&gt;
                 |&lt;br /&gt;
                 V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  PORT B STARTING ADDRESS (HIGH BYTE)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The Z80 DMA defines three more registers in this group through D4 that define interrupt behaviour. Interrups and pulse generation are not implemented in the zxnDMA nor are these registers available for writing.&lt;br /&gt;
&lt;br /&gt;
=== WR5 – Write Register Group 5 ===&lt;br /&gt;
&amp;lt;pre&amp;gt;D7  D6  D5  D4  D3  D2  D1  D0  BASE REGISTER BYTE&lt;br /&gt;
 1   0   |   |   0   0   1   0&lt;br /&gt;
         |   |&lt;br /&gt;
         |   0 = /ce only&lt;br /&gt;
         |   1 = /ce &amp;amp; /wait multiplexed&lt;br /&gt;
         |&lt;br /&gt;
         0 = Stop on end of block&lt;br /&gt;
         1 = Auto restart on end of block&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The /ce &amp;amp; /wait mode is implemented in the zxnDMA but is not currently used. This mode has an external device using the DMA&#039;s /ce pin to insert wait states during the DMA&#039;s transfer.&lt;br /&gt;
&lt;br /&gt;
The auto restart feature causes the DMA to automatically reload its source and destination addresses and reset its byte counter to zero to repeat the last transfer when a previous one is finished.&lt;br /&gt;
&lt;br /&gt;
=== WR6 – Command Register ===&lt;br /&gt;
&amp;lt;pre&amp;gt;D7  D6  D5  D4  D3  D2  D1  D0  BASE REGISTER BYTE&lt;br /&gt;
 1   ?   ?   ?   ?   ?   1   1&lt;br /&gt;
     |   |   |   |   |&lt;br /&gt;
     1   0   0   0   0 = 0xC3 = Reset&lt;br /&gt;
     1   0   0   0   1 = 0xC7 = Reset Port A Timing&lt;br /&gt;
     1   0   0   1   0 = 0xCB = Reset Port B Timing&lt;br /&gt;
     0   1   1   0   0 = 0xB3 = Force Ready (irrelevant for zxnDMA)&lt;br /&gt;
     0   1   1   1   1 = 0xBF = Read Status Byte&lt;br /&gt;
     0   0   0   1   0 = 0x8B = Reinitialize Status Byte&lt;br /&gt;
     0   1   0   0   1 = 0xA7 = Initialize Read Sequence&lt;br /&gt;
     1   0   0   1   1 = 0xCF = Load&lt;br /&gt;
     1   0   1   0   0 = 0xD3 = Continue&lt;br /&gt;
     0   0   0   0   1 = 0x87 = Enable DMA&lt;br /&gt;
     0   0   0   0   0 = 0x83 = Disable DMA&lt;br /&gt;
 +-- 0   1   1   1   0 = 0xBB = Read Mask Follows&lt;br /&gt;
 |&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  READ MASK&lt;br /&gt;
 0   |   |   |   |   |   |   |&lt;br /&gt;
     |   |   |   |   |   |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  Status Byte&lt;br /&gt;
     |   |   |   |   |   |&lt;br /&gt;
     |   |   |   |   |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  Byte Counter Low (&amp;quot;High&amp;quot; with core 3.0.5 = bug in core)&lt;br /&gt;
     |   |   |   |   |&lt;br /&gt;
     |   |   |   |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  Byte Counter High (&amp;quot;Low&amp;quot; with core 3.0.5 = bug in core)&lt;br /&gt;
     |   |   |   |&lt;br /&gt;
     |   |   |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  Port A Address Low&lt;br /&gt;
     |   |   |&lt;br /&gt;
     |   |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  Port A Address High&lt;br /&gt;
     |   |&lt;br /&gt;
     |   V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  Port B Address Low&lt;br /&gt;
     |&lt;br /&gt;
     V&lt;br /&gt;
D7  D6  D5  D4  D3  D2  D1  D0  Port B Address High&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Unimplemented Z80 DMA commands are ignored.&lt;br /&gt;
&lt;br /&gt;
Prior to starting the DMA transfer, a LOAD command must be issued to copy the Port A and Port B addresses into the DMA&#039;s internal pointers. Then an &#039;Enable DMA&#039; command is issued to start the DMA. The last LOAD command before ENABLE must be done with correct transfer direction set.&lt;br /&gt;
&lt;br /&gt;
The &#039;Continue&#039; command resets the DMA&#039;s byte counter so that a following &#039;Enable DMA&#039; allows the DMA to repeat the last transfer but using the current internal address pointers. I.e. it continues from where the last copy operation left off.&lt;br /&gt;
&lt;br /&gt;
Reset and Reset Port A/B Timing commands on zxnDMA do reset also prescalar value.&lt;br /&gt;
&lt;br /&gt;
Registers can be read via an IO read from the DMA port after setting the read mask. (At power up the read mask is set to 0x7f). Register values are the current internal DMA counter values. So &#039;Port Address A Low&#039; is the lower 8-bits of Port A’s next transfer address. Once the end of the read mask is reached, further reads loop around to the first one.&lt;br /&gt;
&lt;br /&gt;
The format of the DMA status byte is as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;00E1101T&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
E is set to 0 if the total block length has been transferred at least once.&lt;br /&gt;
&lt;br /&gt;
T is set to 1 if at least one byte has been transferred.&lt;br /&gt;
&lt;br /&gt;
== Operating speed ==&lt;br /&gt;
The zxnDMA operates at the same speed as the CPU, that is 3.5MHz, 7MHz, 14MHz or 28Mhz. This is a contended clock that is modified by the ULA and the auto-slowdown by [[Layer 2|Layer2]] (which only occurred in Next core&#039;s 1 and 2, the limitation was lifted in core 3.0).&lt;br /&gt;
&lt;br /&gt;
The (pre-core 3.0) auto-slowdown occurs without user intervention if speed exceeds 7Mhz and the active Layer2 display is being generated (higher speed operation resumes when the active Layer2 display is not generated). Programmers do NOT need to account for speed differences regarding DMA transfers as this happens automatically.&lt;br /&gt;
&lt;br /&gt;
Because of this, the cycle lengths for Ports A and B can be set to their minimum values without ill effects. The cycle lengths specified for Ports A and B are intended to selectively slow down read or write cycles for hardware that cannot operate at the DMA&#039;s full speed.&lt;br /&gt;
&lt;br /&gt;
== The DMA and Interrupts ==&lt;br /&gt;
The zxnDMA cannot currently generate [[Interrupts|interrupts]].&lt;br /&gt;
&lt;br /&gt;
The other side of this is that while the DMA controls the bus, the Z80 cannot respond to interrupts. On the Z80, the NMI interrupt is edge triggered so if an NMI occurs the fact that it occurred is stored internally in the Z80 so that it will respond when it is woken up. On the other hand, maskable interrupts are level triggered. That is, the Z80 must be active to regularly sample the /INT line to determine if a maskable interrupt is occurring. On the Spectrum and the ZX Next, the ULA (and line interrupt) are only asserted for a fixed amount of time ~30 cycles at 3.5MHz. If the DMA is executing a transfer while the interrupt is asserted, the CPU will not be able to see this and it will most likely miss the interrupt. In burst mode, with large-enough prescalar value, the CPU will never miss these interrupts, although this may change if multiple channels are implemented.&lt;br /&gt;
&lt;br /&gt;
== Programming examples ==&lt;br /&gt;
A simple way to program the DMA is to walk down the list of registers WR0-WR5, sending desired settings to each. Then start the DMA by sending a LOAD command followed by an ENABLE_DMA command to WR6. Once more familiar with the DMA, you will discover that the amount of information sent can be reduced to what changes between transfers.&lt;br /&gt;
&lt;br /&gt;
=== Assembly ===&lt;br /&gt;
Short example program to DMA memory to the screen, then DMA a sprite image from memory to sprite RAM, and then showing said sprite scrolling across the screen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;;------------------------------------------------------------------------------&lt;br /&gt;
    ; sjasmplus extra options to enable Z80N, stricter syntax and Next device&lt;br /&gt;
    opt --zxnext --syntax=abf : device zxspectrumnext&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
;     DEFINE testing        ; uncomment to produce NEX file (instead of DOT)&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; DMA (Register 6)&lt;br /&gt;
;&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
;zxnDMA programming example&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
;(c) Jim Bagley&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
DMA_RESET                      equ $c3&lt;br /&gt;
DMA_RESET_PORT_A_TIMING        equ $c7&lt;br /&gt;
DMA_RESET_PORT_B_TIMING        equ $cb&lt;br /&gt;
DMA_LOAD                       equ $cf ; %11001111&lt;br /&gt;
DMA_CONTINUE                   equ $d3&lt;br /&gt;
DMA_DISABLE_INTERUPTS          equ $af&lt;br /&gt;
DMA_ENABLE_INTERUPTS           equ $ab&lt;br /&gt;
DMA_RESET_DISABLE_INTERUPTS    equ $a3&lt;br /&gt;
DMA_ENABLE_AFTER_RETI          equ $b7&lt;br /&gt;
DMA_READ_STATUS_BYTE           equ $bf&lt;br /&gt;
DMA_REINIT_STATUS_BYTE         equ $8b&lt;br /&gt;
DMA_START_READ_SEQUENCE        equ $a7&lt;br /&gt;
DMA_FORCE_READY                equ $b3&lt;br /&gt;
DMA_DISABLE                    equ $83&lt;br /&gt;
DMA_ENABLE                     equ $87&lt;br /&gt;
DMA_WRITE_REGISTER_COMMAND     equ $bb&lt;br /&gt;
DMA_BURST                      equ %11001101&lt;br /&gt;
DMA_CONTINUOUS                 equ %10101101&lt;br /&gt;
ZXN_DMA_PORT                   equ $6b&lt;br /&gt;
SPRITE_STATUS_SLOT_SELECT      equ $303B&lt;br /&gt;
SPRITE_IMAGE_PORT              equ $5b&lt;br /&gt;
SPRITE_INFO_PORT               equ $57&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
    IFDEF testing&lt;br /&gt;
        org $5800&lt;br /&gt;
        block 32*24, $38              ; default ULA attributes&lt;br /&gt;
        org $6000&lt;br /&gt;
    ELSE&lt;br /&gt;
        org $2000&lt;br /&gt;
    ENDIF&lt;br /&gt;
&lt;br /&gt;
start&lt;br /&gt;
    ld   hl,$0000&lt;br /&gt;
    ld   de,$4000&lt;br /&gt;
    ld   bc,$800&lt;br /&gt;
    call TransferDMA                  ; copy some random data to the screen pointing&lt;br /&gt;
                                      ; to ROM for now, for the purpose of showing &lt;br /&gt;
                                      ; how to do a DMA copy.&lt;br /&gt;
    ld   a,0                          ; sprite image number we want to update&lt;br /&gt;
    ld   bc,SPRITE_STATUS_SLOT_SELECT&lt;br /&gt;
    out  (c),a                        ; set the sprite image number&lt;br /&gt;
    ld   bc,1*256                     ; number to transfer (1)&lt;br /&gt;
    ld   hl,testsprite                ; from &lt;br /&gt;
    call TransferDMASprite            ; transfer to sprite ram&lt;br /&gt;
&lt;br /&gt;
    nextreg 21,1                      ; turn sprite on. for more info on this check &lt;br /&gt;
                                      ; out https://www.specnext.com/tbblue-io-port-system/&lt;br /&gt;
    ld   de,0&lt;br /&gt;
    ld   (xpos),de                    ; set initial X position ( doesn&#039;t need it for&lt;br /&gt;
                                      ; this demo, but if you run the .loop again it&lt;br /&gt;
                                      ; will continue from where it was&lt;br /&gt;
    ld   a,$20&lt;br /&gt;
    ld   (ypos),a                     ; set initial Y position&lt;br /&gt;
&lt;br /&gt;
.loop&lt;br /&gt;
    ld   a,0                          ; sprite number we want to position&lt;br /&gt;
    ld   bc,SPRITE_STATUS_SLOT_SELECT&lt;br /&gt;
    out  (c),a&lt;br /&gt;
    ld   de,(xpos)&lt;br /&gt;
    ld   hl,(ypos)                    ; ignores H so doing this rather than &lt;br /&gt;
                                      ; ld a,(ypos):ld l,a&lt;br /&gt;
    ld   bc,(image)                   ; not flipped or palette shifted&lt;br /&gt;
    call SetSprite&lt;br /&gt;
&lt;br /&gt;
    halt&lt;br /&gt;
&lt;br /&gt;
    ld   de,(xpos)&lt;br /&gt;
    inc  de&lt;br /&gt;
    ld   (xpos),de&lt;br /&gt;
    ld   a,d&lt;br /&gt;
    cp   $01&lt;br /&gt;
    jr   nz,.loop                     ; if high byte of xpos is not 1 (right of &lt;br /&gt;
                                      ; screen )&lt;br /&gt;
    ld   a,e&lt;br /&gt;
    cp   $20+1&lt;br /&gt;
    jr   nz,.loop                     ; if low byte is not $21 just off the right of&lt;br /&gt;
                                      ; the screen, $20 is off screen but as the &lt;br /&gt;
                                      ; INC DE is just above and not updated sprite&lt;br /&gt;
                                      ; after it, it needs to be $21&lt;br /&gt;
    xor  a&lt;br /&gt;
    ret                               ; return back to basic with OK&lt;br /&gt;
&lt;br /&gt;
xpos dw 0                             ; x position&lt;br /&gt;
ypos db 0                             ; y position&lt;br /&gt;
                                      ; these next two BITS and IMAGE are swapped &lt;br /&gt;
                                      ; as bits needs to go into B register&lt;br /&gt;
image db 0+$80                        ; use image 0 (for the image we transfered)&lt;br /&gt;
                                      ; +$80 to set the sprite to active&lt;br /&gt;
bits db 0                             ; not flipped or palette shifted&lt;br /&gt;
&lt;br /&gt;
c1 = %11100000&lt;br /&gt;
c2 = %11000000&lt;br /&gt;
c3 = %10100000&lt;br /&gt;
c4 = %10000000&lt;br /&gt;
c5 = %01100000&lt;br /&gt;
c6 = %01000000&lt;br /&gt;
c7 = %00100000&lt;br /&gt;
c8 = %00000000&lt;br /&gt;
&lt;br /&gt;
testsprite&lt;br /&gt;
    db c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1&lt;br /&gt;
    db c1,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c1&lt;br /&gt;
    db c1,c2,c3,c3,c3,c3,c3,c3,c3,c3,c3,c3,c3,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c4,c4,c4,c4,c4,c4,c4,c4,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c5,c5,c5,c5,c5,c5,c5,c5,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c5,c6,c6,c6,c6,c6,c6,c5,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c5,c6,c7,c7,c7,c7,c6,c5,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c5,c6,c7,c8,c8,c7,c6,c5,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c5,c6,c7,c8,c8,c7,c6,c5,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c5,c6,c7,c7,c7,c7,c6,c5,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c5,c6,c6,c6,c6,c6,c6,c5,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c5,c5,c5,c5,c5,c5,c5,c5,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c4,c4,c4,c4,c4,c4,c4,c4,c4,c4,c3,c2,c1&lt;br /&gt;
    db c1,c2,c3,c3,c3,c3,c3,c3,c3,c3,c3,c3,c3,c3,c2,c1&lt;br /&gt;
    db c1,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c1&lt;br /&gt;
    db c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1&lt;br /&gt;
&lt;br /&gt;
;-------------------------------------------------&lt;br /&gt;
; de = X&lt;br /&gt;
; l = Y&lt;br /&gt;
; b = bits&lt;br /&gt;
; c = sprite image&lt;br /&gt;
SetSprite&lt;br /&gt;
    push bc&lt;br /&gt;
    ld bc,SPRITE_INFO_PORT&lt;br /&gt;
    out (c),e ; Xpos&lt;br /&gt;
    out (c),l ; Ypos&lt;br /&gt;
    pop hl&lt;br /&gt;
    ld a,d&lt;br /&gt;
    and 1&lt;br /&gt;
    or h&lt;br /&gt;
    out (c),a&lt;br /&gt;
    ld a,l:or $80&lt;br /&gt;
    out (c),a ; image&lt;br /&gt;
    ret&lt;br /&gt;
&lt;br /&gt;
;--------------------------------&lt;br /&gt;
; hl = source&lt;br /&gt;
; de = destination&lt;br /&gt;
; bc = length&lt;br /&gt;
;--------------------------------&lt;br /&gt;
TransferDMA&lt;br /&gt;
    di&lt;br /&gt;
    ld (DMASource),hl&lt;br /&gt;
    ld (DMADest),de&lt;br /&gt;
    ld (DMALength),bc&lt;br /&gt;
    ld hl,DMACode&lt;br /&gt;
    ld b,DMACode_Len&lt;br /&gt;
    ld c,ZXN_DMA_PORT&lt;br /&gt;
    otir&lt;br /&gt;
    ei&lt;br /&gt;
    ret&lt;br /&gt;
&lt;br /&gt;
DMACode db DMA_DISABLE&lt;br /&gt;
        db %01111101                  ; R0-Transfer mode, A -&amp;gt; B, write adress &lt;br /&gt;
                                      ; + block length&lt;br /&gt;
DMASource dw 0                        ; R0-Port A, Start address &lt;br /&gt;
                                      ; (source address)&lt;br /&gt;
DMALength dw 0                        ; R0-Block length (length in bytes)&lt;br /&gt;
        db %01010100                  ; R1-write A time byte, increment, to &lt;br /&gt;
                                      ; memory, bitmask&lt;br /&gt;
        db %00000010                  ; 2t&lt;br /&gt;
        db %01010000                  ; R2-write B time byte, increment, to &lt;br /&gt;
                                      ; memory, bitmask&lt;br /&gt;
        db %00000010                  ; R2-Cycle length port B&lt;br /&gt;
        db DMA_CONTINUOUS             ; R4-Continuous mode (use this for block &lt;br /&gt;
                                      ; transfer), write dest adress&lt;br /&gt;
DMADest dw 0                          ; R4-Dest address (destination address)&lt;br /&gt;
        db %10000010                  ; R5-Restart on end of block, RDY active &lt;br /&gt;
                                      ; LOW&lt;br /&gt;
        db DMA_LOAD                   ; R6-Load&lt;br /&gt;
        db DMA_ENABLE                 ; R6-Enable DMA&lt;br /&gt;
        &lt;br /&gt;
DMACode_Len                    equ $-DMACode&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; hl = source&lt;br /&gt;
; bc = length&lt;br /&gt;
; set port to write to with TBBLUE_REGISTER_SELECT&lt;br /&gt;
; prior to call&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
TransferDMAPort&lt;br /&gt;
    di&lt;br /&gt;
    ld (DMASourceP),hl&lt;br /&gt;
    ld (DMALengthP),bc&lt;br /&gt;
    ld hl,DMACodeP&lt;br /&gt;
    ld b,DMACode_LenP&lt;br /&gt;
    ld c,ZXN_DMA_PORT&lt;br /&gt;
    otir&lt;br /&gt;
    ei&lt;br /&gt;
    ret&lt;br /&gt;
&lt;br /&gt;
DMACodeP db DMA_DISABLE&lt;br /&gt;
        db %01111101                  ; R0-Transfer mode, A -&amp;gt; B, write adress &lt;br /&gt;
                                      ; + block length&lt;br /&gt;
DMASourceP dw 0                       ; R0-Port A, Start address (source address)&lt;br /&gt;
DMALengthP dw 0                       ; R0-Block length (length in bytes)&lt;br /&gt;
        db %01010100                  ; R1-read A time byte, increment, to &lt;br /&gt;
                                      ; memory, bitmask&lt;br /&gt;
        db %00000010                  ; R1-Cycle length port A&lt;br /&gt;
        db %01101000                  ; R2-write B time byte, increment, to &lt;br /&gt;
                                      ; memory, bitmask&lt;br /&gt;
        db %00000010                  ; R2-Cycle length port B&lt;br /&gt;
        db %10101101                  ; R4-Continuous mode (use this for block &lt;br /&gt;
                                      ; transfer), write dest adress&lt;br /&gt;
        dw $253b                      ; R4-Dest address (destination address)&lt;br /&gt;
        db %10000010                  ; R5-Restart on end of block, RDY active&lt;br /&gt;
                                      ; LOW&lt;br /&gt;
        db DMA_LOAD                   ; R6-Load&lt;br /&gt;
        db DMA_ENABLE                 ; R6-Enable DMA&lt;br /&gt;
        &lt;br /&gt;
DMACode_LenP                   equ $-DMACodeP&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; hl = source&lt;br /&gt;
; bc = length&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
TransferDMASprite&lt;br /&gt;
    di&lt;br /&gt;
    ld (DMASourceS),hl&lt;br /&gt;
    ld (DMALengthS),bc&lt;br /&gt;
    ld hl,DMACodeS&lt;br /&gt;
    ld b,DMACode_LenS&lt;br /&gt;
    ld c,ZXN_DMA_PORT&lt;br /&gt;
    otir&lt;br /&gt;
    ei&lt;br /&gt;
    ret&lt;br /&gt;
&lt;br /&gt;
DMACodeS db DMA_DISABLE&lt;br /&gt;
        db %01111101                   ; R0-Transfer mode, A -&amp;gt; B, write adress &lt;br /&gt;
                                       ; + block length&lt;br /&gt;
DMASourceS dw 0                        ; R0-Port A, Start address (source address)&lt;br /&gt;
DMALengthS dw 0                        ; R0-Block length (length in bytes)&lt;br /&gt;
        db %01010100                   ; R1-read A time byte, increment, to &lt;br /&gt;
                                       ; memory, bitmask&lt;br /&gt;
        db %00000010                   ; R1-Cycle length port A&lt;br /&gt;
        db %01101000                   ; R2-write B time byte, increment, to &lt;br /&gt;
                                       ; memory, bitmask&lt;br /&gt;
        db %00000010                   ; R2-Cycle length port B&lt;br /&gt;
        db %10101101                   ; R4-Continuous mode (use this for block&lt;br /&gt;
                                       ; transfer), write dest adress&lt;br /&gt;
        dw SPRITE_IMAGE_PORT           ; R4-Dest address (destination address)&lt;br /&gt;
        db %10000010                   ; R5-Restart on end of block, RDY active&lt;br /&gt;
                                       ; LOW&lt;br /&gt;
        db DMA_LOAD                    ; R6-Load&lt;br /&gt;
        db DMA_ENABLE                  ; R6-Enable DMA&lt;br /&gt;
DMACode_LenS                   equ $-DMACodeS&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; de = dest, a = fill value, bc = lenth&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
DMAFill&lt;br /&gt;
    di&lt;br /&gt;
    ld (FillValue),a&lt;br /&gt;
    ld (DMACDest),de&lt;br /&gt;
    ld (DMACLength),bc&lt;br /&gt;
    ld hl,DMACCode&lt;br /&gt;
    ld b,DMACCode_Len&lt;br /&gt;
    ld c,ZXN_DMA_PORT&lt;br /&gt;
    otir&lt;br /&gt;
    ei&lt;br /&gt;
    ret&lt;br /&gt;
&lt;br /&gt;
FillValue db 22&lt;br /&gt;
DMACCode db DMA_DISABLE&lt;br /&gt;
        db %01111101&lt;br /&gt;
DMACSource dw FillValue&lt;br /&gt;
DMACLength dw 0&lt;br /&gt;
        db %00100100,%00010000,%10101101&lt;br /&gt;
DMACDest dw 0&lt;br /&gt;
        db DMA_LOAD,DMA_ENABLE&lt;br /&gt;
DMACCode_Len equ $-DMACCode&lt;br /&gt;
&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
; End of file&lt;br /&gt;
;------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
    IFDEF testing&lt;br /&gt;
        savenex open &amp;quot;DMAtest.nex&amp;quot;, start, $FF00&lt;br /&gt;
        savenex bank 5&lt;br /&gt;
    ELSE&lt;br /&gt;
fin&lt;br /&gt;
        savebin &amp;quot;DMATEST&amp;quot;,start,fin-start&lt;br /&gt;
    ENDIF&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Based on original text by: Allen Albright &amp;amp; Mike Dailly with input by Jim Bagley, Lyndon J Sharp and Phoebus R. Dokos&lt;br /&gt;
&lt;br /&gt;
== Technical details (core 3.1.3+)  ==&lt;br /&gt;
&lt;br /&gt;
The Zilog/zxnDMA mode is now selected by using the particular I/O port number ({{PortNo|$xx6B}} for zxnDMA mode, {{PortNo|$xx0B}} for Zilog mode). The bit 6 in {{NextRegNo|$06}} is not DMA related any more and will be reused for something different.&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;counter&amp;quot; RR1-RR2 read back after transfer has correct byte order since core 3.1.4.&lt;br /&gt;
&lt;br /&gt;
Other differences described below in &amp;quot;3.0.5&amp;quot; remains (but from practical point of view the Zilog DMA emulation in 3.1.4 is near-perfect, all the remaining differences are very minor).&lt;br /&gt;
&lt;br /&gt;
== Technical details (core 3.0.5)  ==&lt;br /&gt;
&lt;br /&gt;
=== Zilog DMA compatibility mode ===&lt;br /&gt;
In Zilog DMA compatibility mode (bit 6 of {{NextRegNo|$06}}) the zxnDMA will mostly work as expected, but there are few differences in behaviour which may eventually throw off some rare SW, here is the list of the known differences (most of them describe also how the zxnDMA mode works):&lt;br /&gt;
&lt;br /&gt;
The LOAD command must be issued with correct transfer direction, loading addresses in opposite direction and flipping direction afterward will mismatch the source/destination address data (Zilog/UA858D DMA chips are also sensitive to direction flip after LOAD, but the resulting transfer quirks in different way, reading source data byte after write, offsetting whole transfer by one and damaging start/end of sequence).&lt;br /&gt;
(does apply also to zxnDMA mode)&lt;br /&gt;
&lt;br /&gt;
The LOAD command will NOT destroy the already issued &amp;quot;Initialize Read Sequence&amp;quot; - this is how even the original Zilog documentation describes the DMA chip operation, but the real Zilog DMA and UA858D (clone chip) both destroy read sequence upon LOAD command (zxnDMA is better).&lt;br /&gt;
(does apply also to zxnDMA mode)&lt;br /&gt;
&lt;br /&gt;
The content of registers read back after finished transfer differs: the counter has swapped LSB with MSB byte, and both addresses will be adjusted length+1 times (Zilog/UA858D will return destination address adjusted only length-many times).&lt;br /&gt;
(does apply also to zxnDMA mode, except addresses are adjusted only &amp;quot;length&amp;quot; times of course, counter has still swapped bytes)&lt;br /&gt;
&lt;br /&gt;
Any read of zxnDMA port without pending read request (commands &amp;quot;Read Status Byte&amp;quot; or &amp;quot;Initialize Read Sequence&amp;quot;) will return status byte (Zilog will return random value vaguely similar to status byte, but incorrect, UA858D will return zero).&lt;br /&gt;
(does apply also to zxnDMA mode)&lt;br /&gt;
&lt;br /&gt;
Status byte doesn&#039;t have bit 0 set (the &amp;quot;T&amp;quot; bit in description above).&lt;br /&gt;
(does apply also to zxnDMA mode)&lt;br /&gt;
&lt;br /&gt;
Be aware that both custom timing cycles count, and prescalar values are preserved in zxnDMA even when future write to WR1/WR2 does skip these particular bytes. To reset prescalar or cycles timing, write explicitly zero into prescalar register or use commands reset/reset-port-timing.&lt;br /&gt;
(does apply also to zxnDMA mode, the prescalar works only in zxnDMA mode)&lt;br /&gt;
&lt;br /&gt;
The destination port address is LOAD-ed even when it is &amp;quot;fixed&amp;quot; type (Contrary to Zilog DMA, which requires you to load such port as &amp;quot;source&amp;quot;, flip the direction after and re-LOAD again with correct direction. UA858D chip does also load destination port address in any case, just like zxnDMA).&lt;br /&gt;
(does apply also to zxnDMA mode)&lt;br /&gt;
&lt;br /&gt;
=== zxnDMA mode vs Zilog mode ===&lt;br /&gt;
&lt;br /&gt;
In zxnDMA mode length of transfer is equal to the length written to WR0 register, port addresses are adjusted also only length-times.&lt;br /&gt;
&lt;br /&gt;
Prescalar value will affect speed of transfer (use zero to switch prescalar off) (in burst mode during the extra idle time the CPU receives control back and can execute further instructions, in continuous mode the transfer will keep blocking CPU even when &amp;quot;slow&amp;quot; transfer is being done).&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=MAME:Plugins_and_Scripts&amp;diff=41434</id>
		<title>MAME:Plugins and Scripts</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=MAME:Plugins_and_Scripts&amp;diff=41434"/>
		<updated>2025-11-29T08:42:41Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: adding first version of usage notes (TODO verify and cross-link with installation notes / mame.ini lore)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;To load a plugin/script you can use options -plugin and -script on command line, example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mame -plugin skipstartupframes -script profiler&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Or you can select them from the MAME UI (make sure the files are in corresponding plugins/ and scripts/ folders).&lt;br /&gt;
&lt;br /&gt;
These MAME plugins and scripts may be of interest to Next developers and end-users:&lt;br /&gt;
&lt;br /&gt;
=Plugins=&lt;br /&gt;
&lt;br /&gt;
== [https://github.com/Threetwosevensixseven/MAMENextPlugins nextfaststart] ==&lt;br /&gt;
Minimizes MAME Next Machine boot time, by allowing code running inside the emulator to control MAME execution speed. Useful for developers.&lt;br /&gt;
Release: [https://github.com/Threetwosevensixseven/MAMENextPlugins/releases/latest Yes]&lt;br /&gt;
Source: [https://github.com/Threetwosevensixseven/MAMENextPlugins/blob/main/src/plugins/nextfaststart/init.lua Yes]&lt;br /&gt;
&lt;br /&gt;
== [https://github.com/Jakobud/skipstartupframes skipstartupframes ] ==&lt;br /&gt;
Another plugin to speedup MAME boot time, by specifying a number of frames to run at full speed for each machine being emulated. More general, and useful for end-users or developers.&lt;br /&gt;
Release: [https://github.com/Jakobud/skipstartupframes/releases/tag/v3.0.0 Yes]&lt;br /&gt;
Source: [https://github.com/Jakobud/skipstartupframes/tree/main/src Yes]&lt;br /&gt;
&lt;br /&gt;
== [https://github.com/Threetwosevensixseven/MAMENextPlugins debugstart] ==&lt;br /&gt;
Allows to use the MAME debugger later, without compromising startup speed or needing keys to be pressed to continue at startup.&lt;br /&gt;
Release: [https://github.com/Threetwosevensixseven/MAMENextPlugins/releases/latest Yes]&lt;br /&gt;
Source: [https://github.com/Threetwosevensixseven/MAMENextPlugins/blob/main/src/plugins/debugstart/init.lua Yes]&lt;br /&gt;
&lt;br /&gt;
=Scripts=&lt;br /&gt;
&lt;br /&gt;
== [https://github.com/taylorza/MAMEScripts/tree/main/scripts profiler.lua] ==&lt;br /&gt;
A simple on-screen profiler (overlay) designed for the ZX Spectrum Next that tracks up to 8 timers using writes to NEXTREG 127 (0x7F) to control the timers.&lt;br /&gt;
[https://github.com/taylorza/MAMEScripts/blob/main/README.md#profilerlua Documentation]&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=MAME:Installing&amp;diff=41433</id>
		<title>MAME:Installing</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=MAME:Installing&amp;diff=41433"/>
		<updated>2025-11-29T08:34:50Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: fix plugins page name after it was renamed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[https://www.mamedev.org/ MAME] (formerly an acronym of Multiple Arcade Machine Emulator) is a free and open-source emulator designed to emulate the hardware of arcade games, later expanded to include video game consoles, old computers and other systems in software on modern personal computers and other platforms.&lt;br /&gt;
&lt;br /&gt;
MAME supports The ZX Spectrum Next since version 0.267. Existing implementation is based on v3.02.01 core and implements most of the features.&lt;br /&gt;
&lt;br /&gt;
= Get =&lt;br /&gt;
The latest MAME version for Windows is available [https://www.mamedev.org/release.html here] and macOS builds can be downloaded [https://sdlmame.lngn.net/ from here.] For the MAME platform as a whole, check your package manager or [https://docs.mamedev.org/initialsetup/compilingmame.html build from sources].&lt;br /&gt;
&lt;br /&gt;
Linux users can install the latest stable version of MAME also from the flatpak repositories by running:&lt;br /&gt;
&amp;lt;pre&amp;gt;sudo flatpak install org.mamedev.MAME&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Put the ROM dump zip of ZX Next [https://github.com/Threetwosevensixseven/NexCreator/raw/master/bootroms/tbblue.zip tbblue.zip] into MAME&#039;s &amp;lt;code&amp;gt;roms&amp;lt;/code&amp;gt; folder (don&#039;t extract it, mame will look for the zip file when &amp;quot;tbblue&amp;quot; machine is selected).&lt;br /&gt;
&lt;br /&gt;
Prepare an SD card image file of [https://www.specnext.com/system-next22-10/ NextZXOS]. Some published images do not work with some emulators, but all images from https://zxnext.uk/hosted/#sd are now confirmed to work with both MAME and CSpect, including the official ones, including [https://zxnext.uk/hosted/index_files/hdfimages/cspect-next-2gb.zip this one] (the SD card image is the &amp;lt;code&amp;gt;cspect-next-2gb.img&amp;lt;/code&amp;gt; file within the zip file). You will point mame to desired SD card image with &amp;lt;code&amp;gt;-hard1&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;-hard2&amp;lt;/code&amp;gt; options (or select the files from menu inside emulator).&lt;br /&gt;
&lt;br /&gt;
= Use =&lt;br /&gt;
MAME looks for its configuration and helper files in specific (configurable) folders. By default these are relative to current working directory (cwd), ie. from where you did launch the executable. The mame.ini and other folders like &amp;lt;code&amp;gt;roms, bgfx, plugins, language, ...&amp;lt;/code&amp;gt; are expected there, unless ini file specifies other paths. When launching through desktop icon/menu depending on the OS the working directory is often defined by that launch shortcut properties. When launching through command line the current directory is &amp;quot;cwd&amp;quot; (doh). On Linux MAME will look for mame.ini first into ~/.mame folder. You can use option &amp;lt;code&amp;gt;-inipath&amp;lt;/code&amp;gt; to search other path for ini file.&lt;br /&gt;
&lt;br /&gt;
The fastest way to run a machine with a desired configuration is from the command prompt. Most of the features are also available from MAME&#039;s UI, but that takes more time to configure.&lt;br /&gt;
Let&#039;s discover some useful options:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Use window and no mouse more till you get familiar with UI keys:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; mame tbblue -window -mouse_device none -hard1 /path/to/next-distribution.img&amp;lt;/pre&amp;gt;&lt;br /&gt;
To launch the Linux flatpak version using the same options:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; flatpak run org.mamedev.MAME tbblue -window -mouse_device none -hard1 /path/to/next-distribution.img&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Activate UI keys on startup:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -ui_active&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Don&#039;t show info popup on startup:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ...-skip_gameinfo&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;Run with debugger. If not requested on startup, you won&#039;t have access to it:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -debug&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;Use &amp;quot;crisp&amp;quot; pixels:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -nounevenstretch -aspect 2:1 -video bgfx -bgfx_screen_chains unfiltered&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;No joystick connected to PC (may slightly speed up MAME&#039;s startup):&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -joystickprovider none&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Check [https://docs.mamedev.org/commandline/commandline-all.html#mame-commandline-universal official docs] for more advanced usage.&lt;br /&gt;
&lt;br /&gt;
As an example, this invocation: enables UI, &amp;quot;crisp pixels&amp;quot;, starts in a window, doesn&#039;t display the starting gameinfo window (it can still be displayed interactively from the UI), disables the mouse and specifies the disk image is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;mame -ui_active  -nounevenstretch -aspect 2:1 -video bgfx  -bgfx_screen_chains unfiltered -window -skip_gameinfo  -mouse_device none  tbblue -hard1 /path/to/next-distribution.img&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Keys =&lt;br /&gt;
&lt;br /&gt;
Keys are emulated in two modes: to control MAME or completely dedicated to the emulated system. You can toggle between these two keyboard modes with ScrLk or Fn+delete under macOS.&lt;br /&gt;
&lt;br /&gt;
Some UI keys:&lt;br /&gt;
* F3 - soft reset&lt;br /&gt;
* Shift+F3 - hard reset&lt;br /&gt;
* F4 - sprites/tiles/font viewer (Enter, ], [)&lt;br /&gt;
* F5 - pause emulation&lt;br /&gt;
* F6 - save state&lt;br /&gt;
* F7 - load state&lt;br /&gt;
* Tab - emulator settings&lt;br /&gt;
* ~ - menu&lt;br /&gt;
* PgDwn (Linux) or Insert (Win) -- max speed (only while it&#039;s pressed; can be used e.g. to speed up boot)&lt;br /&gt;
* Esc - exit&lt;br /&gt;
* F12 - MF NMI&lt;br /&gt;
* F11 - DivMMC NMI&lt;br /&gt;
&lt;br /&gt;
= Changing the UI toggle key =&lt;br /&gt;
&lt;br /&gt;
Some laptops don&#039;t have a Scroll Lock key so you won&#039;t be able to exit MAME if you run it in full screen mode hence you will need to change the UI toggle key.&lt;br /&gt;
&lt;br /&gt;
Follow these steps to change the UI toggle key:&lt;br /&gt;
&lt;br /&gt;
* Run MAME without any command line arguments (except maybe -window) to open its GUI.&lt;br /&gt;
* Push TAB and enter the General Settings menu.&lt;br /&gt;
* Go to Input Assignments -&amp;gt; User Interface -&amp;gt; Toggle UI controls and select a new key. I use Right Alt / Alt GR.&lt;br /&gt;
* Return to Previous menu twice then choose Save Settings&lt;br /&gt;
&lt;br /&gt;
= Mounting SD card images under Linux =&lt;br /&gt;
&lt;br /&gt;
Under Linux you can use losetup to mount SD card images as loop devices which enables you to copy files to and from the image and perform other file management tasks as you would using any other filesystem.&lt;br /&gt;
&lt;br /&gt;
Run the following commands as the root user to mount an image called sn-emulator-22.10a.img under the /mnt directory:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;losetup --partscan --show --find cspect-next-2gb.img&lt;br /&gt;
mount /dev/loop0p1 /mnt/&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After you have finished modifying the SD card image, cd out of /mnt then unmount and detach the loopback device:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;umount /mnt/&lt;br /&gt;
losetup -D&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Creating a NextZXOS SD card image under Linux =&lt;br /&gt;
&lt;br /&gt;
Most users wanting to emulate the Next using MAME will be fine using a pre-built SD card image downloaded from the specnext website but the following guide is provided for anyone wanting to create a NextZXOS SD card image from scratch.&lt;br /&gt;
&lt;br /&gt;
Download the [https://www.specnext.com/latestdistro/ latest NextZXOS distribution zip file] (named something like sn-complete-WX.YZ.zip) and extract it into a new, empty directory.&lt;br /&gt;
&lt;br /&gt;
Create a disk image of at least 256 MB. The current complete NextZXOS distro requires at least 130 MB of disk space. This command will create a 256 MB SD card image, change the count value to make the image file as big as you want in megabytes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;dd if=/dev/zero of=NextZXOS.img bs=1M count=256&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The rest of the commands in this guide must be run as the root user or using sudo.&lt;br /&gt;
&lt;br /&gt;
You will need the dosfstools and parted packages, if you don&#039;t already have them installed. Debian and Ubuntu Linux users can install these using this apt command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;apt install dosfstools parted&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mount the SD card image loopback device:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;losetup --partscan --show --find NextZXOS.img&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Create a FAT32 partition:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;parted /dev/loop0 mklabel msdos&lt;br /&gt;
parted /dev/loop0 mkpart primary fat32 1MB 100%&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Format and mount the partition under /mnt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;mkfs.vfat -F 32 /dev/loop0p1&lt;br /&gt;
mount /dev/loop0p1 /mnt&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can now copy all of the files you extracted from sn-complete-WX.YZ.zip into /mnt.&lt;br /&gt;
&lt;br /&gt;
After copying the files, unmount and detach the loopback device (the SD card image):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;umount /mnt/&lt;br /&gt;
losetup -D&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=MAME Plugins and Scripts=&lt;br /&gt;
Some plugins which may be useful for MAME Next devs and end-users are listed [[MAME:Plugins_and_Scripts|here: MAME:Plugins_and_Scripts]].&lt;br /&gt;
&lt;br /&gt;
=Continuous Integration MAME Builds=&lt;br /&gt;
&lt;br /&gt;
MAME is updated on a release schedule, but due to the ongoing nature of development, including for the MAME Next machine, it can be sometimes useful to install a recent build, if it contains a new feature or bugfix you are interested in. Sometimes ongoing work is discussed on social media, like [https://discordapp.com/channels/556228195767156758/752197165891321886 Discord].&lt;br /&gt;
&lt;br /&gt;
Continuous Integration (CI) builds are available from both the [https://github.com/mamedev/mame/actions primary MAME] and [https://github.com/holub/mame/actions holub] github repos. Both are considered bleeding-edge, with the primary MAME repo slightly less so. MAME CI builds are available for Windows, linux and MacOS, and are updated automatically every time code is committed by a maintainer or pushed to the primary repo.&lt;br /&gt;
&lt;br /&gt;
To try out a CI build, do a fill MAME install from the [https://www.mamedev.org/release.html latest release] first, if you have not already done so. Then back up your main binary from its installation location - these are called something like &amp;lt;code&amp;gt;mame.exe&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;mame&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;mametiny&amp;lt;/code&amp;gt;. You can always restore these if the CI build doesn&#039;t work, or you don&#039;t like how it behaves.&lt;br /&gt;
&lt;br /&gt;
Then visit the one of the links above, and find a workflow run item for your platform - these are flagged as &amp;lt;code&amp;gt;CI (Windows)&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;CI (Linux)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;CI (macOS)&amp;lt;/code&amp;gt;. Click on it and find the Artifacts section at the bottom, then click the download button. Unzip the downloaded file and find the main binary (same name as above). Copy the main binary over the top of the original one in the install location, and run MAME the same way your were running it before. On Windows you may have to do an additional step of trusting the binary (Run Anyway).&lt;br /&gt;
&lt;br /&gt;
= More MAME links =&lt;br /&gt;
The source code is available [https://github.com/mamedev/mame/blob/master/src/mame/sinclair/specnext.cpp here], the author of Next emulation holub has fork [https://github.com/holub/mame here] (may contain new fixes and features before they are merged to official repository).&lt;br /&gt;
&lt;br /&gt;
MAME [https://docs.mamedev.org/ documentation].&lt;br /&gt;
&lt;br /&gt;
Report any issues with MAME on the [https://mametesters.org/ bugtracker].&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=Miscellaneous&amp;diff=41419</id>
		<title>Miscellaneous</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=Miscellaneous&amp;diff=41419"/>
		<updated>2025-11-27T01:25:31Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: hijacking hdfmonkey github repo to my patched fork&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== &#039;&#039;[http://simon.mooli.org.uk/nextech/ Simon N Goodwin&#039;s Spectrum Next Page]&#039;&#039; ===&lt;br /&gt;
: A host of utilites for NextBasic written by Simon, NextPort, Nextramon, &lt;br /&gt;
: Next MGT Reader amongst other treasures.&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://github.com/kounch/vscode_zx Visual Studio Code Tasks and Scripts]&#039;&#039; ===&lt;br /&gt;
: Some VSC goodies by kounch to work with NextBasic and ZX Basic&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://github.com/stefanbylund/zxnext_bmp_tools Next BMP Tools]&#039;&#039; ===&lt;br /&gt;
: The Next BMP tools are BMP image conversion tools targeting the Sinclair ZX Spectrum Next written&lt;br /&gt;
: by Stefan Bylund&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://wiki.twistedraven.net/index.php?title=Downloads Octarine Studio]&#039;&#039; ===&lt;br /&gt;
: Octarine Studio by Guy Black is a PC based editing tool that currently supports palettes and tiles. &lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://www.specnext.com/forum/viewtopic.php?f=7&amp;amp;t=351 UDGeedNext Sprite Editor]&#039;&#039; ===&lt;br /&gt;
: Windows based sprite editor written by some guy I have never heard of. Currently supports 8 bit&lt;br /&gt;
: palettes. 9 bit and 4 bit sprites should be added at some point....&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[http://worldofpaul.com/speccyart/ Speccy Art]&#039;&#039; ===&lt;br /&gt;
: An online drawing experience that aims to help you create Sinclair ZX Spectrum-like images.&lt;br /&gt;
: Supports the classic ULA mode (256x192 pixels with 8x8 attribute squares and 15 classic ZX colours)&lt;br /&gt;
: Supports the Timex HiColour mode (256x192 pixels with 8x1 attribute rectangles and 15 classic ZX colours)&lt;br /&gt;
: Images can be saved and loaded through TAP files or exported into SCR/SHC files.&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://github.com/varmfskii/zxnext_tools ZX Spectrum Next tools by Theodore (Alex) Evans]&#039;&#039; ===&lt;br /&gt;
: Multiple tools for various graphics conversions and processing&lt;br /&gt;
: zxnftp for transferring files between PC and Next via the ESP WiFi module&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://gitlab.com/zxnexttools/nim Next Image Manipulator by Matt Davies]&#039;&#039; ===&lt;br /&gt;
: windows command line tool to convert various image and palette formats to custom &amp;quot;nip/nim&amp;quot; binary formats which are simple enough to parse (or include directly into source with assemblers supporting binary includes)&lt;br /&gt;
: this is early version (already working, build it from source), but further expansion to support also tiles/etc may happen in future&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://github.com/ped7g/hdfmonkey hdfmonkey (with jjjs patch applied)]&#039;&#039; ===&lt;br /&gt;
: A Swiss Army Knife for working with FAT partitions on Spectrum emulator HDF images.&lt;br /&gt;
: The [https://www.specnext.com/forum/viewtopic.php?p=16108 jjjs builds by johnnyo] also support the [https://www.specnext.com/latestdistro/ imperfect SD card images of the distribution for emulators from specnext.com], and the forum post includes executable binaries for Windows, Linux, and macOS.&lt;br /&gt;
: Original [https://github.com/gasman/hdfmonkey gasman&#039;s version] (missing the jjjs fixes)&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://zeroonetwenty.com/blueharvest/ Blue Harvest]&#039;&#039; ===&lt;br /&gt;
: A convenient macOS tool to keep SD cards free from macOS metadata. Free 30-day trial.&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://github.com/MrKWatkins/ZXSpectrumNextTests ZXSpectrumNextTests by Kevin Watkins and Peter Helcmanovsky]&#039;&#039; ===&lt;br /&gt;
: Suite of tests exercising various aspects of ZX Spectrum Next&lt;br /&gt;
: Tests for: Next registers, Copper, Sprites, Layer2, ULA modes, Extended ULA, Layers mixing modes, Z80N instructions, ...&lt;br /&gt;
: ASM Sources for each test (sjasmplus assembler syntax)&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://github.com/Threetwosevensixseven/ZXSpectrumNextTests ZXSpectrumNextTests by Robin Verhagen-Guest]&#039;&#039; ===&lt;br /&gt;
: Suite of tests exercising various aspects of ZX Spectrum Next (yes, one more :) )&lt;br /&gt;
: Tests for: DMA, MMU paging, Layers mixing modes&lt;br /&gt;
: ASM Sources for each test (Zeus assembler syntax)&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;&amp;lt;div id=&amp;quot;WASPtools&amp;quot; name=&amp;quot;WASPtools&amp;quot;&amp;gt;WASPtools by Phoebus Dokos&amp;lt;/div&amp;gt;&#039;&#039; ===&lt;br /&gt;
WASPtools is a suite of tools comprised of a palette manipulator, a sprite editor, a graphics converter, and tilemap editor (both virtual tilemaps for say Layer2, and the hardware tilemap mode).&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://zx.remysharp.com Online sprite, palette and tilemap editor by Remy Sharp]&#039;&#039; ===&lt;br /&gt;
: Browser based tooling that works fully offline&lt;br /&gt;
: Sprite editor with import and export tools&lt;br /&gt;
: Tile map editor with 16x16 and 8x8 tile support&lt;br /&gt;
: Full 512 palette import and export&lt;br /&gt;
: Also includes image conversion tools from PNG to 8 bit BMP and SL2 formats&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://zingot.itch.io/palette-knife Palette knife by Zingot]&#039;&#039; ===&lt;br /&gt;
: Windows GUI tool to create, combine and edit palettes&lt;br /&gt;
: Supports different file formats and bit depths (also Next unrelated)&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://marketplace.visualstudio.com/items?itemName=remysharp.nextbasic NextBASIC extension for VS Code by Remy Sharp]&#039;&#039; ===&lt;br /&gt;
: Syntax highlighting, folding and definition jumping&lt;br /&gt;
: Export and import .bas to .txt and visa versa&lt;br /&gt;
: Inline help, line number completion and inline error checking&lt;br /&gt;
: Launches Cspect with minimal configuration&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://www.specnext.com/forum/viewtopic.php?f=17&amp;amp;t=1715 NextSync WiFi file transferring by Jari Komppa]&#039;&#039; ===&lt;br /&gt;
: Run &amp;quot;server&amp;quot; code on your local PC (python 3 required)&lt;br /&gt;
: Run &amp;quot;.sync&amp;quot; on the Next&lt;br /&gt;
: Changed files will be copied from PC to Next by ESP WiFi module&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[[NXtel:Introduction|NXtel by Robin Verhagen Guest]]&#039;&#039; ===&lt;br /&gt;
: Comprises a TCP/IP Videotext server, a Next client, and a page editor website&lt;br /&gt;
: Content is community created and supervised by a small team of editors.&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=Miscellaneous&amp;diff=41418</id>
		<title>Miscellaneous</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=Miscellaneous&amp;diff=41418"/>
		<updated>2025-11-27T01:20:17Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: adding palette knife link (some obsolete version was posted on specnext forum, but the project evolved and is hosted on itchio now)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== &#039;&#039;[http://simon.mooli.org.uk/nextech/ Simon N Goodwin&#039;s Spectrum Next Page]&#039;&#039; ===&lt;br /&gt;
: A host of utilites for NextBasic written by Simon, NextPort, Nextramon, &lt;br /&gt;
: Next MGT Reader amongst other treasures.&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://github.com/kounch/vscode_zx Visual Studio Code Tasks and Scripts]&#039;&#039; ===&lt;br /&gt;
: Some VSC goodies by kounch to work with NextBasic and ZX Basic&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://github.com/stefanbylund/zxnext_bmp_tools Next BMP Tools]&#039;&#039; ===&lt;br /&gt;
: The Next BMP tools are BMP image conversion tools targeting the Sinclair ZX Spectrum Next written&lt;br /&gt;
: by Stefan Bylund&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://wiki.twistedraven.net/index.php?title=Downloads Octarine Studio]&#039;&#039; ===&lt;br /&gt;
: Octarine Studio by Guy Black is a PC based editing tool that currently supports palettes and tiles. &lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://www.specnext.com/forum/viewtopic.php?f=7&amp;amp;t=351 UDGeedNext Sprite Editor]&#039;&#039; ===&lt;br /&gt;
: Windows based sprite editor written by some guy I have never heard of. Currently supports 8 bit&lt;br /&gt;
: palettes. 9 bit and 4 bit sprites should be added at some point....&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[http://worldofpaul.com/speccyart/ Speccy Art]&#039;&#039; ===&lt;br /&gt;
: An online drawing experience that aims to help you create Sinclair ZX Spectrum-like images.&lt;br /&gt;
: Supports the classic ULA mode (256x192 pixels with 8x8 attribute squares and 15 classic ZX colours)&lt;br /&gt;
: Supports the Timex HiColour mode (256x192 pixels with 8x1 attribute rectangles and 15 classic ZX colours)&lt;br /&gt;
: Images can be saved and loaded through TAP files or exported into SCR/SHC files.&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://github.com/varmfskii/zxnext_tools ZX Spectrum Next tools by Theodore (Alex) Evans]&#039;&#039; ===&lt;br /&gt;
: Multiple tools for various graphics conversions and processing&lt;br /&gt;
: zxnftp for transferring files between PC and Next via the ESP WiFi module&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://gitlab.com/zxnexttools/nim Next Image Manipulator by Matt Davies]&#039;&#039; ===&lt;br /&gt;
: windows command line tool to convert various image and palette formats to custom &amp;quot;nip/nim&amp;quot; binary formats which are simple enough to parse (or include directly into source with assemblers supporting binary includes)&lt;br /&gt;
: this is early version (already working, build it from source), but further expansion to support also tiles/etc may happen in future&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://github.com/gasman/hdfmonkey hdfmonkey]&#039;&#039; ===&lt;br /&gt;
: A Swiss Army Knife for working with FAT partitions on Spectrum emulator HDF images. The more recent [https://www.specnext.com/forum/viewtopic.php?p=16108 hdfmonkey jjjs builds by johnnyo] also support the [https://www.specnext.com/latestdistro/ imperfect SD card images of the distribution for emulators from specnext.com], and they include executable binaries for Windows, Linux, and macOS.&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://zeroonetwenty.com/blueharvest/ Blue Harvest]&#039;&#039; ===&lt;br /&gt;
: A convenient macOS tool to keep SD cards free from macOS metadata. Free 30-day trial.&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://github.com/MrKWatkins/ZXSpectrumNextTests ZXSpectrumNextTests by Kevin Watkins and Peter Helcmanovsky]&#039;&#039; ===&lt;br /&gt;
: Suite of tests exercising various aspects of ZX Spectrum Next&lt;br /&gt;
: Tests for: Next registers, Copper, Sprites, Layer2, ULA modes, Extended ULA, Layers mixing modes, Z80N instructions, ...&lt;br /&gt;
: ASM Sources for each test (sjasmplus assembler syntax)&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://github.com/Threetwosevensixseven/ZXSpectrumNextTests ZXSpectrumNextTests by Robin Verhagen-Guest]&#039;&#039; ===&lt;br /&gt;
: Suite of tests exercising various aspects of ZX Spectrum Next (yes, one more :) )&lt;br /&gt;
: Tests for: DMA, MMU paging, Layers mixing modes&lt;br /&gt;
: ASM Sources for each test (Zeus assembler syntax)&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;&amp;lt;div id=&amp;quot;WASPtools&amp;quot; name=&amp;quot;WASPtools&amp;quot;&amp;gt;WASPtools by Phoebus Dokos&amp;lt;/div&amp;gt;&#039;&#039; ===&lt;br /&gt;
WASPtools is a suite of tools comprised of a palette manipulator, a sprite editor, a graphics converter, and tilemap editor (both virtual tilemaps for say Layer2, and the hardware tilemap mode).&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://zx.remysharp.com Online sprite, palette and tilemap editor by Remy Sharp]&#039;&#039; ===&lt;br /&gt;
: Browser based tooling that works fully offline&lt;br /&gt;
: Sprite editor with import and export tools&lt;br /&gt;
: Tile map editor with 16x16 and 8x8 tile support&lt;br /&gt;
: Full 512 palette import and export&lt;br /&gt;
: Also includes image conversion tools from PNG to 8 bit BMP and SL2 formats&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://zingot.itch.io/palette-knife Palette knife by Zingot]&#039;&#039; ===&lt;br /&gt;
: Windows GUI tool to create, combine and edit palettes&lt;br /&gt;
: Supports different file formats and bit depths (also Next unrelated)&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://marketplace.visualstudio.com/items?itemName=remysharp.nextbasic NextBASIC extension for VS Code by Remy Sharp]&#039;&#039; ===&lt;br /&gt;
: Syntax highlighting, folding and definition jumping&lt;br /&gt;
: Export and import .bas to .txt and visa versa&lt;br /&gt;
: Inline help, line number completion and inline error checking&lt;br /&gt;
: Launches Cspect with minimal configuration&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://www.specnext.com/forum/viewtopic.php?f=17&amp;amp;t=1715 NextSync WiFi file transferring by Jari Komppa]&#039;&#039; ===&lt;br /&gt;
: Run &amp;quot;server&amp;quot; code on your local PC (python 3 required)&lt;br /&gt;
: Run &amp;quot;.sync&amp;quot; on the Next&lt;br /&gt;
: Changed files will be copied from PC to Next by ESP WiFi module&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[[NXtel:Introduction|NXtel by Robin Verhagen Guest]]&#039;&#039; ===&lt;br /&gt;
: Comprises a TCP/IP Videotext server, a Next client, and a page editor website&lt;br /&gt;
: Content is community created and supervised by a small team of editors.&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=Development_Tools:Linux_setup&amp;diff=41417</id>
		<title>Development Tools:Linux setup</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=Development_Tools:Linux_setup&amp;diff=41417"/>
		<updated>2025-11-27T01:01:15Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: Switching hdfmonkey to ped7g&amp;#039;s github repo archiving jjjs patched version&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== General ==&lt;br /&gt;
&lt;br /&gt;
This page collects summaries of installation process of various tools related to ZX Spectrum Next software development for linux OS users.&lt;br /&gt;
&lt;br /&gt;
As usual with linux, most of the suggestions are in the form of command line command to be used from terminal.&lt;br /&gt;
&lt;br /&gt;
== sjasmplus assembler ==&lt;br /&gt;
&lt;br /&gt;
You can also check the [https://www.youtube.com/watch?v=c6I4kdErEwE video] of installing sjasmplus on freshly reinstalled KDE neon 5.20 linux, where is also extended info how to run the automated tests of sjasmplus, and opening it in KDevelop IDE to eventually write your own modifications.&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
On Debian based systems make sure you have these packages installed (git-cola and cmake are optional, but often handy):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install git build-essential g++ git-cola cmake&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Retrieving the sjasmplus source ===&lt;br /&gt;
&lt;br /&gt;
Use git to clone the [https://github.com/z00m128/sjasmplus z00m&#039;s sjasmplus repository]:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;git clone --recursive -j8 https://github.com/z00m128/sjasmplus.git&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To update already cloned repository, do inside the sjasmplus folder:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;git pull&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
- or use your favourite GIT client app to update the cloned repository.&lt;br /&gt;
&lt;br /&gt;
=== Building the executable binary ===&lt;br /&gt;
&lt;br /&gt;
The GNU make and common C++ compiler (gcc or clang) should be enough to build the binary:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;make clean &amp;amp;&amp;amp; make&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To verify the binary was built (&amp;quot;dot slash&amp;quot; prefix to force running of binary in current folder, not system one):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;./sjasmplus --version&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Installing the executable ===&lt;br /&gt;
&lt;br /&gt;
If you already have sjasmplus installed, use &amp;lt;code&amp;gt;which sjasmplus&amp;lt;/code&amp;gt; to see where the installed executable is (and which installed executable has precedence), you can use this command also after installing the new executable to verify it is being picked up by the system.&lt;br /&gt;
&lt;br /&gt;
Installing the binary in system-wide fashion:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo make install&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or you can install the binary only locally for your user (without root/sudo permissions):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;mkdir -p ~/.local/bin&lt;br /&gt;
make PREFIX=~/.local install&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
- then make sure you have &amp;lt;code&amp;gt;~/.local/bin&amp;lt;/code&amp;gt; in your user &amp;lt;code&amp;gt;PATH&amp;lt;/code&amp;gt; environment variable (on some distros there is already script in .profile to add this to PATH if the dir does exist, so you may need to only logout/restart after creating it to get it active).&lt;br /&gt;
&lt;br /&gt;
=== Checking if it all works ===&lt;br /&gt;
&lt;br /&gt;
Open your terminal and type (in any directory):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sjasmplus --version&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see version of the freshly built sjasmplus executable like this:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;SjASMPlus Z80 Cross-Assembler v1.17.0 (https://github.com/z00m128/sjasmplus)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== hdfmonkey tool ==&lt;br /&gt;
&lt;br /&gt;
The hdfmonkey tool can manipulate card-images, helping to write new builds of your project into NextZXOS card-image, to boot the emulators with full file system. (it&#039;s also possible to mount the images directly into linux by other means, to operate on them with regular file manager/etc, but hdfmonkey suits better use-case when the build script does update the image)&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
On Debian based systems make sure you have these packages installed:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install git build-essential g++ autoconf&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Retrieving the hdfmonkey source ===&lt;br /&gt;
&lt;br /&gt;
Use git to clone the [https://github.com/ped7g/hdfmonkey hdfmonkey repository with patched 0.5.7 jjjs version sources]:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;git clone https://github.com/ped7g/hdfmonkey.git&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
(make sure you are on the default branch &amp;quot;jjjs-variant&amp;quot; to build the improved version, it should be checked out by default after clone)&lt;br /&gt;
&lt;br /&gt;
* to update already cloned repository, do inside the hdfmonkey folder:&lt;br /&gt;
  &amp;lt;nowiki&amp;gt;git pull&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
* or use your favourite GIT client app to update the cloned repository.&lt;br /&gt;
* if you did clone original gasman&#039;s repository, you may want to clone and rebuild the jjjs version to get multiple fixes and convenience features.&lt;br /&gt;
&lt;br /&gt;
=== Building the executable binary ===&lt;br /&gt;
&lt;br /&gt;
The hdfmonkey is using autoconf/autotools to build final Makefile, check the hdfmonkey README for &amp;quot;from git&amp;quot; installation notes, at the moment of writing this page, the steps were:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;cd hdfmonkey&lt;br /&gt;
autoheader&lt;br /&gt;
aclocal&lt;br /&gt;
autoconf&lt;br /&gt;
automake -a&lt;br /&gt;
./configure&lt;br /&gt;
make&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To verify the binary was built:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;src/hdfmonkey help&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Installing the executable ===&lt;br /&gt;
&lt;br /&gt;
If you already have hdfmonkey installed, use &amp;lt;code&amp;gt;which hdfmonkey&amp;lt;/code&amp;gt; to see where the installed executable is (and which installed executable has precedence), you can use this command also after installing the new executable to verify it is being picked up by the system.&lt;br /&gt;
&lt;br /&gt;
Installing the binary in system-wide fashion:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo make install&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or you can install the binary only locally for your user (without root/sudo permissions):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;make prefix=~/.local install&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
- then make sure you have &amp;lt;code&amp;gt;~/.local/bin&amp;lt;/code&amp;gt; in your user &amp;lt;code&amp;gt;PATH&amp;lt;/code&amp;gt; environment variable.&lt;br /&gt;
&lt;br /&gt;
=== Checking if it all works ===&lt;br /&gt;
&lt;br /&gt;
Open your terminal and type (in any directory):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;hdfmonkey help&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see help of the freshly built hdfmonkey executable like this:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;hdfmonkey: utility for manipulating HDF disk images&lt;br /&gt;
&lt;br /&gt;
usage: hdfmonkey &amp;lt;command&amp;gt; [args]&lt;br /&gt;
...&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mounting sd-card image directly ==&lt;br /&gt;
&lt;br /&gt;
Sometimes it may be useful to mount the card image directly, to be able to browse it and manipulate with common tools. But make sure you are not using mounted card image also in emulator at the same time, to prevent any data damage by parallel access.&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
On Debian based systems make sure you have these packages installed:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install fdisk mount&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Prepare empty directory to mount the card image into (let&#039;s call it &amp;quot;next-card&amp;quot;) and have the image file around (&amp;quot;tbblue.mmc&amp;quot; in following examples)&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;mkdir -p next-card&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Mounting the card image ===&lt;br /&gt;
&lt;br /&gt;
To mount the card image you need to know the exact byte-offset where the FAT partition starts, it&#039;s possible to read it from &amp;quot;fdisk&amp;quot; or &amp;quot;parted&amp;quot; tools outputs:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;fdisk -l -o Start tbblue.mmc&lt;br /&gt;
# prints value in sector units, like:&lt;br /&gt;
# Start&lt;br /&gt;
#    63&lt;br /&gt;
# This has to be multiplied by 512 to get byte offset: 63*512 = 32256&lt;br /&gt;
&lt;br /&gt;
# or&lt;br /&gt;
&lt;br /&gt;
parted tbblue.mmc unit B print&lt;br /&gt;
# prints values in bytes with &amp;quot;B&amp;quot; suffix in &amp;quot;Start&amp;quot; column&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
But the fdisk output can be incorporated directly into mount command, which needs root permissions, example with sudo:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo mount tbblue.mmc next-card/ -o loop,offset=$((`fdisk -l -o Start tbblue.mmc | tail -1` * 512)),user,uid=`id -u`,gid=`id -g`&lt;br /&gt;
&lt;br /&gt;
# or you can enter the offset yourself&lt;br /&gt;
&lt;br /&gt;
sudo mount tbblue.mmc next-card/ -o loop,offset=32256,user,uid=`id -u`,gid=`id -g`&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The uid and gid options will mount the filesystem under your regular user, so you can now browse it with file manager, text editors, etc.&lt;br /&gt;
&lt;br /&gt;
Do not run the emulator yet, before unmounting the image (after you are done manipulating the files)!&lt;br /&gt;
&lt;br /&gt;
=== Unmount the image before using it in emulator ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo umount next-card/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Check the result. If the unmounting fails (probably with &amp;quot;target is busy&amp;quot;), find which process is still accessing/viewing the files in the next-card directory, and try to unmount it again.&lt;br /&gt;
&lt;br /&gt;
=== TODO: udiskctl loop device mounting option ===&lt;br /&gt;
&lt;br /&gt;
From discord: &amp;quot;udisksctl loop-setup --file ~/spec/SpectrumNext/tbblue/image/tbblue.mmc&amp;quot;&lt;br /&gt;
&lt;br /&gt;
TODO: describe this solution and check possible gotchas/CLI options (like user must be in udiskctl group to run this without sudo, etc).&lt;br /&gt;
&lt;br /&gt;
== #CSpect emulator ==&lt;br /&gt;
&lt;br /&gt;
The #CSpect is Mike Dailly&#039;s ZX Spectrum Next emulator, written in C# making it cross-platform (sort of, where the mono framework is available). It is non-free (closed-source, custom license) project, but available for usage without any payment (it&#039;s possible to use it internally to develop also commercial titles, but you can not distribute/sell the emulator itself, not even packaged with your game - for such agreement contact the author first and get his permission).&lt;br /&gt;
&lt;br /&gt;
Currently it is most performant and user friendly emulator of ZX Spectrum Next, with good emulation accuracy (see [https://wiki.specnext.dev/CSpect:known_bugs CSpect:known_bugs] page for more detailed report).&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
On Debian based systems make sure you have these packages installed:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;sudo apt-get install mono-complete libopenal1 libsdl2-dev&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Retrieving the #CSpect package ===&lt;br /&gt;
&lt;br /&gt;
Use web browser to visit itch.io dedicated to CSpect project [https://mdf200.itch.io/cspect mdf200.itch.io/cspect] and download latest release.&lt;br /&gt;
&lt;br /&gt;
You may get warnings from your browser or antivirus about the page itself and about the zip/binary files. The #CSpect has long record of triggering false positives of AV engines due to the executable being not digitally signed and because of the code using features of OS which are normal for emulator, but may look wonky for AV heuristic. Whether you trust the executable is virus free is up to you, in the end.&lt;br /&gt;
&lt;br /&gt;
=== Installing the executable ===&lt;br /&gt;
&lt;br /&gt;
Unzip the retrieved zip file (I personally use KDE Dolphin file manager, the file context menu &#039;&#039;&amp;quot;Extract -&amp;gt; Extract archive here, autodetect subfolder&amp;quot;&#039;&#039;), and place the unzipped directory to target destination (&amp;lt;code&amp;gt;~/zx/emulators/CSpect/CSpect2_13_0&amp;lt;/code&amp;gt; in my case). I prefer to keep every version in its own directory, and have general symbolic link pointing to the one I want use by default:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;cd ~/zx/emulators/CSpect&lt;br /&gt;
ln -s CSpect2_13_0 CSpect_current&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then I create launcher bash-scripts in my &amp;lt;code&amp;gt;~/.local/bin&amp;lt;/code&amp;gt; like this (name of script &amp;lt;code&amp;gt;runCSpect&amp;lt;/code&amp;gt;):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;#!/bin/bash&lt;br /&gt;
# personal script of Ped to launch &amp;quot;#CSpect&amp;quot; emulator in &amp;quot;current directory&amp;quot; (with arguments like: &amp;quot;runCSpect file.nex&amp;quot;)&lt;br /&gt;
MONO_IOMAP=all mono ~/zx/emulators/CSpect/CSpect_current/CSpect.exe -tv -zxnext -s28 -w4 -mmc=./ &amp;quot;$@&amp;quot;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notes: I don&#039;t know any more what &amp;lt;code&amp;gt;MONO_IOMAP=all&amp;lt;/code&amp;gt; helps with, I believe it was suggested to help with any filesystem windows-like paths containing backslashes, you can try to do your own research. The &amp;lt;code&amp;gt;-tv&amp;lt;/code&amp;gt; switch will switch off &amp;quot;scanlines&amp;quot; shader effect and generally switch off any GPU shaders, which makes CSpect more compatible with graphics drivers (try it, if you get only black screen or instant crash during init). The &amp;lt;code&amp;gt;-w4&amp;lt;/code&amp;gt; will make the window quite large - 4x scale, the &amp;lt;code&amp;gt;-zxnext -s28&amp;lt;/code&amp;gt; switch #CSpect into ZX Next emulation mode and set 28Mhz speed of OS as default. And finally the &amp;lt;code&amp;gt;-mmc=./ &amp;quot;$@&amp;quot;&amp;lt;/code&amp;gt; will set &#039;&#039;current directory&#039;&#039; for esxdos emulation to the directory where you use the script to launch the emulator, and pass any remaining command line options entered by user, like the name of the SNA/NEX file. Other noteworthy options are &amp;lt;code&amp;gt;-debug -brk -map=file.map&amp;lt;/code&amp;gt;, the -debug entering the debugger just ahead of the first instruction, -brk enables CSpect specific two-byte tag 0xDD 0x01 to work as breakpoint and the -map option allows you to load into debugger the symbol table from your assembler (directive CSPECTMAP in sjasmplus), making labels visible in disassembly.&lt;br /&gt;
&lt;br /&gt;
=== Checking if it all works ===&lt;br /&gt;
&lt;br /&gt;
Go to some directory with SNA/SNX/NEX file (there are also some demo files right in the CSpect directory) and use the launcher script, like:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;runCSpect beast.nex&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see #CSpect emulator window running the beast.nex demo (or whatever else you did want to launch and entered as argument).&lt;br /&gt;
&lt;br /&gt;
[[File:Cspect_test_run.png|frameless|Running CSpect from directory with test snapshots]]&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=MAME:Installing&amp;diff=41397</id>
		<title>MAME:Installing</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=MAME:Installing&amp;diff=41397"/>
		<updated>2025-11-18T00:25:20Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: Moving download links of tbblue.zip and image under &amp;quot;Get&amp;quot; chapter, added more info about where MAME looks for ini and other files and adding few more links to &amp;quot;links&amp;quot; part.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[https://www.mamedev.org/ MAME] (formerly an acronym of Multiple Arcade Machine Emulator) is a free and open-source emulator designed to emulate the hardware of arcade games, later expanded to include video game consoles, old computers and other systems in software on modern personal computers and other platforms.&lt;br /&gt;
&lt;br /&gt;
MAME supports The ZX Spectrum Next since version 0.267. Existing implementation is based on v3.02.01 core and implements most of the features.&lt;br /&gt;
&lt;br /&gt;
= Get =&lt;br /&gt;
The latest MAME version for Windows is available [https://www.mamedev.org/release.html here] and macOS builds can be downloaded [https://sdlmame.lngn.net/ from here.] For the MAME platform as a whole, check your package manager or [https://docs.mamedev.org/initialsetup/compilingmame.html build from sources].&lt;br /&gt;
&lt;br /&gt;
Linux users can install the latest stable version of MAME also from the flatpak repositories by running:&lt;br /&gt;
&amp;lt;pre&amp;gt;sudo flatpak install org.mamedev.MAME&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Put the ROM dump zip of ZX Next [https://github.com/Threetwosevensixseven/NexCreator/raw/master/bootroms/tbblue.zip tbblue.zip] into MAME&#039;s &amp;lt;code&amp;gt;roms&amp;lt;/code&amp;gt; folder (don&#039;t extract it, mame will look for the zip file when &amp;quot;tbblue&amp;quot; machine is selected).&lt;br /&gt;
&lt;br /&gt;
Prepare an SD card image file of [https://www.specnext.com/system-next22-10/ NextZXOS]. Some published images do not work with some emulators, but all images from https://zxnext.uk/hosted/#sd are now confirmed to work with both MAME and CSpect, including the official ones, including [https://zxnext.uk/hosted/index_files/hdfimages/cspect-next-2gb.zip this one] (the SD card image is the &amp;lt;code&amp;gt;cspect-next-2gb.img&amp;lt;/code&amp;gt; file within the zip file). You will point mame to desired SD card image with &amp;lt;code&amp;gt;-hard1&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;-hard2&amp;lt;/code&amp;gt; options (or select the files from menu inside emulator).&lt;br /&gt;
&lt;br /&gt;
= Use =&lt;br /&gt;
MAME looks for its configuration and helper files in specific (configurable) folders. By default these are relative to current working directory (cwd), ie. from where you did launch the executable. The mame.ini and other folders like &amp;lt;code&amp;gt;roms, bgfx, plugins, language, ...&amp;lt;/code&amp;gt; are expected there, unless ini file specifies other paths. When launching through desktop icon/menu depending on the OS the working directory is often defined by that launch shortcut properties. When launching through command line the current directory is &amp;quot;cwd&amp;quot; (doh). On Linux MAME will look for mame.ini first into ~/.mame folder. You can use option &amp;lt;code&amp;gt;-inipath&amp;lt;/code&amp;gt; to search other path for ini file.&lt;br /&gt;
&lt;br /&gt;
The fastest way to run a machine with a desired configuration is from the command prompt. Most of the features are also available from MAME&#039;s UI, but that takes more time to configure.&lt;br /&gt;
Let&#039;s discover some useful options:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Use window and no mouse more till you get familiar with UI keys:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; mame tbblue -window -mouse_device none -hard1 /path/to/next-distribution.img&amp;lt;/pre&amp;gt;&lt;br /&gt;
To launch the Linux flatpak version using the same options:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; flatpak run org.mamedev.MAME tbblue -window -mouse_device none -hard1 /path/to/next-distribution.img&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Activate UI keys on startup:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -ui_active&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Don&#039;t show info popup on startup:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ...-skip_gameinfo&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;Run with debugger. If not requested on startup, you won&#039;t have access to it:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -debug&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;Use &amp;quot;crisp&amp;quot; pixels:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -nounevenstretch -aspect 2:1 -video bgfx -bgfx_screen_chains unfiltered&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;No joystick connected to PC (may slightly speed up MAME&#039;s startup):&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -joystickprovider none&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Check [https://docs.mamedev.org/commandline/commandline-all.html#mame-commandline-universal official docs] for more advanced usage.&lt;br /&gt;
&lt;br /&gt;
= Keys =&lt;br /&gt;
&lt;br /&gt;
Keys are emulated in two modes: to control MAME or completely dedicated to the emulated system. You can toggle between these two keyboard modes with ScrLk or Fn+delete under macOS.&lt;br /&gt;
&lt;br /&gt;
Some UI keys:&lt;br /&gt;
* F3 - soft reset&lt;br /&gt;
* Shift+F3 - hard reset&lt;br /&gt;
* F4 - sprites/tiles/font viewer (Enter, ], [)&lt;br /&gt;
* F5 - pause emulation&lt;br /&gt;
* F6 - save state&lt;br /&gt;
* F7 - load state&lt;br /&gt;
* Tab - emulator settings&lt;br /&gt;
* ~ - menu&lt;br /&gt;
* PgDwn (Linux) or Insert (Win) -- max speed (only while it&#039;s pressed; can be used e.g. to speed up boot)&lt;br /&gt;
* Esc - exit&lt;br /&gt;
* F12 - MF NMI&lt;br /&gt;
* F11 - DivMMC NMI&lt;br /&gt;
&lt;br /&gt;
= Changing the UI toggle key =&lt;br /&gt;
&lt;br /&gt;
Some laptops don&#039;t have a Scroll Lock key so you won&#039;t be able to exit MAME if you run it in full screen mode hence you will need to change the UI toggle key.&lt;br /&gt;
&lt;br /&gt;
Follow these steps to change the UI toggle key:&lt;br /&gt;
&lt;br /&gt;
* Run MAME without any command line arguments (except maybe -window) to open its GUI.&lt;br /&gt;
* Push TAB and enter the General Settings menu.&lt;br /&gt;
* Go to Input Assignments -&amp;gt; User Interface -&amp;gt; Toggle UI controls and select a new key. I use Right Alt / Alt GR.&lt;br /&gt;
* Return to Previous menu twice then choose Save Settings&lt;br /&gt;
&lt;br /&gt;
= Mounting SD card images under Linux =&lt;br /&gt;
&lt;br /&gt;
Under Linux you can use losetup to mount SD card images as loop devices which enables you to copy files to and from the image and perform other file management tasks as you would using any other filesystem.&lt;br /&gt;
&lt;br /&gt;
Run the following commands as the root user to mount an image called sn-emulator-22.10a.img under the /mnt directory:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;losetup --partscan --show --find cspect-next-2gb.img&lt;br /&gt;
mount /dev/loop0p1 /mnt/&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After you have finished modifying the SD card image, cd out of /mnt then unmount and detach the loopback device:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;umount /mnt/&lt;br /&gt;
losetup -D&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Creating a NextZXOS SD card image under Linux =&lt;br /&gt;
&lt;br /&gt;
Most users wanting to emulate the Next using MAME will be fine using a pre-built SD card image downloaded from the specnext website but the following guide is provided for anyone wanting to create a NextZXOS SD card image from scratch.&lt;br /&gt;
&lt;br /&gt;
Download the [https://www.specnext.com/latestdistro/ latest NextZXOS distribution zip file] (named something like sn-complete-WX.YZ.zip) and extract it into a new, empty directory.&lt;br /&gt;
&lt;br /&gt;
Create a disk image of at least 256 MB. The current complete NextZXOS distro requires at least 130 MB of disk space. This command will create a 256 MB SD card image, change the count value to make the image file as big as you want in megabytes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;dd if=/dev/zero of=NextZXOS.img bs=1M count=256&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The rest of the commands in this guide must be run as the root user or using sudo.&lt;br /&gt;
&lt;br /&gt;
You will need the dosfstools and parted packages, if you don&#039;t already have them installed. Debian and Ubuntu Linux users can install these using this apt command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;apt install dosfstools parted&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mount the SD card image loopback device:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;losetup --partscan --show --find NextZXOS.img&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Create a FAT32 partition:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;parted /dev/loop0 mklabel msdos&lt;br /&gt;
parted /dev/loop0 mkpart primary fat32 1MB 100%&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Format and mount the partition under /mnt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;mkfs.vfat -F 32 /dev/loop0p1&lt;br /&gt;
mount /dev/loop0p1 /mnt&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can now copy all of the files you extracted from sn-complete-WX.YZ.zip into /mnt.&lt;br /&gt;
&lt;br /&gt;
After copying the files, unmount and detach the loopback device (the SD card image):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;umount /mnt/&lt;br /&gt;
losetup -D&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Continuous Integration MAME Builds=&lt;br /&gt;
&lt;br /&gt;
MAME is updated on a release schedule, but due to the ongoing nature of development, including for the MAME Next machine, it can be sometimes useful to install a recent build, if it contains a new feature or bugfix you are interested in. Sometimes ongoing work is discussed on social media, like [https://discordapp.com/channels/556228195767156758/752197165891321886 Discord].&lt;br /&gt;
&lt;br /&gt;
Continuous Integration (CI) builds are available from both the [https://github.com/mamedev/mame/actions primary MAME] and [https://github.com/holub/mame/actions holub] github repos. Both are considered bleeding-edge, with the primary MAME repo slightly less so. MAME CI builds are available for Windows, linux and MacOS, and are updated automatically every time code is committed by a maintainer or pushed to the primary repo.&lt;br /&gt;
&lt;br /&gt;
To try out a CI build, do a fill MAME install from the [https://www.mamedev.org/release.html latest release] first, if you have not already done so. Then back up your main binary from its installation location - these are called something like &amp;lt;code&amp;gt;mame.exe&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;mame&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;mametiny&amp;lt;/code&amp;gt;. You can always restore these if the CI build doesn&#039;t work, or you don&#039;t like how it behaves.&lt;br /&gt;
&lt;br /&gt;
Then visit the one of the links above, and find a workflow run item for your platform - these are flagged as &amp;lt;code&amp;gt;CI (Windows)&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;CI (Linux)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;CI (macOS)&amp;lt;/code&amp;gt;. Click on it and find the Artifacts section at the bottom, then click the download button. Unzip the downloaded file and find the main binary (same name as above). Copy the main binary over the top of the original one in the install location, and run MAME the same way your were running it before. On Windows you may have to do an additional step of trusting the binary (Run Anyway).&lt;br /&gt;
&lt;br /&gt;
= More MAME links =&lt;br /&gt;
The source code is available [https://github.com/mamedev/mame/blob/master/src/mame/sinclair/specnext.cpp here], the author of Next emulation holub has fork [https://github.com/holub/mame here] (may contain new fixes and features before they are merged to official repository).&lt;br /&gt;
&lt;br /&gt;
MAME [https://docs.mamedev.org/ documentation].&lt;br /&gt;
&lt;br /&gt;
Report any issues with MAME on the [https://mametesters.org/ bugtracker].&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=MAME:Tricks&amp;diff=41396</id>
		<title>MAME:Tricks</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=MAME:Tricks&amp;diff=41396"/>
		<updated>2025-11-15T23:31:18Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== HOW-TO ==&lt;br /&gt;
&lt;br /&gt;
=== Save state for quick loading of desired file through browser ===&lt;br /&gt;
&lt;br /&gt;
# launch from command line: mame tbblue ... -d&lt;br /&gt;
# F5 - unpause emulation to boot NextZXOS&lt;br /&gt;
# Select Browser&lt;br /&gt;
# Go to the folder where the *.nex file will be... move the cursor to this file (we&#039;ll go here after the soft reset)&lt;br /&gt;
# F3 - soft reset (you can do this in the debugger)&lt;br /&gt;
# F5 - let&#039;s go&lt;br /&gt;
# Set breakpoint bp 2411&lt;br /&gt;
# Wait for the menu... select Browser&lt;br /&gt;
# The breakpoint 2411 should trigger&lt;br /&gt;
# Set the cursor to 2424 (enter from the keyboard polling cycle)&lt;br /&gt;
# F4 - run to cursor&lt;br /&gt;
# statesave n&lt;br /&gt;
# Ctrl+Q exit MAME (TODO check the key, it&#039;s debugger hotkey I guess?)&lt;br /&gt;
&lt;br /&gt;
=== Load saved state ===&lt;br /&gt;
&lt;br /&gt;
# launch from command line: mame tbblue ... -state n&lt;br /&gt;
# test your code&lt;br /&gt;
# exit MAME&lt;br /&gt;
# Copy the new version of the super game to the image file&lt;br /&gt;
# Repeat&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=MAME:Tricks&amp;diff=41395</id>
		<title>MAME:Tricks</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=MAME:Tricks&amp;diff=41395"/>
		<updated>2025-11-15T23:26:33Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: Save/Load state trick to speed up startup of MAME (skipping Next&amp;#039;s boot sequence)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= HOW-TO =&lt;br /&gt;
&lt;br /&gt;
== Save state for quick loading of desired file through browser ==&lt;br /&gt;
&lt;br /&gt;
# launch from command line: mame tbblue ... -d&lt;br /&gt;
# F5 - unpause emulation to boot NextZXOS&lt;br /&gt;
# Select Browser&lt;br /&gt;
# Go to the folder where the *.nex file will be... move the cursor to this file (we&#039;ll go here after the soft reset)&lt;br /&gt;
# F3 - soft reset (you can do this in the debugger)&lt;br /&gt;
# F5 - let&#039;s go&lt;br /&gt;
# Set breakpoint bp 2411&lt;br /&gt;
# Wait for the menu... select Browser&lt;br /&gt;
# The breakpoint 2411 should trigger&lt;br /&gt;
# Set the cursor to 2424 (enter from the keyboard polling cycle)&lt;br /&gt;
# F4 - run to cursor&lt;br /&gt;
# statesave n&lt;br /&gt;
# Ctrl+Q exit MAME (TODO check the key, it&#039;s debugger hotkey I guess?)&lt;br /&gt;
&lt;br /&gt;
== Load saved state ==&lt;br /&gt;
&lt;br /&gt;
# launch from command line: mame tbblue ... -state n&lt;br /&gt;
# test your code&lt;br /&gt;
# exit MAME&lt;br /&gt;
# Copy the new version of the super game to the image file&lt;br /&gt;
# Repeat&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=MAME:Installing&amp;diff=41394</id>
		<title>MAME:Installing</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=MAME:Installing&amp;diff=41394"/>
		<updated>2025-11-15T23:13:20Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[https://www.mamedev.org/ MAME] (formerly an acronym of Multiple Arcade Machine Emulator) is a free and open-source emulator designed to emulate the hardware of arcade games, later expanded to include video game consoles, old computers and other systems in software on modern personal computers and other platforms.&lt;br /&gt;
&lt;br /&gt;
MAME supports The ZX Spectrum Next since version 0.267. Existing implementation is based on v3.02.01 core and implements most of the features.&lt;br /&gt;
&lt;br /&gt;
= Get =&lt;br /&gt;
The latest MAME version for Windows is available [https://www.mamedev.org/release.html here] and macOS builds can be downloaded [https://sdlmame.lngn.net/ from here.] For the MAME platform as a whole, check your package manager or [https://docs.mamedev.org/initialsetup/compilingmame.html build from sources].&lt;br /&gt;
&lt;br /&gt;
Linux users can install the latest stable version of MAME from the flatpak repositories by running:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;sudo flatpak install org.mamedev.MAME&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Use =&lt;br /&gt;
In order to run the Next (and any others) you need to acquire ROM dumps for the system.&lt;br /&gt;
In the case of the Next download [https://github.com/Threetwosevensixseven/NexCreator/raw/master/bootroms/tbblue.zip tbblue.zip] and put it into your MAME roms folder. Under Linux you can copy your MAME roms into &amp;lt;code&amp;gt;~/mame/roms&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
You also need an SD card image of [https://www.specnext.com/system-next22-10/ NextZXOS]. Some published images do not work with some emulators, but all images from https://zxnext.uk/hosted/#sd are now confirmed to work with both MAME and CSpect, including the official ones, including [https://zxnext.uk/hosted/index_files/hdfimages/cspect-next-2gb.zip this one] (the SD card image is the &amp;lt;code&amp;gt;cspect-next-2gb.img&amp;lt;/code&amp;gt; file within the zip file).&lt;br /&gt;
&lt;br /&gt;
The fastest way to run a machine with a desired configuration is from the command prompt. Most of the features are also available from MAME&#039;s UI, but that takes more time to configure.&lt;br /&gt;
Let&#039;s discover some useful options:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Use window and no mouse more till you get familiar with UI keys:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; mame tbblue -window -mouse_device none -hard /path/to/next-distribution.img&amp;lt;/pre&amp;gt;&lt;br /&gt;
To launch the Linux flatpak version using the same options:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; flatpak run org.mamedev.MAME tbblue -window -mouse_device none -hard /path/to/next-distribution.img&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Activate UI keys on startup:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -ui_active&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Don&#039;t show info popup on startup:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ...-skip_gameinfo&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;Run with debugger. If not requested on startup, you won&#039;t have access to it:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -debug&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Check [https://docs.mamedev.org/ official docs] for more advanced usage.&lt;br /&gt;
&lt;br /&gt;
Also, this combination of parameters enables the &amp;quot;crisp&amp;quot; pixels:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;mame -ui_active  -nounevenstretch -aspect 2:1 -video bgfx  -bgfx_screen_chains unfiltered -window -skip_gameinfo  -mouse_device none  tbblue -hard1 /path/to/next-distribution.img&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And if you don&#039;t need to use a joystick attached to the PC there&#039;s a chance that a little faster startup will be when &amp;lt;code&amp;gt;-joystickprovider none &amp;lt;/code&amp;gt; is added to the command line.&lt;br /&gt;
&lt;br /&gt;
= Keys =&lt;br /&gt;
&lt;br /&gt;
Keys are emulated in two modes: to control MAME or completely dedicated to the emulated system. You can toggle between these two keyboard modes with ScrLk or Fn+delete under macOS.&lt;br /&gt;
&lt;br /&gt;
Some UI keys:&lt;br /&gt;
* F3 - soft reset&lt;br /&gt;
* Shift+F3 - hard reset&lt;br /&gt;
* F4 - sprites/tiles/font viewer (Enter, ], [)&lt;br /&gt;
* F5 - pause emulation&lt;br /&gt;
* F6 - save state&lt;br /&gt;
* F7 - load state&lt;br /&gt;
* Tab - emulator settings&lt;br /&gt;
* ~ - menu&lt;br /&gt;
* PgDwn (Linux) or Insert (Win) -- max speed (only while it&#039;s pressed; can be used e.g. to speed up boot)&lt;br /&gt;
* Esc - exit&lt;br /&gt;
* F12 - MF NMI&lt;br /&gt;
* F11 - DivMMC NMI&lt;br /&gt;
&lt;br /&gt;
= Changing the UI toggle key =&lt;br /&gt;
&lt;br /&gt;
Some laptops don&#039;t have a Scroll Lock key so you won&#039;t be able to exit MAME if you run it in full screen mode hence you will need to change the UI toggle key.&lt;br /&gt;
&lt;br /&gt;
Follow these steps to change the UI toggle key:&lt;br /&gt;
&lt;br /&gt;
* Run MAME without any command line arguments (except maybe -window) to open its GUI.&lt;br /&gt;
* Push TAB and enter the General Settings menu.&lt;br /&gt;
* Go to Input Assignments -&amp;gt; User Interface -&amp;gt; Toggle UI controls and select a new key. I use Right Alt / Alt GR.&lt;br /&gt;
* Return to Previous menu twice then choose Save Settings&lt;br /&gt;
&lt;br /&gt;
= Mounting SD card images under Linux =&lt;br /&gt;
&lt;br /&gt;
Under Linux you can use losetup to mount SD card images as loop devices which enables you to copy files to and from the image and perform other file management tasks as you would using any other filesystem.&lt;br /&gt;
&lt;br /&gt;
Run the following commands as the root user to mount an image called sn-emulator-22.10a.img under the /mnt directory:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;losetup --partscan --show --find cspect-next-2gb.img&lt;br /&gt;
mount /dev/loop0p1 /mnt/&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After you have finished modifying the SD card image, cd out of /mnt then unmount and detach the loopback device:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;umount /mnt/&lt;br /&gt;
losetup -D&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Creating a NextZXOS SD card image under Linux =&lt;br /&gt;
&lt;br /&gt;
Most users wanting to emulate the Next using MAME will be fine using a pre-built SD card image downloaded from the specnext website but the following guide is provided for anyone wanting to create a NextZXOS SD card image from scratch.&lt;br /&gt;
&lt;br /&gt;
Download the [https://www.specnext.com/latestdistro/ latest NextZXOS distribution zip file] (named something like sn-complete-WX.YZ.zip) and extract it into a new, empty directory.&lt;br /&gt;
&lt;br /&gt;
Create a disk image of at least 256 MB. The current complete NextZXOS distro requires at least 130 MB of disk space. This command will create a 256 MB SD card image, change the count value to make the image file as big as you want in megabytes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;dd if=/dev/zero of=NextZXOS.img bs=1M count=256&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The rest of the commands in this guide must be run as the root user or using sudo.&lt;br /&gt;
&lt;br /&gt;
You will need the dosfstools and parted packages, if you don&#039;t already have them installed. Debian and Ubuntu Linux users can install these using this apt command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;apt install dosfstools parted&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mount the SD card image loopback device:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;losetup --partscan --show --find NextZXOS.img&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Create a FAT32 partition:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;parted /dev/loop0 mklabel msdos&lt;br /&gt;
parted /dev/loop0 mkpart primary fat32 1MB 100%&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Format and mount the partition under /mnt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;mkfs.vfat -F 32 /dev/loop0p1&lt;br /&gt;
mount /dev/loop0p1 /mnt&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can now copy all of the files you extracted from sn-complete-WX.YZ.zip into /mnt.&lt;br /&gt;
&lt;br /&gt;
After copying the files, unmount and detach the loopback device (the SD card image):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;umount /mnt/&lt;br /&gt;
losetup -D&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Continuous Integration MAME Builds=&lt;br /&gt;
&lt;br /&gt;
MAME is updated on a release schedule, but due to the ongoing nature of development, including for the MAME Next machine, it can be sometimes useful to install a recent build, if it contains a new feature or bugfix you are interested in. Sometimes ongoing work is discussed on social media, like [https://discordapp.com/channels/556228195767156758/752197165891321886 Discord].&lt;br /&gt;
&lt;br /&gt;
Continuous Integration (CI) builds are available from both the [https://github.com/mamedev/mame/actions primary MAME] and [https://github.com/holub/mame/actions holub] github repos. Both are considered bleeding-edge, with the primary MAME repo slightly less so. MAME CI builds are available for Windows, linux and MacOS, and are updated automatically every time code is committed by a maintainer or pushed to the primary repo.&lt;br /&gt;
&lt;br /&gt;
To try out a CI build, do a fill MAME install from the [https://www.mamedev.org/release.html latest release] first, if you have not already done so. Then back up your main binary from its installation location - these are called something like &amp;lt;code&amp;gt;mame.exe&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;mame&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;mametiny&amp;lt;/code&amp;gt;. You can always restore these if the CI build doesn&#039;t work, or you don&#039;t like how it behaves.&lt;br /&gt;
&lt;br /&gt;
Then visit the one of the links above, and find a workflow run item for your platform - these are flagged as &amp;lt;code&amp;gt;CI (Windows)&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;CI (Linux)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;CI (macOS)&amp;lt;/code&amp;gt;. Click on it and find the Artifacts section at the bottom, then click the download button. Unzip the downloaded file and find the main binary (same name as above). Copy the main binary over the top of the original one in the install location, and run MAME the same way your were running it before. On Windows you may have to do an additional step of trusting the binary (Run Anyway).&lt;br /&gt;
&lt;br /&gt;
= More MAME links =&lt;br /&gt;
The source code is available [https://github.com/mamedev/mame/blob/master/src/mame/sinclair/specnext.cpp here.]&lt;br /&gt;
 &lt;br /&gt;
Report any issues with MAME on the [https://mametesters.org/ bugtracker].&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=MAME:Installing&amp;diff=41393</id>
		<title>MAME:Installing</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=MAME:Installing&amp;diff=41393"/>
		<updated>2025-11-15T22:56:08Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[https://www.mamedev.org/ MAME] (formerly an acronym of Multiple Arcade Machine Emulator) is a free and open-source emulator designed to emulate the hardware of arcade games, later expanded to include video game consoles, old computers and other systems in software on modern personal computers and other platforms.&lt;br /&gt;
&lt;br /&gt;
MAME supports The ZX Spectrum Next since version 0.267. Existing implementation is based on v3.02.01 core and implements most of the features.&lt;br /&gt;
&lt;br /&gt;
= Get =&lt;br /&gt;
The latest MAME version for Windows is available [https://www.mamedev.org/release.html here] and macOS builds can be downloaded [https://sdlmame.lngn.net/ from here.] For the MAME platform as a whole, check your package manager or [https://docs.mamedev.org/initialsetup/compilingmame.html build from sources].&lt;br /&gt;
&lt;br /&gt;
Linux users can install the latest stable version of MAME from the flatpak repositories by running:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;sudo flatpak install org.mamedev.MAME&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Use =&lt;br /&gt;
In order to run the Next (and any others) you need to acquire ROM dumps for the system.&lt;br /&gt;
In the case of the Next download [https://github.com/Threetwosevensixseven/NexCreator/raw/master/bootroms/tbblue.zip tbblue.zip] and put it into your MAME roms folder. Under Linux you can copy your MAME roms into &amp;lt;code&amp;gt;~/mame/roms&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
You also need an SD card image of [https://www.specnext.com/system-next22-10/ NextZXOS]. Some published images do not work with some emulators, but all images from https://zxnext.uk/hosted/#sd are now confirmed to work with both MAME and CSpect, including the official ones, including [https://zxnext.uk/hosted/index_files/hdfimages/cspect-next-2gb.zip this one] (the SD card image is the &amp;lt;code&amp;gt;cspect-next-2gb.img&amp;lt;/code&amp;gt; file within the zip file).&lt;br /&gt;
&lt;br /&gt;
The fastest way to run a machine with a desired configuration is from the command prompt. Most of the features are also available from MAME&#039;s UI, but that takes more time to configure.&lt;br /&gt;
Let&#039;s discover some useful options:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Use window and no mouse more till you get familiar with UI keys:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; mame tbblue -window -mouse_device none -hard /path/to/next-distribution.img&amp;lt;/pre&amp;gt;&lt;br /&gt;
To launch the Linux flatpak version using the same options:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; flatpak run org.mamedev.MAME tbblue -window -mouse_device none -hard /path/to/next-distribution.img&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Activate UI keys on startup:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -ui_active&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Don&#039;t show info popup on startup:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ...-skip_gameinfo&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;Run with debugger. If not requested on startup, you won&#039;t have access to it:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -debug&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Check [https://docs.mamedev.org/ official docs] for more advanced usage.&lt;br /&gt;
&lt;br /&gt;
Also, this combination of parameters enables the &amp;quot;crisp&amp;quot; pixels:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;mame -ui_active  -nounevenstretch -aspect 2:1 -video bgfx  -bgfx_screen_chains unfiltered -window -skip_gameinfo  -mouse_device none  tbblue -hard1 /path/to/next-distribution.img&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And if you don&#039;t need to use a joystick attached to the PC there&#039;s a chance that a little faster startup will be when &amp;lt;code&amp;gt;-joystickprovider none &amp;lt;/code&amp;gt; is added to the command line.&lt;br /&gt;
&lt;br /&gt;
= Keys =&lt;br /&gt;
&lt;br /&gt;
Keys are emulated in two modes: to control MAME or completely dedicated to the emulated system. You can toggle between these two keyboard modes with ScrLk or Fn+delete under macOS.&lt;br /&gt;
&lt;br /&gt;
Some UI keys:&lt;br /&gt;
* F3 - soft reset&lt;br /&gt;
* Shift+F3 - hard reset&lt;br /&gt;
* F4 - sprites/tiles/font viewer (Enter, ], [)&lt;br /&gt;
* F6 - save state&lt;br /&gt;
* F7 - load state&lt;br /&gt;
* Tab - emulator settings&lt;br /&gt;
* ~ - menu&lt;br /&gt;
* PgDwn (Linux) or Insert (Win) -- max speed (only while it&#039;s pressed; can be used e.g. to speed up boot)&lt;br /&gt;
* Esc - exit&lt;br /&gt;
* F12 - MF NMI&lt;br /&gt;
* F11 - DivMMC NMI&lt;br /&gt;
&lt;br /&gt;
= Changing the UI toggle key =&lt;br /&gt;
&lt;br /&gt;
Some laptops don&#039;t have a Scroll Lock key so you won&#039;t be able to exit MAME if you run it in full screen mode hence you will need to change the UI toggle key.&lt;br /&gt;
&lt;br /&gt;
Follow these steps to change the UI toggle key:&lt;br /&gt;
&lt;br /&gt;
* Run MAME without any command line arguments (except maybe -window) to open its GUI.&lt;br /&gt;
* Push TAB and enter the General Settings menu.&lt;br /&gt;
* Go to Input Assignments -&amp;gt; User Interface -&amp;gt; Toggle UI controls and select a new key. I use Right Alt / Alt GR.&lt;br /&gt;
* Return to Previous menu twice then choose Save Settings&lt;br /&gt;
&lt;br /&gt;
= Mounting SD card images under Linux =&lt;br /&gt;
&lt;br /&gt;
Under Linux you can use losetup to mount SD card images as loop devices which enables you to copy files to and from the image and perform other file management tasks as you would using any other filesystem.&lt;br /&gt;
&lt;br /&gt;
Run the following commands as the root user to mount an image called sn-emulator-22.10a.img under the /mnt directory:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;losetup --partscan --show --find cspect-next-2gb.img&lt;br /&gt;
mount /dev/loop0p1 /mnt/&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After you have finished modifying the SD card image, cd out of /mnt then unmount and detach the loopback device:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;umount /mnt/&lt;br /&gt;
losetup -D&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Creating a NextZXOS SD card image under Linux =&lt;br /&gt;
&lt;br /&gt;
Most users wanting to emulate the Next using MAME will be fine using a pre-built SD card image downloaded from the specnext website but the following guide is provided for anyone wanting to create a NextZXOS SD card image from scratch.&lt;br /&gt;
&lt;br /&gt;
Download the [https://www.specnext.com/latestdistro/ latest NextZXOS distribution zip file] (named something like sn-complete-WX.YZ.zip) and extract it into a new, empty directory.&lt;br /&gt;
&lt;br /&gt;
Create a disk image of at least 256 MB. The current complete NextZXOS distro requires at least 130 MB of disk space. This command will create a 256 MB SD card image, change the count value to make the image file as big as you want in megabytes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;dd if=/dev/zero of=NextZXOS.img bs=1M count=256&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The rest of the commands in this guide must be run as the root user or using sudo.&lt;br /&gt;
&lt;br /&gt;
You will need the dosfstools and parted packages, if you don&#039;t already have them installed. Debian and Ubuntu Linux users can install these using this apt command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;apt install dosfstools parted&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mount the SD card image loopback device:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;losetup --partscan --show --find NextZXOS.img&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Create a FAT32 partition:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;parted /dev/loop0 mklabel msdos&lt;br /&gt;
parted /dev/loop0 mkpart primary fat32 1MB 100%&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Format and mount the partition under /mnt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;mkfs.vfat -F 32 /dev/loop0p1&lt;br /&gt;
mount /dev/loop0p1 /mnt&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can now copy all of the files you extracted from sn-complete-WX.YZ.zip into /mnt.&lt;br /&gt;
&lt;br /&gt;
After copying the files, unmount and detach the loopback device (the SD card image):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;umount /mnt/&lt;br /&gt;
losetup -D&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Continuous Integration MAME Builds=&lt;br /&gt;
&lt;br /&gt;
MAME is updated on a release schedule, but due to the ongoing nature of development, including for the MAME Next machine, it can be sometimes useful to install a recent build, if it contains a new feature or bugfix you are interested in. Sometimes ongoing work is discussed on social media, like [https://discordapp.com/channels/556228195767156758/752197165891321886 Discord].&lt;br /&gt;
&lt;br /&gt;
Continuous Integration (CI) builds are available from both the [https://github.com/mamedev/mame/actions primary MAME] and [https://github.com/holub/mame/actions holub] github repos. Both are considered bleeding-edge, with the primary MAME repo slightly less so. MAME CI builds are available for Windows, linux and MacOS, and are updated automatically every time code is committed by a maintainer or pushed to the primary repo.&lt;br /&gt;
&lt;br /&gt;
To try out a CI build, do a fill MAME install from the [https://www.mamedev.org/release.html latest release] first, if you have not already done so. Then back up your main binary from its installation location - these are called something like &amp;lt;code&amp;gt;mame.exe&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;mame&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;mametiny&amp;lt;/code&amp;gt;. You can always restore these if the CI build doesn&#039;t work, or you don&#039;t like how it behaves.&lt;br /&gt;
&lt;br /&gt;
Then visit the one of the links above, and find a workflow run item for your platform - these are flagged as &amp;lt;code&amp;gt;CI (Windows)&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;CI (Linux)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;CI (macOS)&amp;lt;/code&amp;gt;. Click on it and find the Artifacts section at the bottom, then click the download button. Unzip the downloaded file and find the main binary (same name as above). Copy the main binary over the top of the original one in the install location, and run MAME the same way your were running it before. On Windows you may have to do an additional step of trusting the binary (Run Anyway).&lt;br /&gt;
&lt;br /&gt;
= More MAME links =&lt;br /&gt;
The source code is available [https://github.com/mamedev/mame/blob/master/src/mame/sinclair/specnext.cpp here.]&lt;br /&gt;
 &lt;br /&gt;
Report any issues with MAME on the [https://mametesters.org/ bugtracker].&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=Emulators&amp;diff=41392</id>
		<title>Emulators</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=Emulators&amp;diff=41392"/>
		<updated>2025-11-15T22:47:49Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
===== WARNING: =====&lt;br /&gt;
&lt;br /&gt;
The current Next emulators are work-in-progress, missing several features of real HW Next, and emulating other features in less than cycle-accurate way (which become a &amp;quot;norm&amp;quot; for classic ZX Spectrum after two decades of emulators development). The differences in results between real Next and CSpect or ZEsarUX are to be expected - as a developer test your SW also with real HW to find any problems early. It may also help to read the known-bugs pages to have some rough idea what works and how accurately. There&#039;re also multiple test-suites and free games and demos which you can try to go through and compare the emulator output with real machine, to get familiar with the differences and adjust your workflow and expectations.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Also make sure to explore the command line options and configuration of each emulator, as there are multiple ways how to run them with different fidelity of emulation. When in doubt, you are welcome to join the official ZX Spectrum Next discord chat and ask for help at #emulator-help channel.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Currently the most UI and performance friendly emulator seems to be #CSpect, the most accurate and performant emulator is MAME.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
!Name||Author||Known bugs||Description||OS||Source||Maintained&lt;br /&gt;
|-&lt;br /&gt;
|[https://mdf200.itch.io/cspect CSpect]||[https://lemmings.info/about/ Mike Dailly]||[[CSpect:known bugs|List]]||Emulates many features of the Next and includes a fully featured debugger, complete with 24bit breakpoints and an assembler||Windows ([https://lemmings.info/installing-cspect-on-a-mac/ mac]/[[Development_Tools:Linux_setup##CSpect_emulator|linux]] with mono - mostly works)||No||[https://www.patreon.com/posts/crash-and-cspect-143597332 Statement of maintenance and support]&lt;br /&gt;
|-&lt;br /&gt;
|[https://www.mamedev.org/ MAME]||[https://github.com/holub holub] (Next), many contributors (MAME)||[[MAME:known bugs|List]]‎||Mature multi-system emulator with relatively recent Next support. See [[MAME:Installing|installation notes]].||Any||[https://github.com/mamedev/mame Yes]||Yes&lt;br /&gt;
|-&lt;br /&gt;
|[https://gitlab.com/garrylancaster/zenext ZENext]||[https://github.com/chernandezba César Hernández Bañó], [https://gitlab.com/garrylancaster Garry Lancaster]|| |||ZX Next-only fork of ZEsarUX emulating most of the core 3.1.10 features to make it run NextZXOS 2.07 (and possibly 2.08/2.09) (missing some features like CTC timers).||Any||[https://gitlab.com/garrylancaster/zenext Yes]||Occasionally&lt;br /&gt;
|-&lt;br /&gt;
|[https://github.com/chernandezba/zesarux/releases ZEsarUX]||César Hernández Bañó|||[[ZEsarUX:known bugs|List]]||A full feature emulator including a debugger - sometimes updated to support Next (TBBlue)||Any||[https://github.com/chernandezba/zesarux Yes]||Yes&lt;br /&gt;
|-&lt;br /&gt;
|[https://github.com/ped7g/zesarux/tree/tbblue_small_fixes2 ZESERUse]||César Hernández Bañó, [https://github.com/ped7g Peter Helcmanovsky]||[[ZESERUse:known bugs|List]]||Fork of older ZEsarUX 8.2 with improved emulation accuracy of (rather old) core 3.1.5||Any||[https://github.com/ped7g/zesarux/tree/tbblue_small_fixes2 Yes]||Rarely&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.desdes.com/products/oldfiles/zeus.htm Zeus]||[https://www.desdes.com/ Simon Brattel]|| || A PC cross-assembler which includes an IDE and Spectrum 48/128/+2/+3 emulator. Includes support for Next MMU banking, sprites and UART only, with remote debugging on Next hardware.||Windows||No||No&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=MAME:Installing&amp;diff=41391</id>
		<title>MAME:Installing</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=MAME:Installing&amp;diff=41391"/>
		<updated>2025-11-15T22:44:29Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: .typos&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[https://www.mamedev.org/ MAME] (formerly an acronym of Multiple Arcade Machine Emulator) is a free and open-source emulator designed to emulate the hardware of arcade games, later expanded to include video game consoles, old computers and other systems in software on modern personal computers and other platforms.&lt;br /&gt;
&lt;br /&gt;
MAME supports The ZX Spectrum Next since version 0.267. Existing implementation is based on v3.02.01 core and implements most of the features.&lt;br /&gt;
&lt;br /&gt;
= Get =&lt;br /&gt;
The latest MAME version for Windows is available [https://www.mamedev.org/release.html here] and macOS builds can be downloaded [https://sdlmame.lngn.net/ from here.] For the MAME platform as a whole, check your package manager or [https://docs.mamedev.org/initialsetup/compilingmame.html build from sources].&lt;br /&gt;
&lt;br /&gt;
Linux users can install the latest stable version of MAME from the flatpak repositories by running:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;sudo flatpak install org.mamedev.MAME&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Use =&lt;br /&gt;
In order to run the Next (and any others) you need to acquire rom dumps for the system.&lt;br /&gt;
In the case of the Next download [https://github.com/Threetwosevensixseven/NexCreator/raw/master/bootroms/tbblue.zip tbblue.zip] and put it into your MAME roms folder. Under Linux you can copy your MAME roms into &amp;lt;code&amp;gt;~/mame/roms&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
You also need an SD card image of [https://www.specnext.com/system-next22-10/ NextZXOS]. Some published images do not work with some emulators, but all images from https://zxnext.uk/hosted/#sd are now confirmed to work with both MAME and CSpect, including the official ones, including [https://zxnext.uk/hosted/index_files/hdfimages/cspect-next-2gb.zip this one] (the SD card image is the &amp;lt;code&amp;gt;cspect-next-2gb.img&amp;lt;/code&amp;gt; file within the zip file).&lt;br /&gt;
&lt;br /&gt;
The fastest way to run a machine with a desired configuration is from the command prompt. Most of the features are also available from MAME&#039;s UI, but that takes more time to configure.&lt;br /&gt;
Let&#039;s discover some useful options:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Use window and no mouse more till you get familiar with UI keys:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; mame tbblue -window -mouse_device none -hard /path/to/next-distribution.img&amp;lt;/pre&amp;gt;&lt;br /&gt;
To launch the Linux flatpak version using the same options:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; flatpak run org.mamedev.MAME tbblue -window -mouse_device none -hard /path/to/next-distribution.img&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Activate UI keys on startup:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -ui_active&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Don&#039;t show info popup on startup:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ...-skip_gameinfo&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;Run with debugger. If not requested on startup, you won&#039;t have access to it:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;gt; ... -debug&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Check [https://docs.mamedev.org/ official docs] for more advanced usage.&lt;br /&gt;
&lt;br /&gt;
Also, this combination of parameters enables the &amp;quot;crisp&amp;quot; pixels:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;mame -ui_active  -nounevenstretch -aspect 2:1 -video bgfx  -bgfx_screen_chains unfiltered -window -skip_gameinfo  -mouse_device none  tbblue -hard1 /path/to/next-distribution.img&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And if you don&#039;t need to use a joystick attached to the PC there&#039;s a chance that a little faster startup will be when &amp;lt;code&amp;gt;-joystickprovider none &amp;lt;/code&amp;gt; is added to the command line.&lt;br /&gt;
&lt;br /&gt;
= Keys =&lt;br /&gt;
&lt;br /&gt;
Keys are emulated in two modes: to control MAME or completely dedicated to the emulated system. You can toggle between these two keyboard modes with ScrLk or Fn+delete under macOS.&lt;br /&gt;
&lt;br /&gt;
Some UI keys:&lt;br /&gt;
* F3 - soft reset&lt;br /&gt;
* Shift+F3 - hard reset&lt;br /&gt;
* F4 - sprites/tiles/font viewer (Enter, ], [)&lt;br /&gt;
* F6 - save state&lt;br /&gt;
* F7 - load state&lt;br /&gt;
* Tab - emulator settings&lt;br /&gt;
* ~ - menu&lt;br /&gt;
* PgDwn (Linux) or Insert (Win) -- max speed (only while it&#039;s pressed; can be used e.g. to speed up boot)&lt;br /&gt;
* Esc - exit&lt;br /&gt;
* F12 - MF NMI&lt;br /&gt;
* F11 - DivMMC NMI&lt;br /&gt;
&lt;br /&gt;
= Changing the UI toggle key =&lt;br /&gt;
&lt;br /&gt;
Some laptops don&#039;t have a Scroll Lock key so you won&#039;t be able to exit MAME if you run it in full screen mode hence you will need to change the UI toggle key.&lt;br /&gt;
&lt;br /&gt;
Follow these steps to change the UI toggle key:&lt;br /&gt;
&lt;br /&gt;
* Run MAME without any command line arguments (except maybe -window) to open its GUI.&lt;br /&gt;
* Push TAB and enter the General Settings menu.&lt;br /&gt;
* Go to Input Assignments -&amp;gt; User Interface -&amp;gt; Toggle UI controls and select a new key. I use Right Alt / Alt GR.&lt;br /&gt;
* Return to Previous menu twice then choose Save Settings&lt;br /&gt;
&lt;br /&gt;
= Mounting SD card images under Linux =&lt;br /&gt;
&lt;br /&gt;
Under Linux you can use losetup to mount SD card images as loop devices which enables you to copy files to and from the image and perform other file management tasks as you would using any other filesystem.&lt;br /&gt;
&lt;br /&gt;
Run the following commands as the root user to mount an image called sn-emulator-22.10a.img under the /mnt directory:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;losetup --partscan --show --find cspect-next-2gb.img&lt;br /&gt;
mount /dev/loop0p1 /mnt/&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After you have finished modifying the SD card image, cd out of /mnt then unmount and detach the loopback device:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;umount /mnt/&lt;br /&gt;
losetup -D&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Creating a NextZXOS SD card image under Linux =&lt;br /&gt;
&lt;br /&gt;
Most users wanting to emulate the Next using MAME will be fine using a pre-built SD card image downloaded from the specnext website but the following guide is provided for anyone wanting to create a NextZXOS SD card image from scratch.&lt;br /&gt;
&lt;br /&gt;
Download the [https://www.specnext.com/latestdistro/ latest NextZXOS distribution zip file] (named something like sn-complete-WX.YZ.zip) and extract it into a new, empty directory.&lt;br /&gt;
&lt;br /&gt;
Create a disk image of at least 256 MB. The current complete NextZXOS distro requires at least 130 MB of disk space. This command will create a 256 MB SD card image, change the count value to make the image file as big as you want in megabytes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;dd if=/dev/zero of=NextZXOS.img bs=1M count=256&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The rest of the commands in this guide must be run as the root user or using sudo.&lt;br /&gt;
&lt;br /&gt;
You will need the dosfstools and parted packages, if you don&#039;t already have them installed. Debian and Ubuntu Linux users can install these using this apt command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;apt install dosfstools parted&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mount the SD card image loopback device:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;losetup --partscan --show --find NextZXOS.img&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Create a FAT32 partition:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;parted /dev/loop0 mklabel msdos&lt;br /&gt;
parted /dev/loop0 mkpart primary fat32 1MB 100%&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Format and mount the partition under /mnt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;mkfs.vfat -F 32 /dev/loop0p1&lt;br /&gt;
mount /dev/loop0p1 /mnt&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can now copy all of the files you extracted from sn-complete-WX.YZ.zip into /mnt.&lt;br /&gt;
&lt;br /&gt;
After copying the files, unmount and detach the loopback device (the SD card image):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;umount /mnt/&lt;br /&gt;
losetup -D&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Continuous Integration MAME Builds=&lt;br /&gt;
&lt;br /&gt;
MAME is updated on a release schedule, but due to the ongoing nature of development, including for the MAME Next machine, it can be sometimes useful to install a recent build, if it contains a new feature or bugfix you are interested in. Sometimes ongoing work is discussed on social media, like [https://discordapp.com/channels/556228195767156758/752197165891321886 Discord].&lt;br /&gt;
&lt;br /&gt;
Continuous Integration (CI) builds are available from both the [https://github.com/mamedev/mame/actions primary MAME] and [https://github.com/holub/mame/actions holub] github repos. Both are considered bleeding-edge, with the primary MAME repo slightly less so. MAME CI builds are available for Windows, linux and MacOS, and are updated automatically every time code is committed by a maintainer or pushed to the primary repo.&lt;br /&gt;
&lt;br /&gt;
To try out a CI build, do a fill MAME install from the [https://www.mamedev.org/release.html latest release] first, if you have not already done so. Then back up your main binary from its installation location - these are called something like &amp;lt;code&amp;gt;mame.exe&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;mame&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;mametiny&amp;lt;/code&amp;gt;. You can always restore these if the CI build doesn&#039;t work, or you don&#039;t like how it behaves.&lt;br /&gt;
&lt;br /&gt;
Then visit the one of the links above, and find a workflow run item for your platform - these are flagged as &amp;lt;code&amp;gt;CI (Windows)&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;CI (Linux)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;CI (macOS)&amp;lt;/code&amp;gt;. Click on it and find the Artifacts section at the bottom, then click the download button. Unzip the downloaded file and find the main binary (same name as above). Copy the main binary over the top of the original one in the install location, and run MAME the same way your were running it before. On Windows you may have to do an additional step of trusting the binary (Run Anyway).&lt;br /&gt;
&lt;br /&gt;
= More MAME links =&lt;br /&gt;
The source code is available [https://github.com/mamedev/mame/blob/master/src/mame/sinclair/specnext.cpp here.]&lt;br /&gt;
 &lt;br /&gt;
Report any issues with MAME on the [https://mametesters.org/ bugtracker].&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=Emulators&amp;diff=41348</id>
		<title>Emulators</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=Emulators&amp;diff=41348"/>
		<updated>2025-11-11T18:01:20Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: Refresh some outdated info and rewording some to make it more concise (dropping details which are useless now, since things like ZESERUse is hopelessly out of date)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
===== WARNING: =====&lt;br /&gt;
&lt;br /&gt;
The current Next emulators are work-in-progress, missing several features of real HW Next, and emulating other features in less than cycle-accurate way (which become a &amp;quot;norm&amp;quot; for classic ZX Spectrum after two decades of emulators development). The differences in results between real Next and CSpect or ZEsarUX are to be expected - as a developer test your SW also with real HW to find any problems early. It may also help to read the known-bugs pages to have some rough idea what works and how accurately. There&#039;re also multiple test-suites and free games and demos which you can try to go through and compare the emulator output with real machine, to get familiar with the differences and adjust your workflow and expectations.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Also make sure to explore the command line options and configuration of each emulator, as there are multiple ways how to run them with different fidelity of emulation. When in doubt, you are welcome to join the official ZX Spectrum Next discord chat and ask for help at #emulator-help channel.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Currently the most UI and performance friendly emulator seems to be #CSpect, the most accurate emulator is MAME.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
!Name||Author||Known bugs||Description||OS||Source||Maintained&lt;br /&gt;
|-&lt;br /&gt;
|CSpect||[https://lemmings.info/about/ Mike Dailly]||[[CSpect:known bugs|List]]||Emulates many features of the Next and includes a fully featured debugger, complete with 24bit breakpoints and an assembler||Windows ([https://lemmings.info/installing-cspect-on-a-mac/ mac]/[[Development_Tools:Linux_setup##CSpect_emulator|linux]] with mono - mostly works)||No||[https://www.patreon.com/posts/change-of-143208075 Yes, privately]&lt;br /&gt;
|-&lt;br /&gt;
|[https://www.mamedev.org/ MAME]||[https://github.com/holub holub] (Next), many contributors (MAME)||[[MAME:known bugs|List]]‎||Mature multi-system emulator with relatively recent Next support. See [[MAME:Installing|installation notes]].||Any||[https://github.com/mamedev/mame Yes] ([https://github.com/holub/mame bleeding-edge Next])||Yes&lt;br /&gt;
|-&lt;br /&gt;
|[https://gitlab.com/garrylancaster/zenext ZENext]||[https://github.com/chernandezba César Hernández Bañó], [https://gitlab.com/garrylancaster Garry Lancaster]|| |||ZX Next-only fork of ZEsarUX emulating most of the core 3.1.10 features to make it run NextZXOS 2.07 (and possibly 2.08/2.09) (missing some features like CTC timers).||Any||[https://gitlab.com/garrylancaster/zenext Yes]||Occasionally&lt;br /&gt;
|-&lt;br /&gt;
|[https://github.com/chernandezba/zesarux/releases ZEsarUX]||César Hernández Bañó|||[[ZEsarUX:known bugs|List]]||A full feature emulator including a debugger - sometimes updated to support Next (TBBlue)||Any||[https://github.com/chernandezba/zesarux Yes]||Yes&lt;br /&gt;
|-&lt;br /&gt;
|[https://github.com/ped7g/zesarux/tree/tbblue_small_fixes2 ZESERUse]||César Hernández Bañó, [https://github.com/ped7g Peter Helcmanovsky]||[[ZESERUse:known bugs|List]]||Fork of older ZEsarUX 8.2 with improved emulation accuracy of (rather old) core 3.1.5||Any||[https://github.com/ped7g/zesarux/tree/tbblue_small_fixes2 Yes]||Rarely&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.desdes.com/products/oldfiles/zeus.htm Zeus]||[https://www.desdes.com/ Simon Brattel]|| || A PC cross-assembler which includes an IDE and Spectrum 48/128/+2/+3 emulator. Includes support for Next MMU banking, sprites and UART only, with remote debugging on Next hardware.||Windows||No||No&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=Copper&amp;diff=41142</id>
		<title>Copper</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=Copper&amp;diff=41142"/>
		<updated>2025-10-10T11:56:59Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The &#039;&#039;&#039;Copper&#039;&#039;&#039; is a simple programmed system which allows certain [[Board feature control|Next Registers]] to be altered automatically at certain scanline positions. &lt;br /&gt;
&lt;br /&gt;
&amp;quot;Copper&amp;quot; is a strangulation of &amp;quot;co-processor&amp;quot; and is a term taken from the Amiga which had a similar function. The copper on the Spectrum Next is not associated with the [[RPi0 Acceleration|Raspberry Pi &#039;coprocessor&#039;]].&lt;br /&gt;
&lt;br /&gt;
A program is uploaded to the Copper by sending it, byte by byte, to {{NextRegNo|$60}}. Each Copper instruction is 16 bits wide and there are 2 opcodes with a single bit in an instruction determines the operation and two special case opcodes. In total the four operations are:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Opcode !! Bit pattern !! Effect&lt;br /&gt;
|-&lt;br /&gt;
| WAIT || %1hhhhhhv %vvvvvvvv || Wait for raster line v (0-311) and horizontal position h*8 (h is 0-55) (duration 1 CLOCK)&lt;br /&gt;
|-&lt;br /&gt;
| MOVE || %0rrrrrrr %vvvvvvvv || Write value &#039;&#039;&#039;v&#039;&#039;&#039; to Next register &#039;&#039;&#039;r&#039;&#039;&#039; (duration 2 CLOCKS)&lt;br /&gt;
|-&lt;br /&gt;
| NOOP || %00000000 %00000000 || Special case of &amp;quot;value 0 to port 0&amp;quot; works as &amp;quot;no operation&amp;quot; (duration 1 CLOCK)&lt;br /&gt;
|-&lt;br /&gt;
| HALT || %11111111 %11111111 || Special case of &amp;quot;WAIT 63,511&amp;quot; works as &amp;quot;halt&amp;quot; instruction&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The copper&#039;s program storage is 2k big; since each instruction is 2 bytes it can store exactly 1024 instructions, numbered 0-1023. The copper is controlled by a word accessed through Next Registers {{NextRegNo|$61}} and {{NextRegNo|$62}}. The internal &amp;quot;program counter&amp;quot; (&#039;&#039;&#039;CPC&#039;&#039;&#039;) has 10 bits (0-1023), auto-incrementing it after each instruction, wrapping around after last one back to first one.&lt;br /&gt;
&lt;br /&gt;
The copper control word has the structure: %cc000iii %iiiiiiii. &#039;&#039;&#039;I&#039;&#039;&#039; is the storage position (0-2047) (for writing instructions with {{NextRegNo|$60}}), and &#039;&#039;&#039;c&#039;&#039;&#039; is used to set the behaviour mode of the copper, as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! C bits !! Effect&lt;br /&gt;
|-&lt;br /&gt;
| %00 || STOP, copper does nothing (CPC keeps its current value)&lt;br /&gt;
|-&lt;br /&gt;
| %01 || reset CPC to 0, then START&lt;br /&gt;
|-&lt;br /&gt;
| %10 || START (resumes from current CPC)&lt;br /&gt;
|-&lt;br /&gt;
| %11 || reset CPC to 0, then START; Also VBLANK does reset CPC to 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
When &#039;&#039;&#039;c&#039;&#039;&#039; bits are identical to previously written value, the control mode is ignored, and only write-index &#039;&#039;&#039;I&#039;&#039;&#039; is modified.&lt;br /&gt;
&lt;br /&gt;
If you don&#039;t want the copper program to loop infinitely, then you can mark the &amp;quot;end&amp;quot; of the copper program by waiting for a line higher than 311 (&amp;quot;HALT&amp;quot; instruction). Since these lines will never be reached, the copper will essentially halt until reset.&lt;br /&gt;
&lt;br /&gt;
The precise timing and many more details are currently documented in distribution file [https://gitlab.com/thesmog358/tbblue/blob/a0d25589bd28b05c510e528332bcd192bc414ebb/docs/extra-hw/copper/COPPER-v0.1c.TXT &amp;quot;/docs/extra-hw/copper/COPPER-v0.1c.TXT&amp;quot;].&lt;br /&gt;
&lt;br /&gt;
(core 2.0) the copper code is executed at 14MHz, and the COPPER-v0.1c.TXT document above describes timing of the core 2.0.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(core 3.0) the copper code is executed at 28MHz, the precise timing is not documented yet&lt;br /&gt;
&lt;br /&gt;
From practical test (with the Swedish-flags copper test) the coordinates for WAIT are identical, MOVE is twice as fast (flags are half of original width because each pixel is created by single MOVE instruction).&lt;br /&gt;
&lt;br /&gt;
Important values affecting pixel display are now sampled at the same moment when the pixel is drawn (no test yet to describe what does that mean at sub-pixel accuracy terms and in which order the copper MOVEs should be done with what kind of lead in case you want to set for example 6 different display-affecting registers, by theoretical approach of single MOVE taking half-pixel width you should start precisely 3 pixels ahead of the edge where all values should be set, but YMMV) (overall it&#039;s probably much wiser to avoid situations where you need sub-pixel precision, or test with the real board heavily)&lt;br /&gt;
&lt;br /&gt;
Extra notes based on discussion with AA at Next discord:&amp;lt;br&amp;gt;&lt;br /&gt;
The copper is 16-bit:&lt;br /&gt;
* it fetches its 16-bit instruction in 1 T (16b atomic fetch from copper code memory) and executes it&lt;br /&gt;
* NOOP (alias MOVE without writing nextreg) takes thus 1 T in total&lt;br /&gt;
* MOVE with writing nextreg is finished in first T state, but then there is 1 T delay to not 100% occupy nextreg logic (starving CPU/DMA of access). So MOVE instruction takes 2 T in total and nextreg reads new value 2 T after MOVE execution.&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=Copper&amp;diff=41141</id>
		<title>Copper</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=Copper&amp;diff=41141"/>
		<updated>2025-10-10T11:53:28Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The &#039;&#039;&#039;Copper&#039;&#039;&#039; is a simple programmed system which allows certain [[Board feature control|Next Registers]] to be altered automatically at certain scanline positions. &lt;br /&gt;
&lt;br /&gt;
&amp;quot;Copper&amp;quot; is a strangulation of &amp;quot;co-processor&amp;quot; and is a term taken from the Amiga which had a similar function. The copper on the Spectrum Next is not associated with the [[RPi0 Acceleration|Raspberry Pi &#039;coprocessor&#039;]].&lt;br /&gt;
&lt;br /&gt;
A program is uploaded to the Copper by sending it, byte by byte, to {{NextRegNo|$60}}. Each Copper instruction is 16 bits wide and there are 2 opcodes with a single bit in an instruction determines the operation and two special case opcodes. In total the four operations are:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Opcode !! Bit pattern !! Effect&lt;br /&gt;
|-&lt;br /&gt;
| WAIT || %1hhhhhhv %vvvvvvvv || Wait for raster line v (0-311) and horizontal position h*8 (h is 0-55) (duration 1 CLOCK)&lt;br /&gt;
|-&lt;br /&gt;
| MOVE || %0rrrrrrr %vvvvvvvv || Write value &#039;&#039;&#039;v&#039;&#039;&#039; to Next register &#039;&#039;&#039;r&#039;&#039;&#039; (duration 2 CLOCKS)&lt;br /&gt;
|-&lt;br /&gt;
| NOOP || %00000000 %00000000 || Special case of &amp;quot;value 0 to port 0&amp;quot; works as &amp;quot;no operation&amp;quot; (duration 1 CLOCK)&lt;br /&gt;
|-&lt;br /&gt;
| HALT || %11111111 %11111111 || Special case of &amp;quot;WAIT 63,511&amp;quot; works as &amp;quot;halt&amp;quot; instruction&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The copper&#039;s program storage is 2k big; since each instruction is 2 bytes it can store exactly 1024 instructions, numbered 0-1023. The copper is controlled by a word accessed through Next Registers {{NextRegNo|$61}} and {{NextRegNo|$62}}. The internal &amp;quot;program counter&amp;quot; (&#039;&#039;&#039;CPC&#039;&#039;&#039;) has 10 bits (0-1023), auto-incrementing it after each instruction, wrapping around after last one back to first one.&lt;br /&gt;
&lt;br /&gt;
The copper control word has the structure: %cc000iii %iiiiiiii. &#039;&#039;&#039;I&#039;&#039;&#039; is the storage position (0-2047) (for writing instructions with {{NextRegNo|$60}}), and &#039;&#039;&#039;c&#039;&#039;&#039; is used to set the behaviour mode of the copper, as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! C bits !! Effect&lt;br /&gt;
|-&lt;br /&gt;
| %00 || STOP, copper does nothing (CPC keeps its current value)&lt;br /&gt;
|-&lt;br /&gt;
| %01 || reset CPC to 0, then START&lt;br /&gt;
|-&lt;br /&gt;
| %10 || START (resumes from current CPC)&lt;br /&gt;
|-&lt;br /&gt;
| %11 || reset CPC to 0, then START; Also VBLANK does reset CPC to 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
When &#039;&#039;&#039;c&#039;&#039;&#039; bits are identical to previously written value, the control mode is ignored, and only write-index &#039;&#039;&#039;I&#039;&#039;&#039; is modified.&lt;br /&gt;
&lt;br /&gt;
If you don&#039;t want the copper program to loop infinitely, then you can mark the &amp;quot;end&amp;quot; of the copper program by waiting for a line higher than 311 (&amp;quot;HALT&amp;quot; instruction). Since these lines will never be reached, the copper will essentially halt until reset.&lt;br /&gt;
&lt;br /&gt;
The precise timing and many more details are currently documented in distribution file [https://gitlab.com/thesmog358/tbblue/blob/a0d25589bd28b05c510e528332bcd192bc414ebb/docs/extra-hw/copper/COPPER-v0.1c.TXT &amp;quot;/docs/extra-hw/copper/COPPER-v0.1c.TXT&amp;quot;].&lt;br /&gt;
&lt;br /&gt;
(core 2.0) the copper code is executed at 14MHz, and the COPPER-v0.1c.TXT document above describes timing of the core2.0.&lt;br /&gt;
(core 3.0) the copper code is executed at 28MHz, the precise timing is not documented yet&lt;br /&gt;
&lt;br /&gt;
From practical test (with the Swedish-flags copper test) the coordinates for WAIT are identical, MOVE is twice as fast (flags are half of original width because each pixel is created by single MOVE instruction).&lt;br /&gt;
&lt;br /&gt;
Important values affecting pixel display are now sampled at the same moment when the pixel is drawn (no test yet to describe what does that mean at sub-pixel accuracy terms and in which order the copper MOVEs should be done with what kind of lead in case you want to set for example 6 different display-affecting registers, by theoretical approach of single MOVE taking half-pixel width you should start precisely 3 pixels ahead of the edge where all values should be set, but YMMV) (overall it&#039;s probably much wiser to avoid situations where you need sub-pixel precision, or test with the real board heavily)&lt;br /&gt;
&lt;br /&gt;
Extra notes based on discussion with AA at Next discord:&amp;lt;br&amp;gt;&lt;br /&gt;
The copper is 16-bit:&lt;br /&gt;
* it fetches its 16-bit instruction in 1 T (16b atomic fetch from copper code memory) and executes it&lt;br /&gt;
* NOOP (alias MOVE without writing nextreg) takes thus 1 T in total&lt;br /&gt;
* MOVE with writing nextreg is finished in first T state, but then there is 1 T delay to not 100% occupy nextreg logic (starving CPU/DMA of access). So MOVE instruction takes 2 T in total and nextreg reads new value 2 T after MOVE execution.&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=Copper&amp;diff=41140</id>
		<title>Copper</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=Copper&amp;diff=41140"/>
		<updated>2025-10-10T10:05:53Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The &#039;&#039;&#039;Copper&#039;&#039;&#039; is a simple programmed system which allows certain [[Board feature control|Next Registers]] to be altered automatically at certain scanline positions. &lt;br /&gt;
&lt;br /&gt;
&amp;quot;Copper&amp;quot; is a strangulation of &amp;quot;co-processor&amp;quot; and is a term taken from the Amiga which had a similar function. The copper on the Spectrum Next is not associated with the [[RPi0 Acceleration|Raspberry Pi &#039;coprocessor&#039;]].&lt;br /&gt;
&lt;br /&gt;
A program is uploaded to the Copper by sending it, byte by byte, to {{NextRegNo|$60}}. Each Copper instruction is 16 bits wide and there are 2 opcodes with a single bit in an instruction determines the operation and two special case opcodes. In total the four operations are:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Opcode !! Bit pattern !! Effect&lt;br /&gt;
|-&lt;br /&gt;
| WAIT || %1hhhhhhv %vvvvvvvv || Wait for raster line v (0-311) and horizontal position h*8 (h is 0-55) (duration 1 CLOCK)&lt;br /&gt;
|-&lt;br /&gt;
| MOVE || %0rrrrrrr %vvvvvvvv || Write value &#039;&#039;&#039;v&#039;&#039;&#039; to Next register &#039;&#039;&#039;r&#039;&#039;&#039; (duration 2 CLOCKS)&lt;br /&gt;
|-&lt;br /&gt;
| NOOP || %00000000 %00000000 || Special case of &amp;quot;value 0 to port 0&amp;quot; works as &amp;quot;no operation&amp;quot; (duration 1 CLOCK)&lt;br /&gt;
|-&lt;br /&gt;
| HALT || %11111111 %11111111 || Special case of &amp;quot;WAIT 63,511&amp;quot; works as &amp;quot;halt&amp;quot; instruction&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The copper&#039;s program storage is 2k big; since each instruction is 2 bytes it can store exactly 1024 instructions, numbered 0-1023. The copper is controlled by a word accessed through Next Registers {{NextRegNo|$61}} and {{NextRegNo|$62}}. The internal &amp;quot;program counter&amp;quot; (&#039;&#039;&#039;CPC&#039;&#039;&#039;) has 10 bits (0-1023), auto-incrementing it after each instruction, wrapping around after last one back to first one.&lt;br /&gt;
&lt;br /&gt;
The copper control word has the structure: %cc000iii %iiiiiiii. &#039;&#039;&#039;I&#039;&#039;&#039; is the storage position (0-2047) (for writing instructions with {{NextRegNo|$60}}), and &#039;&#039;&#039;c&#039;&#039;&#039; is used to set the behaviour mode of the copper, as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! C bits !! Effect&lt;br /&gt;
|-&lt;br /&gt;
| %00 || STOP, copper does nothing (CPC keeps its current value)&lt;br /&gt;
|-&lt;br /&gt;
| %01 || reset CPC to 0, then START&lt;br /&gt;
|-&lt;br /&gt;
| %10 || START (resumes from current CPC)&lt;br /&gt;
|-&lt;br /&gt;
| %11 || reset CPC to 0, then START; Also VBLANK does reset CPC to 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
When &#039;&#039;&#039;c&#039;&#039;&#039; bits are identical to previously written value, the control mode is ignored, and only write-index &#039;&#039;&#039;I&#039;&#039;&#039; is modified.&lt;br /&gt;
&lt;br /&gt;
If you don&#039;t want the copper program to loop infinitely, then you can mark the &amp;quot;end&amp;quot; of the copper program by waiting for a line higher than 311 (&amp;quot;HALT&amp;quot; instruction). Since these lines will never be reached, the copper will essentially halt until reset.&lt;br /&gt;
&lt;br /&gt;
The precise timing and many more details are currently documented in distribution file [https://gitlab.com/thesmog358/tbblue/blob/a0d25589bd28b05c510e528332bcd192bc414ebb/docs/extra-hw/copper/COPPER-v0.1c.TXT &amp;quot;/docs/extra-hw/copper/COPPER-v0.1c.TXT&amp;quot;].&lt;br /&gt;
&lt;br /&gt;
(core 2.0) the copper code is executed at 14MHz, and the COPPER-v0.1c.TXT document above describes timing of the core2.0.&lt;br /&gt;
(core 3.0) the copper code is executed at 28MHz, the precise timing is not documented yet&lt;br /&gt;
&lt;br /&gt;
From practical test (with the Swedish-flags copper test) the coordinates for WAIT are identical, MOVE is twice as fast (flags are half of original width because each pixel is created by single MOVE instruction).&lt;br /&gt;
&lt;br /&gt;
Important values affecting pixel display are now sampled at the same moment when the pixel is drawn (no test yet to describe what does that mean at sub-pixel accuracy terms and in which order the copper MOVEs should be done with what kind of lead in case you want to set for example 6 different display-affecting registers, by theoretical approach of single MOVE taking half-pixel width you should start precisely 3 pixels ahead of the edge where all values should be set, but YMMV) (overall it&#039;s probably much wiser to avoid situations where you need sub-pixel precision, or test with the real board heavily)&lt;br /&gt;
&lt;br /&gt;
Extra notes based on discussion with AA at Next discord:&lt;br /&gt;
The copper is 16-bit :&lt;br /&gt;
- it fetches its 16-bit instruction in 1 T (16b atomic fetch from copper code memory) and executes it&lt;br /&gt;
- NOOP (alias MOVE without writing nextreg) takes thus 1 T in total&lt;br /&gt;
- MOVE with writing nextreg is finished in first T state, but then there is 1 T delay to not 100% occupy nextreg logic (starving CPU/DMA of access). So MOVE instruction takes 2 T in total and nextreg reads new value 2 T after MOVE execution.&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=Copper&amp;diff=41139</id>
		<title>Copper</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=Copper&amp;diff=41139"/>
		<updated>2025-10-10T00:45:17Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The &#039;&#039;&#039;Copper&#039;&#039;&#039; is a simple programmed system which allows certain [[Board feature control|Next Registers]] to be altered automatically at certain scanline positions. &lt;br /&gt;
&lt;br /&gt;
&amp;quot;Copper&amp;quot; is a strangulation of &amp;quot;co-processor&amp;quot; and is a term taken from the Amiga which had a similar function. The copper on the Spectrum Next is not associated with the [[RPi0 Acceleration|Raspberry Pi &#039;coprocessor&#039;]].&lt;br /&gt;
&lt;br /&gt;
A program is uploaded to the Copper by sending it, byte by byte, to {{NextRegNo|$60}}. Each Copper instruction is 16 bits wide and there are 2 opcodes with a single bit in an instruction determines the operation and two special case opcodes. In total the four operations are:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Opcode !! Bit pattern !! Effect&lt;br /&gt;
|-&lt;br /&gt;
| WAIT || %1hhhhhhv %vvvvvvvv || Wait for raster line v (0-311) and horizontal position h*8 (h is 0-55) (duration 1 CLOCK)&lt;br /&gt;
|-&lt;br /&gt;
| MOVE || %0rrrrrrr %vvvvvvvv || Write value &#039;&#039;&#039;v&#039;&#039;&#039; to Next register &#039;&#039;&#039;r&#039;&#039;&#039; (duration 2 CLOCKS)&lt;br /&gt;
|-&lt;br /&gt;
| NOOP || %00000000 %00000000 || Special case of &amp;quot;value 0 to port 0&amp;quot; works as &amp;quot;no operation&amp;quot; (duration 1 CLOCK)&lt;br /&gt;
|-&lt;br /&gt;
| HALT || %11111111 %11111111 || Special case of &amp;quot;WAIT 63,511&amp;quot; works as &amp;quot;halt&amp;quot; instruction&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The copper&#039;s program storage is 2k big; since each instruction is 2 bytes it can store exactly 1024 instructions, numbered 0-1023. The copper is controlled by a word accessed through Next Registers {{NextRegNo|$61}} and {{NextRegNo|$62}}. The internal &amp;quot;program counter&amp;quot; (&#039;&#039;&#039;CPC&#039;&#039;&#039;) has 10 bits (0-1023), auto-incrementing it after each instruction, wrapping around after last one back to first one.&lt;br /&gt;
&lt;br /&gt;
The copper control word has the structure: %cc000iii %iiiiiiii. &#039;&#039;&#039;I&#039;&#039;&#039; is the storage position (0-2047) (for writing instructions with {{NextRegNo|$60}}), and &#039;&#039;&#039;c&#039;&#039;&#039; is used to set the behaviour mode of the copper, as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! C bits !! Effect&lt;br /&gt;
|-&lt;br /&gt;
| %00 || STOP, copper does nothing (CPC keeps its current value)&lt;br /&gt;
|-&lt;br /&gt;
| %01 || reset CPC to 0, then START&lt;br /&gt;
|-&lt;br /&gt;
| %10 || START (resumes from current CPC)&lt;br /&gt;
|-&lt;br /&gt;
| %11 || reset CPC to 0, then START; Also VBLANK does reset CPC to 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
When &#039;&#039;&#039;c&#039;&#039;&#039; bits are identical to previously written value, the control mode is ignored, and only write-index &#039;&#039;&#039;I&#039;&#039;&#039; is modified.&lt;br /&gt;
&lt;br /&gt;
If you don&#039;t want the copper program to loop infinitely, then you can mark the &amp;quot;end&amp;quot; of the copper program by waiting for a line higher than 311 (&amp;quot;HALT&amp;quot; instruction). Since these lines will never be reached, the copper will essentially halt until reset.&lt;br /&gt;
&lt;br /&gt;
The precise timing and many more details are currently documented in distribution file [https://gitlab.com/thesmog358/tbblue/blob/a0d25589bd28b05c510e528332bcd192bc414ebb/docs/extra-hw/copper/COPPER-v0.1c.TXT &amp;quot;/docs/extra-hw/copper/COPPER-v0.1c.TXT&amp;quot;].&lt;br /&gt;
&lt;br /&gt;
(core 2.0) the copper code is executed at 14MHz, and the COPPER-v0.1c.TXT document above describes timing of the core2.0.&lt;br /&gt;
(core 3.0) the copper code is executed at 28MHz, the precise timing is not documented yet&lt;br /&gt;
&lt;br /&gt;
From practical test (with the Swedish-flags copper test) the coordinates for WAIT are identical, MOVE is twice as fast (flags are half of original width because each pixel is created by single MOVE instruction).&lt;br /&gt;
&lt;br /&gt;
Important values affecting pixel display are now sampled at the same moment when the pixel is drawn (no test yet to describe what does that mean at sub-pixel accuracy terms and in which order the copper MOVEs should be done with what kind of lead in case you want to set for example 6 different display-affecting registers, by theoretical approach of single MOVE taking half-pixel width you should start precisely 3 pixels ahead of the edge where all values should be set, but YMMV) (overall it&#039;s probably much wiser to avoid situations where you need sub-pixel precision, or test with the real board heavily)&lt;br /&gt;
&lt;br /&gt;
Extra note from discord by AA: The copper is 16-bit :- it fetches its 16-bit instruction in 1 T and actually all move instructions take 1 T.  However if the move is writing to nextreg (ie it&#039;s not a nop) then there is a 1 T delay for it to go through the nextreg path for the nextreg write to take effect.  While that goes on, the next copper intruction is already executing.&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=Wiki_TODO_list&amp;diff=41126</id>
		<title>Wiki TODO list</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=Wiki_TODO_list&amp;diff=41126"/>
		<updated>2025-10-07T09:17:22Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: more specific info about what was deleted and is gone&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;2025-10-06 update: SemanticWiki plugin was removed due to SW security issues and high maintenance effort requirements. This broke lot of the wiki functionality, like there&#039;s no more auto-generated list of next registers, etc. The source data used by the plugin to generate remaining content and format it are still available as individual wiki pages, check [[Special:AllPages]] (but if something is missing also here, then it&#039;s gone, AFAIK only SemanticWiki code, templates and auto-generation of final page look is gone, so all the Next specific info should be still somewhere in source articles). At this moment I&#039;m not aware of any attempt to improve current state, but if you feel like you want to give it a go, maybe sync on the Next discord at #wiki-wizards-and-hosting-heros channel first to have most current info on situation.&lt;br /&gt;
&lt;br /&gt;
--- older notes, which now after ages sounds to me like &amp;quot;improve everything&amp;quot; ---&lt;br /&gt;
&lt;br /&gt;
These items are known to lack in information amount or accuracy (and anyone having spare time and required information is welcome to improve them):&lt;br /&gt;
* [[Sprites]] - main article is up to date, seems also formatted well, still somebody checking if it holds against actual users and what can be improved...&lt;br /&gt;
* various main articles: check wording, if they are in sync with official docs/manual (memory page vs bank, port vs register, etc...)&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=Wiki_TODO_list&amp;diff=41125</id>
		<title>Wiki TODO list</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=Wiki_TODO_list&amp;diff=41125"/>
		<updated>2025-10-07T09:00:48Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: update about SemanticWiki plugin removal&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;2025-10-06 update: SemanticWiki plugin was removed due to SW security issues and high maintenance effort requirements. This broke lot of the wiki functionality, like there&#039;s no more auto-generated list of next registers, etc. The source data used by the plugin to generate remaining content and format it are still available as individual wiki pages, check [[Special:AllPages]] (but if something is missing also here, then it&#039;s gone). At this moment I&#039;m not aware of any attempt to improve current state, but if you feel like you want to give it a go, maybe sync on the Next discord at #wiki-wizards-and-hosting-heros channel first to have most current info on situation.&lt;br /&gt;
&lt;br /&gt;
These items are known to lack in information amount or accuracy (and anyone having spare time and required information is welcome to improve them):&lt;br /&gt;
* [[Sprites]] - main article is up to date, seems also formatted well, still somebody checking if it holds against actual users and what can be improved...&lt;br /&gt;
* various main articles: check wording, if they are in sync with official docs/manual (memory page vs bank, port vs register, etc...)&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=CSpect:known_bugs&amp;diff=34909</id>
		<title>CSpect:known bugs</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=CSpect:known_bugs&amp;diff=34909"/>
		<updated>2025-09-23T14:41:57Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: DMA WR3 enable bit bug reported by Holub, tested with dmaDebug.sna test and by checking VHDL&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;CSpect V2.19.1.0&lt;br /&gt;
* intentional for performance reasons:&lt;br /&gt;
** sprites: the collision bit is not implemented&lt;br /&gt;
** sprites rendering is not one-scanline-buffer delayed and all changes in sprites affect current scanline&lt;br /&gt;
** modifications to NextRegs done in copper propagate to rendering usually only once per scanline, the state for rendering is sampled after right border area (ahead of copper wait h=39), affecting previous line instead of next (palette changes, X/Y offsets, etc)&lt;br /&gt;
** modifications to NextRegs done by CPU propagate to rendering usually only once per scanline, usually retroactively for whole current scanline&lt;br /&gt;
* major differences / missing features&lt;br /&gt;
** blending modes: improved greatly in V2.19.0.3, blending only L2 priority colours wrongly.&lt;br /&gt;
** NextZXOS streaming API doesn&#039;t work (the initialization of stream fails - rst 8 service 0x86 ; DISK_STRMSTART)&lt;br /&gt;
** DMA: Zilog mode is not implemented (port 0x0B) (but zxnDMA does listen to both ports, so SW using 0x0B will get one byte shorter transfers)&lt;br /&gt;
* subtle differences&lt;br /&gt;
** sprites: in border vs tiles in modes 3,4 and 5 are not drawn same weird way as HW&lt;br /&gt;
** sprites: the wrap-around the 512x512 coordinate space is only partially implemented in extreme cases (relative sprite so far from anchor that x8 scale wraps it back onto screen)&lt;br /&gt;
** NextReg $02 implementation of soft-reset does something, but not the same thing like HW&lt;br /&gt;
** NextBASIC SPECTRUM command may load SNA file with wrong ROM paged in (very likely related to SW NMI trigger emulation &amp;lt;code&amp;gt;nextreg 2,8&amp;lt;/code&amp;gt; ROM2 $0aab)&lt;br /&gt;
** NextZXOS browser is unable to load SNA/SNX/Z80 files in latest distribution (does work with older 3.1.5 core NextZXOS) (may be related to SW NMI)&lt;br /&gt;
** More &amp;gt;&amp;gt; ZX80 and ZX81 modes reset and hangs on a black screen while launching the Paul Farrow emulators. (may be related to soft-reset)&lt;br /&gt;
** More &amp;gt;&amp;gt; 128K BASIC launches but gets no keypresses on 2.19.0.2. On V2.16.6.0 it hangs on a black screen and border. (may be related to soft-reset)&lt;br /&gt;
** DMA: reading-registers are a bit off (for example status bit5+0 not reset correctly after LOAD, probably few more (but core 3.1.5 also reads bit0 wrongly, so always test own code with all target platforms))&lt;br /&gt;
** DMA: setting WR3 enable bit does NOT start transfer (ie. CSpect is emulating the East Germany clone chip, HW Next and Zilog DMA chips will start the transfer after such write like WR3 = 0xC0)&lt;br /&gt;
** NextRegs $09, $34, $41, $8E read incorrectly (reads after certain writes produce wrong value) (but also the test is checking 3.1.5 behaviour, needs update to 3.1.10)&lt;br /&gt;
** debugger: the step-over F8 does run interrupt handler every 16-20ms (as part of debug-live-screen-view drawing), so it&#039;s almost after every F8 press&lt;br /&gt;
** Z80: &amp;lt;code&amp;gt;di : halt&amp;lt;/code&amp;gt; doesn&#039;t put CPU in infinite loop waiting for NMI, but proceeds further&lt;br /&gt;
** Z80: block of prefixes/instructions 0xDD/0xFD/EI does not inhibit masked interrupts&lt;br /&gt;
* recently fixed:&lt;br /&gt;
** &amp;lt;del&amp;gt;L2 mode 320x256 and 640x256 could crash when clip.X2 &amp;gt; clip.X1&amp;lt;/del&amp;gt;&lt;br /&gt;
** &amp;lt;del&amp;gt;CTC timing is affected by the Z80N clock speed. It should be using a constant 28Mhz reference clock.&amp;lt;/del&amp;gt;&lt;br /&gt;
** &amp;lt;del&amp;gt;vertical ULA clipping is not working in Timex modes&amp;lt;/del&amp;gt;&lt;br /&gt;
** &amp;lt;del&amp;gt;ULA scroll and half-width scroll is not implemented in Timex modes&amp;lt;/del&amp;gt;&lt;br /&gt;
** &amp;lt;del&amp;gt;Z80: when masked interrupt handler is entered, the interrupts remain enabled (IFF1=1, IFF2=1)&amp;lt;/del&amp;gt;&lt;br /&gt;
** &amp;lt;del&amp;gt;divMMC automap-enabled traps certain addresses even when RAM is mapped to MMU0/MMU1&amp;lt;/del&amp;gt;&lt;br /&gt;
** &amp;lt;del&amp;gt;something not completely right about Enhanced ULA colours (test TFalBUla.sna)&amp;lt;/del&amp;gt;&lt;br /&gt;
** &amp;lt;del&amp;gt;F3 reset does not autodetect NextZXOS 2.06 vs 2.07 when running with card-image, so 2.06 image ends with purple stripes.&amp;lt;/del&amp;gt;&lt;br /&gt;
** &amp;lt;del&amp;gt;some NextRegs read as zero until they are written into first (quick-boot mode with SNA file without full NextZXOS image)&amp;lt;/del&amp;gt;&lt;br /&gt;
** &amp;lt;del&amp;gt;Layer2 640x256x4bpp clipping is broken&amp;lt;/del&amp;gt; (V2.19.0.3 does fix this correctly, was still broken before)&lt;br /&gt;
&lt;br /&gt;
not verified in V2.19.1.0 (but known bugs of older versions, may be still present):&lt;br /&gt;
* CTC time constant of 0 causes incorrect code execution.&lt;br /&gt;
* the initial file-import sequence of CP/M BIOS fails. (get cpm-a.p3d file from somebody with a working clean CP/M installation and copy that into c:/NextZXOS, or use other emulator to create the file)&lt;br /&gt;
* default ULA palette after power on (quick boot without NextZXOS) is slightly different&lt;br /&gt;
* (should be improved now, to be tested) without the full NextZXOS card image the esxdos services are provided by open source [https://github.com/mikedailly/CSpectPlugins CSpect plugins], the implementation is limited and crude - some of the returned values are incorrect/etc, but loading files works.&lt;br /&gt;
* direct loading of NEX files does not support all combinations of loading-screen type and palette on/off (but V2.12.9 does load more files than V2.12.5, all common ones should work)&lt;br /&gt;
* sprites: something something about default clipping... just set clip windows explicitly in your SW.&lt;br /&gt;
* sprites: clipping in non-over-border configuration is maybe wrong (probably fixed, needs more testing with 2.19.1.0 or later)&lt;br /&gt;
* fixed by V2.19.0.3 &amp;lt;del&amp;gt;stencil mode is not implemented&amp;lt;/del&amp;gt;, needs more testing&lt;br /&gt;
&lt;br /&gt;
Platform Specific (may be already fixed):&lt;br /&gt;
* Mac: Mouse does not work / behaves erratically&lt;br /&gt;
* Mac: after launch keyboard being irresponsive - try &amp;quot;alt+tab&amp;quot; to other app and back&lt;br /&gt;
* Linux: (some/all?) plugin windows like nextregisters (ctrl+alt+r) does not refresh while in debugger&lt;br /&gt;
* Linux: (some/all?) plugin windows like nextregisters (ctrl+alt+r) does draw hover-hint tooltip only for one frame, then it becomes invisible&lt;br /&gt;
&lt;br /&gt;
Not a bug:&lt;br /&gt;
* CSpect works with &amp;quot;-sound&amp;quot; (does switch sounds OFF), but shows only black screen without it:&lt;br /&gt;
** you forgot to install OpenAL, check the ReadMe.txt of the emulator.&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
	<entry>
		<id>https://wiki.specnext.dev/index.php?title=Assemblers&amp;diff=12887</id>
		<title>Assemblers</title>
		<link rel="alternate" type="text/html" href="https://wiki.specnext.dev/index.php?title=Assemblers&amp;diff=12887"/>
		<updated>2025-03-17T00:23:30Z</updated>

		<summary type="html">&lt;p&gt;Ped7g: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Any Z80 assembler can produce code suitable for the Next. However the raw blocks of Z80 code may be not as convenient to use with Next or emulators, so a Next specific tools may be useful for creating one of the supported [[File Formats]].&lt;br /&gt;
&lt;br /&gt;
== Cross-platform tools (running on PC) ==&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[http://www.desdes.com/products/oldfiles/zeus.htm Zeus-ish]&#039;&#039; ===&lt;br /&gt;
: Provides a complete Z80 IDE and Macro assembler, scripted disassember plus an integrated Z80 emulator for a range of machines including partial Next support&lt;br /&gt;
: Supports the Next opcodes directly&lt;br /&gt;
: Supports remote debugging on the Next using ParaSys across a serial link&lt;br /&gt;
: Supports MMU paging in the integrated emulator&lt;br /&gt;
: Supports sprites (core versions prior to 2.00.26) in the integrated emulator&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[http://pasmo.speccy.org/ Pasmo]&#039;&#039; ===&lt;br /&gt;
: A long established Z80 assembler, but has been out of development for a long time&lt;br /&gt;
: Supports all currently known Next extension opcodes through this [https://www.facebook.com/groups/specnext/512169722473686/ modified Pasmo from Russ McNulty and Tony Thompson] and also now supports outputting .sna files to use with CSpect, thanks to Russ McNulty&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;SNasm&#039;&#039; ===&lt;br /&gt;
Included with the [https://mdf200.itch.io/cspect #CSpect] emulator&lt;br /&gt;
: Full macro assembler&lt;br /&gt;
: Full bank control via Segment management&lt;br /&gt;
: Supports the Next extension opcodes directly&lt;br /&gt;
: Generates full 24bit map files for use in CSpect&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;z80asm&#039;&#039; ===&lt;br /&gt;
Part of [https://github.com/z88dk/z88dk Z88dk]&#039;&#039;&lt;br /&gt;
: Supports the Next extension opcodes directly, linking assembler with large z80 library, targets any memory configuration&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://github.com/z00m128/sjasmplus z00m&#039;s fork of sjasmplus]&#039;&#039; ===&lt;br /&gt;
: Supports all (core2.00.28) Next extension opcodes, ZXN memory model (8 memory slots with 8ki pages and 1.75MiB virtual device memory), SAVENEX to build NEX files directly from ASM source (NEX version V1.2 (and experimental extension &amp;quot;V1.3&amp;quot;)), MAP files for [https://mdf200.itch.io/cspect #CSpect] emulator, SLD tracing files for [https://github.com/maziac/DeZog DeZog] and [https://github.com/Ckirby101/NDS-NextDevSystem NDS-NextDevSystem] and it is under active development (feedback is welcome).&lt;br /&gt;
: Open source project (&amp;quot;BSD-3-Clause&amp;quot; license), &#039;&#039;&#039;windows executables available at [https://github.com/z00m128/sjasmplus/releases/latest releases]&#039;&#039;&#039;, mac and linux users are expected to simply build from source (both make and CMake are supported).&lt;br /&gt;
: [http://z00m128.github.io/sjasmplus/documentation.html Documentation], latest stable release v1.21.0 2025-03-15&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://github.com/CatpainBlack/FantASM FantASM]&#039;&#039; ===&lt;br /&gt;
FantASM is a two pass non optimising assembler for the Z80 processor by [https://github.com/CatpainBlack Guy &#039;CatpainBlack&#039; Black].&lt;br /&gt;
&lt;br /&gt;
It supports all undocumented op-codes and the extended instruction set of the ZX Next and additional pseudo opcodes used by the CSpect emulator to control debugging.&lt;br /&gt;
&lt;br /&gt;
== Native tools (running on Next) ==&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://gitlab.com/next-tools/odin Odin]&#039;&#039; ===&lt;br /&gt;
&lt;br /&gt;
Work-in-progress Next-specific assembler written by Matt Davies, used also in video tutorials presented by Jim Bagley, the best way to acquire the binary is to join the official ZX Next discord server and check channel &amp;lt;code&amp;gt;#odin&amp;lt;/code&amp;gt; - pinned messages, where you can also discuss any issues and get how-to hints.&lt;br /&gt;
&lt;br /&gt;
: supports most of the undocumented opcodes, all official Z80 and Next-extended instructions&lt;br /&gt;
: supports nested includes and binary includes&lt;br /&gt;
: source is stored in tokenised form (smaller file), up to 48kiB of source in single file&lt;br /&gt;
: assembling can produce 32kiB of machine code (enough to produce simpler dot command)&lt;br /&gt;
: includes also editor and console modules (debugger is planned)&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://www.solarisite.com/spectrumnext.html Sol]&#039;&#039; ===&lt;br /&gt;
&lt;br /&gt;
Sol is an assembler and editor written by Solaris, that runs natively on the Next. Manual, assembler binary and assembler source can be downloaded [https://www.solarisite.com/spectrumnext.html here].&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://gitlab.com/thesmog358/tbblue/-/tree/master/tools/dev/Zeus ZEUS]&#039;&#039; ===&lt;br /&gt;
&lt;br /&gt;
Classic ZEUS native assembler by Simon Brattel, extended and included directly in the ZX Next distro.&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://gitlab.com/thesmog358/tbblue/-/tree/master/tools/dev/SPED SPED]&#039;&#039; ===&lt;br /&gt;
&lt;br /&gt;
Classic SPED assembler by César Hernández Bañó, included directly in the ZX Next distro, see [https://gitlab.com/thesmog358/tbblue/-/raw/master/docs/apps/dev/SPED53readme.txt README].&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;[https://taylorza.itch.io/nextbasic-inline-assembler NextBASIC Inline Assembler]&#039;&#039;===&lt;br /&gt;
Enables you to write inline assembly code in your NextBASIC application. The assembler can be downloaded from [https://taylorza.itch.io/nextbasic-inline-assembler HERE] with documentation available [https://github.com/taylorza/zxn-inlineasm-doc/blob/main/README.md HERE]&lt;/div&gt;</summary>
		<author><name>Ped7g</name></author>
	</entry>
</feed>