%%% -*- 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 ARM instructions to binary form.
%%% Copyright (C) 2005 Mikael Pettersson
%%%
%%% Implementation Notes:
%%% - The Thumb instruction set is a different entity, and is
%%% not and never will be supported by this module.
%%% - Instructions and instruction forms that are unpredictable
%%% or useless in User mode are not supported. They include:
%%% + Data Processing Instructions with S=1 and Rd=15.
%%% + The LDM(2), LDM(3), and STM(2) instructions.
%%% + MRS instructions that access the SPSR.
%%% + MSR instructions that access the SPSR.
%%% + The LDBRT, LDRT, STBRT, and STRT instructions.
%%%
%%% Instruction Operands:
%%%
%%% S ::= {s,0} | {s,1}
%%% L ::= {l,0} | {l,1}
%%% R ::= {r,RNum}
%%% CR ::= {cr,CRNum}
%%%
%%% Cond ::= {cond,CondName}
%%% CondName ::= eq | ne | cs | hs | cc | lo | mi | pl | vs
%%% | vc | hi | ls | ge | lt | gt | ge | al
%%%
%%% Imm<N> ::= {imm<N>,<N bits>} for N in 4, 5, 8, 12, 16, 24, and 25
%%%
%%% Am1ShifterOperand
%%% ::= {Imm8,Imm4}
%%% | Rm
%%% | {Rm,Am1ShiftOp}
%%% Am1ShiftOp ::= {ShiftOp,Imm5}
%%% | {ShiftOp,Rs}
%%% | rrx
%%% ShiftOp ::= lsl | lsr | asr | ror
%%%
%%% Am2LSWUBOperand ::= {immediate_offset,Rn,Sign,Imm12}
%%% | {register_offset,Rn,Sign,Rm} // redundant
%%% | {scaled_register_offset,Rn,Sign,Rm,Am2ShiftOp}
%%% | {immediate_pre_indexed,Rn,Sign,Imm12}
%%% | {register_pre_indexed,Rn,Sign,Rm} // redundant
%%% | {scaled_register_pre_indexed,Rn,Sign,Rm,Am2ShiftOp}
%%% | {immediate_post_indexed,Rn,Sign,Imm12}
%%% | {register_post_indexed,Rn,Sign,Rm} // redundant
%%% | {scaled_register_post_indexed,Rn,Sign,Rm,Am2ShiftOp}
%%% Am2ShiftOp ::= {ShiftOp,Imm5}
%%% | rrx
%%% Sign ::= + | -
%%%
%%% Am3MiscLSOperand::= {immediate_offset,Rn,Sign,Imm8}
%%% | {register_offset,Rn,Sign,Rm}
%%% | {immediate_pre_indexed,Rn,Sign,Imm8}
%%% | {register_pre_indexed,Rn,Sign,Rm}
%%% | {immediate_post_indexed,Rn,Sign,Imm8}
%%% | {register_post_indexed,Rn,Sign,Rm}
%%%
%%% Am4LSMultiple ::= ia | ib | da | db
%%% | fd | ed | fa | ea
%%%
%%% Am5LSCoprocessor::= {offset,Rn,Sign,Imm8}
%%% | {pre_indexed,Rn,Sign,Imm8}
%%% | {post_indexed,Rn,Sign,Imm8}
%%% | {unindexed,Rn,Imm8}
-module(hipe_arm_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)).
%%%
%%% Addressing Modes
%%%
am1_shifter_operand(Rn, Rd, ShifterOperand) ->
case ShifterOperand of
{{imm8,Imm8},{imm4,RotImm4}} ->
?BIT(25,1) bor ?BF(11,8,RotImm4) bor ?BF(7,0,Imm8);
{r,Rm} ->
%% same as Rm LSL #0
?BF(3,0,Rm);
{{r,Rm},ShiftOp} ->
am1_shift_op(Rn, Rd, Rm, ShiftOp) bor ?BF(3,0,Rm)
end.
am1_shift_op(_Rn, _Rd, _Rm, {ShiftOp,{imm5,ShiftImm5}}) ->
case ShiftOp of
'ror' -> ?ASSERT(ShiftImm5 =/= 0); % denotes RRX form
_ -> []
end,
?BF(11,7,ShiftImm5) bor shift_op_bits65(ShiftOp);
am1_shift_op(Rn, Rd, Rm, {ShiftOp,{r,Rs}}) ->
?ASSERT(Rn =/= 15), % UNPREDICTABLE
?ASSERT(Rd =/= 15), % UNPREDICTABLE
?ASSERT(Rm =/= 15), % UNPREDICTABLE
?ASSERT(Rs =/= 15), % UNPREDICTABLE
?BF(11,8,Rs) bor shift_op_bits65(ShiftOp) bor ?BIT(4,1);
am1_shift_op(_Rn, _Rd, _Rm, 'rrx') ->
?BF(6,5,2#11).
shift_op_bits65(ShiftOp) ->
case ShiftOp of
'lsl' -> ?BF(6,5,2#00);
'lsr' -> ?BF(6,5,2#01);
'asr' -> ?BF(6,5,2#10);
'ror' -> ?BF(6,5,2#11)
end.
sign('+') -> ?BIT(23,1);
sign('-') -> 0.
am2_lswub(Rd, AddressingMode) ->
case AddressingMode of
{immediate_offset,{r,Rn},Sign,{imm12,Imm12}} ->
?BIT(24,1) bor sign(Sign) bor ?BF(19,16,Rn) bor ?BF(11,0,Imm12);
{register_offset,{r,Rn},Sign,{r,Rm}} ->
%% same as scaled_register_offset LSL #0
?ASSERT(Rm =/= 15), % UNPREDICTABLE
?BIT(25,1) bor ?BIT(24,1) bor sign(Sign) bor ?BF(19,16,Rn) bor ?BF(3,0,Rm);
{scaled_register_offset,{r,Rn},Sign,{r,Rm},ShiftOp} ->
?ASSERT(Rm =/= 15), % UNPREDICTABLE
?BIT(25,1) bor ?BIT(24,1) bor sign(Sign) bor ?BF(19,16,Rn) bor am2_shift_op(ShiftOp) bor ?BF(3,0,Rm);
{immediate_pre_indexed,{r,Rn},Sign,{imm12,Imm12}} ->
?ASSERT(Rd =/= Rn), % UNPREDICTABLE
?ASSERT(Rn =/= 15), % UNPREDICTABLE
?BIT(24,1) bor sign(Sign) bor ?BIT(21,1) bor ?BF(19,16,Rn) bor ?BF(11,0,Imm12);
{register_pre_indexed,{r,Rn},Sign,{r,Rm}} ->
%% same as scaled_register_pre_indexed LSL #0
?ASSERT(Rd =/= Rn), % UNPREDICTABLE
?ASSERT(Rn =/= 15), % UNPREDICTABLE
?ASSERT(Rm =/= 15), % UNPREDICTABLE
?ASSERT(Rn =/= Rm), % UNPREDICTABLE
?BIT(25,1) bor ?BIT(24,1) bor sign(Sign) bor ?BIT(21,1) bor ?BF(19,16,Rn) bor ?BF(3,0,Rm);
{scaled_register_pre_indexed,{r,Rn},Sign,{r,Rm},ShiftOp} ->
?ASSERT(Rd =/= Rn), % UNPREDICTABLE
?ASSERT(Rn =/= 15), % UNPREDICTABLE
?ASSERT(Rm =/= 15), % UNPREDICTABLE
?ASSERT(Rn =/= Rm), % UNPREDICTABLE
?BIT(25,1) bor ?BIT(24,1) bor sign(Sign) bor ?BIT(21,1) bor ?BF(19,16,Rn) bor am2_shift_op(ShiftOp) bor ?BF(3,0,Rm);
{immediate_post_indexed,{r,Rn},Sign,{imm12,Imm12}} ->
?ASSERT(Rd =/= Rn), % UNPREDICTABLE
?ASSERT(Rn =/= 15), % UNPREDICTABLE
sign(Sign) bor ?BF(19,16,Rn) bor ?BF(11,0,Imm12);
{register_post_indexed,{r,Rn},Sign,{r,Rm}} ->
%% same as scaled_register_post_indexed LSL #0
?ASSERT(Rd =/= Rn), % UNPREDICTABLE
?BIT(25,1) bor sign(Sign) bor ?BF(19,6,Rn) bor ?BF(3,0,Rm);
{scaled_register_post_indexed,{r,Rn},Sign,{r,Rm},ShiftOp} ->
?ASSERT(Rd =/= Rn), % UNPREDICTABLE
?ASSERT(Rn =/= 15), % UNPREDICTABLE
?ASSERT(Rm =/= 15), % UNPREDICTABLE
?ASSERT(Rn =/= Rm), % UNPREDICTABLE
?BIT(25,1) bor sign(Sign) bor ?BF(19,16,Rn) bor am2_shift_op(ShiftOp) bor ?BF(3,0,Rm)
end.
am2_shift_op({ShiftOp,{imm5,ShiftImm5}}) ->
case ShiftOp of
'ror' -> ?ASSERT(ShiftImm5 =/= 0); % denotes RRX form
_ -> []
end,
?BF(11,7,ShiftImm5) bor shift_op_bits65(ShiftOp);
am2_shift_op('rrx') ->
?BF(6,5,2#11).
am3_miscls(Rd, AddressingMode) ->
case AddressingMode of
{immediate_offset,{r,Rn},Sign,{imm8,Imm8}} ->
?BIT(24,1) bor sign(Sign) bor ?BF(22,21,2#10) bor ?BF(19,16,Rn) bor ?BF(11,8,Imm8 bsr 4) bor ?BF(3,0,Imm8 band 2#1111);
{register_offset,{r,Rn},Sign,{r,Rm}} ->
?ASSERT(Rm =/= 15), % UNPREDICTABLE
?BIT(24,1) bor sign(Sign) bor ?BF(22,21,2#00) bor ?BF(19,16,Rn) bor ?BF(3,0,Rm);
{immediate_pre_indexed,{r,Rn},Sign,{imm8,Imm8}} ->
?ASSERT(Rd =/= Rn), % UNPREDICTABLE
?ASSERT(Rn =/= 15), % UNPREDICTABLE
?BIT(24,1) bor sign(Sign) bor ?BF(22,21,2#11) bor ?BF(19,16,Rn) bor ?BF(11,8,Imm8 bsr 4) bor ?BF(3,0,Imm8 band 2#1111);
{register_pre_indexed,{r,Rn},Sign,{r,Rm}} ->
?ASSERT(Rd =/= Rn), % UNPREDICTABLE
?ASSERT(Rm =/= 15), % UNPREDICTABLE
?ASSERT(Rn =/= 15), % UNPREDICTABLE
?ASSERT(Rm =/= Rn), % UNPREDICTABLE
?BIT(24,1) bor sign(Sign) bor ?BF(22,21,2#01) bor ?BF(19,16,Rn) bor ?BF(3,0,Rm);
{immediate_post_indexed,{r,Rn},Sign,{imm8,Imm8}} ->
?ASSERT(Rd =/= Rn), % UNPREDICTABLE
?ASSERT(Rn =/= 15), % UNPREDICTABLE
?BIT(24,0) bor sign(Sign) bor ?BF(22,21,2#10) bor ?BF(19,16,Rn) bor ?BF(11,8,Imm8 bsr 4) bor ?BF(3,0,Imm8 band 2#1111);
{register_post_indexed,{r,Rn},Sign,{r,Rm}} ->
?ASSERT(Rd =/= Rn), % UNPREDICTABLE
?ASSERT(Rm =/= 15), % UNPREDICTABLE
?ASSERT(Rn =/= 15), % UNPREDICTABLE
?ASSERT(Rm =/= Rn), % UNPREDICTABLE
?BIT(24,0) bor sign(Sign) bor ?BF(22,21,2#00) bor ?BF(19,16,Rn) bor ?BF(3,0,Rm)
end.
am4_ls_multiple(L, AddressingMode) ->
case AddressingMode of
'ia' -> ?BF(24,23,2#01);
'ib' -> ?BF(24,23,2#11);
'da' -> ?BF(24,23,2#00);
'db' -> ?BF(24,23,2#10);
_ ->
%% context-sensitive alias crap
case {L,AddressingMode} of
{1,'fa'} -> ?BF(24,23,2#00);
{1,'fd'} -> ?BF(24,23,2#01);
{1,'ea'} -> ?BF(24,23,2#10);
{1,'ed'} -> ?BF(24,23,2#11);
{0,'ed'} -> ?BF(24,23,2#00);
{0,'ea'} -> ?BF(24,23,2#01);
{0,'fd'} -> ?BF(24,23,2#10);
{0,'fa'} -> ?BF(24,23,2#11)
end
end.
am5_ls_coprocessor(AddressingMode) ->
case AddressingMode of
{offset,{r,Rn},Sign,{imm8,Imm8}} ->
?BIT(24,1) bor sign(Sign) bor ?BF(19,16,Rn) bor ?BF(7,0,Imm8);
{pre_indexed,{r,Rn},Sign,{imm8,Imm8}} ->
?ASSERT(Rn =/= 15), % UNPREDICTABLE
?BIT(24,1) bor sign(Sign) bor ?BIT(21,1) bor ?BF(19,16,Rn) bor ?BF(7,0,Imm8);
{post_indexed,{r,Rn},Sign,{imm8,Imm8}} ->
?ASSERT(Rn =/= 15), % UNPREDICTABLE
sign(Sign) bor ?BIT(21,1) bor ?BF(19,16,Rn) bor ?BF(7,0,Imm8);
{unindexed,{r,Rn},{imm8,Imm8}} ->
?BIT(23,1) bor ?BF(19,16,Rn) bor ?BF(7,0,Imm8)
end.
%%%
'cond'(Cond) ->
case Cond of
'eq' -> ?BF(31,28,2#0000); % equal
'ne' -> ?BF(31,28,2#0001); % not equal
'cs' -> ?BF(31,28,2#0010); % carry set
'hs' -> ?BF(31,28,2#0010); % unsigned higher or same
'cc' -> ?BF(31,28,2#0011); % carry clear
'lo' -> ?BF(31,28,2#0011); % unsigned lower
'mi' -> ?BF(31,28,2#0100); % minus/negative
'pl' -> ?BF(31,28,2#0101); % plus/positive or zero
'vs' -> ?BF(31,28,2#0110); % overflow
'vc' -> ?BF(31,28,2#0111); % no overflow
'hi' -> ?BF(31,28,2#1000); % unsigned higher
'ls' -> ?BF(31,28,2#1001); % unsigned lower or same
'ge' -> ?BF(31,28,2#1010); % signed greater than or equal
'lt' -> ?BF(31,28,2#1011); % signed less than
'gt' -> ?BF(31,28,2#1100); % signed greater than
'le' -> ?BF(31,28,2#1101); % signed less than or equal
'al' -> ?BF(31,28,2#1110) % always
end.
%%%
%%% ARM Instructions
%%%
data_processing_form(Cond, OpCode, S, Rn, Rd, ShifterOperand) ->
case S of
1 -> ?ASSERT(Rd =/= 15); % UNPREDICTABLE in User or System mode
_ -> []
end,
'cond'(Cond) bor ?BF(24,21,OpCode) bor ?BIT(20,S) bor ?BF(19,16,Rn) bor ?BF(15,12,Rd) bor am1_shifter_operand(Rn,Rd,ShifterOperand).
data_processing_form(OpCode, {{'cond',Cond},{s,S},{r,Rd},{r,Rn},ShifterOperand}) ->
data_processing_form(Cond, OpCode, S, Rn, Rd, ShifterOperand).
adc(Opnds) -> data_processing_form(2#0101, Opnds).
add(Opnds) -> data_processing_form(2#0100, Opnds).
'and'(Opnds) -> data_processing_form(2#0000, Opnds).
bic(Opnds) -> data_processing_form(2#1110, Opnds).
eor(Opnds) -> data_processing_form(2#0001, Opnds).
orr(Opnds) -> data_processing_form(2#1100, Opnds).
rsb(Opnds) -> data_processing_form(2#0011, Opnds).
rsc(Opnds) -> data_processing_form(2#0111, Opnds).
sbc(Opnds) -> data_processing_form(2#0110, Opnds).
sub(Opnds) -> data_processing_form(2#0010, Opnds).
cmp_form(OpCode, {{'cond',Cond},{r,Rn},ShifterOperand}) ->
data_processing_form(Cond, OpCode, 1, Rn, 0, ShifterOperand).
cmn(Opnds) -> cmp_form(2#1011, Opnds).
cmp(Opnds) -> cmp_form(2#1010, Opnds).
teq(Opnds) -> cmp_form(2#1001, Opnds).
tst(Opnds) -> cmp_form(2#1000, Opnds).
mov_form(OpCode, {{'cond',Cond},{s,S},{r,Rd},ShifterOperand}) ->
data_processing_form(Cond, OpCode, S, 0, Rd, ShifterOperand).
mov(Opnds) -> mov_form(2#1101, Opnds).
mvn(Opnds) -> mov_form(2#1111, Opnds).
%%%
b_form(L, {{'cond',Cond},{imm24,Imm24}}) ->
'cond'(Cond) bor ?BF(27,25,2#101) bor ?BIT(24,L) bor ?BF(23,0,Imm24).
b(Opnds) -> b_form(0, Opnds).
bl(Opnds) -> b_form(1, Opnds).
bkpt({{imm16,Imm16}}) ->
?BF(31,28,2#1110) bor ?BF(27,20,2#00010010) bor ?BF(19,8,Imm16 bsr 4) bor ?BF(7,4,2#0111) bor ?BF(3,0,Imm16 band 2#1111).
bx_form(SubOpcode, {{'cond',Cond},{r,Rm}}, IsBlx) ->
case IsBlx of
true -> ?ASSERT(Rm =/= 15); % UNPREDICTABLE
_ -> []
end,
'cond'(Cond) bor ?BF(27,20,2#00010010) bor ?BF(19,16,2#1111) bor ?BF(15,12,2#1111) bor ?BF(11,8,2#1111) bor ?BF(7,4,SubOpcode) bor ?BF(3,0,Rm).
blx(Opnds) ->
case Opnds of
{{imm25,Imm25}} -> % u16-offset!
?BF(31,28,2#1111) bor ?BF(27,25,2#101) bor ?BIT(24,Imm25 band 1) bor ?BF(23,0,Imm25 bsr 1);
_ ->
bx_form(2#0011, Opnds, true)
end.
bx(Opnds) -> bx_form(2#0001, Opnds, false).
cdp_form(Cond, CpOp4, CRn, CRd, CpNum, CpOp3, CRm) ->
Cond bor ?BF(27,24,2#1110) bor ?BF(23,20,CpOp4) bor ?BF(19,16,CRn) bor ?BF(15,12,CRd) bor ?BF(11,8,CpNum) bor ?BF(7,5,CpOp3) bor ?BF(3,0,CRm).
cdp({{'cond',Cond},{cpnum,CpNum},{cpop4,CpOp4},{cr,CRd},{cr,CRn},{cr,CRm},{cpop3,CpOp3}}) ->
cdp_form('cond'(Cond), CpOp4, CRn, CRd, CpNum, CpOp3, CRm).
cdp2({{cpnum,CpNum},{cpop4,CpOp4},{cr,CRd},{cr,CRn},{cr,CRm},{cpop3,CpOp3}}) ->
cdp_form(?BF(31,28,2#1111), CpOp4, CRn, CRd, CpNum, CpOp3, CRm).
clz({{'cond',Cond},{r,Rd},{r,Rm}}) ->
?ASSERT(Rd =/= 15), % UNPREDICTABLE
?ASSERT(Rm =/= 15), % UNPREDICTABLE
'cond'(Cond) bor ?BF(27,20,2#00010110) bor ?BF(19,16,2#1111) bor ?BF(15,12,Rd) bor ?BF(11,8,2#1111) bor ?BF(7,4,2#0001) bor ?BF(3,0,Rm).
ldstc_form(Cond, L, B20, CRd, CpNum, AddressingMode) ->
Cond bor ?BF(27,25,2#110) bor ?BIT(22,L) bor ?BIT(20,B20) bor ?BF(15,12,CRd) bor ?BF(11,8,CpNum) bor am5_ls_coprocessor(AddressingMode).
ldstc(B20, {{'cond',Cond},{l,L},{cpnum,CpNum},{cr,CRd},AddressingMode}) ->
ldstc_form('cond'(Cond), L, B20, CRd, CpNum, AddressingMode).
ldc(Opnds) -> ldstc(1, Opnds).
stc(Opnds) -> ldstc(0, Opnds).
ldstc2(B20, {{l,L},{cpnum,CpNum},{cr,CRd},AddressingMode}) ->
ldstc_form(?BF(31,28,2#1111), L, B20, CRd, CpNum, AddressingMode).
ldc2(Opnds) -> ldstc2(1, Opnds).
stc2(Opnds) -> ldstc2(0, Opnds).
ldstm_form(Cond, AddressingMode, W, L, Rn, Registers) ->
RegisterList = register_list(Registers),
?ASSERT(RegisterList =/= 0), % UNPREDICTABLE
?ASSERT(Rn =/= 15), % UNPREDICTABLE
case W of
1 ->
BitRn = 1 bsl Rn,
case L of
1 ->
%% LDM! Rn in Registers is UNPREDICTABLE
?ASSERT((RegisterList band BitRn) =:= 0);
0 ->
%% STM! Rn in Registers and not lowest is UNPREDICTABLE
case RegisterList band BitRn of
0 -> [];
_ ->
?ASSERT((RegisterList band (-RegisterList)) =:= BitRn)
end
end;
_ -> []
end,
'cond'(Cond) bor ?BF(27,25,2#100) bor am4_ls_multiple(L, AddressingMode) bor ?BIT(21,W) bor ?BIT(20,L) bor ?BF(19,16,Rn) bor ?BF(15,0,RegisterList).
register_list(Registers) -> register_list(Registers, 0).
register_list([{r,R}|Rs], Mask) -> register_list(Rs, Mask bor (1 bsl R));
register_list([], Mask) -> Mask.
ldstm(L, Opnds) ->
case Opnds of
{{'cond',Cond},AddressingMode,{r,Rn},'!',Registers} ->
ldstm_form(Cond, AddressingMode, 1, L, Rn, Registers);
{{'cond',Cond},AddressingMode,{r,Rn},Registers} ->
ldstm_form(Cond, AddressingMode, 0, L, Rn, Registers)
%% the ldm(2), ldm(3), and stm(2) forms are UNPREDICTABLE
%% in User or System mode
end.
ldm(Opnds) -> ldstm(1, Opnds).
stm(Opnds) -> ldstm(0, Opnds).
ldstr_form2(B, L, {{'cond',Cond},{r,Rd},AddressingMode}) ->
'cond'(Cond) bor ?BF(27,26,2#01) bor am2_lswub(Rd, AddressingMode) bor ?BIT(22,B) bor ?BIT(20,L) bor ?BF(15,12,Rd).
ldr(Opnds) -> ldstr_form2(0, 1, Opnds).
ldrb(Opnds) -> ldstr_form2(1, 1, Opnds).
str(Opnds) -> ldstr_form2(0, 0, Opnds).
strb(Opnds) -> ldstr_form2(1, 0, Opnds).
ldstr_form3(L, SubOpcode, {{'cond',Cond},{r,Rd},AddressingMode}) ->
?ASSERT(Rd =/= 15), % UNPREDICTABLE
'cond'(Cond) bor am3_miscls(Rd, AddressingMode) bor ?BIT(20,L) bor ?BF(15,12,Rd) bor ?BF(7,4,SubOpcode).
ldrh(Opnds) -> ldstr_form3(1, 2#1011, Opnds).
ldrsb(Opnds) -> ldstr_form3(1, 2#1101, Opnds).
ldrsh(Opnds) -> ldstr_form3(1, 2#1111, Opnds).
strh(Opnds) -> ldstr_form3(0, 2#1011, Opnds).
mcr_form(Cond, OP1, CRn, Rd, CpNum, OP2, CRm) ->
?ASSERT(Rd =/= 15), % UNPREDICTABLE
Cond bor ?BF(27,24,2#1110) bor ?BF(23,21,OP1) bor ?BF(19,16,CRn) bor ?BF(15,12,Rd) bor ?BF(11,8,CpNum) bor ?BF(7,5,OP2) bor ?BIT(4,1) bor ?BF(3,0,CRm).
mcr({{'cond',Cond},{cpnum,CpNum},{cpop3,OP1},{r,Rd},{cr,CRn},{cr,CRm},{cpop3,OP2}}) ->
mcr_form('cond'(Cond), OP1, CRn, Rd, CpNum, OP2, CRm).
mcr2({{cpnum,CpNum},{cpop3,OP1},{r,Rd},{cr,CRn},{cr,CRm},{cpop3,OP2}}) ->
mcr_form(?BF(31,28,2#1111), OP1, CRn, Rd, CpNum, OP2, CRm).
mla({{'cond',Cond},{s,S},{r,Rd},{r,Rm},{r,Rs},{r,Rn}}) ->
?ASSERT(Rd =/= 15), % UNPREDICTABLE
?ASSERT(Rm =/= 15), % UNPREDICTABLE
?ASSERT(Rs =/= 15), % UNPREDICTABLE
?ASSERT(Rn =/= 15), % UNPREDICTABLE
?ASSERT(Rd =/= Rm), % UNPREDICTABLE
'cond'(Cond) bor ?BIT(21,1) bor ?BIT(20,S) bor ?BF(19,16,Rd) bor ?BF(15,12,Rn) bor ?BF(11,8,Rs) bor ?BF(7,4,2#1001) bor ?BF(3,0,Rm).
mrc_form(Cond, OP1, CRn, Rd, CpNum, OP2, CRm) ->
Cond bor ?BF(27,24,2#1110) bor ?BF(23,21,OP1) bor ?BIT(20,1) bor ?BF(19,16,CRn) bor ?BF(15,12,Rd) bor ?BF(11,8,CpNum) bor ?BF(7,5,OP2) bor ?BIT(4,1) bor ?BF(3,0,CRm).
mrc({{'cond',Cond},{cpnum,CpNum},{cpop3,OP1},{r,Rd},{cr,CRn},{cr,CRm},{cpop3,OP2}}) ->
mrc_form('cond'(Cond), OP1, CRn, Rd, CpNum, OP2, CRm).
mrc2({{cpnum,CpNum},{cpop3,OP1},{r,Rd},{cr,CRn},{cr,CRm},{cpop3,OP2}}) ->
mrc_form(?BF(31,28,2#1111), OP1, CRn, Rd, CpNum, OP2, CRm).
mrs({{'cond',Cond},{r,Rd},'cpsr'}) ->
%% the SPSR form is UNPREDICTABLE in User or System mode
?ASSERT(Rd =/= 15), % UNPREDICTABLE
'cond'(Cond) bor ?BIT(24,1) bor ?BF(19,16,2#1111) bor ?BF(15,12,Rd).
msr_form(Cond, FieldMask4, Operand) ->
'cond'(Cond) bor ?BIT(24,1) bor ?BIT(21,1) bor ?BF(19,16,FieldMask4) bor ?BF(15,12,2#1111) bor Operand.
msr(Opnds) ->
%% the SPSR form is UNPREDICTABLE in User or System mode
case Opnds of
{{'cond',Cond},'cpsr',{field_mask,FieldMask4},{imm8,Imm8},{imm4,RotImm4}} ->
msr_form(Cond, FieldMask4, ?BIT(25,1) bor ?BF(11,8,RotImm4) bor ?BF(7,0,Imm8));
{{'cond',Cond},'cpsr',{field_mask,FieldMask4},{r,Rm}} ->
msr_form(Cond, FieldMask4, ?BF(3,0,Rm))
end.
mul({{'cond',Cond},{s,S},{r,Rd},{r,Rm},{r,Rs}}) ->
?ASSERT(Rd =/= 15), % UNPREDICTABLE
?ASSERT(Rm =/= 15), % UNPREDICTABLE
?ASSERT(Rs =/= 15), % UNPREDICTABLE
?ASSERT(Rd =/= Rm), % UNPREDICTABLE
'cond'(Cond) bor ?BIT(20,S) bor ?BF(19,16,Rd) bor ?BF(11,8,Rs) bor ?BF(7,4,2#1001) bor ?BF(3,0,Rm).
ml_form2(OpCode, Cond, S, RdLo, RdHi, Rm, Rs) ->
?ASSERT(RdHi =/= 15), % UNPREDICTABLE
?ASSERT(RdLo =/= 15), % UNPREDICTABLE
?ASSERT(Rm =/= 15), % UNPREDICTABLE
?ASSERT(Rs =/= 15), % UNPREDICTABLE
?ASSERT(RdHi =/= RdLo),% UNPREDICTABLE
?ASSERT(RdHi =/= Rm), % UNPREDICTABLE
?ASSERT(RdLo =/= Rm), % UNPREDICTABLE
'cond'(Cond) bor ?BF(27,21,OpCode) bor ?BIT(20,S) bor ?BF(19,16,RdHi) bor ?BF(15,12,RdLo) bor ?BF(11,8,Rs) bor ?BF(7,4,2#1001) bor ?BF(3,0,Rm).
ml_form(OpCode, {{'cond',Cond},{s,S},{r,RdLo},{r,RdHi},{r,Rm},{r,Rs}}) ->
ml_form2(OpCode, Cond, S, RdLo, RdHi, Rm, Rs).
%%smlal(Opnds) -> ml_form(2#0000111, Opnds).
smull(Opnds) -> ml_form(2#0000110, Opnds).
umlal(Opnds) -> ml_form(2#0000101, Opnds).
umull(Opnds) -> ml_form(2#0000100, Opnds).
swi({{'cond',Cond},{imm24,Imm24}}) ->
'cond'(Cond) bor ?BF(27,24,2#1111) bor ?BF(23,0,Imm24).
swp_form(B22, {{'cond',Cond},{r,Rd},{r,Rm},{r,Rn}}) ->
?ASSERT(Rd =/= 15), % UNPREDICTABLE
?ASSERT(Rm =/= 15), % UNPREDICTABLE
?ASSERT(Rn =/= 15), % UNPREDICTABLE
?ASSERT(Rn =/= Rm), % UNPREDICTABLE
?ASSERT(Rn =/= Rd), % UNPREDICTABLE
'cond'(Cond) bor ?BIT(24,1) bor ?BIT(22,B22) bor ?BF(19,16,Rn) bor ?BF(15,12,Rd) bor ?BF(7,4,2#1001) bor ?BF(3,0,Rm).
swp(Opnds) -> swp_form(0, Opnds).
swpb(Opnds) -> swp_form(1, Opnds).
%%%
%%% Enhanced DSP Extension Instructions
%%%
ldstrd_form(OpCode, {{'cond',Cond},{r,Rd},AddressingMode}) ->
?ASSERT(Rd =/= 14), % UNPREDICTABLE
?ASSERT((Rd band 1) =:= 0), % UNDEFINED
%% XXX: unpredictable if write-back and base reg Rn equals Rd or Rd+1
%% XXX: if is load then unpredictable if index reg Rm and Rm equals Rd or Rd+1
'cond'(Cond) bor am3_miscls(Rd, AddressingMode) bor ?BF(15,12,Rd) bor ?BF(7,4,OpCode).
ldrd(Opnds) -> ldstrd_form(2#1101, Opnds).
strd(Opnds) -> ldstrd_form(2#1111, Opnds).
mcrr({{'cond',Cond},{cpnum,CpNum},{cpop4,OP},{r,Rd},{r,Rn},{cr,CRm}}) ->
?ASSERT(Rd =/= 15), % UNPREDICTABLE
?ASSERT(Rn =/= 15), % UNPREDICTABLE
'cond'(Cond) bor ?BF(27,20,2#11000100) bor ?BF(19,16,Rn) bor ?BF(15,12,Rd) bor ?BF(11,8,CpNum) bor ?BF(7,4,OP) bor ?BF(3,0,CRm).
mrrc({{'cond',Cond},{cpnum,CpNum},{cpop4,OP},{r,Rd},{r,Rn},{cr,CRm}}) ->
?ASSERT(Rd =/= 15), % UNPREDICTABLE
?ASSERT(Rn =/= 15), % UNPREDICTABLE
?ASSERT(Rd =/= Rn), % UNPREDICTABLE
'cond'(Cond) bor ?BF(27,20,2#11000101) bor ?BF(19,16,Rn) bor ?BF(15,12,Rd) bor ?BF(11,8,CpNum) bor ?BF(7,4,OP) bor ?BF(3,0,CRm).
pld({AddressingMode}) ->
AM = am2_lswub(42, AddressingMode), % 42 is a dummy reg nr
%% not all adressing modes are allowed: bit 24 must be 1
%% and bit 21 must be 0
?ASSERT(((AM bsr 21) band 2#1001) =:= 2#1000),
16#F550F000 bor AM.
q_form(OpCode, {{'cond',Cond},{r,Rd},{r,Rm},{r,Rn}}) ->
?ASSERT(Rd =/= 15), % UNPREDICTABLE
?ASSERT(Rm =/= 15), % UNPREDICTABLE
?ASSERT(Rn =/= 15), % UNPREDICTABLE
'cond'(Cond) bor ?BF(27,20,OpCode) bor ?BF(19,16,Rn) bor ?BF(15,11,Rd) bor ?BF(7,4,2#0101) bor ?BF(3,0,Rm).
qadd(Opnds) -> q_form(2#00010000, Opnds).
qdadd(Opnds) -> q_form(2#00010100, Opnds).
qdsub(Opnds) -> q_form(2#00010110, Opnds).
qsub(Opnds) -> q_form(2#00010010, Opnds).
smlaxy_form(Cond, OpCode, Rd, Rn, Rs, Y, X, Rm) ->
?ASSERT(Rd =/= 15), % UNPREDICTABLE
?ASSERT(Rm =/= 15), % UNPREDICTABLE
?ASSERT(Rs =/= 15), % UNPREDICTABLE
?ASSERT(Rn =/= 15), % UNPREDICTABLE
'cond'(Cond) bor ?BF(27,20,OpCode) bor ?BF(19,16,Rd) bor ?BF(15,12,Rn) bor ?BF(11,8,Rs) bor ?BIT(7,1) bor ?BIT(6,Y) bor ?BIT(5,X) bor ?BF(3,0,Rm).
smla({{bt,X},{bt,Y},{'cond',Cond},{r,Rd},{r,Rm},{r,Rs},{r,Rn}}) ->
smlaxy_form(Cond, 2#00010000, Rd, Rn, Rs, Y, X, Rm).
smlal(Opnds) -> % may be regular ARM or DSP insn :-(
case Opnds of
{{'cond',Cond},{s,S},{r,RdLo},{r,RdHi},{r,Rm},{r,Rs}} ->
ml_form2(2#0000111, Cond, S, RdLo, RdHi, Rm, Rs);
{{bt,X},{bt,Y},{'cond',Cond},{r,RdLo},{r,RdHi},{r,Rm},{r,Rs}} ->
?ASSERT(RdLo =/= RdHi), % UNPREDICTABLE
smlaxy_form(Cond, 2#00010100, RdHi, RdLo, Rs, Y, X, Rm)
end.
smlaw({{bt,Y},{'cond',Cond},{r,Rd},{r,Rm},{r,Rs},{r,Rn}}) ->
smlaxy_form(Cond, 2#00010010, Rd, Rn, Rs, Y, 0, Rm).
smul({{bt,X},{bt,Y},{'cond',Cond},{r,Rd},{r,Rm},{r,Rs}}) ->
smlaxy_form(Cond, 2#00010110, Rd, 0, Rs, Y, X, Rm).
smulw({{bt,Y},{'cond',Cond},{r,Rd},{r,Rm},{r,Rs}}) ->
smlaxy_form(Cond, 2#00010010, Rd, 0, Rs, Y, 1, Rm).
%%%
%%% Main Encode Dispatch
%%%
insn_encode(Op, Opnds) ->
case Op of
'adc' -> adc(Opnds);
'add' -> add(Opnds);
'and' -> 'and'(Opnds);
'b' -> b(Opnds);
'bic' -> bic(Opnds);
'bkpt' -> bkpt(Opnds);
'bl' -> bl(Opnds);
'blx' -> blx(Opnds);
'bx' -> bx(Opnds);
'cdp' -> cdp(Opnds);
'cdp2' -> cdp2(Opnds);
'clz' -> clz(Opnds);
'cmn' -> cmn(Opnds);
'cmp' -> cmp(Opnds);
'eor' -> eor(Opnds);
'ldc' -> ldc(Opnds);
'ldc2' -> ldc2(Opnds);
'ldm' -> ldm(Opnds);
'ldr' -> ldr(Opnds);
'ldrb' -> ldrb(Opnds);
'ldrd' -> ldrd(Opnds);
%% ldrbt: omitted
'ldrh' -> ldrh(Opnds);
'ldrsb' -> ldrsb(Opnds);
'ldrsh' -> ldrsh(Opnds);
%% ldrt: omitted
'mcr' -> mcr(Opnds);
'mcr2' -> mcr2(Opnds);
'mcrr' -> mcrr(Opnds);
'mla' -> mla(Opnds);
'mov' -> mov(Opnds);
'mrc' -> mrc(Opnds);
'mrc2' -> mrc2(Opnds);
'mrrc' -> mrrc(Opnds);
'mrs' -> mrs(Opnds);
'msr' -> msr(Opnds);
'mul' -> mul(Opnds);
'mvn' -> mvn(Opnds);
'orr' -> orr(Opnds);
'pld' -> pld(Opnds);
'qadd' -> qadd(Opnds);
'qdadd' -> qdadd(Opnds);
'qdsub' -> qdsub(Opnds);
'qsub' -> qsub(Opnds);
'rsb' -> rsb(Opnds);
'rsc' -> rsc(Opnds);
'sbc' -> sbc(Opnds);
'smla' -> smla(Opnds);
'smlal' -> smlal(Opnds); % may be regular ARM or DSP insn :-(
'smlaw' -> smlaw(Opnds);
'smull' -> smull(Opnds);
'smul' -> smul(Opnds);
'smulw' -> smulw(Opnds);
'stc' -> stc(Opnds);
'stc2' -> stc2(Opnds);
'stm' -> stm(Opnds);
'str' -> str(Opnds);
'strb' -> strb(Opnds);
%% strbt: omitted
'strd' -> strd(Opnds);
'strh' -> strh(Opnds);
%% strt: omitted
'sub' -> sub(Opnds);
'swi' -> swi(Opnds);
'swp' -> swp(Opnds);
'swpb' -> swpb(Opnds);
'teq' -> teq(Opnds);
'tst' -> tst(Opnds);
'umlal' -> umlal(Opnds);
'umull' -> umull(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"),
%%
Rn = {r,9},
Rd = {r,8}, % must be even and less than 14 for some insns
Rm = {r,7},
Rs = {r,6},
RdLo = Rn,
RdHi = Rd,
Registers = [Rm,Rs,Rd], % must exclude Rn for some insns
CRd = {cr,15},
CRn = {cr,14},
CRm = {cr,13},
BT0 = {bt,0},
BT1 = {bt,1},
CpNum = {cpnum,15},
CpOp3 = {cpop3,16#3},
CpOp4 = {cpop4,16#F},
L0 = {l,0},
L1 = {l,1},
S0 = {s,0},
S1 = {s,1},
FieldMask4 = {field_mask,16#F},
Imm4 = {imm4,16#F},
Imm5 = {imm5,16#1F},
Imm8 = {imm8,16#FF},
Imm12 = {imm12,16#FFF},
Imm16 = {imm16,16#FFFF},
Imm24 = {imm24,16#FFFFF},
Imm25 = {imm25,16#FFFFF1},
%%
AM1_1 = {Imm8,Imm4},
AM1_2 = Rm,
AM1_3_1 = {Rm,{'lsl',Imm5}},
AM1_3_2 = {Rm,{'lsr',Imm5}},
AM1_3_3 = {Rm,{'asr',Imm5}},
AM1_3_4 = {Rm,{'ror',Imm5}},
AM1_3_5 = {Rm,{'lsl',Rs}},
AM1_3_6 = {Rm,{'lsr',Rs}},
AM1_3_7 = {Rm,{'asr',Rs}},
AM1_3_8 = {Rm,{'ror',Rs}},
AM1_3_9 = {Rm,'rrx'},
%%
AM2ShiftOp1 = {'lsl',Imm5},
AM2ShiftOp2 = {'lsr',Imm5},
AM2ShiftOp3 = {'asr',Imm5},
AM2ShiftOp4 = {'ror',Imm5},
AM2ShiftOp5 = 'rrx',
SignP = '+',
SignM = '-',
AM2_1_1 = {immediate_offset,Rn,SignP,Imm12},
AM2_1_2 = {immediate_offset,Rn,SignM,Imm12},
AM2_2_1 = {register_offset,Rn,SignP,Rm},
AM2_2_2 = {register_offset,Rn,SignM,Rm},
AM2_3_1 = {scaled_register_offset,Rn,SignP,Rm,AM2ShiftOp1},
AM2_3_2 = {scaled_register_offset,Rn,SignM,Rm,AM2ShiftOp2},
AM2_3_3 = {scaled_register_offset,Rn,SignP,Rm,AM2ShiftOp3},
AM2_3_4 = {scaled_register_offset,Rn,SignM,Rm,AM2ShiftOp4},
AM2_3_5 = {scaled_register_offset,Rn,SignP,Rm,AM2ShiftOp5},
AM2_4_1 = {immediate_pre_indexed,Rn,SignP,Imm12},
AM2_4_2 = {immediate_pre_indexed,Rn,SignM,Imm12},
AM2_5_1 = {register_pre_indexed,Rn,SignP,Rm},
AM2_5_2 = {register_pre_indexed,Rn,SignM,Rm},
AM2_6_1 = {scaled_register_pre_indexed,Rn,SignP,Rm,AM2ShiftOp1},
AM2_6_2 = {scaled_register_pre_indexed,Rn,SignM,Rm,AM2ShiftOp2},
AM2_6_3 = {scaled_register_pre_indexed,Rn,SignP,Rm,AM2ShiftOp3},
AM2_6_4 = {scaled_register_pre_indexed,Rn,SignM,Rm,AM2ShiftOp4},
AM2_6_5 = {scaled_register_pre_indexed,Rn,SignP,Rm,AM2ShiftOp5},
AM2_7_1 = {immediate_post_indexed,Rn,SignP,Imm12},
AM2_7_2 = {immediate_post_indexed,Rn,SignM,Imm12},
AM2_8_1 = {register_post_indexed,Rn,SignP,Rm},
AM2_8_2 = {register_post_indexed,Rn,SignM,Rm},
AM2_9_1 = {scaled_register_post_indexed,Rn,SignP,Rm,AM2ShiftOp1},
AM2_9_2 = {scaled_register_post_indexed,Rn,SignM,Rm,AM2ShiftOp2},
AM2_9_3 = {scaled_register_post_indexed,Rn,SignP,Rm,AM2ShiftOp3},
AM2_9_4 = {scaled_register_post_indexed,Rn,SignM,Rm,AM2ShiftOp4},
AM2_9_5 = {scaled_register_post_indexed,Rn,SignP,Rm,AM2ShiftOp5},
%%
AM3_1_1 = {immediate_offset,Rn,SignP,Imm8},
AM3_1_2 = {immediate_offset,Rn,SignM,Imm8},
AM3_2_1 = {register_offset,Rn,SignP,Rm},
AM3_2_2 = {register_offset,Rn,SignM,Rm},
AM3_3_1 = {immediate_pre_indexed,Rn,SignP,Imm8},
AM3_3_2 = {immediate_pre_indexed,Rn,SignM,Imm8},
AM3_4_1 = {register_pre_indexed,Rn,SignP,Rm},
AM3_4_2 = {register_pre_indexed,Rn,SignM,Rm},
AM3_5_1 = {immediate_post_indexed,Rn,SignP,Imm8},
AM3_5_2 = {immediate_post_indexed,Rn,SignM,Imm8},
AM3_6_1 = {register_post_indexed,Rn,SignP,Rm},
AM3_6_2 = {register_post_indexed,Rn,SignM,Rm},
%%
AM4_1 = 'ia',
AM4_2 = 'ib',
AM4_3 = 'da',
AM4_4 = 'db',
AM4_5 = 'fa',
AM4_6 = 'fd',
AM4_7 = 'ea',
AM4_8 = 'ed',
%%
AM5_1_1 = {offset,Rn,SignP,Imm8},
AM5_1_2 = {offset,Rn,SignM,Imm8},
AM5_2_1 = {pre_indexed,Rn,SignP,Imm8},
AM5_2_2 = {pre_indexed,Rn,SignM,Imm8},
AM5_3_1 = {post_indexed,Rn,SignP,Imm8},
AM5_3_2 = {post_indexed,Rn,SignM,Imm8},
AM5_4 = {unindexed,Rn,Imm8},
%%
Cond_eq = {'cond','eq'},
Cond_ne = {'cond','ne'},
Cond_cs = {'cond','cs'},
Cond_hs = {'cond','hs'},
Cond_cc = {'cond','cc'},
Cond_lo = {'cond','lo'},
Cond_mi = {'cond','mi'},
Cond_pl = {'cond','pl'},
Cond_vs = {'cond','vs'},
Cond_vc = {'cond','vc'},
Cond_hi = {'cond','hi'},
Cond_ls = {'cond','ls'},
Cond_ge = {'cond','ge'},
Cond_lt = {'cond','lt'},
Cond_gt = {'cond','gt'},
Cond_le = {'cond','le'},
Cond_al = {'cond','al'},
%%
t(OS,'adc',{Cond_al,S0,Rd,Rn,AM1_1}), % test all AM1 operands
t(OS,'adc',{Cond_al,S0,Rd,Rn,AM1_2}),
t(OS,'adc',{Cond_al,S0,Rd,Rn,AM1_3_1}),
t(OS,'adc',{Cond_al,S0,Rd,Rn,AM1_3_2}),
t(OS,'adc',{Cond_al,S0,Rd,Rn,AM1_3_3}),
t(OS,'adc',{Cond_al,S0,Rd,Rn,AM1_3_4}),
t(OS,'adc',{Cond_al,S0,Rd,Rn,AM1_3_5}),
t(OS,'adc',{Cond_al,S0,Rd,Rn,AM1_3_6}),
t(OS,'adc',{Cond_al,S0,Rd,Rn,AM1_3_7}),
t(OS,'adc',{Cond_al,S0,Rd,Rn,AM1_3_8}),
t(OS,'adc',{Cond_al,S0,Rd,Rn,AM1_3_9}),
t(OS,'add',{Cond_al,S0,Rd,Rn,AM1_1}), % test all S operands
t(OS,'add',{Cond_al,S1,Rd,Rn,AM1_1}),
t(OS,'and',{Cond_eq,S0,Rd,Rn,AM1_1}), % test all Cond operands
t(OS,'and',{Cond_ne,S0,Rd,Rn,AM1_1}),
t(OS,'and',{Cond_cs,S0,Rd,Rn,AM1_1}),
t(OS,'and',{Cond_hs,S0,Rd,Rn,AM1_1}),
t(OS,'and',{Cond_cc,S0,Rd,Rn,AM1_1}),
t(OS,'and',{Cond_lo,S0,Rd,Rn,AM1_1}),
t(OS,'and',{Cond_mi,S0,Rd,Rn,AM1_1}),
t(OS,'and',{Cond_pl,S0,Rd,Rn,AM1_1}),
t(OS,'and',{Cond_vs,S0,Rd,Rn,AM1_1}),
t(OS,'and',{Cond_vc,S0,Rd,Rn,AM1_1}),
t(OS,'and',{Cond_hi,S0,Rd,Rn,AM1_1}),
t(OS,'and',{Cond_ls,S0,Rd,Rn,AM1_1}),
t(OS,'and',{Cond_ge,S0,Rd,Rn,AM1_1}),
t(OS,'and',{Cond_lt,S0,Rd,Rn,AM1_1}),
t(OS,'and',{Cond_gt,S0,Rd,Rn,AM1_1}),
t(OS,'and',{Cond_le,S0,Rd,Rn,AM1_1}),
t(OS,'and',{Cond_al,S0,Rd,Rn,AM1_1}),
t(OS,'b',{Cond_al,Imm24}),
t(OS,'bic',{Cond_al,S0,Rd,Rn,AM1_1}),
t(OS,'bkpt',{Imm16}),
t(OS,'bl',{Cond_al,Imm24}),
t(OS,'blx',{Imm25}),
t(OS,'blx',{Cond_al,Rm}),
t(OS,'bx',{Cond_al,Rm}),
t(OS,'cdp',{Cond_al,CpNum,CpOp4,CRd,CRn,CRm,CpOp3}),
t(OS,'cdp2',{CpNum,CpOp4,CRd,CRn,CRm,CpOp3}),
t(OS,'clz',{Cond_al,Rd,Rm}),
t(OS,'cmn',{Cond_al,Rn,AM1_1}),
t(OS,'cmp',{Cond_al,Rn,AM1_1}),
t(OS,'eor',{Cond_al,S0,Rd,Rn,AM1_1}),
t(OS,'ldc',{Cond_al,L0,CpNum,CRd,AM5_1_1}), % test all AM5 operands
t(OS,'ldc',{Cond_al,L1,CpNum,CRd,AM5_1_2}),
t(OS,'ldc',{Cond_al,L0,CpNum,CRd,AM5_2_1}),
t(OS,'ldc',{Cond_al,L1,CpNum,CRd,AM5_2_2}),
t(OS,'ldc',{Cond_al,L0,CpNum,CRd,AM5_3_1}),
t(OS,'ldc',{Cond_al,L1,CpNum,CRd,AM5_3_2}),
t(OS,'ldc',{Cond_al,L0,CpNum,CRd,AM5_4}),
t(OS,'ldc2',{L0,CpNum,CRd,AM5_1_1}),
t(OS,'ldm',{Cond_al,AM4_1,Rn,'!',Registers}),
t(OS,'ldm',{Cond_al,AM4_1,Rn,Registers}), % test all AM4 operands
t(OS,'ldm',{Cond_al,AM4_2,Rn,Registers}), % test all AM4 operands
t(OS,'ldm',{Cond_al,AM4_3,Rn,Registers}), % test all AM4 operands
t(OS,'ldm',{Cond_al,AM4_4,Rn,Registers}), % test all AM4 operands
t(OS,'ldm',{Cond_al,AM4_5,Rn,Registers}), % test all AM4 operands
t(OS,'ldm',{Cond_al,AM4_6,Rn,Registers}), % test all AM4 operands
t(OS,'ldm',{Cond_al,AM4_7,Rn,Registers}), % test all AM4 operands
t(OS,'ldm',{Cond_al,AM4_8,Rn,Registers}), % test all AM4 operands
t(OS,'ldr',{Cond_al,Rd,AM2_1_1}), % test all AM2 operands
t(OS,'ldr',{Cond_al,Rd,AM2_1_2}),
t(OS,'ldr',{Cond_al,Rd,AM2_2_1}),
t(OS,'ldr',{Cond_al,Rd,AM2_2_2}),
t(OS,'ldr',{Cond_al,Rd,AM2_3_1}),
t(OS,'ldr',{Cond_al,Rd,AM2_3_2}),
t(OS,'ldr',{Cond_al,Rd,AM2_3_3}),
t(OS,'ldr',{Cond_al,Rd,AM2_3_4}),
t(OS,'ldr',{Cond_al,Rd,AM2_3_5}),
t(OS,'ldr',{Cond_al,Rd,AM2_4_1}),
t(OS,'ldr',{Cond_al,Rd,AM2_4_2}),
t(OS,'ldr',{Cond_al,Rd,AM2_5_1}),
t(OS,'ldr',{Cond_al,Rd,AM2_5_2}),
t(OS,'ldr',{Cond_al,Rd,AM2_6_1}),
t(OS,'ldr',{Cond_al,Rd,AM2_6_2}),
t(OS,'ldr',{Cond_al,Rd,AM2_6_3}),
t(OS,'ldr',{Cond_al,Rd,AM2_6_4}),
t(OS,'ldr',{Cond_al,Rd,AM2_6_5}),
t(OS,'ldr',{Cond_al,Rd,AM2_7_1}),
t(OS,'ldr',{Cond_al,Rd,AM2_7_2}),
t(OS,'ldr',{Cond_al,Rd,AM2_8_1}),
t(OS,'ldr',{Cond_al,Rd,AM2_8_2}),
t(OS,'ldr',{Cond_al,Rd,AM2_9_1}),
t(OS,'ldr',{Cond_al,Rd,AM2_9_2}),
t(OS,'ldr',{Cond_al,Rd,AM2_9_3}),
t(OS,'ldr',{Cond_al,Rd,AM2_9_4}),
t(OS,'ldr',{Cond_al,Rd,AM2_9_5}),
t(OS,'ldrb',{Cond_al,Rd,AM2_1_1}),
t(OS,'ldrd',{Cond_al,Rd,AM3_1_1}),
t(OS,'ldrh',{Cond_al,Rd,AM3_1_1}), % test all AM3 operands
t(OS,'ldrh',{Cond_al,Rd,AM3_1_2}),
t(OS,'ldrh',{Cond_al,Rd,AM3_2_1}),
t(OS,'ldrh',{Cond_al,Rd,AM3_2_2}),
t(OS,'ldrh',{Cond_al,Rd,AM3_3_1}),
t(OS,'ldrh',{Cond_al,Rd,AM3_3_2}),
t(OS,'ldrh',{Cond_al,Rd,AM3_4_1}),
t(OS,'ldrh',{Cond_al,Rd,AM3_4_2}),
t(OS,'ldrh',{Cond_al,Rd,AM3_5_1}),
t(OS,'ldrh',{Cond_al,Rd,AM3_5_2}),
t(OS,'ldrh',{Cond_al,Rd,AM3_6_1}),
t(OS,'ldrh',{Cond_al,Rd,AM3_6_2}),
t(OS,'ldrsb',{Cond_al,Rd,AM3_1_1}),
t(OS,'ldrsh',{Cond_al,Rd,AM3_1_1}),
t(OS,'mcr',{Cond_al,CpNum,CpOp3,Rd,CRn,CRm,CpOp3}),
t(OS,'mcr2',{CpNum,CpOp3,Rd,CRn,CRm,CpOp3}),
t(OS,'mcrr',{Cond_al,CpNum,CpOp4,Rd,Rn,CRm}),
t(OS,'mla',{Cond_al,S0,Rd,Rm,Rs,Rn}),
t(OS,'mov',{Cond_al,S0,Rd,AM1_1}),
t(OS,'mrc',{Cond_al,CpNum,CpOp3,Rd,CRn,CRm,CpOp3}),
t(OS,'mrc2',{CpNum,CpOp3,Rd,CRn,CRm,CpOp3}),
t(OS,'mrrc',{Cond_al,CpNum,CpOp4,Rd,Rn,CRm}),
t(OS,'mrs',{Cond_al,Rd,'cpsr'}),
t(OS,'msr',{Cond_al,'cpsr',FieldMask4,Imm8,Imm4}),
t(OS,'msr',{Cond_al,'cpsr',FieldMask4,Rm}),
t(OS,'mul',{Cond_al,S0,Rd,Rm,Rs}),
t(OS,'mvn',{Cond_al,S1,Rd,AM1_1}),
t(OS,'orr',{Cond_al,S0,Rd,Rn,AM1_1}),
t(OS,'pld',{AM2_1_1}),
t(OS,'qadd',{Cond_al,Rd,Rm,Rn}),
t(OS,'qdadd',{Cond_al,Rd,Rm,Rn}),
t(OS,'qdsub',{Cond_al,Rd,Rm,Rn}),
t(OS,'qsub',{Cond_al,Rd,Rm,Rn}),
t(OS,'rsb',{Cond_al,S0,Rd,Rn,AM1_1}),
t(OS,'rsc',{Cond_al,S0,Rd,Rn,AM1_1}),
t(OS,'sbc',{Cond_al,S0,Rd,Rn,AM1_1}),
t(OS,'smla',{BT0,BT0,Cond_al,Rd,Rm,Rs,Rn}),
t(OS,'smla',{BT0,BT1,Cond_al,Rd,Rm,Rs,Rn}),
t(OS,'smla',{BT1,BT0,Cond_al,Rd,Rm,Rs,Rn}),
t(OS,'smla',{BT1,BT1,Cond_al,Rd,Rm,Rs,Rn}),
t(OS,'smlal',{Cond_al,S0,RdLo,RdHi,Rm,Rs}),
t(OS,'smlal',{BT0,BT1,Cond_al,RdLo,RdHi,Rm,Rs}),
t(OS,'smlaw',{BT1,Cond_al,Rd,Rm,Rs,Rn}),
t(OS,'smull',{Cond_al,S0,RdLo,RdHi,Rm,Rs}),
t(OS,'smul',{BT1,BT0,Cond_al,Rd,Rm,Rs}),
t(OS,'smulw',{BT1,Cond_al,Rd,Rm,Rs}),
t(OS,'stc',{Cond_al,L0,CpNum,CRd,AM5_1_1}),
t(OS,'stc2',{L0,CpNum,CRd,AM5_1_1}),
t(OS,'stm',{Cond_al,AM4_1,Rn,Registers}),
t(OS,'str',{Cond_al,Rd,AM2_1_1}),
t(OS,'strb',{Cond_al,Rd,AM2_1_1}),
t(OS,'strd',{Cond_al,Rd,AM3_1_1}),
t(OS,'strh',{Cond_al,Rd,AM3_1_1}),
t(OS,'sub',{Cond_al,S0,Rd,Rn,AM1_1}),
t(OS,'swi',{Cond_al,Imm24}),
t(OS,'swp',{Cond_al,Rd,Rm,Rn}),
t(OS,'swpb',{Cond_al,Rd,Rm,Rn}),
t(OS,'teq',{Cond_al,Rn,AM1_1}),
t(OS,'tst',{Cond_al,Rn,AM1_1}),
t(OS,'umlal',{Cond_al,S0,RdLo,RdHi,Rm,Rs}),
t(OS,'umull',{Cond_al,S0,RdLo,RdHi,Rm,Rs}),
[].
dotest() -> dotest1(group_leader()).
dotest(File) ->
{ok,OS} = file:open(File, [write]),
dotest1(OS),
file:close(OS).
-endif.