Coding Compendium
A free 100-page ebook collecting my projects and tutorials for Raspberry Pi, micro:bit, Scratch and Python. Simply join my newsletter to download it.
Sean McManus shows you how to integrate machine code with your Amstrad Basic programs
Eventually Basic begins to get claustrophobic and limited. Versatile as it may be, Amstrad Basic is unable to perform all the functions the machine is capable of. Most Basic programmers are driven to using the odd machine code routine in their own programs.
464 Users may have already run the fill routine at the start of this package and all Amstrad users will come up against machine code routines for handling sprites in the next section. Machine code differs from Basic in many ways. Firstly, it's just a string of numbers. Whereas you can list your Basic program and edit it (even though the machine "remembers it" in a code form), machine code cannot be edited as such. A block of memory can be full of numbers which could easily be commands, sprite data or musical notes. The only way the computer knows is by what it is looking for when it stumbles upon the code. If it's looking for commands when it runs into the music data, it will execute it anyway.
Here is another problem with machine code. It has no error messages. When things go wrong, there's no return. The screen freaks, the machine freezes. Whatever happens, it usually sentences the machine to a reset, wiping the contents of memory. Using machine code routines, you need to be especially careful. RSXs are extra commands for Basic, preceded by the bar character. Mistyping the name of one of these will often freeze the machine. Likewise, if you pass silly parameters to them or stray from the correct usage you rely heavily on the programmer having error trapped extensively. This is rarely the case, since it can double the length of the code. Initialising the same RSXs twice can crash the machine, so be careful to only run an RSX loader once. RSXs are handled slightly differently on the 464 to later machines, as shown in the chapter on downgrading.
HIMEM is a system variable which marks the top of the amount of memory allocated to Basic (HIgh-MEMory). The MEMORY command is used to set HIMEM. To prevent Basic programs overwriting machine code routines, HIMEM is usually lowered to just below where the first machine code routine begins. If, for example, your machine code is poked into locations 40000 onwards, then MEMORY 39999 would prevent Basic stomping all over it. Due to an unexpected feature (i.e. bug) in Basic, the MEMORY command plays havoc with the SYMBOL AFTER command. SYMBOL AFTER is used to define how much of the character set is to be set aside for the user to redefine. The solution to this predicament is to precede the MEMORY command with SYMBOL AFTER 256:
SYMBOL AFTER 256:MEMORY 39999
After this, SYMBOL AFTER can be issued to the correct value as necessary.
You can specify where in memory you want to load machine code programs or data by putting the location after the filename, separated by a comma: LOAD"sprites.bnk",40000 will load the file "sprites.bnk" into memory, starting at memory location 40000. If the machine complains, try lowering HIMEM to just below where you are trying to load. In this case, we would use MEMORY 39999. Basic will only let you load a machine code file above HIMEM.
As HIMEM falls and the amount of memory allocated to Basic falls, it begins to feel a lot less spacious than it used to. With memory allocation at its default, you can usually get away with up to about 38k if the program is very lean on variables. If your program is anywhere near this length, you should consider multi-loading using the CHAIN command to run a program without clearing out the current variable settings. Alternatively, if it is a game you could look at the possibility of bridging sections using passwords between parts. With machine code routines in memory, the amount of space allocated to Basic can plummet and relatively small programs can benefit from compression. Here is a list of tips on how programs can be made to tip-toe around "Memory Full" crashes more daintily:
You can check your progress by using PRINT FRE(0) to tell you how many free bytes there are between the end of your program and the top of memory. Arrays seriously eat space, so use them sparingly and ERASE them once their role is ended.
Because machine code programs are just lists of numbers, there is no equivalent of the renumber command. This causes problems when you want to use two different programs at the same time which both occupy the same memory locations. In most cases if you just load it into a lower memory location, a program will not work. All its "GOTO" commands (which are vital in machine code because they govern looping and conditional operations) will still be pointing to the old locations. There is a program on this disc which aims to try to solve this. Code Relocator will look at the code and when it finds a "GOTO" or "GOSUB" command will relocate where it points to if necessary. It expects to load the chunk of memory from tape/disc and to be told its start address, length and the address it is to be relocated to. (The word address is used to refer to the number of a memory location). Since the numbers could be anything, it will relocate graphics and sound data if it stumbles across it. It cannot handle self modifying code. This means it will not work for routines that use a score table or RSXs. It's a little hit-and-miss for more complex programs, but is worth trying. If the first program will not relocate, try the one it is conflicting with.
When you begin to use the sprite definer in the next section, you will be creating blocks of memory containing sprites. These can be a little bit difficult to manage in Basic programs. They can be saved using
SAVE "filename",b,start,length
Listings in magazines and books usually have the machine code program and data listed as numbers in DATA statements. These numbers are then read and poked into the right place, instead of needing to be loaded from disc. The Data Maker program will create a Basic loader for any sprite data or machine code programs you later write and will save it as a Basic program onto disc or tape.
As you begin to use machine code routines, you will come into contact with hexadecimal. People count in blocks of ten, probably because it's how many fingers and toes we have. Computers count in units of eight because that's how many zeroes or ones make a byte. Hexadecimal is just a different way of representing the same numbers, which has grown from the computer world's obsession with multiples of eight. Basic precedes hex numbers with a & sign. To find the hex equivalent of a "normal" number, use PRINT HEX$(number). To convert it back again, use PRINT &hex version.
PRINT HEX$(12)
gives the result C
PRINT &C
gives the result 12.
As is clear from this example, hexadecimal uses letters as well as numbers: the letters A-F in fact. &E is fourteen, &F is fifteen, &10 is sixteen, &11 is seventeen. What our usual number system knows as the tens column is the sixteens column in hexadecimal. It takes a little getting used to, but in the context of Basic is rarely more difficult than using the program's instructions.
Here's a simple tool to convert numbers between hex and decimal. Just enter a number in the hex box and press Enter to see it in the Decimal box. You can put a number in the decimal box and tap Enter to see it in the hex box, too.
When I was updating The Further Adventures of Fred, I created a simple Hexdump program to display the contents of memory. I used this together with the built-in debugger. I found my Hexdump particularly useful for reading text and paging through memory to find interesting pieces of code to investigate further.
The Hexdump program is on my updated Amstrad CPC software disc. You can also enter it into Winape directly using the Auto Type feature (Ctrl+F5), which will type in instructions for you. Here's the code:
5 ' Hexdump - Sean McManus - www.sean.co.uk - October 2020
10 mode 1:window 1,40,1,3:window #2,1,40,4,25:window #3,7,31,4,25:window #4,32,39,4,25:paper #2,3:paper #3,2:paper #4,3:cls #2:cls #3:cls #4:window #2,2,6,4,25:window #3,8,31,4,25
20 call &bc02:ink 0,0:border 0:ink 2,15:ink 1,26:pen 3:print"Hexdump by Sean McManus - 2020":pen 1:print
30 input"Memory address:",mem
35 print:print"Press ESC to pause"
40 while 1:print #2,hex$(mem):for g=0 to 7:print #3,hex$(peek(mem+g),2);" ";:if peek(mem+g)>31 then print #4,chr$(peek(mem+g)); else print #4,".";
50 next g:mem=mem+8:wend
Pokes for games can sometimes be intercepted and used to get inside the game for a look around. The CALL command is used to start executing a machine code routine (always double check the number used), so removing this from a basic program will stop the machine code program being started once it has been loaded. Pokes which have to contend with complex fast loaders can also sometimes be intercepted. C3 is the code for JumP, which is the same as Basic GOTO and CD is the code for CALL (in machine code, a bit like GOSUB). These can be used to start execution of the game. The two hexadecimal numbers after the CD or C3 represent the address that execution begins from. It is calculated by address=(first number)+256*(second number). This is a good place to start looking around. To stop the program being run and the routine returning to Basic after loading, try replacing the CD or C3 with C9. This is a RETURN instruction and should return you to Basic. It is all highly dependent on the individual case, so you might have to try a couple of the CDs or C3s before it works.
CALL is a command with attitude.
It makes it child's play to totally crash the machine if its parameter is mistyped.
It is very difficult to cause any harm that will outlive a reset but this wastes anything in memory you had grown emotionally attached to.
There are some relatively useful CALLs which can be used from Basic quite easily:
If you're looking for a particular CALL instruction in a machine code program, I've created a three-line program that does the search for you. You can find it in my article about updating The Further Adventures of Fred. You'll need to change the memory start and end addresses to your own program.
Most users only ever need the odd machine code routine to plug Basic's essential weaknesses. One of these is in sprites and the next section aims to plug this gap.
Find all my Amstrad CPC tutorials here, and download my updated software disc here!
© Sean McManus. All rights reserved.
Visit www.sean.co.uk for free chapters from Sean's coding books (including Mission Python, Scratch Programming in Easy Steps and Coder Academy) and more!
A free 100-page ebook collecting my projects and tutorials for Raspberry Pi, micro:bit, Scratch and Python. Simply join my newsletter to download it.
Web Design in Easy Steps, now in its 7th Edition, shows you how to make effective websites that work on any device.
Power up your Microsoft Excel skills with this powerful pocket-sized book of tips that will save you time and help you learn more from your spreadsheets.
This book, now fully updated for Scratch 3, will take you from the basics of the Scratch language into the depths of its more advanced features. A great way to start programming.
Code a space adventure game in this Python programming book published by No Starch Press.
Discover how to make 3D games, create mazes, build a drum machine, make a game with cartoon animals and more!