align hex \ just in case
0 value ADDR \ address of current (or next) ppc instruction
\ 021 proxies for other secondary opcodes with same validation case
: prep-rA=rT-rejection ( u -- u|021 )
CASE
023 OF 021 >r ENDOF
029 OF 021 >r ENDOF
02b OF 021 >r ENDOF
DUP >r
ENDCASE
r>
;
: prep-rA=r0-rejection ( u -- u|025 ) \ group together to validate
CASE
027 OF 025 >r ENDOF
02d OF 025 >r ENDOF
031 OF 025 >r ENDOF
033 OF 025 >r ENDOF
035 OF 025 >r ENDOF
037 OF 025 >r ENDOF
DUP >r
ENDCASE
r>
;
: ?rA=0-averse ( -- flag )
addr @ ( instruction with Secondary Mask = 07ff )
07e AND 06e =
;
: ?rA=rT-averse ( -- flag )
addr @ ( instruction with Secondary Mask = 07ff )
57e AND 06e =
;
: @rT ( -- n ) \ extract contents of ppc instruction field rT
addr @ 015 >> 0000001f AND
;
: @rA ( -- n ) \ get contents of field rA
addr @ 010 >> 0000001f AND
;
: @nB ( -- n ) \ get contents of field nB
addr @ 0b >> 0000001f AND
;
: @nR ( -- n ) ( rT+n = last reg in range needed to hold nB bytes )
@nB 0= IF d# 32 ( result matches 'lswi','lswx' instruction's )
ELSE @nB THEN ( Power ISA v2.05 p.59 refers )
1-
4 / \ this rslt + the T in rT gives # of last gpr overwritten
;
variable last-reg \ temp for roughmask 'lswi' validation
\ 'lswi' only. ('lswx' similar but can't utilize test as nB dynamic)
: incompatible-operands ( lswi-instruction -- flag )
@rT @nR + last-reg !
last-reg @ d# 32 < \ will there be wrap-around ?
IF @rA @rT >= @rA last-reg @ <= AND
ELSE @rA @rT >= @rA d# 32 + last-reg @ <= OR
THEN
;
: wildbits ( bc-instr'n -- flag ) \ spurious bits in br-condition?
addr @ DUP DUP
03000000 AND 03000000 = -ROT
00c00000 AND 00c00000 = SWAP
02a00000 AND 02a00000 = OR OR
;
0 constant INVALID \ 0 to roughmask invalidates any instruction
0 value casemask \ to pass result fm internal to external CASE
\ Rough mask sufficient to uniquely identify candidate G4 instr'n
( Alternative Form instrns singled out for more distinctive masks)
( Also, invalid operands need detecting here b4 mnemonic printed )
: roughmask ( addr -- mask ) ( instruction address also in addr )
@ d# 26 >> \ isolate hi 6-bit major opcode by shifting to far right
CASE
\ use return stack, as ENDCASE removes top item from stack
010 OF \ 'bc' group (4 instructions)
wildbits IF INVALID >r ELSE fc000003 >r THEN ENDOF
011 OF fc000003 >r ENDOF \ 'sc' (1 instruction)
012 OF fc000003 >r ENDOF \ 'b' (branch unconditional) (4)
013 OF \ CR etc group (15 instructions)
addr @ 000003fe AND DUP \ extract secondary opcode
020 = SWAP 420 = OR \ = 020 ( bclr ) or 420 ( bcctr ) ?
IF wildbits
IF INVALID >r ELSE fc0007ff >r THEN
THEN ENDOF
014 OF fc000001 >r ENDOF \ 'rlwimi' 'rlwimi.' (2)
015 OF fc000001 >r ENDOF \ 'rlwinm' 'rlwinm.' (2)
017 OF fc000001 >r ENDOF \ 'rlwnm' 'rlwnm.' (2)
01f OF \ Load, Store, Arithmetic, Logic (151-1+2)
fc0007ff to casemask ( subject to amendment in foll. bloc)
?rA=rT-averse @rA @rT = AND
?rA=0-averse @rA 0= AND OR
IF
INVALID to casemask
ELSE
addr @ casemask AND
CASE
7c0004aa ( 'lswi' ) OF incompatible-operands IF
INVALID to casemask THEN ENDOF
7c00042a ( 'lswx' ) OF @rA @rT = IF
INVALID to casemask THEN ENDOF
7c0002e6 ( 'mftb' ) OF addr @ fc1effff AND 7c0c42e6 = IF
\ combine distinguishing operand with 'mftb','mftbu' opcode
fc1fffff to casemask THEN ENDOF
ENDCASE
THEN casemask >r
ENDOF
03b OF fc00003f >r ENDOF \ First Floating-point group (18)
\ 03e OF fc0007ff >r ENDOF ( needed only for 64-bit cpu's )
03f OF addr @ d# 32 AND \ 2nd Floating-point group (47)
IF fc00003f >r ELSE fc0007ff >r THEN ENDOF
\ Major opcode alone identifies remaining instructions =
\ majority of Load, Store, plus some int arith & logic (39)
prep-rA=r0-rejection \ CASE 025 proxy for 027,02d,031,033,035,037
025 OF @rA IF fc000000 >r ELSE INVALID >r THEN ( rA <> r0 ? )
ENDOF
prep-rA=rT-rejection \ CASE 021 proxies for CASEs 023, 029, 02b
021 OF @rA DUP 0= SWAP @rT = OR ( rA==r0 OR rA==rT ? )
IF INVALID >r ELSE fc000000 >r THEN
ENDOF
02e OF @rA @rT >=
IF INVALID >r ELSE fc000000 >r THEN \ 'lmw'
ENDOF
( Remainder ) fc000000 >r
ENDCASE ( TOTAL PPC INSTRUCTIONS = 287 )
r>
;
\ In the operand-extraction functions which follow, "trimmed-
\ instruction" means the progressively reduced ppc instruction
\ remnant, after all bits to the right of the current operand
\ (if any) have been shifted out.
\ Single operand primitives. If they start with '.' they output to
\ screen. Otherwise they pass the result back to the instruction-
\ nominated calling routine which then has to do the output itself.
\
: .comma ( -- ) 2c emit ;
: .0x ( -- ) [CHAR] 0 emit [CHAR] x emit ;
: .hexdump ( u -- ) 0 <# # # # # # # # # #> type ;
\ can substitute '8 u.r' if it pads with 0's instead of blanks
: .nbr ( trimmed-instruction -- )
01f AND 0 <# decimal #s hex #> \ prints rhs 5 bits in decimal
type ;
: .gpr ( trimmed-instruction -- )
[CHAR] r emit .nbr ; \ outputs one of r0 r1 r2 ... r31
: .fpr ( trimmed-instruction -- )
[CHAR] f emit .gpr ; \ outputs one of fr0 fr1 fr2 ... fr31
: .fld ( trimmed-instruction -- )
07 AND 0 <# decimal #s hex #> type ; \ one of 0 1 2 ... 7
: .segr ( trimmed-instruction -- )
0f AND 0 <# decimal #s hex #> type ; \ one of 0 1 2 ... 15
: .imm ( trimmed-instruction -- ) 0 <# # #> type ; \ 0 1 2 ... f
: .xx ( trimmed-instruction -- )
ff AND .0x 0 <# # # #> type ; \ one of 0x00 0x01 0x02 ... 0xff
: .cc ( trimmed-instruction -- ) 1f AND .xx ;
: .ui ( trimmed-instruction -- ) ( zero trimming in this case )
ffff AND .0x 0 <# # # # # #> type ; \ 0xXXXX where X = hexdigit
: sign-extend ( ppc-instr'n -- immed-data-field-expanded-to-32-bits)
lwsplit drop ( works with rhs 16-bit immediate fields only )
dup 8000 AND
if ffff else 0000 then \ put sign extension on stack
wljoin
;
\ 0 alignment assumes code being disassembled fm executable location
: align-address ( address -- address|address-1|address-2|address-3 )
-4 AND
;
: .si \ output signed immedate data as 4 hex digits
sign-extend dup abs 0
<# # # # #s [char] x hold [char] 0 hold rot sign #>
type ;
\ : .si \ more flexible if your computer's (.) output matches mine
\ sign-extend dup (.) rot dup 0< IF
\ swap 1- rot 1+ \ skip 1st char '-' and reduce length
\ swap rot \ unscramble stack
\ [char] - emit \ send a minus sign to output
\ THEN
\ -9 9 between NOT
\ IF .0x THEN \ only 1 numeric digit, so skip .0x
\ type
\ ;
: .sd ( trimmed-instruction -- ) .si ;
: .spr ( trimmed-instruction -- ) \ as in 'mtspr'.
0 <# decimal #s hex #> type ; \ output matches documentation
: btarget ( offset ppc-instr'n -- to-address ) ( 24-bit abs. field )
( for relative result,supply instrn addr;absolute rslt use 0 offset)
swap
03fffffc AND dup ( + 2 alignment bits -> 26 bits )
02000000 AND ( most G4 32-bit addr start with 00 or ff )
if fc000000 OR then \ if hi bit = 1, keep address hi
+ \ add the offset
;
\ These extract-and-display-multiple-operands routines are nominated
\ within the individual ppc instruction records which make up the
\ data table near the end of this source. By that means, individual
\ ppc instructions tell disasm1 how to display their operands.
: nil ( instruction -- ) DROP \ instr'ns with no operands eg 'rfi'
9 spaces ;
: all ( instruction -- ) \ used by "data" pseudo-instruction only
.hexdump ;
: T*4a ( ppc-instruction -- ) \ used by 'ba' and 'bla'
0 btarget \ zero offset keeps it absolute
.hexdump ;
: T*4r ( ppc-instruction -- ) \ 'b','bl' ( r=relative src fld )
addr btarget \ offset = instrn-addr changes absolute to relative
.hexdump
;
: cCbNT*4a ( ppc-instruction -- ) \ eg 'bcla'
align-address
dup 010 rshift dup 5 rshift
.xx .comma .nbr .comma sign-extend .hexdump ;
: cCbNT*4r ( ppc-instruction -- ) \ eg 'bc'
align-address
dup 010 rshift dup 5 rshift
.xx .comma .nbr .comma sign-extend
addr + ( rel. field + curr. instr'n addr -> final target addr )
.hexdump ;
: cCrAsI ( ppc-instruction -- ) \ 'twi' only
dup 010 rshift dup 5 rshift
.cc .comma .gpr .comma .si
;
: cCbN ( ppc-instruction -- ) \ eg 'bcctr' ("branch to addr in CTR")
010 rshift dup 5 rshift
.cc .comma .nbr
;
: cCrAB ( ppc-instruction -- ) \ 'tw' only
0b rshift dup 5 rshift dup 5 rshift
.nbr .comma .gpr .comma .gpr
;
: r@B ( ppc-instruction -- ) \ eg, 'dcba'
0b rshift \ discard all to right of right-most operand
dup 5 rshift \ push, then do similar for next operand
dup 01f and IF .gpr ELSE .nbr THEN .comma .gpr
;
: rB ( ppc-instruction -- ) \ eg, 'tlbie'
0b rshift \ re-position field to rhs for processing
.gpr \ output field as a general purpose register
;
: rT ( ppc-instruction -- )
015 rshift .gpr ;
: rS ( ppc-instruction -- ) rT ;
: fpT ( ppc-instruction -- ) \ eg 'mffs.'
015 rshift .fpr ;
: nT ( ppc-instruction -- ) \ eg 'mtfsb0'
015 rshift .nbr
;
: rTA ( ppc-instruction -- ) \ eg, 'neg.'
010 rshift
dup 5 rshift
.gpr .comma .gpr ;
: rxSA ( ppc-instruction -- )
010 rshift
dup 5 rshift SWAP
.gpr .comma .gpr
;
: rTAB ( ppc-instruction -- ) \ eg, 'mullw'
0b rshift \ position last 5-bit field to rhs
dup 5 rshift dup 5 rshift \ push remainder fields in rvs order
.gpr .comma .gpr .comma .gpr ; \ pop and print them
: rSAB ( ppc-instruction -- ) rTAB ; \ eg 'stbx'
: rT@B ( ppc-instruction -- ) \ eg, 'lbzx'
0b rshift dup 5 rshift dup 5 rshift
.gpr .comma dup 1f and IF .gpr ELSE .nbr THEN .comma .gpr ;
: rS@B ( ppc-instruction -- ) rT@B ; \ eg 'ecowx'
: rxSAB ( ppc-instruction -- ) \ eg. 'andc'
0b rshift
dup 5 rshift dup 5 rshift SWAP
.gpr .comma .gpr .comma .gpr
;
: fpTAB ( ppc-instruction -- ) \ eg 'fsubs'
0b rshift \ bring registers to chopping block for trimming
dup 5 rshift dup 5 rshift
.fpr .comma .fpr .comma .fpr ;
: fpTrAB ( ppc-instruction -- ) \ eg,'lfsux'
0b rshift \ shift right til only operands (and major opc) remain
dup 5 rshift dup 5 rshift \ copy & push after prev oprnd removed
.fpr .comma .gpr .comma .gpr ;
: fpSrAB ( ppc-instruction -- ) fpTrAB ; \ eg 'stfsx'
: fpTr@B ( ppc-instruction -- ) \ eg 'lfdx'
0b rshift dup 5 rshift dup 5 rshift
.fpr .comma dup 1f and IF .gpr ELSE .nbr THEN .comma .gpr ;
: fpSr@B ( ppc-instruction -- ) fpTr@B ; \ eg 'lfdx'
: nTAB ( ppc-instruction -- ) \ eg 'crxor'
0b rshift
dup 5 rshift dup 5 rshift
.nbr .comma .nbr .comma .nbr ;
: rT@nB ( ppc-instruction -- ) \ eg 'lswi'
0b rshift
dup 5 rshift dup 5 rshift
.gpr .comma dup 1f and IF .gpr ELSE .nbr THEN .comma .nbr ;
: rS@nB ( ppc-instruction -- ) rT@nB ; \ eg 'stswi'
: rxSAnB ( ppc-instruction -- ) \ eg 'srw'
0b rshift
dup 5 rshift dup 5 rshift SWAP
.gpr .comma .gpr .comma .nbr
;
: fpTAxBC ( ppc-instruction -- ) \ eg, 'fmadds'
06 rshift
dup 5 rshift dup 5 rshift dup 5 rshift \ xBC = output C before B
.fpr .comma .fpr .comma SWAP .fpr .comma .fpr
;
: rxSAnBCD ( ppc-instruction -- ) \ eg, 'rlwimi'
01 rshift
dup 5 rshift dup 5 rshift dup 5 rshift dup 5 rshift
SWAP .gpr .comma .gpr .comma .nbr .comma .nbr .comma .nbr ;
: rxSABnCD ( ppc-instruction -- ) \ eg, 'rlwinm.'
01 rshift
dup 5 rshift dup 5 rshift dup 5 rshift dup 5 rshift
SWAP .gpr .comma .gpr .comma .gpr .comma .nbr .comma .nbr
;
: fpTAC ( ppc-instruction -- ) \ eg, 'fmuls.'
06 rshift
dup 0a rshift dup 5 rshift
.fpr .comma .fpr .comma .fpr
;
: rTB ( ppc-instruction -- )
0b rshift \ eg, 'mfsrin'
dup 0a rshift ( skips register-B and unused reg-A at same time)
.gpr .comma .gpr ;
: rSB ( ppc-instruction -- ) rTB ; \ eg, 'fctiwz'
: fpTB ( ppc-instruction -- )
0b rshift
dup 0a rshift
.fpr .comma .fpr
;
: fpTx(rA)sD ( ppc-instruction -- ) \ eg 'lfd'
dup 10 rshift dup 5 rshift
.fpr .comma SWAP .sd [CHAR] ( emit .gpr [CHAR] ) emit ;
: fpTx(r@)sD ( ppc-instruction -- )
dup 10 rshift dup 5 rshift
.fpr .comma SWAP .sd [CHAR] ( emit dup 1f and IF .gpr ELSE .nbr
THEN [CHAR] ) emit ;
: fpSx(rA)sD ( ppc-instruction -- ) fpTx(rA)sD ; \ eg, 'stfdu'
: fpSx(r@)sD ( ppc-instruction -- ) fpTx(r@)sD \ eg, 'lfd'
;
: fT ( ppc-instruction -- ) \ 'mcrxr' only
017 rshift
.fld
;
: fTS ( ppc-instruction -- )
012 rshift dup 5 rshift
.fld .comma .fld
;
: fT.rAB ( ppc-instruction -- ) \ eg, 'cmp'
0b rshift
dup 5 rshift dup 7 rshift 0 SWAP
.fld .comma .nbr .comma .gpr .comma .gpr ;
: fTfpAB ( ppc-instruction -- ) \ eg, 'fcmpo'
0b rshift
dup 5 rshift dup 7 rshift
.fld .comma .fpr .comma .fpr
;
: fT.rAsI ( ppc-instruction -- ) \ 'cmpi' only
dup 010 rshift dup 7 rshift 0 SWAP
.fld .comma .nbr .comma .gpr .comma .si ;
: fT.rAuI ( ppc-instruction -- ) \ 'cmpli' only
dup 010 rshift dup 7 rshift 0 SWAP
.fld .comma .nbr .comma .gpr .comma .ui
;
: fThB ( ppc-instruction -- ) \ eg 'mtfsfi.'
0c rshift dup 0b rshift .fld .comma .imm ;
: rTgR ( ppc-instruction -- ) \ 'mfsr' only
010 rshift dup 5 rshift .gpr .comma .segr
;
: rTx(A)sD ( ppc-instruction -- ) \ eg, 'lwzu'
dup 010 rshift dup 5 rshift
.gpr .comma SWAP .si [CHAR] ( emit .gpr [CHAR] ) emit ;
: rSx(A)sD ( ppc-instruction -- ) rTx(A)sD ; \ eg 'stbu'
: rTx(@)sD ( ppc-instruction -- )
dup 010 rshift dup 5 rshift .gpr .comma SWAP .si
[CHAR] ( emit dup 1f AND IF .gpr ELSE .nbr THEN [CHAR] ) emit ;
: rSx(@)sD ( ppc-instruction -- ) rTx(@)sD
;
: rTAsI ( ppc-instruction -- ) \ eg, 'subfic'
dup 010 rshift dup 5 rshift
.gpr .comma .gpr .comma .si ;
: rT@sI ( ppc-instruction -- ) \ @ = A|0 as in (eg) 'addis'
dup 010 rshift dup 5 rshift
.gpr .comma
dup 01f and IF .gpr ELSE .nbr THEN \ rA == 0 -> '0' not 'r0'
.comma .si ;
: rxSAuI ( ppc-instruction -- ) \ eg, 'ori'
dup 010 rshift dup 5 rshift SWAP
.gpr .comma .gpr .comma .ui ;
: mMfpB ( ppc-instruction -- ) \ eg, 'mtfsf'
0b rshift dup 6 rshift \ trim to reg B, push; ditto 8-bit mask
.xx .comma .fpr
;
: xrSmM ( ppc-instruction -- ) \ 'mtcrf' only )
0c rshift dup 9 rshift SWAP \ ignore hi 0 to left of 8-bit field
.xx .comma .gpr ;
: xrSgS ( ppc-instruction -- ) \ 'mtsr' only )
010 rshift dup 5 rshift
.gpr .comma .segr ;
\ swap halves of spr/tbr spec field lo-hi to hi-lo order for display
: swap-ends ( ppc-instruction -- spr-specification )
001ff800 AND \ trim extraneous data from spr spec
lwsplit \ separate hi and lo halves
swap \ reverse their order
6 rshift \ reposition hi half to 5 of 10 most sig. bits
+ \ recombine
;
: rTxLH ( ppc-instruction -- ) \ 'mfspr' and 'mftb'
dup swap-ends
swap
015 rshift .gpr .comma .spr ;
: xrSxLH ( ppc-instruction -- ) \ 'mtspr' only
dup swap-ends
.spr .comma 015 rshift .gpr
;
\ ----------( end of extract-and-display-operand functions )-------
\ s, works like , (comma) but appends string not nbr to dictionary
: s, ( fm-addr len -- ) ( " string" in source leaves args on stack )
here swap move
2 cells allot
;
: records cells 5 * ;
0 value record->
0 value table
0 value last-record
here to table \ addr to start appending instr'n array to dictionary
\ The 'operands' fields below have names which are a form of
\ shorthand describing their composition. These same tags are
\ used to name and implement their extraction functions. Eg,
\ the most common register combinations derive from 5-bit fields
\ in fixed positions immediately following the obligatory six-bit
\ 'Major Opcode' on the far left of every 32-bit ppc instruction.
\ These most common operand fields are designated herein as T, A,
\ B, C. Any lower-case letters preceding those upper-case register
\ names apply as modifiers to all following register names until
\ another lower-case letter supercedes it. Thus fpTrABnC would
\ represent one floating-point register (T), two general purpose
\ registers (A and B) and a five-bit number (C). The function
\ "fpTrABnC" developed to implement it would thus output (eg)
\ fr1,r31,r2,23 , depending on the contents extracted from the
\ fields so nominated.
\ There are a few infrequently encountered exceptions however. Eg a
\ single 'x' augments but does not supercede the preceding
\ lower-case modifier. It means that the two registers to its right
\ are displayed in the opposite order to their relative positions
\ within the 32-bit ppc instruction they were extracted from.
\ (Such an 'x' transcribes directly to the forth word SWAP the way
\ it is implemented here). Note that these tags refer to their
\ relative position within 32-bit ppc instructions. The disassembler
\ syntax usually BUT NOT ALWAYS displays the operands in the same
\ left-to-right order they were extracted.
\
\ For more insights into the meanings of the uppercase designators,
\ refer to "Optimising PowerPC Code" by Gary Kacmarcik (Addison-
\ Wesley 1995). That book is the source of much of the ppc data
\ utilized for writing this disassembler. ('@' = short for 'rA|0')
\ Online documention, since discovered, substitutes 'rD' for 'rT'
\
\ The lower-case modifier-prefixes are:
\
\ r = general purpose register
\ fp = floating point register
\ m = mask
\ n = a number extracted from the same fields as abv, no prefix
\ f = a 3-bit field nbr, typically upper 3 of normal 5-bit field
\ g = 4-bit number, eg seGment register id (displayed in decimal)
\ h = 4-bit immediate data, eg bitmap of field (displayed in Hex)
\ c = a code,eg, cC = a code of type 'condition'="condition code"
\ i = immediate data (often the rhs half-word of the ppc instr'n)
\ s = signed (to the ppc & optionally displayed as such by 'dis')
\ u = unsigned (applies to immed. data copied direct fm instr'n)
\ d = a displacement or fixed offset fm number in associated reg.
\ a = absolute address (as near as you can get with the major
\ opcode occupying the six lhs bits of the instruction).
\ r = relative to address of current instruction.
\ ( = operand to be separated from prev one by '(' instead of ','
\ ) = Ignore. It is just there to make the meaning of '(' clearer
\ x = display the following two registers in reverse order
\ . = Display a constant '0' at this point without affecting
\ anything else. (It can also be a '1' on 64-bit ppc's only)
\
table d# 289 records BL fill \ pre-pad count must be >= #records
\ opcode final mask mnemonic operands (commas do the poking)
\ --------------------------------------------
00000000 , 00000000 , " data" s, ' all , ( the only pseudo-op)
\ The foll. 288 records = G4 Instruction Set
7c000214 , fc0007ff , " add" s, ' rTAB ,
7c000215 , fc0007ff , " add." s, ' rTAB ,
7c000014 , fc0007ff , " addc" s, ' rTAB ,
7c000015 , fc0007ff , " addc." s, ' rTAB ,
7c000414 , fc0007ff , " addco" s, ' rTAB ,
7c000415 , fc0007ff , " addco." s, ' rTAB ,
7c00008a , fc0007ff , " adde" s, ' rTAB ,
7c00008b , fc0007ff , " adde." s, ' rTAB ,
7c00048a , fc0007ff , " addeo" s, ' rTAB ,
7c00048b , fc0007ff , " addeo." s, ' rTAB ,
38000000 , fc000000 , " addi" s, ' rT@sI ,
30000000 , fc000000 , " addic" s, ' rTAsI ,
34000000 , fc000000 , " addic." s, ' rTAsI ,
3c000000 , fc000000 , " addis" s, ' rT@sI ,
7c0001d4 , fc00ffff , " addme" s, ' rTA ,
7c0001d5 , fc00ffff , " addme." s, ' rTA ,
7c0005d4 , fc00ffff , " addmeo" s, ' rTA ,
7c0005d5 , fc00ffff , " addmeo." s, ' rTA ,
7c000614 , fc0007ff , " addo" s, ' rTAB ,
7c000615 , fc0007ff , " addo." s, ' rTAB ,
7c000194 , fc00ffff , " addze" s, ' rTA ,
7c000195 , fc00ffff , " addze." s, ' rTA ,
7c000594 , fc00ffff , " addzeo" s, ' rTA ,
7c000595 , fc00ffff , " addzeo." s, ' rTA ,
7c000038 , fc0007ff , " and" s, ' rxSAB ,
7c000039 , fc0007ff , " and." s, ' rxSAB ,
7c000078 , fc0007ff , " andc" s, ' rxSAB ,
7c000079 , fc0007ff , " andc." s, ' rxSAB ,
70000000 , fc000000 , " andi." s, ' rxSAuI ,
74000000 , fc000000 , " andis." s, ' rxSAuI ,
48000000 , fc000003 , " b" s, ' T*4r ,
48000002 , fc000003 , " ba" s, ' T*4a ,
40000000 , fc000003 , " bc" s, ' cCbNT*4r ,
40000002 , fc000003 , " bca" s, ' cCbNT*4a ,
4c000420 , fc00ffff , " bcctr" s, ' cCbN ,
4c000421 , fc00ffff , " bcctrl" s, ' cCbN ,
40000001 , fc000003 , " bcl" s, ' cCbNT*4r ,
40000003 , fc000003 , " bcla" s, ' cCbNT*4a ,
4c000020 , fc00ffff , " bclr" s, ' cCbN ,
4c000021 , fc00ffff , " bclrl" s, ' cCbN ,
48000001 , fc000003 , " bl" s, ' T*4r ,
48000003 , fc000003 , " bla" s, ' T*4a ,
7c000000 , fc6007ff , " cmp" s, ' fT.rAB ,
2c000000 , fc600000 , " cmpi" s, ' fT.rAsI ,
7c000040 , fc6007ff , " cmpl" s, ' fT.rAB ,
28000000 , fc600000 , " cmpli" s, ' fT.rAuI ,
7c000034 , fc00ffff , " cntlzw" s, ' rxSA ,
7c000035 , fc00ffff , " cntlzw." s, ' rxSA ,
4c000202 , fc0007ff , " crand" s, ' nTAB ,
4c000102 , fc0007ff , " crandc" s, ' nTAB ,
4c000242 , fc0007ff , " creqv" s, ' nTAB ,
4c0001c2 , fc0007ff , " crnand" s, ' nTAB ,
4c000042 , fc0007ff , " crnor" s, ' nTAB ,
4c000382 , fc0007ff , " cror" s, ' nTAB ,
4c000342 , fc0007ff , " crorc" s, ' nTAB ,
4c000182 , fc0007ff , " crxor" s, ' nTAB ,
7c0002f6 , ffe007ff , " dcba" s, ' r@B ,
7c0000ac , ffe007ff , " dcbf" s, ' r@B ,
7c0003ac , ffe007ff , " dcbi" s, ' r@B ,
7c00006c , ffe007ff , " dcbst" s, ' r@B ,
7c00022c , ffe007ff , " dcbt" s, ' r@B ,
7c0001ec , ffe007ff , " dcbtst" s, ' r@B ,
7c0007ec , ffe007ff , " dcbz" s, ' r@B ,
7c0003d6 , fc0007ff , " divw" s, ' rTAB ,
7c0003d7 , fc0007ff , " divw." s, ' rTAB ,
7c0007d6 , fc0007ff , " divwo" s, ' rTAB ,
7c0007d7 , fc0007ff , " divwo." s, ' rTAB ,
7c000396 , fc0007ff , " divwu" s, ' rTAB ,
7c000397 , fc0007ff , " divwu." s, ' rTAB ,
7c000796 , fc0007ff , " divwuo" s, ' rTAB ,
7c000797 , fc0007ff , " divwuo." s, ' rTAB ,
7c00026c , fc0007ff , " eciwx" s, ' rT@B ,
7c00036c , fc0007ff , " ecowx" s, ' rS@B ,
7c0006ac , ffffffff , " eieio" s, ' nil ,
7c000238 , fc0007ff , " eqv" s, ' rxSAB ,
7c000239 , fc0007ff , " eqv." s, ' rxSAB ,
7c000774 , fc00ffff , " extsb" s, ' rxSA ,
7c000775 , fc00ffff , " extsb." s, ' rxSA ,
7c000734 , fc00ffff , " extsh" s, ' rxSA ,
7c000735 , fc00ffff , " extsh." s, ' rxSA ,
fc000210 , fc1f07ff , " fabs" s, ' fpTB ,
fc000211 , fc1f07ff , " fabs." s, ' fpTB ,
fc00002a , fc00003f , " fadd" s, ' fpTAB ,
fc00002b , fc00003f , " fadd." s, ' fpTAB ,
ec00002a , fc00003f , " fadds" s, ' fpTAB ,
ec00002b , fc00003f , " fadds." s, ' fpTAB ,
fc000040 , fc6007ff , " fcmpo" s, ' fTfpAB ,
fc000000 , fc6007ff , " fcmpu" s, ' fTfpAB ,
fc00001c , fc1f07ff , " fctiw" s, ' fpTB ,
fc00001d , fc1f07ff , " fctiw." s, ' fpTB ,
fc00001e , fc1f07ff , " fctiwz" s, ' fpTB ,
fc00001f , fc1f07ff , " fctiwz." s, ' fpTB ,
fc000024 , fc00003f , " fdiv" s, ' fpTAB ,
fc000025 , fc00003f , " fdiv." s, ' fpTAB ,
ec000024 , fc0007ff , " fdivs" s, ' fpTAB ,
ec000025 , fc0007ff , " fdivs." s, ' fpTAB ,
fc00003a , fc00003f , " fmadd" s, ' fpTAxBC ,
fc00003b , fc00003f , " fmadd." s, ' fpTAxBC ,
ec00003a , fc00003f , " fmadds" s, ' fpTAxBC ,
ec00003b , fc00003f , " fmadds." s, ' fpTAxBC ,
fc000090 , fc1f07ff , " fmr" s, ' fpTB ,
fc000091 , fc1f07ff , " fmr." s, ' fpTB ,
fc000038 , fc00003f , " fmsub" s, ' fpTAxBC ,
fc000039 , fc00003f , " fmsub." s, ' fpTAxBC ,
ec000038 , fc00003f , " fmsubs" s, ' fpTAxBC ,
ec000039 , fc00003f , " fmsubs." s, ' fpTAxBC ,
fc000032 , fc00f83f , " fmul" s, ' fpTAC ,
fc000033 , fc00003f , " fmul." s, ' fpTAC ,
ec000032 , fc00f83f , " fmuls" s, ' fpTAC ,
ec000033 , fc00f83f , " fmuls." s, ' fpTAC ,
fc000110 , fc1f07ff , " fnabs" s, ' fpTB ,
fc000111 , fc1f07ff , " fnabs." s, ' fpTB ,
fc000050 , fc1f07ff , " fneg" s, ' fpTB ,
fc000051 , fc1f07ff , " fneg." s, ' fpTB ,
fc00003e , fc00003f , " fnmadd" s, ' fpTAxBC ,
fc00003f , fc00003f , " fnmadd." s, ' fpTAxBC ,
ec00003e , fc00003f , " fnmadds" s, ' fpTAxBC ,
ec00003f , fc00003f , " fnmadds." s, ' fpTAxBC ,
fc00003c , fc00003f , " fnmsub" s, ' fpTAxBC ,
fc00003d , fc00003f , " fnmsub." s, ' fpTAxBC ,
ec00003c , fc00003f , " fnmsubs" s, ' fpTAxBC ,
ec00003d , fc00003f , " fnmsubs." s, ' fpTAxBC ,
ec000030 , fc1f07ff , " fres" s, ' fpTB ,
ec000031 , fc1f07ff , " fres." s, ' fpTB ,
fc000018 , fc1f07ff , " frsp" s, ' fpTB ,
fc000019 , fc1f07ff , " frsp." s, ' fpTB ,
fc000034 , fc1f003f , " frsqrte" s, ' fpTB ,
fc000035 , fc1f003f , " frsqrte." s, ' fpTB ,
fc00002e , fc00003f , " fsel" s, ' fpTAxBC ,
fc00002f , fc00003f , " fsel." s, ' fpTAxBC ,
fc000028 , fc00003f , " fsub" s, ' fpTAB ,
fc000029 , fc00003f , " fsub." s, ' fpTAB ,
ec000028 , fc00003f , " fsubs" s, ' fpTAB ,
ec000029 , fc00003f , " fsubs." s, ' fpTAB ,
7c0007ac , ffe007ff , " icbi" s, ' r@B ,
4c00012c , ffffffff , " isync" s, ' nil ,
88000000 , fc000000 , " lbz" s, ' rTx(@)sD ,
8c000000 , fc000000 , " lbzu" s, ' rTx(A)sD ,
7c0000ee , fc0007ff , " lbzux" s, ' rTAB ,
7c0000ae , fc0007ff , " lbzx" s, ' rT@B ,
c8000000 , fc000000 , " lfd" s, ' fpTx(r@)sD ,
cc000000 , fc000000 , " lfdu" s, ' fpTx(rA)sD ,
7c0004ee , fc0007ff , " lfdux" s, ' fpTrAB ,
7c0004ae , fc0007ff , " lfdx" s, ' fpTr@B ,
c0000000 , fc000000 , " lfs" s, ' fpTx(r@)sD ,
c4000000 , fc000000 , " lfsu" s, ' fpTx(rA)sD ,
7c00046e , fc0007ff , " lfsux" s, ' fpTrAB ,
7c00042e , fc0007ff , " lfsx" s, ' fpTr@B ,
a8000000 , fc000000 , " lha" s, ' rTx(A)sD ,
ac000000 , fc000000 , " lhau" s, ' rTx(@)sD ,
7c0002ee , fc0007ff , " lhaux" s, ' rTAB ,
7c0002ae , fc0007ff , " lhax" s, ' rT@B ,
7c00062c , fc0007ff , " lhbrx" s, ' rT@B ,
a0000000 , fc000000 , " lhz" s, ' rTx(@)sD ,
a4000000 , fc000000 , " lhzu" s, ' rTx(A)sD ,
7c00026e , fc0007ff , " lhzux" s, ' rTAB ,
7c00022e , fc0007ff , " lhzx" s, ' rT@B ,
b8000000 , fc000000 , " lmw" s, ' rTx(@)sD ,
7c0004aa , fc0007ff , " lswi" s, ' rT@nB ,
7c00042a , fc0007ff , " lswx" s, ' rT@B ,
7c000028 , fc0007ff , " lwarx" s, ' rT@B ,
7c00042c , fc0007ff , " lwbrx" s, ' rT@B ,
80000000 , fc000000 , " lwz" s, ' rTx(@)sD ,
84000000 , fc000000 , " lwzu" s, ' rTx(A)sD ,
7c00006e , fc0007ff , " lwzux" s, ' rTAB ,
7c00002e , fc0007ff , " lwzx" s, ' rT@B ,
4c000000 , fc63ffff , " mcrf" s, ' fTS ,
fc000080 , fc63ffff , " mcrfs" s, ' fTS ,
7c000400 , fc7fffff , " mcrxr" s, ' fT ,
7c000026 , fc1fffff , " mfcr" s, ' rT ,
fc00048e , fc1fffff , " mffs" s, ' fpT ,
fc00048f , fc1fffff , " mffs." s, ' fpT ,
7c0000a6 , fc1fffff , " mfmsr" s, ' rT ,
7c0002a6 , fc0007ff , " mfspr" s, ' rTxLH ,
7c0004a6 , fc10ffff , " mfsr" s, ' rTgR ,
7c000526 , fc1f07ff , " mfsrin" s, ' rTB ,
7c0c42e6 , fc1fffff , " mftb" s, ' rT , \ Alt Form 'mftb rT,268'
7c0d42e6 , fc1fffff , " mftbu" s, ' rT , \ Alt Form 'mftb rT,269'
\ Basic Form 'mftb' removed as 268 & 269 are its only valid operands
7c000120 , fc100fff , " mtcrf" s, ' xrSmM ,
fc00008c , fc1fffff , " mtfsb0" s, ' nT ,
fc00008d , fc1fffff , " mtfsb0." s, ' nT ,
fc00004c , fc1fffff , " mtfsb1" s, ' nT ,
fc00004d , fc1fffff , " mtfsb1." s, ' nT ,
fc00058e , fe0107ff , " mtfsf" s, ' mMfpB ,
fc00058f , fe0107ff , " mtfsf." s, ' mMfpB ,
fc00010c , fc7f0fff , " mtfsfi" s, ' fThB ,
fc00010d , fc7f0fff , " mtfsfi." s, ' fThB ,
7c000124 , fc1fffff , " mtmsr" s, ' rS ,
7c0003a6 , fc0007ff , " mtspr" s, ' xrSxLH ,
7c0001a4 , fc0007ff , " mtsr" s, ' xrSgS ,
7c0001e4 , fc1f07ff , " mtsrin" s, ' rSB ,
7c000092 , fc0007ff , " mulhw" s, ' rTAB ,
7c000093 , fc0007ff , " mulhw." s, ' rTAB ,
7c000016 , fc0007ff , " mulhwu" s, ' rTAB ,
7c000017 , fc0007ff , " mulhwu." s, ' rTAB ,
1c000000 , fc000000 , " mulli" s, ' rTAsI ,
7c0001d6 , fc0007ff , " mullw" s, ' rTAB ,
7c0001d7 , fc0007ff , " mullw." s, ' rTAB ,
7c0005d6 , fc0007ff , " mullwo" s, ' rTAB ,
7c0005d7 , fc0007ff , " mullwo." s, ' rTAB ,
7c0003b8 , fc0007ff , " nand" s, ' rxSAB ,
7c0003b9 , fc0007ff , " nand." s, ' rxSAB ,
7c0000d0 , fc00ffff , " neg" s, ' rTA ,
7c0000d1 , fc00ffff , " neg." s, ' rTA ,
7c0004d0 , fc00ffff , " nego" s, ' rTA ,
7c0004d1 , fc00ffff , " nego." s, ' rTA ,
7c0000f8 , fc0007ff , " nor" s, ' rxSAB ,
7c0000f9 , fc0007ff , " nor." s, ' rxSAB ,
7c000378 , fc0007ff , " or" s, ' rxSAB ,
7c000379 , fc0007ff , " or." s, ' rxSAB ,
7c000338 , fc0007ff , " orc" s, ' rxSAB ,
7c000339 , fc0007ff , " orc." s, ' rxSAB ,
60000000 , fc000000 , " ori" s, ' rxSAuI ,
64000000 , fc000000 , " oris" s, ' rxSAuI ,
4c000064 , ffffffff , " rfi" s, ' nil ,
50000000 , fc000001 , " rlwimi" s, ' rxSAnBCD ,
50000001 , fc000001 , " rlwimi." s, ' rxSAnBCD ,
54000000 , fc000001 , " rlwinm" s, ' rxSAnBCD ,
54000001 , fc000001 , " rlwinm." s, ' rxSAnBCD ,
5c000000 , fc000001 , " rlwnm" s, ' rxSABnCD ,
5c000001 , fc000001 , " rlwnm." s, ' rxSABnCD ,
44000002 , fc000003 , " sc" s, ' nil ,
7c000030 , fc0007ff , " slw" s, ' rxSAB ,
7c000031 , fc0007ff , " slw." s, ' rxSAB ,
7c000630 , fc0007ff , " sraw" s, ' rxSAB ,
7c000631 , fc0007ff , " sraw." s, ' rxSAB ,
7c000670 , fc0007ff , " srawi" s, ' rxSAnB ,
7c000671 , fc0007ff , " srawi." s, ' rxSAnB ,
7c000430 , fc0007ff , " srw" s, ' rxSAB ,
7c000431 , fc0007ff , " srw." s, ' rxSAB ,
98000000 , fc000000 , " stb" s, ' rSx(@)sD ,
9c000000 , fc000000 , " stbu" s, ' rSx(A)sD ,
7c0001ee , fc0007ff , " stbux" s, ' rSAB ,
7c0001ae , fc0007ff , " stbx" s, ' rS@B ,
d8000000 , fc000000 , " stfd" s, ' fpSx(r@)sD ,
dc000000 , fc000000 , " stfdu" s, ' fpSx(rA)sD ,
7c0005ee , fc0007ff , " stfdux" s, ' fpSrAB ,
7c0005ae , fc0007ff , " stfdx" s, ' fpSr@B ,
7c0007ae , fc0007ff , " stfiwx" s, ' fpSr@B ,
d0000000 , fc000000 , " stfs" s, ' fpSx(r@)sD ,
d4000000 , fc000000 , " stfsu" s, ' fpSx(rA)sD ,
7c00056e , fc0007ff , " stfsux" s, ' fpSrAB ,
7c00052e , fc0007ff , " stfsx" s, ' fpSr@B ,
b0000000 , fc000000 , " sth" s, ' rSx(@)sD ,
7c00072c , fc0007ff , " sthbrx" s, ' rS@B ,
b4000000 , fc000000 , " sthu" s, ' rSx(A)sD ,
7c00036e , fc0007ff , " sthux" s, ' rSAB ,
7c00032e , fc0007ff , " sthx" s, ' rS@B ,
bc000000 , fc000000 , " stmw" s, ' rSx(@)sD ,
7c0005aa , fc0007ff , " stswi" s, ' rS@nB ,
7c00052a , fc0007ff , " stswx" s, ' rS@B ,
90000000 , fc000000 , " stw" s, ' rSx(@)sD ,
7c00052c , fc0007ff , " stwbrx" s, ' rS@B ,
7c00012d , fc0007ff , " stwcx." s, ' rS@B ,
94000000 , fc000000 , " stwu" s, ' rSx(A)sD ,
7c00016e , fc0007ff , " stwux" s, ' rSAB ,
7c00012e , fc0007ff , " stwx" s, ' rS@B ,
7c000050 , fc0007ff , " subf" s, ' rTAB ,
7c000051 , fc0007ff , " subf." s, ' rTAB ,
7c000010 , fc0007ff , " subfc" s, ' rTAB ,
7c000011 , fc0007ff , " subfc." s, ' rTAB ,
7c000410 , fc0007ff , " subfco" s, ' rTAB ,
7c000411 , fc0007ff , " subfco." s, ' rTAB ,
7c000110 , fc0007ff , " subfe" s, ' rTAB ,
7c000111 , fc0007ff , " subfe." s, ' rTAB ,
7c000510 , fc0007ff , " subfeo" s, ' rTAB ,
7c000511 , fc0007ff , " subfeo." s, ' rTAB ,
20000000 , fc000000 , " subfic" s, ' rTAsI ,
7c0001d0 , fc00ffff , " subfme" s, ' rTA ,
7c0001d1 , fc00ffff , " subfme." s, ' rTA ,
7c0005d0 , fc00ffff , " subfmeo" s, ' rTA ,
7c0005d1 , fc00ffff , " subfmeo." s, ' rTA ,
7c000450 , fc0007ff , " subfo" s, ' rTAB ,
7c000451 , fc0007ff , " subfo." s, ' rTAB ,
7c000190 , fc00ffff , " subfze" s, ' rTA ,
7c000191 , fc00ffff , " subfze." s, ' rTA ,
7c000591 , fc00ffff , " subfzeo" s, ' rTA ,
7c000590 , fc00ffff , " subfzeo." s, ' rTA ,
7c0004ac , ffffffff , " sync" s, ' nil ,
7c000264 , ffff07ff , " tlbie" s, ' rB ,
7c00046c , ffffffff , " tlbsync" s, ' nil ,
7c000008 , fc0007ff , " tw" s, ' cCrAB ,
0c000000 , fc000000 , " twi" s, ' cCrAsI ,
7c000278 , fc0007ff , " xor" s, ' rxSAB ,
7c000279 , fc0007ff , " xor." s, ' rxSAB ,
68000000 , fc000000 , " xori" s, ' rxSAuI ,
6c000000 , fc000000 , " xoris" s, ' rxSAuI ,
\ ====================================
here 1 records - to last-record
here to addr \ garbage better than +dis : Illegal memory access
0 value opcode
: find-record
table last-record DO \ search for opcode in table
I @ opcode = IF I leave THEN \ found: put index on stack
I table = IF I leave THEN \ not found: make 'data' the instrn
-1 records +LOOP
;
: disasm1 ( address --) ( on exit, opcode=FALSE for invalid instr'n)
hex
align-address \ force, so that branch operands always accurate
dup to addr
.hexdump 3a emit BL emit ( print instruction address )
addr @ .hexdump 2 spaces \ optional line:add raw code to output
addr dup @ swap roughmask AND to opcode ( save candidate opc )
find-record to record->
record-> cell+ @ ( instr'n-nominated mask combined with )
addr @ AND dup ( instruction gives precise opcode)
opcode <> IF ( does it match initially calc'd opcode ? )
table to record-> THEN ( invalid instr'n becomes "data" )
( dup'd) to opcode ( also doubles as return code )
record-> 2 cells + ( advance record pointer to mnemonic )
8 type BL emit ( output mnemonic )
addr @
record-> 4 cells + @ ( ppc instr'n rec. nominates routine to )
execute ( extract, format and print its operands)
cr
addr cell+ to addr ( postincrement preps for next instr'n )
;
: dis ( address -- ) \ replaces built-in original
cr -1 swap
do i disasm1
exit? \ displays pagination prompt; use ret-key to single-step
if leave then
cell +loop
;
: +dis ( -- ) addr dis ; \ replaces built-in original
: +dasm ( -- ) \ '+dis' variant stops at end of code bloc
cr
begin
addr disasm1
\ stop on any foll. unconditional return or non ret-saved jump
opcode 48000000 ( b ) =
opcode 48000002 ( ba ) = OR
opcode 4c000064 ( rfi ) = OR
addr cell - @ ffe0ffff AND 4e800020 ( blr, any crf ) = OR
addr cell - @ ffe0ffff AND 4e800420 ( bctr, any crf) = OR
addr cell - @ ffe00001 AND 42800000 ( bc unconditional ) = OR
exit? OR
until
;
: dasm ( address -- ) \ dis halted by 'b' 'ba' 'rfi' 'blr' or 'bctr'
to addr +dasm
;
cr
." Public Domain replacement 'dis' for G4 Macintosh Open Firmware."
cr
." Written and revised by Neville Duguid (Tinkerer), Apr-Jun 2008."
cr
." dis, +dis, dasm, +dasm await your command. Usage: <address> dis"
cr
\ ---- Bonus Evaluation Kit. Delete when you've had your fun -----
\ Cheap and nasty one-note assembler to test 'lswi' "Load String
\ Word Immediate" - the instruction most likely to drive you nuts
\ trying to verify.(Actually 'lswx' is worse, but can't be tested
\ automatically by disassembler since its nB is runtime variable)
( It has been left here to show how easy it is to improvise a one- )
( line assembler using Forth and the resources in this source file )
\ Sample usage (incompatible operands downgrade "lswi" to "data"):
\ The args have to fit in 5-bit fields. Limit values to d# 0-31
\ 2 3 4 lswi --> lswi r2,r3,4 ( all 4 bytes fit in r2 )
\ 2 3 5 lswi --> data 7c432caa (5th byte zaps src reg r3)
\ d# 31 6 d# 31 lswi --> data 7fe6fcaa (range wraps around to r6)
\ d# 31 7 d# 31 lswi --> lswi r31,r7,31 (31 bytes fit in r31,r0-6)
\ d# 31 6 0 lswi --> data 7fe604aa (0 byte-count taken as 32)
\ ... and they call it RISC ! The fun is just beginning ...
\
: lswi ( rT rA nB -- ) \ assembles 'lswi' instructions only
01f and 0b << -rot
01f and 010 << swap
01f and 015 <<
7c0004aa OR OR OR \ 'lswi' instruction literally assembled
align here ! ( '!' is Forth for 32-bit poke )
cr
here disasm1 ( 'here' points to start of free memory )
opcode IF \ FALSE (0) only if disasm1 output "data"
cell allot \ success, advance 'here' to next memory cell
THEN \ else next attempt will overwrite this one
;