Skip to main content

sp1_core_machine/operations/
trap.rs

1use crate::air::MemoryAirBuilder;
2#[cfg(feature = "mprotect")]
3use slop_air::AirBuilder;
4use slop_algebra::{AbstractField, Field, PrimeField32};
5use sp1_core_executor::{
6    events::{ByteRecord, MemoryRecordEnum},
7    TrapResult,
8};
9use sp1_derive::AlignedBorrow;
10#[cfg(feature = "mprotect")]
11use sp1_hypercube::air::BaseAirBuilder;
12
13use sp1_hypercube::air::SP1AirBuilder;
14use sp1_hypercube::Word;
15use struct_reflection::{StructReflection, StructReflectionHelper};
16
17use crate::memory::MemoryAccessCols;
18
19#[derive(AlignedBorrow, Default, Debug, Clone, Copy, StructReflection)]
20#[repr(C)]
21pub struct TrapOperation<T> {
22    pub next_pc_reader: MemoryAccessCols<T>,
23    pub code_writer: MemoryAccessCols<T>,
24    pub pc_writer: MemoryAccessCols<T>,
25}
26
27impl<F: PrimeField32> TrapOperation<F> {
28    pub fn populate(&mut self, record: &mut impl ByteRecord, trap_result: TrapResult) {
29        self.next_pc_reader.populate(MemoryRecordEnum::Read(trap_result.handler_record), record);
30        self.code_writer.populate(MemoryRecordEnum::Write(trap_result.code_record), record);
31        self.pc_writer.populate(MemoryRecordEnum::Write(trap_result.pc_record), record);
32    }
33}
34
35impl<F: Field> TrapOperation<F> {
36    #[allow(clippy::too_many_arguments)]
37    pub fn eval<AB: SP1AirBuilder>(
38        builder: &mut AB,
39        cols: TrapOperation<AB::Var>,
40        clk_high: AB::Expr,
41        clk_low: AB::Expr,
42        code: AB::Expr,
43        pc: [AB::Expr; 3],
44        addresses: [[AB::Var; 3]; 3],
45        is_real: AB::Expr,
46    ) -> [AB::Var; 3] {
47        builder.assert_bool(is_real.clone());
48        #[cfg(feature = "mprotect")]
49        {
50            let public_values = builder.extract_public_values();
51            builder.when(is_real.clone()).assert_one(public_values.enable_trap_handler);
52
53            for i in 0..3 {
54                builder
55                    .when(is_real.clone())
56                    .assert_all_eq(public_values.trap_context[i], addresses[i]);
57            }
58        }
59        // Read the `next_pc` value from the memory.
60        builder.eval_memory_access_read(
61            clk_high.clone(),
62            clk_low.clone(),
63            &addresses[0].map(Into::into),
64            cols.next_pc_reader,
65            is_real.clone(),
66        );
67
68        // Write the `code` value to the memory.
69        // The caller is responsible to ensure that `code` is a valid u16 value.
70        builder.eval_memory_access_write(
71            clk_high.clone(),
72            clk_low.clone(),
73            &addresses[1].map(Into::into),
74            cols.code_writer,
75            Word::extend_expr::<AB>(code.clone()),
76            is_real.clone(),
77        );
78
79        // Write the `pc` value to the memory.
80        // The caller is responsible to ensure that `pc` is valid u16 limbs.
81        builder.eval_memory_access_write(
82            clk_high.clone(),
83            clk_low.clone(),
84            &addresses[2].map(Into::into),
85            cols.pc_writer,
86            Word([pc[0].clone(), pc[1].clone(), pc[2].clone(), AB::Expr::zero()]),
87            is_real.clone(),
88        );
89
90        [
91            cols.next_pc_reader.prev_value[0],
92            cols.next_pc_reader.prev_value[1],
93            cols.next_pc_reader.prev_value[2],
94        ]
95    }
96}