Classic Computer Magazine Archive COMPUTE! ISSUE 55 / DECEMBER 1984 / PAGE 193

INSIGHT: Atari

Bill Wilkinson

As I promised, this month will be spent answering more letters. Some of the topics I will discuss here have been requested many times; others are unique queries that provide an insight into the workings of your Atari. I think they are all interesting questions.

Before starting on the questions, though, I have a bit of news that can't wait: Microbits (Albany, Oregon) is currently developing both a parallel floppy disk drive and a hard disk system for the 800XL. Preliminary speed measurements indicate that we may be able to read/write over 40,000 bytes per second to and from the disk. Imagine being able to load any of your favorite games from disk in half a second or so. Presumably, you would use the parallel floppy to back up the hard disk. Since even a five-megabyte disk (small by today's standards) takes 25 double-density floppies to back up, anything Microbits does to enhance the speed or density of the floppy will be appreciated.

Microbits has not announced any delivery dates yet (in fact, they haven't even finished development, so they can't deliver anything), but I think you should ask your local dealer to get all the information he can as soon as he can. Just think of the possibilities for graphics applications (do you realize that you could load five or six graphics mode 15 pictures per second this way? Or how about windows?).

Phase Errors

Michael Richardson, of Plattsburgh, New York, used the machine language graphics routines printed in this column in 1982 as the basis for a set of his own routines. He ran up against an unexpected error with the Atari Assembler Editor cartridge. Although he did not provide a complete listing, I will present what I believe is a correct excerpt here:

10	* = $600; (or any other good location)
20	DRIVE = FNAME+1; see below
30;
40	LDA DRIVE; looks reasonable, doesn't it?


99	FNAME .BYTE "D1 :ANYNAME.*"

Now that tiny segment of code certainly looks innocuous, doesn't it? But when you try to assemble it, it gives you an ERROR 13, a "phase" error. Why?

Before answering the question, let's consider what would happen if we replaced line 40 with:

40	LDA FNAME

Do you know what will happen? Can you guess? Believe it or not, you will not get a phase error from the Assembler Editor cartridge.

Let's take this step by step. Remember that good old ASMED (if you will pardon my inventing an acronym for ASseMbler EDitor) is a two-pass assembler. On the first pass, ASMED tries to assemble LDA FNAME and discovers that FNAME has not been defined yet. "That's okay," says ASMED to itself, "I'll just assume that FNAME will be defined later as a non-zero page location. I'll reserve three bytes for this LDA instruction." Well, lo and not-too-surprisingly behold, FNAME is indeed defined later, and it is indeed not a zero page location. Thus, on the second pass through the source code, ASMED generates a three-byte LDA instruction (both in the listing and in the object code). Pass 1 and pass 2 have agreed on how much code to generate. Voilá, no phase errors.

What happens, though, when ASMED tries to assemble our original line 40, LDA DRIVE? Well, ASMED is smart (just how smart we will see in a moment), but it's not exactly all-powerful. When it encountered the line DRIVE = FNAME+1, it said to itself, "Aha! FNAME is undefined. But since it is used in an expression, I must give it a value for now. Hmm. Why not give it a value of zero?"

Why not? Because then FNAME + 1 is evaluated by ASMED as 0 + 1, and DRIVE is given a value of 1. ASMED is not smart enough to realize that DRIVE should be considered undefined along with FNAME.

The consequence? During pass 1 of the assembly, ASMED sees LDA DRIVE as being equivalent to LDA $0001, a zero page reference which thus requires only two bytes of memory. But—you saw this coming, didn't you—by the time ASMED gets to LDA DRIVE on pass 2, FNAME has been defined and so DRIVE gets a value of other than one (presumably $06xx in our little example). "Okay," says ASMED, "I'll generate three bytes for the LDA." Oops! Phase error!

