Skip to content

Commit

Permalink
Merge pull request #151 from valida-xyz/thealmarty-ldst8
Browse files Browse the repository at this point in the history
Add `STOREU8`, `LOADU8`, `LOADS8`
  • Loading branch information
morganthomas authored Apr 19, 2024
2 parents 0a9ed96 + c4f44ac commit 7a17fe8
Show file tree
Hide file tree
Showing 10 changed files with 283 additions and 9 deletions.
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, "");

// 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());

// 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

0 comments on commit 7a17fe8

Please sign in to comment.