Skip to content

Commit e15c6e6

Browse files
introduce opcode_extension to the structure of Instruction.
1 parent df12864 commit e15c6e6

File tree

6 files changed

+139
-63
lines changed

6 files changed

+139
-63
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
#### Upcoming Changes
44

5+
* feat: add the field `opcode_extension` to the structure of `Instruction` [#1933](https://github.com/lambdaclass/cairo-vm/pull/1933)
6+
57
* fix(BREAKING): Fix no trace padding flow in proof mode [#1909](https://github.com/lambdaclass/cairo-vm/pull/1909)
68

79
* refactor: Limit ret opcode decodeing to Cairo0's standards. [#1925](https://github.com/lambdaclass/cairo-vm/pull/1925)

vm/src/types/instruction.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ pub struct Instruction {
2727
pub ap_update: ApUpdate,
2828
pub fp_update: FpUpdate,
2929
pub opcode: Opcode,
30+
pub opcode_extension: OpcodeExtension,
3031
}
3132

3233
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
@@ -76,6 +77,11 @@ pub enum Opcode {
7677
Ret,
7778
}
7879

80+
#[derive(Clone, Debug, Copy, PartialEq, Eq)]
81+
pub enum OpcodeExtension {
82+
Stone,
83+
}
84+
7985
impl Instruction {
8086
pub fn size(&self) -> usize {
8187
match self.op1_addr {

vm/src/vm/context/run_context.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ mod tests {
106106
use super::*;
107107
use crate::relocatable;
108108
use crate::stdlib::string::ToString;
109-
use crate::types::instruction::{ApUpdate, FpUpdate, Opcode, PcUpdate, Res};
109+
use crate::types::instruction::{ApUpdate, FpUpdate, Opcode, OpcodeExtension, PcUpdate, Res};
110110
use crate::utils::test_utils::mayberelocatable;
111111
use crate::vm::errors::memory_errors::MemoryError;
112112
use crate::Felt252;
@@ -130,6 +130,7 @@ mod tests {
130130
ap_update: ApUpdate::Regular,
131131
fp_update: FpUpdate::Regular,
132132
opcode: Opcode::NOp,
133+
opcode_extension: OpcodeExtension::Stone,
133134
};
134135

135136
let run_context = RunContext {
@@ -158,6 +159,7 @@ mod tests {
158159
ap_update: ApUpdate::Regular,
159160
fp_update: FpUpdate::Regular,
160161
opcode: Opcode::NOp,
162+
opcode_extension: OpcodeExtension::Stone,
161163
};
162164

163165
let run_context = RunContext {
@@ -187,6 +189,7 @@ mod tests {
187189
ap_update: ApUpdate::Regular,
188190
fp_update: FpUpdate::Regular,
189191
opcode: Opcode::NOp,
192+
opcode_extension: OpcodeExtension::Stone,
190193
};
191194

192195
let run_context = RunContext {
@@ -215,6 +218,7 @@ mod tests {
215218
ap_update: ApUpdate::Regular,
216219
fp_update: FpUpdate::Regular,
217220
opcode: Opcode::NOp,
221+
opcode_extension: OpcodeExtension::Stone,
218222
};
219223

220224
let run_context = RunContext {
@@ -243,6 +247,7 @@ mod tests {
243247
ap_update: ApUpdate::Regular,
244248
fp_update: FpUpdate::Regular,
245249
opcode: Opcode::NOp,
250+
opcode_extension: OpcodeExtension::Stone,
246251
};
247252

248253
let run_context = RunContext {
@@ -271,6 +276,7 @@ mod tests {
271276
ap_update: ApUpdate::Regular,
272277
fp_update: FpUpdate::Regular,
273278
opcode: Opcode::NOp,
279+
opcode_extension: OpcodeExtension::Stone,
274280
};
275281

276282
let run_context = RunContext {
@@ -299,6 +305,7 @@ mod tests {
299305
ap_update: ApUpdate::Regular,
300306
fp_update: FpUpdate::Regular,
301307
opcode: Opcode::NOp,
308+
opcode_extension: OpcodeExtension::Stone,
302309
};
303310

304311
let run_context = RunContext {
@@ -327,6 +334,7 @@ mod tests {
327334
ap_update: ApUpdate::Regular,
328335
fp_update: FpUpdate::Regular,
329336
opcode: Opcode::NOp,
337+
opcode_extension: OpcodeExtension::Stone,
330338
};
331339

332340
let run_context = RunContext {
@@ -358,6 +366,7 @@ mod tests {
358366
ap_update: ApUpdate::Regular,
359367
fp_update: FpUpdate::Regular,
360368
opcode: Opcode::NOp,
369+
opcode_extension: OpcodeExtension::Stone,
361370
};
362371

363372
let run_context = RunContext {
@@ -388,6 +397,7 @@ mod tests {
388397
ap_update: ApUpdate::Regular,
389398
fp_update: FpUpdate::Regular,
390399
opcode: Opcode::NOp,
400+
opcode_extension: OpcodeExtension::Stone,
391401
};
392402

393403
let run_context = RunContext {
@@ -420,6 +430,7 @@ mod tests {
420430
ap_update: ApUpdate::Regular,
421431
fp_update: FpUpdate::Regular,
422432
opcode: Opcode::NOp,
433+
opcode_extension: OpcodeExtension::Stone,
423434
};
424435

425436
let run_context = RunContext {

vm/src/vm/decoding/decoder.rs

Lines changed: 62 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
use 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.
1212
pub 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
}

vm/src/vm/errors/vm_errors.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ pub enum VirtualMachineError {
7676
InvalidRes(u64),
7777
#[error("Invalid opcode value: {0}")]
7878
InvalidOpcode(u64),
79+
#[error("Invalid opcode extension value: {0}")]
80+
InvalidOpcodeExtension(u64),
7981
#[error("This is not implemented")]
8082
NotImplemented,
8183
#[error("Inconsistent auto-deduction for {}, expected {}, got {:?}", (*.0).0, (*.0).1, (*.0).2)]

0 commit comments

Comments
 (0)