Before discussing the fix for this problem, I would like to point out that many (if not all) of the other assemblers available for the Atari would also produce a phase error here. More interestingly, some (many? I haven't had a chance to try them all) would probably produce a phase error even on our other example, where we coded LDA FNAME. If so, it is because they treat undefined labels as having a value of zero, and thus reserve space for only a two-byte instruction on pass 1. The situation gets even stickier with forward referenced and/or undefined macro parameters, as implemented in the various macro assemblers available.

Anyway, what is the fix? Well, my favorite rule is simple: Never use a label until after you have defined it. I can't think of any occasion where this rule will get you in trouble. I can think of lots of ways that ignoring it can cause strange programming problems. My suggestion for the code in question would be to simply rearrange it, thus:

10	* = $600	;(or any other good location)
20	FNAME .BYTE "D1 : ANYNAME.*"
30	DRIVE = FNAME + 1	;guaranteed to be defined now
40;


99	LDA DRIVE	;always three bytes now!

Give Me Room

Matthew Ratcliff, of St. Louis, Missouri, sent me a very complete listing of a program he calls "GTIA TEXTWRITER" along with some fairly thorny problems. Without repeating the actual questions, I think I can safely say they should all be lumped into the category of assembling relatively large programs on an Atari computer. Since many people (including Ratcliff) are still using ASMED, let's begin with a look at how ASMED uses memory.

Much has been written (here and elsewhere) about how Atari BASIC allocates memory, but I can't remember ever seeing a good description of how ASMED slices up your hard-earned RAM. Shall we rectify that?

First, because ASMED was written primarily by one of the members of the Atari BASIC team (Kathleen O'Brien, and in less than three months), it is not surprising that ASMED shares many of BASIC's allocation techniques. In fact, those of you familiar with BASIC's use of the memory pointers at $80 through $92 would be right at home if you looked at ASMED's source code. There are, however, some major differences.

Just as BASIC has to juggle the several parts of your program (variable name table, the tokenized program, arrays, etc.), so must ASMED find places for its needed components. While you are using just the editor, this task is simple: No tokenizing takes place, no variable name or variable valuable tables are built—just straight-forward expands, contracts, and inserts of your source code lines.

When you assemble, though, ASMED must find a place to put your symbol table (all the labels used in your program and what their values are, etc.). For its own convenience, ASMED simply places the symbol table in memory directly following your source code. Object code is easier: ASMED puts your object code where you tell it to. If you are assembling directly to memory, ASMED puts it in memory exactly where your *= directives tell it to.

I spot some potential trouble with that last part, don't you? But let's look at what ASMED can tell us about its usage of memory: Probably the most overlooked tool in the ASMED user's reach is the SIZE command. This is roughly the equivalent of BASIC's PRINT FRE(0). When you use SIZE, you are presented with three hexadecimal numbers. The first is the lowest non-zero page RAM being used by ASMED. The second is the current top-of-the-program source code in memory. (Even if you have no program in memory, ASMED has some fixed overhead, so this number never equals the first one.) The third hex number gives you the top of the memory which ASMED will use. Not surprisingly, the first and third numbers are derived from the Atari OS locations LOMEM (at $02E7) and HIMEM (at $02E5).

Let's take a hypothetical situation (which might really occur if you used a 16K machine with a cassette recorder) where you type SIZE and ASMED responds with:

0700	321C 3C1F

What does this display tell you? It tells me that this person may be in trouble. He has only $0A03 (2563 decimal) bytes left for his symbol table when he assembles this program. Depending on the size and number of his labels, that may or may not be enough space. But that's only the first problem.

Where is the object code going to go? Aside from poor, overworked page 6 ($0600 to $06FF), that ??? isn't any memory free (and page 6 probably isn't big enough to hold the output from this assembly, anyway). What to do? Well, the obvious answer is to assemble your object code directly to the tape recorder. You do that simply by giving the command:

ASM ,,#C:

to ASMED. Then you can use NEW, check memory with SIZE again, and LOAD the object code back in memory, ready to debug it. Not bad. Time-consuming, but it works.

Or does it? Many people complain that after producing an object tape they cannot reload it successfully (usually, they get an ERROR 138, timeout). Why? Simply because ASMED turns on the cassette recorder at the beginning of pass 1, even though it may be a minute or two before pass 2 writes anything to the tape. Also, if you are producing a listing, the time taken to write the tape increases to the point where other start/stop errors are possible. There is no total fix for these problems, but here are some suggestions which might help.

First, do your assembly twice, once for the object code and once for the listing. During the object code assembly, turn off the listing (by using .OPT NOLIST as, say, line 1). Before starting the assembly, zero your tape counter. Then, as the object code is assembled to cassette, listen in (turn up the volume on your television). When you hear the first burst of data being sent to the cassette (near the beginning of pass 2 of the assembly), note the value of the tape counter. Then, to reload the object tape, rewind the tape to about five to ten seconds ahead of the counter value you noted. And that's about as good as you can do using ASMED with a cassette recorder.

Before going on, I'd like to discuss a point I sidestepped a couple of paragraphs ago. I noted that the SIZE command gave the memory used by ASMED (exclusive of symbol table space). Perhaps not obvious to many first-time users of ASMED is that you may not direct object code (via * = ) to memory anywhere between those first and second numbers. (And you'd better leave a healthy hunk alone above the second number for the symbol table.)

What happens if you don't follow this rule? Typically, you find that your object code tries to share space with your source. Bye-bye, source. Or, worse, you may find the object code sitting on top of the symbol table. This can cause some extremely bizarre symptoms. I have seen ASMED start spitting out hundreds of errors for a single line when this happened.

Despite the fact that ASMED is one of the most bug-free programs I have ever encountered, it has a few very bad design flaws. And as we just noted, one of them is that it will assemble code right on top of memory it is using for other purposes.

