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