cairo_lang_casm/
encoder.rs1#[cfg(not(feature = "std"))]
2use alloc::{vec, vec::Vec};
3
4use num_bigint::BigInt;
5
6use crate::assembler::{ApUpdate, FpUpdate, InstructionRepr, Op1Addr, Opcode, PcUpdate, Res};
7use crate::operand::Register;
8
9#[cfg(test)]
10#[path = "encoder_test.rs"]
11mod test;
12
13const OFFSET_BITS: u32 = 16;
14
15const DST_REG_BIT: i32 = 0;
16const OP0_REG_BIT: i32 = 1;
17const OP1_IMM_BIT: i32 = 2;
18const OP1_FP_BIT: i32 = 3;
19const OP1_AP_BIT: i32 = 4;
20const RES_ADD_BIT: i32 = 5;
21const RES_MUL_BIT: i32 = 6;
22const PC_JUMP_ABS_BIT: i32 = 7;
23const PC_JUMP_REL_BIT: i32 = 8;
24const PC_JNZ_BIT: i32 = 9;
25const AP_ADD_BIT: i32 = 10;
26const AP_ADD1_BIT: i32 = 11;
27const OPCODE_CALL_BIT: i32 = 12;
28const OPCODE_RET_BIT: i32 = 13;
29const OPCODE_ASSERT_EQ_BIT: i32 = 14;
30
31impl InstructionRepr {
32 pub fn encode(&self) -> Vec<BigInt> {
33 let off0_enc: u64 = ((self.off0 as i32) + (1 << (OFFSET_BITS - 1))) as u64;
36 let off1_enc: u64 = ((self.off1 as i32) + (1 << (OFFSET_BITS - 1))) as u64;
37 let off2_enc: u64 = ((self.off2 as i32) + (1 << (OFFSET_BITS - 1))) as u64;
38
39 let mut flags = 0;
40 if self.dst_register == Register::FP {
41 flags |= 1 << DST_REG_BIT;
42 }
43 if self.op0_register == Register::FP {
44 flags |= 1 << OP0_REG_BIT;
45 }
46 assert_eq!(
47 self.imm.is_some(),
48 self.op1_addr == Op1Addr::Imm,
49 "Immediate must appear iff op1_addr is Op1Addr.IMM"
50 );
51 flags |= match self.op1_addr {
52 Op1Addr::Imm => 1 << OP1_IMM_BIT,
53 Op1Addr::AP => 1 << OP1_AP_BIT,
54 Op1Addr::FP => 1 << OP1_FP_BIT,
55 Op1Addr::Op0 => 0,
56 };
57
58 flags |= match self.res {
59 Res::Add => 1 << RES_ADD_BIT,
60 Res::Mul => 1 << RES_MUL_BIT,
61 Res::Op1 => 0,
62 Res::Unconstrained => 0,
63 };
64
65 assert_eq!(
66 self.res == Res::Unconstrained,
67 self.pc_update == PcUpdate::Jnz,
68 "res must be Unconstrained iff pc_update is Jnz"
69 );
70
71 flags |= match self.pc_update {
72 PcUpdate::Jump => 1 << PC_JUMP_ABS_BIT,
73 PcUpdate::JumpRel => 1 << PC_JUMP_REL_BIT,
74 PcUpdate::Jnz => 1 << PC_JNZ_BIT,
75 PcUpdate::Regular => 0,
76 };
77
78 assert_eq!(
79 self.ap_update == ApUpdate::Add2,
80 self.opcode == Opcode::Call,
81 "ap_update is Add2 iff opcode is Call"
82 );
83
84 flags |= match self.ap_update {
85 ApUpdate::Add => 1 << AP_ADD_BIT,
86 ApUpdate::Add1 => 1 << AP_ADD1_BIT,
87 ApUpdate::Add2 => 0,
88 ApUpdate::Regular => 0,
89 };
90
91 assert_eq!(
92 self.fp_update,
93 match self.opcode {
94 Opcode::Nop => FpUpdate::Regular,
95 Opcode::Call => FpUpdate::ApPlus2,
96 Opcode::Ret => FpUpdate::Dst,
97 Opcode::AssertEq => FpUpdate::Regular,
98 },
99 "fp_update {:?} does not match opcode {:?}.",
100 self.fp_update,
101 self.opcode
102 );
103
104 flags |= match self.opcode {
105 Opcode::Call => 1 << OPCODE_CALL_BIT,
106 Opcode::Ret => 1 << OPCODE_RET_BIT,
107 Opcode::AssertEq => 1 << OPCODE_ASSERT_EQ_BIT,
108 Opcode::Nop => 0,
109 };
110
111 let mut encoding: u64 = flags << (3 * OFFSET_BITS);
112 encoding |= off2_enc << (2 * OFFSET_BITS);
113 encoding |= off1_enc << (OFFSET_BITS);
114 encoding |= off0_enc;
115
116 let bigint_encoding = BigInt::from(encoding);
117 if let Some(imm) = self.imm.clone() {
118 vec![bigint_encoding, imm]
119 } else {
120 vec![bigint_encoding]
121 }
122 }
123}