Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion codegen/masm/src/codegen/emit/mem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ impl<'a> OpEmitter<'a> {
let ptr = self.stack.pop().expect("operand stack is empty");
match ptr.ty() {
Type::Ptr(_) => {
// Converet the pointer to a native pointer representation
// Convert the pointer to a native pointer representation
self.emit_native_ptr();
match &ty {
Type::I128 => self.load_quad_word(None),
Expand Down
59 changes: 59 additions & 0 deletions codegen/masm/src/emulator/memory.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
use std::{
collections::BTreeSet,
fmt::Debug,
ops::{Index, IndexMut},
};

use miden_core::FieldElement;
use midenc_hir::Felt;

const EMPTY_WORD: [Felt; 4] = [Felt::ZERO; 4];

pub struct Memory {
memory: Vec<[Felt; 4]>,
set_memory_addrs: BTreeSet<usize>,
}

impl Memory {
pub fn new(memory_size: usize) -> Self {
Self {
memory: vec![EMPTY_WORD; memory_size],
set_memory_addrs: Default::default(),
}
}

pub fn len(&self) -> usize {
self.memory.len()
}

pub fn reset(&mut self) {
for addr in self.set_memory_addrs.iter() {
self.memory[*addr] = EMPTY_WORD;
}
self.set_memory_addrs = Default::default();
}
}

impl Index<usize> for Memory {
type Output = [Felt; 4];

fn index(&self, index: usize) -> &Self::Output {
&self.memory[index]
}
}

impl IndexMut<usize> for Memory {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
self.set_memory_addrs.insert(index);
&mut self.memory[index]
}
}

impl Debug for Memory {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for addr in self.set_memory_addrs.iter() {
write!(f, "{}: {:?}, ", addr, self[*addr])?;
}
Ok(())
}
}
32 changes: 25 additions & 7 deletions codegen/masm/src/emulator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ mod breakpoints;
mod debug;
mod events;
mod functions;
mod memory;

use std::{cell::RefCell, cmp, rc::Rc, sync::Arc};

use memory::Memory;
use miden_assembly::{ast::ProcedureName, LibraryNamespace};
use midenc_hir::{assert_matches, Felt, FieldElement, FunctionIdent, Ident, OperandStack, Stack};
use rustc_hash::{FxHashMap, FxHashSet};
Expand Down Expand Up @@ -118,7 +120,7 @@ pub struct Emulator {
locals: FxHashMap<FunctionIdent, Addr>,
modules_loaded: FxHashMap<Ident, Arc<Module>>,
modules_pending: FxHashSet<Ident>,
memory: Vec<[Felt; 4]>,
memory: Memory,
stack: OperandStack<Felt>,
advice_stack: OperandStack<Felt>,
callstack: Vec<Activation>,
Expand All @@ -131,26 +133,31 @@ pub struct Emulator {
clk: usize,
clk_limit: usize,
entrypoint: Option<FunctionIdent>,
print_trace: bool,
}
impl Default for Emulator {
fn default() -> Self {
Self::new(Self::DEFAULT_HEAP_SIZE, Self::DEFAULT_HEAP_START, Self::DEFAULT_LOCALS_START)
Self::new(
Self::DEFAULT_HEAP_SIZE,
Self::DEFAULT_HEAP_START,
Self::DEFAULT_LOCALS_START,
false,
)
}
}
impl Emulator {
pub const DEFAULT_HEAP_SIZE: u32 = (4 * Self::PAGE_SIZE) / 16;
pub const DEFAULT_HEAP_START: u32 = (2 * Self::PAGE_SIZE) / 16;
pub const DEFAULT_LOCALS_START: u32 = (3 * Self::PAGE_SIZE) / 16;
const EMPTY_WORD: [Felt; 4] = [Felt::ZERO; 4];
const PAGE_SIZE: u32 = 64 * 1024;

/// Construct a new, empty emulator with:
///
/// * A linear memory heap of `memory_size` words
/// * The start of the usable heap set to `hp` (an address in words)
/// * The start of the reserved heap used for locals set to `lp` (an address in words)
pub fn new(memory_size: u32, hp: u32, lp: u32) -> Self {
let memory = vec![Self::EMPTY_WORD; memory_size as usize];
pub fn new(memory_size: u32, hp: u32, lp: u32, print_stack: bool) -> Self {
let memory = Memory::new(memory_size as usize);
Self {
status: Status::Init,
functions: Default::default(),
Expand All @@ -170,6 +177,7 @@ impl Emulator {
clk: 0,
clk_limit: usize::MAX,
entrypoint: None,
print_trace: print_stack,
}
}

Expand Down Expand Up @@ -570,7 +578,7 @@ impl Emulator {
pub fn stop(&mut self) {
self.callstack.clear();
self.stack.clear();
self.memory = vec![Self::EMPTY_WORD; self.memory.len()];
self.memory.reset();
self.hp = self.hp_start;
self.lp = self.lp_start;
self.step_over = None;
Expand Down Expand Up @@ -887,7 +895,12 @@ macro_rules! peek_u32 {
macro_rules! pop_addr {
($emu:ident) => {{
let addr = pop_u32!($emu, "expected valid 32-bit address, got {}") as usize;
assert!(addr < $emu.memory.len(), "out of bounds memory access");
assert!(
addr < $emu.memory.len(),
"out of bounds memory access, addr: {}, available memory: {}",
addr,
$emu.memory.len()
);
addr
}};
}
Expand Down Expand Up @@ -1241,6 +1254,11 @@ impl Emulator {
// control flow effect occurred to reach it
let ix_with_op = state.next();
if let Some(ix_with_op) = ix_with_op {
if self.print_trace {
eprintln!("mem: {:?}", self.memory);
eprintln!("stk: {}", self.stack.debug());
eprintln!("op>: {:?}", ix_with_op.op);
}
match ix_with_op.op {
Op::Padw => {
self.stack.padw();
Expand Down
8 changes: 7 additions & 1 deletion codegen/masm/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,19 @@ struct TestByEmulationHarness {
}
#[allow(unused)]
impl TestByEmulationHarness {
pub fn with_emulator_config(memory_size: usize, hp: usize, lp: usize) -> Self {
pub fn with_emulator_config(
memory_size: usize,
hp: usize,
lp: usize,
print_stack: bool,
) -> Self {
let mut harness = Self {
context: TestContext::default(),
emulator: Emulator::new(
memory_size.try_into().expect("invalid memory size"),
hp.try_into().expect("invalid address"),
lp.try_into().expect("invalid address"),
print_stack,
),
};
harness.set_cycle_budget(2000);
Expand Down
17 changes: 16 additions & 1 deletion hir/src/asm/stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,22 @@ impl<'a, E: StackElement, T: ?Sized + Stack<Element = E>> fmt::Debug for DebugSt
.finish()
}
}

impl<'a, E: StackElement + fmt::Debug, T: ?Sized + Stack<Element = E>> fmt::Display
for DebugStack<'a, T>
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_list()
.entries(
self.stack
.stack()
.iter()
.rev()
.enumerate()
.take(self.limit.unwrap_or(self.stack.len())),
)
.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
Expand Down