6502 Primer: Building your own 6502 computer |
large math look-up tables |
65c02 assembly structure macros |
simple multitask |
6502 interrupts |
zero-overhead Forth interrupts |
RS-232 primer |
assembly relevant today |
NMOS-CMOS 6502 differences |
6502 stacks treatise |
If you write an assembler, please, please, please:
- Do not make it require dots in front of assembler directives (also known as "pseudo-ops"). It makes it looks like
vertically aligned things are not aligned. If someone wants to put them there, it should accept them, for
example ORG $8000 or .ORG $8000
(or *=). Choice is always good. Someone might have come from another assembler
and is in the habit of putting the dots there, or may want to re-use someone else's code with minimal modification.
- Carrying that theme further, make it as flexible as possible (although in some cases it may be good to encourage use of
more-mainstream mnemonics, assembler directives, operators, etc.).
ORG 0x8000 ; although I personally hate this one!
*=*+$40 ; skip $40 bytes
ORG $ + $40 ; skip $40 bytes
The $ above, when not followed by hex digits, is the way all three commercial assemblers I've
used returned the current value of the program counter.
- Allow macro definitions to invoke other macros, in other words, allow it to nest macros.
- Allow macros to accept varying numbers of macro parameters, and a way to do conditional assembly in the macro saying for
example, "If a fourth parameter exists, do the following." The 2500AD assembler used the directive
IFMA for this. IFMA 4 meant, "If a fourth parameter exists..." An example of
its usefulness is to clear a set of flag variable bytes all in a single line, where the number of variables to clear will
change from one use to another, for example:
CLR_FLAG ICNT, IHEAD, ITAIL, OCNT, OHEAD, OTAIL, OIE ; Init the software flags.
which stores a zero in each of those. If the maximum number of flag variables to clear were 8,
IFMA...ENDIF would be used eight times in the macro definition (or actually seven, assuming
the first one is not optional, so you don't use the IFMA on that one). In this case,
each IFMA would be followed by a STZ <addr> (STore Zero)
line (or STA <addr> if you had an NMOS 6502 and had to start with
LDA #0 at the top), before the ENDIF line.
- Do not require blank lines to be commented out. It makes it look really messy to see a broken column of semicolons
down the left edge.
- Do not require labels to start in column 1. Text editors that have a "condense" feature can give a display of only
the lines that have something in column 1, which makes it faster to find things sometimes. When I do this, I don't
want to see the labels that are only of local interest. Labels that start in column 2 or later can still be recognized
as labels if they're the first thing on the line and are followed by a colon. Using a colon after a label is good
practice anyway, even when it's not required, because if you do a search for the label, you can put the colon in the search
term and it will take you right to it, rather than wasting your time by first turning up a lot of references to the
- Do not require labels to be on their own lines. It just makes the source code longer. You should be able to
put down a label, then continue on the same line, with code.
- Case-sensitivity should be selectable. Some people don't want it. I do. As with so many other
things, if the user can turn it off and on, it makes everyone happy.
- A COMMENT...END_COMMENT feature is good, so you can have a set of lines describing something,
without having to put the column of semicolons down the left edge. A good reason to have it is that it makes it easier
to change the word-wrap points if you insert a sentence in the comment paragraph for example, so you don't have to contend
with the semicolons. My MultiEdit text editor has a feature that allows changing the indentation and word-wrap line
length for the paragraph you're working on which makes it super easy—as long as you don't have the semicolons.
Here's an example from one of my files:
Don't use N-1 like other systems. It's not necessary with 816 & it'll put you
in XSAVE. You DEX twice before writing the first stack cell, so S0adr isn't
used by stack. X holds the actual ZP address of the top stack cell. Top of
both stacks is the stack cell closest to address 0. Altho' the '816 can have
the direct page anywhere in bank 0, it runs fastest if we leave the direct
page on a page boundary, so we might as well leave it at ZP just like w/ 6502.
- Make sure a comma in a quoted string doesn't fool the assembler into thinking you're going on to the next parameter in a
line (as in a macro invocation with multiple parameters). If the closing quote is not reached, the comma is part of the
string. (This is the only bug I can think of in my old C32 assembler.)
- Allow arrays of assembler variables. By "assembler variables," I mean labeled values similar to an EQUate
but which can be changed any number of times during the assembly process, and they take memory only in the assembler while
it's running, not in the assembled program. This matter of arrays of assembler variables becomes valuable particularly
in forming program-structure macros. There
should be a way to index into the array, so an expression (probably involving another assembler variable) tells which variable
you're specifying within the array.
- Do not forbid the user from putting a negative number in something that is normally positive, like an address. He
may be totally aware of what he's doing and just wants the low 8 bits in a byte or ZP address, or the low 16 or 24 bits in
an absolute or long address, even if the assembler's 32-bit internal representation has FF's in the high byte(s). The
64tass assembler had this problem, discussed in the forum topic
"OSI BASIC and STA $aaaa,Y" (which turned out
to be an inappropriate name for the topic).
- The output options of the assembler (or linker, if you use a linker too) should include at least
Intel Hex and binary formats, and
perhaps Motorola S-record as well. There should of course be the option to additionally generate a listing (.lst) file
showing the addresses and machine-code output to the left of each line of source code, with option to turn macro expansion
on and off. If there are error conditions, they should be shown there, easy to find with a search for "Error".
Another helpful thing is to have an alphabetized list of labels and variables at the end of the .lst file, with their
addresses. If it also shows the number of times each one is referred to used, the programmer can see if he has ones
that can be eliminated.
- On the C32 assembler, I like that in source code for the 65816 whose registers can be set to 8-bit or 16-bit, you don't
need assembler directives like LONGA taking up extra lines. For example, a routine that is
only to be called with the index registers in 8-bit mode can start with LDY #<0 to mean
it should lay down only one byte (the low byte) of operand rather than two, without taking a line to
say SHORTX to tell the assembler that indeX registers are 8-bit at this point,
regardless of their size at the end of the routine just above it.
- Make error messages very clear as to what the problem is.
- Have a way for the user to make the assembler display messages during the assembly process.
Assembly Language: Still Relevant Today <--Previous
last updated Jan 30, 2024