The Spawn tool was designed to generate the machine specific parts of the Executable Editing Library (EEL). Spawn reads a detailed instruction set architecture description written in SADL, and specializes the machine specific C++ code used by EEL to manipulate these machine instructions. Architecture descriptions capture the binary instruction encodings, instruction semantics, and architectural register descriptions of several RISC processors. From analysis of these descriptions Spawn can distinguish between different kinds of instructions (e.g., loads, stores, jumps, branches, floating point or integer computation, traps), determine which registers are read from or written to, and lots of other useful information. There is enough information contained in the description of most instructions for Spawn to generate C++ code to simulate the instruction's semantic operation.
A brief description of Spawn, SADL, and their relation to EEL is given in "EEL: Machine-Independent Executable Editing," appearing in the Proceedings of the SIGPLAN Conference on Programming Language Design and Implementation (PLDI), June 1995. Spawn and SADL were later extended to provide information for instruction scheduling as part EEL's editing of an executable. Another paper, appearing in MICRO29, shows that simple instruction scheduling can hide 20-65% of the cost of some program instrumentation.
/////////////////////////////////////////////////////////////////////////////// // // Spawn description file for the SPARC instruction encodings. // encode{32} instruction fields op 30:31, op2 22:24, op3 19:24, opf 5:13, rd 25:29, rs1 14:18, rs2 0:4, iflag 13:13, simm13 0:12, imm22 0:21, disp22 0:21, disp30 0:29, cond 25:28, aflag 29:29, asi 5:12 pat [op0inst call op2inst op3inst] is op=[0..3] // // Macro patterns to insure bits are zero based on // the use or lack of the immediate value field. pat noasi is (iflag=0 && asi=0) || iflag=1 pat trapn is (iflag=0 && asi=0) || (iflag=1 && instruction{7:12}=0) // // branch & other op0 instructions pat sethi is op0inst && op2=0b100 pat nop is sethi && rd=0 && imm22=0 pat unimp is op0inst && op2=0b000 && rd=0 pat [ bn be ble bl bleu bcs bneg bvs ba bne bg bge bgu bcc bpos bvc fbn fbne fblg fbul fbl fbug fbg fbu fba fbe fbue fbge fbuge fble fbule fbo cbn cb123 cb12 cb13 cb1 cb23 cb2 cb3 cba cb0 cb03 cb02 cb023 cb01 cb013 cb012 ] is op0inst && op2=[0b010 0b110 0b111] && cond=[0..15] // // load & store instructions pat [ ld ldub lduh ldd st stb sth std _ ldsb ldsh _ _ ldstub _ swap lda lduba lduha ldda sta stba stha stda _ ldsba ldsha _ _ ldstuba _ swapa ] is op3inst && op3=[0b000000..0b011111] pat [ ldf ldfsr _ lddf stf stfsr stdfq stdf ldc ldcsr _ lddc stc stcsr stdcq stdc ] is op3inst && (op3=[0b100000..0b100111] || op3=[0b110000..0b110111]) && noasi // // op2 instructions pat [ add and or xor sub andn orn xnor addx _ umul smul subx _ udiv sdiv addcc andcc orcc xorcc subcc andncc orncc xnorcc addxcc _ umulcc smulcc subxcc _ udivcc sdivcc taddcc tsubcc taddcctv tsubcctv mulscc _ _ _ _ _ _ _ _ _ _ _ wranc wrpsr wrwim wrtbr _ _ _ _ jmpl _ _ _ save restore _ _ ] is op2inst && op3=[0b000000..0b111111] && noasi pat [sll srl sra] is op2inst && op3=[0b100101..0b100111] && asi=0 pat [fpop1 fpop2 cpop1 cpop2] is op2inst && op3=[0b110100..0b110111] pat [rett flush] is op2inst && op3=[0b111001 0b111011] && rd=0 && noasi pat [rdanc rdpsr rdwim rdtbr] is op2inst && op3=[0b101000..0b101011] && iflag=0 && simm13=0 pat rdy is rdanc && rs1=0 pat rdasr is rdanc // && rs1=[1..31] pat wry is wranc && rs1=0 pat wrasr is wranc // && rs1=[1..31] pat stbar is op2inst && op3=0b101000 && rd=0 && rs1=0b01111 && iflag=0 && simm13=0 pat [ tn te tle tl tleu tcs tneg tvs ta tne tg tge tgu tcc tpos tvc ] is op2inst && aflag=0 && cond=[0..15] && op3=0b111010 && trapn pat [ fabss faddd faddq fadds fdivd fdivq fdivs fdmulq fdtoi fdtoq fdtos fitod fitoq fitos fmovs fmuld fmulq fmuls fnegs fqtod fqtoi fqtos fsmuld fsqrtd fsqrtq fsqrts fstod fstoi fstoq fsubd fsubq fsubs ] is fpop1 && opf = [ 0b000001001 0b001000010 0b001000011 0b001000001 0b001001110 0b001001111 0b001001101 0b001101110 0b011010010 0b011001110 0b011000110 0b011001000 0b011001100 0b011000100 0b000000001 0b001001010 0b001001011 0b001001001 0b000000101 0b011001011 0b011010011 0b011000111 0b001101001 0b000101010 0b000101011 0b000101001 0b011001001 0b011010001 0b011001101 0b001000110 0b001000111 0b001000101 ] pat [ fcmpd fcmpq fcmps fcmped fcmpeq fcmpes ] is fpop2 && opf = [ 0b001010010 0b001010011 0b001010001 0b001010110 0b001010111 0b001010101 ]
/////////////////////////////////////////////////////////////////////////////// // // Resource Definitions // val [% +] is [(\s1:unsigned{32}.\s2. umod32 (unsigned{64}s1) s2) uadd32] // // Integer Data Path (IDP) type address register untyped{32} pc // program counter register untyped{32} R[35] // general purpose register set alias untyped{32} zero is R[0] alias untyped{32} irpc is R[31] alias untyped{32} orpc is R[15] alias untyped{32} sp is R[14] alias untyped{32} fp is R[30] alias untyped{32} PSR is R[32] alias untyped{32} FSR is R[33] alias untyped{32} Y is R[34] alias signed{32} R4r[i] is R[i] // ALU read from register set alias unsigned{32} uR4r[i] is R[i] alias signed{32} R4w[i] is R[i] // ALU write to register set alias unsigned{32} uR4w[i] is R[i] alias address{32} aR4r[i] is R[i] // LSU read address reg alias untyped{32} R4r'[i] is R[i] // LSU read from register set alias untyped{32} R4w'[i] is R[i] // LSU write to register set // double word LSU access to register set alias untyped{64} R8r'[i: unsigned{32}i%2=0] is R[i]::R[unsigned{32}i + 1] alias untyped{64} R8w'[i: unsigned{32}i%2=0] is R[i]::R[unsigned{32}i + 1] // // Floating-Point Unit (FPU) type float register untyped{32} F[32] // floating-point register set // FP read 4 and 8 byte values alias float{32} F4r[i] is isFloat, F[i] alias float{64} F8r[i: unsigned{32}i%2=0] is isFloat, (F[i]::F[unsigned{32}i + 1]) alias signed{32} FIr[i] is isFloat, F[i] // FP write 4 and 8 byte values alias float{32} F4w[i] is isFloat, F[i] alias float{64} F8w[i: unsigned{32}i%2=0] is isFloat, (F[i]::F[unsigned{32}i + 1]) alias signed{32} FIw[i] is isFloat, F[i] // FP load/store: read 4 and 8 byte values alias untyped{32} F4r'[i] is isFloat, F[i] alias untyped{64} F8r'[i: unsigned{32}i%2=0] is isFloat, (F[i]::F[unsigned{32}i + 1]) // FP load/store: write 4 and 8 byte values alias untyped{32} F4w'[i] is isFloat, F[i] alias untyped{64} F8w'[i: unsigned{32}i%2=0] is isFloat, (F[i]::F[unsigned{32}i + 1]) // // Special Registers register untyped{32} WIM, TBR, CWP register untyped{64} FQ // // Memory memory untyped{ 8} M1[address{32}] memory untyped{16} M2[address{32}] memory untyped{32} M4[address{32}] memory untyped{64} M8[address{32}] // operators used in definition of memory aliases val % is \a:address{32}.\i. (unsigned a) % i alias untyped{32} M1[i] is (untyped{24}0)::M1[i] alias untyped{32} M2[i: i%2=0] is (untyped{16}0)::M2[i] alias untyped{16} M2[i: i%2=0] is M2[i] alias untyped{32} M4[i: i%4=0] is M4[i] alias untyped{64} M8[i: i%8=0] is M8[i] // Load of 1, 2, 4, and 8 byte values alias untyped{ 8} M1r[i] is ARf Memory, M1[i] alias untyped{32} M1r[i] is ARf Memory, M1[i] alias untyped{16} M2r[i] is ARf Memory, M2[i] alias untyped{32} M2r[i] is ARf Memory, M2[i] alias untyped{32} M4r[i] is ARf Memory, M4[i] alias untyped{64} M8r[i] is ARf Memory, M8[i] // Store of 1, 2, 4, and 8 byte values alias untyped{ 8} M1w[i] is M1[i] alias untyped{32} M1w[i] is M1[i] alias untyped{16} M2w[i] is M2[i] alias untyped{32} M2w[i] is M2[i] alias untyped{32} M4w[i] is M4[i] alias untyped{64} M8w[i] is M8[i]
/////////////////////////////////////////////////////////////////////////////// // // Operator Definitions // val Id32 is \a:untyped{32}. untyped{32} a val Id64 is \a:untyped{64}. untyped{64} a val [ # # # # # ] is (\op.\s1. op s1) @ [ ext8 ext13 ext16 ext22 ext30 ] // // Protocol for reading source registers val src1 is R4r[rs1] val src1 is uR4r[rs1] val src2 is iflag=1 ? #simm13 : R4r[rs2] val src2 is iflag=1 ? unsigned{32} simm13 : uR4r[rs2] val addr is _a1:=aR4r[rs1], _a2:=(iflag=1 ? address{32}(#simm13) : aR4r[rs2]), address(add32 (signed _a1) (signed _a2)) // // ALU Operators val [ + - & | ^ ] is (\op.\s1.\s2. op s1 s2) @ [ add32 sub32 and32 or32 xor32 ] val [ :+ :- ] is (\op.\s1.\s2. (??) PSR (op s1 s2)) @ [ add32 sub32 ] val [ +' -' &' |' ^' ] is (\op.\s1.\s2. _x:=op s1 s2, PSR:=(??), _x) @ [ add32 sub32 and32 or32 xor32 ] val [ :+' :-' ] is (\op.\s1.\s2. _x:=(??) PSR (op s1 s2), PSR:=(??), _x) @ [ add32 sub32 ] val [ << >> >> ] is (\op.\s1.\s2. isShift, op s1 s2) @ [ sll32 srl32 sra32 ] infixl 7 :*' val :*' is \a:signed{32}.\b:signed{32}. _x:=(??) PSR a b, PSR:=(??), _x val [ * $* / $/ ] is (\op.\s1.\s2. op s1 s2) @ [ mul32 umul32 div32 udiv32 ] val [ *' $*' /' $/' ] is (\op.\s1.\s2. _x:=op s1 s2, PSR:=(??), _x) @ [ mul32 umul32 div32 udiv32 ] val [ !& !| !^ !&' !|' !^' ] is (\op.\s1.\s2. op s1 (not32 s2)) @ [ & | ^ &' |' ^' ] // // FPU Operators val [ abs cvt cvt cvt cvt mov ~ cvt cvt ] is (\op.\s1. op s1) @ [ fabss fdtoi fdtos fitod fitos (\a.a) fnegs fstod fstoi ] val [ sqrt sqrt ] is (\op.\s1. op s1) @ [ fsqrts fsqrtd ] val [ + + - - ] is (\op.\s1.\s2. op s1 s2) @ [ fadds faddd fsubs fsubd ] val [ * * * ] is (\op.\s1.\s2. op s1 s2) @ [ fmuls fmuld fsmuld ] val [ / / ] is (\op.\s1.\s2. op s1 s2) @ [ fdivs fdivd ] /////////////////////////////////////////////////////////////////////////////// // // Instruction Semantics // sem sethi is uR4w[rd]:=sll32 (unsigned{32}imm22) 10 // // load & store instructions sem [ ldsb ldsh ldub lduh ld ldf lddf ldsba ldsha lduba lduha lda ] is (\r.\m.\sgn. r[rd]:=sgn m[addr]) @ [ R4w' R4w' R4w' R4w' R4w' F4w' F8w' R4w' R4w' R4w' R4w' R4w' ] $ [ M1r M2r M1r M2r M4r M4r M8r M1r M2r M1r M2r M4r ] $ [ # # Id32 Id32 Id32 Id32 Id64 # # Id32 Id32 Id32 ] sem [ ldd ldda ] is (\r.\m.\sgn. r[rd]:=sgn m[addr]) @ [ R8w' R8w' ] $ [ M8r M8r ] $ [ Id64 Id64 ] sem [ stb sth st stf stdf stba stha sta std stda ] is (\r.\m. m[addr]:=r[rd]) @ [ R4r' R4r' R4r' F4r' F8r' R4r' R4r' R4r' R8r' R8r' ] $ [ M1w M2w M4w M4w M8w M1w M2w M4w M8w M8w ] sem ldfsr is FSR:=M4r[addr] sem stfsr is M4w[addr]:=FSR sem ldstub is a:=addr, x:=M1r[a], M1[a]:=untyped{8}0xff, R4w[rd]:=x sem ldstuba is a:=addr, x:=M1r[a], M1[a]:=untyped{8}0xff, R4w[rd]:=x sem swap is a:=addr, x:=R4r'[rd], y:=M4r[a], M4[a]:=x, R4w[rd]:=y sem swapa is a:=addr, x:=R4r'[rd], y:=M4r[a], M4[a]:=x, R4w[rd]:=y sem [ rdy rdpsr rdwim rdtbr ] is (\r. R4w[rd]:=r) @ [ Y PSR WIM TBR ] sem [ wry wrpsr wrwim wrtbr ] is (\r. r:=src1^src2) @ [ Y PSR WIM TBR ] sem flush is iflag=1 ? () // // Integer computation instructions sem [ add addcc addx addxcc sub subcc subx subxcc sra ] is (\op. R4w[rd]:=op src1 src2) @ [ + +' :+ :+' - -' :- :-' >> ] sem [ and andcc andn andncc or orcc orn orncc xor xorcc xnor xnorcc sll srl ] is (\op. uR4w[rd]:=op src1 src2) @ [ & &' !& !&' | |' !| !|' ^ ^' !^ !^' << >> ] sem [ taddcctv tsubcctv ] is (\op. R4w[rd]:=op src1 src2) @ [ +' -' ] sem mulscc is R4w[rd]:=src1:*'src2 sem [ smul smulcc umul umulcc ] is (\op. x:=op src1 src2, Y:=x{32:63}, uR4w[rd]:=x{0:31}) @ [ * *' $* $*' ] sem [ sdiv sdivcc ] is (\op. s1:=signed{64}(Y::((\a:unsigned.a)src1)), R4w[rd]:=op s1 src2) @ [ / /' ] sem [ udiv udivcc ] is (\op. s1:=(Y::((\a:unsigned.a)src1)), uR4w[rd]:=op s1 src2) @ [ $/ $/' ] sem [ save restore ] is (\op. s1:=src1, s2:=src2, CWP:=op CWP 1, R4w[rd]:=s1+s2) @ [ usub32 uadd32 ] // // FP computation instructions sem [ fabss fdtoi fdtos fitod fitos fmovs fnegs fstod fstoi fsqrtd fsqrts ] is (\op.\r.\w. w[rd]:=op r[rs2]) @ [ abs cvt cvt cvt cvt mov ~ cvt cvt sqrt sqrt ] $ [ F4r F8r F8r FIr FIr F4r F4r F4r F4r F8r F4r ] $ [ F4w FIw F4w F8w F4w F4w F4w F8w FIw F8w F4w ] sem [ faddd fadds fsubd fsubs fdivd fdivs fmuld fmuls fsmuld ] is (\op.\r.\w. w[rd]:=op r[rs1] r[rs2]) @ [ + + - - / / * * * ] $ [ F8r F4r F8r F4r F8r F4r F8r F4r F4r ] $ [ F8w F4w F8w F4w F8w F4w F8w F4w F8w ] sem [ fcmpd fcmped fcmpes fcmps ] is (\r. (??):=r[rs1]-r[rs2], FSR:=(??)) @ [ F8r F8r F4r F4r ] // // control transfer instructions val target is add32 (signed{32} pc) (signed (sll32 (unsigned (#disp22)) 2)) val branch is \r.\op. (); op r ? pc:=target : aflag=1 ? annul val trap is \op. op PSR ? system ((\a:signed.a)src2) : () val baf is aflag=1 ? pc:=target : ((); pc:=target) val bnf is aflag=1 ? pc:=pc+8 sem [ba fba] is [baf baf] sem [bn fbn] is [bnf bnf] sem [bne be] is branch PSR @ [test1 test2] sem [bg ble] is branch PSR @ [test1 test2] sem [bge bl] is branch PSR @ [test1 test2] sem [bgu bleu] is branch PSR @ [test1 test2] sem [bcc bcs] is branch PSR @ [test1 test2] sem [bpos bneg] is branch PSR @ [test1 test2] sem [bvc bvs] is branch PSR @ [test1 test2] sem [fbu fbo] is branch FSR @ [test1 test2] sem [fbg fbule] is branch FSR @ [test1 test2] sem [fbug fble] is branch FSR @ [test1 test2] sem [fbl fbuge] is branch FSR @ [test1 test2] sem [fbul fbge] is branch FSR @ [test1 test2] sem [fblg fbue] is branch FSR @ [test1 test2] sem [fbne fbe] is branch FSR @ [test1 test2] sem call is t:=uadd32 pc (sll32 (unsigned{32}disp30) 2), uR4w[15]:=pc; pc:=t sem jmpl is t:=addr, uR4w[rd]:=pc; pc:=t sem rett is t:=addr, PSR:=(??); pc:=t sem ta is system ((\a:signed{32}.a)src2) sem tn is iflag=1 ? () sem [tne te] is trap @ [test1 test2] sem [tg tle] is trap @ [test1 test2] sem [tge tl] is trap @ [test1 test2] sem [tgu tleu] is trap @ [test1 test2] sem [tcc tcs] is trap @ [test1 test2] sem [tpos tneg] is trap @ [test1 test2] sem [tvc tvs] is trap @ [test1 test2]