@@ -5,34 +5,39 @@ 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+ // 31 ... 17 16 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
1010
1111/// Decodes an instruction. The encoding is little endian, so flags go from bit 64 to 48.
12- pub fn decode_instruction ( encoded_instr : u64 ) -> Result < Instruction , VirtualMachineError > {
13- const DST_REG_MASK : u64 = 0x0001 ;
14- const DST_REG_OFF : u64 = 0 ;
15- const OP0_REG_MASK : u64 = 0x0002 ;
16- const OP0_REG_OFF : u64 = 1 ;
17- const OP1_SRC_MASK : u64 = 0x001C ;
18- const OP1_SRC_OFF : u64 = 2 ;
19- const RES_LOGIC_MASK : u64 = 0x0060 ;
20- const RES_LOGIC_OFF : u64 = 5 ;
21- const PC_UPDATE_MASK : u64 = 0x0380 ;
22- const PC_UPDATE_OFF : u64 = 7 ;
23- const AP_UPDATE_MASK : u64 = 0x0C00 ;
24- const AP_UPDATE_OFF : u64 = 10 ;
25- const OPCODE_MASK : u64 = 0x7000 ;
26- const OPCODE_OFF : u64 = 12 ;
27- const OPCODE_EXTENSION_OFF : u64 = 63 ;
12+ pub fn decode_instruction ( encoded_instr : u128 ) -> Result < Instruction , VirtualMachineError > {
13+ const HIGH_BITS : u128 = ( ( 1 << 127 ) - ( 1 << 64 ) ) << 1 ;
14+ const DST_REG_MASK : u128 = 0x0001 ;
15+ const DST_REG_OFF : u128 = 0 ;
16+ const OP0_REG_MASK : u128 = 0x0002 ;
17+ const OP0_REG_OFF : u128 = 1 ;
18+ const OP1_SRC_MASK : u128 = 0x001C ;
19+ const OP1_SRC_OFF : u128 = 2 ;
20+ const RES_LOGIC_MASK : u128 = 0x0060 ;
21+ const RES_LOGIC_OFF : u128 = 5 ;
22+ const PC_UPDATE_MASK : u128 = 0x0380 ;
23+ const PC_UPDATE_OFF : u128 = 7 ;
24+ const AP_UPDATE_MASK : u128 = 0x0C00 ;
25+ const AP_UPDATE_OFF : u128 = 10 ;
26+ const OPCODE_MASK : u128 = 0x7000 ;
27+ const OPCODE_OFF : u128 = 12 ;
28+ const OPCODE_EXTENSION_OFF : u128 = 63 ;
2829
2930 // Flags start on the 48th bit.
30- const FLAGS_OFFSET : u64 = 48 ;
31- const FLAGS_MASK : u64 = 0x7FFF ;
32- const OFF0_OFF : u64 = 0 ;
33- const OFF1_OFF : u64 = 16 ;
34- const OFF2_OFF : u64 = 32 ;
35- const OFFX_MASK : u64 = 0xFFFF ;
31+ const FLAGS_OFFSET : u128 = 48 ;
32+ const FLAGS_MASK : u128 = 0x7FFF ;
33+ const OFF0_OFF : u128 = 0 ;
34+ const OFF1_OFF : u128 = 16 ;
35+ const OFF2_OFF : u128 = 32 ;
36+ const OFFX_MASK : u128 = 0xFFFF ;
37+
38+ if ( encoded_instr & HIGH_BITS ) != 0 {
39+ return Err ( VirtualMachineError :: NonZeroReservedBits ) ;
40+ }
3641
3742 // Grab offsets and convert them from little endian format.
3843 let off0 = decode_offset ( encoded_instr >> OFF0_OFF & OFFX_MASK ) ;
@@ -158,8 +163,8 @@ pub fn decode_instruction(encoded_instr: u64) -> Result<Instruction, VirtualMach
158163 } )
159164}
160165
161- fn decode_offset ( offset : u64 ) -> isize {
162- let vectorized_offset: [ u8 ; 8 ] = offset. to_le_bytes ( ) ;
166+ fn decode_offset ( offset : u128 ) -> isize {
167+ let vectorized_offset: [ u8 ; 8 ] = ( offset as u64 ) . to_le_bytes ( ) ;
163168 let offset_16b_encoded = u16:: from_le_bytes ( [ vectorized_offset[ 0 ] , vectorized_offset[ 1 ] ] ) ;
164169 let complement_const = 0x8000u16 ;
165170 let ( offset_16b, _) = offset_16b_encoded. overflowing_sub ( complement_const) ;
@@ -175,6 +180,16 @@ mod decoder_test {
175180 #[ cfg( target_arch = "wasm32" ) ]
176181 use wasm_bindgen_test:: * ;
177182
183+ #[ test]
184+ #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
185+ fn non_zero_high_bits ( ) {
186+ let error = decode_instruction ( 0x214a7800080008000 ) ;
187+ assert_eq ! (
188+ error. unwrap_err( ) . to_string( ) ,
189+ "Reserved instruction bits must be 0" ,
190+ )
191+ }
192+
178193 #[ test]
179194 #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
180195 fn invalid_op1_reg ( ) {
@@ -222,7 +237,7 @@ mod decoder_test {
222237 #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
223238 fn decode_flags_nop_add_jmp_add_imm_fp_fp ( ) {
224239 // opcode_extension| opcode|ap_update|pc_update|res_logic|op1_src|op0_reg|dst_reg
225- // ... 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
240+ // 31 ... 17 16 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
226241 // Stone| NOp| ADD| JUMP| ADD| IMM| FP| FP
227242 // 0 0 0 0 0 1 0 0 1 0 1 0 0 1 1 1
228243 // 0000 0100 1010 0111 = 0x04A7; offx = 0
@@ -241,7 +256,7 @@ mod decoder_test {
241256 #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
242257 fn decode_flags_nop_add1_jmp_rel_mul_fp_ap_ap ( ) {
243258 // opcode_extension| opcode|ap_update|pc_update|res_logic|op1_src|op0_reg|dst_reg
244- // ... 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
259+ // 31 ... 17 16 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
245260 // Stone| NOp| ADD1| JUMP_REL| MUL| FP| AP| AP
246261 // 0 0 0 0 1 0 0 1 0 1 0 0 1 0 0 0
247262 // 0000 1001 0100 1000 = 0x0948; offx = 0
@@ -260,7 +275,7 @@ mod decoder_test {
260275 #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
261276 fn decode_flags_assrt_add_regular_mul_ap_ap_ap ( ) {
262277 // opcode_extension| opcode|ap_update|pc_update|res_logic|op1_src|op0_reg|dst_reg
263- // ... 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
278+ // 31 ... 17 16 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
264279 // Stone| ASSRT_EQ| ADD| REGULAR| MUL| AP| AP| AP
265280 // 0 1 0 0 1 0 0 0 0 1 0 1 0 0 0 0
266281 // 0100 1000 0101 0000 = 0x4850; offx = 0
@@ -279,7 +294,7 @@ mod decoder_test {
279294 #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
280295 fn decode_flags_assrt_add2_jnz_uncon_op0_ap_ap ( ) {
281296 // opcode_extension| opcode|ap_update|pc_update|res_logic|op1_src|op0_reg|dst_reg
282- // ... 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
297+ // 31 ... 17 16 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
283298 // Stone| ASSRT_EQ| ADD2| JNZ|UNCONSTRD| OP0| AP| AP
284299 // 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0
285300 // 0100 0010 0000 0000 = 0x4200; offx = 0
@@ -298,7 +313,7 @@ mod decoder_test {
298313 #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
299314 fn decode_flags_nop_regu_regu_op1_op0_ap_ap ( ) {
300315 // opcode_extension| opcode|ap_update|pc_update|res_logic|op1_src|op0_reg|dst_reg
301- // ... 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
316+ // 31 ... 17 16 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
302317 // Stone| NOP| REGULAR| REGULAR| OP1| OP0| AP| AP
303318 // 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
304319 // 0000 0000 0000 0000 = 0x0000; offx = 0
@@ -317,7 +332,7 @@ mod decoder_test {
317332 #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
318333 fn decode_offset_negative ( ) {
319334 // opcode_extension| opcode|ap_update|pc_update|res_logic|op1_src|op0_reg|dst_reg
320- // ... 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
335+ // 31 ... 17 16 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
321336 // Stone| NOP| REGULAR| REGULAR| OP1| OP0| AP| AP
322337 // 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
323338 // 0000 0000 0000 0000 = 0x0000; offx = 0
@@ -331,7 +346,7 @@ mod decoder_test {
331346 #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
332347 fn decode_ret_cairo_standard ( ) {
333348 // opcode_extension| opcode|ap_update|pc_update|res_logic|op1_src|op0_reg|dst_reg
334- // ... 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
349+ // 31 ... 17 16 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
335350 // Stone| RET| REGULAR| JUMP| Op1| FP| FP| FP
336351 // 0 0 1 0 0 0 0 0 1 0 0 0 1 0 1 1
337352 // 0010 0000 1000 1011 = 0x208b; off0 = -2, off1 = -1
@@ -352,8 +367,8 @@ mod decoder_test {
352367 #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
353368 fn decode_call_cairo_standard ( ) {
354369 // opcode_extension| opcode|ap_update|pc_update|res_logic|op1_src|op0_reg|dst_reg
355- // ... 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
356- // Stone| CALL| Add2 | JumpRel| Op1| FP| FP| FP
370+ // 31 ... 17 16 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
371+ // Stone| CALL| Regular | JumpRel| Op1| FP| FP| FP
357372 // 0 0 0 1 0 0 0 1 0 0 0 0 0 1 0 0
358373 // 0001 0001 0000 0100 = 0x1104; off0 = 0, off1 = 1
359374 let inst = decode_instruction ( 0x1104800180018000 ) . unwrap ( ) ;
@@ -373,7 +388,7 @@ mod decoder_test {
373388 #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
374389 fn decode_ret_opcode_error ( ) {
375390 // opcode_extension| opcode|ap_update|pc_update|res_logic|op1_src|op0_reg|dst_reg
376- // ... 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
391+ // 31 ... 17 16 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
377392 // Stone| RET| REGULAR| JUMP| Op1| FP| FP| FP
378393 // 0 0 1 0 0 0 0 0 1 0 0 0 1 0 1 1
379394 // 0010 0000 1000 1011 = 0x208b; off0 = -1, off1 = -1
@@ -385,8 +400,8 @@ mod decoder_test {
385400 #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
386401 fn decode_call_opcode_error ( ) {
387402 // opcode_extension| opcode|ap_update|pc_update|res_logic|op1_src|op0_reg|dst_reg
388- // ... 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
389- // Stone| CALL| Add2 | JumpRel| Op1| FP | FP | FP
403+ // 31 ... 17 16 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
404+ // Stone| CALL| REGULAR | JumpRel| Op1| IMM | AP | AP
390405 // 0 0 0 1 0 0 0 1 0 0 0 0 0 1 0 0
391406 // 0001 0001 0000 0100 = 0x1104; off0 = 1, off1 = 1
392407 let error = decode_instruction ( 0x1104800180018001 ) ;
0 commit comments