Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add STOREU8, LOADU8, LOADS8 #151

Merged
merged 13 commits into from
Apr 19, 2024
2 changes: 1 addition & 1 deletion assembler/grammar/assembly.pest
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ comment = { ";" ~ (!"\n" ~ ANY)* ~ "\n" }
label = { (!":" ~ !"\n" ~ ANY)+ ~ ":" ~ "\n" }
instruction = { mnemonic ~ (operand ~ ", "?)+? ~ "\n"? }
mnemonic = {
"lw" | "sw" | "jalv" | "jal" | "beqi" | "beq" | "bnei" | "bne" | "imm32" | "stop" |
"lw" | "sw" | "loadu8" | "loads8" | "storeu8" | "jalv" | "jal" | "beqi" | "beq" | "bnei" | "bne" | "imm32" | "stop" |
"advread" | "advwrite" |
"addi" | "add" | "subi" | "sub" | "muli" | "mul" | "mulhsi"| "mulhui"| "mulhs"| "mulhu" | "divi" | "div" | "sdiv" | "sdivi" |
"ilte" | "ltei" | "lte" | "ilt" | "lti" | "lt" | "shli" | "shl" | "shri" | "shr" | "srai" | "sra" |
Expand Down
7 changes: 5 additions & 2 deletions assembler/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,10 @@ pub fn assemble(input: &str) -> Result<Vec<u8>, String> {
let opcode = match mnemonic {
// Core CPU
"lw" => LOAD32,
"loadu8" => LOADU8,
"loads8" => LOADS8,
"sw" => STORE32,
"storeu8" => STOREU8,
"jal" => JAL,
"jalv" => JALV,
"beq" | "beqi" => BEQ,
Expand Down Expand Up @@ -101,12 +104,12 @@ pub fn assemble(input: &str) -> Result<Vec<u8>, String> {

// Insert zero operands if necessary
match mnemonic {
"lw" => {
"lw" | "loadu8" | "loads8" => {
// (a, 0, c, 0, 0)
operands.insert(1, 0);
operands.extend(vec![0; 2]);
}
"sw" => {
"sw" | "storeu8" => {
// (0, b, c, 0, 0)
operands.insert(0, 0);
operands.extend(vec![0; 2]);
Expand Down
2 changes: 1 addition & 1 deletion basic/src/bin/valida.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ fn last_frame(_: ArgMatches, context: &mut Context) -> Result<Option<String>> {
frame += &format!("Current FP: 0x{:x}\n", fp).as_str();

// print last frame
for i in (-5..(last_size / 4) + 1).rev() {
for i in (-10..(last_size / 4) + 1).rev() {
let offset = (i * 4) as i32;
let read_addr = (fp + offset) as u32;
let string_val = context.machine_.mem().examine(read_addr);
Expand Down
17 changes: 15 additions & 2 deletions basic/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ use valida_bus::{
};
use valida_cpu::{
BeqInstruction, BneInstruction, Imm32Instruction, JalInstruction, JalvInstruction,
Load32Instruction, LoadFpInstruction, ReadAdviceInstruction, StopInstruction,
Store32Instruction,
Load32Instruction, LoadFpInstruction, LoadS8Instruction, LoadU8Instruction,
ReadAdviceInstruction, StopInstruction, Store32Instruction, StoreU8Instruction,
};
use valida_cpu::{CpuChip, MachineWithCpuChip};
use valida_machine::__internal::p3_challenger::{CanObserve, FieldChallenger};
Expand All @@ -63,7 +63,11 @@ use valida_machine::StarkConfig;
pub struct BasicMachine<F: PrimeField32 + TwoAdicField> {
// Core instructions
load32: Load32Instruction,
loadu8: LoadU8Instruction,
loads8: LoadS8Instruction,
store32: Store32Instruction,
storeu8: StoreU8Instruction,

jal: JalInstruction,
jalv: JalvInstruction,
beq: BeqInstruction,
Expand Down Expand Up @@ -1071,9 +1075,18 @@ impl<F: PrimeField32 + TwoAdicField> Machine<F> for BasicMachine<F> {
<Load32Instruction as Instruction<Self, F>>::OPCODE => {
Load32Instruction::execute_with_advice::<Adv>(self, ops, advice)
}
<LoadU8Instruction as Instruction<Self, F>>::OPCODE => {
LoadU8Instruction::execute_with_advice::<Adv>(self, ops, advice)
}
<LoadS8Instruction as Instruction<Self, F>>::OPCODE => {
LoadS8Instruction::execute_with_advice::<Adv>(self, ops, advice)
}
<Store32Instruction as Instruction<Self, F>>::OPCODE => {
Store32Instruction::execute_with_advice::<Adv>(self, ops, advice)
}
<StoreU8Instruction as Instruction<Self, F>>::OPCODE => {
StoreU8Instruction::execute_with_advice::<Adv>(self, ops, advice)
}
<JalInstruction as Instruction<Self, F>>::OPCODE => {
JalInstruction::execute_with_advice::<Adv>(self, ops, advice)
}
Expand Down
3 changes: 3 additions & 0 deletions cpu/src/columns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,10 @@ pub struct OpcodeFlagCols<T> {
pub is_bus_op_with_mem: T,
pub is_imm_op: T,
pub is_load: T,
pub is_load_u8: T,
pub is_load_s8: T,
pub is_store: T,
pub is_store_u8: T,
pub is_beq: T,
pub is_bne: T,
pub is_jal: T,
Expand Down
189 changes: 186 additions & 3 deletions cpu/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ use core::marker::Sync;
use core::mem::transmute;
use valida_bus::{MachineWithGeneralBus, MachineWithMemBus, MachineWithProgramBus};
use valida_machine::{
instructions, AdviceProvider, Chip, Instruction, InstructionWord, Interaction, Operands, Word,
addr_of_word, index_of_byte, instructions, AdviceProvider, Chip, Instruction, InstructionWord,
Interaction, Operands, Word,
};
use valida_memory::{MachineWithMemoryChip, Operation as MemoryOperation};
use valida_opcodes::{
BEQ, BNE, BYTES_PER_INSTR, IMM32, JAL, JALV, LOAD32, LOADFP, READ_ADVICE, STOP, STORE32,
BEQ, BNE, BYTES_PER_INSTR, IMM32, JAL, JALV, LOAD32, LOADFP, LOADS8, LOADU8, READ_ADVICE, STOP,
STORE32, STOREU8,
};

use p3_air::VirtualPairCol;
Expand All @@ -31,7 +33,10 @@ pub mod stark;
#[derive(Clone)]
pub enum Operation {
Store32,
StoreU8,
Load32,
LoadU8,
LoadS8,
Jal,
Jalv,
Beq(Option<Word<u8>> /*imm*/),
Expand Down Expand Up @@ -175,6 +180,15 @@ impl CpuChip {
Operation::Load32 => {
cols.opcode_flags.is_load = SC::Val::one();
}
Operation::StoreU8 => {
cols.opcode_flags.is_store_u8 = SC::Val::one();
}
Operation::LoadU8 => {
cols.opcode_flags.is_load_u8 = SC::Val::one();
}
Operation::LoadS8 => {
cols.opcode_flags.is_load_s8 = SC::Val::one();
}
Operation::Jal => {
cols.opcode_flags.is_jal = SC::Val::one();
}
Expand Down Expand Up @@ -349,7 +363,10 @@ pub trait MachineWithCpuChip<F: Field>: MachineWithMemoryChip<F> {

instructions!(
Load32Instruction,
LoadU8Instruction,
LoadS8Instruction,
Store32Instruction,
StoreU8Instruction,
JalInstruction,
JalvInstruction,
BeqInstruction,
Expand Down Expand Up @@ -441,6 +458,119 @@ where
}
}

impl<M, F> Instruction<M, F> for LoadU8Instruction
where
M: MachineWithCpuChip<F>,
F: Field,
{
const OPCODE: u32 = LOADU8;

fn execute(state: &mut M, ops: Operands<i32>) {
let opcode = <Self as Instruction<M, F>>::OPCODE;
let clk = state.cpu().clock;
let pc = state.cpu().pc;
let fp = state.cpu().fp;

let read_addr_loc = (fp as i32 + ops.c()) as u32;

let read_addr = state
.mem_mut()
.read(clk, read_addr_loc, true, pc, opcode, 0, "");
let read_addr_index = addr_of_word(read_addr.into());

// The word from the read address.
let cell = state.mem_mut().read(
clk,
read_addr_index,
true,
pc,
opcode,
1,
&format!(
"fp = {}, c = {}, [fp+c] = {:?}",
fp as i32,
ops.c() as u32,
read_addr_index
),
);

// The array index of the word for the byte to read from
let index_of_read = index_of_byte(read_addr.into());
// The byte from the read cell.
let cell_byte = cell[index_of_read];

let write_addr = (state.cpu().fp as i32 + ops.a()) as u32;
// The address, converted to a multiple of 4.
let write_addr_index = addr_of_word(write_addr);

// The Word to write, with one byte overwritten to the read byte
let cell_to_write = Word::zero_extend_byte(cell_byte);

state
.mem_mut()
.write(clk, write_addr_index, cell_to_write, true);
state.cpu_mut().pc += 1;
state.cpu_mut().push_op(Operation::LoadU8, opcode, ops);
}
}

impl<M, F> Instruction<M, F> for LoadS8Instruction
where
M: MachineWithCpuChip<F>,
F: Field,
{
const OPCODE: u32 = LOADS8;

fn execute(state: &mut M, ops: Operands<i32>) {
let opcode = <Self as Instruction<M, F>>::OPCODE;
let clk = state.cpu().clock;
let pc = state.cpu().pc;
let fp = state.cpu().fp;

let read_addr_loc = (fp as i32 + ops.c()) as u32;

let read_addr = state
.mem_mut()
.read(clk, read_addr_loc, true, pc, opcode, 0, "");

let read_addr_index = addr_of_word(read_addr.into());

// The word from the read address.
let cell = state.mem_mut().read(
clk,
read_addr_index,
true,
pc,
opcode,
1,
&format!(
"fp = {}, c = {}, [fp+c] = {:?}",
fp as i32,
ops.c() as u32,
read_addr_index
),
);

// The array index of the word for the byte to read from
let index_of_read = index_of_byte(read_addr.into());
// The byte from the read cell.
let cell_byte = cell[index_of_read];

let write_addr = (state.cpu().fp as i32 + ops.a()) as u32;
// The address, converted to a multiple of 4.
let write_addr_index = addr_of_word(write_addr);

// The Word to write, with one byte overwritten to the read byte
let cell_to_write = Word::sign_extend_byte(cell_byte);

state
.mem_mut()
.write(clk, write_addr_index, cell_to_write, true);
state.cpu_mut().pc += 1;
state.cpu_mut().push_op(Operation::LoadS8, opcode, ops);
}
}

impl<M, F> Instruction<M, F> for Store32Instruction
where
M: MachineWithCpuChip<F>,
Expand All @@ -456,7 +586,7 @@ where
let pc = state.cpu().pc;
let write_addr = state
.mem_mut()
.read(clk, write_addr_loc.into(), true, pc, opcode, 0, "");
.read(clk, write_addr_loc, true, pc, opcode, 0, "");
let cell = state
.mem_mut()
.read(clk, read_addr, true, pc, opcode, 1, "");
Expand All @@ -466,6 +596,59 @@ where
}
}

impl<M, F> Instruction<M, F> for StoreU8Instruction
where
M: MachineWithCpuChip<F>,
F: Field,
{
const OPCODE: u32 = STOREU8;

fn execute(state: &mut M, ops: Operands<i32>) {
let opcode = <Self as Instruction<M, F>>::OPCODE;
let clk = state.cpu().clock;
let read_addr = (state.cpu().fp as i32 + ops.c()) as u32;

// Make sure we get to the correct and non empty map for the byte.
let read_addr_index = addr_of_word(read_addr);
let write_addr_loc = (state.cpu().fp as i32 + ops.b()) as u32;
let pc = state.cpu().pc;
let write_addr = state
.mem_mut()
.read(clk, write_addr_loc.into(), true, pc, opcode, 0, "");

thealmarty marked this conversation as resolved.
Show resolved Hide resolved
// Read the cell from the read address.
let cell = state
.mem_mut()
.read(clk, read_addr_index, true, pc, opcode, 1, "");

// The array index of the word for the byte to read from
let index_of_read = index_of_byte(read_addr);

// The word from the read address.
let cell_read = cell.0;
// The byte from the read cell.
let cell_byte = cell_read[index_of_read];

// The array index of the word for the byte to write to
let index_of_write = index_of_byte(write_addr.into());

thealmarty marked this conversation as resolved.
Show resolved Hide resolved
// The key to the memory map, converted to a multiple of 4.
let write_addr_index = addr_of_word(write_addr.into());

// The original content of the cell to write to. If the cell is empty, initiate it with a default value.
let cell_write = state.mem_mut().read_or_init(clk, write_addr_index, true);

// The Word to write, with one byte overwritten to the read byte
let cell_to_write = cell_write.update_byte(cell_byte, index_of_write);

state
.mem_mut()
.write(clk, write_addr_index, cell_to_write, true);
state.cpu_mut().pc += 1;
state.cpu_mut().push_op(Operation::StoreU8, opcode, ops);
}
}

impl<M, F> Instruction<M, F> for JalInstruction
where
M: MachineWithCpuChip<F>,
Expand Down
37 changes: 37 additions & 0 deletions machine/src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,18 @@ use p3_field::{Field, PrimeField};
#[derive(Copy, Clone, Debug, Default)]
pub struct Word<F>(pub [F; MEMORY_CELL_BYTES]);

// Functions for byte manipulations
/// Get the index of a byte in a memory cell.
pub fn index_of_byte(addr: u32) -> usize {
(addr & 3) as usize
}

/// Get the address of the memory cells which is not empty (a multiple of 4).
pub fn addr_of_word(addr: u32) -> u32 {
(addr & !3) as u32
}
//----------------------------------

impl Word<u8> {
pub fn from_u8(byte: u8) -> Self {
let mut result = [0; MEMORY_CELL_BYTES];
Expand All @@ -15,6 +27,31 @@ impl Word<u8> {
}
}

impl Word<u8> {
pub fn sign_extend_byte(byte: u8) -> Self {
let sign = byte as i8 >> 7;
let mut result: [u8; MEMORY_CELL_BYTES] = [sign as u8; MEMORY_CELL_BYTES];
result[0] = byte;
Self(result)
}
}

impl Word<u8> {
pub fn zero_extend_byte(byte: u8) -> Self {
let mut result: [u8; MEMORY_CELL_BYTES] = [0; MEMORY_CELL_BYTES];
result[0] = byte;
Self(result)
}
}

impl Word<u8> {
pub fn update_byte(self, byte: u8, loc: usize) -> Self {
let mut result: [u8; MEMORY_CELL_BYTES] = self.0;
result[loc] = byte;
Self(result)
}
}

impl<F: Copy> Word<F> {
pub fn transform<T, G>(self, mut f: G) -> Word<T>
where
Expand Down
Loading
Loading