Manual for the Editor-Not-Included Assembler, version 1.0 Program and manual (C) Aaron Heiss (heiss@pdx.edu), December 2000 This program is Freeware! That means a number of things, all of which I will explain. You may download, keep, copy and use this program freely, without compensating its author (me) or distributor in any way whatsoever. You may upload, distribute or otherwise disseminate this program freely, with my thanks, provided that (1) you distribute it only in its original, unmodified form, (2) you include this file with it in the same archive and directory, as applicable, in its original, unmodified form, and (3) you receive no money at all for it, except for reasonable compensation for media and shipping (if any). You may not sell any mass distribution of this program, with or without any collection of other software, without my explicit permission. The nature of this program requires an additional clause. I make no claim whatsoever to any software developed with the use of this program; nor do I accept any responsibility for the functionality of any such software, or any errors in its object code. Any software developed with the use of this program need not be noted as such. Although this program is Freeware, I make no requirements about anything developed with it, and you may classify your programs as Freeware, Shareware, Public Domain, or however else you like. In short, whatever code you write with this is yours to do with as you see fit, and I will take neither credit nor blame for it. How to Run this Program: First note that the source code to be assembled must be in standard ProDOS TXT format; that is, regular ASCII, with all lines terminated by carriage return characters ($0D) only. Text will be accepted with or without the high bit set. This program is a SYS file, which means that it may be launched from any ProDOS selector or shell, and it will exit to whatever selector or shell is resident in or specified by the system. The program itself is complete in the one file, so that the disk containing it need only be used for initial loading and can be removed as soon as the program starts. After launching, the assembler first prompts for the source code pathname. You must know this beforehand, and enter it in from the keyboard; there is no catalog feature. No extension is assumed for the source file; if one exists, you must supply it. When entering a pathname, both the left-arrow key and the DELETE key will function as a backspace. ESC will delete the entire entry. Hitting RETURN with no input at all will abort the entry. Pathnames may or may not need to be fully qualified, depending on whether or not a default pathname is defined, and on whether or not any currently defined default pathname corresponds to a valid path on a currently mounted volume. The assembler next prompts for the object file pathname. No default exists for this; you must specify the complete filename. The provided object code pathname will be checked to see if it currently exists. If so, you are asked for permission to delete that file. If permission is not given, the assembler will return to the object file pathname prompt. Note that this assembler will not delete locked files. Once the object pathname has been established, the assembler will prompt for the filetype of the object program. Several options are provided as single-key selections. They are SYS, BIN, CMD and REL. There is also an "Other" option, which enables you to enter in the two-digit hexadecimal filetype code desired. Any code may be used; this is not checked by the assembler. Next, the assembler prompts for the status file pathname. You may enter one in or simply press RETURN with no entry present to cancel the creation of a status file. If the status file is not cancelled, it will first be checked for by the assembler, and if a file already exists with the specified pathname, you will be prompted to delete the file. If this is not desired, the assembler will prompt for another status file pathname. Once again, this assembler will not delete locked files. Assembly is an automatic process. However, if errors are encountered in the first pass, the assembler will pause between passes and ask permission to continue. If permission is denied, the assembler will return to the source file pathname prompt. If at any time during its operation the assembler encounters a ProDOS error, it will report this and abort its operation, returning to the source file pathname prompt. Pressing RETURN with a blank line at this prompt will cause the assembler to quit, returning you to the environment from which the assembler was launched. General Syntactic Conventions: Source code follows the conventional assembler format, with each line divided into four fields. An optional label occupies the first field; an instruction or directive mnemonic must be in the second; an operand, if applicable, is placed in the third; and any comments desired may be placed in the fourth. Lines may be any length up to and including 128 bytes. Any lines longer than this limit will produce unpredictable results. Every line must end with a carriage return character (ASCII $8D), including the last line of the source file. At least one space must separate all fields. However, there is no limit to the number of spaces that may be used, so long as the entire line is within 128 bytes. Thus, tabbing may be effected through the use of multiple spaces. Blank lines are ignored. All alphabetic characters to be interpreted by the assembler, which is to say all letters not in comments or explicitly declared as ASCII values, must be uppercase. Thus, all mnemonics and all labels can contain no lowercase letters at all, and the hexadecimal values A through F likewise must be "spelled" in capitals. Comments must be preceded by either an asterisk ('*') or a semicolon (';'). If an entire line is to be used as a comment, one or the other of these characters must be the first character in that line. If there is a label in the label field, its first character must be the first character in the line. If there is no label in this field, the first character in the line must be a space character. Labels must follow the same rules as ProDOS filenames: they must begin with a letter, contain only letters, numbers and the period ('.'), and may be one to fifteen characters in length. No spaces are allowed within an operand, the only exceptions being ASCII codes preceded by an apostrophe (') and spaces within strings. Syntactic Conventions of Operands: All instructions with no operand and no register or flag explicit in their mnemonics are assumed to be accumulator mode. Thus, LSR by itself will be accumulator mode; LSR A will be assumed to refer to a label called A, and will produce an error if no such label exists. Note that this includes the 65c02-only instructions INC and DEC. However, the mnemonics INA and DEA are also supported. All operands indicate zero page mode (if available) if their high byte is zero. Absolute mode may be specified by prefixing the operand with a carat (^), so if LABEL is equated to $0042, instructions such as STA LABEL will be in zero page mode, while STA ^LABEL will be in absolute mode. The low-order byte of an operand can be specified by the less-than sign (<), and the high-order byte can be specified by the greater-than sign (>). These qualifiers will specify zero page mode if applicable. Note, however, that an expression such as LDA ^>$1234 will produce an error. Immediate addressing mode is specified by prefixing the operand with a number sign (#). This must be the first character in the operand field; if other qualifiers are used, they must follow this sign. All hexadecimal values must be prefixed by a dollar sign ($). All binary values must be similarly prefixed by a percent sign (%). ASCII codes may be included as values (with the high bit set) if preceded by an apostrophe ('). Thus, LDA #'A is equivalent to LDA #$C1. These signs must be after any other prefixes and adjacent to the value itself. Decimal values neither require nor allow any special declaration. Labels also neither require nor allow any special declaration, but they must follow the naming conventions given above. Values may be computed. Addition and subtraction are allowed using the regular signs (+ and -), and may be compounded. Compound computations are processed in a left-to-right order, and parentheses are not allowed. The minus sign may not be used to specify a negative value by itself; if one is desired, an expression such as 0-VALUE is necessary. All values are stored internally as two-byte numbers. Single-byte values are thus stored with their high-order bytes equal to zero, and can be referred to as double-byte values if desired (using the carat as outlined above). Values requiring more than two bytes will be truncated. Thus, $12345 will be cut to $2345, and 65537 will be equal to 1. Directives: Four directives are supported by this assembler. DEF defines its operand as data to be inserted into the object code. No label is required for this directive to function. Data can be of any legal type, and may consist of single-byte values, double-byte values (always stored low-order byte first), or strings. Multiple units of data may be included with one DEF, provided that all are separated by commas (,) only with no spaces. Each unit of data must be individually specified; that is, each hexadecimal number must have its own dollar sign ($) prefix, each binary number its own percent sign (%) prefix, and so on. Multiple types of data may be mixed together as desired. In addition, strings may be specified (always assembled with the high bit of each character set) merely by enclosing the string in double quotes ("). A double quote character may be included in the string by repeating it (""). EQU specifies that a label be equated to a value for internal use by the assembler. It is important to note that EQU does not assemble to anything at all by itself. If there is no label specified in the label field, this directive will essentially be ignored. ORG specifies the origin of the object code. There must be at least one ORG in any program, and it may not be of the value $0000, as this is used internally to indicate "no origin." Multiple ORGs are allowed, however, to permit the development of self-relocating code. Note that the first ORG is used by the assembler to specify the AUXTYP field of the object code. Note also that files of type SYS require that the first ORG be $2000. SPC is used to insert the number of bytes specified in the operand into the source file. These bytes are initialised to zero, so that SPC 12 will insert twelve zeroes into the object code. Also, the special case of SPC 0 is supported, so that a label may be used to indicate a particular position in the program with no addition being made to the object code. This is of particular value if a label is required for the end of the file. Understanding and Coping with Error Messages I have tried to keep the error messages as informative as possible while keeping them short enough to display on one 40-column line. Obviously, this means that I have had to make some compromises, and in some cases their meaning may not be clear. Hopefully, this will help. "Bad addressing mode" The addressing mode might be valid for some instructions, but not the instruction in this line's opcode field. This error often results from a lapse in memory of what addressing modes the 65c02 will and will not allow with which instructions. "Branch out of range" This very common error results from the source and destination points of a branch instruction being more than 127 bytes apart if the branch goes forward, or 128 if it goes backward. Fixing this situation means that either code will need to be removed between the two points, or the destination will have to be moved, perhaps to a JMP instruction. "Disk full." Every disk has a finite amount of storage space, and the disk you have specified has reached its. Use another disk, or quit the assembler and erase or abbreviate files on the present disk to make more room. "Disk write protected." This is pretty obvious. Either you don't want to write to the disk being accessed, or you will have to take it out of the drive and remove its write-protect tab. "Duplicate label" This assembler allows only one instance of each label in all the label fields of the source code. The indicated line is the second (or third, or fourth...) line with the same label in the label field. "Duplicate filename." At least two of the pathnames that you gave the assembler are identical, and that the assembler is trying to access one of them for the wrong purpose. For instance, you could have requested a status file with the same name as your object file. "File access denied." This means that the assembler has tried to write to or delete a write- or delete-protected file. Unfortunately, this assembler cannot unlock such locked files, and so you will either have to specify another pathname, use another disk, or leave the assembler and unlock the files in question yourself. "File already open." The assembler did not abort a prior operation properly. It will close the file in question after it gives this message, though, and if you try again you should not have this problem. If this condition persists, hit CONTROL-RESET; this will always close all open files. "I/O error." This is something of a catch-all, as it could indicate anything from an unformatted disk to a faulty disk drive or controller. In any event, the volume accessed is not available to ProDOS. Hopefully, you have made a backup! "Illegal label" All labels must start with an uppercase letter, contain only uppercase letters, numbers and the dot (.), and be at most fifteen characters long. These are the same rules that must be followed by ProDOS filenames, which should help you remember them. "Illegal operand" Operands must follow rigid syntax requirements, which are outlined above. Violation of those requirements (a hexadecimal number without a leading dollar sign, for instance) will result in this error, as will characters not allowed in the operand field (lowercase letters not in a string are a good example) and poorly-defined addressing modes, such as indirect with only one parenthesis or indexed with nothing following the comma. Essentially, this is a basic syntax error. "Input buffer overflow" This means that the indicated line is over 128 bytes in length. Actually, I would not recommend lines over 80 characters in length as they are difficult to read on a standard Apple II display, but you might disagree with me, so I allowed more. "Label not found" A label was referenced that has not been defined elsewhere in the program. Besides the obvious possibility that you forgot to declare the label, it is also possible that you changed a label's name everywhere but in the indicated line, or that you inadvertantly deleted a line with the label's declaration. "No instruction found" Every line that does not start with an asterisk or a semicolon must have something in the opcode field. Thus, a label by itself is not a complete line, and will return this error message. "No operand found" Instructions with only two- and/or three-byte addressing modes require an operand. This error condition may result in unequal length passes. "No operand needed" An operand was found for an instruction with only a single-byte addressing mode, such as TYA or RTS. This will result from a comment with no semicolon or asterisk delineator. "No ORG found." All programs must have at least one ORG directive, preferably before any code-producing opcodes (all 65c02 instructions and the DEF and SPC directives). There is no corresponding error for multiple ORGs, as this is necessary for self-relocating code. "Operation aborted." An error occurred that was so severe that the assembler could not continue assembling. This always happens after a ProDOS error. It means that the system has been returned to the state it was in just after the assembler was loaded. "Passes assembled to unequal length." Some instructions that were assembled to three bytes in the first pass were assembled to two in the second, or vice versa. I will admit that this is a difficult error to deal with. Some cases are obvious. The most likely is that you have declared a label with EQU to be a zero-page location after it was first referenced as data. The assembler assumes that all such forward references are to two-byte values, so it is important that you place all zero-page EQU's before their first reference. Another case is that expressions like STY ^ADDR,X are only allowed two bytes by the 65c02, although the carat prefix indicates to the assembler to produce a three-byte instruction. My tactic when correcting this error is to locate the disparity. To do this, you can assemble the code to a BIN file and load it under BASIC, switch to the Monitor, and use the disassembler in ROM to locate JSR's and references to easily identifiable data. Check the entry points of the JSR's, and try to track down the location of the disparity. Sometimes it helps to add SPC's or DEF's with recognisable data, like all $FF's or sequences like $00,$11,$22,..., and to try and locate whether or not these appear in the right places. Once you have located the disparity, you can get a better idea of what might be wrong in the source code. "Pathname not found." This could mean one of three things: the disk you specified is not currently mounted, any subdirectories that you specified may not exist, or the filename itself is not present. This could simply be a result of a misspelling, or you may not be remembering the complete pathname correctly. "Required memory is not free." The assembler cannot run because ProDOS has not been told that the memory that it needs to run has been freed. "Source file is not of type TXT." The specified source code is not stored in the proper format. This could mean that the source code is stored in a non-text format, or it could mean that the word processor or text editor used to create or edit the file uses a proprietary format, that is, something other than plain ASCII (AppleWorks does this). Most word processors that do this have an option to save to a plain text file. If you get this message under these circumstances, you must quit the assembler (just hit RETURN at the source code prompt without any file entry), launch your word processor, load your file, and save it as a plain text file in order for this assembler to be able to use it. "Symbol table overflow" There is no fixed limit to the number of symbols that this assembler will allow, but there is a limit to the size of the symbol table. Longer labels will take up more room than shorter ones, so this error may simply indicate that you use shorter labels. Also, programs or data that remain resident in high RAM will reduce the amount of memory available for the symbol table. Quitting the assembler and removing these programs or data will help. "SYS file requires ORG at $2000." ProDOS requires that all files of type SYS have their loading point at $2000. There are other things that are a good idea to have a SYS file do, and if you do not know them, perhaps you should not be writing a SYS file in the first place! "This program uses 65c02 instructions." This is not really an error message, but it does have implications for compatibility. It means that your program uses 65c02-only instructions, like STZ or BRA, or original 6502 instructions with 65c02-only addressing modes, like LDA (ZP) or DEC. The program may work fine on an Apple //c, an expanded //e or a IIgs, but it will not behave itself on an original //e or anything earlier. "Unknown instruction" The assembler will recognise only valid 65c02 instructions and its own four directives in the opcode field. Using other assemblers' directives will return this message (for instance, using DFB, DW or ASC instead of DEF), as will any misspellings. "Volume directory full." ProDOS allows the main directory on the disk to contain at most only 51 files, and you have asked it to provide a 52nd. Subdirectories have no such limit, however, and if you specify a path that uses one, you will avoid this problem. You could also use another disk, of course. Final Note: This project has taken a great deal of my time and energy, and I would like nothing more than to see that others appreciate that. If you find this program at all useful, I would greatly appreciate hearing from you. If you find it lacking, let me know, and I might add your suggestions to the next version! In fact, the development of a next version may very well depend on feedback from interested users, as I do not at this point know whether or not I will want or need anything more sophisticated than this program is right now. Be aware, though, that I may not be able to include any such suggestions for a number of reasons, as you should expect from your own experience with assembly language programming. In any event, I hope that you will find this program to be of use, and that you will tell me about your experiences with it. Happy assembling!