sp1_core_machine/control_flow/jalr/
air.rs1use crate::{
2 adapter::{
3 register::i_type::{ITypeReader, ITypeReaderInput},
4 state::{CPUState, CPUStateInput},
5 },
6 air::{SP1CoreAirBuilder, SP1Operation},
7 eval_untrusted_program,
8 operations::AddOperationInput,
9 TrustMode, UserMode,
10};
11use slop_air::{Air, AirBuilder};
12use slop_algebra::{AbstractField, Field};
13use slop_matrix::Matrix;
14use sp1_core_executor::{ByteOpcode, Opcode, CLK_INC};
15use sp1_hypercube::Word;
16use std::borrow::Borrow;
17
18use crate::operations::AddOperation;
19
20use super::{JalrChip, JalrColumns};
21
22impl<AB, M> Air<AB> for JalrChip<M>
23where
24 AB: SP1CoreAirBuilder,
25 AB::Var: Sized,
26 M: TrustMode,
27{
28 #[inline(never)]
29 fn eval(&self, builder: &mut AB) {
30 let main = builder.main();
31 let local = main.row_slice(0);
32 let local: &JalrColumns<AB::Var, M> = (*local).borrow();
33
34 builder.assert_bool(local.is_real);
35
36 let opcode = Opcode::JALR.as_field::<AB::F>();
37 let funct3 = AB::Expr::from_canonical_u8(Opcode::JALR.funct3().unwrap());
38 let funct7 = AB::Expr::from_canonical_u8(Opcode::JALR.funct7().unwrap_or(0));
39 let base_opcode = AB::Expr::from_canonical_u32(Opcode::JALR.base_opcode().0);
40 let instr_type = AB::Expr::from_canonical_u32(Opcode::JALR.instruction_type().0 as u32);
41
42 let op_input = AddOperationInput::<AB>::new(
44 local.adapter.b().map(|x| x.into()),
45 local.adapter.c().map(|x| x.into()),
46 local.add_operation,
47 local.is_real.into(),
48 );
49 <AddOperation<AB::F> as SP1Operation<AB>>::eval(builder, op_input);
50
51 let next_pc = local.add_operation.value;
52 builder.assert_zero(next_pc[3]);
53
54 builder.assert_bool(local.lsb);
56
57 builder.send_byte(
61 AB::Expr::from_canonical_u32(ByteOpcode::Range as u32),
62 (next_pc[0].into() - local.lsb.into()) * AB::F::from_canonical_u32(4).inverse(),
63 AB::Expr::from_canonical_u32(14),
64 AB::Expr::zero(),
65 local.is_real,
66 );
67
68 <CPUState<AB::F> as SP1Operation<AB>>::eval(
72 builder,
73 CPUStateInput::new(
74 local.state,
75 [next_pc[0].into() - local.lsb.into(), next_pc[1].into(), next_pc[2].into()],
76 AB::Expr::from_canonical_u32(CLK_INC),
77 local.is_real.into(),
78 ),
79 );
80
81 let mut is_trusted: AB::Expr = local.is_real.into();
82
83 #[cfg(feature = "mprotect")]
84 builder.assert_eq(
85 builder.extract_public_values().is_untrusted_programs_enabled,
86 AB::Expr::from_bool(!M::IS_TRUSTED),
87 );
88
89 if !M::IS_TRUSTED {
90 let local = main.row_slice(0);
91 let local: &JalrColumns<AB::Var, UserMode> = (*local).borrow();
92
93 let instruction = local.adapter.instruction::<AB>(opcode);
94
95 #[cfg(not(feature = "mprotect"))]
96 builder.assert_zero(local.is_real);
97
98 eval_untrusted_program(
99 builder,
100 local.state.pc,
101 instruction,
102 [instr_type, base_opcode, funct3, funct7],
103 [local.state.clk_high::<AB>(), local.state.clk_low::<AB>()],
104 local.is_real.into(),
105 local.adapter_cols,
106 );
107
108 is_trusted = local.adapter_cols.is_trusted.into();
109 }
110
111 <ITypeReader<AB::F> as SP1Operation<AB>>::eval(
113 builder,
114 ITypeReaderInput::new(
115 local.state.clk_high::<AB>(),
116 local.state.clk_low::<AB>(),
117 local.state.pc,
118 Opcode::JALR.as_field::<AB::F>().into(),
119 local.op_a_operation.value.map(|x| x.into()),
120 local.adapter,
121 local.is_real.into(),
122 is_trusted,
123 ),
124 );
125
126 builder.when_not(local.is_real).assert_zero(local.adapter.op_a_0);
127
128 let op_input = AddOperationInput::<AB>::new(
133 Word([
134 local.state.pc[0].into(),
135 local.state.pc[1].into(),
136 local.state.pc[2].into(),
137 AB::Expr::zero(),
138 ]),
139 Word([
140 AB::Expr::from_canonical_u16(4),
141 AB::Expr::zero(),
142 AB::Expr::zero(),
143 AB::Expr::zero(),
144 ]),
145 local.op_a_operation,
146 local.is_real.into() - local.adapter.op_a_0,
147 );
148 <AddOperation<AB::F> as SP1Operation<AB>>::eval(builder, op_input);
149 builder.assert_zero(local.op_a_operation.value[3]);
150 for i in 0..3 {
151 builder.when(local.adapter.op_a_0).assert_zero(local.op_a_operation.value[i]);
152 }
153 }
154}