Skip to content

Commit

Permalink
Merge pull request #1360 from o1-labs/dw/start-interpreter
Browse files Browse the repository at this point in the history
Interpreter: add InstructionParts and decode it
  • Loading branch information
dannywillems authored Dec 1, 2023
2 parents 5db877a + 4830a6d commit 7972ca1
Show file tree
Hide file tree
Showing 4 changed files with 168 additions and 103 deletions.
11 changes: 10 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,13 @@ _build

*.html
# If symlink created for kimchi-visu
tools/srs
tools/srs

optimism/*op-program-data-log.sh
optimism/cpu.pprof
optimism/meta.json
optimism/out.json
optimism/op-program-db*
optimism/state.json
meta.json
state.json
2 changes: 1 addition & 1 deletion optimism/run-vm.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/env bash
set -euo pipefail

cargo run -p kimchi_optimism -- \
cargo run --release -p kimchi_optimism -- \
--pprof-cpu \
--info-at '%10000000' \
--proof-at never \
Expand Down
38 changes: 38 additions & 0 deletions optimism/src/mips/interpreter.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use serde::{Deserialize, Serialize};
use std::ops::Index;
use strum_macros::{EnumCount, EnumIter};

pub const FD_STDIN: u32 = 0;
Expand All @@ -8,6 +10,42 @@ pub const FD_HINT_WRITE: u32 = 4;
pub const FD_PREIMAGE_READ: u32 = 5;
pub const FD_PREIMAGE_WRITE: u32 = 6;

#[derive(Debug, Clone, Copy, Eq, PartialEq, EnumCount, EnumIter)]
pub enum InstructionPart {
OpCode,
RS,
RT,
RD,
Shamt,
Funct,
}

#[derive(Debug, Clone, Copy, Eq, PartialEq, Default, Serialize, Deserialize)]
pub struct InstructionParts<T> {
pub op_code: T,
pub rs: T,
pub rt: T,
pub rd: T,
pub shamt: T,
pub funct: T,
}

// To use InstructionParts[OpCode]
impl<A> Index<InstructionPart> for InstructionParts<A> {
type Output = A;

fn index(&self, index: InstructionPart) -> &Self::Output {
match index {
InstructionPart::OpCode => &self.op_code,
InstructionPart::RS => &self.rs,
InstructionPart::RT => &self.rt,
InstructionPart::RD => &self.rd,
InstructionPart::Shamt => &self.shamt,
InstructionPart::Funct => &self.funct,
}
}
}

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum Instruction {
RType(RTypeInstruction),
Expand Down
220 changes: 119 additions & 101 deletions optimism/src/mips/witness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ use crate::{
},
mips::{
interpreter::{
self, ITypeInstruction, Instruction, InterpreterEnv, JTypeInstruction, RTypeInstruction,
self, ITypeInstruction, Instruction, InstructionParts, InterpreterEnv,
JTypeInstruction, RTypeInstruction,
},
registers::Registers,
},
Expand Down Expand Up @@ -42,6 +43,7 @@ impl SyscallEnv {
}

pub struct Env<Fp> {
pub instruction_parts: InstructionParts<u32>,
pub instruction_counter: usize,
pub memory: Vec<(u32, Vec<u8>)>,
pub memory_write_index: Vec<(u32, Vec<usize>)>,
Expand Down Expand Up @@ -144,6 +146,9 @@ impl<Fp: Field> Env<Fp> {
};

Env {
// Will be modified by decode_instruction.
// We set the instruction parts to 0 to begin
instruction_parts: InstructionParts::default(),
instruction_counter: state.step as usize,
memory: initial_memory.clone(),
memory_write_index: memory_offsets
Expand Down Expand Up @@ -176,122 +181,135 @@ impl<Fp: Field> Env<Fp> {
panic!("Could not access address")
}

pub fn decode_instruction(&self) -> Instruction {
pub fn decode_instruction(&self) -> (Instruction, u32) {
let instruction = ((self.get_memory_direct(self.instruction_pointer) as u32) << 24)
| ((self.get_memory_direct(self.instruction_pointer + 1) as u32) << 16)
| ((self.get_memory_direct(self.instruction_pointer + 2) as u32) << 8)
| (self.get_memory_direct(self.instruction_pointer + 3) as u32);
match instruction >> 26 {
0x00 => match instruction & 0x3F {
0x00 => Instruction::RType(RTypeInstruction::ShiftLeftLogical),
0x02 => Instruction::RType(RTypeInstruction::ShiftRightLogical),
0x03 => Instruction::RType(RTypeInstruction::ShiftRightArithmetic),
0x04 => Instruction::RType(RTypeInstruction::ShiftLeftLogicalVariable),
0x06 => Instruction::RType(RTypeInstruction::ShiftRightLogicalVariable),
0x07 => Instruction::RType(RTypeInstruction::ShiftRightArithmeticVariable),
0x08 => Instruction::RType(RTypeInstruction::JumpRegister),
0x09 => Instruction::RType(RTypeInstruction::JumpAndLinkRegister),
0x0a => Instruction::RType(RTypeInstruction::MoveZero),
0x0b => Instruction::RType(RTypeInstruction::MoveNonZero),
0x0c => match self.registers.general_purpose[2] {
4090 => Instruction::RType(RTypeInstruction::SyscallMmap),
4045 => {
// sysBrk
Instruction::RType(RTypeInstruction::SyscallOther)
}
4120 => {
// sysClone
Instruction::RType(RTypeInstruction::SyscallOther)
}
4246 => Instruction::RType(RTypeInstruction::SyscallExitGroup),
4003 => match self.registers.general_purpose[4] {
interpreter::FD_PREIMAGE_READ => {
Instruction::RType(RTypeInstruction::SyscallReadPreimage)
let opcode = {
match instruction >> 26 {
0x00 => match instruction & 0x3F {
0x00 => Instruction::RType(RTypeInstruction::ShiftLeftLogical),
0x02 => Instruction::RType(RTypeInstruction::ShiftRightLogical),
0x03 => Instruction::RType(RTypeInstruction::ShiftRightArithmetic),
0x04 => Instruction::RType(RTypeInstruction::ShiftLeftLogicalVariable),
0x06 => Instruction::RType(RTypeInstruction::ShiftRightLogicalVariable),
0x07 => Instruction::RType(RTypeInstruction::ShiftRightArithmeticVariable),
0x08 => Instruction::RType(RTypeInstruction::JumpRegister),
0x09 => Instruction::RType(RTypeInstruction::JumpAndLinkRegister),
0x0a => Instruction::RType(RTypeInstruction::MoveZero),
0x0b => Instruction::RType(RTypeInstruction::MoveNonZero),
0x0c => match self.registers.general_purpose[2] {
4090 => Instruction::RType(RTypeInstruction::SyscallMmap),
4045 => {
// sysBrk
Instruction::RType(RTypeInstruction::SyscallOther)
}
_ => Instruction::RType(RTypeInstruction::SyscallReadOther),
},
4004 => match self.registers.general_purpose[4] {
interpreter::FD_PREIMAGE_WRITE => {
Instruction::RType(RTypeInstruction::SyscallWritePreimage)
4120 => {
// sysClone
Instruction::RType(RTypeInstruction::SyscallOther)
}
interpreter::FD_HINT_WRITE => {
Instruction::RType(RTypeInstruction::SyscallWriteHint)
4246 => Instruction::RType(RTypeInstruction::SyscallExitGroup),
4003 => match self.registers.general_purpose[4] {
interpreter::FD_PREIMAGE_READ => {
Instruction::RType(RTypeInstruction::SyscallReadPreimage)
}
_ => Instruction::RType(RTypeInstruction::SyscallReadOther),
},
4004 => match self.registers.general_purpose[4] {
interpreter::FD_PREIMAGE_WRITE => {
Instruction::RType(RTypeInstruction::SyscallWritePreimage)
}
interpreter::FD_HINT_WRITE => {
Instruction::RType(RTypeInstruction::SyscallWriteHint)
}
_ => Instruction::RType(RTypeInstruction::SyscallWriteOther),
},
4055 => Instruction::RType(RTypeInstruction::SyscallFcntl),
_ => {
// NB: This has well-defined behavior. Don't panic!
Instruction::RType(RTypeInstruction::SyscallOther)
}
_ => Instruction::RType(RTypeInstruction::SyscallWriteOther),
},
4055 => Instruction::RType(RTypeInstruction::SyscallFcntl),
0x0f => Instruction::RType(RTypeInstruction::Sync),
0x10 => Instruction::RType(RTypeInstruction::MoveFromHi),
0x11 => Instruction::RType(RTypeInstruction::MoveToHi),
0x12 => Instruction::RType(RTypeInstruction::MoveFromLo),
0x13 => Instruction::RType(RTypeInstruction::MoveToLo),
0x18 => Instruction::RType(RTypeInstruction::Multiply),
0x19 => Instruction::RType(RTypeInstruction::MultiplyUnsigned),
0x1a => Instruction::RType(RTypeInstruction::Div),
0x1b => Instruction::RType(RTypeInstruction::DivUnsigned),
0x20 => Instruction::RType(RTypeInstruction::Add),
0x21 => Instruction::RType(RTypeInstruction::AddUnsigned),
0x22 => Instruction::RType(RTypeInstruction::Sub),
0x23 => Instruction::RType(RTypeInstruction::SubUnsigned),
0x24 => Instruction::RType(RTypeInstruction::And),
0x25 => Instruction::RType(RTypeInstruction::Or),
0x26 => Instruction::RType(RTypeInstruction::Xor),
0x2a => Instruction::RType(RTypeInstruction::SetLessThan),
0x2b => Instruction::RType(RTypeInstruction::SetLessThanUnsigned),
_ => {
// NB: This has well-defined behavior. Don't panic!
Instruction::RType(RTypeInstruction::SyscallOther)
panic!("Unhandled instruction {:#X}", instruction)
}
},
0x0f => Instruction::RType(RTypeInstruction::Sync),
0x10 => Instruction::RType(RTypeInstruction::MoveFromHi),
0x11 => Instruction::RType(RTypeInstruction::MoveToHi),
0x12 => Instruction::RType(RTypeInstruction::MoveFromLo),
0x13 => Instruction::RType(RTypeInstruction::MoveToLo),
0x18 => Instruction::RType(RTypeInstruction::Multiply),
0x19 => Instruction::RType(RTypeInstruction::MultiplyUnsigned),
0x1a => Instruction::RType(RTypeInstruction::Div),
0x1b => Instruction::RType(RTypeInstruction::DivUnsigned),
0x20 => Instruction::RType(RTypeInstruction::Add),
0x21 => Instruction::RType(RTypeInstruction::AddUnsigned),
0x22 => Instruction::RType(RTypeInstruction::Sub),
0x23 => Instruction::RType(RTypeInstruction::SubUnsigned),
0x24 => Instruction::RType(RTypeInstruction::And),
0x25 => Instruction::RType(RTypeInstruction::Or),
0x26 => Instruction::RType(RTypeInstruction::Xor),
0x2a => Instruction::RType(RTypeInstruction::SetLessThan),
0x2b => Instruction::RType(RTypeInstruction::SetLessThanUnsigned),
0x02 => Instruction::JType(JTypeInstruction::Jump),
0x03 => Instruction::JType(JTypeInstruction::JumpAndLink),
0x08 => Instruction::IType(ITypeInstruction::AddImmediate),
0x09 => Instruction::IType(ITypeInstruction::AddImmediateUnsigned),
0x0A => Instruction::IType(ITypeInstruction::SetLessThanImmediate),
0x0B => Instruction::IType(ITypeInstruction::SetLessThanImmediateUnsigned),
0x0C => Instruction::IType(ITypeInstruction::AndImmediate),
0x0D => Instruction::IType(ITypeInstruction::OrImmediate),
0x0E => Instruction::IType(ITypeInstruction::XorImmediate),
0x0F => Instruction::IType(ITypeInstruction::LoadUpperImmediate),
0x1C => match instruction & 0x3F {
0x02 => Instruction::RType(RTypeInstruction::MultiplyToRegister),
0x20 => Instruction::RType(RTypeInstruction::CountLeadingZeros),
0x21 => Instruction::RType(RTypeInstruction::CountLeadingOnes),
_ => panic!("Unhandled instruction {:#X}", instruction),
},
0x20 => Instruction::IType(ITypeInstruction::Load8),
0x21 => Instruction::IType(ITypeInstruction::Load16),
0x22 => Instruction::IType(ITypeInstruction::LoadWordLeft),
0x23 => Instruction::IType(ITypeInstruction::Load32),
0x24 => Instruction::IType(ITypeInstruction::Load8Unsigned),
0x25 => Instruction::IType(ITypeInstruction::Load16Unsigned),
0x26 => Instruction::IType(ITypeInstruction::LoadWordRight),
0x28 => Instruction::IType(ITypeInstruction::Store8),
0x29 => Instruction::IType(ITypeInstruction::Store16),
0x2a => Instruction::IType(ITypeInstruction::StoreWordLeft),
0x2b => Instruction::IType(ITypeInstruction::Store32),
0x2e => Instruction::IType(ITypeInstruction::StoreWordRight),
0x30 => {
// Note: This is ll (LoadLinked), but we're only simulating a single processor.
Instruction::IType(ITypeInstruction::Load32)
}
0x38 => {
// Note: This is sc (StoreConditional), but we're only simulating a single processor.
Instruction::IType(ITypeInstruction::Store32)
}
_ => {
panic!("Unhandled instruction {:#X}", instruction)
}
},
0x02 => Instruction::JType(JTypeInstruction::Jump),
0x03 => Instruction::JType(JTypeInstruction::JumpAndLink),
0x08 => Instruction::IType(ITypeInstruction::AddImmediate),
0x09 => Instruction::IType(ITypeInstruction::AddImmediateUnsigned),
0x0A => Instruction::IType(ITypeInstruction::SetLessThanImmediate),
0x0B => Instruction::IType(ITypeInstruction::SetLessThanImmediateUnsigned),
0x0C => Instruction::IType(ITypeInstruction::AndImmediate),
0x0D => Instruction::IType(ITypeInstruction::OrImmediate),
0x0E => Instruction::IType(ITypeInstruction::XorImmediate),
0x0F => Instruction::IType(ITypeInstruction::LoadUpperImmediate),
0x1C => match instruction & 0x3F {
0x02 => Instruction::RType(RTypeInstruction::MultiplyToRegister),
0x20 => Instruction::RType(RTypeInstruction::CountLeadingZeros),
0x21 => Instruction::RType(RTypeInstruction::CountLeadingOnes),
_ => panic!("Unhandled instruction {:#X}", instruction),
},
0x20 => Instruction::IType(ITypeInstruction::Load8),
0x21 => Instruction::IType(ITypeInstruction::Load16),
0x22 => Instruction::IType(ITypeInstruction::LoadWordLeft),
0x23 => Instruction::IType(ITypeInstruction::Load32),
0x24 => Instruction::IType(ITypeInstruction::Load8Unsigned),
0x25 => Instruction::IType(ITypeInstruction::Load16Unsigned),
0x26 => Instruction::IType(ITypeInstruction::LoadWordRight),
0x28 => Instruction::IType(ITypeInstruction::Store8),
0x29 => Instruction::IType(ITypeInstruction::Store16),
0x2a => Instruction::IType(ITypeInstruction::StoreWordLeft),
0x2b => Instruction::IType(ITypeInstruction::Store32),
0x2e => Instruction::IType(ITypeInstruction::StoreWordRight),
0x30 => {
// Note: This is ll (LoadLinked), but we're only simulating a single processor.
Instruction::IType(ITypeInstruction::Load32)
}
0x38 => {
// Note: This is sc (StoreConditional), but we're only simulating a single processor.
Instruction::IType(ITypeInstruction::Store32)
}
_ => {
panic!("Unhandled instruction {:#X}", instruction)
}
}
};
(opcode, instruction)
}

pub fn step(&mut self, config: VmConfiguration, metadata: &Meta, start: &Start) {
let instruction = self.decode_instruction();
println!("instruction: {:?}", instruction);
let (opcode, instruction) = self.decode_instruction();
let instruction_parts: InstructionParts<u32> = InstructionParts {
op_code: ((instruction >> 26) & ((1 << (32 - 26)) - 1)),
rs: ((instruction >> 21) & ((1 << (26 - 21)) - 1)),
rt: ((instruction >> 16) & ((1 << (21 - 16)) - 1)),
rd: ((instruction >> 11) & ((1 << (16 - 11)) - 1)),
shamt: ((instruction >> 6) & ((1 << (11 - 6)) - 1)),
funct: (instruction & ((1 << 6) - 1)),
};
self.instruction_parts = instruction_parts;

println!("instruction: {:?}", opcode);

self.pp_info(config.info_at, metadata, start);

Expand All @@ -301,7 +319,7 @@ impl<Fp: Field> Env<Fp> {
return;
}

interpreter::interpret_instruction(self, instruction);
interpreter::interpret_instruction(self, opcode);
}

fn should_trigger_at(&self, at: StepFrequency) -> bool {
Expand Down Expand Up @@ -361,7 +379,7 @@ impl<Fp: Field> Env<Fp> {
.unwrap_or_else(|| "n/a".to_string());

info!(
"processing step {} pc {:#010x} insn {:#010x} ips {:.2} page {} mem {} name {}",
"processing step={} pc={:#010x} insn={:#010x} ips={:.2} page={} mem={} name={}",
step, pc, insn, ips, pages, mem, name
);
}
Expand Down

0 comments on commit 7972ca1

Please sign in to comment.