El Cheapo Assembler by S.L Judd 12/98 Well, the SCPU is nearing its third birthday, and yet in all this time an assembler has never been written. Hence this program. El Cheapo Assembler -- or CheapAss, if you like -- is not the fanciest assembler in the world. It's purpose is to work, and be practical. It also has a number of useful features, including local variables, an integrated editor and monitor, useful pseudo-opcodes, and a few other nifty things. And most importantly, it knows 65816 opcodes. In fact, it requires a SCPU to work properly. Note that El Cheapo is a work in progress -- newer features will undoubtably appear down the road. The first version was written in a short flurry of programming, so save that source code often! So in the spirit of a hastily slapped-together program, here are some hastily slapped-together docs. Boot program ------------ The boot program loads an ML monitor to $8800, pokes the init address to $0334/$0335, and then loads the main program. The program uses the $0334 vector to enter the monitor, so you can use any monitor you want. The program also POKEs the swap bank -- change this to use a bank other than bank 1 if you have SuperRAM (bank 1 is used for lots of system things, which you may lose). The editor ---------- The editor's name is NED. Hello NED. NED is a 240-column editor which has been updated for writing assembly code. The text is automatically formatted into label/opcode/argument/comment columns. NED also features cut and paste, and some decent navigational aids. shift-return - Insert a new line cursor keys, return - What you would expect insert, delete - Likewise shift-clear - Clear all text home - Move to top of file R/S - Tab (not needed) F1 - Assemble F2 - Exit to ML monitor F7 - Disk menu CTRL-a - Delete characters to right of cursor -d - Delete line -b/n - Move to beginning/end of line -c/x - Copy/cut lines to clipboard -p - Paste line from clipboard -j/k - Move 40 columns left/right (max 240 columns) -i/m - Move 25 rows up/down -g - Goto line # -z - Reformat all text (convert source) - <- - Exit to BASIC (SYS 822 to re-enter) The assembler ------------- Lines of code are structured as follows: label opcode argument comment Each field must be separated by at least one space, with the exception of comments, which may begin at any column. While assembling, RUN/STOP will halt assembly and <- (backarrow) will toggle the screen output. The assembler is case insensitive, both for labels and opcodes. Thus lda LDA lDa are equivalent, as would be labels such as warez and wArEz. * Comments ;this is a comment * This is also a comment, provided the * is in column 1 * Opcodes All the 65816 opcodes are supported, and alternate mnemonics are provided for the following commands: BCC BLT BCS BGE DEC A DEA INC A INA JSR JSL (Long JSR) JMP JML (Force long JMP) Moreover, BRK and COP are in principle two-byte instructions, so they can include an optional argument, i.e. BRK assembles as 00, but BRK $02 assembles as 00 02. * Addressing modes All of the 65816 modes are supported. Arguments may be - Numbers: LDA 100 LDA $64 LDA %01100100 - Labels: JSR CHROUT - Characters: LDA #'a' LDA #"a" - PC: LDA $D011 BPL *-3 Simple mathematical operations are supported -- currently just addition and subtraction (but multiplication and division are a cinch and just a matter of me adding them in). Thus arguments like CHROUT+$20-* are perfectly valid. * Labels Labels are composed of letters and numbers. Labels must start with a colon or a letter. Labels may be any length (although shorter lengths save memory, and lengths greater than eight chars will produce messy program listings). Labels beginning with a colon are _local_ labels -- their scope only extends to the next global variable (think of them as being 'attached' to the last global variable). Example: GLOBAL1 LDX #$20 :L1 JSR CHROUT DEX BNE :L1 ;Backwards branch GLOBAL2 CMP #$80 BCS :L1 ;Forwards branch AND #$7F :L1 Thus local labels are reusable labels. Pretty cool, eh? * Prefixes The standard 65816 prefixes are supported. These are < ^ > for #immediate mode, and < ! > for absolute addresses. Immediate-mode prefixes specify which part of the byte to use: Operand One-byte result Two-byte result #$01020304 04 04 03 #<$01020304 04 04 03 #>$01020304 03 03 02 #^$01020304 02 02 01 It should be noted that, currently, El Cheapo Assembler only supports 24-bit numbers, not 32-bits as the above indicates (coming later!). Address prefixes specify the length of the address: < One byte (direct a.k.a. zero page) ! Two bytes (absolute) > Three bytes (abs long) Thus LDA $0203 and LDA !$010203 are equivalent. Note that this is perhaps the only way to force long addressing in bank zero (LDA $000102 will assemble to LDA $0102). * Pseudo-Opcodes Several useful pseudo-opcodes are supported. ORG address alternate syntax: *= address ORG * ORG sets the program ORiGin to address, and is thus the first line of most programs. For example, ORG $C000 assembles the program to $C000. Subsequent ORG directives may be specified change the address again -- this is useful when you have a section of code to copy to another area of memory. Finally, ORG without any argument performs a re-ORG, that is, resets the program counter to its proper value. For example: ORG $0801 ... basic header here LDX #END-START :LOOP LDA START-1,X STA $C000,X DEX BNE :LOOP RTS START ORG $C000 ;Assemble below code as if to $C000 L1 JSR CHROUT JMP L1 ;JMP $C000 ORG ;Re-ORG END EQU or = EQUate a label to some value. Examples: CHROUT = $FFD2 ZERO EQU 0 --- Storage opcodes --- DFB or DB DeFine Byte -- output bytes directly into code. Examples: DFB $20 DFB 100,$64,%1100100 Note separating commas DA or DW Define Address -- assembles 16-bit address in lo/hi order: DA $FFD2 ;assembles as D2 FF DA $0801,$FFD2 ;assembles as 01 08 D2 FF DLA Define Long Address -- like DA, but 24-bit HEX Define hex bytes. No comma separators are used and each byte is two characters HEX 20D2FF ;Assembles as 20 D2 FF DS and DS ^ Define storage -- fill memory with specified number of bytes. DS ^ fills to the end of the page. DS 5 ;Assembles as 00 00 00 00 00 DS 5,$3D ;Assembles as 3D 3D 3D 3D 3D DS ^ ;Fills memory with zeros to end of page DS ^,$3D ;Fills memory with 3D to end of page TXT Assemble text. Text is delimited using either ' or ". Currently the two function the same, but this may change in the future. The purpose of having two delimiters is so that the other may be embedded into the string. Examples: TXT 'Hello' TXT "I said, 'Hello'" TXT 'boo!',0d,0d,00 Hex bytes, separated by commas, may follow the string. --- Conditional Assembly --- DO arg If arg=0 then assembly is halted, until an ELSE or FIN condition is reached. Examples: DO 0 ;Don't assemble DO DEBUG ;Don't assemble if DEBUG=0 DO *-$C000 ;Don't assemble if *=$C000 ELSE Reverse the last DO condition. FIN End DO/ELSE constructs. All DO's should end with a FIN. --- Disk I/O --- PUT 'filename' PUT currently doesn't work, so don't use it! --- 16-bit support --- REG REG ON REG OFF The 65816 uses the same opcode for LDA #$12 and LDA #$1234 -- should the assembler assume 8 or 16 bits? In the code this is determined by the settings of the M and X flags, so normally El Cheapo tracks these flags by remembering any changes made by REP or SEP. REG OFF turns off this feature; REG ON turns it back on. REG #$30 will set the register bits to #$30 -- REG acts like LDA, NOT like REP or SEP. JamaicaMon ---------- JamaicaMON -- or Jammon, for short -- is a full-featured ML monitor for the SCPU. Please see the included doc file for more info. The only difference is that 'x' exits back to the editor. Memory Map ---------- $0334/$0335 ML monitor vector $0336 JMP to editor $0800- Source code $8800-$9900 Jammon $9A00-$BFFF CheapAss $C000-$FFFF Label/variable table (temporary) Code is assembled to the swap bank, so it can be quite large. When the program exits to the monitor, banks zero and the swap bank are swapped -- so the source is now in the swap bank and the binary is in bank 0 -- and the binary is translated to its specified starting address, before entering the monitor. Thus, if you crash the machine, and suddenly realize you didn't save the last three hours of coding -- well, don't lose heart just yet. Instead, enter the monitor (e.g. SYS $8800) and look through memory for the text -- in particular, look through the swap bank. You can then transfer to bank 0 and save (or if you have PeekPokePatch you can save from the swap bank directly). By golly -------- By golly, that's all I can think of for now!