#------------------------------------------------------------------------------------
#	Sleigh specification file for DALVIK VM
#------------------------------------------------------------------------------------

# Source:
# https://android.googlesource.com/platform/art/+/[...]/runtime/dex_instruction_list.h
#		where [...] is the actual Android version name (ie "oreo-release")

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;

define pcodeop breakpoint;

#SOURCE:  https://android.googlesource.com/platform/art/+/kitkat-dev/runtime/dex_instruction_list.h

#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------

# 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:4      =  *[ram] ( inst_start + distance );
	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;
}

#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------

# 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 ];
}

#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------

# 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 ];
} 

#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------

# 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???
}

#------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------

