However, for zero page locations that are input/output parameters of ROM routines it makes sense to use EQUs, e.g.
Code: Select all
ROMSUB1PARM1 = $FD
ROMSUB1PARM2 = $FE
ROMSUB1 = $F000
ROMSUB2PARM1 = $FB
ROMSUB2 = $F123
Another example is that address-address can be either a constant or an address, e.g.
Code: Select all
LDX #0
LOOP LDA STR,X
JSR SUB
INX
CPX #STR_END-STR ; address - address = constant
BCC LOOP
RTS
STR .byte "some string"
STR_END
Code: Select all
DP_BASE = $1000 ; address
VAR1 = DP_BASE ; address
VAR2 = DP_BASE+2 ; address
SUB1
;
; Set up VAR1 for later
; The D register doesn't point at DP_BASE yet
;
ASL
STA VAR1 ; uses abs (or long) addressing here
RTS
SUB2
;
; Set the D register to DP_BASE (e.g. for speed)
;
LDA #DP_BASE
TCD
;
; Start by copying VAR1 to VAR2
;
LDA VAR1-DP_BASE ; address - address = dp address
STA VAR2-DP_BASE
Speaking of macros, they can be simpler without the distinction in the instruction, e.g.
Code: Select all
MOV2A MAC ; 6502/65C02 (.n are the macro parameters)
LDA .1
STA .2
LDA 1+.1
STA 1+.2
EOM
The assembler only has to be written once. I'm not sure that making the assembler itself easy to write is all that important.
Code: Select all
ldxiw 16 ; LDXIW = LDX #nnnn
nextBit: ; LDXIB = LDX #nn
lsrd multiplier ; it'd do away with .a8/.i16 etc.
Code: Select all
LDA #0 ; assembles A9 00
LDA ##0 ; assembles A9 00 00
(snip)
The whole assembler is small enough to keep in memory all the time.
I wrote an ugly 6502 prefix assembler (I should've just made it postfix and I should've implemented labels differently) which is both a simplification and an expansion of the FIG-Forth 6502 assembler. There are colon definitions for JMP and JSR, and only 4 defining words: one for addressing modes, one for implied instructions, one for relative branch instructions, and one for the remaining instructions. It includes branch range checking, and ORG capability, i.e. ORG need not equal HERE (it was intended as a cross assembler for the NMOS 6502). It doesn't include forced zp or abs, though that would be really simple to add (probably only a few dozen bytes or so). It only takes 775 bytes of dictionary space and 690 bytes of head space (heads are separated in this particular indirect-threaded Forth). A significant percentage of it consists of using the defining words to define the instructions (ADC, AND, etc.) It's not as simple as what you're doing, but as poorly designed as it is, it was still pretty easy to do.