3 The Monitor A monitor is a program which allows you to work directly with your computer's memory cells. When the computer "falls below" BASIC into the monitor mode, BASIC is no longer active. If you type RUN, it will not execute anything. BASIC commands are not recognized. The computer waits, as usual, for you to type in some instructions. There are only a few instructions to give to a monitor. When you're working with it, you're pretty close to talking directly to the machine in machine language. The PET and Apple II have monitors in ROM. This means that you do not need to load the monitor program into the computer; it's always available to you. (PETs with Original ROM sets do not have a ROM monitor; you must load in the monitor from a tape or disk.) Atari and VIC computers have a monitor as part of a larger "Assembler Editor" plug-in cartridge. The monitor on the Atari cartridge is called the "Debugger." That's a good name for it: debugging is the main purpose of a monitor. You use it to check your ML code, to find errors. The various computers have different sets of instructions which their monitors recognize. However, the main functions are similar, so it is worth reading through all of the following descriptions, even if the discussion is not specifically about the monitor for your computer. On the PET/CBM, VIC, and 64 you can add many of these functions with a monitor "extension" program called Micromon or Supermon (about which more later). These monitors are included in Appendix F. The monitors on the Apple II and available in the Atari Assembler Editor Cartridge do not need "extending." They contain most of the significant features required of a monitor. However, the special extensions in Appendix F for the Commodore computers add considerably to the Commodore ML programmer's repertoire. The Apple II You enter the Apple monitor by typing CALL -151. You will see the "*" monitor prompt and the cursor immediately after it. Here are the monitor instructions: 1. Typing an address (in hex) will show you the number contained in that memory cell. *2000 (hit RETURN) will show 2000 - FF (if, in fact, 255 decimal ($FF, hex) is in that location). 2. You can examine a larger amount of memory in hex (this is called a memory dump or a hex dump). The Apple monitor remembers the address of the last number displayed. This can be used as a starting address for the dump. If you type the instruction in number one above, and then type *.2010, you will see a dump of memory between 2001 and 2010. The only difference between this and instruction one is the period (.) before the requested address. 3. You can directly cause a dump by putting the period between two addresses: *2000.2010 combines the actions of instructions one and two above. 4. Hitting RETURN will continue a dump, one line at a time. 5. The last displayed memory location can be changed by using the colon (:). This is the equivalent of BASIC's POKE. If *2000 results in FF on the screen, you can change this FF to zero by typing *:00. To see the change, type *2000 again. Or you could type *2000:00 and make the change directly. The Apple II reference manual contains excellent descriptions of the monitor instructions. We will list the rest of them only briefly here: 6. Change a series of locations at once: *2000: 00 69 15 65 12. 7. Move (transfer) a section of memory: *4000 < 2000.2010M will copy what's between 2000 and 2010 up to address 4000. (All these addresses are hex.) 8. Compare two sections of memory: *4000 < 2000.2010V. This looks like Move, but its job is to see if there are any differences between the numbers in the memory cells from 2000-2010 and those from 4000-4010. If differences are found, the address where the difference occurs appears on screen. If the two memory ranges are identical, nothing is printed on the screen. 9. Saving (writing) a section of ML to tape: *2000.2010W. This is how you would save an ML program. You specify the addresses of the start and end of your program. 10. Loading (reading) a section of memory (or an ML program) back into the computer from tape: *2000.2010R will put the bytes saved, in instruction nine, above, back where they were when you saved them. An interesting additional feature is that you could send the bytes to any address in the computer. To put them at 4000, you would just type *4000.4010R. This gives you another way to relocate subroutines or entire ML programs (in addition to the Move instruction, number seven above). If you move an ML program to reside at a different address from the one it was originally intended during assembly, any JMP or JSR (Jump To Subroutine, like BASIC's GOSUB) instructions which point to within your program must be adjusted to point to the new addresses. If your subroutine contained an instruction such as 2000 JSR 2005, and you loaded at 4000, it would still say 4000 JSR 2005. You would have to change it to read 4000 JSR 4005. All the BNE, BPL, BEQ, branching instructions, though, will make the move without damage. They are relative addresses (as opposed to the absolute addressing of JSR 2005). They will not need any adjusting. We'll go into this in detail later. 11. Run (go): *2000G will start executing the ML program which begins at address 2000. There had better be a program there or the machine is likely to lock up, performing some nonsense, an endless loop, until you turn off the power or press a RESET key. The program or subroutine will finish and return control of the computer to the monitor when it encounters an RTS. This is like BASIC's SYS command, except the computer returns to the monitor mode. 12. Disassemble (list): *2000L will list 20 lines of ML on the screen. It will contain three fields (a field is a "zone" of information). The first field will contain the address of an instruction (in hex). The address field is somewhat comparable to BASIC's line numbers. It defines the order in which instructions will normally be carried out. Here's a brief review of disassembly listings. The second field shows the hex numbers for the instruction, and the third field is where a disassembly differs from a "memory" or "hex" dump (see numbers one and two, above). This third field translates the hex numbers of the second field back into a mnemonic and its argument. Here's an example of a disassembly: `2000 A9 41 LDA #$41 2002 8D 23 32 STA $3223 2005 A4 99 LDY $99` Recall that a dollar sign ($) shows that a number is in hexadecimal. The pound sign (#) means "immediate" addressing (put the number itself into the A register at 2000 above). Confusing these two symbols is a major source of errors for beginning ML programmers. You should pay careful attention to the distinction between LDA #$41 and LDA $41. The second instruction (without the pound sign) means to load A with whatever number is found in address $41 hex. LDA #$41 means put the actual number 41 itself into the accumulator. If you are debugging a routine, check to see that you've got these two types of numbers straight, that you've loaded from addresses where you meant to (and, vice versa, you've loaded immediately where you intended). 13. Mini-assembler. This is an assembler program, though it is not part of the monitor ROM. It is in the Integer BASIC ROM, so systems using firmware Applesoft II cannot use it although the Apple II Plus can, in the INT mode. Like the Simple Assembler, this mini-assembler cannot use labels or calculate forward branches. (The Simple Assembler can be used for forward branches, however, as we'll see later.) You enter the Apple mini-assembler by typing the address, mnemonic, and argument of your first instruction. The ! is printed by the computer: `!2000:LDA #15` This will be disassembled, and then you type in the next line, using spaces between each field: `! LDY #01` 14. Step and Trace. These are very useful ways to isolate and fix errors. Remember that ML does not have much in the way of error messages. In fact, unless you are using a very complex assembler program, the only error that an assembler can usually detect is an impossible mnemonic. If you mistyped LDA as LDDA, your assembler would print ??? or, in the Apple, sound a beep and put a circumflex (^) near the error. In any case, you are not going to get elaborate SYNTAX ERROR messages. The Simple Assembler will type the word ERROR on the screen. Try it. We'll examine step and trace debugging methods under numbers 10 and 11 of the discussion of the Atari cartridge below. The Atari Assembler Cartridge and the Commodore Monitor Extension programs both allow step and trace, too. 15. Changing registers. *(CONTROL) E will display the contents of the Accumulator, the X and Y registers, the status register (P) and the stack pointer (S). You can then change the contents of these registers by typing them in on screen, following a colon. Note that to change the Y register, you must type in the A and X registers as well: `*(CONTROL) E` You'll see: A=01 X=05 Y=FF P=30 S=FE (whatever's in the registers at the time). To change the Y register to 00, you type in the A, X, and then the new version of Y: *:01 05 00 (and hit RETURN) 16. Going back to BASIC. You can use * (CONTROL) B to go to BASIC (but it will wipe out any BASIC program that might have been there). Or you can use * (CONTROL) C to go back to BASIC, non-destructively. The Atari Monitor To enter the monitor on the Atari, you put the assembler cartridge into the left slot. The Atari does not have a monitor in ROM; you need the cartridge. As mentioned at the start of this chapter, the monitor mode in Atari is called DEBUG and is a part of the larger program within the assembler cartridge. There are three parts (or modes) within the cartridge: EDIT, ASM (assembler), and DEBUG. Before looking at the commands available in the DEBUG mode, let's briefly explore how an ML program is created using the EDIT mode followed by ASM. The cartridge provides the Atari with a more advanced assembler than the Simple Assembler or the mini-assemblers available within the Apple II monitor or the Commodore monitor extension programs. The cartridge allows labels, comments, and line numbers. Until now, we've discussed ML programming which uses three fields (zones). Here's an example program which shows these three simple fields. We will print ten "A's" on the screen (the numbers are decimal):
Address Field | Instruction Field | Argument (Operand) Field
2000 | LDY | #10
2002 | LDA | #33
2004 | STA | (88),y (The screen location is remembered by the Atari in addresses 88 and 89.)
2007 | DEY |
2008 | BNE | 2004
2010 | RTS (or BRK) |
When you are in Atari's EDIT mode, you construct a program somewhat differently than you do with the Simple Assembler (or with mini-assemblers). Here's the same program using the Atari's additional fields: `Line # Label Instruction Argument Comments 100 START LDY #10 Set up counter for loop 110 LDA #33 "A" in ATASCII 120 LOOP STA (88),Y 130 DEY 140 BNE LOOP Loop until zero` Notice that labels allow us to use the word LOOP instead of the specific address we want to loop back to. In addition to all this, there are pseudo-ops which are instructions to the assembler to perform some task. A pseudo-op does not become part of the ML program (it's not a 6502 instruction), but it affects the assembly process in some way. We would need two pseudo-ops in the above program to allow it to be assembled properly. Add these lines: 10 * = $0600 (tells the assembler that this program should be assembled starting at address $0600. The $ means hexadecimal.) 160 .END (tells the assembler that it should stop assembling here.) The example above with line numbers and labels is called source code because it is the source from which the assembler gets its information when it assembles object code (object code is an actual ML program which could be run, or executed). You cannot run the program above as is. It must first be assembled into 6502 ML. For one thing, the label LOOP has to be replaced with the correct branch back to line 120. Source code does not put bytes into memory as you write it (as a more elementary assembler like the Simple Assembler does). More Than A Monitor To make this into object code which you can actually execute, you type ASM (for assemble), and the computer will put the program together and POKE the bytes into memory, showing you on screen what it looks like. To test the program, type BUG to enter the DEBUG mode, clear the screen, and RUN it by typing G600 (for GO $0600). You'll see AAAAAAAAAA on screen. It works! All this isn't, strictly speaking, a monitor. It's a full assembler. The part of the assembler cartridge program which is equivalent to the monitor programs on Apple II and PET is the DEBUG mode. There are a number of commands in DEBUG with which you can examine, test, and correct ML code. As on the other computers, the DEBUG (monitor) mode allows you to work closely with single bytes at a time, to see the registers, to trace program flow. All numbers you see on screen (or use to enter into the computer) are in hex. You enter the DEBUG mode by typing BUG when the Assembler Cartridge is in the Atari. (To go back to EDIT mode, type X.) Here are the commands of DEBUG: 1. Display the registers: type DR (RETURN) and you will see whatever is in the various registers. A=01 X=05 Y=OF P=30 S=FE (P is the status register and S is the stack pointer.) 2. Change the registers: type CR < 6,2 (RETURN) and you will have put a six into the accumulator and a two into the X register. To put a five into the status register, you must show how far to go by using commas: CR < „, 5 would do it. CR < 5 would put five into the accumulator. 3. Dump memory: type D2000 and you will see the eight hex numbers which start at address 2000 in memory. `D2000 2000 FF 02 60 20 FF D2 00 00 D2000,2020` (would dump out memory between these two addresses) 4. Change memory: type C2000 < 00,00 to put zeros into the first two bytes following address 2000. 5. Transfer (move) memory: type M1000 < 2000,2010 and you will non-destructively copy what's between 2000-2010 down into 1000-1010. 6. Compare (verify) memory: type V1000 < 2000,2010 and any mismatches will be printed out. 7. Disassemble (list): type L2000 and you will see 20 lines of instructions displayed, the mnemonics and their arguments. 8. Mini-assemble: the DEBUG mode allows you to enter mnemonics and arguments one at a time, but you cannot use labels. (The pseudo-ops BYTE, DBYTE, and WORD are available, though.) This is similar to the Simple Assembler and the mini-assemblers available to Apple II and PET monitor users. You type 2000 < LDA $05 and the computer will show you the bytes as they assemble into this address. Subsequent instructions can be entered by simply using the less-than sign again: < INC $05. To return to the DEBUG mode, you can hit the RETURN key on a blank line. 9. Go (RUN a program): type G2000 and whatever program starts at address 2000 will run. Usually, you can stop the RUN by hitting the BREAK key. There are cases, though, (endless loops) which will require that you turn off the computer to regain control. 10. Trace: type T2000 and you will also RUN your program, but the registers, bytes of ML code, and the disassembled mnemonics and arguments are shown as each instruction is executed. This is especially useful since you can watch the changes taking place in the registers and discover errors. If you have an LDA $03 and you then expect to find the accumulator to have the number three in it - you'll notice that you made that very common mistake we talked about earlier. Following LDA $03, you will see that the accumulator has, perhaps, a ten in it instead of the three you thought you'd get. Why? Because you wanted to write LDA #03 (immediate). Instead, you mistakenly loaded A with the value in address three, whatever it is. Seeing unexpected things like this happen during trace allows you to isolate and fix your errors. Trace will stop when it lands on a BRK instruction or when you press the BREAK key. 11. Step: type S2000 and you will "step" through your program at 2000, one instruction at a time. It will look like trace, but you move slowly and you control the rate. To see the following instruction, you type the S key again. Typing S over and over will bring you through the program. 12. Return to EDIT mode: type X. PET, VIC, And Commodore 64 Monitors The resident monitor on the PET/CBM computer is the simplest of monitors. You enter it from BASIC by typing SYS 4 when no program is RUNning. This lands on a BReaK instruction; address 4 always contains a zero which is the opcode for BRK. You are then in monitor mode. Original ROM PETs, the earliest models, do not have a monitor in ROM, but one is available on tape, called TIM. Everything is done with hexadecimal numbers. There are only six monitor commands: 1. Go (RUN) : type G 2000 and the program starts at address 2000. It will continue until it lands on a BRK instruction. There is no key you can type to stop it. 2. LOAD (from tape or disk) : type L "0:NAME",08 and a program called "name" on disk drive zero will be loaded at the address from which it was SAVEd. There is no provision to allow you to LOAD to a different address. L "NAME",01 will LOAD from tape. 3. SAVE (to a tape or disk): type S -0: NAME", 08,2000,2009 and the bytes between hex 2000 and 2008 will be saved to disk drive zero and called "name." Important note: you should always be aware that a SAVE will not save the highest byte listed in your SAVE instruction. You always specify one byte more than you want to save. In our example here, we typed 2009 as our top address, but the monitor SAVEd only up to 2008. S "NAME",01,2000,2009 will SAVE to tape. An interesting trick is to save the picture on your screen. Try this from the monitor (for a disk drive) : S "0: SCREEN", 08,8000,8400 (with a tape drive: S "SCREEN",01,8000,8400). Then, clear the screen and type: L "0:SCREEN",08 (tape: L "SCREEN",01). This illustrates that an ML SAVE or LOAD just takes bytes from within whatever range of memory you specify; it doesn't care what those bytes contain or if they make ML sense as a program. 4. See memory (memory dump): type M 2000 2009 and the bytes between these addresses will be displayed on screen. To change them, you use the PET cursor controls to move to one of these hex numbers and type over it. Hitting the RETURN key makes the change in the computer's memory (the same way you would change a line in BASIC). Machine Language Registers 5. See the registers: type R and you will see something like this on screen (the particular numbers in each category will depend on what's going on in your computer whenever you type R): `PC IRQ SR AC XR YR SP 2000 E62E 30 00 05 FF FE` The PC is the program counter: above, it means that the next instruction the computer would perform is found at address 2000. If you typed G (for RUN), this is where it would start executing. The IRQ is the interrupt request. The SR is the status register (the condition of the flags). The AC is the accumulator, the XR and YR are the X and Y registers. The SP is the stack pointer. We'll get into all this later. 6. Exit to BASIC: type X. That's it. Obviously, you will want to add trace, step, transfer, disassemble, and other useful monitor aids. Fortunately, they are available. Two programs, Supermon and Micromon, can be LOADed into your Commodore computer and will automatically attach themselves to your "resident" monitor. That is, when you're in the monitor mode, you can type additional monitor commands. Both Micromon and Supermon are widely available through user groups (they are in the public domain, available to everyone for free). If there is no user group nearby, you can type them in yourself. Supermon appeared in COMPUTE! Magazine, December 1981, Issue #19, on page 134. Micromon appeared in COMPUTE!, January 1982, Issue #20, page 160. A Micromon for VIC can be found in COMPUTE!, November 1982. Because of their value, particularly when you are debugging or analyzing ML programs, you will want to add them to your program library. Several of these monitor extensions can be found in Appendix F. Using The Monitors You will make mistakes. Monitors are for checking and fixing ML programs. ML is an exacting programming process, and causing bugs is as unavoidable as mistyping when writing a letter. It will happen, be sure, and the only thing for it is to go back and try to locate and fix the slip-up. It is said that every Persian rug is made with a deliberate mistake somewhere in its pattern. The purpose of this is to show that only Allah is perfect. This isn't our motivation when causing bugs in an ML program, but we'll cause them nonetheless. The best you can do is try to get rid of them when they appear. Probably the most effective tactic, especially when you are just starting out with ML, is to write very short sub-programs (subroutines). Because they are short, you can more easily check each one to make sure that it is functioning the way it should. Let's assume that you want to write an ML subroutine to ask a question on the screen. (This is often called a prompt since it prompts the user to do something.) The message can be: "press any key." First, we'll have to store the message in a data table. We'll put it at hex $1500. That's as good a place as anywhere else. Remember that your computer may be using a different screen RAM POKE code to display these letters. POKE the letter "A" into your screen RAM to see what number represents the start of your screen alphabet and use those numbers for any direct-to-screen messages in this book.
ASCII | ATARI
1500 80 P | 48
1501 82 R | 50
1502 69 E | 37
1503 83 S | 51
1504 83 S | 51
1505 32 | 0
1506 65 A | 33
1507 78 N | 46
1508 89 Y | 57
1509 32 | 0
150A 75 K | 43
150B 69 E | 37
150C 89 Y | 57
150D 00 | `` 255 (the delimiter, the signal that the message is finished. Atari must use something beside zero which is used to represent the space character.)
We'll put the subroutine at $1000, but be warned! This subroutine will not work as printed. There are two errors in this program. See if you can spot them: `1000 LDY #$00 1002 LDA $1500,Y 1005 CMP $00` (is it the delimiter?) `1007 BNE $100A` (if not, continue on) `1009 RTS` (it was zero, so quit and return to whatever JSRed, or called, this subroutine) `100A STA $8000,Y` (for PET) `100D INY 100E JMP $1000` (always JMP back to $1000) Make the following substitutions if you use one of these machines: Atari: 1005 CMP $FF (That's hex for 255.) Atari: 100A STA ($88),Y Apple: 100A STA $0400,Y Since we haven't yet gone into addressing or instructions much, this is like learning to swim by the throw-them-in-the-water method. See if you can make out some of the meanings of these instructions anyway. This subroutine will not work. There are two errors and they are two of the most common bugs in ML programming. Unfortunately, they are not obvious bugs. An obvious bug would be mistyping: LIDS when you mean LDA. That sort of bug would be caught by your assembler, and it would print an error message to let you know that no such instruction as LIDS exists in 6502 ML. The bugs in this routine are mistakes in logic. If you disassemble this, it will also look fine to the disassembler, and no error messages will be printed there either. But, it will not work the way you wanted it to. Before reading on, see if you can spot the two errors. Also see if you can figure out how this routine would execute its instructions. Where does the computer go after the first pass through this code? When and how does it finish the job? Two Common Errors A very common bug, perhaps the most common ML bug, is caused by accidentally using zero page addressing when you mean to use immediate addressing. We mentioned this before, but it is the cause of so much puzzlement to the beginning ML programmer that we'll go over it several times in this book. Zero page addressing looks very similar to immediate addressing. Zero page means that you are addressing one of the cells in the first 256 addresses. A page of memory is 256 bytes. The lowest page is called zero page and is the RAM cells from number zero through 255. Page one is from 256-511 (this is the location of the "stack" which we'll get to later). Addresses 512-767 are page three and so on up to the top memory, page 255. Immediate addressing means that the number is right within the ML code, that it's the number which follows (which is the operand or the argument of) an instruction. LDA #13 is immediate. It puts the number 13 into the accumulator. LDA $13 is zero page and puts whatever number is in address 13 into the accumulator. It's easy and very common to mix up these two, so you might look at these instructions first when debugging a faulty program. See that all your zero page addressing is supposed to be zero page and that all your immediate addressing is supposed to be immediate. In the prompt example above, the LDY #00 is correct - we do want to set the Y register counter to zero to begin printing the message. So we want an immediate, the actual number zero. Take a good look, however, at the instruction at location $1005. Here we are not asking the computer to compare the number in the accumulator to zero. Instead, we are asking the computer to compare it to whatever might be in address zero - with unpredictable results. To fix this bug, the instruction should be changed to the immediate addressing mode with CMP # 0. The second bug is also a very common one. The subroutine, as written, can never leave itself. It is an endless loop. Loop structures are usually preceded by a short initialization phase. The counters have to be set up before the loop can begin. Just as in BASIC, where FOR I =1 TO 10 tells the loop to cycle ten times, in ML, we set the Y register to zero to let it act as our counter. It kills two birds with one stone in this subroutine. It is the offset (a pointer to the current position in a list or series) to load from the message in the data table and the offset to print to the screen. Without Y going up one (INY) each time through the loop, we would always print the first letter of the message, and always in the first position on the screen. What's the problem? It's that JMP instruction at $100E. It sends us back to the LDY # 0 address at 1000. We should be looping back to address 1002. As things stand, the Y register will always be reset to zero, and there will never be any chance to pick up the delimiter and exit the subroutine. An endless cycle of loading the "P" and printing it will occur. Y will never get beyond zero because each loop jumps back to 1000 and puts a zero back into Y. To see this, here's the same bug in BASIC: 10 T=5 20 T=T+1 30 IF T=10 THEN 50 40 GOTO 10 Tracking Them Down The monitor will let you discover these and other errors. You can replace an instruction with zero (BRK) and see what happens when you execute the program up to the BRK. Better yet, you can single step through the program and see that, for example, you are not really computing CMP #00 where you thought you were. It would also be easy to see that the Y register is being reset to zero each time through the loop. You are expecting to use it as a counter and it's not cooperating, it's not counting up each time through the loop. These and other errors are, if not obvious, at least discoverable from the monitor. Also, the disassembler function of the monitor will permit you to study the program and look, deliberately, for correct use of #00 and $00. Since that mix-up between immediate and zero page addressing is so common an error, always check for it first. Programming Tools The single most significant quality of monitors which contributes to easing the ML programmer's job is that monitors, like BASIC, are interactive. This means that you can make changes and test them right away, right then. In BASIC, you can find an error in line 120, make the correction, and RUN a test immediately. It's not always that easy to locate and fix bugs in ML: there are few, if any, error messages, so finding the location of a bug can be difficult. But a monitor does allow interactivity: you make changes and test them on the spot. This is one of the drawbacks of complex assemblers, especially those which have several steps between the writing of the source code and the final assembly of executable object code (ML which can be executed). These assemblers often require several steps between writing an ML program and being able to test it. There are linkers, relocatable loaders, double-pass assembly, etc. All of these functions make it easier to rearrange ML subroutines, put them anywhere in memory without modification, etc. They make ML more modular (composed of small, self-sufficient modules or subroutines), but they also make it less interactive. You cannot easily make a change and see the effects at once. However, using a mini-assembler or the Simple Assembler, you are right near the monitor level and fixes can easily and quickly be tested. In other words, the simpler assemblers sometimes gain in efficiency what they lose in flexibility. The simpler assemblers support a style of programming which involves less pre-planning, less forethought, less abstract analysis. If something goes awry, you can just try something else until it all works. Plan Ahead Or Plunge In? Some find such trial and error programming uncomfortable, even disgraceful. The more complicated assemblers discourage interactivity and expect careful preliminary planning, flowcharts, even writing out the program ahead of time on paper and debugging it there. In one sense, these large assemblers are a holdover from the early years of computing when computer time was extremely expensive. There was a clear advantage to coming to the terminal as prepared as possible. Interactivity was costly. But, like the increasingly outdated advice urging programmers to worry about saving computer memory space, it seems that strategies designed to conserve computer time are anachronistic. You can spend all the time you want on your personal computer. Complex assemblers tend to downgrade the importance of a monitor, to reduce its function in the assembly process. Some programmers who've worked on IBM computers for 20 years do not use the word monitor in the sense we are using it. To them, monitors are CRT screens. The deluxe assembler on the SuperPet, for example, does have a monitor, but it has no single-step function and has no provision for SAVEing an ML program to disk or tape from the monitor. Whether or not you are satisfied with the interactive style of simple, mini-assemblers and their greater reliance on the monitor mode and on trial and error programming is your decision. If you want to graduate to the more complicated assemblers, to move closer to high-level languages with labels and relocatable code, fine. The Atari assembler is fairly high-level already, but it does contain a full-featured monitor, the "debugger," as well. The choice is ultimately a matter of personal style. Some programmers are uncomfortable unless they have a fairly complete plan before they even get to the computer keyboard. Others are quickly bored by elaborate flowcharting, "dry computing" on paper, and can't wait to get on the computer and see-what-happens-if. Perhaps a good analogy can be found in the various ways that people make telephone calls. When long-distance calls were extremely expensive, many people made lists of what they wanted to say and carefully planned the call before dialing. They would also watch the clock during the call. (Some still do this today.) As the costs of phoning came down, most people found that spontaneous conversation was more satisfying. It's up to you. Computer time, though, is now extremely cheap. If your computer uses 100 watts and your electric company charges five cents per KWH, leaving the computer on continuously costs about 12 cents a day. Return to Table of Contents | Previous Chapter | Next Chapter |