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]