@@ -5,37 +5,42 @@ 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
1111/// Decodes an instruction. The encoding is little endian, so flags go from bit 63 to 48.
1212/// The bits 64 and beyond are reserved for the opcode extension.
1313/// opcode_extension_num=0 means the instruction is a Stone instruction.
1414/// 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 ;
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 FLAGS_MASK : u64 = 0x7FFF ;
35- const OFF0_OFF : u64 = 0 ;
36- const OFF1_OFF : u64 = 16 ;
37- const OFF2_OFF : u64 = 32 ;
38- const OFFX_MASK : u64 = 0xFFFF ;
34+ const FLAGS_OFFSET : u128 = 48 ;
35+ const FLAGS_MASK : u128 = 0x7FFF ;
36+ const OFF0_OFF : u128 = 0 ;
37+ const OFF1_OFF : u128 = 16 ;
38+ const OFF2_OFF : u128 = 32 ;
39+ const OFFX_MASK : u128 = 0xFFFF ;
40+
41+ if ( encoded_instr & HIGH_BITS ) != 0 {
42+ return Err ( VirtualMachineError :: NonZeroReservedBits ) ;
43+ }
3944
4045 // Grab offsets and convert them from little endian format.
4146 let off0 = decode_offset ( encoded_instr >> OFF0_OFF & OFFX_MASK ) ;
@@ -161,8 +166,8 @@ pub fn decode_instruction(encoded_instr: u64) -> Result<Instruction, VirtualMach
161166 } )
162167}
163168
164- fn decode_offset ( offset : u64 ) -> isize {
165- let vectorized_offset: [ u8 ; 8 ] = offset. to_le_bytes ( ) ;
169+ fn decode_offset ( offset : u128 ) -> isize {
170+ let vectorized_offset: [ u8 ; 8 ] = ( offset as u64 ) . to_le_bytes ( ) ;
166171 let offset_16b_encoded = u16:: from_le_bytes ( [ vectorized_offset[ 0 ] , vectorized_offset[ 1 ] ] ) ;
167172 let complement_const = 0x8000u16 ;
168173 let ( offset_16b, _) = offset_16b_encoded. overflowing_sub ( complement_const) ;
@@ -178,6 +183,16 @@ mod decoder_test {
178183 #[ cfg( target_arch = "wasm32" ) ]
179184 use wasm_bindgen_test:: * ;
180185
186+ #[ test]
187+ #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
188+ fn non_zero_high_bits ( ) {
189+ let error = decode_instruction ( 0x214a7800080008000 ) ;
190+ assert_eq ! (
191+ error. unwrap_err( ) . to_string( ) ,
192+ "Reserved instruction bits must be 0" ,
193+ )
194+ }
195+
181196 #[ test]
182197 #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
183198 fn invalid_op1_reg ( ) {
@@ -225,7 +240,7 @@ mod decoder_test {
225240 #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
226241 fn decode_flags_nop_add_jmp_add_imm_fp_fp ( ) {
227242 // opcode_extension| opcode|ap_update|pc_update|res_logic|op1_src|op0_reg|dst_reg
228- // ... 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
243+ // 79 ... 17 16 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
229244 // Stone| NOp| ADD| JUMP| ADD| IMM| FP| FP
230245 // 0 0 0 0 0 1 0 0 1 0 1 0 0 1 1 1
231246 // 0000 0100 1010 0111 = 0x04A7; offx = 0
@@ -245,7 +260,7 @@ mod decoder_test {
245260 #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
246261 fn decode_flags_nop_add1_jmp_rel_mul_fp_ap_ap ( ) {
247262 // opcode_extension| opcode|ap_update|pc_update|res_logic|op1_src|op0_reg|dst_reg
248- // ... 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
263+ // 79 ... 17 16 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
249264 // Stone| NOp| ADD1| JUMP_REL| MUL| FP| AP| AP
250265 // 0 0 0 0 1 0 0 1 0 1 0 0 1 0 0 0
251266 // 0000 1001 0100 1000 = 0x0948; offx = 0
@@ -265,7 +280,7 @@ mod decoder_test {
265280 #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
266281 fn decode_flags_assrt_add_regular_mul_ap_ap_ap ( ) {
267282 // opcode_extension| opcode|ap_update|pc_update|res_logic|op1_src|op0_reg|dst_reg
268- // ... 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
283+ // 79 ... 17 16 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
269284 // Stone| ASSRT_EQ| ADD| REGULAR| MUL| AP| AP| AP
270285 // 0 1 0 0 1 0 0 0 0 1 0 1 0 0 0 0
271286 // 0100 1000 0101 0000 = 0x4850; offx = 0
@@ -285,7 +300,7 @@ mod decoder_test {
285300 #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
286301 fn decode_flags_assrt_add2_jnz_uncon_op0_ap_ap ( ) {
287302 // opcode_extension| opcode|ap_update|pc_update|res_logic|op1_src|op0_reg|dst_reg
288- // ... 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
303+ // 79 ... 17 16 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
289304 // Stone| ASSRT_EQ| ADD2| JNZ|UNCONSTRD| OP0| AP| AP
290305 // 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0
291306 // 0100 0010 0000 0000 = 0x4200; offx = 0
@@ -305,7 +320,7 @@ mod decoder_test {
305320 #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
306321 fn decode_flags_nop_regu_regu_op1_op0_ap_ap ( ) {
307322 // opcode_extension| opcode|ap_update|pc_update|res_logic|op1_src|op0_reg|dst_reg
308- // ... 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
323+ // 79 ... 17 16 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
309324 // Stone| NOP| REGULAR| REGULAR| OP1| OP0| AP| AP
310325 // 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
311326 // 0000 0000 0000 0000 = 0x0000; offx = 0
@@ -325,7 +340,7 @@ mod decoder_test {
325340 #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
326341 fn decode_offset_negative ( ) {
327342 // opcode_extension| opcode|ap_update|pc_update|res_logic|op1_src|op0_reg|dst_reg
328- // ... 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
343+ // 79 ... 17 16 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
329344 // Stone| NOP| REGULAR| REGULAR| OP1| OP0| AP| AP
330345 // 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
331346 // 0000 0000 0000 0000 = 0x0000; offx = 0
@@ -339,7 +354,7 @@ mod decoder_test {
339354 #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
340355 fn decode_ret_cairo_standard ( ) {
341356 // opcode_extension| opcode|ap_update|pc_update|res_logic|op1_src|op0_reg|dst_reg
342- // ... 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
357+ // 79 ... 17 16 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
343358 // Stone| RET| REGULAR| JUMP| Op1| FP| FP| FP
344359 // 0 0 1 0 0 0 0 0 1 0 0 0 1 0 1 1
345360 // 0010 0000 1000 1011 = 0x208b; off0 = -2, off1 = -1
@@ -361,8 +376,8 @@ mod decoder_test {
361376 #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
362377 fn decode_call_cairo_standard ( ) {
363378 // opcode_extension| opcode|ap_update|pc_update|res_logic|op1_src|op0_reg|dst_reg
364- // ... 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
365- // Stone| CALL| Add2 | JumpRel| Op1| IMM | FP| FP
379+ // 79 ... 17 16 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
380+ // Stone| CALL| Regular | JumpRel| Op1| FP | FP| FP
366381 // 0 0 0 1 0 0 0 1 0 0 0 0 0 1 0 0
367382 // 0001 0001 0000 0100 = 0x1104; off0 = 0, off1 = 1
368383 let inst = decode_instruction ( 0x1104800180018000 ) . unwrap ( ) ;
@@ -383,7 +398,7 @@ mod decoder_test {
383398 #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
384399 fn decode_ret_opcode_error ( ) {
385400 // opcode_extension| opcode|ap_update|pc_update|res_logic|op1_src|op0_reg|dst_reg
386- // ... 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
401+ // 79 ... 17 16 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
387402 // Stone| RET| REGULAR| JUMP| Op1| FP| FP| FP
388403 // 0 0 1 0 0 0 0 0 1 0 0 0 1 0 1 1
389404 // 0010 0000 1000 1011 = 0x208b; off0 = -1, off1 = -1
@@ -395,8 +410,8 @@ mod decoder_test {
395410 #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
396411 fn decode_call_opcode_error ( ) {
397412 // opcode_extension| opcode|ap_update|pc_update|res_logic|op1_src|op0_reg|dst_reg
398- // ... 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
399- // Stone| CALL| Add2 | JumpRel| Op1| FP | FP | FP
413+ // 79 ... 17 16 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
414+ // Stone| CALL| REGULAR | JumpRel| Op1| IMM | AP | AP
400415 // 0 0 0 1 0 0 0 1 0 0 0 0 0 1 0 0
401416 // 0001 0001 0000 0100 = 0x1104; off0 = 1, off1 = 1
402417 let error = decode_instruction ( 0x1104800180018001 ) ;
@@ -407,7 +422,7 @@ mod decoder_test {
407422 #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
408423 fn decode_invalid_opcode_extension_error ( ) {
409424 // opcode_extension| opcode|ap_update|pc_update|res_logic|op1_src|op0_reg|dst_reg
410- // ... 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
425+ // 79 ... 17 16 15| 14 13 12| 11 10| 9 8 7| 6 5|4 3 2| 1| 0
411426 // ???| CALL| Add2| JumpRel| Op1| IMM| FP| FP
412427 // 1 0 0 1 0 0 0 1 0 0 0 0 0 1 0 0
413428 // 1001 0001 0000 0100 = 0x9104; off0 = 0, off1 = 1
0 commit comments