Some Assembly Required
by Robert A. Peck
Each month in this column I'll be showing you how you can get more out of your Atari computer. As with many other processors on the market, the real power of the computer is only accessible if you learn how to talk to it in the most direct way. This direct communication requires that you learn the language that the machine itself speaks-Assembly Code.
If you work with Basic or some other language for a while, you know that a program often takes a very long time to complete its task. Some of you may have learned various tricks to speed up the program. For example, one of the tricks is to disable the video output during long computations to avoid the video memory access time from slowing down the processor. Another trick is to make up as many compound statements as possible, because the more line numbers you have, the longer Basic could take to find the selected one.
The ultimate speed trick is to use as much Assembly code as possible. This gives you direct control of the computer. That's what this column is all about. What is Assembly code? It is an English-like language that represents the detailed steps that a processor goes through to perform a program. Every possible processor operation is represented by a set of instructions called "mnemonics" (pronounced nee-mon-ics). These are comparable to the keywords in Basic. You will see some mnemonics later in this introductory article.
Comparison with Basic
Before going further, it might be best to tell you why assembly language is useful, and exactly WHY it does speed up the program which is running. Let's compare it to Basic.
Most Basics are designed to be very easy for a beginning programmer. They are interpretive languages. An interpretive language keeps its program inside the computer in a form which is very easy to reconstruct. This means that the program can be listed directly from the instruction types that are stored in the memory.
If the user makes an error, Basic is very forgiving, it stops, tells you where the error is located and waits for you to tell it what to do next. In most cases, all you need to do is to type a new version of the offending line and run the program again. There is no need for a delay; it is ready to try again.
This interpretive nature of Basic is helpful to novice programmers because it provides immediate feedback. They learn from their mistakes, fix them and get the corrected result immediately.
But now that you are not a beginner any more, you are writing longer programs. You have seen what the arcade games are using screen graphics and how some of the business programs are performing calculations and updating the screen. You're finding that Basic alone just can't come close to their speed. And that's why you are reading this.
Just why is Basic slow? BECAUSE it is interpretive! Each time it runs your program, it must read each of the program statements and figure out what to do with them. A simple Goto statement is a good example.
If Basic is to perform a Goto, it must find out where the line number is located so it knows where to go. In other words, if your Basic encounters a Goto, Basic must start searching at the top of the program (first line) and look at the line number on each line to see if this is the one you requested. If it is not, it must go to the next one.
If this is the search method required because of the interpretive nature of the language, you can easily imagine that if a program had 5000 sequentially numbered lines, a GOTO 1 would execute much faster than a GOTO 5000, no matter where in the body of the program the Goto was issued. This is because the search always starts at the first line and proceeds towards the highest numbered one. (The second Goto should take about 5000 times as long to execute.)
If, instead of Basic, you used Assembly code, a GOTO anywhere would execute in the same amount of time (about 3 machine cycles) no matter where in the program the GOTO (in Assembly code JMP for Jump) was issued. That is a major difference. The Atari executes about 1.7 million machine cycles per second.
Assembly language is not as easy to use as Basic. For one thing, you will have to have access or "invent" some of the functions that are automatically built-in to a language like Basic. In addition, you will have to wait each time you change the program for the Assembler program to translate your English-like language into something that the machine can understand. And, unlike Basic, there is a chance that something you program can send the machine off into Never-never Land (because of your direct control over what the machine is doing).
But, on the brighter side, Assembly language, once translated into machine code, is ready to execute immediately each time. The machine does not need to read and interpret each line. Instead it will directly execute the statement, at the fastest possible speed. So that is the trade-off you will be making--you'll spend more time developing your program in exchange for maximum execution speed later.
This month's column will close with an example written in Atari Basic and the same example written in Assembly language. The machine codes are the translated . . . number you will see in the DUMP that follows the example. These are in the instructions which the machine itself understands. The example itself contains the Assembly language, that is, the English-like language which you are going to learn to read and use.
Because the Atari Assembler Cartridge is likely to be the most widely used among the readers, I'll show all examples in a format compatible with this assembler. As we go along however and some longer examples are required, I'll use some other assemblers for printout clarity.
We won't go into details this time on how to get the Assembly code example into your machine. If you have the Atari Assembler, or a friend who has any 6502 assembler, ask him or her to show you how to try the example.
Next month we'll begin to cover the Atari Assembler Cartridge, using this example as the basis of the article.
Some notes about the examples below. Both show a delay being performed. The first one, in Basic, performs the delay in about the minimum time possible where a For/Next can be used. Both the For and the Next occur on the same line, and the program is really short. This program takes about 140 seconds from the time it starts line 20 until it ends and prints the results.
By contrast, the assembly language program which follows it performs exactly the same function, merely a count from 65535 to zero. Before it starts, it zeros the Atari real-time clock location so it can later display what the loop time was on completion. These appear in A, X and Y, with Y showing the sixtieths of a second count.
This program shows an average of 15/60ths of a second (1/4 sec) to do the same function in Assembly Code. Different functions take different times, but it would seem that a factor of 560 to 1 in speed, at least for one example, may be enough to interest you in learning more.
By the way, in this column I'll try to respond to reader questions if possible. You will have the chance to ask just what you wanted to know about how to use Assembly code on the Atari. It won't be possible to go into really long examples, because I'd like to put out enough beginners info to bring them up to speed. But problems which might be answered by a small example of sorts are more than welcome. Well, see you next month with another installment.
Listing 1. Basic program to count from zero to 65535 (using the For/Next function).
Listing 2. Assembly code counter from 65535 to zero in Atari Assembler Cartridge format.
Robert Peck has published articles in a number of magazines. Currently he is writing a book on Atari Basic for Howard W. Sams. He is the author of several manuals for Atari, Inc. Bob lives and work in Sunnyvale, California.