-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
138 additions
and
10 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
//! The memory module contains the memory data structures and functionality for the emulator. | ||
|
||
use crate::page::{self, CachedPage}; | ||
use alloy_primitives::B256; | ||
use std::{cell::RefCell, collections::BTreeMap, rc::Rc}; | ||
|
||
type PageIndex = u32; | ||
|
||
struct Memory { | ||
/// Map of generalized index -> the merkle root of each index. None if invalidated. | ||
nodes: BTreeMap<u64, Option<B256>>, | ||
/// Map of page indices to [CachedPage]s. | ||
pages: BTreeMap<u64, Rc<RefCell<CachedPage>>>, | ||
/// We store two caches upfront; we often read instructions from one page and reserve another | ||
/// for scratch memory. This prevents map lookups for each instruction. | ||
last_page: [(PageIndex, Option<Rc<RefCell<CachedPage>>>); 2], | ||
} | ||
|
||
impl Default for Memory { | ||
fn default() -> Self { | ||
Self { | ||
nodes: BTreeMap::default(), | ||
pages: BTreeMap::default(), | ||
last_page: [(!0u32, None), (!0u32, None)], | ||
} | ||
} | ||
} | ||
|
||
impl Memory { | ||
/// Returns the number of allocated pages in memory. | ||
pub fn page_count(&self) -> usize { | ||
self.pages.len() | ||
} | ||
|
||
/// Performs an operation on all pages in the memory. | ||
/// | ||
/// ### Takes | ||
/// - `f`: A function that takes a page index and a mutable reference to a [CachedPage]. | ||
pub fn for_each_page(&mut self, mut f: impl FnMut(u64, Rc<RefCell<CachedPage>>)) { | ||
for (key, page) in self.pages.iter() { | ||
f(*key, Rc::clone(page)); | ||
} | ||
} | ||
|
||
/// Invalidate a given memory address | ||
/// | ||
/// ### Takes | ||
/// - `address`: The address to invalidate. | ||
pub fn invalidate(&mut self, address: u32) { | ||
if address & 0x3 != 0 { | ||
panic!("Unaligned memory access: {:x}", address); | ||
} | ||
|
||
// Find the page and invalidate the address within it. | ||
if let Some(page) = self.page_lookup(address >> page::PAGE_ADDRESS_SIZE) { | ||
let mut page = page.borrow_mut(); | ||
page.invalidate(address & page::PAGE_ADDRESS_MASK as u32); | ||
if !page.valid[1] { | ||
return; | ||
} | ||
} else { | ||
// Nothing to invalidate | ||
return; | ||
} | ||
|
||
// Find the generalized index of the first page covering the address | ||
let mut g_index = ((1 << 32) | address) >> page::PAGE_ADDRESS_SIZE as u32; | ||
while g_index > 0 { | ||
self.nodes.insert(g_index.into(), None); | ||
g_index >>= 1; | ||
} | ||
} | ||
|
||
fn page_lookup(&mut self, page_index: PageIndex) -> Option<Rc<RefCell<CachedPage>>> { | ||
// Check caches before maps | ||
if let Some((_, Some(page))) = self.last_page.iter().find(|(key, _)| *key == page_index) { | ||
return Some(Rc::clone(page)); | ||
} else if let Some(page) = self.pages.get(&(page_index as u64)) { | ||
// Cache the page | ||
self.last_page[1] = self.last_page[0].clone(); | ||
self.last_page[0] = (page_index, Some(Rc::clone(page))); | ||
|
||
Some(Rc::clone(page)) | ||
} else { | ||
None | ||
} | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod test {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters