Assembling for ZX Spectrum 128K (how I do it)…

Hey all !

I had an idea….. that I should document the way I edit/assemble/run my ZX Spectrum assembly code.
This isn’t going to be a coding tutorial, there are much better coders who can do that ;),  It’s just to show you the software and utilities I use to code.
So, let’s get started…

I don’t use Notepad++ or any of the other text editors, although they are most definitely excellent and very powerful when you set them up.  They are also better than what I use, but I’m used to mine, 🙂

So, I present PoloED, my Z80 assembly editor, 😉


PoloED allows me to dock and tab different files, which helps me when I need to refer to other bits of code, and has syntax highlighting.  It also has rudimentary project handling which I only really use because it is quicker when opening files related to the game I’m working on, 🙂

It also has a live info tab, which updates information about opcodes/timings/and what they do.  It updates when you hover over or click on an instruction, although it can sometimes be a bit slow :/


I am also working on a built in emulator. There are a few issues with it, but it is only a work in progress, 🙂


I forgot about this, but at some point I added a very basic character editor (8×8 pixels).  It allows you to edit up to 256 characters and either save as binary/defb’s or squirt the data into which ever assembly file is currently active.


There is a Snippets tab, but I haven’t touched that due to either laziness or err just forgetting, 🙂

Now, the main couple of reasons I created this editor was to help automate as much of the edit/assemble/run process, and also so that I could throw docked/tabbed windows everywhere, 😀
So, to that end I made sure I could pick whichever assemblers and emulators I wanted.

Here is the settings dialog, along with the settings I use when coding for the ZX Spectrum 48K. This currently uses Pasmo to assemble and ZX Spin to execute.  Note the parameters that can be inserted into paths or exe parameters.  They come in very handy, :


These are the settings when coding for the ZX Spectrum 128K, but more about the 128K later, 😉


