1use crate::Felt252;
2use num_traits::ToPrimitive;
3use serde::{Deserialize, Serialize};
4
5use crate::vm::decoding::decoder::decode_instruction;
6
7#[cfg(feature = "test_utils")]
8use arbitrary::Arbitrary;
9
10#[cfg_attr(feature = "test_utils", derive(Arbitrary))]
11#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, Eq)]
12pub enum Register {
13 AP,
14 FP,
15}
16
17#[derive(Copy, Clone, Debug, PartialEq, Eq)]
18pub struct Instruction {
19 pub off0: isize,
20 pub off1: isize,
21 pub off2: isize,
22 pub dst_register: Register,
23 pub op0_register: Register,
24 pub op1_addr: Op1Addr,
25 pub res: Res,
26 pub pc_update: PcUpdate,
27 pub ap_update: ApUpdate,
28 pub fp_update: FpUpdate,
29 pub opcode: Opcode,
30 pub opcode_extension: OpcodeExtension,
31}
32
33#[derive(Copy, Clone, Debug, PartialEq, Eq)]
34pub enum Op1Addr {
35 Imm,
36 AP,
37 FP,
38 Op0,
39}
40
41#[derive(Copy, Clone, Debug, PartialEq, Eq)]
42pub enum Res {
43 Op1,
44 Add,
45 Mul,
46 Unconstrained,
47}
48
49#[derive(Copy, Clone, Debug, PartialEq, Eq)]
50pub enum PcUpdate {
51 Regular,
52 Jump,
53 JumpRel,
54 Jnz,
55}
56
57#[derive(Copy, Clone, Debug, PartialEq, Eq)]
58pub enum ApUpdate {
59 Regular,
60 Add,
61 Add1,
62 Add2,
63}
64
65#[derive(Copy, Clone, Debug, PartialEq, Eq)]
66pub enum FpUpdate {
67 Regular,
68 APPlus2,
69 Dst,
70}
71
72#[derive(Copy, Clone, Debug, PartialEq, Eq)]
73pub enum Opcode {
74 NOp,
75 AssertEq,
76 Call,
77 Ret,
78}
79
80#[derive(Clone, Debug, Copy, PartialEq, Eq)]
81pub enum OpcodeExtension {
82 Stone,
83 Blake,
84 BlakeFinalize,
85 QM31Operation,
86}
87
88impl Instruction {
89 pub fn size(&self) -> usize {
90 match self.op1_addr {
91 Op1Addr::Imm => 2,
92 _ => 1,
93 }
94 }
95}
96
97pub(crate) fn is_call_instruction(encoded_instruction: &Felt252) -> bool {
99 let encoded_u128_instruction = match encoded_instruction.to_u128() {
100 Some(num) => num,
101 None => return false,
102 };
103 let instruction = match decode_instruction(encoded_u128_instruction) {
104 Ok(inst) => inst,
105 Err(_) => return false,
106 };
107 instruction.res == Res::Op1
108 && (instruction.pc_update == PcUpdate::Jump || instruction.pc_update == PcUpdate::JumpRel)
109 && instruction.ap_update == ApUpdate::Add2
110 && instruction.fp_update == FpUpdate::APPlus2
111 && instruction.opcode == Opcode::Call
112}
113
114#[cfg(test)]
115mod tests {
116 use super::*;
117
118 #[cfg(target_arch = "wasm32")]
119 use wasm_bindgen_test::*;
120
121 #[test]
122 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
123 fn is_call_instruction_true() {
124 let encoded_instruction = Felt252::from(1226245742482522112_i64);
125 assert!(is_call_instruction(&encoded_instruction));
126 }
127
128 #[test]
129 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
130 fn is_call_instruction_false() {
131 let encoded_instruction = Felt252::from(4612671187288031229_i64);
132 assert!(!is_call_instruction(&encoded_instruction));
133 }
134
135 #[test]
136 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
137 fn is_call_instruction_invalid() {
138 let encoded_instruction = Felt252::from(1u64 << 63);
139 assert!(!is_call_instruction(&encoded_instruction));
140 }
141
142 #[test]
143 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
144 fn instruction_size() {
145 let encoded_instruction = Felt252::from(1226245742482522112_i64);
146 let instruction = decode_instruction(encoded_instruction.to_u128().unwrap()).unwrap();
147 assert_eq!(instruction.size(), 2);
148 }
149}