Skip to content

Commit

Permalink
Improve memory alignment in FixedMemory (#97)
Browse files Browse the repository at this point in the history
Improve memory alignment in FixedMemory

This commit enhances the memory management in FixedMemory to ensure word-aligned sizing. Previously, the memory could be resized to an odd number of bytes, which is not ideal for word-based operations.

Key changes:
- Modify the resize logic to always expand the memory to a word-aligned size
- Adjust the write operation to occur after proper resizing

This approach ensures that all memory operations are performed on word-aligned boundaries, improving efficiency and reducing potential alignment issues.

Co-authored-by: duc-nx <>
  • Loading branch information
duc-nx authored and sjudson committed Feb 12, 2025
1 parent 50f99ee commit 31bc400
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 20 deletions.
9 changes: 9 additions & 0 deletions common/src/memory/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@ impl MemAccessSize {
MemAccessSize::Word => (0, 0xffffffff),
}
}

// Helper function to check if the input address is aligned or not
pub fn is_aligned(&self, address: u32) -> bool {
match self {
MemAccessSize::Byte => true,
MemAccessSize::HalfWord => address & 0x1 == 0,
MemAccessSize::Word => address & 0x3 == 0,
}
}
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
Expand Down
4 changes: 2 additions & 2 deletions vm/src/emulator/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -539,8 +539,8 @@ impl LinearEmulator {
}

fn manage_timestamps(&mut self, size: &MemAccessSize, address: &u32) -> usize {
let half_aligned_address = address & !0x1;
let full_aligned_address = address & !0x3;
let half_aligned_address = address & !(WORD_SIZE / 2 - 1) as u32;
let full_aligned_address = address & !(WORD_SIZE - 1) as u32;

let prev = match size {
MemAccessSize::Byte => max(
Expand Down
63 changes: 49 additions & 14 deletions vm/src/memory/fixed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,30 +89,30 @@ impl<M: Mode> FixedMemory<M> {
}

// Check for alignment
if address & size as u32 != 0 {
if !size.is_aligned(address) {
return Err(MemoryError::UnalignedMemoryWrite(raw_address));
}

// Align to word boundary
let aligned_address = (address & !0x3) as usize;
let aligned_address = (address & !(WORD_SIZE - 1) as u32) as usize;
let (shift, mask) = size.get_shift_and_mask(address);

let write_mask = !(mask << shift);
let data = (value & mask) << shift;

let prev_value: u32;
let prev_value = if self.vec.len() <= aligned_address {
// Resize the vector to the next word-aligned size
let new_size = ((aligned_address / WORD_SIZE) + 1) * WORD_SIZE;
self.vec.resize(new_size, 0);

if self.vec.len() <= aligned_address {
prev_value = 0;

self.vec.resize_with(1 + aligned_address, Default::default);
self.vec[aligned_address] = data;
0
} else {
prev_value = (self.vec[aligned_address] >> shift) & mask;
(self.vec[aligned_address] >> shift) & mask
};

self.vec[aligned_address] &= write_mask;
self.vec[aligned_address] |= data;
}
// Perform the write operation
self.vec[aligned_address] &= write_mask;
self.vec[aligned_address] |= data;

Ok(StoreOp::Op(
size,
Expand Down Expand Up @@ -146,12 +146,12 @@ impl<M: Mode> FixedMemory<M> {
}

// Check for alignment
if address & size as u32 != 0 {
if !size.is_aligned(address) {
return Err(MemoryError::UnalignedMemoryRead(raw_address));
}

// Align to word boundary
let aligned_address = (address & !0x3) as usize;
let aligned_address = (address & !(WORD_SIZE - 1) as u32) as usize;
let (shift, mask) = size.get_shift_and_mask(address);

if self.vec.len() <= aligned_address {
Expand Down Expand Up @@ -610,4 +610,39 @@ mod tests {
Err(MemoryError::UnauthorizedWrite(0x1000))
);
}

#[test]
fn test_memory_size_alignment() {
let mut memory = FixedMemory::<RW>::new(0x1000, 0x100);

// Initial size should be 0
assert_eq!(memory.vec.len(), 0);

// Write a byte at the start of the memory
memory.write(0x1000, MemAccessSize::Byte, 0xAB).unwrap();
assert_eq!(memory.vec.len(), 4);

// Write a byte at an address that would require 2 words
memory.write(0x1007, MemAccessSize::Byte, 0xCD).unwrap();
assert_eq!(memory.vec.len(), 8);

// Write a halfword at an address that would require 3 words
memory
.write(0x100A, MemAccessSize::HalfWord, 0xEF12)
.unwrap();
assert_eq!(memory.vec.len(), 12);

// Write a word at an address that would require 5 words
memory
.write(0x1010, MemAccessSize::Word, 0x12345678)
.unwrap();
assert_eq!(memory.vec.len(), 20);

// Write a byte at a far address
memory.write(0x10FF, MemAccessSize::Byte, 0xFF).unwrap();
assert_eq!(memory.vec.len(), 256);

// Verify that all sizes are multiples of 4 (word-aligned)
assert!(memory.vec.len() % 4 == 0);
}
}
9 changes: 5 additions & 4 deletions vm/src/memory/variable.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::collections::BTreeMap;
use std::marker::PhantomData;

use crate::WORD_SIZE;
use nexus_common::error::MemoryError;

use super::{LoadOp, MemAccessSize, MemoryProcessor, Mode, StoreOp, RO, RW, WO};
Expand Down Expand Up @@ -35,12 +36,12 @@ impl<M: Mode> VariableMemory<M> {
let (shift, mask) = size.get_shift_and_mask(address);

// Check for alignment
if address & size as u32 != 0 {
if !size.is_aligned(address) {
return Err(MemoryError::UnalignedMemoryWrite(address));
}

// Align to word boundary
let aligned_address = address & !0x3;
let aligned_address = address & !(WORD_SIZE - 1) as u32;
let write_mask = !(mask << shift);
let data = (value & mask) << shift;

Expand Down Expand Up @@ -77,12 +78,12 @@ impl<M: Mode> VariableMemory<M> {
fn execute_read(&self, address: u32, size: MemAccessSize) -> Result<LoadOp, MemoryError> {
let (shift, mask) = size.get_shift_and_mask(address);

if address & size as u32 != 0 {
if !size.is_aligned(address) {
return Err(MemoryError::UnalignedMemoryRead(address));
}

// Align to word boundary
let aligned_address = address & !0x3;
let aligned_address = address & !(WORD_SIZE - 1) as u32;

let value = self
.0
Expand Down

0 comments on commit 31bc400

Please sign in to comment.