However, for the disk user with 40K or more of RAM, ASMED presents no real problems if used properly. Since both the source code and the object code may be on the disk, the only real limitations are the sizes of the files. Obviously, the object file can be loaded in after giving a NEW command, so it need only fit between the second and third numbers given when the SIZE command is used.

But what about the source file? At first glance, it might appear that your source file is limited to what can be edited in memory. Not so! Albeit tedious, there is a way to assemble very large source files with ASMED. Simply edit the source code in pieces, none larger than ASMED's buffer space. Then, when all are ready, use the append capability of Atari DOS's option C to append one file after another to the first piece of the source. (Please do this on a copy of your master disk. It's very easy to make a mistake and append in the wrong direction.) Now you can assemble this giant source file.

There are, of course, some real disadvantages with doing things this way. The biggest of these is obvious: What happens when you get an assembly error in the middle of the fourth of the appended files? You have to edit that file and then go through the backup and append process all over again. Another problem is simply the speed of ASMED. If you expect to assemble 16K of object code, even without a listing to the printer, you might as well go out to a movie while you wait. A double feature. Finally, ASMED's extravagant use of zero page memory (leaving you, the programmer, only about 32 bytes) can be a real killer with large programs.

Well, we've wandered a little off the original track here, but it's all been germane to the problems of assembling large programs on your Atari. Is there a general solution to these problems? Several, if you have a disk drive. What are they? Just a nice selection of other assemblers.

ASMED is a usable introduction to machine language programming, but it is (after all) only 8K bytes long, and a lot of features had to be pared to make it fit. So when it begins to grate on your nerves, get rid of it. What do you get instead?

Since my company (OSS) produces MAC/65 (also a cartridge-based assembler, editor, and debugger), any answer I give is bound to be prejudiced. So I will simply tell you to go out and compare the prices, features, and speeds of the various assemblers available. You might, for instance, consult The Book of Atari Software, 1984, from either the Book Company or Addison-Wesley, which describes several assemblers and gives comparison charts. The advantage of getting a second assembler is that you now know what parts of ASMED you did not like, and you can look for assemblers that fix these areas.

16 Megabytes?

The topic heading here does not refer to any secret projects going on behind closed doors. Rather, I have been asked (more times than I can count) about the 16-bit version of the 6502 which has been developed by the Western Design Center (of Mesa, Arizona). I believe it is designated as the 65816, and is purported to be faster than a Motorola 68000 in many operations and capable of addressing 16 megabytes of memory. The question I am asked is fairly obvious: "Can I put this chip in my Atari and address 16 megabytes and make BASIC run faster and …?" The answer is simple: no.

I can't let an answer like that sit around naked, so let's see if we can't flesh it out a bit. First, in order to address 16 megabytes, you have to have 16 megabytes. Have you seen any 800XLs with a lot of spare RAM floating around lately? Further, addressing 16 megabytes means you must have 24 address lines. (The 16 address lines in your Atari computer can access only 64K.) There simply isn't any place provided on the Atari circuit boards for such an expanded address bus.

Now, at least one version of the 65816 is purported to be pin-compatible with existing 6502s. If this is wrong, I apologize. I admit I am repeating what I have been told. Presuming this to be true, though, it may barely be possible to imagine an expansion box for an 800XL which can properly decode some sort of I/O signal to "bank" in additional RAM. I suspect, though, that the pin-compatible version may be so compatible that it limits you to 64K of memory.

So far, however, this highly hypothetical discussion has assumed that the chip will be compatible enough (with a 6502) to fool the rest of an 800XL's circuitry. I'm not convinced that this will prove to be true. Why? Because the 65C02 (which, you may or may not recall, is a CMOS version of the 6502 which adds a few—still all 8-bit—instructions and capabilities) does not work in an 800XL. Even though it works great in older Atari 800s.

I am not sure why the 65C02 is incompatible with the 800XL, but I have been told it is because Atari started using a custom version of the 6502 in its newer machines. (The story is that the newer CPU is the same one found in the 2600 game machines, and it has one or two pins used differently.) In any case, the problems with the 65C02 cause me to doubt that the 65816 will enjoy a better fate.

Last, let us assume that you really can plunk a 65816 down into the middle of your 800XL. Will it do you any good? Not unless you are a heavyweight in machine language. Compatible means just that: It executes all standard 8-bit 6502 instructions in the same old way. And where are you going to get any of the new 16-bit instructions from? I dunno. It is extremely doubtful that any major software vendor will be able to justify the expense of developing programs which use the 65816 in an Atari, since using the chip involves doing nasty things to your computer that very, very few users are willing to try.

And there you have it. I hope I am wrong about much of the above, solely for my own personal satisfaction with such a 16-bit machine. But—sigh—I am probably mostly right. (But what if … nah … it couldn't happen.)