Skip to content

Commit

Permalink
Merge branch 'main' into InstructionType-from
Browse files Browse the repository at this point in the history
  • Loading branch information
tcoratger authored Nov 6, 2024
2 parents d90afac + 03a15d4 commit de5a090
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 49 deletions.
7 changes: 3 additions & 4 deletions crates/brainfuck_vm/src/bin/brainfuck_vm.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
// Adapted from rkdud007 brainfuck-zkvm https://github.com/rkdud007/brainfuck-zkvm/blob/main/src/main.rs

use brainfuck_vm::{compiler::Compiler, machine::Machine};
use clap::{Parser, ValueHint};
use std::{
fs,
io::{stdin, stdout},
path::PathBuf,
};

use brainfuck_vm::{compiler::Compiler, machine::Machine};

#[derive(Parser)]
#[clap(author, version, about, long_about = None)]
struct Args {
Expand Down Expand Up @@ -37,8 +36,8 @@ fn main() {
let stdin = stdin();
let stdout = stdout();
let mut bf_vm = match args.ram_size {
Some(size) => Machine::new_with_config(ins, stdin, stdout, size),
None => Machine::new(ins, stdin, stdout),
Some(size) => Machine::new_with_config(&ins, stdin, stdout, size),
None => Machine::new(&ins, stdin, stdout),
};
tracing::info!("Provide inputs separated by linefeeds: ");
bf_vm.execute().unwrap();
Expand Down
24 changes: 12 additions & 12 deletions crates/brainfuck_vm/src/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,25 @@ pub struct Instruction {

#[derive(PartialEq, Eq, Debug, Clone)]
pub enum InstructionType {
// '>': Increment the data pointer (to point to the next cell to the right).
/// '>': Increment the data pointer (to point to the next cell to the right).
Right,
// '<': Decrement the data pointer (to point to the next cell to the left).
/// '<': Decrement the data pointer (to point to the next cell to the left).
Left,
// '+': Increment (increase by one) the byte at the data pointer.
/// '+': Increment (increase by one) the byte at the data pointer.
Plus,
// '-': Decrement (decrease by one) the byte at the data pointer.
/// '-': Decrement (decrease by one) the byte at the data pointer.
Minus,
// '.': Output the byte at the data pointer.
/// '.': Output the byte at the data pointer.
PutChar,
// ',': Accept one byte of input, storing its value in the byte at the data pointer.
/// ',': Accept one byte of input, storing its value in the byte at the data pointer.
ReadChar,
// '[': If the byte at the data pointer is zero, then instead of moving the instruction
// pointer forward to the next command, jump it forward to the command after the matching ']'
// command.
/// '[': If the byte at the data pointer is zero, then instead of moving the instruction
/// pointer forward to the next command, jump it forward to the command after the matching ']'
/// command.
JumpIfZero,
// ']': If the byte at the data pointer is nonzero, then instead of moving the instruction
// pointer forward to the next command, jump it back to the command after the matching '['
// command.
/// ']': If the byte at the data pointer is nonzero, then instead of moving the instruction
/// pointer forward to the next command, jump it back to the command after the matching '['
/// command.
JumpIfNotZero,
}

Expand Down
102 changes: 76 additions & 26 deletions crates/brainfuck_vm/src/machine.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,64 @@
// Adapted from rkdud007 brainfuck-zkvm https://github.com/rkdud007/brainfuck-zkvm/blob/main/src/machine.rs

use crate::{instruction::InstructionType, registers::Registers};
use num_traits::identities::{One, Zero};
use std::{
error::Error,
io::{Read, Write},
};
use stwo_prover::core::fields::{m31::BaseField, FieldExpOps};

use num_traits::identities::{One, Zero};
pub struct MachineBuilder {
code: Vec<BaseField>,
input: Option<Box<dyn Read>>,
output: Option<Box<dyn Write>>,
ram_size: usize,
}

use stwo_prover::core::fields::{m31::BaseField, FieldExpOps};
impl MachineBuilder {
/// Creates a new [`MachineBuilder`] with the specified code.
pub fn new(code: &[BaseField]) -> Self {
Self { code: code.to_vec(), input: None, output: None, ram_size: Machine::DEFAULT_RAM_SIZE }
}

use crate::{instruction::InstructionType, registers::Registers};
/// Sets the input stream for the machine.
#[must_use]
pub fn with_input<R: Read + 'static>(mut self, input: R) -> Self {
self.input = Some(Box::new(input));
self
}

/// Sets the output stream for the machine.
#[must_use]
pub fn with_output<W: Write + 'static>(mut self, output: W) -> Self {
self.output = Some(Box::new(output));
self
}

/// Sets the RAM size for the machine.
#[must_use]
pub const fn with_ram_size(mut self, ram_size: usize) -> Self {
self.ram_size = ram_size;
self
}

/// Builds the [`Machine`] instance with the provided configuration.
pub fn build(self) -> Result<Machine, &'static str> {
if self.input.is_none() || self.output.is_none() {
return Err("Input and output streams must be provided");
}

Ok(Machine {
program: ProgramMemory { code: self.code },
state: MutableState {
ram: vec![BaseField::zero(); self.ram_size],
registers: Registers::new(),
},
io: IO { input: self.input.unwrap(), output: self.output.unwrap() },
trace: vec![],
})
}
}

