ghidra/Ghidra/Processors/Dalvik/data/languages/Dalvik.slaspec

2393 lines
82 KiB
Plaintext

#------------------------------------------------------------------------------------
# Sleigh specification file for DALVIK VM
#------------------------------------------------------------------------------------
define endian=little;
define alignment=1;
@define CPOOL_METHOD "0:4"
@define CPOOL_FIELD "1:4"
@define CPOOL_STATIC_FIELD "2:4"
@define CPOOL_STATIC_METHOD "3:4"
@define CPOOL_STRING "4:4"
@define CPOOL_CLASSREF "5:4"
@define CPOOL_ARRAYLENGTH "6:4"
@define CPOOL_SUPER "7:4"
@define CPOOL_INSTANCEOF "8:4"
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
define space ram type=ram_space size=4 default;
#define space object type=ram_space size=4; # object instances
#define space method type=ram_space size=4; # method references
#define space field type=ram_space size=4; # field references
define space register type=register_space size=4;
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
define register offset=0x0 size=4 [ sp fp resultreg ];
define register offset=0x8 size=8 [ resultregw ];
define register offset=0x100 size=4 # Special input registers
[
iv0 iv1 iv2 iv3 iv4 iv5 iv6 iv7
iv8 iv9 iv10 iv11 iv12 iv13 iv14 iv15
];
define register offset=0x104 size=8 # Wide input registers ODD
[
ivw1 ivw3 ivw5 ivw7 ivw9 ivw11 ivw13
];
define register offset=0x100 size=8 # Wide input registers EVEN
[
ivw0 ivw2 ivw4 ivw6 ivw8 ivw10 ivw12 ivw14
];
define register offset=0x1000 size=4
[
v0 v1 v2 v3 v4 v5 v6 v7 v8 v9 v10 v11 v12 v13 v14 v15
v16 v17 v18 v19 v20 v21 v22 v23 v24 v25 v26 v27 v28 v29 v30 v31
v32 v33 v34 v35 v36 v37 v38 v39 v40 v41 v42 v43 v44 v45 v46 v47
v48 v49 v50 v51 v52 v53 v54 v55 v56 v57 v58 v59 v60 v61 v62 v63
v64 v65 v66 v67 v68 v69 v70 v71 v72 v73 v74 v75 v76 v77 v78 v79
v80 v81 v82 v83 v84 v85 v86 v87 v88 v89 v90 v91 v92 v93 v94 v95
v96 v97 v98 v99 v100 v101 v102 v103 v104 v105 v106 v107 v108 v109 v110 v111
v112 v113 v114 v115 v116 v117 v118 v119 v120 v121 v122 v123 v124 v125 v126 v127
v128 v129 v130 v131 v132 v133 v134 v135 v136 v137 v138 v139 v140 v141 v142 v143
v144 v145 v146 v147 v148 v149 v150 v151 v152 v153 v154 v155 v156 v157 v158 v159
v160 v161 v162 v163 v164 v165 v166 v167 v168 v169 v170 v171 v172 v173 v174 v175
v176 v177 v178 v179 v180 v181 v182 v183 v184 v185 v186 v187 v188 v189 v190 v191
v192 v193 v194 v195 v196 v197 v198 v199 v200 v201 v202 v203 v204 v205 v206 v207
v208 v209 v210 v211 v212 v213 v214 v215 v216 v217 v218 v219 v220 v221 v222 v223
v224 v225 v226 v227 v228 v229 v230 v231 v232 v233 v234 v235 v236 v237 v238 v239
v240 v241 v242 v243 v244 v245 v246 v247 v248 v249 v250 v251 v252 v253 v254 v255
];
define register offset=0x1004 size=8 # ODD NUMBER WIDE REGISTERS
[
vw1 vw3 vw5 vw7 vw9 vw11 vw13 vw15
vw17 vw19 vw21 vw23 vw25 vw27 vw29 vw31
vw33 vw35 vw37 vw39 vw41 vw43 vw45 vw47
vw49 vw51 vw53 vw55 vw57 vw59 vw61 vw63
vw65 vw67 vw69 vw71 vw73 vw75 vw77 vw79
vw81 vw83 vw85 vw87 vw89 vw91 vw93 vw95
vw97 vw99 vw101 vw103 vw105 vw107 vw109 vw111
vw113 vw115 vw117 vw119 vw121 vw123 vw125 vw127
vw129 vw131 vw133 vw135 vw137 vw139 vw141 vw143
vw145 vw147 vw149 vw151 vw153 vw155 vw157 vw159
vw161 vw163 vw165 vw167 vw169 vw171 vw173 vw175
vw177 vw179 vw181 vw183 vw185 vw187 vw189 vw191
vw193 vw195 vw197 vw199 vw201 vw203 vw205 vw207
vw209 vw211 vw213 vw215 vw217 vw219 vw221 vw223
vw225 vw227 vw229 vw231 vw233 vw235 vw237 vw239
vw241 vw243 vw245 vw247 vw249 vw251 vw253
];
define register offset=0x1000 size=8 # EVEN NUMBER WIDE REGISTERS
[
vw0 vw2 vw4 vw6 vw8 vw10 vw12 vw14
vw16 vw18 vw20 vw22 vw24 vw26 vw28 vw30
vw32 vw34 vw36 vw38 vw40 vw42 vw44 vw46
vw48 vw50 vw52 vw54 vw56 vw58 vw60 vw62
vw64 vw66 vw68 vw70 vw72 vw74 vw76 vw78
vw80 vw82 vw84 vw86 vw88 vw90 vw92 vw94
vw96 vw98 vw100 vw102 vw104 vw106 vw108 vw110
vw112 vw114 vw116 vw118 vw120 vw122 vw124 vw126
vw128 vw130 vw132 vw134 vw136 vw138 vw140 vw142
vw144 vw146 vw148 vw150 vw152 vw154 vw156 vw158
vw160 vw162 vw164 vw166 vw168 vw170 vw172 vw174
vw176 vw178 vw180 vw182 vw184 vw186 vw188 vw190
vw192 vw194 vw196 vw198 vw200 vw202 vw204 vw206
vw208 vw210 vw212 vw214 vw216 vw218 vw220 vw222
vw224 vw226 vw228 vw230 vw232 vw234 vw236 vw238
vw240 vw242 vw244 vw246 vw248 vw250 vw252 vw254
];
# TODO:
# 1) test accessing register space past v255. e.g. v12345.
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
define token instruction_byte ( 8 )
inst0 = ( 0, 7 )
;
define token instruction_byte_w_padding ( 16 )
inst1 = ( 0, 7 )
inst1_padding = ( 0, 15 )
;
define token instruction_operands_4_4 ( 8 )
A_BITS_0_3 = (0,3)
B_BITS_0_3 = (0,3)
A_BITS_4_7 = (4,7)
B_BITS_4_7 = (4,7)
B_BITS_4_7_S = (4,7) signed
;
define token instruction_operands_8 ( 8 )
A_BITS_0_7 = (0,7)
A_BITS_0_7_S = (0,7) signed
B_BITS_0_7 = (0,7)
B_BITS_0_7_S = (0,7) signed
C_BITS_0_7 = (0,7)
C_BITS_0_7_S = (0,7) signed
;
define token instruction_operands_16 ( 16 )
A_BITS_0_15 = (0,15)
A_BITS_0_15_S = (0,15) signed
B_BITS_0_15 = (0,15)
B_BITS_0_15_S = (0,15) signed
C_BITS_0_15 = (0,15)
C_BITS_0_15_S = (0,15) signed
;
define token instruction_operands_32 ( 32 )
A_BITS_0_31 = (0,31)
A_BITS_0_31_S = (0,31) signed
B_BITS_0_31 = (0,31)
B_BITS_0_31_S = (0,31) signed
C_BITS_0_31 = (0,31)
C_BITS_0_31_S = (0,31) signed
;
define token invoke_operands ( 40 )
N_PARAMS = ( 4, 7)
PARAM_G = ( 0, 3)
METHOD_INDEX = ( 8,23)
VTABLE_OFFSET = ( 8,23)
INLINE = ( 8,23)
PARAM_D = (28,31)
PARAM_C = (24,27)
PARAM_F = (36,39)
PARAM_E = (32,35)
;
define token array_operands ( 40 )
N_ELEMENTS = ( 4, 7)
ELEMENT_G = ( 0, 3)
TYPE_INDEX = ( 8,23)
ELEMENT_D = (28,31)
ELEMENT_C = (24,27)
ELEMENT_F = (36,39)
ELEMENT_E = (32,35)
;
define token CONST16 ( 16 ) # one 16 constant
constant16 = ( 0,15 )
constant16s = ( 0,15 ) signed
;
define token CONST32 ( 32 ) # one 32 constant
constant32 = ( 0,31 )
constant32s = ( 0,31 ) signed
;
define token CONST64 ( 64 ) # one 64 constant
constant64 = ( 0,63 )
;
# add "8" to skip over "fp" and "sp" !!
registerA4: reg is A_BITS_0_3 [ reg = (A_BITS_0_3 * 4) + 0x1000; ] { export *[register]:4 reg; }
registerA8: reg is A_BITS_0_7 [ reg = (A_BITS_0_7 * 4) + 0x1000; ] { export *[register]:4 reg; }
registerA16: reg is A_BITS_0_15 [ reg = (A_BITS_0_15 * 4) + 0x1000; ] { export *[register]:4 reg; }
registerA4w: reg is A_BITS_0_3 [ reg = (A_BITS_0_3 * 4) + 0x1000; ] { export *[register]:8 reg; }
registerA8w: reg is A_BITS_0_7 [ reg = (A_BITS_0_7 * 4) + 0x1000; ] { export *[register]:8 reg; }
registerA16w: reg is A_BITS_0_15 [ reg = (A_BITS_0_15 * 4) + 0x1000; ] { export *[register]:8 reg; }
registerB4: reg is B_BITS_4_7 [ reg = (B_BITS_4_7 * 4) + 0x1000; ] { export *[register]:4 reg; }
registerB8: reg is B_BITS_0_7 [ reg = (B_BITS_0_7 * 4) + 0x1000; ] { export *[register]:4 reg; }
registerB16: reg is B_BITS_0_15 [ reg = (B_BITS_0_15 * 4) + 0x1000; ] { export *[register]:4 reg; }
registerB4w: reg is B_BITS_4_7 [ reg = (B_BITS_4_7 * 4) + 0x1000; ] { export *[register]:8 reg; }
registerB8w: reg is B_BITS_0_7 [ reg = (B_BITS_0_7 * 4) + 0x1000; ] { export *[register]:8 reg; }
registerB16w: reg is B_BITS_0_15 [ reg = (B_BITS_0_15 * 4) + 0x1000; ] { export *[register]:8 reg; }
registerC8: reg is C_BITS_0_7 [ reg = (C_BITS_0_7 * 4) + 0x1000; ] { export *[register]:4 reg; }
registerC16: reg is C_BITS_0_15 [ reg = (C_BITS_0_15 * 4) + 0x1000; ] { export *[register]:4 reg; }
registerC32: reg is C_BITS_0_31 [ reg = (C_BITS_0_31 * 4) + 0x1000; ] { export *[register]:4 reg; }
registerC8w: reg is C_BITS_0_7 [ reg = (C_BITS_0_7 * 4) + 0x1000; ] { export *[register]:8 reg; }
registerC16w: reg is C_BITS_0_15 [ reg = (C_BITS_0_15 * 4) + 0x1000; ] { export *[register]:8 reg; }
registerC32w: reg is C_BITS_0_31 [ reg = (C_BITS_0_31 * 4) + 0x1000; ] { export *[register]:8 reg; }
regParamC: reg is PARAM_C [ reg = (PARAM_C * 4) + 0x1000; ] { export *[register]:4 reg; }
regParamD: reg is PARAM_D [ reg = (PARAM_D * 4) + 0x1000; ] { export *[register]:4 reg; }
regParamE: reg is PARAM_E [ reg = (PARAM_E * 4) + 0x1000; ] { export *[register]:4 reg; }
regParamF: reg is PARAM_F [ reg = (PARAM_F * 4) + 0x1000; ] { export *[register]:4 reg; }
regParamG: reg is PARAM_G [ reg = (PARAM_G * 4) + 0x1000; ] { export *[register]:4 reg; }
regElemC: reg is ELEMENT_C [ reg = (ELEMENT_C * 4) + 0x1000; ] { export *[register]:4 reg; }
regElemD: reg is ELEMENT_D [ reg = (ELEMENT_D * 4) + 0x1000; ] { export *[register]:4 reg; }
regElemE: reg is ELEMENT_E [ reg = (ELEMENT_E * 4) + 0x1000; ] { export *[register]:4 reg; }
regElemF: reg is ELEMENT_F [ reg = (ELEMENT_F * 4) + 0x1000; ] { export *[register]:4 reg; }
regElemG: reg is ELEMENT_G [ reg = (ELEMENT_G * 4) + 0x1000; ] { export *[register]:4 reg; }
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
rel16: reloc is A_BITS_0_15_S [ reloc = inst_start + ( A_BITS_0_15_S * 2 ); ] { export *[ram]:32 reloc; }
goto8: reloc is A_BITS_0_7_S [ reloc = inst_start + ( A_BITS_0_7_S * 2 ); ] { export *[ram]:8 reloc; }
goto16: reloc is A_BITS_0_15_S [ reloc = inst_start + ( A_BITS_0_15_S * 2 ); ] { export *[ram]:16 reloc; }
goto32: reloc is A_BITS_0_31_S [ reloc = inst_start + ( A_BITS_0_31_S ); ] { export *[ram]:32 reloc; }
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
# Special op which injects correct p-code for invoke*_range instructions
# It takes two arguments: 1) is the number of parameters for the method 2) is the starting register
define pcodeop moveRangeToIV;
define pcodeop monitorEnter;
define pcodeop monitorExit;
define pcodeop checkCast;
define pcodeop throwException;
define pcodeop getStaticFieldVolatile;
define pcodeop setStaticFieldVolatile;
define pcodeop getInstanceFieldQuick;
define pcodeop getInstanceFieldVolatile;
define pcodeop setInstanceFieldQuick;
define pcodeop setInstanceFieldVolatile;
define pcodeop filledNewArray;
define pcodeop filledNewArrayRange;
define pcodeop invokeSuperQuick;
define pcodeop invokeSuperQuickRange;
define pcodeop invokeVirtualQuick;
define pcodeop invokeVirtualQuickRange;
define pcodeop switchAssist;
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
# Waste cycles.
:nop is inst0=0x00
{
#no pCode
}
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
# Move the contents of one non-object register to another.
#
# A: destination register (4 bits)
# B: source register (4 bits)
:move registerA4,registerB4 is inst0=0x01 ; registerA4 & registerB4
{
registerA4 = registerB4;
}
# Move the contents of one non-object register to another.
#
# A: destination register (8 bits)
# B: source register (16 bits)
:move_from_16 registerA8,registerB16 is inst0=0x02 ; registerA8 ; registerB16
{
registerA8 = registerB16;
}
# Move the contents of one non-object register to another.
#
# A: destination register (16 bits)
# B: source register (16 bits)
:move_16 registerA16,registerB16 is inst1=0x03 & inst1_padding ; registerA16 ; registerB16
{
registerA16 = registerB16;
}
# Move the contents of one register-pair to another.
#
# A: destination register pair (4 bits)
# B: source register pair (4 bits)
:move_wide registerA4w,registerB4w is inst0=0x04 ; registerA4w & registerB4w
{
registerA4w = registerB4w;
}
# Move the contents of one register-pair to another.
#
# A: destination register pair (8 bits)
# B: source register pair (16 bits)
:move_wide_from_16 registerA8w,registerB16w is inst0=0x05 ; registerA8w ; registerB16w
{
registerA8w = registerB16w;
}
# Move the contents of one register-pair to another.
#
# A: destination register pair (16 bits)
# B: source register pair (16 bits)
:move_wide_16 registerA16w,registerB16w is inst0=0x06 ; registerA16w ; registerB16w
{
registerA16w = registerB16w;
}
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# Move the contents of one object-bearing register to another.
#
# A: destination register (4 bits)
# B: source register (4 bits)
:move_object registerA4,registerB4 is inst0=0x07 ; registerA4 & registerB4
{
registerA4 = registerB4;
}
# Move the contents of one object-bearing register to another.
#
# A: destination register (8 bits)
# B: source register (16 bits)
:move_object_from_16 registerA8,registerB16 is inst0=0x08 ; registerA8 ; registerB16
{
registerA8 = registerB16;
}
# Move the contents of one object-bearing register to another.
#
# A: destination register (16 bits)
# B: source register (16 bits)
:move_object_16 registerA16,registerB16 is inst1=0x09 & inst1_padding ; registerA16 ; registerB16
{
registerA16 = registerB16;
}
# Move the single-word non-object result of the most recent invoke-kind
# into the indicated register. This must be done as the instruction
# immediately after an invoke-kind whose (single-word, non-object)
# result is not to be ignored; anywhere else is invalid.
#
# A: destination register (8 bits)
:move_result registerA8 is inst0=0x0a ; registerA8
{
registerA8 = resultreg;
}
# Move the double-word result of the most recent invoke-kind into
# the indicated register pair. This must be done as the instruction
# immediately after an invoke-kind whose (double-word) result is
# not to be ignored; anywhere else is invalid.
#
# A: destination register pair (8 bits)
:move_result_wide registerA8w is inst0=0x0b ; registerA8w
{
registerA8w = resultregw;
}
# Move the object result of the most recent invoke-kind into
# the indicated register. This must be done as the instruction
# immediately after an invoke-kind or filled-new-array whose
# (object) result is not to be ignored; anywhere else is invalid.
#
# A: destination register (8 bits)
:move_result_object registerA8 is inst0=0x0c ; registerA8
{
registerA8 = resultreg;
}
# Save a just-caught exception into the given register. This must
# be the first instruction of any exception handler whose caught
# exception is not to be ignored, and this instruction must only
# ever occur as the first instruction of an exception handler;
# anywhere else is invalid.
#
# A: destination register (8 bits)
:move_exception registerA8 is inst0=0x0d ; registerA8
{
#TODO pCode
# this requires state!?
}
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
# Return from a void method.
:return_void is inst1=0x0e & inst1_padding
{
return [sp];
}
# Return from a single-width (32-bit) non-object value-returning method.
#
# A: return value register (8 bits)
:return registerA8 is inst0=0x0f ; registerA8
{
resultreg = registerA8;
return [sp];
}
# Return from a double-width (64-bit) value-returning method.
#
# A: return value register-pair (8 bits)
:return_wide registerA8w is inst0=0x10 ; registerA8w
{
resultregw = registerA8w;
return [sp];
}
# Return from an object-returning method.
#
# A: return value register (8 bits)
:return_object registerA8 is inst0=0x11 ; registerA8
{
resultreg = registerA8;
return [sp];
}
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
# Move the given literal value (sign-extended to 32 bits) into the specified register.
#
# A: destination register (4 bits)
# B: signed int (4 bits)
:const_4 registerA4,B_BITS_4_7_S is inst0=0x12 ; registerA4 & B_BITS_4_7_S
{
registerA4 = sext( B_BITS_4_7_S:4) ;
}
# Move the given literal value (sign-extended to 32 bits) into the specified register.
#
# A: destination register (8 bits)
# B: signed int (16 bits)
:const_16 registerA8,B_BITS_0_15_S is inst0=0x13 ; registerA8 ; B_BITS_0_15_S
{
registerA8 = sext( B_BITS_0_15_S:4 );
}
# Move the given literal value into the specified register.
#
# A: destination register (8 bits)
# B: arbitrary 32-bit constant
:"const" registerA8,constant32 is inst0=0x14 ; registerA8 ; constant32
{
registerA8 = constant32;
}
# Move the given literal value (right-zero-extended to 32 bits) into the specified register.
#
# A: destination register (8 bits)
# B: signed int (16 bits)
:const_high_16 registerA8,B_BITS_0_15 is inst0=0x15 ; registerA8 ; B_BITS_0_15
{
registerA8 = B_BITS_0_15:4 << 16;
}
# Move the given literal value (sign-extended to 64 bits) into the specified register-pair.
#
# A: destination register (8 bits)
# B: signed int (16 bits)
:const_wide_16 registerA8w,constant16s is inst0=0x16 ; registerA8w ; constant16s
{
registerA8w = sext( constant16s:2 );
}
# Move the given literal value (sign-extended to 64 bits) into the specified register-pair.
#
# A: destination register (8 bits)
# B: signed int (32 bits)
:const_wide_32 registerA8w,constant32s is inst0=0x17 ; registerA8w ; constant32s
{
registerA8w = sext( constant32s:4 );
}
# Move the given literal value into the specified register-pair.
#
# A: destination register (8 bits)
# B: arbitrary double-width (64-bit) constant
:const_wide registerA8w,constant64 is inst0=0x18 ; registerA8w ; constant64
{
registerA8w = constant64;
}
# Move the given literal value (right-zero-extended to 64 bits) into the specified register-pair.
#
# A: destination register (8 bits)
# B: signed int (16 bits)
:const_wide_high_16 registerA8w,B_BITS_0_15_S is inst0=0x19 ; registerA8w ; B_BITS_0_15_S
{
registerA8w = B_BITS_0_15_S << 48;
}
# Move a reference to the string specified by the given index into the specified register.
#
# A: destination register (8 bits)
# B: string index
:const_string registerA8,B_BITS_0_15 is inst0=0x1a ; registerA8 ; B_BITS_0_15
{
registerA8 = cpool(0:4, B_BITS_0_15:4, $(CPOOL_STRING));
}
# Move a reference to the string specified by the given index into the specified register.
#
# A: destination register (8 bits)
# B: string index
:const_string_jumbo registerA8,B_BITS_0_31 is inst0=0x1b ; registerA8 ; B_BITS_0_31
{
registerA8 = cpool(0:4, B_BITS_0_31:4, $(CPOOL_STRING));
}
# Move a reference to the class specified by the given index into the
# specified register. In the case where the indicated type is primitive,
# this will store a reference to the primitive type's degenerate class.
#
# A: destination register (8 bits)
# B: type index
:const_class registerA8,B_BITS_0_15 is inst0=0x1c ; registerA8 ; B_BITS_0_15
{
registerA8 = cpool( 0:4, B_BITS_0_15:4, $(CPOOL_CLASSREF));
}
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
# Acquire the monitor for the indicated object.
#
# A: reference-bearing register (8 bits)
:monitor_enter registerA8 is inst0=0x1d ; registerA8
{
monitorEnter( registerA8 );
}
# Release the monitor for the indicated object.
#
# A: reference-bearing register (8 bits)
:monitor_exit registerA8 is inst0=0x1e ; registerA8
{
monitorExit( registerA8 );
}
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
# Throw a ClassCastException if the reference in the given register
# cannot be cast to the indicated type.
#
# A: reference-bearing register (8 bits)
# B: type index (16 bits)
:check_cast registerA8,B_BITS_0_15 is inst0=0x1f ; registerA8 ; B_BITS_0_15
{
checkCast( registerA8, cpool( 0:4, B_BITS_0_15:4, $(CPOOL_CLASSREF)) );
}
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
# Store in the given destination register 1 if the indicated reference
# is an instance of the given type, or 0 if not.
#
# A: destination register (4 bits)
# B: reference-bearing register (4 bits)
# C: type index (16 bits)
:instance_of registerA4,registerB4,C_BITS_0_15 is inst0=0x20 ; registerA4 & registerB4 ; C_BITS_0_15
{
res:1 = cpool( registerB4, C_BITS_0_15:4, $(CPOOL_INSTANCEOF) );
registerA4 = zext( res );
}
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
# Store in the given destination register the length of the indicated array, in entries
#
# A: destination register (4 bits)
# B: array reference-bearing register (4 bits)
:array_length registerA4,registerB4 is inst0=0x21 ; registerA4 & registerB4
{
registerA4 = cpool( registerB4, 0:4, $(CPOOL_ARRAYLENGTH) );
}
# Construct a new instance of the indicated type, storing a reference
# to it in the destination. The type must refer to a non-array class.
#
# A: destination register (8 bits)
# B: type index
:new_instance registerA8,B_BITS_0_15 is inst0=0x22 ; registerA8 ; B_BITS_0_15
{
registerA8 = newobject( cpool( 0:4, B_BITS_0_15:4, $(CPOOL_CLASSREF)) );
}
# Construct a new array of the indicated type and size. The type must be an array type.
#
# A: destination register (8 bits)
# B: size register
# C: type index
:new_array registerA4,registerB4,C_BITS_0_15 is inst0=0x23 ; registerA4 & registerB4 ; C_BITS_0_15
{
registerA4 = newobject( cpool( 0:4, C_BITS_0_15:4, $(CPOOL_CLASSREF)), registerB4 );
}
# Construct an array of the given type and size, filling it with the supplied
# contents. The type must be an array type. The array's contents must be
# single-word (that is, no arrays of long or double, but reference types are
# acceptable). The constructed instance is stored as a "result" in the same
# way that the method invocation instructions store their results, so the
# constructed instance must be moved to a register with an immediately
# subsequent move-result-object instruction (if it is to be used).
#
# A: array size and argument word count (4 bits)
# B: type index (16 bits)
# C..G: argument registers (4 bits each)
:filled_new_array TYPE_INDEX is inst0=0x24 ; N_ELEMENTS = 0 & TYPE_INDEX & regElemC & regElemD & regElemE & regElemF & regElemG
{
#TODO pCode
filledNewArray( TYPE_INDEX:4 );
}
:filled_new_array TYPE_INDEX,regElemC is inst0=0x24 ; N_ELEMENTS = 1 & TYPE_INDEX & regElemC & regElemD & regElemE & regElemF & regElemG
{
#TODO pCode
filledNewArray( TYPE_INDEX:4, regElemC );
}
:filled_new_array TYPE_INDEX,regElemC,regElemD is inst0=0x24 ; N_ELEMENTS = 2 & TYPE_INDEX & regElemC & regElemD & regElemE & regElemF & regElemG
{
#TODO pCode
filledNewArray( TYPE_INDEX:4, regElemC, regElemD );
}
:filled_new_array TYPE_INDEX,regElemC,regElemD,regElemE is inst0=0x24 ; N_ELEMENTS = 3 & TYPE_INDEX & regElemC & regElemD & regElemE & regElemF & regElemG
{
#TODO pCode
filledNewArray( TYPE_INDEX:4, regElemC, regElemD, regElemE );
}
:filled_new_array TYPE_INDEX,regElemC,regElemD,regElemE,regElemF is inst0=0x24 ; N_ELEMENTS = 4 & TYPE_INDEX & regElemC & regElemD & regElemE & regElemF & regElemG
{
#TODO pCode
filledNewArray( TYPE_INDEX:4, regElemC, regElemD, regElemE, regElemF );
}
:filled_new_array TYPE_INDEX,regElemC,regElemD,regElemE,regElemF,regElemG is inst0=0x24 ; N_ELEMENTS = 5 & TYPE_INDEX & regElemC & regElemD & regElemE & regElemF & regElemG
{
#TODO pCode
filledNewArray( TYPE_INDEX:4, regElemC, regElemD, regElemE, regElemF, regElemG );
}
# Construct an array of the given type and size, filling it with
# the supplied contents. Clarifications and restrictions are the
# same as filled-new-array, described above.
#
# A: array size and argument word count (8 bits)
# B: type index (16 bits)
# C: first argument register (16 bits)
# N = A + C - 1
:filled_new_array_range A_BITS_0_7,B_BITS_0_15,registerC16 is inst0=0x25 ; A_BITS_0_7 ; B_BITS_0_15 ; registerC16
{
#TODO pCode
filledNewArrayRange( A_BITS_0_7:4, B_BITS_0_15:4, registerC16 );
}
# Fill the given array with the indicated data. The reference must
# be to an array of primitives, and the data table must match it in type
# and must contain no more elements than will fit in the array. That is,
# the array may be larger than the table, and if so, only the initial
# elements of the array are set, leaving the remainder alone.
#
# A: array reference (8 bits)
# B: signed "branch" offset to table data pseudo-instruction (32 bits)
:fill_array_data registerA8,B_BITS_0_31_S is inst0=0x26 ; registerA8 ; B_BITS_0_31_S
{
#TODO pCode
# fillArrayData
}
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
# Throw the indicated exception.
#
# A: exception-bearing register (8 bits)
:throw registerA8 is inst0=0x27 ; registerA8
{
throwException( registerA8 );
return [registerA8];#TODO is the best way to return??
}
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
# Unconditionally jump to the indicated instruction.
#
# A: signed branch offset (8 bits)
:goto goto8 is inst0=0x28 ; goto8
{
goto goto8;
}
# Unconditionally jump to the indicated instruction.
#
# A: signed branch offset (16 bits)
:goto_16 goto16 is inst1=0x29 & inst1_padding ; goto16
{
goto goto16;
}
# Unconditionally jump to the indicated instruction.
#
# A: signed branch offset (32 bits)
:goto_32 goto32 is inst1=0x2a & inst1_padding ; goto32
{
goto goto32;
}
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
# Jump to a new instruction based on the value in the given register,
# using a table of offsets corresponding to each value in a particular
# integral range, or fall through to the next instruction if there is no match.
#
# A: register to test
# B: signed "branch" offset to table data pseudo-instruction (32 bits)
#
# NOTE: Offset (B) and destinations must be multiplied by 2.
# TODO use disassembly action??
:packed_switch registerA8,B_BITS_0_31_S is inst0=0x2b ; registerA8 ; B_BITS_0_31_S
{
distance:4 = B_BITS_0_31_S * 2;
# ident:2 = *[ram] ( inst_start + distance );
# if (ident != 0x0100) goto inst_next;
size2:2 = *[ram] ( inst_start + distance + 2 );
sze:4 = zext( size2 );
first_key:4 = *[ram] ( inst_start + distance + 2 + 2 );
if ( registerA8 < first_key ) goto inst_next;
if ( registerA8 >= ( first_key + sze ) ) goto inst_next;
targets:4 = ( inst_start + distance + 2 + 2 + 4 );
delta:4 = ( registerA8 ) - ( first_key ); # which index into target
value:4 = *[ram] ( targets + ( delta * 4 ) );
address:4 = ( inst_start + ( value * 2 ) );
goto [ address ];
}
# Jump to a new instruction based on the value in the given register,
# using an ordered table of value-offset pairs, or fall through to the
# next instruction if there is no match.
#
# A: register to test
# B: signed "branch" offset to table data pseudo-instruction (32 bits)
#
# NOTE: Offset (B) and destinations must be multiplied by 2.
:sparse_switch registerA8,B_BITS_0_31_S is inst0=0x2c ; registerA8 ; B_BITS_0_31_S
{
distance:4 = B_BITS_0_31_S * 2;
temp:4 = inst_start;
size2:2 = *[ram] ( temp + 2 + distance);
sze:4 = zext( size2 );
defaultPos:4 = inst_next;
address:4 = switchAssist( registerA8, sze, defaultPos, temp, distance );
goto [ address ];
}
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
# Perform the indicated floating point or long comparison,
# setting a to 0 if b == c, 1 if b > c, or -1 if b < c.
# The "bias" listed for the floating point operations indicates
# how NaN comparisons are treated: "gt bias" instructions return 1 for
# NaN comparisons, and "lt bias" instructions return -1.
#
# For example, to check to see if floating point x < y it is advisable
# to use cmpg-float; a result of -1 indicates that the test was true,
# and the other values indicate it was false either due to a valid
# comparison or because one of the values was NaN.
#
# A: destination register (8 bits)
# B: first source register or pair
# C: second source register or pair
:cmpl_float registerA8,registerB8,registerC8 is inst0=0x2d ; registerA8 ; registerB8 ; registerC8
{
registerA8 = zext( registerC8 f<= registerB8) + zext( registerC8 f< registerB8) - 1;
}
:cmpg_float registerA8,registerB8,registerC8 is inst0=0x2e ; registerA8 ; registerB8 ; registerC8
{
registerA8 = zext( registerC8 f<= registerB8) + zext( registerC8 f< registerB8) - 1;
}
:cmpl_double registerA8,registerB8w,registerC8w is inst0=0x2f ; registerA8 ; registerB8w ; registerC8w
{
registerA8 = zext( registerC8w f<= registerB8w) + zext( registerC8w f< registerB8w) - 1;
}
:cmpg_double registerA8,registerB8w,registerC8w is inst0=0x30 ; registerA8 ; registerB8w ; registerC8w
{
registerA8 = zext( registerC8w f<= registerB8w) + zext( registerC8w f< registerB8w) - 1;
}
:cmp_long registerA8,registerB8w,registerC8w is inst0=0x31 ; registerA8 ; registerB8w ; registerC8w
{
registerA8 = zext( registerC8w s<= registerB8w ) + zext( registerC8w s< registerB8w ) - 1;
}
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
# Branch to the given destination if the given two registers' values compare as specified.
#
# A: first register to test (4 bits)
# B: second register to test (4 bits)
# C: signed branch offset (16 bits)
:if_eq registerA4,registerB4,rel16 is inst0=0x32 ; registerA4 & registerB4 ; rel16
{
if ( registerA4 == registerB4 ) goto rel16;
}
:if_ne registerA4,registerB4,rel16 is inst0=0x33 ; registerA4 & registerB4 ; rel16
{
if ( registerA4 != registerB4 ) goto rel16;
}
:if_lt registerA4,registerB4,rel16 is inst0=0x34 ; registerA4 & registerB4 ; rel16
{
if ( registerA4 s< registerB4 ) goto rel16;
}
:if_ge registerA4,registerB4,rel16 is inst0=0x35 ; registerA4 & registerB4 ; rel16
{
if ( registerA4 s>= registerB4 ) goto rel16;
}
:if_gt registerA4,registerB4,rel16 is inst0=0x36 ; registerA4 & registerB4 ; rel16
{
if ( registerA4 s> registerB4 ) goto rel16;
}
:if_le registerA4,registerB4,rel16 is inst0=0x37 ; registerA4 & registerB4 ; rel16
{
if ( registerA4 s<= registerB4 ) goto rel16;
}
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
# Branch to the given destination if the given register's value compares with 0 as specified.
#
# A: register to test (8 bits)
# B: signed branch offset (16 bits)
:if_eqz registerA8,rel16 is inst0=0x38 ; registerA8 ; rel16
{
if ( registerA8 == 0 ) goto rel16;
}
:if_nez registerA8,rel16 is inst0=0x39 ; registerA8 ; rel16
{
if ( registerA8 != 0 ) goto rel16;
}
:if_ltz registerA8,rel16 is inst0=0x3a ; registerA8 ; rel16
{
if ( registerA8 s< 0 ) goto rel16;
}
:if_gez registerA8,rel16 is inst0=0x3b ; registerA8 ; rel16
{
if ( registerA8 s>= 0 ) goto rel16;
}
:if_gtz registerA8,rel16 is inst0=0x3c ; registerA8 ; rel16
{
if ( registerA8 s> 0 ) goto rel16;
}
:if_lez registerA8,rel16 is inst0=0x3d ; registerA8 ; rel16
{
if ( registerA8 s<= 0 ) goto rel16;
}
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
# 0x3e unused
# 0x3f unused
# 0x40 unused
# 0x41 unused
# 0x42 unused
# 0x43 unused
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
# Perform the identified array operation at the identified index
# of the given array, loading or storing into the value register.
#
# A: value register or pair; may be source or dest (8 bits)
# B: array register (8 bits)
# C: index register (8 bits)
:aget registerA8,registerB8,registerC8 is inst0=0x44 ; registerA8 ; registerB8 ; registerC8
{
registerA8 = *( registerB8 + registerC8*4 );
}
:aget_wide registerA8w,registerB8,registerC8 is inst0=0x45 ; registerA8w ; registerB8 ; registerC8
{
registerA8w = *( registerB8 + registerC8*8 );
}
:aget_object registerA8,registerB8,registerC8 is inst0=0x46 ; registerA8 ; registerB8 ; registerC8
{
registerA8 = *( registerB8 + registerC8*4 );
}
:aget_boolean registerA8,registerB8,registerC8 is inst0=0x47 ; registerA8 ; registerB8 ; registerC8
{
registerA8 = zext( *:1 ( registerB8 + registerC8 ));
}
:aget_byte registerA8,registerB8,registerC8 is inst0=0x48 ; registerA8 ; registerB8 ; registerC8
{
registerA8 = sext( *:1 (registerB8 + registerC8) );
}
:aget_char registerA8,registerB8,registerC8 is inst0=0x49 ; registerA8 ; registerB8 ; registerC8
{
registerA8 = zext( *:2 (registerB8 + registerC8*2 ) );
}
:aget_short registerA8,registerB8,registerC8 is inst0=0x4a ; registerA8 ; registerB8 ; registerC8
{
registerA8 = sext( *:2 (registerB8 + registerC8 * 2 ) );
}
:aput registerA8,registerB8,registerC8 is inst0=0x4b ; registerA8 ; registerB8 ; registerC8
{
*( registerB8 + registerC8 * 4 ) = registerA8;
}
:aput_wide registerA8w,registerB8,registerC8 is inst0=0x4c ; registerA8w ; registerB8 ; registerC8
{
*( registerB8 + registerC8 * 8 ) = registerA8w;
}
:aput_object registerA8,registerB8,registerC8 is inst0=0x4d ; registerA8 ; registerB8 ; registerC8
{
*( registerB8 + registerC8 * 4 ) = registerA8;
}
:aput_boolean registerA8,registerB8,registerC8 is inst0=0x4e ; registerA8 ; registerB8 ; registerC8
{
*( registerB8 + registerC8 ) = registerA8:1;
}
:aput_byte registerA8,registerB8,registerC8 is inst0=0x4f ; registerA8 ; registerB8 ; registerC8
{
*( registerB8 + registerC8 ) = registerA8:1;
}
:aput_char registerA8,registerB8,registerC8 is inst0=0x50 ; registerA8 ; registerB8 ; registerC8
{
*( registerB8 + registerC8*2 ) = registerA8:2;
}
:aput_short registerA8,registerB8,registerC8 is inst0=0x51 ; registerA8 ; registerB8 ; registerC8
{
*( registerB8 + registerC8*2 ) = registerA8:2;
}
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
# Perform the identified object instance field operation with the
# identified field, loading or storing into the value register.
#
# A: value register or pair; may be source or dest (4 bits)
# B: object register (4 bits)
# C: instance field reference index (16 bits)
:iget registerA4,[registerB4:C_BITS_0_15] is inst0=0x52 ; registerA4 & registerB4 ; C_BITS_0_15
{
ptr:4 = cpool( registerB4, C_BITS_0_15:4, $(CPOOL_FIELD));
registerA4 = *ptr;
}
:iget_wide registerA4w,[registerB4:C_BITS_0_15] is inst0=0x53 ; registerA4w & registerB4 ; C_BITS_0_15
{
ptr:4 = cpool( registerB4, C_BITS_0_15:4, $(CPOOL_FIELD));
registerA4w = *ptr;
}
:iget_object registerA4,[registerB4:C_BITS_0_15] is inst0=0x54 ; registerA4 & registerB4 ; C_BITS_0_15
{
ptr:4 = cpool( registerB4, C_BITS_0_15:4, $(CPOOL_FIELD));
registerA4 = *ptr;
}
:iget_boolean registerA4,[registerB4:C_BITS_0_15] is inst0=0x55 ; registerA4 & registerB4 ; C_BITS_0_15
{
ptr:4 = cpool( registerB4, C_BITS_0_15:4, $(CPOOL_FIELD));
registerA4 = zext( *:1 ptr );
}
:iget_byte registerA4,[registerB4:C_BITS_0_15] is inst0=0x56 ; registerA4 & registerB4 ; C_BITS_0_15
{
ptr:4 = cpool( registerB4, C_BITS_0_15:4, $(CPOOL_FIELD));
registerA4 = sext( *:1 ptr );
}
:iget_char registerA4,[registerB4:C_BITS_0_15] is inst0=0x57 ; registerA4 & registerB4 ; C_BITS_0_15
{
ptr:4 = cpool( registerB4, C_BITS_0_15:4, $(CPOOL_FIELD));
registerA4 = zext( *:2 ptr );
}
:iget_short registerA4,[registerB4:C_BITS_0_15] is inst0=0x58 ; registerA4 & registerB4 ; C_BITS_0_15
{
ptr:4 = cpool( registerB4, C_BITS_0_15:4, $(CPOOL_FIELD));
registerA4 = sext( *:2 ptr );
}
:iput registerA4,[registerB4:C_BITS_0_15] is inst0=0x59 ; registerA4 & registerB4 ; C_BITS_0_15
{
ptr:4 = cpool(registerB4, C_BITS_0_15:4, $(CPOOL_FIELD));
*ptr = registerA4;
}
:iput_wide registerA4w,[registerB4:C_BITS_0_15] is inst0=0x5a ; registerA4w & registerB4 ; C_BITS_0_15
{
ptr:4 = cpool(registerB4, C_BITS_0_15:4, $(CPOOL_FIELD));
*ptr = registerA4w;
}
:iput_object registerA4,[registerB4:C_BITS_0_15] is inst0=0x5b ; registerA4 & registerB4 ; C_BITS_0_15
{
ptr:4 = cpool(registerB4, C_BITS_0_15:4, $(CPOOL_FIELD));
*ptr = registerA4;
}
:iput_boolean registerA4,[registerB4:C_BITS_0_15] is inst0=0x5c ; registerA4 & registerB4 ; C_BITS_0_15
{
ptr:4 = cpool(registerB4, C_BITS_0_15:4, $(CPOOL_FIELD));
*ptr = registerA4 : 1;
}
:iput_byte registerA4,[registerB4:C_BITS_0_15] is inst0=0x5d ; registerA4 & registerB4 ; C_BITS_0_15
{
ptr:4 = cpool(registerB4, C_BITS_0_15:4, $(CPOOL_FIELD));
*ptr = registerA4 : 1;
}
:iput_char registerA4,[registerB4:C_BITS_0_15] is inst0=0x5e ; registerA4 & registerB4 ; C_BITS_0_15
{
ptr:4 = cpool(registerB4, C_BITS_0_15:4, $(CPOOL_FIELD));
*ptr = registerA4 : 2;
}
:iput_short registerA4,[registerB4:C_BITS_0_15] is inst0=0x5f ; registerA4 & registerB4 ; C_BITS_0_15
{
ptr:4 = cpool(registerB4, C_BITS_0_15:4, $(CPOOL_FIELD));
*ptr = registerA4 : 2;
}
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
# Perform the identified object static field operation with the identified
# static field, loading or storing into the value register.
#
# A: value register or pair; may be source or dest (8 bits)
# B: static field reference index (16 bits)
:sget registerA8,B_BITS_0_15 is inst0=0x60 ; registerA8 ; B_BITS_0_15
{
ptr:4 = cpool(0:4,B_BITS_0_15:4,$(CPOOL_STATIC_FIELD));
registerA8 = *ptr;
}
:sget_wide registerA8w,B_BITS_0_15 is inst0=0x61 ; registerA8w ; B_BITS_0_15
{
ptr:4 = cpool(0:4,B_BITS_0_15:4,$(CPOOL_STATIC_FIELD));
registerA8w = *ptr;
}
:sget_object registerA8,B_BITS_0_15 is inst0=0x62 ; registerA8 ; B_BITS_0_15
{
ptr:4 = cpool(0:4,B_BITS_0_15:4,$(CPOOL_STATIC_FIELD));
registerA8 = *ptr;
}
:sget_boolean registerA8,B_BITS_0_15 is inst0=0x63 ; registerA8 ; B_BITS_0_15
{
ptr:4 = cpool(0:4,B_BITS_0_15:4,$(CPOOL_STATIC_FIELD));
registerA8 = zext(*:1 ptr);
}
:sget_byte registerA8,B_BITS_0_15 is inst0=0x64 ; registerA8 ; B_BITS_0_15
{
ptr:4 = cpool(0:4,B_BITS_0_15:4,$(CPOOL_STATIC_FIELD));
registerA8 = sext(*:1 ptr);
}
:sget_char registerA8,B_BITS_0_15 is inst0=0x65 ; registerA8 ; B_BITS_0_15
{
ptr:4 = cpool(0:4,B_BITS_0_15:4,$(CPOOL_STATIC_FIELD));
registerA8 = zext(*:2 ptr);
}
:sget_short registerA8,B_BITS_0_15 is inst0=0x66 ; registerA8 ; B_BITS_0_15
{
ptr:4 = cpool(0:4,B_BITS_0_15:4,$(CPOOL_STATIC_FIELD));
registerA8 = sext(*:2 ptr);
}
:sput registerA8,B_BITS_0_15 is inst0=0x67 ; registerA8 ; B_BITS_0_15
{
ptr:4 = cpool(0:4,B_BITS_0_15:4,$(CPOOL_STATIC_FIELD));
*ptr = registerA8;
}
:sput_wide registerA8w,B_BITS_0_15 is inst0=0x68 ; registerA8w ; B_BITS_0_15
{
ptr:4 = cpool(0:4,B_BITS_0_15:4,$(CPOOL_STATIC_FIELD));
*ptr = registerA8w;
}
:sput_object registerA8,B_BITS_0_15 is inst0=0x69 ; registerA8 ; B_BITS_0_15
{
ptr:4 = cpool(0:4,B_BITS_0_15:4,$(CPOOL_STATIC_FIELD));
*ptr = registerA8;
}
:sput_boolean registerA8,B_BITS_0_15 is inst0=0x6a ; registerA8 ; B_BITS_0_15
{
ptr:4 = cpool(0:4,B_BITS_0_15:4,$(CPOOL_STATIC_FIELD));
*ptr = registerA8:1;
}
:sput_byte registerA8,B_BITS_0_15 is inst0=0x6b ; registerA8 ; B_BITS_0_15
{
ptr:4 = cpool(0:4,B_BITS_0_15:4,$(CPOOL_STATIC_FIELD));
*ptr = registerA8:1;
}
:sput_char registerA8,B_BITS_0_15 is inst0=0x6c ; registerA8 ; B_BITS_0_15
{
ptr:4 = cpool(0:4,B_BITS_0_15:4,$(CPOOL_STATIC_FIELD));
*ptr = registerA8:2;
}
:sput_short registerA8,B_BITS_0_15 is inst0=0x6d ; registerA8 ; B_BITS_0_15
{
ptr:4 = cpool(0:4,B_BITS_0_15:4,$(CPOOL_STATIC_FIELD));
*ptr = registerA8:2;
}
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
# Call the indicated method. The result (if any) may be stored with
# an appropriate move-result* variant as the immediately subsequent
# instruction.
#
# A: argument word count (4 bits)
# B: method reference index (16 bits)
# C..G: argument registers (4 bits each)
# invoke-virtual is used to invoke a normal virtual method
# (a method that is not private, static, or final, and is also not a constructor).
:invoke_virtual METHOD_INDEX is inst0=0x6e ; N_PARAMS=0 & METHOD_INDEX
{
destination:4 = cpool( 0:4, METHOD_INDEX:4, $(CPOOL_METHOD));
call [ destination ];
}
:invoke_virtual METHOD_INDEX,regParamC is inst0=0x6e ; N_PARAMS=1 & METHOD_INDEX & regParamC
{
iv0 = regParamC;
destination:4 = cpool( regParamC, METHOD_INDEX:4, $(CPOOL_METHOD));
call [ destination ];
}
:invoke_virtual METHOD_INDEX,regParamC,regParamD is inst0=0x6e ; N_PARAMS=2 & METHOD_INDEX & regParamC & regParamD
{
iv0 = regParamC;
iv1 = regParamD;
destination:4 = cpool( regParamC, METHOD_INDEX:4, $(CPOOL_METHOD));
call [ destination ];
}
:invoke_virtual METHOD_INDEX,regParamC,regParamD,regParamE is inst0=0x6e ; N_PARAMS=3 & METHOD_INDEX & regParamC & regParamD & regParamE
{
iv0 = regParamC;
iv1 = regParamD;
iv2 = regParamE;
destination:4 = cpool( regParamC, METHOD_INDEX:4, $(CPOOL_METHOD));
call [ destination ];
}
:invoke_virtual METHOD_INDEX,regParamC,regParamD,regParamE,regParamF is inst0=0x6e ; N_PARAMS=4 & METHOD_INDEX & regParamC & regParamD & regParamE & regParamF
{
iv0 = regParamC;
iv1 = regParamD;
iv2 = regParamE;
iv3 = regParamF;
destination:4 = cpool( regParamC, METHOD_INDEX:4, $(CPOOL_METHOD));
call [ destination ];
}
:invoke_virtual METHOD_INDEX,regParamC,regParamD,regParamE,regParamF,regParamG is inst0=0x6e ; N_PARAMS=5 & METHOD_INDEX & regParamC & regParamD & regParamE & regParamF & regParamG
{
iv0 = regParamC;
iv1 = regParamD;
iv2 = regParamE;
iv3 = regParamF;
iv4 = regParamG;
destination:4 = cpool( regParamC, METHOD_INDEX:4, $(CPOOL_METHOD));
call [ destination ];
}
# invoke-super is used to invoke the closest superclass's virtual
# method (as opposed to the one with the same method_id in the
# calling class). The same method restrictions hold as for invoke-virtual.
:invoke_super METHOD_INDEX is inst0=0x6f ; N_PARAMS=0 & METHOD_INDEX
{
destination:4 = cpool( cpool( 0:4, 0:4, $(CPOOL_SUPER)), METHOD_INDEX:4, $(CPOOL_METHOD));
call [ destination ];
}
:invoke_super METHOD_INDEX,regParamC is inst0=0x6f ; N_PARAMS=1 & METHOD_INDEX & regParamC
{
iv0 = regParamC;
destination:4 = cpool( cpool( 0:4, 0:4, $(CPOOL_SUPER)), METHOD_INDEX:4, $(CPOOL_METHOD));
call [ destination ];
}
:invoke_super METHOD_INDEX,regParamC,regParamD is inst0=0x6f ; N_PARAMS=2 & METHOD_INDEX & regParamC & regParamD
{
iv0 = regParamC;
iv1 = regParamD;
destination:4 = cpool( cpool( 0:4, 0:4, $(CPOOL_SUPER)), METHOD_INDEX:4, $(CPOOL_METHOD));
call [ destination ];
}
:invoke_super METHOD_INDEX,regParamC,regParamD,regParamE is inst0=0x6f ; N_PARAMS=3 & METHOD_INDEX & regParamC & regParamD & regParamE
{
iv0 = regParamC;
iv1 = regParamD;
iv2 = regParamE;
destination:4 = cpool( cpool( 0:4, 0:4, $(CPOOL_SUPER)), METHOD_INDEX:4, $(CPOOL_METHOD));
call [ destination ];
}
:invoke_super METHOD_INDEX,regParamC,regParamD,regParamE,regParamF is inst0=0x6f ; N_PARAMS=4 & METHOD_INDEX & regParamC & regParamD & regParamE & regParamF
{
iv0 = regParamC;
iv1 = regParamD;
iv2 = regParamE;
iv3 = regParamF;
destination:4 = cpool( cpool( 0:4, 0:4, $(CPOOL_SUPER)), METHOD_INDEX:4, $(CPOOL_METHOD));
call [ destination ];
}
:invoke_super METHOD_INDEX,regParamC,regParamD,regParamE,regParamF,regParamG is inst0=0x6f ; N_PARAMS=5 & METHOD_INDEX & regParamC & regParamD & regParamE & regParamF & regParamG
{
iv0 = regParamC;
iv1 = regParamD;
iv2 = regParamE;
iv3 = regParamF;
iv4 = regParamG;
destination:4 = cpool( cpool( 0:4, 0:4, $(CPOOL_SUPER)), METHOD_INDEX:4, $(CPOOL_METHOD));
call [ destination ];
}
# invoke-direct is used to invoke a non-static direct
# method (that is, an instance method that is by its
# nature non-overridable, namely either a private instance
# method or a constructor).
:invoke_direct METHOD_INDEX is inst0=0x70 ; N_PARAMS=0 & METHOD_INDEX
{
destination:4 = cpool( 0:4, METHOD_INDEX, $(CPOOL_METHOD));
call [destination];
}
:invoke_direct METHOD_INDEX,regParamC is inst0=0x70 ; N_PARAMS=1 & METHOD_INDEX & regParamC
{
iv0 = regParamC;
destination:4 = cpool( regParamC, METHOD_INDEX, $(CPOOL_METHOD));
call [ destination ];
}
:invoke_direct METHOD_INDEX,regParamC,regParamD, is inst0=0x70 ; N_PARAMS=2 & METHOD_INDEX & regParamC & regParamD
{
iv0 = regParamC;
iv1 = regParamD;
destination:4 = cpool( regParamC, METHOD_INDEX, $(CPOOL_METHOD));
call [ destination ];
}
:invoke_direct METHOD_INDEX,regParamC,regParamD,regParamE is inst0=0x70 ; N_PARAMS=3 & METHOD_INDEX & regParamC & regParamD & regParamE
{
iv0 = regParamC;
iv1 = regParamD;
iv2 = regParamE;
destination:4 = cpool( regParamC, METHOD_INDEX, $(CPOOL_METHOD));
call [ destination ];
}
:invoke_direct METHOD_INDEX,regParamC,regParamD,regParamE,regParamF is inst0=0x70 ; N_PARAMS=4 & METHOD_INDEX & regParamC & regParamD & regParamE & regParamF
{
iv0 = regParamC;
iv1 = regParamD;
iv2 = regParamE;
iv3 = regParamF;
destination:4 = cpool( regParamC, METHOD_INDEX, $(CPOOL_METHOD));
call [ destination ];
}
:invoke_direct METHOD_INDEX,regParamC,regParamD,regParamE,regParamF,regParamG is inst0=0x70 ; N_PARAMS=5 & METHOD_INDEX & regParamC & regParamD & regParamE & regParamF & regParamG
{
iv0 = regParamC;
iv1 = regParamD;
iv2 = regParamE;
iv3 = regParamF;
iv4 = regParamG;
destination:4 = cpool( regParamC, METHOD_INDEX, $(CPOOL_METHOD));
call [ destination ];
}
# invoke-static is used to invoke a static method
# (which is always considered a direct method).
:invoke_static METHOD_INDEX is inst0=0x71 ; N_PARAMS=0 & METHOD_INDEX
{
destination:4 = cpool( 0:4, METHOD_INDEX, $(CPOOL_STATIC_METHOD));
call [ destination ];
}
:invoke_static METHOD_INDEX,regParamC is inst0=0x71 ; N_PARAMS=1 & METHOD_INDEX & regParamC
{
iv0 = regParamC;
destination:4 = cpool( 0:4, METHOD_INDEX, $(CPOOL_STATIC_METHOD));
call [ destination ];
}
:invoke_static METHOD_INDEX,regParamC,regParamD is inst0=0x71 ; N_PARAMS=2 & METHOD_INDEX & regParamC & regParamD
{
iv0 = regParamC;
iv1 = regParamD;
destination:4 = cpool( 0:4, METHOD_INDEX, $(CPOOL_STATIC_METHOD));
call [ destination ];
}
:invoke_static METHOD_INDEX,regParamC,regParamD,regParamE is inst0=0x71 ; N_PARAMS=3 & METHOD_INDEX & regParamC & regParamD & regParamE
{
iv0 = regParamC;
iv1 = regParamD;
iv2 = regParamE;
destination:4 = cpool( 0:4, METHOD_INDEX, $(CPOOL_STATIC_METHOD));
call [ destination ];
}
:invoke_static METHOD_INDEX,regParamC,regParamD,regParamE,regParamF is inst0=0x71 ; N_PARAMS=4 & METHOD_INDEX & regParamC & regParamD & regParamE & regParamF
{
iv0 = regParamC;
iv1 = regParamD;
iv2 = regParamE;
iv3 = regParamF;
destination:4 = cpool( 0:4, METHOD_INDEX, $(CPOOL_STATIC_METHOD));
call [ destination ];
}
:invoke_static METHOD_INDEX,regParamC,regParamD,regParamE,regParamF,regParamG is inst0=0x71 ; N_PARAMS=5 & METHOD_INDEX & regParamC & regParamD & regParamE & regParamF & regParamG
{
iv0 = regParamC;
iv1 = regParamD;
iv2 = regParamE;
iv3 = regParamF;
iv4 = regParamG;
destination:4 = cpool( 0:4, METHOD_INDEX, $(CPOOL_STATIC_METHOD));
call [ destination ];
}
# invoke-interface is used to invoke an interface
# method, that is, on an object whose concrete
# class isn't known, using a method_id that refers
# to an interface.
:invoke_interface METHOD_INDEX is inst0=0x72 ; N_PARAMS=0 & METHOD_INDEX
{
destination:4 = cpool( 0:4, METHOD_INDEX,$(CPOOL_METHOD));
call [ destination ];
}
:invoke_interface METHOD_INDEX,regParamC is inst0=0x72 ; N_PARAMS=1 & METHOD_INDEX & regParamC
{
iv0 = regParamC;
destination:4 = cpool(regParamC,METHOD_INDEX,$(CPOOL_METHOD));
call [ destination ];
}
:invoke_interface METHOD_INDEX,regParamC,regParamD is inst0=0x72 ; N_PARAMS=2 & METHOD_INDEX & regParamC & regParamD
{
iv0 = regParamC;
iv1 = regParamD;
destination:4 = cpool(regParamC,METHOD_INDEX,$(CPOOL_METHOD));
call [ destination ];
}
:invoke_interface METHOD_INDEX,regParamC,regParamD,regParamE is inst0=0x72 ; N_PARAMS=3 & METHOD_INDEX & regParamC & regParamD & regParamE
{
iv0 = regParamC;
iv1 = regParamD;
iv2 = regParamE;
destination:4 = cpool(regParamC,METHOD_INDEX,$(CPOOL_METHOD));
call [ destination ];
}
:invoke_interface METHOD_INDEX,regParamC,regParamD,regParamE,regParamF is inst0=0x72 ; N_PARAMS=4 & METHOD_INDEX & regParamC & regParamD & regParamE & regParamF
{
iv0 = regParamC;
iv1 = regParamD;
iv2 = regParamE;
iv3 = regParamF;
destination:4 = cpool(regParamC,METHOD_INDEX,$(CPOOL_METHOD));
call [ destination ];
}
:invoke_interface METHOD_INDEX,regParamC,regParamD,regParamE,regParamF,regParamG is inst0=0x72 ; N_PARAMS=5 & METHOD_INDEX & regParamC & regParamD & regParamE & regParamF & regParamG
{
iv0 = regParamC;
iv1 = regParamD;
iv2 = regParamE;
iv3 = regParamF;
iv4 = regParamG;
destination:4 = cpool(regParamC,METHOD_INDEX,$(CPOOL_METHOD));
call [ destination ];
}
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
# 0x73 unused
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
# Call the indicated method.
# See first invoke-kind description above for details, caveats, and suggestions.
#
# A: argument word count (8 bits)
# B: method reference index (16 bits)
# C: first argument register (16 bits)
# N = A + C - 1
:invoke_virtual_range B_BITS_0_15,A_BITS_0_7,registerC16 is inst0=0x74 ; A_BITS_0_7 ; B_BITS_0_15 ; registerC16
{
moveRangeToIV( A_BITS_0_7:4, registerC16 );
destination:4 = cpool(registerC16, B_BITS_0_15:4, $(CPOOL_METHOD));
call [ destination ];
}
:invoke_super_range B_BITS_0_15,A_BITS_0_7,registerC16 is inst0=0x75 ; A_BITS_0_7 ; B_BITS_0_15 ; registerC16
{
moveRangeToIV( A_BITS_0_7:4, registerC16 );
destination:4 = cpool( cpool( 0:4, 0:4, $(CPOOL_SUPER)), B_BITS_0_15:4, $(CPOOL_METHOD));
call [ destination ];
}
:invoke_direct_range B_BITS_0_15,A_BITS_0_7,registerC16 is inst0=0x76 ; A_BITS_0_7 ; B_BITS_0_15 ; registerC16
{
moveRangeToIV( A_BITS_0_7:4, registerC16 );
destination:4 = cpool(registerC16, B_BITS_0_15:4, $(CPOOL_METHOD));
call [ destination ];
}
:invoke_static_range B_BITS_0_15,A_BITS_0_7,registerC16 is inst0=0x77 ; A_BITS_0_7 ; B_BITS_0_15 ; registerC16
{
moveRangeToIV( A_BITS_0_7:4, registerC16 );
destination:4 = cpool(0:4, B_BITS_0_15:4, $(CPOOL_STATIC_METHOD));
call [ destination ];
}
:invoke_interface_range B_BITS_0_15,A_BITS_0_7,registerC16 is inst0=0x78 ; A_BITS_0_7 ; B_BITS_0_15 ; registerC16
{
moveRangeToIV( A_BITS_0_7:4, registerC16 );
destination:4 = cpool(registerC16, B_BITS_0_15:4, $(CPOOL_METHOD));
call [ destination ];
}
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
# 0x79 unused
# 0x7a unused
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
# Perform the identified unary operation on the source register,
# storing the result in the destination register.
#
# A: destination register or pair (4 bits)
# B: source register or pair (4 bits)
:neg_int registerA4,registerB4 is inst0=0x7b ; registerA4 & registerB4
{
registerA4 = -registerB4;
}
:not_int registerA4,registerB4 is inst0=0x7c ; registerA4 & registerB4
{
registerA4 = ~registerB4;
}
:neg_long registerA4w,registerB4w is inst0=0x7d ; registerA4w & registerB4w
{
registerA4w = -registerB4w;
}
:not_long registerA4w,registerB4w is inst0=0x7e ; registerA4w & registerB4w
{
registerA4w = ~registerB4w;
}
:neg_float registerA4,registerB4 is inst0=0x7f ; registerA4 & registerB4
{
registerA4 = f-registerB4;
}
:neg_double registerA4,registerB4 is inst0=0x80 ; registerA4 & registerB4
{
registerA4 = f-registerB4;
}
:int_to_long registerA4w,registerB4 is inst0=0x81 ; registerA4w & registerB4
{
registerA4w = sext(registerB4);
}
:int_to_float registerA4,registerB4 is inst0=0x82 ; registerA4 & registerB4
{
registerA4 = int2float(registerB4);
}
:int_to_double registerA4w,registerB4 is inst0=0x83 ; registerA4w & registerB4
{
registerA4w = int2float(registerB4);
}
:long_to_int registerA4,registerB4w is inst0=0x84 ; registerA4 & registerB4w
{
registerA4 = registerB4w:4;
}
:long_to_float registerA4,registerB4w is inst0=0x85 ; registerA4 & registerB4w
{
registerA4 = int2float(registerB4w);
}
:long_to_double registerA4w,registerB4w is inst0=0x86 ; registerA4w & registerB4w
{
registerA4w = int2float(registerB4w);
}
:float_to_int registerA4,registerB4 is inst0=0x87 ; registerA4 & registerB4
{
registerA4 = trunc(registerB4);
}
:float_to_long registerA4w,registerB4 is inst0=0x88 ; registerA4w & registerB4
{
registerA4w = trunc(registerB4);
}
:float_to_double registerA4w,registerB4 is inst0=0x89 ; registerA4w & registerB4
{
registerA4w = float2float(registerB4);
}
:double_to_int registerA4,registerB4w is inst0=0x8a ; registerA4 & registerB4w
{
registerA4 = trunc(registerB4w);
}
:double_to_long registerA4w,registerB4w is inst0=0x8b ; registerA4w & registerB4w
{
registerA4w = trunc(registerB4w);
}
:double_to_float registerA4,registerB4w is inst0=0x8c ; registerA4 & registerB4w
{
registerA4 = float2float(registerB4w);
}
:int_to_byte registerA4,registerB4 is inst0=0x8d ; registerA4 & registerB4
{
registerA4 = sext(registerB4:1);
}
:int_to_char registerA4,registerB4 is inst0=0x8e ; registerA4 & registerB4
{
registerA4 = zext(registerB4:2);
}
:int_to_short registerA4,registerB4 is inst0=0x8f ; registerA4 & registerB4
{
registerA4 = sext(registerB4:2);
}
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
# Perform the identified binary operation on the two source registers,
# storing the result in the destination register.
#
# A: destination register or pair (8 bits)
# B: first source register or pair (8 bits)
# C: second source register or pair (8 bits)
:add_int registerA8,registerB8,registerC8 is inst0=0x90 ; registerA8 ; registerB8 ; registerC8
{
registerA8 = registerB8 + registerC8;
}
:sub_int registerA8,registerB8,registerC8 is inst0=0x91 ; registerA8 ; registerB8 ; registerC8
{
registerA8 = registerB8 - registerC8;
}
:mul_int registerA8,registerB8,registerC8 is inst0=0x92 ; registerA8 ; registerB8 ; registerC8
{
registerA8 = registerB8 * registerC8;
}
:div_int registerA8,registerB8,registerC8 is inst0=0x93 ; registerA8 ; registerB8 ; registerC8
{
registerA8 = registerB8 s/ registerC8;
}
:rem_int registerA8,registerB8,registerC8 is inst0=0x94 ; registerA8 ; registerB8 ; registerC8
{
registerA8 = registerB8 s% registerC8;
}
:and_int registerA8,registerB8,registerC8 is inst0=0x95 ; registerA8 ; registerB8 ; registerC8
{
registerA8 = registerB8 & registerC8;
}
:or_int registerA8,registerB8,registerC8 is inst0=0x96 ; registerA8 ; registerB8 ; registerC8
{
registerA8 = registerB8 | registerC8;
}
:xor_int registerA8,registerB8,registerC8 is inst0=0x97 ; registerA8 ; registerB8 ; registerC8
{
registerA8 = registerB8 ^ registerC8;
}
:shl_int registerA8,registerB8,registerC8 is inst0=0x98 ; registerA8 ; registerB8 ; registerC8
{
registerA8 = registerB8 << registerC8;
}
:shr_int registerA8,registerB8,registerC8 is inst0=0x99 ; registerA8 ; registerB8 ; registerC8
{
registerA8 = registerB8 s>> registerC8;
}
:ushr_int registerA8,registerB8,registerC8 is inst0=0x9a ; registerA8 ; registerB8 ; registerC8
{
registerA8 = registerB8 >> registerC8;
}
:add_long registerA8w,registerB8w,registerC8w is inst0=0x9b ; registerA8w ; registerB8w ; registerC8w
{
registerA8w = registerB8w + registerC8w;
}
:sub_long registerA8w,registerB8w,registerC8w is inst0=0x9c ; registerA8w ; registerB8w ; registerC8w
{
registerA8w = registerB8w - registerC8w;
}
:mul_long registerA8w,registerB8w,registerC8w is inst0=0x9d ; registerA8w ; registerB8w ; registerC8w
{
registerA8w = registerB8w * registerC8w;
}
:div_long registerA8w,registerB8w,registerC8w is inst0=0x9e ; registerA8w ; registerB8w ; registerC8w
{
registerA8w = registerB8w s/ registerC8w;
}
:rem_long registerA8w,registerB8w,registerC8w is inst0=0x9f ; registerA8w ; registerB8w ; registerC8w
{
registerA8w = registerB8w s% registerC8w;
}
:and_long registerA8w,registerB8w,registerC8w is inst0=0xa0 ; registerA8w ; registerB8w ; registerC8w
{
registerA8w = registerB8w & registerC8w;
}
:or_long registerA8w,registerB8w,registerC8w is inst0=0xa1 ; registerA8w ; registerB8w ; registerC8w
{
registerA8w = registerB8w | registerC8w;
}
:xor_long registerA8w,registerB8w,registerC8w is inst0=0xa2 ; registerA8w ; registerB8w ; registerC8w
{
registerA8w = registerB8w ^ registerC8w;
}
:shl_long registerA8w,registerB8w,registerC8 is inst0=0xa3 ; registerA8w ; registerB8w ; registerC8
{
registerA8w = registerB8w << registerC8;
}
:shr_long registerA8w,registerB8w,registerC8 is inst0=0xa4 ; registerA8w ; registerB8w ; registerC8
{
registerA8w = registerB8w s>> registerC8;
}
:ushr_long registerA8w,registerB8w,registerC8 is inst0=0xa5 ; registerA8w ; registerB8w ; registerC8
{
registerA8w = registerB8w >> registerC8;
}
:add_float registerA8,registerB8,registerC8 is inst0=0xa6 ; registerA8 ; registerB8 ; registerC8
{
registerA8 = registerB8 f+ registerC8;
}
:sub_float registerA8,registerB8,registerC8 is inst0=0xa7 ; registerA8 ; registerB8 ; registerC8
{
registerA8 = registerB8 f- registerC8;
}
:mul_float registerA8,registerB8,registerC8 is inst0=0xa8 ; registerA8 ; registerB8 ; registerC8
{
registerA8 = registerB8 f* registerC8;
}
:div_float registerA8,registerB8,registerC8 is inst0=0xa9 ; registerA8 ; registerB8 ; registerC8
{
registerA8 = registerB8 f/ registerC8;
}
:rem_float registerA8,registerB8,registerC8 is inst0=0xaa ; registerA8 ; registerB8 ; registerC8
{
registerA8 = registerB8 s% registerC8;#TODO how to tell floating point??
}
:add_double registerA8w,registerB8w,registerC8w is inst0=0xab ; registerA8w ; registerB8w ; registerC8w
{
registerA8w = registerB8w f+ registerC8w;
}
:sub_double registerA8w,registerB8w,registerC8w is inst0=0xac ; registerA8w ; registerB8w ; registerC8w
{
registerA8w = registerB8w f- registerC8w;
}
:mul_double registerA8w,registerB8w,registerC8w is inst0=0xad ; registerA8w ; registerB8w ; registerC8w
{
registerA8w = registerB8w f* registerC8w;
}
:div_double registerA8w,registerB8w,registerC8w is inst0=0xae ; registerA8w ; registerB8w ; registerC8w
{
registerA8w = registerB8w f/ registerC8w;
}
:rem_double registerA8w,registerB8w,registerC8w is inst0=0xaf ; registerA8w ; registerB8w ; registerC8w
{
registerA8w = registerB8w s% registerC8w;#TODO how to tell floating point??
}
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
# Perform the identified binary operation on the two source registers,
# storing the result in the first source register.
#
# A: destination and first source register or pair (4 bits)
# B: second source register or pair (4 bits)
:add_int_2addr registerA4,registerB4 is inst0=0xb0 ; registerA4 & registerB4
{
registerA4 = registerA4 + registerB4;
}
:sub_int_2addr registerA4,registerB4 is inst0=0xb1 ; registerA4 & registerB4
{
registerA4 = registerA4 - registerB4;
}
:mul_int_2addr registerA4,registerB4 is inst0=0xb2 ; registerA4 & registerB4
{
registerA4 = registerA4 * registerB4;
}
:div_int_2addr registerA4,registerB4 is inst0=0xb3 ; registerA4 & registerB4
{
registerA4 = registerA4 s/ registerB4;
}
:rem_int_2addr registerA4,registerB4 is inst0=0xb4 ; registerA4 & registerB4
{
registerA4 = registerA4 s% registerB4;
}
:and_int_2addr registerA4,registerB4 is inst0=0xb5 ; registerA4 & registerB4
{
registerA4 = registerA4 & registerB4;
}
:or_int_2addr registerA4,registerB4 is inst0=0xb6 ; registerA4 & registerB4
{
registerA4 = registerA4 | registerB4;
}
:xor_int_2addr registerA4,registerB4 is inst0=0xb7 ; registerA4 & registerB4
{
registerA4 = registerA4 ^ registerB4;
}
:shl_int_2addr registerA4,registerB4 is inst0=0xb8 ; registerA4 & registerB4
{
registerA4 = registerA4 << registerB4;
}
:shr_int_2addr registerA4,registerB4 is inst0=0xb9 ; registerA4 & registerB4
{
registerA4 = registerA4 s>> registerB4;
}
:ushr_int_2addr registerA4,registerB4 is inst0=0xba ; registerA4 & registerB4
{
registerA4 = registerA4 >> registerB4;
}
:add_long_2addr registerA4w,registerB4w is inst0=0xbb ; registerA4w & registerB4w
{
registerA4w = registerA4w + registerB4w;
}
:sub_long_2addr registerA4w,registerB4w is inst0=0xbc ; registerA4w & registerB4w
{
registerA4w= registerA4w - registerB4w;
}
:mul_long_2addr registerA4w,registerB4w is inst0=0xbd ; registerA4w & registerB4w
{
registerA4w = registerA4w * registerB4w;
}
:div_long_2addr registerA4w,registerB4w is inst0=0xbe ; registerA4w & registerB4w
{
registerA4w = registerA4w s/ registerB4w;
}
:rem_long_2addr registerA4w,registerB4w is inst0=0xbf ; registerA4w & registerB4w
{
registerA4w = registerA4w s% registerB4w;
}
:and_long_2addr registerA4w,registerB4w is inst0=0xc0 ; registerA4w & registerB4w
{
registerA4w = registerA4w & registerB4w;
}
:or_long_2addr registerA4w,registerB4w is inst0=0xc1 ; registerA4w & registerB4w
{
registerA4w = registerA4w | registerB4w;
}
:xor_long_2addr registerA4w,registerB4w is inst0=0xc2 ; registerA4w & registerB4w
{
registerA4w = registerA4w ^ registerB4w;
}
:shl_long_2addr registerA4w,registerB4 is inst0=0xc3 ; registerA4w & registerB4
{
registerA4w = registerA4w << registerB4;
}
:shr_long_2addr registerA4w,registerB4 is inst0=0xc4 ; registerA4w & registerB4
{
registerA4w = registerA4w s>> registerB4;
}
:ushr_long_2addr registerA4w,registerB4 is inst0=0xc5 ; registerA4w & registerB4
{
registerA4w = registerA4w >> registerB4;
}
:add_float_2addr registerA4,registerB4 is inst0=0xc6 ; registerA4 & registerB4
{
registerA4 = registerA4 f+ registerB4;
}
:sub_float_2addr registerA4,registerB4 is inst0=0xc7 ; registerA4 & registerB4
{
registerA4 = registerA4 f- registerB4;
}
:mul_float_2addr registerA4,registerB4 is inst0=0xc8 ; registerA4 & registerB4
{
registerA4 = registerA4 f* registerB4;
}
:div_float_2addr registerA4,registerB4 is inst0=0xc9 ; registerA4 & registerB4
{
registerA4 = registerA4 f/ registerB4;
}
:rem_float_2addr registerA4,registerB4 is inst0=0xca ; registerA4 & registerB4
{
registerA4 = registerA4 s% registerB4;
}
:add_double_2addr registerA4w,registerB4w is inst0=0xcb ; registerA4w & registerB4w
{
registerA4w = registerA4w f+ registerB4w;
}
:sub_double_2addr registerA4w,registerB4w is inst0=0xcc ; registerA4w & registerB4w
{
registerA4w = registerA4w f- registerB4w;
}
:mul_double_2addr registerA4w,registerB4w is inst0=0xcd ; registerA4w & registerB4w
{
registerA4w = registerA4w f* registerB4w;
}
:div_double_2addr registerA4w,registerB4w is inst0=0xce ; registerA4w & registerB4w
{
registerA4w = registerA4w f/ registerB4w;
}
:rem_double_2addr registerA4w,registerB4w is inst0=0xcf ; registerA4w & registerB4w
{
registerA4w = registerA4w s% registerB4w;
}
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
# Perform the indicated binary op on the indicated register (first argument)
# and literal value (second argument), storing the result in the destination
# register.
#
# A: destination register (4 bits)
# B: source register (4 bits)
# C: signed int constant (16 bits)
:add_int_lit16 registerA4,registerB4,C_BITS_0_15_S is inst0=0xd0 ; registerA4 & registerB4 ; C_BITS_0_15_S
{
registerA4 = registerB4 + C_BITS_0_15_S;
}
:rsub_int registerA4,registerB4,C_BITS_0_15_S is inst0=0xd1 ; registerA4 & registerB4 ; C_BITS_0_15_S
{
registerA4 = C_BITS_0_15_S - registerB4; # Twos-complement reverse subtraction.
}
:mul_int_lit16 registerA4,registerB4,C_BITS_0_15_S is inst0=0xd2 ; registerA4 & registerB4 ; C_BITS_0_15_S
{
registerA4 = registerB4 * C_BITS_0_15_S;
}
:div_int_lit16 registerA4,registerB4,C_BITS_0_15_S is inst0=0xd3 ; registerA4 & registerB4 ; C_BITS_0_15_S
{
registerA4 = registerB4 s/ C_BITS_0_15_S;
}
:rem_int_lit16 registerA4,registerB4,C_BITS_0_15_S is inst0=0xd4 ; registerA4 & registerB4 ; C_BITS_0_15_S
{
registerA4 = registerB4 s% C_BITS_0_15_S;
}
:and_int_lit16 registerA4,registerB4,C_BITS_0_15_S is inst0=0xd5 ; registerA4 & registerB4 ; C_BITS_0_15_S
{
registerA4 = registerB4 & C_BITS_0_15_S;
}
:or_int_lit16 registerA4,registerB4,C_BITS_0_15_S is inst0=0xd6 ; registerA4 & registerB4 ; C_BITS_0_15_S
{
registerA4 = registerB4 | C_BITS_0_15_S;
}
:xor_int_lit16 registerA4,registerB4,C_BITS_0_15_S is inst0=0xd7 ; registerA4 & registerB4 ; C_BITS_0_15_S
{
registerA4 = registerB4 ^ C_BITS_0_15_S;
}
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
# Perform the indicated binary op on the indicated register (first argument)
# and literal value (second argument), storing the result in the destination
# register.
#
# A: destination register (8 bits)
# B: source register (8 bits)
# C: signed int constant (8 bits)
:add_int_lit8 registerA8,registerB8,C_BITS_0_7_S is inst0=0xd8 ; registerA8 ; registerB8 ; C_BITS_0_7_S
{
registerA8 = registerB8 + C_BITS_0_7_S;
}
:rsub_int_lit8 registerA8,registerB8,C_BITS_0_7_S is inst0=0xd9 ; registerA8 ; registerB8 ; C_BITS_0_7_S
{
registerA8 = C_BITS_0_7_S - registerB8; # Twos-complement reverse subtraction.
}
:mul_int_lit8 registerA8,registerB8,C_BITS_0_7_S is inst0=0xda ; registerA8 ; registerB8 ; C_BITS_0_7_S
{
registerA8 = registerB8 * C_BITS_0_7_S;
}
:div_int_lit8 registerA8,registerB8,C_BITS_0_7_S is inst0=0xdb ; registerA8 ; registerB8 ; C_BITS_0_7_S
{
registerA8 = registerB8 s/ C_BITS_0_7_S;
}
:rem_int_lit8 registerA8,registerB8,C_BITS_0_7_S is inst0=0xdc ; registerA8 ; registerB8 ; C_BITS_0_7_S
{
registerA8 = registerB8 s% C_BITS_0_7_S;
}
:and_int_lit8 registerA8,registerB8,C_BITS_0_7_S is inst0=0xdd ; registerA8 ; registerB8 ; C_BITS_0_7_S
{
registerA8 = registerB8 & C_BITS_0_7_S;
}
:or_int_lit8 registerA8,registerB8,C_BITS_0_7_S is inst0=0xde ; registerA8 ; registerB8 ; C_BITS_0_7_S
{
registerA8 = registerB8 | C_BITS_0_7_S;
}
:xor_int_lit8 registerA8,registerB8,C_BITS_0_7_S is inst0=0xdf ; registerA8 ; registerB8 ; C_BITS_0_7_S
{
registerA8 = registerB8 ^ C_BITS_0_7_S;
}
:shl_int_lit8 registerA8,registerB8,C_BITS_0_7_S is inst0=0xe0 ; registerA8 ; registerB8 ; C_BITS_0_7_S
{
registerA8 = registerB8 << C_BITS_0_7_S;
}
:shr_int_lit8 registerA8,registerB8,C_BITS_0_7_S is inst0=0xe1 ; registerA8 ; registerB8 ; C_BITS_0_7_S
{
registerA8 = registerB8 s>> C_BITS_0_7_S;
}
:ushr_int_lit8 registerA8,registerB8,C_BITS_0_7_S is inst0=0xe2 ; registerA8 ; registerB8 ; C_BITS_0_7_S
{
registerA8 = registerB8 >> C_BITS_0_7_S; #TODO should this value be signed???
}
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
:iget_volatile registerA4,[registerB4:C_BITS_0_15] is inst0=0xe3 ; registerA4 & registerB4 ; C_BITS_0_15
{
registerA4 = getInstanceFieldVolatile( registerB4, C_BITS_0_15:16 );
}
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
:iput_volatile registerA4,[registerB4:C_BITS_0_15] is inst0=0xe4 ; registerA4 & registerB4 ; C_BITS_0_15
{
setInstanceFieldVolatile( registerB4, C_BITS_0_15:16, registerA4 );
}
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
:sget_volatile registerA8,B_BITS_0_15 is inst0=0xe5 ; registerA8 ; B_BITS_0_15
{
registerA8 = getStaticFieldVolatile( B_BITS_0_15:16 );
}
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
:sput_volatile registerA8,B_BITS_0_15 is inst0=0xe6 ; registerA8 ; B_BITS_0_15
{
setStaticFieldVolatile( B_BITS_0_15:16, registerA8 );
}
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
:iget_object_volatile registerA4,[registerB4:C_BITS_0_15] is inst0=0xe7 ; registerA4 & registerB4 ; C_BITS_0_15
{
registerA4 = getInstanceFieldVolatile( registerB4, C_BITS_0_15:16 );
}
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
:iget_wide_volatile registerA4w,[registerB4:C_BITS_0_15] is inst0=0xe8 ; registerA4w & registerB4 ; C_BITS_0_15
{
registerA4w = getInstanceFieldVolatile( registerB4, C_BITS_0_15:16 );
}
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
:iput_wide_volatile registerA4w,[registerB4:C_BITS_0_15] is inst0=0xe9 ; registerA4w & registerB4 ; C_BITS_0_15
{
setInstanceFieldVolatile( registerB4, C_BITS_0_15:16, registerA4w );
}
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
:sget_wide_volatile registerA8w,B_BITS_0_15 is inst0=0xea ; registerA8w ; B_BITS_0_15
{
registerA8w = getStaticFieldVolatile( B_BITS_0_15:16 );
}
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
:sput_wide_volatile registerA8w,B_BITS_0_15 is inst0=0xeb ; registerA8w ; B_BITS_0_15
{
setStaticFieldVolatile( B_BITS_0_15:16, registerA8w );
}
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
:iput_byte_quick registerA4,[registerB4:C_BITS_0_15] is inst0=0xec ; registerA4 & registerB4 ; C_BITS_0_15
{
setInstanceFieldQuick( registerB4, C_BITS_0_15:16, registerA4 );
}
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
:throw_verification_error registerA8,registerB16 is inst0=0xed ; registerA8 ; registerB16
{
registerA8 = registerB16;
}
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
:execute_inline INLINE,{} is inst0=0xee ; N_PARAMS=0 & INLINE
{
destination:4 = *[ram] ( ( 4 * INLINE:4 ) + 0xe0000000 );
call [ destination ];
}
:execute_inline INLINE,{regParamC} is inst0=0xee ; N_PARAMS=1 & INLINE & regParamC
{
destination:4 = *[ram] ( ( 4 * INLINE:4 ) + 0xe0000000 );
call [ destination ];
}
:execute_inline INLINE,{regParamC,regParamD} is inst0=0xee ; N_PARAMS=2 & INLINE & regParamC & regParamD
{
destination:4 = *[ram] ( ( 4 * INLINE:4 ) + 0xe0000000 );
call [ destination ];
}
:execute_inline INLINE,{regParamC,regParamD,regParamE} is inst0=0xee ; N_PARAMS=3 & INLINE & regParamC & regParamD & regParamE
{
destination:4 = *[ram] ( ( 4 * INLINE:4 ) + 0xe0000000 );
call [ destination ];
}
:execute_inline INLINE,{regParamC,regParamD,regParamE,regParamF} is inst0=0xee ; N_PARAMS=4 & INLINE & regParamC & regParamD & regParamE & regParamF
{
destination:4 = *[ram] ( ( 4 * INLINE:4 ) + 0xe0000000 );
call [ destination ];
}
:execute_inline INLINE,{regParamC,regParamD,regParamE,regParamF,regParamG} is inst0=0xee ; N_PARAMS=5 & INLINE & regParamC & regParamD & regParamE & regParamF & regParamG
{
destination:4 = *[ram] ( ( 4 * INLINE:4 ) + 0xe0000000 );
call [ destination ];
}
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
:execute_inline_range "inline@"^B_BITS_0_15,A_BITS_0_7,registerC16 is inst0=0xef ; A_BITS_0_7 ; B_BITS_0_15 ; registerC16
{
destination:4 = *[ram] ( ( 4 * B_BITS_0_15:4 ) + 0xe0000000 );
call [ destination ];
}
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
# THIS ODEX INSTRUCTION WAS VALID UNTIL API version 13 (OS Version 3.2.x)
# :invoke_direct_empty METHOD_INDEX is inst0=0xf0 ; N_PARAMS=0 & METHOD_INDEX
# {
# destination:4 = *[ram] ( ( 4 * METHOD_INDEX:4 ) + 0xe0000000 );
# call [ destination ];
# }
# :invoke_direct_empty METHOD_INDEX,regParamC is inst0=0xf0 ; N_PARAMS=1 & METHOD_INDEX & regParamC
# {
# destination:4 = *[ram] ( ( 4 * METHOD_INDEX:4 ) + 0xe0000000 );
# call [ destination ];
# }
# :invoke_direct_empty METHOD_INDEX,regParamC,regParamD is inst0=0xf0 ; N_PARAMS=2 & METHOD_INDEX & regParamC & regParamD
# {
# destination:4 = *[ram] ( ( 4 * METHOD_INDEX:4 ) + 0xe0000000 );
# call [ destination ];
# }
# :invoke_direct_empty METHOD_INDEX,regParamC,regParamD,regParamE is inst0=0xf0 ; N_PARAMS=3 & METHOD_INDEX & regParamC & regParamD & regParamE
# {
# destination:4 = *[ram] ( ( 4 * METHOD_INDEX:4 ) + 0xe0000000 );
# call [ destination ];
# }
# :invoke_direct_empty METHOD_INDEX,regParamC,regParamD,regParamE,regParamF is inst0=0xf0 ; N_PARAMS=4 & METHOD_INDEX & regParamC & regParamD & regParamE & regParamF
# {
# destination:4 = *[ram] ( ( 4 * METHOD_INDEX:4 ) + 0xe0000000 );
# call [ destination ];
# }
# :invoke_direct_empty METHOD_INDEX,regParamC,regParamD,regParamE,regParamF,regParamG is inst0=0xf0 ; N_PARAMS=5 & METHOD_INDEX & regParamC & regParamD & regParamE & regParamF & regParamG
# {
# destination:4 = *[ram] ( ( 4 * METHOD_INDEX:4 ) + 0xe0000000 );
# call [ destination ];
# }
# THIS ODEX INSTRUCTION WAS ADDED IN API version 14 (OS VERSIOn 4.0.x ICS)
:invoke_object_init_range B_BITS_0_15,A_BITS_0_7,registerC16 is inst0=0xf0 ; A_BITS_0_7 ; B_BITS_0_15 ; registerC16
{
destination:4 = *[ram] ( ( 4 * B_BITS_0_15:4 ) + 0xe0000000 );
call [ destination ];
}
# 0xf0 iget-byte-quick TODO All ART Versions
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
:return_void_barrier is inst1=0xf1 & inst1_padding
{
return [sp];#TODO
}
# 0xf1 iget-char-quick TODO
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
:iget_quick "field@"^C_BITS_0_15,registerA4,registerB4 is inst0=0xf2 ; registerA4 & registerB4 ; C_BITS_0_15
{
registerA4 = getInstanceFieldQuick( registerB4, C_BITS_0_15:16 );
}
# 0xf2 iget-short-quick TODO
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
:iget_wide_quick "field@"^C_BITS_0_15,registerA4w,registerB4 is inst0=0xf3 ; registerA4w & registerB4 ; C_BITS_0_15
{
registerA4w = getInstanceFieldQuick( registerB4, C_BITS_0_15:16 );
}
# 0xf3 invoke-lambda TODO
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
:iget_object_quick "field@"^C_BITS_0_15,registerA4,registerB4 is inst0=0xf4 ; registerA4 & registerB4 ; C_BITS_0_15
{
registerA4 = getInstanceFieldQuick( registerB4, C_BITS_0_15:16 );
}
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
:iput_quick "field@"^C_BITS_0_15,registerA4,registerB4 is inst0=0xf5 ; registerA4 & registerB4 ; C_BITS_0_15
{
setInstanceFieldQuick( registerB4, C_BITS_0_15:16, registerA4 );
}
# 0xf5 capture-variable TODO
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
:iput_wide_quick "field@"^C_BITS_0_15,registerA4w,registerB4 is inst0=0xf6 ; registerA4w & registerB4 ; C_BITS_0_15
{
setInstanceFieldQuick( registerB4, C_BITS_0_15:16, registerA4w );
}
# 0xf6 create-lambda TODO
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
:iput_object_quick "field@"^C_BITS_0_15,registerA4,registerB4 is inst0=0xf7 ; registerA4 & registerB4 ; C_BITS_0_15
{
setInstanceFieldQuick( registerB4, C_BITS_0_15:16, registerA4 );
}
# 0xf7 liberate-variable TODO
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
:invoke_virtual_quick "vtable@"^VTABLE_OFFSET is inst0=0xf8 ; N_PARAMS=0 & VTABLE_OFFSET
{
invokeVirtualQuick( VTABLE_OFFSET:4 );
}
:invoke_virtual_quick "vtable@"^VTABLE_OFFSET,regParamC is inst0=0xf8 ; N_PARAMS=1 & VTABLE_OFFSET & regParamC
{
invokeVirtualQuick( VTABLE_OFFSET:4, regParamC );
}
:invoke_virtual_quick "vtable@"^VTABLE_OFFSET,regParamC,regParamD is inst0=0xf8 ; N_PARAMS=2 & VTABLE_OFFSET & regParamC & regParamD
{
invokeVirtualQuick( VTABLE_OFFSET:4, regParamC, regParamD );
}
:invoke_virtual_quick "vtable@"^VTABLE_OFFSET,regParamC,regParamD,regParamE is inst0=0xf8 ; N_PARAMS=3 & VTABLE_OFFSET & regParamC & regParamD & regParamE
{
invokeVirtualQuick( VTABLE_OFFSET:4, regParamC, regParamD, regParamE );
}
:invoke_virtual_quick "vtable@"^VTABLE_OFFSET,regParamC,regParamD,regParamE,regParamF is inst0=0xf8 ; N_PARAMS=4 & VTABLE_OFFSET & regParamC & regParamD & regParamE & regParamF
{
invokeVirtualQuick( VTABLE_OFFSET:4, regParamC, regParamD, regParamE, regParamF );
}
:invoke_virtual_quick "vtable@"^VTABLE_OFFSET,regParamC,regParamD,regParamE,regParamF,regParamG is inst0=0xf8 ; N_PARAMS=5 & VTABLE_OFFSET & regParamC & regParamD & regParamE & regParamF & regParamG
{
invokeVirtualQuick( VTABLE_OFFSET:4, regParamC, regParamD, regParamE, regParamF, regParamG );
}
# 0xf8 box-lambda TODO
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
:invoke_virtual_quick_range "vtable@"^B_BITS_0_15,A_BITS_0_7,registerC16 is inst0=0xf9 ; A_BITS_0_7 ; B_BITS_0_15 ; registerC16
{
invokeVirtualQuickRange( B_BITS_0_15:4, A_BITS_0_7:4, registerC16 );
}
# 0xf9 unbox-lambda TODO
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
:invoke_super_quick "vtable@"^VTABLE_OFFSET is inst0=0xfa ; N_PARAMS=0 & VTABLE_OFFSET
{
invokeSuperQuick( VTABLE_OFFSET:4 );
}
:invoke_super_quick "vtable@"^VTABLE_OFFSET,regParamC is inst0=0xfa ; N_PARAMS=1 & VTABLE_OFFSET & regParamC
{
invokeSuperQuick( VTABLE_OFFSET:4, regParamC );
}
:invoke_super_quick "vtable@"^VTABLE_OFFSET,regParamC,regParamD is inst0=0xfa ; N_PARAMS=2 & VTABLE_OFFSET & regParamC & regParamD
{
invokeSuperQuick( VTABLE_OFFSET:4, regParamC, regParamD );
}
:invoke_super_quick "vtable@"^VTABLE_OFFSET,regParamC,regParamD,regParamE is inst0=0xfa ; N_PARAMS=3 & VTABLE_OFFSET & regParamC & regParamD & regParamE
{
invokeSuperQuick( VTABLE_OFFSET:4, regParamC, regParamD, regParamE );
}
:invoke_super_quick "vtable@"^VTABLE_OFFSET,regParamC,regParamD,regParamE,regParamF is inst0=0xfa ; N_PARAMS=4 & VTABLE_OFFSET & regParamC & regParamD & regParamE & regParamF
{
invokeSuperQuick( VTABLE_OFFSET:4, regParamC, regParamD, regParamE, regParamF );
}
:invoke_super_quick "vtable@"^VTABLE_OFFSET,regParamC,regParamD,regParamE,regParamF,regParamG is inst0=0xfa ; N_PARAMS=5 & VTABLE_OFFSET & regParamC & regParamD & regParamE & regParamF & regParamG
{
invokeSuperQuick( VTABLE_OFFSET:4, regParamC, regParamD, regParamE, regParamF, regParamG );
}
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
:invoke_super_quick_range "vtable@"^B_BITS_0_15,A_BITS_0_7,registerC16 is inst0=0xfb ; A_BITS_0_7 ; B_BITS_0_15 ; registerC16
{
invokeSuperQuickRange( B_BITS_0_15:4, A_BITS_0_7:4, registerC16 );
}
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
:iput_object_volatile registerA4,registerB4,C_BITS_0_15 is inst0=0xfc ; registerA4 & registerB4 ; C_BITS_0_15
{
setInstanceFieldVolatile( registerB4, C_BITS_0_15:16, registerA4 );
}
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
:sget_object_volatile registerA8,B_BITS_0_15 is inst0=0xfd ; registerA8 ; B_BITS_0_15
{
registerA8 = getStaticFieldVolatile( B_BITS_0_15:16 );
}
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
:sput_object_volatile registerA8,B_BITS_0_15 is inst0=0xfe ; registerA8 ; B_BITS_0_15
{
setStaticFieldVolatile( B_BITS_0_15:16, registerA8 );
}
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------
# 0xff ?
#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------