@@ -5,36 +5,41 @@ use crate::{
55 vm:: errors:: vm_errors:: VirtualMachineError ,
66} ;
77
8- // opcode_extension| opcode|ap_update|pc_update|res_logic|op1_src|op0_reg|dst_reg
9- // ... 15|14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
8+ // opcode_extension| opcode|ap_update|pc_update|res_logic|op1_src|op0_reg|dst_reg
9+ // 79 ... 17 16 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
1010
11- /// Decodes an instruction. The encoding is little endian, so flags go from bit 63 to 48.
12- /// The bits 64 and beyond are reserved for the opcode extension.
11+ /// Decodes an instruction. The encoding is little endian, so flags go from bit 127 to 48.
12+ /// The bits 63 and beyond are reserved for the opcode extension.
1313/// opcode_extension_num=0 means the instruction is a Stone instruction.
14- /// opcode_extension_num>1 is for new Stwo opcodes.
15- pub fn decode_instruction ( encoded_instr : u64 ) -> Result < Instruction , VirtualMachineError > {
16- const DST_REG_MASK : u64 = 0x0001 ;
17- const DST_REG_OFF : u64 = 0 ;
18- const OP0_REG_MASK : u64 = 0x0002 ;
19- const OP0_REG_OFF : u64 = 1 ;
20- const OP1_SRC_MASK : u64 = 0x001C ;
21- const OP1_SRC_OFF : u64 = 2 ;
22- const RES_LOGIC_MASK : u64 = 0x0060 ;
23- const RES_LOGIC_OFF : u64 = 5 ;
24- const PC_UPDATE_MASK : u64 = 0x0380 ;
25- const PC_UPDATE_OFF : u64 = 7 ;
26- const AP_UPDATE_MASK : u64 = 0x0C00 ;
27- const AP_UPDATE_OFF : u64 = 10 ;
28- const OPCODE_MASK : u64 = 0x7000 ;
29- const OPCODE_OFF : u64 = 12 ;
30- const OPCODE_EXTENSION_OFF : u64 = 63 ;
14+ /// opcode_extension_num>0 is for new Stwo opcodes.
15+ pub fn decode_instruction ( encoded_instr : u128 ) -> Result < Instruction , VirtualMachineError > {
16+ const HIGH_BITS : u128 = ( ( 1 << 127 ) - ( 1 << 64 ) ) << 1 ;
17+ const DST_REG_MASK : u128 = 0x0001 ;
18+ const DST_REG_OFF : u128 = 0 ;
19+ const OP0_REG_MASK : u128 = 0x0002 ;
20+ const OP0_REG_OFF : u128 = 1 ;
21+ const OP1_SRC_MASK : u128 = 0x001C ;
22+ const OP1_SRC_OFF : u128 = 2 ;
23+ const RES_LOGIC_MASK : u128 = 0x0060 ;
24+ const RES_LOGIC_OFF : u128 = 5 ;
25+ const PC_UPDATE_MASK : u128 = 0x0380 ;
26+ const PC_UPDATE_OFF : u128 = 7 ;
27+ const AP_UPDATE_MASK : u128 = 0x0C00 ;
28+ const AP_UPDATE_OFF : u128 = 10 ;
29+ const OPCODE_MASK : u128 = 0x7000 ;
30+ const OPCODE_OFF : u128 = 12 ;
31+ const OPCODE_EXTENSION_OFF : u128 = 63 ;
3132
3233 // Flags start on the 48th bit.
33- const FLAGS_OFFSET : u64 = 48 ;
34- const OFF0_OFF : u64 = 0 ;
35- const OFF1_OFF : u64 = 16 ;
36- const OFF2_OFF : u64 = 32 ;
37- const OFFX_MASK : u64 = 0xFFFF ;
34+ const FLAGS_OFFSET : u128 = 48 ;
35+ const OFF0_OFF : u128 = 0 ;
36+ const OFF1_OFF : u128 = 16 ;
37+ const OFF2_OFF : u128 = 32 ;
38+ const OFFX_MASK : u128 = 0xFFFF ;
39+
40+ if ( encoded_instr & HIGH_BITS ) != 0 {
41+ return Err ( VirtualMachineError :: NonZeroReservedBits ) ;
42+ }
3843
3944 // Grab offsets and convert them from little endian format.
4045 let off0 = decode_offset ( encoded_instr >> OFF0_OFF & OFFX_MASK ) ;
@@ -160,8 +165,8 @@ pub fn decode_instruction(encoded_instr: u64) -> Result<Instruction, VirtualMach
160165 } )
161166}
162167
163- fn decode_offset ( offset : u64 ) -> isize {
164- let vectorized_offset: [ u8 ; 8 ] = offset. to_le_bytes ( ) ;
168+ fn decode_offset ( offset : u128 ) -> isize {
169+ let vectorized_offset: [ u8 ; 8 ] = ( offset as u64 ) . to_le_bytes ( ) ;
165170 let offset_16b_encoded = u16:: from_le_bytes ( [ vectorized_offset[ 0 ] , vectorized_offset[ 1 ] ] ) ;
166171 let complement_const = 0x8000u16 ;
167172 let ( offset_16b, _) = offset_16b_encoded. overflowing_sub ( complement_const) ;
@@ -177,6 +182,16 @@ mod decoder_test {
177182 #[ cfg( target_arch = "wasm32" ) ]
178183 use wasm_bindgen_test:: * ;
179184
185+ #[ test]
186+ #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
187+ fn non_zero_high_bits ( ) {
188+ let error = decode_instruction ( 0x214a7800080008000 ) ;
189+ assert_eq ! (
190+ error. unwrap_err( ) . to_string( ) ,
191+ "Reserved instruction bits must be 0" ,
192+ )
193+ }
194+
180195 #[ test]
181196 #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
182197 fn invalid_op1_reg ( ) {
@@ -224,7 +239,7 @@ mod decoder_test {
224239 #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
225240 fn decode_flags_nop_add_jmp_add_imm_fp_fp ( ) {
226241 // opcode_extension| opcode|ap_update|pc_update|res_logic|op1_src|op0_reg|dst_reg
227- // ... 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
242+ // 79 ... 17 16 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
228243 // Stone| NOp| ADD| JUMP| ADD| IMM| FP| FP
229244 // 0 0 0 0 0 1 0 0 1 0 1 0 0 1 1 1
230245 // 0000 0100 1010 0111 = 0x04A7; offx = 0
@@ -244,7 +259,7 @@ mod decoder_test {
244259 #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
245260 fn decode_flags_nop_add1_jmp_rel_mul_fp_ap_ap ( ) {
246261 // opcode_extension| opcode|ap_update|pc_update|res_logic|op1_src|op0_reg|dst_reg
247- // ... 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
262+ // 79 ... 17 16 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
248263 // Stone| NOp| ADD1| JUMP_REL| MUL| FP| AP| AP
249264 // 0 0 0 0 1 0 0 1 0 1 0 0 1 0 0 0
250265 // 0000 1001 0100 1000 = 0x0948; offx = 0
@@ -264,7 +279,7 @@ mod decoder_test {
264279 #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
265280 fn decode_flags_assrt_add_regular_mul_ap_ap_ap ( ) {
266281 // opcode_extension| opcode|ap_update|pc_update|res_logic|op1_src|op0_reg|dst_reg
267- // ... 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
282+ // 79 ... 17 16 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
268283 // Stone| ASSRT_EQ| ADD| REGULAR| MUL| AP| AP| AP
269284 // 0 1 0 0 1 0 0 0 0 1 0 1 0 0 0 0
270285 // 0100 1000 0101 0000 = 0x4850; offx = 0
@@ -284,7 +299,7 @@ mod decoder_test {
284299 #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
285300 fn decode_flags_assrt_add2_jnz_uncon_op0_ap_ap ( ) {
286301 // opcode_extension| opcode|ap_update|pc_update|res_logic|op1_src|op0_reg|dst_reg
287- // ... 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
302+ // 79 ... 17 16 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
288303 // Stone| ASSRT_EQ| ADD2| JNZ|UNCONSTRD| OP0| AP| AP
289304 // 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0
290305 // 0100 0010 0000 0000 = 0x4200; offx = 0
@@ -304,7 +319,7 @@ mod decoder_test {
304319 #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
305320 fn decode_flags_nop_regu_regu_op1_op0_ap_ap ( ) {
306321 // opcode_extension| opcode|ap_update|pc_update|res_logic|op1_src|op0_reg|dst_reg
307- // ... 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
322+ // 79 ... 17 16 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
308323 // Stone| NOP| REGULAR| REGULAR| OP1| OP0| AP| AP
309324 // 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
310325 // 0000 0000 0000 0000 = 0x0000; offx = 0
@@ -324,7 +339,7 @@ mod decoder_test {
324339 #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
325340 fn decode_offset_negative ( ) {
326341 // opcode_extension| opcode|ap_update|pc_update|res_logic|op1_src|op0_reg|dst_reg
327- // ... 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
342+ // 79 ... 17 16 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
328343 // Stone| NOP| REGULAR| REGULAR| OP1| OP0| AP| AP
329344 // 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
330345 // 0000 0000 0000 0000 = 0x0000; offx = 0
@@ -338,7 +353,7 @@ mod decoder_test {
338353 #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
339354 fn decode_ret_cairo_standard ( ) {
340355 // opcode_extension| opcode|ap_update|pc_update|res_logic|op1_src|op0_reg|dst_reg
341- // ... 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
356+ // 79 ... 17 16 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
342357 // Stone| RET| REGULAR| JUMP| Op1| FP| FP| FP
343358 // 0 0 1 0 0 0 0 0 1 0 0 0 1 0 1 1
344359 // 0010 0000 1000 1011 = 0x208b; off0 = -2, off1 = -1
@@ -360,8 +375,8 @@ mod decoder_test {
360375 #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
361376 fn decode_call_cairo_standard ( ) {
362377 // opcode_extension| opcode|ap_update|pc_update|res_logic|op1_src|op0_reg|dst_reg
363- // ... 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
364- // Stone| CALL| Add2 | JumpRel| Op1| IMM | FP| FP
378+ // 79 ... 17 16 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
379+ // Stone| CALL| Regular | JumpRel| Op1| FP | FP| FP
365380 // 0 0 0 1 0 0 0 1 0 0 0 0 0 1 0 0
366381 // 0001 0001 0000 0100 = 0x1104; off0 = 0, off1 = 1
367382 let inst = decode_instruction ( 0x1104800180018000 ) . unwrap ( ) ;
@@ -382,7 +397,7 @@ mod decoder_test {
382397 #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
383398 fn decode_ret_opcode_error ( ) {
384399 // opcode_extension| opcode|ap_update|pc_update|res_logic|op1_src|op0_reg|dst_reg
385- // ... 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
400+ // 79 ... 17 16 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
386401 // Stone| RET| REGULAR| JUMP| Op1| FP| FP| FP
387402 // 0 0 1 0 0 0 0 0 1 0 0 0 1 0 1 1
388403 // 0010 0000 1000 1011 = 0x208b; off0 = -1, off1 = -1
@@ -394,8 +409,8 @@ mod decoder_test {
394409 #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
395410 fn decode_call_opcode_error ( ) {
396411 // opcode_extension| opcode|ap_update|pc_update|res_logic|op1_src|op0_reg|dst_reg
397- // ... 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
398- // Stone| CALL| Add2 | JumpRel| Op1| FP | FP | FP
412+ // 79 ... 17 16 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
413+ // Stone| CALL| REGULAR | JumpRel| Op1| IMM | AP | AP
399414 // 0 0 0 1 0 0 0 1 0 0 0 0 0 1 0 0
400415 // 0001 0001 0000 0100 = 0x1104; off0 = 1, off1 = 1
401416 let error = decode_instruction ( 0x1104800180018001 ) ;
@@ -406,7 +421,7 @@ mod decoder_test {
406421 #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
407422 fn decode_invalid_opcode_extension_error ( ) {
408423 // opcode_extension| opcode|ap_update|pc_update|res_logic|op1_src|op0_reg|dst_reg
409- // ... 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
424+ // 79 ... 17 16 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
410425 // ???| CALL| Add2| JumpRel| Op1| IMM| FP| FP
411426 // 1 0 0 1 0 0 0 1 0 0 0 0 0 1 0 0
412427 // 1001 0001 0000 0100 = 0x9104; off0 = 0, off1 = 1
0 commit comments