pub struct ProgramMemory {
code: Vec<BaseField>,
Expand All @@ -35,28 +84,29 @@ pub struct Machine {
impl Machine {
pub const DEFAULT_RAM_SIZE: usize = 30000;

pub fn new_with_config<R, W>(code: Vec<BaseField>, input: R, output: W, ram_size: usize) -> Self
pub fn new_with_config<R, W>(code: &[BaseField], input: R, output: W, ram_size: usize) -> Self
where
R: Read + 'static,
W: Write + 'static,
{
Self {
program: ProgramMemory { code },
state: MutableState {
ram: vec![BaseField::zero(); ram_size],
registers: Registers::new(),
},
io: IO { input: Box::new(input), output: Box::new(output) },
trace: vec![],
}
MachineBuilder::new(code)
.with_input(input)
.with_output(output)
.with_ram_size(ram_size)
.build()
.expect("Failed to build Machine")
}

pub fn new<R, W>(code: Vec<BaseField>, input: R, output: W) -> Self
pub fn new<R, W>(code: &[BaseField], input: R, output: W) -> Self
where
R: Read + 'static,
W: Write + 'static,
{
Self::new_with_config(code, input, output, Self::DEFAULT_RAM_SIZE)
MachineBuilder::new(code)
.with_input(input)
.with_output(output)
.build()
.expect("Failed to build Machine")
}

pub fn execute(&mut self) -> Result<(), Box<dyn Error>> {
Expand Down Expand Up @@ -185,7 +235,7 @@ mod tests {
#[test]
fn test_default_machine_initialization() {
let code = vec![BaseField::from(43)];
let (machine, _) = create_test_machine(code.clone(), &[]);
let (machine, _) = create_test_machine(&code, &[]);

assert_eq!(machine.program.code, code);
assert_eq!(machine.state.ram.len(), Machine::DEFAULT_RAM_SIZE);
Expand All @@ -198,7 +248,7 @@ mod tests {
let input: &[u8] = &[];
let output = TestWriter::new();
let ram_size = 55000;
let machine = Machine::new_with_config(code.clone(), input, output, ram_size);
let machine = Machine::new_with_config(&code, input, output, ram_size);

assert_eq!(machine.program.code, code);
assert_eq!(machine.state.ram.len(), ram_size);
Expand All @@ -209,7 +259,7 @@ mod tests {
fn test_right_instruction() -> Result<(), Box<dyn Error>> {
// '>>'
let code = vec![BaseField::from(62), BaseField::from(62)];
let (mut machine, _) = create_test_machine(code, &[]);
let (mut machine, _) = create_test_machine(&code, &[]);
machine.execute()?;

assert_eq!(machine.state.registers.mp, BaseField::from(2));
Expand All @@ -220,7 +270,7 @@ mod tests {
fn test_left_instruction() -> Result<(), Box<dyn Error>> {
// '>><'
let code = vec![BaseField::from(62), BaseField::from(62), BaseField::from(60)];
let (mut machine, _) = create_test_machine(code, &[]);
let (mut machine, _) = create_test_machine(&code, &[]);
machine.execute()?;

assert_eq!(machine.state.registers.mp, BaseField::from(1));
Expand All @@ -231,7 +281,7 @@ mod tests {
fn test_plus_instruction() -> Result<(), Box<dyn Error>> {
// '+'
let code = vec![BaseField::from(43)];
let (mut machine, _) = create_test_machine(code, &[]);
let (mut machine, _) = create_test_machine(&code, &[]);
machine.execute()?;

assert_eq!(machine.state.ram[0], BaseField::from(1));
Expand All @@ -243,7 +293,7 @@ mod tests {
fn test_minus_instruction() -> Result<(), Box<dyn Error>> {
// '--'
let code = vec![BaseField::from(45), BaseField::from(45)];
let (mut machine, _) = create_test_machine(code, &[]);
let (mut machine, _) = create_test_machine(&code, &[]);
machine.execute()?;

assert_eq!(machine.state.ram[0], BaseField::from(P - 2));
Expand All @@ -256,7 +306,7 @@ mod tests {
// ',.'
let code = vec![BaseField::from(44), BaseField::from(46)];
let input = b"a";
let (mut machine, output) = create_test_machine(code, input);
let (mut machine, output) = create_test_machine(&code, input);

machine.execute()?;

Expand All @@ -277,7 +327,7 @@ mod tests {
BaseField::from(2),
BaseField::from(43),
];
let (mut machine, _) = create_test_machine(code, &[]);
let (mut machine, _) = create_test_machine(&code, &[]);
machine.execute()?;

assert_eq!(machine.state.ram[0], BaseField::one());
Expand All @@ -298,7 +348,7 @@ mod tests {
BaseField::from(93),
BaseField::from(3),
];
let (mut machine, _) = create_test_machine(code, &[]);
let (mut machine, _) = create_test_machine(&code, &[]);
machine.execute()?;

assert_eq!(machine.state.ram[0], BaseField::from(2));
Expand All @@ -311,7 +361,7 @@ mod tests {
fn test_get_trace() -> Result<(), Box<dyn Error>> {
// '++'
let code = vec![BaseField::from(43), BaseField::from(43)];
let (mut machine, _) = create_test_machine(code, &[]);
let (mut machine, _) = create_test_machine(&code, &[]);
machine.execute()?;

// Initial state + executed instructions
Expand Down Expand Up @@ -356,7 +406,7 @@ mod tests {
fn test_pad_trace() -> Result<(), Box<dyn Error>> {
// '++'
let code = vec![BaseField::from(43), BaseField::from(43)];
let (mut machine, _) = create_test_machine(code, &[]);
let (mut machine, _) = create_test_machine(&code, &[]);
machine.execute()?;

// Initial state + executed instructions
Expand Down
2 changes: 1 addition & 1 deletion crates/brainfuck_vm/src/test_helper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ impl Clone for TestWriter {
}

// Helper function to create a test machine
pub fn create_test_machine(code: Vec<BaseField>, input: &[u8]) -> (Machine, TestWriter) {
pub fn create_test_machine(code: &[BaseField], input: &[u8]) -> (Machine, TestWriter) {
let input = Cursor::new(input.to_vec());
let output = TestWriter::new();
let test_output = output.clone();
Expand Down
12 changes: 6 additions & 6 deletions crates/brainfuck_vm/tests/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ fn test_a_bc() {

let code = compile_from_path(path);
let input = b"a";
let (mut machine, output) = create_test_machine(code, input);
let (mut machine, output) = create_test_machine(&code, input);
machine.execute().unwrap();
let expected_output = b"bc".to_vec();
assert_eq!(output.get_output(), expected_output);
Expand All @@ -27,7 +27,7 @@ fn test_collatz() {

let code = compile_from_path(path);
let input = &[0x37, 10]; // 7 EOF
let (mut machine, output) = create_test_machine(code, input);
let (mut machine, output) = create_test_machine(&code, input);
machine.execute().unwrap();
let expected_output = [0x31, 0x36, 10].to_vec(); // 16 EOF
assert_eq!(output.get_output(), expected_output);
Expand All @@ -38,7 +38,7 @@ fn test_hello_world_1() {
let path = "../../brainfuck_programs/hello1.bf";

let code = compile_from_path(path);
let (mut machine, output) = create_test_machine(code, &[]);
let (mut machine, output) = create_test_machine(&code, &[]);
machine.execute().unwrap();
let expected_output = b"Hello World!\n".to_vec();
assert_eq!(output.get_output(), expected_output);
Expand All @@ -49,7 +49,7 @@ fn test_hello_world_2() {
let path = "../../brainfuck_programs/hello2.bf";

let code = compile_from_path(path);
let (mut machine, output) = create_test_machine(code, &[]);
let (mut machine, output) = create_test_machine(&code, &[]);
machine.execute().unwrap();
let expected_output = b"Hello World!\n".to_vec();
assert_eq!(output.get_output(), expected_output);
Expand All @@ -60,7 +60,7 @@ fn test_hello_world_3() {
let path = "../../brainfuck_programs/hello3.bf";

let code = compile_from_path(path);
let (mut machine, output) = create_test_machine(code, &[]);
let (mut machine, output) = create_test_machine(&code, &[]);
machine.execute().unwrap();
let expected_output = b"Hello, World!\n".to_vec();
assert_eq!(output.get_output(), expected_output);
Expand All @@ -71,7 +71,7 @@ fn test_hello_world_4() {
let path = "../../brainfuck_programs/hello4.bf";

let code = compile_from_path(path);
let (mut machine, output) = create_test_machine(code, &[]);
let (mut machine, output) = create_test_machine(&code, &[]);
machine.execute().unwrap();
let expected_output = b"Hello World!\n".to_vec();
assert_eq!(output.get_output(), expected_output);
Expand Down

0 comments on commit de5a090

Please sign in to comment.