Tutorial by Luca Bordoni
This tutorial is oriented to AGD programmers who are already involved in a project; it’s suggested to read & learn the AGD official documentation first.
Here, we’ll try to go deep about a hot topic already discussed on the AGD official forum by the author Jonathan Cauldwell. Learning the ASM calls, it means to bring a professional touch to any AGD work, because we’ll be able to include external machine code routines (e.g. generated by other programs), such as graphic and sound effects. That’s the only purpose of the ASM calls employment.
How an ASM call works in AGD
An ASM call (ASM stands for “Assembly”) is none other than an AGD instruction which produces the same effect of the Sinclair Basic command USR: it evokes a routine previously stored in a specified memory address.
We should know that the AGD syntax cannot handle values greater than 255… but here, we have to call memory addresses which could reach the value of 64000 and beyond! So, if in Sinclair Basic we simply write “RANDOMIZE USR 50000”, how could we give a similar instruction in AGD?!
The answer is: through three ASM commands, each-one handling values from 0 to 255. All together, these three commands will return a single instruction to AGD, building the memory address through a simple calculation.
All we have to do is to learn the way this calculation works, and the secret of the ASM calls will be finally clear.
The three ASM values
Let’s assume we have a sound effect we’ve stored at the address 50000 and we want to create the ASM call in our AGD project. The ASM commands must be written in the exact point where we want the sound to be executed (just like it happens for a BEEP command), and the code will be:
The explanation is very simple. The first parameter is a fixed value: for AGD purposes, that is call a machine code routine within the game code, it will be always set at 205, so it’s the most easy of all 🙂
Now let’s divide the starting address by 256 and jot down the result and the remainder. In our example the calculation will be 50000 ÷ 256 = 195 with a remainder of 80.
Do these numbers sound familiar? Right, they are the values for our ASM call, which will be used by AGD to build the address 50000.
ASM 205 (1st value, a fixed parameter)
ASM 80 (2nd value, the division’s remainder)
ASM 195 (3rd value, the division’s integer result)
We’re ready to include our “special effects” in our AGD game! Just don’t miss some important notes in the next chapter.
Tip for advanced users: the 195,x,x combination jumps to the memory address without storing the last address in the stack (as the 205,x,x does). This could be useful for starting a game from the beginning when we use a custom Basic menu, where we say RANDOMIZE USR 32000: GO TO (menu start line). Using the 195,0,125 combination (that is the equivalent of the USR 32000) at the end of the AGD win/lose event, there’s no more need for the GO TO command in the Basic menu, since it won’t return to Basic when the game ends.
Follow progressive steps as good practice
If an AGD project with ASM commands is tested, the program will crash, losing all the possible coding progress! That’s why it’s very important to save apart a clean AGD project, without ASM commands (or ASM commands with zero values).
1 ─ Finish the project. Once the code is complete, it’s possible to check the available memory space and choose the starting memory addresses for the machine code routines we want to integrate (see the memory references chapter below).
2 ─ Check the available memory and prepare your external routine files. Take note of the memory address to call and make the ASM calculations to use in the AGD project.
3 ─ Write the ASM commands inside the AGD project in the points where the routines have to be called, but set all the ASM commands to zero. This way, you’ll preserve a backup project which can be still tested: the ASM 0 commands won’t affect the running of the AGD test. Save this project apart.
4 ─ Open the previously saved project and replace the ASM 0 commands with the previously calculated values. Then save the project as a new file. This project cannot longer be executed (tested) from AGD (unless the ASM values are changed again to zero).
Now the code (with the correct ASM calls) is ready to be saved from AGD. From the Basic loader, we’ll have to load the various machine code blocks, that is the final AGD save and the machine code routines.
Skilled ZX Spectrum programmers will be able to merge the external routines along with the main AGD game code, in order to load a unique file in the loader.
Considering a finished AGD project for a 48K ZX Spectrum, always take in mind these parameters:
Lower memory references:
─ a memory range starting from the address 23552 is reserved to the Basic System Variables; in order to avoid possible crashes, it’s suggested to place the routines not before the address 24600;
─ the lower usable memory starts around the address 24600 till the starting address of the AGD project (-1).
Upper memory references:
─ an AGD project cannot exceed the address 64767;
─ the upper free memory starts from the ending address of the AGD project (+1) till 64767.
Still about the upper memory, there are some useful informations from the AGD official instructions:
At the very top of RAM, the last 768 bytes from 64768 to 65535 are used as a dummy collision map area to distinguish between different types of blocks – walls, ladders, empty space and so on. At the end of the game is an area of 300 bytes used for the particle engine should you decide to employ lasers, vapour trails or explosions. This buffer does not exist in the puzzle or effects engines.
AGD ASM CALCULATOR
Enter an usable memory address (between 24600 and 64760) and get your ASM values on the fly!