Skip to content

Best Practise

This is a collection of "best practises". These are tested solutions that solve a common problem in an easy way.

However, it is said that "all roads lead to Rome". The solutions you find here may not be the only way to solve your problem. The Next Skeleton is supposed to make your life easier. If you find a way that suits better to your needs, just use it.

How can I debug my program?

In #CSpect, you can enter the debugger at any time by pressing the F1 key. This is helpful when your program is stuck in an endless loop and you want to find out where.

You can also use ant debug to start the #CSpect emulator in debug mode. It will change three things:

  • The BREAK pseudo op-code is enabled. If executed by the emulator, it will stop code execution and switch to the debugger. You can use it as a breakpoint.
  • The EXIT pseudo op-code is enabled. It will exit the emulator.
  • The SpecNext register Machine ID (0x00) reveals that your code is executed in an emulator. You can evaluate this register, and then run special debug functions that are usually bypassed.

To enable the BREAK and EXIT opcode in the assembler, add this line to the head of your assembler source code:

        OPT --zxnext=cspect

Remember to remove this line and the opcodes after debugging! BREAK and EXIT are proprietary to #CSpect, and may crash your program if executed on a real ZX Spectrum or another emulator. For this reason, they are disabled by default, and need to be enabled manually.

Where shall I put include files?

There are two kind of include files for the assembler: static and generated ones.

The static ones are written by yourself or copied from somewhere else, and won't change during the build process. Examples are macro definitions, assembler modules, or fixed binary files. These are meant to be placed in the src directory. If there are many of those files, it is recommended to group them in subdirectories, like for example:

  • src/inc/ -> generic include files (e.g. macros or offset tables)
  • src/bin/ -> binaries (e.g. data tables)
  • src/screen/ -> screen files that are ready to be included
  • src/charset/ -> character sets
  • src/music/ -> music files
  • src/palette/ -> palette files

In large projects, you can also use subdirectories for modules:

  • src/gfx/ -> all assembler files related to graphics
  • src/io/ -> all assembler files related to I/O operations

It is possible that an include file needs to be generated from other files first. For example, you have a PNG file, and you want to convert it to a ZX Spectrum bitmap using a converter tool. You could invoke that tool manually, and place the converted file in the src directory like mentioned above. But it is easier to change a PNG file, so you'd prefer to have this one in your project instead.

What you can do here, is to put the PNG file into the src directory (say, in a src/image or src/png directory). Now change the build.xml and extend the prepare target so it invokes your converter tool. Since it is always possible to re-generate the bitmap file from the PNG file, there is no need to permanently store the converted bitmap file in git (or whatever your favourite SCM is), so the converted file is written into the dist/inc directory. The dist/inc directory is already known to the assembler, so you can directly import files from there.

Example: There is a file called src/image/tiles.png that contains tile images for your game. In the prepare target, a converter would read the ${src}/image/tiles.png file and write the converted binary to ${dist}/inc/tiles.bin. In the assembler, you can include this binary just with INCBIN "tiles.bin". You can rely on ant that the include file is generated before the assembler is invoked.

Where can I put files for distribution?

You may want to have files in your project that are only meant to be added to your release, for example:

  • the user manual
  • example files for the user of your program
  • files that are supposed to be loaded by your program at runtime (screens, music etc)

You can put all these files into the resources directory. ant will just copy all files from that directory to your release directory, but won't touch them otherwise.

What about generated files for distribution?

There may be files that need to be generated, but shall be present in the release directory instead of being included by the assembler. For example:

  • a PNG image that need to be converted to a bitmap and is supposed to be loaded at runtime
  • user documentation that is generated by a document generator

The sources of these files can be placed in the src directory (maybe in a subdirectory). Now edit the build.xml and extend the build target. Extend it so the files are generated and stored straight into ${dist}/resources.

Where can I put other build tools?

If you want other developers to participate in your project, you should make it as easy as possible for them to start.

You can state commonly available build tools as dependency in your project README, and rely on the other developers having them installed before they build your project.

If you use special build tools, you should put them into the tools directory, so they will be present when other developers check out your project. For open source projects, you should avoid to use binary tools, as they may not run on other machines. Better use tools that are written in common languages like Python.

What files should not be committed?

The .image and dist directories are generated, and also consume a lot of disk space. You should never commit those directories to a SCM like git or Subversion. The skeleton already contains a matching .gitignore file.

How can I change the size of the MMC image?

Open the build.xml file in an editor. Locate the line <property name="sdsize" value="1G"/> and change it to the desired MMC image size. Invoke ant clean to delete the old image.mmc file, then ant sdcard to create a new one.

How can I upgrade my project to the latest Next Skeleton?

First, make sure that your project is saved somewhere (e.g. in git or by making a backup copy), so you can revert it if the upgrade fails and messes up your project.

Now run ant purge first, to remove all generated files and bring your project into a clean state.

After that, copy all files of skeleton/tools to the tools directory of your project.

Finally, open the skeleton/build.xml and the build.xml of your project in your favourite diff tool (e.g. meld), and carefully adopt all the changes into your own build.xml file.

Do not just copy the skeleton/build.xml file into your project! The skeleton/build.xml is a template that has been adapted to your project by the nxtsetup tool. The placeholders in the template are marked with {{double curly braces}}. Leave those places unchanged in your build.xml if in doubt.

There may be a migration chapter in future versions of the Next Skeleton. It will explain all the steps that are necessary to migrate your project. It's recommended to have a look at the documentation first.

How can I copy a file from the current MMC image?

If you create or change a file in the emulated ZX Spectrum Next, it is saved on the dist/image.mmc file. You can use mcopy to copy it to your system. To copy the file helloworld/mychange.bas to your project directory, use:

mcopy -i dist/image.mmc@@1M ::helloworld/mychange.bas .

The line looks a little strange, but the @@1M and the :: are important parts, so do not forget them.

The dist/image.mmc file is deleted with all your changes when you invoke ant clean, so make sure to copy important files before.

Can I use ZEsarUX instead of #CSpect?

ZEsarUX is another ZX Spectrum Next emulator. It is also available for Linux. You can download the latest release, and install it using the install.sh script that can be found in the project.

Now open the build.xml file and locate this block:

        <exec executable="${emulator}">
            <arg value="-tv"/>
            <arg value="-w3"/>
            <arg value="-zxnext"/>
            <arg value="-nextrom"/>
            <arg value="-map=${dist}/${ant.project.name}.map"/>
            <arg value="-mmc=${sdcard}"/>
        </exec>

Replace it with:

        <exec executable="zesarux">
            <arg value="--noconfigfile"/>
            <arg value="--zoom"/><arg value="1"/>
            <arg value="--machine"/><arg value="tbblue"/>
            <arg value="--realvideo"/>
            <arg value="--quickexit"/>
            <arg value="--nowelcomemessage"/>
            <arg value="--enable-mmc"/>
            <arg value="--enable-divmmc-ports"/>
            <arg value="--mmc-file"/><arg path="${sdcard}"/>
        </exec>

ZEsarUX is untested in the Next Skeleton. It may or may not work for you.