%%% -*- erlang-indent-level: 2 -*- %%% %%% Licensed under the Apache License, Version 2.0 (the "License"); %%% you may not use this file except in compliance with the License. %%% You may obtain a copy of the License at %%% %%% http://www.apache.org/licenses/LICENSE-2.0 %%% %%% Unless required by applicable law or agreed to in writing, software %%% distributed under the License is distributed on an "AS IS" BASIS, %%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %%% See the License for the specific language governing permissions and %%% limitations under the License. %%% %%% Encode symbolic SPARC instructions to binary form. %%% Copyright (C) 2007-2008 Mikael Pettersson -module(hipe_sparc_encode). -export([insn_encode/2]). %%-define(TESTING,1). -ifdef(TESTING). -export([dotest/0, dotest/1]). -endif. -define(ASSERT(G), if G -> []; true -> exit({assertion_failed,?MODULE,?LINE,??G}) end). bf(LeftBit, RightBit, Value) -> ?ASSERT(32 > LeftBit), ?ASSERT(LeftBit >= RightBit), ?ASSERT(RightBit >= 0), ?ASSERT(Value >= 0), ?ASSERT(Value < (1 bsl ((LeftBit - RightBit) + 1))), Value bsl RightBit. -define(BF(LB,RB,V), bf(LB,RB,V)). -define(BIT(Pos,Val), ?BF(Pos,Pos,Val)). %%-define(BITS(N,Val), ?BF(N,0,Val)). %%% %%% Instruction Formats %%% format1(Disp30) -> ?BIT(30,1) bor ?BF(29,0,Disp30). format2a(Rd, Op2, Imm22) -> ?BF(29,25,Rd) bor ?BF(24,22,Op2) bor ?BF(21,0,Imm22). format2b(A, Cond, Op2, Disp22) -> ?BIT(29,A) bor ?BF(28,25,Cond) bor ?BF(24,22,Op2) bor ?BF(21,0,Disp22). format2c(A, Cond, Op2, CC1, CC0, P, Disp19) -> ?BIT(29,A) bor ?BF(28,25,Cond) bor ?BF(24,22,Op2) bor ?BIT(21,CC1) bor ?BIT(20,CC0) bor ?BIT(19,P) bor ?BF(18,0,Disp19). format2d(A, RCond, Op2, P, Rs1, Disp16) -> D16Hi = Disp16 bsr 14, D16Lo = Disp16 band 16#3FFF, ?BIT(29,A) bor ?BF(27,25,RCond) bor ?BF(24,22,Op2) bor ?BF(21,20,D16Hi) bor ?BIT(19,P) bor ?BF(18,14,Rs1) bor ?BF(13,0,D16Lo). format3common(Op, Rd, Op3, Rs1) -> % format 3, bits 31..14 ?BF(31,30,Op) bor ?BF(29,25,Rd) bor ?BF(24,19,Op3) bor ?BF(18,14,Rs1). format3a(Op, Rd, Op3, Rs1, Rs2) -> format3common(Op, Rd, Op3, Rs1) bor ?BF(4,0,Rs2). format3ax(Op, Rd, Op3, Rs1, Rs2) -> format3a(Op, Rd, Op3, Rs1, Rs2) bor ?BIT(12,1). format3b(Op, Rd, Op3, Rs1, Simm13) -> format3common(Op, Rd, Op3, Rs1) bor ?BIT(13,1) bor ?BF(12,0,Simm13). format3b32(Op, Rd, Op3, Rs1, Shcnt32) -> format3a(Op, Rd, Op3, Rs1, Shcnt32) bor ?BIT(13,1). format3b64(Op, Rd, Op3, Rs1, Shcnt64) -> format3common(Op, Rd, Op3, Rs1) bor ?BIT(13,1) bor ?BF(5,0,Shcnt64). format3ab(Op, {r,Rd}, Op3, {r,Rs1}, Src2) -> case Src2 of {r,Rs2} -> format3a(Op, Rd, Op3, Rs1, Rs2); {simm13,Simm13} -> format3b(Op, Rd, Op3, Rs1, Simm13) end. format3ab({Rs1,Src2,Rd}, Op3, Op) -> format3ab(Op, Rd, Op3, Rs1, Src2). -ifdef(notdef). format3c(Op, Rd, Op3, Rs1, Opf, Rs2) -> format3h(Op, Rd, Op3, Rs1) bor (Opf bsl 5) bor Rs2. format3d(Op, Rd, Op3, Rs1, I, Rs2) -> format3h(Op, Rd, Op3, Rs1) bor (I bsl 13) bor Rs2. -endif. %%% %%% Instruction Operands %%% 'cond'(Cond) -> case Cond of 'n' -> 2#0000; 'e' -> 2#0001; 'le' -> 2#0010; 'l' -> 2#0011; 'leu' -> 2#0100; 'lu' -> 2#0101; % a.k.a. 'cs' 'neg' -> 2#0110; 'vs' -> 2#0111; 'a' -> 2#1000; 'ne' -> 2#1001; 'g' -> 2#1010; 'ge' -> 2#1011; 'gu' -> 2#1100; 'geu' -> 2#1101; % a.k.a. 'cc' 'pos' -> 2#1110; 'vc' -> 2#1111 end. rcond(RCond) -> case RCond of 'z' -> 2#001; 'lez' -> 2#010; 'lz' -> 2#011; 'nz' -> 2#101; 'gz' -> 2#110; 'gez' -> 2#111 end. pred(Pred) -> case Pred of 'pt' -> 1; 'pn' -> 0 end. %%% %%% Branch Instructions %%% call({disp30,Disp30}) -> format1(Disp30). ba({disp22,Disp22}) -> % V7 Bicc, only used for unconditional branches format2b(0, 'cond'('a'), 2#010, Disp22). bp({{'cond',Cond},{pred,Pred},{disp19,Disp19}}) -> %% XXX: sparc64 will need CC1=1 here format2c(0, 'cond'(Cond), 2#001, 0, 0, pred(Pred), Disp19). br({{rcond,RCond},{pred,Pred},{r,Rs1},{disp16,Disp16}}) -> format2d(0, rcond(RCond), 2#011, pred(Pred), Rs1, Disp16). %%% %%% Integer Arithmetic Instructions %%% alu(Opnds, Op3) -> format3ab(Opnds, Op3, 2#10). add(Opnds) -> alu(Opnds, 2#000000). addcc(Opnds) -> alu(Opnds, 2#010000). %%addc(Opnds) -> alu(Opnds, 2#001000). %%addccc(Opnds) -> alu(Opnds, 2#011000). sub(Opnds) -> alu(Opnds, 2#000100). subcc(Opnds) -> alu(Opnds, 2#010100). %%subc(Opnds) -> alu(Opnds, 2#001100). % XXX: hipe_sparc_op has bug here %%subccc(Opnds) -> alu(Opnds, 2#011100). % XXX: hipe_sparc_op has bug here %%taddcc(Opnds) -> alu(Opnds, 2#100000). %%taddcctv(Opnds) -> alu(Opnds, 2#100010). %%tsubcc(Opnds) -> alu(Opnds, 2#100001). %%tsubcctv(Opnds) -> alu(Opnds, 2#100011). mulx(Opnds) -> alu(Opnds, 2#001001). %%sdivx(Opnds) -> alu(Opnds, 2#101101). %%udivx(Opnds) -> alu(Opnds, 2#001101). %%umul(Opnds) -> alu(Opnds, 2#001010). smul(Opnds) -> alu(Opnds, 2#001011). %%umulcc(Opnds) -> alu(Opnds, 2#011010). %%smulcc(Opnds) -> alu(Opnds, 2#011011). 'and'(Opnds) -> alu(Opnds, 2#000001). andcc(Opnds) -> alu(Opnds, 2#010001). %%andn(Opnds) -> alu(Opnds, 2#000101). %%andncc(Opnds) -> alu(Opnds, 2#010101). 'or'(Opnds) -> alu(Opnds, 2#000010). orcc(Opnds) -> alu(Opnds, 2#010010). %%orn(Opnds) -> alu(Opnds, 2#000110). %%orncc(Opnds) -> alu(Opnds, 2#010110). 'xor'(Opnds) -> alu(Opnds, 2#000011). xorcc(Opnds) -> alu(Opnds, 2#010011). %%xnor(Opnds) -> alu(Opnds, 2#000111). %%xnorcc(Opnds) -> alu(Opnds, 2#010111). shift32({{r,Rs1},Src2,{r,Rd}}, Op3) -> case Src2 of {r,Rs2} -> format3a(2#10, Rd, Op3, Rs1, Rs2); {uimm5,Shcnt32} -> format3b32(2#10, Rd, Op3, Rs1, Shcnt32) end. shift64({{r,Rs1},Src2,{r,Rd}}, Op3) -> case Src2 of {r,Rs2} -> format3ax(2#10, Rd, Op3, Rs1, Rs2); {uimm6,Shcnt64} -> format3b64(2#10, Rd, Op3, Rs1, Shcnt64) end. sll(Opnds) -> shift32(Opnds, 2#100101). sllx(Opnds) -> shift64(Opnds, 2#100101). srl(Opnds) -> shift32(Opnds, 2#100110). srlx(Opnds) -> shift64(Opnds, 2#100110). sra(Opnds) -> shift32(Opnds, 2#100111). srax(Opnds) -> shift64(Opnds, 2#100111). jmpl(Opnds) -> alu(Opnds, 2#111000). rd({y,{r,Rd}}) -> format3a(2#10, Rd, 2#101000, 0, 0). sethi({{uimm22,UImm22},{r,Rd}}) -> format2a(Rd, 2#100, UImm22). ld(Opnds, Op3) -> format3ab(Opnds, Op3, 2#11). ldsb(Opnds) -> ld(Opnds, 2#001001). ldsh(Opnds) -> ld(Opnds, 2#001010). ldsw(Opnds) -> ld(Opnds, 2#001000). ldub(Opnds) -> ld(Opnds, 2#000001). lduh(Opnds) -> ld(Opnds, 2#000010). lduw(Opnds) -> ld(Opnds, 2#000000). ldx(Opnds) -> ld(Opnds, 2#001011). %%ldd(Opnds) -> ld(Opnds, 2#000011). st({Rd,Rs1,Src2}, Op3) -> format3ab(2#11, Rd, Op3, Rs1, Src2). stb(Opnds) -> st(Opnds, 2#000101). %%sth(Opnds) -> st(Opnds, 2#000110). stw(Opnds) -> st(Opnds, 2#000100). stx(Opnds) -> st(Opnds, 2#001110). %%std(Opnds) -> st(Opnds, 2#000111). %%% %%% Floating-Point Instructions %%% format3f(Rd, Rs1, Opf, Rs2) -> format3a(2#10, Rd, 2#110100, Rs1, Rs2) bor ?BF(13,5,Opf). fpop1binary(Opf, {{fr,Rs1},{fr,Rs2},{fr,Rd}}) -> format3f(Rd, Rs1, Opf, Rs2). faddd(Opnds) -> fpop1binary(2#001000010, Opnds). fdivd(Opnds) -> fpop1binary(2#001001110, Opnds). fmuld(Opnds) -> fpop1binary(2#001001010, Opnds). fsubd(Opnds) -> fpop1binary(2#001000110, Opnds). fpop1unary(Opf, {{fr,Rs2},{fr,Rd}}) -> format3f(Rd, 0, Opf, Rs2). fitod(Opnds) -> fpop1unary(2#011001000, Opnds). fmovd(Opnds) -> fpop1unary(2#000000010, Opnds). fnegd(Opnds) -> fpop1unary(2#000000110, Opnds). ldf({{r,Rs1},{simm13,Simm13},{fr,Rd}}) -> format3b(2#11, Rd, 2#100000, Rs1, Simm13). stf({{fr,Rd},{r,Rs1},{simm13,Simm13}}) -> format3b(2#11, Rd, 2#100100, Rs1, Simm13). -ifdef(notdef). fpop1(Rs1,Opf,Rs2,Rd) -> format3a(2#10, Rd, 2#110100, Rs1, Opf, Rs2). %% fpop2(Rs1,Opf,Rs2,Rd) -> format3a(2#10, Rd, 2#110101, Rs1, Opf, Rs2). %% fxtos(Rs2, Rd) -> fpop1(0,2#010000100,Rs2,Rd). %% fxtod(Rs2, Rd) -> fpop1(0,2#010001000,Rs2,Rd). %% fxtoq(Rs2, Rd) -> fpop1(0,2#010001100,Rs2,Rd). fitos(Rs2, Rd) -> fpop1(0,2#011000100,Rs2,Rd). fitoq(Rs2, Rd) -> fpop1(0,2#011001100,Rs2,Rd). %% fstox(Rs2, Rd) -> fpop1(0,2#010000001,Rs2,Rd). %% fdtox(Rs2, Rd) -> fpop1(0,2#010000010,Rs2,Rd). %% fqtox(Rs2, Rd) -> fpop1(0,2#010000011,Rs2,Rd). %% fstoi(Rs2, Rd) -> fpop1(0,2#011010001,Rs2,Rd). %% fdtoi(Rs2, Rd) -> fpop1(0,2#011010010,Rs2,Rd). %% fqtoi(Rs2, Rd) -> fpop1(0,2#011010011,Rs2,Rd). %% fstod(Rs2, Rd) -> fpop1(0,2#011001001,Rs2,Rd). %% fstoq(Rs2, Rd) -> fpop1(0,2#011001101,Rs2,Rd). %% fdtos(Rs2, Rd) -> fpop1(0,2#011000110,Rs2,Rd). %% fdtoq(Rs2, Rd) -> fpop1(0,2#011001110,Rs2,Rd). %% fqtos(Rs2, Rd) -> fpop1(0,2#011000111,Rs2,Rd). %% fqtod(Rs2, Rd) -> fpop1(0,2#011001011,Rs2,Rd). fmovs(Rs2, Rd) -> fpop1(0,2#000000001,Rs2,Rd). fnegs(Rs2, Rd) -> fpop1(0,2#000000101,Rs2,Rd). fabss(Rs2, Rd) -> fpop1(0,2#000001001,Rs2,Rd). fabsd(Rs2, Rd) -> fpop1(0,2#000001010,Rs2,Rd). fmovq(Rs2, Rd) -> fpop1(0,2#000000011,Rs2,Rd). fnegq(Rs2, Rd) -> fpop1(0,2#000000111,Rs2,Rd). fabsq(Rs2, Rd) -> fpop1(0,2#000001011,Rs2,Rd). %% fsqrts(Rs2, Rd) -> fpop1(0,2#000101001,Rs2,Rd). %% fsqrtd(Rs2, Rd) -> fpop1(0,2#000101010,Rs2,Rd). %% fsqrtq(Rs2, Rd) -> fpop1(0,2#000101011,Rs2,Rd). fadds(Rs1, Rs2, Rd) -> fpop1(Rs1,2#001000001,Rs2,Rd). faddq(Rs1, Rs2, Rd) -> fpop1(Rs1,2#001000011,Rs2,Rd). fsubs(Rs1, Rs2, Rd) -> fpop1(Rs1,2#001000101,Rs2,Rd). fsubq(Rs1, Rs2, Rd) -> fpop1(Rs1,2#001000111,Rs2,Rd). fmuls(Rs1, Rs2, Rd) -> fpop1(Rs1,2#001001001,Rs2,Rd). fmulq(Rs1, Rs2, Rd) -> fpop1(Rs1,2#001001011,Rs2,Rd). %% fsmuld(Rs1, Rs2, Rd) -> fpop1(Rs1,2#001101001,Rs2,Rd). %% fdmulq(Rs1, Rs2, Rd) -> fpop1(Rs1,2#001101110,Rs2,Rd). fdivs(Rs1, Rs2, Rd) -> fpop1(Rs1,2#001001101,Rs2,Rd). fdivq(Rs1, Rs2, Rd) -> fpop1(Rs1,2#001001111,Rs2,Rd). %% Uses fcc0 %% fcmps(Rs1, Rs2) -> fpop2(Rs1,2#001010001,Rs2,0). %% fcmpd(Rs1, Rs2) -> fpop2(Rs1,2#001010010,Rs2,0). %% fcmpq(Rs1, Rs2) -> fpop2(Rs1,2#001010011,Rs2,0). %% fcmpes(Rs1, Rs2) -> fpop2(Rs1,2#001010101,Rs2,0). %% fcmped(Rs1, Rs2) -> fpop2(Rs1,2#001010110,Rs2,0). %% fcmpeq(Rs1, Rs2) -> fpop2(Rs1,2#001010111,Rs2,0). %% fcmps(N, Rs1, Rs2) -> fpcn(N,2#001010001,Rs1,Rs2). %% fcmpd(N, Rs1, Rs2) -> fpcn(N,2#001010010,Rs1,Rs2). %% fcmpq(N, Rs1, Rs2) -> fpcn(N,2#001010011,Rs1,Rs2). %% fcmpes(N, Rs1, Rs2) -> fpcn(N,2#001010101,Rs1,Rs2). %% fcmped(N, Rs1, Rs2) -> fpcn(N,2#001010110,Rs1,Rs2). %% fcmpeq(N, Rs1, Rs2) -> fpcn(N,2#001010111,Rs1,Rs2). stfi(Rd, Rs1, Offset) -> format3b(2#11, Rd, 2#100100, Rs1, Offset). stdf(Rd, Rs1, Rs2) -> format3a(2#11, Rd, 2#100111, Rs1, 0, Rs2). stdfi(Rd, Rs1, Offset) -> format3b(2#11, Rd, 2#100111, Rs1, Offset). stqf(Rd, Rs1, Rs2) -> format3a(2#11, Rd, 2#100110, Rs1, 0, Rs2). stqfi(Rd, Rs1, Offset) -> format3b(2#11, Rd, 2#100110, Rs1, Offset). %% stfsr(Rd, Rs1, Rs2) -> format3a(2#11, Rd, 2#100101, Rs1, 0, Rs2). %% stfsri(Rd, Rs1, Offset) -> format3b(2#11, Rd, 2#100101, Rs1, Offset). ldfi(Rd, Rs1, Offset) -> format3b(2#11, Rd, 2#100000, Rs1, Offset). lddf(Rd, Rs1, Rs2) -> format3a(2#11, Rd, 2#100011, Rs1, 0, Rs2). lddfi(Rd, Rs1, Offset) -> format3b(2#11, Rd, 2#100011, Rs1, Offset). ldqf(Rd, Rs1, Rs2) -> format3a(2#11, Rd, 2#100010, Rs1, 0, Rs2). ldqfi(Rd, Rs1, Offset) -> format3b(2#11, Rd, 2#100010, Rs1, Offset). %% ldxfsr(Rs1, Rs2) -> format3a(2#11, 1, 2#100001, Rs1, 0, Rs2). %% ldxfsri(Rs1, Offset) -> format3b(2#11, 1, 2#100001, Rs1, Offset). %% fpcn(N, Opf, Rs1, Rs2) -> %% case N of %% 0 -> fpc0(Opf, Rs1, Rs2); %% 1 -> fpc1(Opf, Rs1, Rs2); %% 2 -> fpc2(Opf, Rs1, Rs2); %% 3 -> fpc3(Opf, Rs1, Rs2) %% end. %% fpc0(Opf, Rs1, Rs2) -> format3c(2#10, 2#00000, 2#110101, Rs1, Opf, Rs2). %% fpc1(Opf, Rs1, Rs2) -> format3c(2#10, 2#00001, 2#110101, Rs1, Opf, Rs2). %% fpc2(Opf, Rs1, Rs2) -> format3c(2#10, 2#00010, 2#110101, Rs1, Opf, Rs2). %% fpc3(Opf, Rs1, Rs2) -> format3c(2#10, 2#00011, 2#110101, Rs1, Opf, Rs2). -endif. % FP insns %%% %%% Main Encode Dispatch %%% insn_encode(Op, Opnds) -> case Op of 'add' -> add(Opnds); 'addcc' -> addcc(Opnds); 'and' -> 'and'(Opnds); 'andcc' -> andcc(Opnds); 'ba' -> ba(Opnds); 'bp' -> bp(Opnds); 'br' -> br(Opnds); 'call' -> call(Opnds); 'jmpl' -> jmpl(Opnds); 'ldsb' -> ldsb(Opnds); 'ldsh' -> ldsh(Opnds); 'ldsw' -> ldsw(Opnds); 'ldub' -> ldub(Opnds); 'lduh' -> lduh(Opnds); 'lduw' -> lduw(Opnds); 'ldx' -> ldx(Opnds); 'mulx' -> mulx(Opnds); 'or' -> 'or'(Opnds); 'orcc' -> orcc(Opnds); 'rd' -> rd(Opnds); 'sethi' -> sethi(Opnds); 'sll' -> sll(Opnds); 'sllx' -> sllx(Opnds); 'smul' -> smul(Opnds); 'sra' -> sra(Opnds); 'srax' -> srax(Opnds); 'srl' -> srl(Opnds); 'srlx' -> srlx(Opnds); 'stb' -> stb(Opnds); 'stw' -> stw(Opnds); 'stx' -> stx(Opnds); 'sub' -> sub(Opnds); 'subcc' -> subcc(Opnds); 'xor' -> 'xor'(Opnds); 'xorcc' -> xorcc(Opnds); 'faddd' -> faddd(Opnds); 'fdivd' -> fdivd(Opnds); 'fmuld' -> fmuld(Opnds); 'fsubd' -> fsubd(Opnds); 'fitod' -> fitod(Opnds); 'fmovd' -> fmovd(Opnds); 'fnegd' -> fnegd(Opnds); 'ldf' -> ldf(Opnds); 'stf' -> stf(Opnds); _ -> exit({?MODULE,insn_encode,Op}) end. %%% %%% Testing Interface %%% -ifdef(TESTING). say(OS, Str) -> file:write(OS, Str). hex_digit(Dig0) -> Dig = Dig0 band 16#F, if Dig >= 16#A -> $A + (Dig - 16#A); true -> $0 + Dig end. say_byte(OS, Byte) -> say(OS, [hex_digit(Byte bsr 4)]), say(OS, [hex_digit(Byte)]). say_word(OS, Word) -> say(OS, "0x"), say_byte(OS, Word bsr 24), say_byte(OS, Word bsr 16), say_byte(OS, Word bsr 8), say_byte(OS, Word). t(OS, Op, Opnds) -> Word = insn_encode(Op, Opnds), say(OS, "\t.long "), say_word(OS, Word), say(OS, "\n"). dotest1(OS) -> say(OS, "\t.text\n\t.align 4\n"), []. dotest() -> dotest1(group_leader()). dotest(File) -> {ok,OS} = file:open(File, [write]), dotest1(OS), file:close(OS). -endif.