Beyond the Basics

Printing to the Screen from Machine Language on the Atari

Larry Isaacs

If you use machine language you'll find this useful. There are two techniques presented here: screen output and a relocating loader.

If you are machine language programming on the ATARI, it can be very advantageous to know where some of the operating system subroutines can be found. I can provide you with only one at this time, but it's one of the handier ones. This is the output subroutine for the Editor device. It accepts the full ATASCII character set, printing the displayable character on the screen, or executing the control characters. To use the routine, simply load the character into the accumulator and execute a JSR $F6A4 instruction. The only other fact needed is that the X and Y registers aren't preserved by this subroutine.

To illustrate the use of this subroutine, the DUMP program is provided. This program also illustrates one way of using machine language with BASIC. The program asks for starting and ending addresses, which should be given in hex. Then the requested memory is dumped on the screen by a machine language program executed by the USR command.

Naturally, before the machine language can be executed, it must be placed in memory. This is done by the BASIC subroutine in statements 10200-10430. This subroutine loads machine code found in DATA statements, which begin at line 20000 in this program. The first thing the subroutine does is read the number of bytes in the machine language program. It then dimensions DMY$ to length 1 and an array called STORAGE of sufficient size to hold the machine code.

The subroutine then starts reading the data as strings and POKEing the appropriate code. If the string read doesn't start with a special character (".", "*", "+", "=", or "!") then the string is assumed to be two hex characters which are stored in the next available byte. If the string begins with a ".", then the string is assumed to be a comment and is ignored. If it begins with an "*", the subroutine assumes the rest of the string is four hex characters which form a two byte address. This address is POKE'd low byte first, then the high byte. If the string begins with a "+", the rest of the string is assumed to be four hex characters which form a two byte displacement from the beginning location of the code. This displacement is added to the beginning location of the code to form a two byte address. This address is also POKE'd low byte first, followed by high byte. If the first character is an "=", then the rest of the string is assumed to be a displacement as with "*". However, once the address is computed, the current poke location plus one is subtracted from this address to form a one byte displacement which is POKE'd into the next location. Finally, if the first character of the string is an "!", the subroutine stops loading machine code. The rest of the string is assumed to be a two byte displacement as with the "*", and the computed address is checked with the current poke location to see if it matches. If they don't match, it's likely that you've miscounted some bytes and that some of the displacements given by strings starting with the "*" or "=" character are in error.

This may seem somewhat complicated, but it really makes it fairly simple to write relocatable code. This relocatability is necessary because you don't know where the code will be loaded until the program is running. Relative addressed used by branch instructions may be given as a hex byte or as an "=" followed by the displacement from the beginning of the program. Internal absolute addresses should be given with a "+" followed by the displacement. And finally, external addresses can be specified by giving two hex bytes, or by an "*" followed by the address.

Once the code is loaded, ADR(DMY$) gives the first location. This also happens to be the entry point of the machine language dump program. Now the dump routine can be executed by calling for the USR function to be executed with ADR(DMY$) as its address. This is done on line 80 of the BASIC program.

It is important to note that the dump routine can only be executed while the BASIC program is running. Trying to execute it by a direct command will not work because the direct command gets inserted in between the end of the program and where the machine code has been poked. This will cause the machine code to be moved. Since it contained some internal absolute addressing, it will not execute properly any more. If the code contains no internal absolute addressing, it can be executed by a direct command.

The machine code is fairly simple, so you should be able to understand what it is doing. Upon entry, the machine code first checks to see if the right number of parameters are present. If not, the parameters are pulled off the stack and the program returns to BASIC. If the correct number (2) is present, the machine code will dump the requested memory, printing 8 bytes per line.

I hope you will find some of the techniques used in this program useful, as well as the program itself.

Program: Print to Screen in Machine Language

Download (Saved BASIC)
Download / View (Listed BASIC)

Return to Table of Contents | Previous Section | Next Section