SALP ver 1.0 Structured Assembly Language Preprocessor Public Domain No Rights Reserved Unlimited Distribution is Encouraged "We are tied down to a language which makes up in obscurity what it lacks in style." -- T. Stoppard Introduction ------------ SALP will take a structured assembly source file as input and create an assembly source file as output. It will give your assembler the ability to use structured assembly language. An assembler is still needed to produce machine code. This means the development cycle now has an extra step. Instead of edit-assemble-test or edit-assemble-link-test, it is now edit-preprocess-assemble-test or edit-preprocess-assemble-link-test. SALP requires the 65C02 processor and ProDOS 8. As distributed, version 1.0 only works with the Merlin assembler. All SALP command lines start with "*!" (asterisk exclamation-point, or star-bang). This lets you assemble your source code to check for errors before using SALP, since these lines are treated by the assembler as comments. There cannot be blank spaces before the asterisk or between the asterisk and exclamation-point. No comments are allowed on SALP command lines. All lines of code added by SALP end in ";!" (semi-colon exclamation-point, or semi-bang). Any lines read in by SALP that end this way are removed. This lets you run source code through SALP over and over without generating more and more extraneous code. Do not end any of your lines this way! SALP reserves all four-character labels starting with "Z" from "Z000" through "ZZZZ" for a total of 46,656 possible labels. The large number is adequate for any reasonable program. The short length conserves symbol table space. The only code produced by SALP are branches and labels. No registers or flags are changed. SALP liberates you from the tyranny of the column-oriented assemblers that are the legacy of the computer punched card. Source code can be formatted so the structure is visually striking and helps to understand the code in less time. Please questions, comments, and BUG REPORTS to the author: Paul R. Santa-Maria P.O. Box 924 Monroe, MI 48161 Use --- When you run SALP, it looks for a file named "SOURCE.A" in the current directory and reads that file first. I recommend you keep "SOURCE.A" small. It should contain only the CPU command and a list of FILE commands. Keep a copy of SALP in the same directory as your assembler. Keep the "SOURCE.A" file with your source files. When you want to use SALP, either copy SALP to your source directory or copy the "SOURCE.A" file to your assembler directory. Every SALP file name should end in ".A", but the ".A" should not be in the FILE command. SALP will append the ".A". The ".A" stands for "Assembly" source code. The SALP 1.0 distribution disk contains all the source code for SALP written in SALP itself. There is an appropriate "SOURCE.A" file. Study the disk and you will see how to use SALP. Commands -------- *! IF {length} *! ELSE {length} *! ENDIF *! LOOP *! AGAIN {length} *! WHILE {length} *! UNTIL {length} *! FOREVER {length} *! FILE path name *! CPU 6502|65C02|65802|65816 Condition Codes --------------- The following condition codes are used in SALP: flag clear flag set ------------------------- ----------------------- not equal (Z=0) equal (Z=1) carry clear (C=0) carry set (C=1) plus (N=0) minus (N=1) overflow clear (V=0) overflow set (V=1) unsigned comparisons signed comparisons ---------------------- ---------------------- higher greater than higher or same greater or equal equal (same) equal not equal (not same) not equal lower or same less or equal lower less than There are sixteen different condition codes. Note that and do triple duty as flag, signed comparison, and unsigned comparison conditions. The 6502 has no standard way to distinguish between branches for signed and unsigned comparisons. Some assemblers allow BGE and BLT as synonyms for BCS and BCC for use after unsigned comparisons, which conflicts with SALP. (The 6800, 6809, 68000, and 80X86 have always used the same conventions for signed comparisons as SALP.) Lengths ------- SALP assumes all branches are NEAR branches. For unconditional branches, SALP uses the following table: CPU | 6502 65C02 65802 65816 ------+------------------------------ Length NEAR | JMP BRA BRA BRA FAR | JMP JMP BRL BRL IF-ELSE-ENDIF ------------- The IF command will execute the code following it if the condition is true. The ELSE is optional. Example: *!65C02 LDA DataByte CMP #TestValue *!IF FAR DEC Counter *!ELSE INC Counter *!ENDIF The "IF FAR" will generate a long branch to the ELSE. The ELSE will generate a short branch to the ENDIF. The final code would look like this in column format: LDA DataByte CMP #TestValue BEQ Z000 JMP Z001 Z000 DEC Counter BRA Z002 Z001 INC Counter Z002 LOOP ---- The two basic forms of loops are *! LOOP *! UNTIL and *! LOOP *! FOREVER The first will continue looping as long as the condition is true. The second will loop forever. The two options within the loop are AGAIN and WHILE. AGAIN will return to the top of the loop if the condition is true, and continue below itself if the condition is false. WHILE will continue below itself if the condition is true, and jump past the UNTIL or FOREVER if the condition is false. Keywords -------- The conditions. To generate the reverse condition, flip bit 0 of the token. Keyword Description ------- ---------------- carry clear carry set plus minus overflow clear overflow set not equal equal lower (unsigned) higher or same (unsigned) lower or same (unsigned) higher (unsigned) less than (signed) greater or equal (signed) less or equal (signed) greater than (signed) The commands. These immediately follow the "*!". IF ELSE ENDIF LOOP AGAIN WHILE UNTIL FOREVER FILE CPU The modifiers. These are used inside a command. NEAR FAR 6502 65C02 65802 65816 Flag branches ------------- The near version is on the left; the far version is on the right. branch if carry clear (C flag = 0) BCC YES | BCS Z000 | JMP YES | Z000 EQU * branch if carry set (C flag = 1) BCS YES | BCC Z000 | JMP YES | Z000 EQU * branch if plus (N flag = 0) BPL YES | BMI Z000 | JMP YES | Z000 EQU * branch if minus (N flag = 1) BMI YES | BPL Z000 | JMP YES | Z000 EQU * branch if overflow clear (V flag = 0) BVC YES | BVS Z000 | JMP YES | Z000 EQU * branch if overflow set (V flag = 1) BVS YES | BVC Z000 | JMP YES | Z000 EQU * branch if not equal (Z flag = 0) BNE YES | BEQ Z000 | JMP YES | Z000 EQU * branch if equal (Z flag = 1) BEQ YES | BNE Z000 | JMP YES | Z000 EQU * Unsigned branches ----------------- branch if lower BCC YES | BCS Z000 | JMP YES | Z000 EQU * branch if higher or same BCS YES | BCC Z000 | JMP YES | Z000 EQU * branch if lower or same BCC YES | BCC Z000 BEQ YES | BNE Z001 | Z000 JMP YES | Z001 EQU * branch if higher BCC Z000 | BCC Z001 BNE YES | BEQ Z001 Z000 EQU * | Z000 JMP YES | Z001 EQU * Signed branches --------------- branch if less than BVC Z000 | BVC Z001 BMI Z001 | BMI Z002 BPL YES | Z000 JMP YES Z000 BMI YES | Z001 BMI Z000 Z001 EQU * | Z002 EQU * branch if greater or equal BVC Z000 | BVC Z001 BPL Z001 | BPL Z002 BMI YES | Z000 JMP YES Z000 BPL YES | Z001 BPL Z000 Z001 EQU * | Z002 EQU * branch if less or equal BEQ YES | BEQ Z000 BVC Z000 | BVC Z001 BMI Z001 | BMI Z002 BPL YES | Z000 JMP YES Z000 BMI YES | Z001 BMI Z000 Z001 EQU * | Z002 EQU * branch if greater than BEQ Z001 | BEQ Z002 BVC Z000 | BVC Z001 BPL Z001 | BPL Z002 BMI YES | Z000 JMP YES Z000 BPL YES | Z001 BPL Z000 Z001 EQU * | Z002 EQU *