\ qasm.f: QS5 QASM Assembler/Disassembler (QASM is pronounced chasm) \ ========================================================================= \ Copyright 1997-1999 by John Rible, \ Permission is granted for individual non-commercial use, provided this \ notice is included. Contact the author concerning other uses. \ ========================================================================= \ I think this is an ANS Forth Program with Environmental Dependencies, \ requiring: \ the Search-Order word set, \ PARSE from the Core-Extension word set (only used in ,C"), \ THROW from the Exception-Handling word set (only used in PACK), \ and :O [O] ;O from the metacompiler. \ A Standard System exists after this program is loaded. \ Any operator's terminal facilities provided by the system are adequate. \ ------------------------------------------------------------------------- \ 04/22/1999 jr: modified for qs5 (took many 'features' out) \ 12/11/1998 jr: modify for qs4 \ 07/14/1998 jr: update for new qs3 bits and registers \ 06/04/1998 jr: merged with disassembler & made dependent on metacompiler \ 05/29/1998 jr: more work, both mine and JET's \ 03/30/1998 jt: modified for qs3: hex, new opcode layout, and more \ 01/12/1998 jr: changed ALU opcodes again, removed interrupt stuff \ 10/20/1997 jr: changed ALU opcodes back to qs2 order, increased branch offset \ 08/28/1997 jr: fixed big problem with register masking \ 08/27/1997 jr: added 'jump' & branch opcodes \ 07/29/1997 jr: finished making lots of changes to the instruction formats \ 06/15/1997 jr: copied and modified sp1601 file \ ========================================================================= \ MARKER toss \ uncomment these 2 lines to test without the metacompiler \ : :O : ; : [O] ; IMMEDIATE : ;O POSTPONE ; ; IMMEDIATE HEX DEFINITIONS \ set base and make sure current = context wordlist : .QASM ( - ) ." qasm 5.1 " ; \ Uncomment these search-order words if they're not already available \ : -ORDER ( - ) GET-ORDER 1- SWAP DROP SET-ORDER ; \ : +ORDER ( wid - ) >R GET-ORDER 1+ R> SWAP SET-ORDER ; \ : SWAP-CURRENT ( wid - wid' ) GET-CURRENT SWAP SET-CURRENT ; \ Comment out these string words if they're already available DECIMAL : PACK ( ca1 cc ca2 - ca2 ) \ 0x83 ( ca1 cc ca2 ) >R 255 OVER U< -18 AND THROW R@ ( R: ca2 ) OVER >R CHAR+ SWAP CHARS MOVE R> R@ C! R> ( R: ) ; : S, ( ca cc - ) HERE OVER 1+ CHARS ALLOT PACK DROP ; : ,C" ( - ) [CHAR] " PARSE S, ; HEX \ QASM Disassembler ======================================================== \ QS5 Opcode bit layout (little-endian) \ OP Class | High order (odd) byte | Low order (even) byte | \ ---------+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ \ template | iiii/*baa | *yyy/uuuu |f/r| xxx | cc | op | \ =========+===+===+===+===+===+===+===+===+===+===+===+===+===+===+===+===+ \ call | Cell address of machine code routine | 0 | \ ---------+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ \ branch | br_ | distance | 0 | 1 1 1 | cond | 0 | 1 | \ +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ \ aluop | iiii | literal | 0 | dest | cond | 0 | 1 | \ ---------+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ \ branch | br_ | * | * | source | 1 | 1 1 1 | cond | 0 | 1 | \ +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ \ aluop | iiii | * | source | 1 | dest | cond | 0 | 1 | \ ---------+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ \ std | * | 0 | addr | * | source | 0 | 0 0 0 | cond | 1 | 1 | \ +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ \ out | * | 1 | addr | * | source | 0 | 0 0 0 | cond | 1 | 1 | \ +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ \ _st | * | b | stride| * | source | 0 | pointer | cond | 1 | 1 | \ ---------+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ \ ldd/jpd | * | 0 | addr | * | dest/111 | 1 | 0 0 0 | cond | 1 | 1 | \ +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ \ in | * | 1 | addr | * | dest | 1 | 0 0 0 | cond | 1 | 1 | \ +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ \ ld_/jp_ | * | b | stride| * | dest/111 | 1 | pointer | cond | 1 | 1 | \ +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ \ ldi/jpi | * | 0 | 1 | 0 | * | dest/111 | 1 | 1 1 1 | cond | 1 | 1 | \ =========+===+===+===+===+===+===+===+===+===+===+===+===+===+===+===+===+ \ bit# 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 \ notes: - '*' shows an unused opcode bit. \ - There are many undefined opcodes (i.e., the above table is not a \ complete list of the possible opcodes, only the decoded ones). \ - 'ldi' & 'jpi' opcodes are followed by a data word. \ - The branch distance is measured in cells, starting one cell after \ the opcode fetched during the current instruction (usually the \ current address + 4 bytes) : OP-BITS ( x:mask +n:shift-count - ) CREATE ( shift-count ) , ( mask ) , DOES> ( op ia - i ) 2@ >R AND R> RSHIFT ; \ builds words to extract & shift opcode fields to make an index or literal F000 0C OP-BITS |iiii| C000 0E OP-BITS |ii| 3F00 07 OP-BITS |dddddd| 7000 0C OP-BITS |b**| 3000 0C OP-BITS |aa| 3000 0C OP-BITS |mi| 4000 0E OP-BITS |b| 0F00 08 OP-BITS |uuuu| 0700 08 OP-BITS |yyy| 0080 07 OP-BITS |f| 0080 07 OP-BITS |r| 0070 04 OP-BITS |xxx| 000C 02 OP-BITS |cc| 0002 01 OP-BITS |o*| 0001 00 OP-BITS |*p| FFF3 CONSTANT unconditional \ masks 0001 CONSTANT 0005 CONSTANT \ opcodes 2643 CONSTANT 36C7 CONSTANT 7 CONSTANT \ registers 0 CONSTANT \ Opcode display strings : .STRING= ( - ) \ builds tables of display strings CREATE ' ( xt ) -origin , \ table filled in with ,C" " DOES> ( .. ia - ) ( .. ia ) >R R@ @ +origin EXECUTE \ xt generates the index for the table ( i ) R> CELL+ BEGIN SWAP ?DUP WHILE 1- SWAP COUNT + REPEAT COUNT TYPE ; .STRING= .cc_ |cc| ,C" " ,C" ret& " ,C" z? " ,C" nz? " .STRING= .xxx |xxx| ,C" fl " ,C" g1 " ,C" g2 " ,C" g3 " ,C" g4 " ,C" ts " ,C" ra " ,C" pc " .STRING= .yyy |yyy| ,C" fl" ,C" g1" ,C" g2" ,C" g3" ,C" g4" ,C" ts" ,C" ra" ,C" pc" .STRING= .[xxx] |xxx| ,C" " ,C" [g1]" ,C" [g2]" ,C" [g3]" ,C" [g4]" ,C" [ts]" ,C" [ra]" ,C" [pc]" .STRING= .[aa] |aa| ,C" 08" ,C" 0A" ,C" 0C" ,C" 0E" .STRING= .alu_ |iiii| ,C" adn " ,C" sbn " ,C" mov " ,C" neg " ,C" add " ,C" sub " ,C" adc " ,C" sbb " ,C" and " ,C" inv " ,C" or " ,C" xor " ,C" sr " ,C" sl " ,C" rrc " ,C" rlc " .STRING= .br_ |ii| ,C" bf " ,C" bb " ,C" br " ,C" br " .STRING= .bi_ |ii| ,C" bfi " ,C" bbi " ,C" bi " ,C" bi " .STRING= .ldd_ |b| ,C" ldd " ,C" in " .STRING= .jpd_ |b| ,C" jpd " ,C" jpin " .STRING= .std_ |b| ,C" std " ,C" out " .STRING= .lds_ |b**| ,C" ld " ,C" ld " ,C" ld++ " ,C" ld-- " ,C" ldb " ,C" ldb " ,C" ldb+ " ,C" ldb- " .STRING= .jps_ |b**| ,C" jp " ,C" jp " ,C" jp++ " ,C" jp-- " ,C" jpb " ,C" jpb " ,C" jpb+ " ,C" jpb- " .STRING= .sts_ |b**| ,C" st " ,C" st " ,C" ++st " ,C" --st " ,C" stb " ,C" stb " ,C" +stb " ,C" -stb " \ internal display words : .0n ( u - ) 0 <# #S # #> TYPE ; \ opcode display words : .jp ( f op - f ) OVER IF DROP ." jpi" EXIT THEN DUP |xxx| IF DUP .jps_ .[xxx] EXIT THEN DUP .jpd_ .[aa] ; : .ld ( f op - f ) OVER IF ." ldi " .yyy EXIT THEN DUP |xxx| IF DUP .lds_ DUP .[xxx] ." , " .yyy EXIT THEN DUP .ldd_ DUP .[aa] SPACE .yyy ; : .st ( f op - f ) DUP |xxx| IF DUP .sts_ DUP .yyy ." , " .[xxx] EXIT THEN DUP .std_ DUP .yyy ." , " .[aa] ; : .memop ( op - f ) ( op ) DUP |xxx| = SWAP ( f op ) DUP |r| 0= IF .st EXIT THEN DUP |yyy| = IF .jp EXIT THEN .ld ; : .branch ( op - ) DUP |f| IF DUP .br_ .yyy EXIT THEN DUP .bi_ |dddddd| .0n ; : .from_ ( op - op ) DUP |f| IF DUP |yyy| OVER |xxx| XOR IF DUP .yyy ." , " THEN EXIT THEN DUP |uuuu| .0n ." #, " ; : .aluop ( op - ) DUP |xxx| = IF .branch EXIT THEN DUP .alu_ .from_ .xxx ; : .OP ( op - f ) \ display TOS as QASM opcode; flag is true if imm follows DUP |*p| 0= IF ." call " .0n 0 EXIT THEN DUP = IF ." nop" DROP 0 EXIT THEN DUP = IF ." ret" DROP 0 EXIT THEN DUP = IF ." nest" DROP 0 EXIT THEN DUP = IF ." exit" DROP 0 EXIT THEN DUP .cc_ unconditional AND DUP |o*| IF .memop EXIT THEN .aluop 0 ; : .. ( u - ) .OP IF ." " THEN ; \ display for testing \ QASM Assembler =========================================================== \ Implementation Notes: \ All instructions and inline data MUST be aligned at even byte addresses. \ An instruction is initiated by the opcode (or condition code), built up \ by the operands, and stored when the next opcode (or condition code) is \ encountered. Only rudimentary error checking is done. \ Each "opcode class" vectors the word NEW-OP to store the assembled \ opcode into memory correctly. Literal values are picked up from the stack \ when specified, but the stack depth is not checked. \ The assembly process is controlled by using a mask to fill the 'xxx' \ and/or the 'yyy' fields, as well as to keep track of how much of the \ opcode has been assembled. CREATE OP 3 CELLS ALLOT \ datafield cells: | opcode | mask | xt | : MASK ( - a ) OP CELL+ ; : XTOP ( - a ) MASK CELL+ ; : INITOP ( - ) 0 0 OP 2! 0 XTOP ! ; : NEW-OP ( x? - ) XTOP @ ?DUP IF EXECUTE INITOP THEN ; : >OP ( bits - ) OP @ OR OP ! ; : >MASK ( mask - ) MASK @ 0003 AND OR MASK ! ; : >MOP ( bits mask - ) >MASK >OP ; : >XMOP ( bits mask xt - ) XTOP ! >MOP ; : short ( u - lit ) DUP FFF0 AND ABORT" short" 8 LSHIFT ; : dist ( u - lit ) DUP FF81 AND ABORT" dist" 7 LSHIFT ; \ 'a' is address following branch opcode, 'A' is destination : ( a A - ) OVER [O] CELL+ - dist SWAP [O] CELL- >R R@ [O] @ OR R> [O] ! ; : NOTcc ( - ) \ invert test condition for IF WHILE and UNTIL OP 2@ OR 0= ABORT" no cc" OP @ DUP 8 AND IF 4 XOR THEN OP ! ; \ opcode storing words : literal? ( - op f ) \ check for completed opcode; true flag if literal expected MASK @ FFFC AND ABORT" incomplete" OP 2@ SWAP 1 AND ; : call, ( a - ) DUP 1 AND OP 2@ OR OR ABORT" call" [O] , ; \ store the address : alu, ( x? - ) \ store all alu opcodes, assuming a needed literal is on stack ( x? ) literal? IF \ literal: need range check & shift ( x op ) SWAP OVER 0070 AND 0070 XOR IF short ELSE dist THEN ( op lit ) OR ( OP ) THEN [O] , ; : mem, ( x? - ) \ store all pointer opcodes, assuming a needed literal is on stack ( x? ) literal? IF \ immediate stores 2 cells ( x op ) OVER 1 AND OVER 700 AND 700 = AND OVER 70F3 AND 20F3 XOR OR ABORT" imm" [O] , \ 'ldi' & 'jpi' opcodes ( x ) THEN ( x|op ) [O] , ; : dir, ( x? - ) \ store all direct opcodes, assuming the address is on stack ( x? ) literal? 0= OVER 3070 AND OR ABORT" dir" ( x? op ) DUP 4000 AND IF 0 SWAP THEN \ add i/o port address (byte direct opcode) ( X op ) SWAP OVER 4000 AND IF 2* ELSE 0008 XOR THEN DUP FFF9 AND ABORT" dir" ( op X ) 0B LSHIFT OR [O] , ; \ qasm defining words : opclass= ( m xt 'word1' - ) CREATE -origin , , \ opcode-class defining words DOES> ( op ia1 'word2' ) CREATE -origin , , \ opcode defining words DOES> ( x? ia2 ) >R NEW-OP R> 2@ +origin 2@ +origin >XMOP \ opcodes ; \ The table below shows how the opcodes and operands affect the mask. \ -> mask -> mask -> mask \ NEW-OP [0000] \ call [0000] 07F0 ' alu, opclass= alu= \ (same source/destination) alu op [07F0] reg [0000] \ (different source/destination) alu op [07F0] reg, [0070] reg [0000] \ (literals) alu op [07F0] #, [0071] reg [0001] 0780 ' alu, opclass= bra= \ (reg branches) bra op [0780] reg [0000] \ (lit branches) bri op [0001] 0703 ' dir, opclass= dir= \ (direct stores) std op [0703] reg [0003] \ (direct loads) ldd op [0703] reg [0003] 0003 ' dir, opclass= jpd= \ (direct jumps) jpd op [0003] 0702 ' mem, opclass= mem= \ (normal stores/loads) mem op [0702] reg, [0002] [ptr] [0002] \ (normal stores/loads) mem op [0702] [ptr], [0702] reg [0002] 0002 ' mem, opclass= jmp= \ (normal jump) jmp op [0002] [ptr] [0002] 0703 ' mem, opclass= ldi= \ (immediate loads) ldi op [0703] reg [0003] 0003 ' mem, opclass= jpi= \ (immediate jumps) jpi op [0003] : cc= ( bits - ) CREATE , \ define condition codes DOES> ( x? ia - ) >R NEW-OP R> OP 2@ OR ABORT" cc" ( ia ) @ >OP ; : reg= ( bits - ) CREATE , \ define source/dest registers; ends opcode DOES> ( ia - ) OP 2@ AND FFFC AND ABORT" reg" ( ia ) @ MASK @ AND 0000 >MOP ; : reg,= ( bits - ) CREATE , \ define source registers DOES> ( ia - ) OP 2@ AND FFFC AND ABORT" reg," ( ia ) @ MASK @ AND MASK @ 0070 AND >MOP ; : ptr= ( bits - ) CREATE , \ define pointer registers DOES> ( ia - ) OP @ 0070 AND MASK @ 0003 AND 0002 XOR OR ABORT" ptr" ( ia ) @ >OP ; \ only the active assembler words are in the QASM wordlist WORDLIST CONSTANT QASM-WORDLIST : code[ ( - ) QASM-WORDLIST +ORDER INITOP ; \ These words hide the stuff : ]code ( x? - ) NEW-OP -ORDER ; \ needed to use the assembler QASM-WORDLIST +ORDER DEFINITIONS \ QASM registers, operands, and opcodes \ watch out for conflicts with Forth words! (XOR AND OR IF BEGIN etc.) : #, ( - ) MASK @ 0783 AND 0780 XOR ABORT" lit" MASK @ 0070 AND 0001 OR >MASK ; : call ( - ) NEW-OP 0 0 ['] call, >XMOP ; 0005 cc= ret& 0009 cc= z? 000D cc= nz? 0001 alu= adn 0071 bra= bf 8001 alu= and 1001 alu= sbn 4071 bra= bb 9001 alu= inv 2001 alu= mov 8071 bra= br A001 alu= or 3001 alu= neg B001 alu= xor 4001 alu= add C001 alu= sr 5001 alu= sub D001 alu= sl 6001 alu= adc E001 alu= rrc 7001 alu= sbb F001 alu= rlc 0083 dir= ldd 0783 jpd= jpd 0003 dir= std 20F3 ldi= ldi 0083 mem= ld 0783 jmp= jp 0003 mem= st 27F3 jpi= jpi 2083 mem= ld++ 2783 jmp= jp++ 2003 mem= ++st 3083 mem= ld-- 3783 jmp= jp-- 3003 mem= --st 4083 dir= in 4783 jpd= jpin 4003 dir= out 4083 mem= ldb 4783 jmp= jpb 4003 mem= stb 6083 mem= ldb+ 6783 jmp= jpb+ 6003 mem= +stb 7083 mem= ldb- 7783 jmp= jpb- 7003 mem= -stb 0080 reg= fl 0080 reg,= fl, 0190 reg= g1 0180 reg,= g1, 0010 ptr= [g1] 0010 ptr= [g1], 02A0 reg= g2 0280 reg,= g2, 0020 ptr= [g2] 0020 ptr= [g2], 03B0 reg= g3 0380 reg,= g3, 0030 ptr= [g3] 0030 ptr= [g3], 03B0 reg= sp 0380 reg,= sp, 0030 ptr= [sp] 0030 ptr= [sp], 04C0 reg= g4 0480 reg,= g4, 0040 ptr= [g4] 0040 ptr= [g4], 04C0 reg= rp 0480 reg,= rp, 0040 ptr= [rp] 0040 ptr= [rp], 05D0 reg= ts 0580 reg,= ts, 0050 ptr= [ts] 0050 ptr= [ts], 06E0 reg= ra 0680 reg,= ra, 0060 ptr= [ra] 0060 ptr= [ra], 07F0 reg= pc 0780 reg,= pc, 0070 ptr= [pc] 0070 ptr= [pc], \ assembler macros : nop adn 0 #, fl ; : ret ret& nop ; : return br ra ; \ conditional return, with delay-slot : bfi bf #, ; : clc and 0e #, fl ; : bbi bb #, ; : stc or 1 #, fl ; : bi br #, ; : ivc xor 1 #, fl ; \ assembler control structures: they use branches, so all have a delay slot! \ ELSE and REPEAT branch to the opcode after the delay-slot. : ahead ( x? - a ) bfi 0 NEW-OP [O] HERE ; \ 'a' is the next-opcode address : if ( - a ) NOTcc ahead ; : else ( a1 x? - a2 ) ahead SWAP [O] HERE [O] CELL+ branch> ; : then ( a x? - ) NEW-OP [O] HERE branch> ; : begin ( x? - A ) NEW-OP [O] HERE ; \ 'A' is the destination address : while ( A - a A ) if SWAP ; : entry ( a A x? - A ) NEW-OP SWAP then ; : again ( A x? - ) bbi [O] HERE [O] CELL+ ; \ List (colon definition) control words for e4th are also single opcodes \ for e4th, return stack grows up, data stack grows down : nest ( - ) ++st ra, [rp] ; \ in-line DO-COLON : exit ( - ) ret& ld-- [rp], ra ; \ in-line EXIT \ metacompiler-assembler interface words : LABEL ( 'word' - ) NEW-OP [O] LABEL ; : HERE ( - a ) NEW-OP [O] HERE ; : , ( x? x - ) >R NEW-OP R> [O] , ; \ must be AFTER all uses of ',' : END-CODE ( - ) ]code ?aligned ; -ORDER DEFINITIONS \ Restore previous (meta) wordlist :O CODE ( 'word' - ) [O] WHERE [O] >XT [O] ALIAS code[ ;O \ assembler test words :O @+ ( a - a+ x ) DUP [O] CELL+ SWAP [O] @ ;O : .xxxx ( u - ) 0 <# # # # # #> TYPE ; : ..OP ( a - a+ ) [O] @+ CR ." ( " DUP .xxxx ." ) " .op IF [O] @+ SPACE .0n THEN ; : c[ ( - a u ) [O] HERE DEPTH code[ ; \ begin a code snippet for testing : ]c ( a u x? - ) \ end a code snippet and disassemble it ]code DEPTH 1- XOR ABORT" stack changed" [O] HERE SWAP BEGIN 2DUP XOR WHILE ..OP REPEAT 2DROP CR ; \ used as: c[ nz? add 5 #, g1 ld++ [ra], g3 ]c \ QASM assembler/disassembler syntax ======================================= \ nop|ret|nest|exit \ call ADDRESS \ {CONDITION} jpi ADDRESS \ {CONDITION} JUMPOP ADDR|[PTR] \ {CONDITION} BRANCH SOURCE|DISTANCE DELAYSLOT \ {CONDITION} return DELAYSLOT \ {CONDITION|ret&} ALUOP {SOURCE,|SHORT #,} DEST \ {CONDITION|ret&} clc|stc|ivc \ {CONDITION|ret&} LOADOP SOURCE, ADDR|[PTR] \ {CONDITION|ret&} STOREOP ADDR|[PTR], DEST \ {CONDITION|ret&} ldi VALUE DEST \ {CONDITION|ret&} in DEST \ {CONDITION|ret&} out SOURCE \ where braces ({}) enclose optional items, a vertical bar (|) separates \ alternatives, CAPITALIZED text represents catagories described below, \ and lower-case text and ALL other punctuation are required. \ VALUE Any 16-bit value. \ SHORT An unsigned value between 0 and 15. \ DISTANCE An unsigned even value between 0 and 126, the number of bytes between \ the destination address and the opcode address + 4. \ ADDRESS Any even (cell aligned) 16-bit address. \ ADDR Only with ldd/jpd/std opcodes: 8 10 12 14 \ SOURCE One of the 8 accessible registers: \ FL Flags (bits: 0000:0000:0000:REQ.ACK.SEND.C) \ G1 general use (ro, rw, rw, rw) \ G2 general use \ G3 general use, data stack pointer SP (grows down) \ G4 general use, return stack pointer RP (grows up) \ TS general use, testable \ RA general use, return address \ PC program counter \ DEST One of: FL G1 G2 G3|SP G4|RP TS RA. \ PTR One of: G1 G2 G3|SP G4|RP TS RA. \ DELAYSLOT May be any opcode except 'ldi' or 'jdi'. It is always executed, \ but may have its own condition codes. It should not have 'ret&'. \ QS5 branch delay-slot issues: \ The PC (normal) and RA (ret&) values used to fetch the next opcode are their \ contents at the BEGINNING of the instruction's execution. Branch opcodes modify \ the PC or RA register in the MIDDLE of the instruction's execution, AFTER the next \ opcode has been fetched (and AFTER the default update of the PC with the fetch \ address plus 2). \ The delay-slot opcode executes with the PC at the branch target address, so: \ - 'ldi' and 'jpi' have immediate data which will be read from the branch \ target address instead of the address following the delay-slot opcode. \ - 'bf' and 'bb' distances are relative to the branch opcode address plus 2. \ - 'ret&' on a delay-slot opcode overrides the branch target address as the \ address of its next-opcode fetch. \ CONDITION One of the following condition codes: \ z? Store results if TS is zero at start of opcode. \ nz? Store results if TS is nonzero at start of opcode. \ ret& Fetch the next opcode using the value in RA; opcodes \ without 'ret&' use the value in PC. \ ALUOP SOURCE may be omitted when it and DEST are the same register. \ In the following equations, 's' represents SOURCE or SHORT, \ 'd' is DEST, 'C' is FL[0], and 'c' is the new FL[0]. \ adn d = d + s and d = d and s \ sbn d = d - s inv d = invert s \ mov d = 0 + s or d = d or s \ neg d = 0 - s xor d = d xor s \ add c.d = d + s sr d = C.s[15:1] \ sub c.d = d - s sl d = s[14:0].0 \ adc c.d = d + s + C rrc d.c = C.s \ sbb c.d = d - s - C rlc c.d = s.C \ BRANCH to PC + SOURCE: bf \ to PC - SOURCE: bb \ to SOURCE: br \ to PC + DISTANCE: bfi \ to PC - DISTANCE: bbi \ to DISTANCE: bi \ LOADOP jump to 16-bit address from memory at ADDR: jpd \ jump to 16-bit address from memory at [PTR]: jp jp++ jp-- \ jump to 8-bit address from memory at [PTR]: jpb jpb+ jpb- \ load 16-bit data from memory at ADDR: ldd \ load 16-bit data from memory at [PTR]: ld ld++ ld-- \ load 8-bit data from memory at [PTR]: ldb ldb+ ldb- \ STOREOP store 16-bit data to memory at ADDR: std \ store 16-bit data to memory at (modified) [PTR]: st ++st --st \ store 8-bit data to memory at (modified) [PTR]: stb +stb -stb \ Forth-like assembler control-flow macros are single opcodes. They are branch \ opcodes, so the range is limited to +65/-63 cells from the next opcode address, \ and a delay-slot opcode is required where noted. The forward branch around \ ELSE and REPEAT goes past the delay-slot opcode. \ ahead DELAYSLOT begin \ CONDITION if DELAYSLOT CONDITION while DELAYSLOT \ else DELAYSLOT CONDITION until DELAYSLOT \ then repeat DELAYSLOT \ again DELAYSLOT