11use crate :: {
22 types:: instruction:: {
3- ApUpdate , FpUpdate , Instruction , Op1Addr , Opcode , PcUpdate , Register , Res ,
3+ ApUpdate , FpUpdate , Instruction , Op1Addr , Opcode , OpcodeExtension , PcUpdate , Register , Res ,
44 } ,
55 vm:: errors:: vm_errors:: VirtualMachineError ,
66} ;
77
8- // 0 | 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+ // ... 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.
11+ /// Decodes an instruction. The encoding is little endian, so flags go from bit 64 to 48.
1212pub fn decode_instruction ( encoded_instr : u64 ) -> Result < Instruction , VirtualMachineError > {
13- const HIGH_BIT : u64 = 1u64 << 63 ;
1413 const DST_REG_MASK : u64 = 0x0001 ;
1514 const DST_REG_OFF : u64 = 0 ;
1615 const OP0_REG_MASK : u64 = 0x0002 ;
@@ -25,25 +24,23 @@ pub fn decode_instruction(encoded_instr: u64) -> Result<Instruction, VirtualMach
2524 const AP_UPDATE_OFF : u64 = 10 ;
2625 const OPCODE_MASK : u64 = 0x7000 ;
2726 const OPCODE_OFF : u64 = 12 ;
27+ const OPCODE_EXTENSION_OFF : u64 = 63 ;
2828
2929 // Flags start on the 48th bit.
3030 const FLAGS_OFFSET : u64 = 48 ;
31+ const FLAGS_MASK : u64 = 0x7FFF ;
3132 const OFF0_OFF : u64 = 0 ;
3233 const OFF1_OFF : u64 = 16 ;
3334 const OFF2_OFF : u64 = 32 ;
3435 const OFFX_MASK : u64 = 0xFFFF ;
3536
36- if encoded_instr & HIGH_BIT != 0 {
37- return Err ( VirtualMachineError :: InstructionNonZeroHighBit ) ;
38- }
39-
4037 // Grab offsets and convert them from little endian format.
4138 let off0 = decode_offset ( encoded_instr >> OFF0_OFF & OFFX_MASK ) ;
4239 let off1 = decode_offset ( encoded_instr >> OFF1_OFF & OFFX_MASK ) ;
4340 let off2 = decode_offset ( encoded_instr >> OFF2_OFF & OFFX_MASK ) ;
4441
4542 // Grab flags
46- let flags = encoded_instr >> FLAGS_OFFSET ;
43+ let flags = ( encoded_instr >> FLAGS_OFFSET ) & FLAGS_MASK ;
4744 // Grab individual flags
4845 let dst_reg_num = ( flags & DST_REG_MASK ) >> DST_REG_OFF ;
4946 let op0_reg_num = ( flags & OP0_REG_MASK ) >> OP0_REG_OFF ;
@@ -53,6 +50,9 @@ pub fn decode_instruction(encoded_instr: u64) -> Result<Instruction, VirtualMach
5350 let ap_update_num = ( flags & AP_UPDATE_MASK ) >> AP_UPDATE_OFF ;
5451 let opcode_num = ( flags & OPCODE_MASK ) >> OPCODE_OFF ;
5552
53+ // Grab opcode_extension
54+ let opcode_extension_num = encoded_instr >> OPCODE_EXTENSION_OFF ;
55+
5656 // Match each flag to its corresponding enum value
5757 let dst_register = if dst_reg_num == 1 {
5858 Register :: FP
@@ -98,6 +98,15 @@ pub fn decode_instruction(encoded_instr: u64) -> Result<Instruction, VirtualMach
9898 _ => return Err ( VirtualMachineError :: InvalidOpcode ( opcode_num) ) ,
9999 } ;
100100
101+ let opcode_extension = match opcode_extension_num {
102+ 0 => OpcodeExtension :: Stone ,
103+ _ => {
104+ return Err ( VirtualMachineError :: InvalidOpcodeExtension (
105+ opcode_extension_num,
106+ ) )
107+ }
108+ } ;
109+
101110 let ap_update = match ( ap_update_num, opcode == Opcode :: Call ) {
102111 ( 0 , true ) => ApUpdate :: Add2 ,
103112 ( 0 , false ) => ApUpdate :: Regular ,
@@ -145,6 +154,7 @@ pub fn decode_instruction(encoded_instr: u64) -> Result<Instruction, VirtualMach
145154 ap_update,
146155 fp_update,
147156 opcode,
157+ opcode_extension,
148158 } )
149159}
150160
@@ -165,16 +175,6 @@ mod decoder_test {
165175 #[ cfg( target_arch = "wasm32" ) ]
166176 use wasm_bindgen_test:: * ;
167177
168- #[ test]
169- #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
170- fn non_zero_high_bit ( ) {
171- let error = decode_instruction ( 0x94A7800080008000 ) ;
172- assert_eq ! (
173- error. unwrap_err( ) . to_string( ) ,
174- "Instruction MSB should be 0" ,
175- )
176- }
177-
178178 #[ test]
179179 #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
180180 fn invalid_op1_reg ( ) {
@@ -221,10 +221,10 @@ mod decoder_test {
221221 #[ test]
222222 #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
223223 fn decode_flags_nop_add_jmp_add_imm_fp_fp ( ) {
224- // 0| 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
226- // | NOp| ADD| JUMP| ADD| IMM| FP| FP
227- // 0 0 0 0 0 1 0 0 1 0 1 0 0 1 1 1
224+ // 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
226+ // Stone| NOp| ADD| JUMP| ADD| IMM| FP| FP
227+ // 0 0 0 0 0 1 0 0 1 0 1 0 0 1 1 1
228228 // 0000 0100 1010 0111 = 0x04A7; offx = 0
229229 let inst = decode_instruction ( 0x04A7800080008000 ) . unwrap ( ) ;
230230 assert_matches ! ( inst. dst_register, Register :: FP ) ;
@@ -240,10 +240,10 @@ mod decoder_test {
240240 #[ test]
241241 #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
242242 fn decode_flags_nop_add1_jmp_rel_mul_fp_ap_ap ( ) {
243- // 0| 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
245- // | NOp| ADD1| JUMP_REL| MUL| FP| AP| AP
246- // 0 0 0 0 1 0 0 1 0 1 0 0 1 0 0 0
243+ // 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
245+ // Stone| NOp| ADD1| JUMP_REL| MUL| FP| AP| AP
246+ // 0 0 0 0 1 0 0 1 0 1 0 0 1 0 0 0
247247 // 0000 1001 0100 1000 = 0x0948; offx = 0
248248 let inst = decode_instruction ( 0x0948800080008000 ) . unwrap ( ) ;
249249 assert_matches ! ( inst. dst_register, Register :: AP ) ;
@@ -259,10 +259,10 @@ mod decoder_test {
259259 #[ test]
260260 #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
261261 fn decode_flags_assrt_add_regular_mul_ap_ap_ap ( ) {
262- // 0| 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
264- // | ASSRT_EQ| ADD| REGULAR| MUL| AP| AP| AP
265- // 0 1 0 0 1 0 0 0 0 1 0 1 0 0 0 0
262+ // 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
264+ // Stone| ASSRT_EQ| ADD| REGULAR| MUL| AP| AP| AP
265+ // 0 1 0 0 1 0 0 0 0 1 0 1 0 0 0 0
266266 // 0100 1000 0101 0000 = 0x4850; offx = 0
267267 let inst = decode_instruction ( 0x4850800080008000 ) . unwrap ( ) ;
268268 assert_matches ! ( inst. dst_register, Register :: AP ) ;
@@ -278,10 +278,10 @@ mod decoder_test {
278278 #[ test]
279279 #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
280280 fn decode_flags_assrt_add2_jnz_uncon_op0_ap_ap ( ) {
281- // 0| 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
283- // | ASSRT_EQ| ADD2| JNZ|UNCONSTRD| OP0| AP| AP
284- // 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0
281+ // 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
283+ // Stone| ASSRT_EQ| ADD2| JNZ|UNCONSTRD| OP0| AP| AP
284+ // 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0
285285 // 0100 0010 0000 0000 = 0x4200; offx = 0
286286 let inst = decode_instruction ( 0x4200800080008000 ) . unwrap ( ) ;
287287 assert_matches ! ( inst. dst_register, Register :: AP ) ;
@@ -297,10 +297,10 @@ mod decoder_test {
297297 #[ test]
298298 #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
299299 fn decode_flags_nop_regu_regu_op1_op0_ap_ap ( ) {
300- // 0| 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
302- // | NOP| REGULAR| REGULAR| OP1| OP0| AP| AP
303- // 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
300+ // 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
302+ // Stone| NOP| REGULAR| REGULAR| OP1| OP0| AP| AP
303+ // 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
304304 // 0000 0000 0000 0000 = 0x0000; offx = 0
305305 let inst = decode_instruction ( 0x0000800080008000 ) . unwrap ( ) ;
306306 assert_matches ! ( inst. dst_register, Register :: AP ) ;
@@ -316,10 +316,10 @@ mod decoder_test {
316316 #[ test]
317317 #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
318318 fn decode_offset_negative ( ) {
319- // 0| 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
321- // | NOP| REGULAR| REGULAR| OP1| OP0| AP| AP
322- // 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
319+ // 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
321+ // Stone| NOP| REGULAR| REGULAR| OP1| OP0| AP| AP
322+ // 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
323323 // 0000 0000 0000 0000 = 0x0000; offx = 0
324324 let inst = decode_instruction ( 0x0000800180007FFF ) . unwrap ( ) ;
325325 assert_eq ! ( inst. off0, -1 ) ;
@@ -330,10 +330,10 @@ mod decoder_test {
330330 #[ test]
331331 #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
332332 fn decode_ret_cairo_standard ( ) {
333- // 0| 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
335- // | RET| REGULAR| JUMP| Op1| FP| FP| FP
336- // 0 0 1 0 0 0 0 0 1 0 0 0 1 0 1 1
333+ // 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
335+ // Stone| RET| REGULAR| JUMP| Op1| FP| FP| FP
336+ // 0 0 1 0 0 0 0 0 1 0 0 0 1 0 1 1
337337 // 0010 0000 1000 1011 = 0x208b; off0 = -2, off1 = -1
338338 let inst = decode_instruction ( 0x208b7fff7fff7ffe ) . unwrap ( ) ;
339339 assert_matches ! ( inst. opcode, Opcode :: Ret ) ;
@@ -351,11 +351,11 @@ mod decoder_test {
351351 #[ test]
352352 #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
353353 fn decode_call_cairo_standard ( ) {
354- // 0| 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- // | CALL| Add2| JumpRel| Op1| FP| FP| FP
357- // 0 0 0 1 0 0 0 1 0 0 0 0 0 1 0 0
358- // 0001 0001 0000 0100 = 0x208b ; off0 = 0, off1 = 1
354+ // 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
357+ // 0 0 0 1 0 0 0 1 0 0 0 0 0 1 0 0
358+ // 0001 0001 0000 0100 = 0x1104 ; off0 = 0, off1 = 1
359359 let inst = decode_instruction ( 0x1104800180018000 ) . unwrap ( ) ;
360360 assert_matches ! ( inst. opcode, Opcode :: Call ) ;
361361 assert_matches ! ( inst. off0, 0 ) ;
@@ -372,10 +372,10 @@ mod decoder_test {
372372 #[ test]
373373 #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
374374 fn decode_ret_opcode_error ( ) {
375- // 0| 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
377- // | RET| REGULAR| JUMP| Op1| FP| FP| FP
378- // 0 0 1 0 0 0 0 0 1 0 0 0 1 0 1 1
375+ // 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
377+ // Stone| RET| REGULAR| JUMP| Op1| FP| FP| FP
378+ // 0 0 1 0 0 0 0 0 1 0 0 0 1 0 1 1
379379 // 0010 0000 1000 1011 = 0x208b; off0 = -1, off1 = -1
380380 let error = decode_instruction ( 0x208b7fff7fff7fff ) ;
381381 assert_matches ! ( error, Err ( VirtualMachineError :: InvalidOpcode ( 2 ) ) ) ;
@@ -384,11 +384,11 @@ mod decoder_test {
384384 #[ test]
385385 #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
386386 fn decode_call_opcode_error ( ) {
387- // 0| 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- // | CALL| Add2| JumpRel| Op1| FP| FP| FP
390- // 0 0 0 1 0 0 0 1 0 0 0 0 0 1 0 0
391- // 0001 0001 0000 0100 = 0x208b ; off0 = 1, off1 = 1
387+ // 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
390+ // 0 0 0 1 0 0 0 1 0 0 0 0 0 1 0 0
391+ // 0001 0001 0000 0100 = 0x1104 ; off0 = 1, off1 = 1
392392 let error = decode_instruction ( 0x1104800180018001 ) ;
393393 assert_matches ! ( error, Err ( VirtualMachineError :: InvalidOpcode ( 1 ) ) ) ;
394394 }
0 commit comments