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 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 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 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 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 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 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 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 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 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 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 let reconstructed_rs1 =
388 Word::from_le_bits::<AB>(&local.encoded_instruction_bits[15..20], false);
389
390 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 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 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 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}