So you’re interested in Assembly Language Programming, and you want to know how to get started down this path on the SAM Coupé? You’re in the right place! I’ll be taking you through, step by step, in how to get the right tools, get your development tools setup, create some code, get it assembling, test it on an emulator, write your program to disk and debug your code…
Let’s get started…
A Little History
I’ve recently been reunited with a childhood computer – An MGT made Sam Coupè.
I spent long hard summer days working to save up the £250 for, what was then, a big upgrade from my ZX Spectrum 48k+.
The Sam Coupè was touted as the logical evolution of the ZX Spectrum. Originally developed by Alan Miles and Bruce Gordon in 1989 through their company Miles Gordon Technology or MGT, It’s thought roughly 250,000 machines were built in between 1989 and 1994.
I used to write quite a few little programs for this machine back in the day, my favourite of which was an advert for Lemmings which I created in BASIC, and was published in Issue 22 of the perennial Disk based Magazine FRED by Colin MacDonald:
It turned out to be rather prophetic, as it turned out to be FRED Publishing who would go on and bring Lemmings to the SAM Coupé some years later. I never made the step up to Assembler programming until much later, when I studied the 6502 at college, using an EMMA 2 Development Board:
Since then, I’ve programmed in Assembler on a fair few different platforms, most recently on the Microchip PIC Microcontroller.
However, I’ve always yearned to roll back the years and actually learn how to program my old computers, and now that I’ve been reunited with my SAM Coupé, I thought I’d leap in and give it a go.
As always, it’s the getting started which is the hard part, and there’s very little in the way of detailed curated information for the SAM in this area, which is no surprise given it’s rather niche user base.
But, with the help of Balor Price and Andrew Collier in the excellent Sam Coupé User Group page on Facebook, I was able to get started… So I thought I’d share my experiences here, in the hope of a) Helping somebody else get started, and b) so that when I come back to this, I’ll be able to get going again myself!
The best place to get started of course is by aquiring some of the tools required to start Programming and Compiling Sam Coupé Code. (We’ll get onto how to use them in a later section!)
I’ll begin with the Editor… These days I tend to use Microsoft’s Visual Studio Code…This is a really light weight and versatile editor… You can grab that here;
If you’d like a little “syntax highlighting” then you can download a nice Z80 Syntax Highlighting extension for Visual Studio Code from here;
Next you’ll need an assembler… There’s an excellent PC Python Based SAM Coupé oriented Z80 Assembler from Intensity called PYZ80… This allows you to Compile Z80 Source code and create SAM Disk Images Directly…
There’s a new version of PYZ80 in a branch by Simon Owen which promises to by Python 3 compatible… You can get that version here;
PYZ80 doesn’t actually need installing, just unzipping…I unzipped mine into a folder in the root directory… So something like “c:\pyz80\” will do…
PYZ80 is Python Based, so you’ll need to go ahead and download that too:
Next, If you want to make real SAM Disks that Boot on a real SAM, you’ll need to extract the SAMDos 2 file from a SAMDos 2 Disk Image. You can get the SamDos 2 Image from World of Sam here;
You’ll then need a way to extract the SAMDos 2 raw file from the image. For this you can use Andrew Colliers Disk Image Manipulator. You can get that from the Intensity Website at;
Before you think about writing Disk Images to actual disks… You’ll want to test and debug your code… The fastest way to do this is by running it on an Emulator… The only one worth considering here is the excellent SimCoupe by Simon Owen…Currently at version 1,1, SimCoupe covers all the various version of the SAM; Memory, Disk Drives, Peripherals etc etc, and even includes a really good debugger too. You can grab a copy from Simon’s GitHub page here;
If you want to actually write your compiled Disk Images to a real disk for a SAM Coupé…. Firstly, you’re going to need a suitable PC with a real Floppy Disk Drive… a USB Floppy drive won’t work here, because the firmware is fixed and they can’t be overridden to write SAM Format Disks. Secondly, you’ll need a handy tool by Simon Owen called SAMDisk, which allows you to Read and Write SAM Format Disk Images from and to actual Disks. You can grab SAMDisk from here;
Finally… In order to work around the PC Floppy Driver limitations, you’ll need a Floppy Filter Driver called fdrawcmd.sys… You can find a copy here;
Introducing the code
Ok… So, if you’ve got all of the above tools downloaded, extracted and installed… You should be about ready to go!
Let’s start by opening up Visual Studio Code and writing our first program…. I’ve chosen a program written by Steve ‘Wizard’ Taylor and published in Issue 6 of Colin MacDonald’s FRED Magaine which basically prints an ASCII Character set;
With the help of Balor Price and Andrew Collier, I managed to get it to work with PYZ80… Or, quite possibly, there was a bug in the code which meant it could’ve never run. Either way, you can go ahead and grab a modified and updated version of the code here;
Understanding the code
The First Loop – Printing an ASCII Table
I’m not going to go into masses of deep detail for assembly programming, as there are plenty of resources on the internet to help with that, however, I will break the code down and explain what each section/line is doing…
On Line 1 we have;
This piece of code allows our program to automatically start when loaded.
On Line 2 we have;
This line puts our code at a specific address in memory. The address 32768 or 8000 in Hex, is a throwback to the Spectrum Memory Map… In short, the memory was split up into sections, where space below the address 8000 was mapped in conjunction with the ULA, which took precedence, and so called Contended Memory… So things like driving the screen etc took priority in this area. Everything from 32768 and above was un-contended, so read faster!
Lines 6 and 7 Setup the starting conditions for the loop to Print out an ASCII table… We also encounter our first label…
print_test: LD B, 96
We’re using the B Register as a loop counter here and we want to print 96 characters in OUR ASCII table. The label, at least in this case, is simply so we can give anyone reading the code an idea of our intentions at this point. However, it’s technically useless.
LD A, 32
LD or LoaD instruction, we preload the A Register with 32, which is the first ASCII Character in our ASCII table, and equates to the SPACE character.
On line 9 we start our first loop;
loop2: LD C,A
This is where I’ve needed to make the first change to the original FRED code – We store the contents of the A register in the C register, so we can retrieve and us it again later…
Next is a call to a predefined SAM Coupé Machine Code Subroutine;
The Sam Coupé ROM has a selection of predefined routines which we can call from our program which help us speed up development. One of these is described in the SAM Coupé Technical Manual as;
Print char in ‘A’ register to current stream. The ‘K’ and ‘S’ channels respond to control codes for PEN, PAPER, OVER, INVERSE, FLASH, delete, left, right, up, down, AT, TAB and carriage return
So, as you can see, on line 9 we’re loading the value of 32 into the A register. The
RST Or ReSTart instruction, is very similair to the
CALL instruction. However, it is a far more lightweight but limited instruction, in that it can only call a small selection of predefined ROM addresses, whereas
CALL can call any address in memory.
So here, we’re calling the
I’ve made the change at Line 9 to cope with the fact that the
RST 16 routine will corrupt the contents of the A register. This meant that, where below we’re reusing the A Register, the
RST 16 call would leave an incorrect value in the A register, breaking our loop.
So we store the contents of the A register temporarily using the
LD or LoaD instruction on Line 9, call
RST 16 on Line 10, then on Line 11 we simply restore the previous contents of the A register from our temporary storage in the C Register using the
LD instruction again;
RST 16LD C,A
On line 12 we add 1 to the A register. This has the effect of pointing to the next ASCII Character, the first time around the loop this will now be pointing to an exclamation mark character “!”;
On line 13 we’re making use of the
CP or ComPare instruction. This instruction compares the given register to the A register. In this case, we’re comparing the B register to the A register. If you remember, we set the B register up with a value of 96 on line 6. This is because 96 is the last ASCII character we want to display in our table… It corresponds to the back apostrophe “`” character;
On line 14, we are using the
JR instruction. This instruction takes a comparison operator and a jump label. Here, we’re checking to see if the Zero Flag isn’t set, and if it’s not set, we jump to the label
loop2, which is up there on line 9;
And that’s the first loop complete…
Understanding the Code
The Second Loop – Printing a String
So, with the first loop over, we can now move on to a slightly different printing routine. Whereas above we were simply looping through and printing the next ASCII character, we’ll now print a 20 character long string stored in memory – “Howsaboutis, then!!!”.
We store this string right at the end of our program on line 35, with the label text2;
DM "Howsaboutis, then!!!"
We’ll now be introducing a new concept – Pointers. In the previous loop, a call to the
RST 16 routine would go ahead and print the contents of the A register to the screen. If we want to print a string, we need a way of grabbing each character in our string and sending it to the
RST 16 routine.
This is where Pointers come in… Pointers allow our application to grab an item at a location in memory based on a value in a register – This value is our pointer and points to the position of our string in memory.
In our second loop, we begin on line 18 by setting up our pointer by loading the start of our string into a pair of registers; H and L. These two 8 bit wide registers can be combined together into a single 16bit wide register. We need to do this, as the RAM of the SAM is 16bits wide – That is, an 8bit register can hold a value from 0 to 255, whereas a 16bit register can hold 0 to 65535;
We’ve stored our string at a position denoted by the label
LD instruction takes the address of the text2 label and loads it into the H and L register pair. We’ll see later what this looks like when we get onto Debugging.
On line 19 we set up the scope for our loop… Our string is 20 characters long, so we need to loop through each of the 20 characters and PRINT it to the screen. Again. we use the B register here for our loop, as the A register is used to hold the value to show on the screen;
On line 21 we have the start of our loop, and the first time we start utilising the Pointer we set up at Line 18;
The line above introduces a new style of instruction, where we’ve wrapped an operand in Parentheses, this denotes to the Assembler that this operand is a Pointer. So we’re saying that we want to LoaD a value, pointed to by the HL register pair, into the A register. The first time round this loop, this will the the ASCII character H, or Decimal 72 / Hex 48.
Next, on line 22, we have a familiar call to
RST 16, which we know by now, Prints the contents of the A Register to the Screen.
On line 23, we use the
INC or INCrement instruction, to point the HL register to the next character in our string;
Next, on line 24, we us the DJNZ or Decrement and Jump if Not Zero instruction to decrement our Loop Counting B register;
This instruction, decrements the B register, and if the register isn’t Zero, that is, the result of Decrementing the B register doesn’t set the Zero Flag in the processor, then the code should jump to the print_loop label on line 21. Obviously the first 19 times around the B register will be counting down to zero, and only when we’ve printed the final character – An exclamation mark – will we exit the loop.
Understanding the code
The Final Loop – Reading the Keyboard
With the main body of our program complete, we have one final step to take care of… Running our code at the minute, will happily work without any errors… The only problem is, once it’s finished showing our ASCII table and our string,it exits right back to BASIC, and both disappear… Not the best result!
What we need to do is show our ASCII table and string, then wait for the user to hit a key before returning to BASIC.
As I mentioned earlier… The SAM Coupé ROM has got a set of pre-programmed routines which can be accessed by our code. We have access to a routine called
JREADKEY which reads the keyboard, and if a key is pressed, stores the key value in the A register. If no key is pressed, the Z or Zero flag is set.
On line 28, we
CALL the address for
JREADKEY which is &0169. You’ll notice that we’re not using
RST here, which is because this routine doesn’t fall under the small remit of routines covered by the
wait_for_key: CALL &0169
This line forms the start of a loop where we wait for the user to press a key. On line 29 we check the Zero flag, and if it’s set, we simply return to line 28 and check the keyboard again;
It should be noted, that as well as the
JREADYKEY routine,we could have also simply used the
JWAITKEY routine. However, I chose
JREADYKEY to demonstrate how we loop to wait for a key press.
Finally, on line 30, we have the
RET or RETurn instruction. This instruction exits the program and returns us back to the BASIC interpreter;
And that’s the end of our code… Once assembled, running this code will produce a result like the following;
But, before we get to actually see our program running, we need to assemble it, and convert it into a disk image…
Assembling the Code
Ok… So we’ve completed the code, it’s time to make it into something we can run! The process of turning a raw text Assembly Language file into an executable program is called Assembling. This process converts the individual Mnemonics into Machine Code Opcodes and Operands – Essentially Binary, which the Z80B processor can run.
The tool we’ll use to assemble our code is Simon Owens’ branch of PYZ80. PYZ80 as the name suggests, is a Python based Assembler, which allows us to take our code file, add in a DOS image, and produce a SAM Coupé compatible Disk image. We’ll go through the steps needed in detail here…
The first thing to do is make sure that you have Python installed – You can install either version of Python at this point, as Stefan Drissen as kindly updated PYZ80 to be Python 3 compatible.
Once you’ve installed Python, it’s a good idea to check that it’s installed correctly and up and running, the best way to do that is to open up a command prompt and type
python.If python is installed, you should get something along the lines of;
You can see above, that I have Python 3.6.2 installed. If you receive an error instead, go and make sure that Python is installed correctly, using a repair install.
Once, you’ve got python installed, download a copy of Simon Owens’ branch of PYZ80 and unzip it to an easy location on your hard drive. I renamed the main directory and chose just d:\pyz80…
Once you’ve done that, You can copy or move your Source File into the same directory as pyz80… This isn’t strictly necessary, but just makes like easier when we come to run our commands.
Next , open a command prompt in the pyz80 directory, and we’ll try assembling our code for the first time…. The Assembly process at this stage is rather simple, where we simply type;
python pyz80.py helloworld.asm
pyz80 will then Assemble our code and automatically create a SAM Coupé Disk Image image for us;
All being well, you’ll see something similair to what you can see above… If not, then check what the error message is telling you, and look at the appropriate line in your code.
Our directory now has our brand new Sam Coupé Disk Image in it;
Wahoo… We’ve just successfully Assembled our SAM Coupé source file!
The next step is to try running the code in SimCoupe… SimCoupe is what is known as an emulator – A piece of software which, when running, pretends to be the hardware and software of another device. In this case,the original SAM Coupé.
First, go ahead and download the latest SimCoupe release from github. Extract the zip file to somewhere memorable on your hard drive and run the SimCoupe executable. All being well, you’ll be presented with the familiar Sam Coupé Opening Screen;
We can now try opening our newly created Disk Image and seeing if SimCoupe will run it for us… So, go to File>Open and navigate to your pzy80 directory and open your HellowWorld.dsk file… All being well, as soon as you finish opening the file, SimCoupe should automatically load your program, and you should see something similair to;
Assembling the Code
For a real SAM Coupé
We now have a program that compiles and runs in SimCoupe! But, what we really want is to be authentic and run our program on a real SAM Coupé… There’s a few steps to go through to achieve this…
Firstly, you’ll need a copy of Andrew Colliers Disk Image Manipulator… Download and extract this to a location you can remember on your hard drive.
Next we need to add SAMDOS to our image… In order to do this, you’ll need to go and grab a disk image of SAMDOS 2… Download that and save it to the directory you put the Disk Image Manipulator. It might be worthwhile renaming that file to something easier to type in later, like SAMDOS2.dsk maybe?
What we’re going to do is extract the actual SAMDOS file from our Disk Image. Adding this file to our Assembled Disk Image, will allow the SAM Coupé to load our Program.
So, open a command prompt and run dskman32 (No i!)… You should be presented with a simple interface;
Press the O key on your keyboard, and you’ll be prompted to enter the filename of the Disk Image you want to open. If you renamed your file as I suggested, then type SAMDOS2.dsk here and press enter, after which you should see that the Disk Image has been loaded;
We can now examine the contents of the loaded Disk by pressing the D key, which should look something similair to;
The file we want to extract from this disk is the first item listed called “samdos2”. So, if you press L key to “Load file from .dsk” you’ll be prompted to enter a filename. This is the filename of the file within our Disk Image, so enter “samdos2”, then press return. Next you’ll be prompted to enter a filename to save the samdos2 file as. Enter samdos2.raw here and press return, after which the program will tell us that the file has been saved, along with some details about it;
We can now quit the Disk Manipulator using the Q key. Now that we’re back to the command prompt, if you run the dir command, you should see our new samdos2.raw file;
Using explorer, copy the samdos2.raw file to your pyz80 directory and open a command prompt there again if you’ve closed that window.
We can now reassemble our source code again, but this time, we can “include” the samdos2.raw file with the
-I switch. So, if you type;
python pyz80.py --nozip -I samdos2.raw helloworld.asm
Which should assemble correctly just as before. You might have also noticed that we’ve added a
--nozip switch. This allows the Disk Manipulator Program to open our disk image.
With that in mind, go ahead and copy our helloworld.dsk file into the DiskmanDOS directory using explorer, and switch back to, or open up a new command window at that location, and run diskman32.exe.
Press the O key and enter “helloworld.dsk”, which should happily load our new Disk Image. Press the D Key, and we should now have the “samdos2,.raw” file and our “helloworld” file;
You can now quit the Disk Manipulator program, and open up SimCoupe again… Open your new helloworld.dsk Disk Image and make sure it still works!
Writing the Image to a real disk
Ok… Now it’s time to get serious and try our program out on a real SAM! You’ll need a PC with a Floppy drive for this bit of course… You won’t be able to use a USB floppy drive, as we’ll be writing a non standard image to the Disk, which USB Floppy Drives won’t let us do. You’ll also need a Dual Density 720Kb Disk… (Or possibly just tape across the hole on a HD 1.44Mb disk 😉 )
So, fire up your Floppy Drive based PC, and download Simon Owens SAM Disk…. Go ahead and extract that to somewhere memorable… I just put mine in the root, so c:\SAMDisk.
Next your going to need a driver so that SAMDisk can control how the floppy drive reads and writes images at a lower level… For this you’ll need to install a driver called fdrawcmd.sys.
Once that’s installed copy your helloworld.dsk file into your c:\SAMDisk (or whatever you called it) directory and open a command prompt at that location. running a dir command should show something like;
We now need to run SAMDisk and have it write our image to disk. Generally you won’t need any options for this at all, although, if you struggle to get images to work, spend some time looking at Simon Owen’s website, and see if you can figure it out. The command we need to run is simply;
samdisk helloworld.dsk a:
Inserting a disk and running this command will write the image sector by sector, head by head to our disk;
The above has been sped up by quite a few times of course, but when it’s complete, and assuming you don’t get a failure with a red warning… Your disk is ready to pop into your SAM Coupé and hit F9!!!
Debugging our code
Moving on in our path of developing SAM Coupé software, we’re likely to write more and more complicated software. Eventually we’ll end up having a problem that we need to diagnose. The easiest way to do this is to use a debugger… Nicely, SimCoupe has a debugger built in… So, open up SimCoupe again, and load your helloworld.dsk file.
Our program will be shown… We can now invoke the debugger… In version 1.2 of SimCoupe, you can access the Debugger by pressing the “/” key on your numberpad. If you haven’t got a numberpad on your keyboard, you can either access the debugger from the Tools menu, or download a NumberPad emulator such as NumPad. This will show the SimCoupe Dissasembler;
We now need to find our code. User code is separated into pages of 64k in the SAM Coupé Memory. The SAM Coupé has two registers which control which page of RAM is active – The LMPR (Low Memory Page Register) and HMPR (High Memory Page Register);
Our code is stored at 32768 if you remember, which is 8000 in hex. So we need to select Section C above. We do this by loading the HMPR register with a 1, which selects the first 64k page of RAM in Section C, which is where our code is. To do this, with the debugger open, press the “H” key and enter a value of “1” followed by pressing Enter.
Next we need to navigate to the start of our code, which resides at address 8000. To do this, press the “A” key and enter a value of 8000, which should show us our code;
You’ll see that the SimCoupe Debugger refers to all values in HEX rather than the Decimal we’re using in our source code. However, you can see our first two lines of code proper beginning at address 8000, which in our code begins at the label print_test;
If we’re having trouble with our code, what we ideally want to be able to do is step through each line of code and examine the contents of the various registers. We can do this in the debugger by setting what’s known as a BreakPoint at our first line of code. This has the effect of stopping the execution of our code when the program hits the line with the BreakPoint set on it. To set our BreakPoint double click the top line of code –
LD B,60. This will turn that line red, indicating the BreakPoint has been set successfully;
Now, press the escape key to exit the debugger, and press the F9 key to boot our code back up again, at which point, the debugger should be shown, the code should stop and the line we set our debugger on should be highlighted to indicate that’s where the current execution is;
You’ll notice that the code in the debugger window is missing all of course labels however. This is common in debuggers, as the assembled file we created normally has no way of conveying our labels to the Debugger, instead, all the labels are replaced with their numeric equivalents. While functional, this doesn’t make for a nice reading experience… So, with a tip from Simon Owen, we can slightly modify our PYZ80 assemble command to create what’s known as a “map” file. This file, when used with the SimCoupe debugger, allows the debugger to convert the assembled numbers in the source code back into their text equivalents… Very neat!
So, to create our “map” file, we use the following command for PYZ80;
python pyz80.py --nozip --mapfile=helloworld.map -I samdos2.raw helloworld.asm
Once you’ve created a new version of the HelloWorld.dsk file, reset SimCoupe, and reload your disk. Follow the same steps as detailed above to set the debugger up and set a BreakPoint. This time when your code breaks, you should see a nicely annotated version instead;
We can now step through our code using the Number-Pad 8 key. This has the effect of stepping over each instruction, meaning that any execution will simply step over any CALL or RST instructions, rather than stepping into each routine separately, which just simplifies this demonstration somewhat.
As I mentioned earlier, while I was getting started with this code, which as I mentioned was taken from FRED Magazine Issue 6, I found that it didn’t work correctly for some reason. The issue was introduced upon a call to
RST 16 (
RST 10 in the debugger). We can actually see this issue in action if we step through the code past the
RST 16 instruction;
You’ll see, at 8002 we load the value of 20 into the A register. You can see the Value of the A register at the top right section, combined with the F register, being set to 203B after the instruction at 8002 has been executed – The A register has a value of 20, the F register has a value of 3B.
After storing the A register in the C register at 8004, we have the
RST 10 call. After we’ve returned from the
RST 10 call, you can see that the Value of the A Register has changed from 20 to 00. This had the effect of causing our loop to, well, loop forever, show a page full of “?” symbols, and eventually crash out.
As a result, I added the lines which store and retrieve the A register in the C register, which cures the problem nicely.
You can carry on stepping through the code and examine how the register change, or press the escape key, and the program will run to it’s end again.
To wrap up then… You’ve learnt how to;
- Setup your development environment for SAM Coupé Assembly Language Development, including the installation and configuration of various tools.
- Create some relevant application source code, including how it all hangs together.
- Assemble the source code into a disk image using PYZ80.
- Run your disk Image on the SimCoupe Emulator
- Extract Files from an existing Disk Image using DiskmanDOS
- Add Files into a Disk Image which assembling using PYZ80.
- Copy Disk Images to an actual Disk Using SAMDisk and run them on a real SAM Coupé
- Debug code using SimCoupe.
If you’d like a copy of the finished Disk Image, feel free to grab a copy here!
I really hope that this has helped you get started on your journey to creating some amazing software for the SAM Coupé!