Note that you can change font size by clicking on the font text at the right (i.e. click where it says “Verdana : 9”.  Custom colours is partially implemented but it is not active at the moment.  I will get around to it eventually, honest, 🙂

Output from the assembler etc. is displayed in the Output window.


So, all I need to do is edit some code and then assemble it by pressing F9, (the hotkeys can be either F9/10/11/12, selectable).  I then quickly glance at the Output window to check there are no errors and then tap F10 to run the assembled code in the emulator that was specified in the Settings window.  Nice ‘n’ easy eh…

One thing though…..  With Pasmo, make sure that you have the –tapbas parameter specified on the Pasmo command line parameters.  PoloED has a checkbox to enable .tap file creation (which just adds the –tapbas parameter when executing Pasmo).


To use the automatic loading and executing feature of code that you write, make sure that you use the END directive in your assembly code.


I also check “generate_symbol_map” that generates a file which allows me to quickly see the locations of labels in my assembly code, handy for debugging.


That is all there is to the process I use for the ZX Spectrum 48K, 😀


The 128K !!!

Now for the fun part, 🙂

Due to having multiple memory banks, it isn’t possible to just write a load of assembly files and get Pasmo to assemble it all together with a BASIC loader (or at least I am not aware of it being able to do that).  I have not come across another assembler that can do that either (although I am probably wrong heh).
First of all… the code…..

I always use constants to make sure that I cannot confuse what code/data is in which banks….

PoloED11This also means that I can change which banks hold which data, without having to go through all my assembly files changing them manually.

For each bank I create a separate .asm file.  If the bank is used only for data then I just include the binary of the data, although you could use defb etc for other data.

PoloED12As you can see, there are 3 assembly files for banks (I named music.asm incorrectly, it should be musicbank.asm heh).
Now, it’s all well and good having data in banks, but what about code???  To put code in a bank just create an assembly file for the bank and add your code.
One thing that you have to be aware of is that to call that code you need to page that bank into memory and then CALL the address of the routine you want to use.  This is where I make sure that Pasmo generates a symbol map (although for 128K the generate_symbol_map tickbox does not help, as you will see later).  Once you have the symbol map, you can place a couple of constants in the assembly file that will be calling into the code in the bank.
For example; I have a music player and the tune in bank 3.  In my constants.asm file I have this…

As you can see, MUSICBANK holds the bank I store it in, and MUSICINIT/MUSICPLAY/MUSICSTOP are the locations in memory to CALL to when I want to use the player.
IMPORTANT NOTE: If you are placing code into a memory bank, you should in most cases start the assembly code with org 49152. This will allow Pasmo to calculate all the correct CALL/JP/JR’s etc., ie this is the start of my music bank…


Now, make sure you decide upon a load order, as this does matter later on.  I decided on loading the maps, then tiles, then music banks.
At the start of my main code I change where the stack points to, otherwise you *will* end up paging it out of memory, and end up watching your code explode quickly, :/
I put the stack just before the start of my code.  The data I have before the stack has to be watched so that the data and stack do not collide, although that is very unlikely if you plan where your data and code are going to be.

Then I call the loading routines for the banks.


This is one of the loading routines. The others are the same except they page in the relevant bank. Note that I have a bit of code to skip the header.  I cannot remember how I told the utility I use to create a header less file (but I know it does it). Anyway, this code will probably be changed to a fast-loader or summat, 🙂
I also do not set the data length in DE to the exact number of bytes until I finalise the data/code in the banks.  As it is, it will load fine.

Once the data is loaded, you can continue with the rest of your game code.  As mentioned before, you must make sure that whenever you want to access data or call code in the banks you page that bank in, 🙂

Now for the fiddly part.  Due to not being able to assemble your normal assembly along with the data/code in banks into the same .tap file, we have to use a little batch file and a couple of utilities.  There may be better or less awkward ways to do this, but this works for me.

First, create a text file called “bbrloader.bas” and populate it with the code below. This is the BASIC loader we are going to use. You can put any BASIC code in here and it will be added to the .tap file.

Second, make sure you have the utilities – Pasmo, bintap, mktap.  You can get the versions I use here.
I have also added in bbrloader.bas and CompileAndAddMapData.bat.  You can rename them if you wish, but if you rename bbrloader.bas make sure to change it in the CompileAndAddMapData.bat file.

Third, create a batch file CompileAndAddMapData.bat using the script below.


Ok, let’s break the important bits down…

This compiles the main code, along with the three banks that we saw earlier. I use a couple of parameters. The “-v” parameter means verbose (so I have more information in the Output window in PoloED), –alocal tells Pasmo to allow _loca vars (handy). The next parameter is the assembly file that Pasmo is to assemble. Next up is the name of the binary file that Pasmo will create (these .bin filenames are used later).  Finally, and this is optional although I find it really handy, is the symbol file name so that you know where all the labels/routines etc are located in memory.  I would advise to give a file name for a symbol file even if you don’t think you will need it.

The bintap utility takes a binary file and creates a .tap out of it.  Parameters are: the binary file name, the name you want the .tap to be, then the name you want the header to display (if you were loading by LOAD “” CODE in BASIC, I don’t use the header, hence the fake header code in the routine a while back). Next up is the load address of the code (again, I set this correctly, but I don’t actually make use of it), and finally >null passes any text output (copyright lines etc) to a black hole.  I use null just so that when assembling etc it doesn’t clutter up the Output window in PoloED.  Leave it off if you would like to see what information is displayed.

The above will create 4 .tap files, 3 for the banks and 1 for the main code.  Note that this does not mean you can load and execute it now, 🙂

We need a BASIC loader………  Remember bbrloader.bas?  That’s what the next bit does.  It takes bbrloader, creates a BASIC loader and makes a .tap for just that loader.

PoloED22Parameters:  “-b” tells mktap to convert a text file to a BASIC program. “TBB128K” is the name that shows as “Program: ” when loading, the number 10 tells the utility to autorun this line (just like the LINE command when saving in BASIC), <bbrloader.bas> is the text file to create the BASIC program from, and “>TBBLOAD.tap” means output to a .tap file named “TBBLOAD.tap”. Simples eh, 🙂
I have just at this moment realised that the parameter to create a headerless block is -r. That means that the fake header part of my code can be removed, 🙂

So, 5 .taps, and we still cannot load and run the code, :/

FINALLY: This command will mash all the .taps together to make a nice single .tap that can be executed 🙂

PoloED23You don’t really need to know much about this line except that you use + to add all the .taps together. Make sure that the BASIC loader is first in the line (TBBLOAD.tap), and that the banks are in the same order as your code to load them. TBB128K.tap is the name of the final completed .tap that can be run in an emulator.

As you have seen in the picture of the Settings window of PoloED, the assemble key (F9) is set to run CompileAndAddMapDate.bat, and the execute key (F10) is set to run the completed .tap file in an emulator (ZX Spin in this case).

Now, I hope that made sense but if you do have any questions or comments, you can contact me in many ways…

Or, leave a comment on here, 🙂

Have fun coding, the ZX Spectrum 128K is fun to code for 🙂


John Young [polomint]