Skip to main content

sp1_core_machine/program/
instruction_decode.rs

1use core::{
2    borrow::{Borrow, BorrowMut},
3    mem::{size_of, MaybeUninit},
4};
5
6use crate::{
7    air::{SP1CoreAirBuilder, SP1Operation, WordAirBuilder},
8    operations::{IsZeroOperation, IsZeroOperationInput},
9    program::InstructionCols,
10    utils::next_multiple_of_32,
11};
12use slop_air::{Air, AirBuilder, BaseAir};
13use slop_algebra::{AbstractField, PrimeField32};
14use slop_matrix::Matrix;
15use sp1_core_executor::{ExecutionRecord, InstructionType, Opcode, Program};
16use sp1_derive::AlignedBorrow;
17use sp1_hypercube::{
18    air::{MachineAir, SP1AirBuilder},
19    Word,
20};
21
22use rrs_lib::instruction_formats::{
23    OPCODE_AUIPC, OPCODE_BRANCH, OPCODE_JAL, OPCODE_JALR, OPCODE_LOAD, OPCODE_LUI, OPCODE_OP,
24    OPCODE_OP_32, OPCODE_OP_IMM, OPCODE_OP_IMM_32, OPCODE_STORE,
25};
26
27/// The number of program columns.
28pub const NUM_INSTRUCTION_DECODE_COLS: usize = size_of::<InstructionDecodeCols<u8>>();
29
30/// The column layout for the chip.
31#[derive(AlignedBorrow, Clone, Copy, Default)]
32#[repr(C)]
33pub struct InstructionDecodeCols<T> {
34    pub multiplicity: T,
35    pub instruction: InstructionCols<T>,
36    pub instr_type: T,
37    pub funct3: T,
38    pub funct7: T,
39    pub is_r_type: T,
40    pub is_i_type: T,
41    pub is_i_type_shamt: T,
42    pub is_i_type_shamt_32: T,
43    pub is_j_type: T,
44    pub is_b_type: T,
45    pub is_s_type: T,
46    pub is_u_type: T,
47    pub is_a_0: IsZeroOperation<T>,
48    pub encoded_instruction: [T; 2],
49    pub encoded_instruction_bits: [T; 32],
50}
51
52/// A chip that implements instruction decoding.
53#[derive(Default)]
54pub struct InstructionDecodeChip;
55
56impl InstructionDecodeChip {
57    pub const fn new() -> Self {
58        Self {}
59    }
60}
61
62impl<F: PrimeField32> MachineAir<F> for InstructionDecodeChip {
63    type Record = ExecutionRecord;
64
65    type Program = Program;
66
67    fn name(&self) -> &'static str {
68        "InstructionDecode"
69    }
70
71    fn generate_dependencies(&self, _input: &ExecutionRecord, _output: &mut ExecutionRecord) {
72        // Do nothing since this chip has no dependencies.
73    }
74
75    fn generate_trace_into(
76        &self,
77        input: &ExecutionRecord,
78        _output: &mut ExecutionRecord,
79        buffer: &mut [MaybeUninit<F>],
80    ) {
81        let padded_nb_rows =
82            <InstructionDecodeChip as MachineAir<F>>::num_rows(self, input).unwrap();
83        let num_event_rows = input.instruction_decode_events.len();
84
85        unsafe {
86            let total_size = padded_nb_rows * NUM_INSTRUCTION_DECODE_COLS;
87            if total_size > 0 {
88                core::ptr::write_bytes(buffer.as_mut_ptr(), 0, total_size);
89            }
90        }
91
92        let buffer_ptr = buffer.as_mut_ptr() as *mut F;
93        let values = unsafe {
94            core::slice::from_raw_parts_mut(
95                buffer_ptr,
96                num_event_rows * NUM_INSTRUCTION_DECODE_COLS,
97            )
98        };
99
100        values.chunks_mut(NUM_INSTRUCTION_DECODE_COLS).enumerate().for_each(|(idx, row)| {
101            let cols: &mut InstructionDecodeCols<F> = row.borrow_mut();
102            let event = &input.instruction_decode_events[idx];
103
104            let instruction = event.instruction;
105            cols.instruction.populate(&instruction);
106            cols.is_a_0.populate(instruction.op_a.into());
107
108            // Check that the encoded instruction is correct
109            let encoding_check = instruction.encode();
110            assert_eq!(event.encoded_instruction, encoding_check);
111
112            cols.encoded_instruction[0] = F::from_canonical_u32(event.encoded_instruction & 0xFFFF);
113            cols.encoded_instruction[1] =
114                F::from_canonical_u32((event.encoded_instruction >> 16) & 0xFFFF);
115
116            for (i, bit) in event
117                .encoded_instruction
118                .to_le_bytes()
119                .iter()
120                .flat_map(|byte| {
121                    let mut bits = [0u8; 8];
122                    for j in 0..8 {
123                        bits[j] = (byte >> j) & 1;
124                    }
125                    bits
126                })
127                .enumerate()
128            {
129                cols.encoded_instruction_bits[i] = F::from_canonical_u8(bit);
130            }
131
132            if instruction.opcode != Opcode::UNIMP {
133                let (instr_type, instr_type_imm) = instruction.opcode.instruction_type();
134                let instr_type = if instr_type_imm.is_some() && instruction.imm_c {
135                    instr_type_imm.unwrap()
136                } else {
137                    instr_type
138                };
139                cols.instr_type = F::from_canonical_u32(instr_type as u32);
140
141                let (base_opcode, base_imm_opcode) = instruction.opcode.base_opcode();
142                let base_opcode = if base_imm_opcode.is_some() && instruction.imm_c {
143                    base_imm_opcode.unwrap()
144                } else {
145                    base_opcode
146                };
147                let funct3 = instruction.opcode.funct3().unwrap_or(0);
148                let funct7 = instruction.opcode.funct7().unwrap_or(0);
149                cols.funct3 = F::from_canonical_u8(funct3);
150                cols.funct7 = F::from_canonical_u8(funct7);
151
152                cols.is_r_type =
153                    F::from_bool(base_opcode == OPCODE_OP || base_opcode == OPCODE_OP_32);
154
155                let is_i_type = matches!(
156                    base_opcode,
157                    OPCODE_OP_IMM | OPCODE_OP_IMM_32 | OPCODE_LOAD | OPCODE_JALR
158                );
159                if is_i_type {
160                    if matches!(funct3, 0b001 | 0b101) && base_opcode == OPCODE_OP_IMM {
161                        cols.is_i_type_shamt = F::one();
162                    } else if matches!(funct3, 0b001 | 0b101) && base_opcode == OPCODE_OP_IMM_32 {
163                        cols.is_i_type_shamt_32 = F::one();
164                    } else {
165                        cols.is_i_type = F::one();
166                    }
167                }
168
169                cols.is_j_type = F::from_bool(base_opcode == OPCODE_JAL);
170                cols.is_b_type = F::from_bool(base_opcode == OPCODE_BRANCH);
171                cols.is_s_type = F::from_bool(base_opcode == OPCODE_STORE);
172                cols.is_u_type =
173                    F::from_bool(base_opcode == OPCODE_AUIPC || base_opcode == OPCODE_LUI);
174            }
175
176            cols.multiplicity = F::from_canonical_usize(event.multiplicity);
177        });
178    }
179
180    fn included(&self, shard: &Self::Record) -> bool {
181        if let Some(shape) = shard.shape.as_ref() {
182            shape.included::<F, _>(self)
183        } else {
184            !shard.instruction_decode_events.is_empty()
185        }
186    }
187
188    fn num_rows(&self, input: &Self::Record) -> Option<usize> {
189        let nb_rows = next_multiple_of_32(
190            input.instruction_decode_events.len(),
191            input.fixed_log2_rows::<F, _>(self),
192        );
193        Some(nb_rows)
194    }
195}
196
197impl<F> BaseAir<F> for InstructionDecodeChip {
198    fn width(&self) -> usize {
199        NUM_INSTRUCTION_DECODE_COLS
200    }
201}
202
203impl<AB> Air<AB> for InstructionDecodeChip
204where
205    AB: SP1CoreAirBuilder,
206{
207    fn eval(&self, builder: &mut AB) {
208        let main = builder.main();
209        let local = main.row_slice(0);
210        let local: &InstructionDecodeCols<AB::Var> = (*local).borrow();
211
212        // We do not allow untrusted instructions to make ecalls.
213        builder.assert_bool(local.is_r_type);
214        builder.assert_bool(local.is_i_type);
215        builder.assert_bool(local.is_i_type_shamt);
216        builder.assert_bool(local.is_i_type_shamt_32);
217        builder.assert_bool(local.is_j_type);
218        builder.assert_bool(local.is_b_type);
219        builder.assert_bool(local.is_s_type);
220        builder.assert_bool(local.is_u_type);
221
222        let is_real: AB::Expr = local.is_r_type
223            + local.is_i_type
224            + local.is_i_type_shamt
225            + local.is_i_type_shamt_32
226            + local.is_j_type
227            + local.is_b_type
228            + local.is_s_type
229            + local.is_u_type;
230
231        // Assert that at most one of the instruction selectors is set.
232        builder.assert_bool(is_real.clone());
233        builder.assert_eq(
234            builder.extract_public_values().is_untrusted_programs_enabled,
235            AB::Expr::one(),
236        );
237
238        #[cfg(not(feature = "mprotect"))]
239        builder.assert_zero(is_real.clone());
240        #[cfg(not(feature = "mprotect"))]
241        builder.assert_zero(local.multiplicity);
242
243        // Assert that the right instruction selector is set.
244        builder.assert_eq(
245            local.instr_type,
246            local.is_r_type * AB::Expr::from_canonical_u32(InstructionType::RType as u32)
247                + local.is_i_type * AB::Expr::from_canonical_u32(InstructionType::IType as u32)
248                + local.is_i_type_shamt
249                    * AB::Expr::from_canonical_u32(InstructionType::ITypeShamt as u32)
250                + local.is_i_type_shamt_32
251                    * AB::Expr::from_canonical_u32(InstructionType::ITypeShamt32 as u32)
252                + local.is_j_type * AB::Expr::from_canonical_u32(InstructionType::JType as u32)
253                + local.is_b_type * AB::Expr::from_canonical_u32(InstructionType::BType as u32)
254                + local.is_s_type * AB::Expr::from_canonical_u32(InstructionType::SType as u32)
255                + local.is_u_type * AB::Expr::from_canonical_u32(InstructionType::UType as u32),
256        );
257
258        let (
259            decoded_base_opcode,
260            decoded_funct3,
261            decoded_funct7_rtype,
262            decoded_funct7_i_type_shamt,
263            decoded_rd,
264            decoded_rs1,
265            decoded_rs2,
266        ) = self.decode_instruction(builder, local);
267
268        self.r_type_eval(
269            builder,
270            local,
271            decoded_funct3.clone(),
272            decoded_funct7_rtype.clone(),
273            decoded_rd.clone(),
274            decoded_rs1.clone(),
275            decoded_rs2.clone(),
276        );
277        self.i_type_eval(
278            builder,
279            local,
280            decoded_funct3.clone(),
281            decoded_rd.clone(),
282            decoded_rs1.clone(),
283        );
284        self.i_type_shamt_eval(
285            builder,
286            local,
287            decoded_funct3.clone(),
288            decoded_funct7_i_type_shamt.clone(),
289            decoded_rd.clone(),
290            decoded_rs1.clone(),
291        );
292        self.i_type_shamt_32_eval(
293            builder,
294            local,
295            decoded_funct3.clone(),
296            decoded_funct7_i_type_shamt.clone(),
297            decoded_rd.clone(),
298            decoded_rs1.clone(),
299        );
300        self.j_type_eval(builder, local, decoded_rd.clone());
301        self.b_type_eval(
302            builder,
303            local,
304            decoded_funct3.clone(),
305            decoded_rs1.clone(),
306            decoded_rs2.clone(),
307        );
308        self.s_type_eval(
309            builder,
310            local,
311            decoded_funct3.clone(),
312            decoded_rs1.clone(),
313            decoded_rs2.clone(),
314        );
315        self.u_type_eval(builder, local, decoded_rd.clone());
316
317        // Check the op_a_0 column.
318        IsZeroOperation::<AB::F>::eval(
319            builder,
320            IsZeroOperationInput::new(local.instruction.op_a.into(), local.is_a_0, is_real.clone()),
321        );
322        builder.when(is_real.clone()).assert_eq(local.is_a_0.result, local.instruction.op_a_0);
323
324        // Constrain the interaction with instruction decode table
325        let untrusted_instruction_const_fields = [
326            local.instr_type.into(),
327            decoded_base_opcode,
328            local.funct3.into(),
329            local.funct7.into(),
330        ];
331
332        builder.when_not(is_real).assert_zero(local.multiplicity);
333
334        builder.receive_instruction_decode(
335            [local.encoded_instruction[0].into(), local.encoded_instruction[1].into()],
336            local.instruction,
337            untrusted_instruction_const_fields,
338            local.multiplicity.into(),
339        );
340    }
341}
342
343impl InstructionDecodeChip {
344    fn decode_instruction<AB: SP1AirBuilder>(
345        &self,
346        builder: &mut AB,
347        local: &InstructionDecodeCols<AB::Var>,
348    ) -> (AB::Expr, AB::Expr, AB::Expr, AB::Expr, AB::Expr, Word<AB::Expr>, Word<AB::Expr>) {
349        let mut reconstructed_first_limb = AB::Expr::zero();
350        for (i, bit) in local.encoded_instruction_bits[0..16].iter().enumerate() {
351            builder.assert_bool(*bit);
352            reconstructed_first_limb =
353                reconstructed_first_limb.clone() + AB::Expr::from_wrapped_u32(1 << i) * *bit;
354        }
355
356        let mut reconstructed_second_limb = AB::Expr::zero();
357        for (i, bit) in local.encoded_instruction_bits[16..32].iter().enumerate() {
358            builder.assert_bool(*bit);
359            reconstructed_second_limb =
360                reconstructed_second_limb.clone() + AB::Expr::from_wrapped_u32(1 << i) * *bit;
361        }
362
363        builder.assert_eq(local.encoded_instruction[0].into(), reconstructed_first_limb);
364        builder.assert_eq(local.encoded_instruction[1].into(), reconstructed_second_limb);
365
366        // True for all instruction types
367        let mut reconstructed_base_opcode = AB::Expr::zero();
368        for (i, bit) in local.encoded_instruction_bits[0..7].iter().enumerate() {
369            reconstructed_base_opcode =
370                reconstructed_base_opcode.clone() + AB::Expr::from_wrapped_u32(1 << i) * *bit;
371        }
372
373        // True for R, I, U, J, Not right for S, B
374        let mut reconstructed_rd = AB::Expr::zero();
375        for (i, bit) in local.encoded_instruction_bits[7..12].iter().enumerate() {
376            reconstructed_rd = reconstructed_rd.clone() + AB::Expr::from_wrapped_u32(1 << i) * *bit;
377        }
378
379        // True for R, I, S, B, Not right for U, J
380        let mut reconstructed_funct3 = AB::Expr::zero();
381        for (i, bit) in local.encoded_instruction_bits[12..15].iter().enumerate() {
382            reconstructed_funct3 =
383                reconstructed_funct3.clone() + AB::Expr::from_wrapped_u32(1 << i) * *bit;
384        }
385
386        // True for R, I, S, B, Not right for U, J
387        let reconstructed_rs1 =
388            Word::from_le_bits::<AB>(&local.encoded_instruction_bits[15..20], false);
389
390        // True for R, S, B, Not right for I, U, J
391        let reconstructed_rs2 =
392            Word::from_le_bits::<AB>(&local.encoded_instruction_bits[20..25], false);
393
394        let mut reconstructed_funct7_rtype = AB::Expr::zero();
395        for (i, bit) in local.encoded_instruction_bits[25..32].iter().enumerate() {
396            reconstructed_funct7_rtype =
397                reconstructed_funct7_rtype.clone() + AB::Expr::from_wrapped_u32(1 << i) * *bit;
398        }
399
400        let mut reconstructed_funct7_i_type_shamt = AB::Expr::zero();
401        for (i, bit) in local.encoded_instruction_bits[26..32].iter().enumerate() {
402            reconstructed_funct7_i_type_shamt = reconstructed_funct7_i_type_shamt.clone()
403                + AB::Expr::from_wrapped_u32(1 << i) * *bit;
404        }
405        reconstructed_funct7_i_type_shamt =
406            reconstructed_funct7_i_type_shamt.clone() * AB::Expr::from_wrapped_u32(2);
407
408        (
409            reconstructed_base_opcode,
410            reconstructed_funct3,
411            reconstructed_funct7_rtype,
412            reconstructed_funct7_i_type_shamt,
413            reconstructed_rd,
414            reconstructed_rs1,
415            reconstructed_rs2,
416        )
417    }
418
419    #[allow(clippy::too_many_arguments)]
420    fn r_type_eval<AB: SP1CoreAirBuilder>(
421        &self,
422        builder: &mut AB,
423        local: &InstructionDecodeCols<AB::Var>,
424        decoded_funct3: AB::Expr,
425        decoded_funct7: AB::Expr,
426        decoded_rd: AB::Expr,
427        decoded_rs1: Word<AB::Expr>,
428        decoded_rs2: Word<AB::Expr>,
429    ) {
430        let mut r_type_builder = builder.when(local.is_r_type);
431
432        r_type_builder.assert_eq(local.funct3, decoded_funct3);
433        r_type_builder.assert_eq(local.funct7, decoded_funct7);
434
435        r_type_builder.assert_eq(local.instruction.op_a, decoded_rd);
436        r_type_builder.assert_word_eq(local.instruction.op_b, decoded_rs1);
437        r_type_builder.assert_word_eq(local.instruction.op_c, decoded_rs2);
438
439        r_type_builder.assert_zero(local.instruction.imm_b);
440        r_type_builder.assert_zero(local.instruction.imm_c);
441    }
442
443    fn i_type_eval<AB: SP1AirBuilder>(
444        &self,
445        builder: &mut AB,
446        local: &InstructionDecodeCols<AB::Var>,
447        decoded_funct3: AB::Expr,
448        decoded_rd: AB::Expr,
449        decoded_rs1: Word<AB::Expr>,
450    ) {
451        let mut i_type_builder = builder.when(local.is_i_type);
452
453        i_type_builder.assert_eq(local.funct3, decoded_funct3);
454        i_type_builder.assert_eq(local.funct7, AB::Expr::zero());
455
456        i_type_builder.assert_eq(local.instruction.op_a, decoded_rd);
457        i_type_builder.assert_word_eq(local.instruction.op_b, decoded_rs1);
458
459        let mut imm_le_bits = Vec::new();
460        imm_le_bits.extend(local.encoded_instruction_bits[20..32].iter().map(|x| (*x).into()));
461        let sign_extended_imm = Word::from_le_bits::<AB>(&imm_le_bits, true);
462
463        i_type_builder.assert_word_eq(local.instruction.op_c, sign_extended_imm);
464
465        i_type_builder.assert_zero(local.instruction.imm_b);
466        i_type_builder.assert_one(local.instruction.imm_c);
467    }
468
469    fn i_type_shamt_eval<AB: SP1AirBuilder>(
470        &self,
471        builder: &mut AB,
472        local: &InstructionDecodeCols<AB::Var>,
473        decoded_funct3: AB::Expr,
474        decoded_funct7: AB::Expr,
475        decoded_rd: AB::Expr,
476        decoded_rs1: Word<AB::Expr>,
477    ) {
478        let mut i_type_shamt_builder = builder.when(local.is_i_type_shamt);
479
480        i_type_shamt_builder.assert_eq(local.funct3, decoded_funct3);
481        i_type_shamt_builder.assert_eq(local.funct7, decoded_funct7);
482
483        i_type_shamt_builder.assert_eq(local.instruction.op_a, decoded_rd);
484        i_type_shamt_builder.assert_word_eq(local.instruction.op_b, decoded_rs1);
485
486        let shamt = Word::from_le_bits::<AB>(&local.encoded_instruction_bits[20..26], false);
487        i_type_shamt_builder.assert_word_eq(local.instruction.op_c, shamt);
488
489        i_type_shamt_builder.assert_zero(local.instruction.imm_b);
490        i_type_shamt_builder.assert_one(local.instruction.imm_c);
491    }
492
493    fn i_type_shamt_32_eval<AB: SP1AirBuilder>(
494        &self,
495        builder: &mut AB,
496        local: &InstructionDecodeCols<AB::Var>,
497        decoded_funct3: AB::Expr,
498        decoded_funct7: AB::Expr,
499        decoded_rd: AB::Expr,
500        decoded_rs1: Word<AB::Expr>,
501    ) {
502        let mut i_type_shamt_32_builder = builder.when(local.is_i_type_shamt_32);
503
504        i_type_shamt_32_builder.assert_eq(local.funct3, decoded_funct3);
505        i_type_shamt_32_builder.assert_eq(local.funct7, decoded_funct7);
506
507        i_type_shamt_32_builder.assert_eq(local.instruction.op_a, decoded_rd);
508        i_type_shamt_32_builder.assert_word_eq(local.instruction.op_b, decoded_rs1);
509
510        let shamt = Word::from_le_bits::<AB>(&local.encoded_instruction_bits[20..25], false);
511        i_type_shamt_32_builder.assert_word_eq(local.instruction.op_c, shamt);
512
513        i_type_shamt_32_builder.assert_zero(local.encoded_instruction_bits[25]);
514
515        i_type_shamt_32_builder.assert_zero(local.instruction.imm_b);
516        i_type_shamt_32_builder.assert_one(local.instruction.imm_c);
517    }
518
519    fn j_type_eval<AB: SP1AirBuilder>(
520        &self,
521        builder: &mut AB,
522        local: &InstructionDecodeCols<AB::Var>,
523        decoded_rd: AB::Expr,
524    ) {
525        {
526            let mut imm_le_bits = Vec::new();
527
528            // The least significant bit (bit 0) is always 0.
529            imm_le_bits.push(AB::Expr::zero());
530            imm_le_bits.extend(local.encoded_instruction_bits[21..31].iter().map(|x| (*x).into()));
531            imm_le_bits.push(local.encoded_instruction_bits[20].into());
532            imm_le_bits.extend(local.encoded_instruction_bits[12..20].iter().map(|x| (*x).into()));
533            imm_le_bits.push(local.encoded_instruction_bits[31].into());
534
535            let sign_extended_word = Word::from_le_bits::<AB>(&imm_le_bits, true);
536
537            let mut j_type_builder = builder.when(local.is_j_type);
538
539            j_type_builder.assert_eq(local.funct3, AB::Expr::zero());
540            j_type_builder.assert_eq(local.funct7, AB::Expr::zero());
541
542            j_type_builder.assert_eq(local.instruction.op_a, decoded_rd);
543            j_type_builder.assert_word_eq(local.instruction.op_b, sign_extended_word);
544            j_type_builder.assert_word_zero(local.instruction.op_c);
545
546            j_type_builder.assert_one(local.instruction.imm_b);
547            j_type_builder.assert_one(local.instruction.imm_c);
548        }
549    }
550
551    fn b_type_eval<AB: SP1AirBuilder>(
552        &self,
553        builder: &mut AB,
554        local: &InstructionDecodeCols<AB::Var>,
555        decoded_funct3: AB::Expr,
556        decoded_rs1: Word<AB::Expr>,
557        decoded_rs2: Word<AB::Expr>,
558    ) {
559        let mut b_type_builder = builder.when(local.is_b_type);
560
561        b_type_builder.assert_eq(local.funct3, decoded_funct3);
562        b_type_builder.assert_eq(local.funct7, AB::Expr::zero());
563
564        let op_a_word = Word::extend_expr::<AB>(local.instruction.op_a.into());
565        b_type_builder.assert_word_eq(op_a_word, decoded_rs1);
566        b_type_builder.assert_word_eq(local.instruction.op_b, decoded_rs2);
567
568        let mut imm_le_bits = Vec::new();
569        imm_le_bits.push(AB::Expr::zero());
570        imm_le_bits.extend(local.encoded_instruction_bits[8..12].iter().map(|x| (*x).into()));
571        imm_le_bits.extend(local.encoded_instruction_bits[25..31].iter().map(|x| (*x).into()));
572        imm_le_bits.push(local.encoded_instruction_bits[7].into());
573        imm_le_bits.push(local.encoded_instruction_bits[31].into());
574
575        let signed_extended_imm = Word::from_le_bits::<AB>(&imm_le_bits, true);
576        b_type_builder.assert_word_eq(local.instruction.op_c, signed_extended_imm);
577
578        b_type_builder.assert_zero(local.instruction.imm_b);
579        b_type_builder.assert_one(local.instruction.imm_c);
580    }
581
582    fn s_type_eval<AB: SP1AirBuilder>(
583        &self,
584        builder: &mut AB,
585        local: &InstructionDecodeCols<AB::Var>,
586        decoded_funct3: AB::Expr,
587        decoded_rs1: Word<AB::Expr>,
588        decoded_rs2: Word<AB::Expr>,
589    ) {
590        let mut s_type_builder = builder.when(local.is_s_type);
591
592        s_type_builder.assert_eq(local.funct3, decoded_funct3);
593        s_type_builder.assert_eq(local.funct7, AB::Expr::zero());
594
595        let op_a_word = Word::extend_expr::<AB>(local.instruction.op_a.into());
596        s_type_builder.assert_word_eq(op_a_word, decoded_rs2);
597        s_type_builder.assert_word_eq(local.instruction.op_b, decoded_rs1);
598
599        let mut imm_le_bits = Vec::new();
600        imm_le_bits.extend(local.encoded_instruction_bits[7..12].iter().map(|x| (*x).into()));
601        imm_le_bits.extend(local.encoded_instruction_bits[25..32].iter().map(|x| (*x).into()));
602        let signed_extended_imm = Word::from_le_bits::<AB>(&imm_le_bits, true);
603
604        s_type_builder.assert_word_eq(local.instruction.op_c, signed_extended_imm);
605
606        s_type_builder.assert_zero(local.instruction.imm_b);
607        s_type_builder.assert_one(local.instruction.imm_c);
608    }
609
610    fn u_type_eval<AB: SP1AirBuilder>(
611        &self,
612        builder: &mut AB,
613        local: &InstructionDecodeCols<AB::Var>,
614        decoded_rd: AB::Expr,
615    ) {
616        let mut imm_le_bits = Vec::new();
617        // The first 12 bits are all 0.
618        for _ in 0..12 {
619            imm_le_bits.push(AB::Expr::zero());
620        }
621        imm_le_bits.extend(local.encoded_instruction_bits[12..32].iter().map(|x| (*x).into()));
622
623        let reconstructed_imm = Word::from_le_bits::<AB>(&imm_le_bits, true);
624
625        let mut utype_builder = builder.when(local.is_u_type);
626
627        utype_builder.assert_eq(local.funct3, AB::Expr::zero());
628        utype_builder.assert_eq(local.funct7, AB::Expr::zero());
629
630        utype_builder.assert_eq(local.instruction.op_a, decoded_rd);
631        utype_builder.assert_word_eq(local.instruction.op_b, reconstructed_imm.clone());
632        utype_builder.assert_word_eq(local.instruction.op_c, reconstructed_imm);
633
634        utype_builder.assert_one(local.instruction.imm_b);
635        utype_builder.assert_one(local.instruction.imm_c);
636    }
637}
638
639#[cfg(test)]
640mod tests {
641    #![allow(clippy::print_stdout)]
642
643    use std::sync::Arc;
644
645    use sp1_primitives::SP1Field;
646
647    use slop_matrix::dense::RowMajorMatrix;
648    use sp1_core_executor::{ExecutionRecord, Instruction, Opcode, Program};
649    use sp1_hypercube::air::MachineAir;
650
651    use crate::program::InstructionDecodeChip;
652
653    #[test]
654    fn generate_trace() {
655        // main:
656        //     addi x29, x0, 5
657        //     addi x30, x0, 37
658        //     add x31, x30, x29
659        let instructions = vec![
660            Instruction::new(Opcode::ADDI, 29, 0, 5, false, true),
661            Instruction::new(Opcode::ADDI, 30, 0, 37, false, true),
662            Instruction::new(Opcode::ADD, 31, 30, 29, false, false),
663        ];
664        let shard = ExecutionRecord {
665            program: Arc::new(Program::new(instructions, 0, 0)),
666            ..Default::default()
667        };
668        let chip = InstructionDecodeChip::new();
669        let trace: RowMajorMatrix<SP1Field> =
670            chip.generate_trace(&shard, &mut ExecutionRecord::default());
671        println!("{:?}", trace.values)
672    }
673}