mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-03 22:33:06 +00:00
244 lines
10 KiB
Rust
244 lines
10 KiB
Rust
use plonky2::field::types::Field;
|
|
|
|
use crate::cpu::columns::{CpuColumnsView, NUM_CPU_COLUMNS};
|
|
use crate::logic;
|
|
use crate::memory::segments::Segment;
|
|
use crate::witness::errors::ProgramError;
|
|
use crate::witness::memory::{MemoryAddress, MemoryState};
|
|
use crate::witness::operation::{
|
|
generate_binary_logic_op, generate_dup, generate_eq, generate_exit_kernel, generate_iszero,
|
|
generate_not, generate_swap, generate_syscall, Operation,
|
|
};
|
|
use crate::witness::state::RegistersState;
|
|
use crate::witness::traces::Traces;
|
|
use crate::witness::util::mem_read_code_with_log_and_fill;
|
|
|
|
const KERNEL_CONTEXT: usize = 0;
|
|
|
|
fn read_code_memory<F: Field>(
|
|
registers_state: RegistersState,
|
|
memory_state: &MemoryState,
|
|
traces: &mut Traces<F>,
|
|
row: &mut CpuColumnsView<F>,
|
|
) -> u8 {
|
|
let code_context = if registers_state.is_kernel {
|
|
KERNEL_CONTEXT
|
|
} else {
|
|
registers_state.context
|
|
};
|
|
row.code_context = F::from_canonical_usize(code_context);
|
|
|
|
let address = MemoryAddress::new(
|
|
code_context,
|
|
Segment::Code as usize,
|
|
registers_state.program_counter,
|
|
);
|
|
let (opcode, mem_log) = mem_read_code_with_log_and_fill(address, memory_state, traces, row);
|
|
|
|
traces.push_memory(mem_log);
|
|
|
|
opcode
|
|
}
|
|
|
|
fn decode(registers_state: RegistersState, opcode: u8) -> Result<Operation, ProgramError> {
|
|
match (opcode, registers_state.is_kernel) {
|
|
(0x00, _) => Ok(Operation::Syscall(opcode)),
|
|
(0x01, _) => Ok(Operation::NotImplemented),
|
|
(0x02, _) => Ok(Operation::NotImplemented),
|
|
(0x03, _) => Ok(Operation::NotImplemented),
|
|
(0x04, _) => Ok(Operation::NotImplemented),
|
|
(0x05, _) => Ok(Operation::Syscall(opcode)),
|
|
(0x06, _) => Ok(Operation::NotImplemented),
|
|
(0x07, _) => Ok(Operation::Syscall(opcode)),
|
|
(0x08, _) => Ok(Operation::NotImplemented),
|
|
(0x09, _) => Ok(Operation::NotImplemented),
|
|
(0x0a, _) => Ok(Operation::Syscall(opcode)),
|
|
(0x0b, _) => Ok(Operation::Syscall(opcode)),
|
|
(0x0c, true) => Ok(Operation::NotImplemented),
|
|
(0x0d, true) => Ok(Operation::NotImplemented),
|
|
(0x0e, true) => Ok(Operation::NotImplemented),
|
|
(0x10, _) => Ok(Operation::NotImplemented),
|
|
(0x11, _) => Ok(Operation::NotImplemented),
|
|
(0x12, _) => Ok(Operation::Syscall(opcode)),
|
|
(0x13, _) => Ok(Operation::Syscall(opcode)),
|
|
(0x14, _) => Ok(Operation::Eq),
|
|
(0x15, _) => Ok(Operation::Iszero),
|
|
(0x16, _) => Ok(Operation::BinaryLogic(logic::Op::And)),
|
|
(0x17, _) => Ok(Operation::BinaryLogic(logic::Op::Or)),
|
|
(0x18, _) => Ok(Operation::BinaryLogic(logic::Op::Xor)),
|
|
(0x19, _) => Ok(Operation::Not),
|
|
(0x1a, _) => Ok(Operation::NotImplemented),
|
|
(0x1b, _) => Ok(Operation::NotImplemented),
|
|
(0x1c, _) => Ok(Operation::NotImplemented),
|
|
(0x1d, _) => Ok(Operation::Syscall(opcode)),
|
|
(0x20, _) => Ok(Operation::Syscall(opcode)),
|
|
(0x21, _) => Ok(Operation::NotImplemented),
|
|
(0x30, _) => Ok(Operation::Syscall(opcode)),
|
|
(0x31, _) => Ok(Operation::Syscall(opcode)),
|
|
(0x32, _) => Ok(Operation::Syscall(opcode)),
|
|
(0x33, _) => Ok(Operation::Syscall(opcode)),
|
|
(0x34, _) => Ok(Operation::Syscall(opcode)),
|
|
(0x35, _) => Ok(Operation::Syscall(opcode)),
|
|
(0x36, _) => Ok(Operation::Syscall(opcode)),
|
|
(0x37, _) => Ok(Operation::Syscall(opcode)),
|
|
(0x38, _) => Ok(Operation::Syscall(opcode)),
|
|
(0x39, _) => Ok(Operation::Syscall(opcode)),
|
|
(0x3a, _) => Ok(Operation::Syscall(opcode)),
|
|
(0x3b, _) => Ok(Operation::Syscall(opcode)),
|
|
(0x3c, _) => Ok(Operation::Syscall(opcode)),
|
|
(0x3d, _) => Ok(Operation::Syscall(opcode)),
|
|
(0x3e, _) => Ok(Operation::Syscall(opcode)),
|
|
(0x3f, _) => Ok(Operation::Syscall(opcode)),
|
|
(0x40, _) => Ok(Operation::Syscall(opcode)),
|
|
(0x41, _) => Ok(Operation::Syscall(opcode)),
|
|
(0x42, _) => Ok(Operation::Syscall(opcode)),
|
|
(0x43, _) => Ok(Operation::Syscall(opcode)),
|
|
(0x44, _) => Ok(Operation::Syscall(opcode)),
|
|
(0x45, _) => Ok(Operation::Syscall(opcode)),
|
|
(0x46, _) => Ok(Operation::Syscall(opcode)),
|
|
(0x47, _) => Ok(Operation::Syscall(opcode)),
|
|
(0x48, _) => Ok(Operation::Syscall(opcode)),
|
|
(0x49, _) => Ok(Operation::NotImplemented),
|
|
(0x50, _) => Ok(Operation::NotImplemented),
|
|
(0x51, _) => Ok(Operation::Syscall(opcode)),
|
|
(0x52, _) => Ok(Operation::Syscall(opcode)),
|
|
(0x53, _) => Ok(Operation::Syscall(opcode)),
|
|
(0x54, _) => Ok(Operation::Syscall(opcode)),
|
|
(0x55, _) => Ok(Operation::Syscall(opcode)),
|
|
(0x56, _) => Ok(Operation::NotImplemented),
|
|
(0x57, _) => Ok(Operation::NotImplemented),
|
|
(0x58, _) => Ok(Operation::NotImplemented),
|
|
(0x59, _) => Ok(Operation::Syscall(opcode)),
|
|
(0x5a, _) => Ok(Operation::NotImplemented),
|
|
(0x5b, _) => Ok(Operation::NotImplemented),
|
|
(0x5c, true) => Ok(Operation::NotImplemented),
|
|
(0x5d, true) => Ok(Operation::NotImplemented),
|
|
(0x5e, true) => Ok(Operation::NotImplemented),
|
|
(0x5f, true) => Ok(Operation::NotImplemented),
|
|
(0x60..=0x7f, _) => Ok(Operation::Push(opcode & 0x1f)),
|
|
(0x80..=0x8f, _) => Ok(Operation::Dup(opcode & 0xf)),
|
|
(0x90..=0x9f, _) => Ok(Operation::Swap(opcode & 0xf)),
|
|
(0xa0, _) => Ok(Operation::Syscall(opcode)),
|
|
(0xa1, _) => Ok(Operation::Syscall(opcode)),
|
|
(0xa2, _) => Ok(Operation::Syscall(opcode)),
|
|
(0xa3, _) => Ok(Operation::Syscall(opcode)),
|
|
(0xa4, _) => Ok(Operation::Syscall(opcode)),
|
|
(0xf0, _) => Ok(Operation::Syscall(opcode)),
|
|
(0xf1, _) => Ok(Operation::Syscall(opcode)),
|
|
(0xf2, _) => Ok(Operation::Syscall(opcode)),
|
|
(0xf3, _) => Ok(Operation::Syscall(opcode)),
|
|
(0xf4, _) => Ok(Operation::Syscall(opcode)),
|
|
(0xf5, _) => Ok(Operation::Syscall(opcode)),
|
|
(0xf6, true) => Ok(Operation::NotImplemented),
|
|
(0xf7, true) => Ok(Operation::NotImplemented),
|
|
(0xf8, true) => Ok(Operation::NotImplemented),
|
|
(0xf9, true) => Ok(Operation::ExitKernel),
|
|
(0xfa, _) => Ok(Operation::Syscall(opcode)),
|
|
(0xfb, true) => Ok(Operation::NotImplemented),
|
|
(0xfc, true) => Ok(Operation::NotImplemented),
|
|
(0xfd, _) => Ok(Operation::Syscall(opcode)),
|
|
(0xff, _) => Ok(Operation::Syscall(opcode)),
|
|
_ => Err(ProgramError::InvalidOpcode),
|
|
}
|
|
}
|
|
|
|
fn fill_op_flag<F: Field>(op: Operation, row: &mut CpuColumnsView<F>) {
|
|
let flags = &mut row.op;
|
|
*match op {
|
|
Operation::Push(_) => &mut flags.push,
|
|
Operation::Dup(_) => &mut flags.dup,
|
|
Operation::Swap(_) => &mut flags.swap,
|
|
Operation::Iszero => &mut flags.iszero,
|
|
Operation::Not => &mut flags.not,
|
|
Operation::Syscall(_) => &mut flags.syscall,
|
|
Operation::Eq => &mut flags.eq,
|
|
Operation::ExitKernel => &mut flags.exit_kernel,
|
|
Operation::BinaryLogic(logic::Op::And) => &mut flags.and,
|
|
Operation::BinaryLogic(logic::Op::Or) => &mut flags.or,
|
|
Operation::BinaryLogic(logic::Op::Xor) => &mut flags.xor,
|
|
_ => panic!("operation not implemented: {:?}", op),
|
|
} = F::ONE;
|
|
}
|
|
|
|
fn perform_op<F: Field>(
|
|
op: Operation,
|
|
registers_state: RegistersState,
|
|
memory_state: &MemoryState,
|
|
traces: &mut Traces<F>,
|
|
row: CpuColumnsView<F>,
|
|
) -> Result<RegistersState, ProgramError> {
|
|
let mut new_registers_state = match op {
|
|
Operation::Dup(n) => generate_dup(n, registers_state, memory_state, traces, row)?,
|
|
Operation::Swap(n) => generate_swap(n, registers_state, memory_state, traces, row)?,
|
|
Operation::Iszero => generate_iszero(registers_state, memory_state, traces, row)?,
|
|
Operation::Not => generate_not(registers_state, memory_state, traces, row)?,
|
|
Operation::Syscall(opcode) => {
|
|
generate_syscall(opcode, registers_state, memory_state, traces, row)?
|
|
}
|
|
Operation::Eq => generate_eq(registers_state, memory_state, traces, row)?,
|
|
Operation::ExitKernel => generate_exit_kernel(registers_state, memory_state, traces, row)?,
|
|
Operation::BinaryLogic(binary_logic_op) => {
|
|
generate_binary_logic_op(binary_logic_op, registers_state, memory_state, traces, row)?
|
|
}
|
|
_ => panic!("operation not implemented: {:?}", op),
|
|
};
|
|
|
|
new_registers_state.program_counter += match op {
|
|
Operation::Syscall(_) | Operation::ExitKernel => 0,
|
|
_ => 1,
|
|
};
|
|
|
|
Ok(new_registers_state)
|
|
}
|
|
|
|
fn try_perform_instruction<F: Field>(
|
|
registers_state: RegistersState,
|
|
memory_state: &MemoryState,
|
|
traces: &mut Traces<F>,
|
|
) -> Result<RegistersState, ProgramError> {
|
|
let mut row: CpuColumnsView<F> = [F::ZERO; NUM_CPU_COLUMNS].into();
|
|
row.is_cpu_cycle = F::ONE;
|
|
|
|
let opcode = read_code_memory(registers_state, memory_state, traces, &mut row);
|
|
let op = decode(registers_state, opcode)?;
|
|
log::trace!(
|
|
"Executing {}={:?} at {}",
|
|
opcode,
|
|
op,
|
|
registers_state.program_counter
|
|
);
|
|
// TODO: Temporarily slowing down so we can view logs easily.
|
|
std::thread::sleep(std::time::Duration::from_millis(200));
|
|
fill_op_flag(op, &mut row);
|
|
|
|
perform_op(op, registers_state, memory_state, traces, row)
|
|
}
|
|
|
|
fn handle_error<F: Field>(
|
|
_registers_state: RegistersState,
|
|
_memory_state: &MemoryState,
|
|
_traces: &mut Traces<F>,
|
|
) -> RegistersState {
|
|
todo!("constraints for exception handling are not implemented");
|
|
}
|
|
|
|
pub(crate) fn transition<F: Field>(
|
|
registers_state: RegistersState,
|
|
memory_state: &MemoryState,
|
|
traces: &mut Traces<F>,
|
|
) -> RegistersState {
|
|
let checkpoint = traces.checkpoint();
|
|
let result = try_perform_instruction(registers_state, memory_state, traces);
|
|
|
|
match result {
|
|
Ok(new_registers_state) => new_registers_state,
|
|
Err(_) => {
|
|
traces.rollback(checkpoint);
|
|
if registers_state.is_kernel {
|
|
panic!("exception in kernel mode");
|
|
}
|
|
handle_error(registers_state, memory_state, traces)
|
|
}
|
|
}
|
|
}
|