Skip to content

Commit

Permalink
Add MMIO peek functions, dump function to support mmio in memory viewer
Browse files Browse the repository at this point in the history
  • Loading branch information
dbalsom committed Aug 15, 2023
1 parent e8f6b07 commit 6e8607c
Show file tree
Hide file tree
Showing 5 changed files with 219 additions and 1 deletion.
144 changes: 144 additions & 0 deletions core/src/bus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ pub trait MemoryMappedDevice {
fn get_read_wait(&mut self, address: usize, cycles: u32) -> u32;
fn mmio_read_u8(&mut self, address: usize, cycles: u32) -> (u8, u32);
fn mmio_read_u16(&mut self, address: usize, cycles: u32) -> (u16, u32);
fn mmio_peek_u8(&self, address: usize) -> u8;
fn mmio_peek_u16(&self, address: usize) -> u16;

fn get_write_wait(&mut self, address: usize, cycles: u32) -> u32;
fn mmio_write_u8(&mut self, address: usize, data: u8, cycles: u32) -> u32;
Expand Down Expand Up @@ -699,6 +701,51 @@ impl BusInterface {
Err(MemError::ReadOutOfBoundsError)
}

pub fn peek_u8(&self, address: usize) -> Result<u8, MemError> {
if address < self.memory.len() {
if address < self.mmio_data.first_map || address > self.mmio_data.last_map {
// Address is not mapped.
let b: u8 = self.memory[address];
return Ok(b)
}
else {
// Handle memory-mapped devices
for map_entry in &self.mmio_map {
if address >= map_entry.0.address && address < map_entry.0.address + map_entry.0.size {

match map_entry.1 {
MmioDeviceType::Video => {
match &self.video {
VideoCardDispatch::Cga(cga) => {
let data = MemoryMappedDevice::mmio_peek_u8(cga, address);
return Ok(data);
}
#[cfg(feature = "ega")]
VideoCardDispatch::Ega(ega) => {
let data = MemoryMappedDevice::mmio_peek_u8(ega, address);
return Ok(data);
}
#[cfg(feature = "vga")]
VideoCardDispatch::Vga(vga) => {
let data = MemoryMappedDevice::mmio_peek_u8(vga, address);
return Ok(data);
}
_ => {}
}
}
_=> {}
}
return Err(MemError::MmioError)
}
}
// We didn't match any mmio devices, return raw memory
let b: u8 = self.memory[address];
return Ok(b)
}
}
Err(MemError::ReadOutOfBoundsError)
}

pub fn read_u16(&mut self, address: usize, cycles: u32) -> Result<(u16, u32), MemError> {
if address < self.memory.len() - 1 {
if address < self.mmio_data.first_map || address > self.mmio_data.last_map {
Expand Down Expand Up @@ -1079,6 +1126,103 @@ impl BusInterface {
vec
}

/// Dump memory to a vector of vectors of SyntaxTokens.
///
/// Uses bus peek functions to resolve MMIO addresses.
pub fn dump_flat_tokens_ex(&self, address: usize, cursor: usize, mut size: usize) -> Vec<Vec<SyntaxToken>> {

let mut vec: Vec<Vec<SyntaxToken>> = Vec::new();

if address >= self.memory.len() {
// Start address is invalid. Send only an error token.
let mut linevec = Vec::new();

linevec.push(SyntaxToken::ErrorString("REQUEST OUT OF BOUNDS".to_string()));
vec.push(linevec);

return vec;
}
else if address + size >= self.memory.len() {
// Request size invalid. Send truncated result.
let new_size = size - ((address + size) - self.memory.len());
size = new_size
}

let addr_vec = Vec::from_iter(address..address+size);
let mut display_address = address;

for dump_addr_row in addr_vec.chunks_exact(16) {

let mut line_vec = Vec::new();

// Push memory flat address tokens
line_vec.push(
SyntaxToken::MemoryAddressFlat(
display_address as u32,
format!("{:05X}", display_address)
)
);

// Build hex byte value tokens
let mut i = 0;
for addr in dump_addr_row {

let byte = self.peek_u8(*addr).unwrap();

if (display_address + i) == cursor {
line_vec.push(
SyntaxToken::MemoryByteHexValue(
(display_address + i) as u32,
byte,
format!("{:02X}", byte),
true, // Set cursor on this byte
0
)
);
}
else {
line_vec.push(
SyntaxToken::MemoryByteHexValue(
(display_address + i) as u32,
byte,
format!("{:02X}", byte),
false,
0
)
);
}
i += 1;
}

// Build ASCII representation tokens
let mut i = 0;
for addr in dump_addr_row {

let byte = self.peek_u8(*addr).unwrap();

let char_str = match byte {
00..=31 => ".".to_string(),
32..=127 => format!("{}", byte as char),
128.. => ".".to_string()
};
line_vec.push(
SyntaxToken::MemoryByteAsciiValue(
(display_address + i) as u32,
byte,
char_str,
0
)
);
i += 1;
}

vec.push(line_vec);
display_address += 16;
}

vec
}

pub fn dump_mem(&self, path: &Path) {

let mut filename = path.to_path_buf();
Expand Down
14 changes: 14 additions & 0 deletions core/src/devices/cga/mmio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,20 @@ impl MemoryMappedDevice for CGACard {
}
}

fn mmio_peek_u8(&self, address: usize) -> u8 {

let a_offset = (address & CGA_MEM_MASK) - CGA_MEM_ADDRESS;

self.mem[a_offset]
}

fn mmio_peek_u16(&self, address: usize) -> u16 {

let a_offset = (address & CGA_MEM_MASK) - CGA_MEM_ADDRESS;

(self.mem[a_offset] as u16) << 8 | self.mem[a_offset + 1] as u16
}

fn mmio_write_u8(&mut self, address: usize, byte: u8, _cycles: u32) -> u32 {
let a_offset = (address & CGA_MEM_MASK) - CGA_MEM_ADDRESS;
if a_offset < CGA_MEM_SIZE {
Expand Down
30 changes: 30 additions & 0 deletions core/src/devices/ega/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1558,6 +1558,36 @@ impl MemoryMappedDevice for EGACard {
((ho_byte as u16) << 8 | lo_byte as u16, wait1 + wait2)
}

fn mmio_peek_u8(&self, address: usize) -> u8 {
// RAM Enable disables memory mapped IO
if !self.misc_output_register.enable_ram() {
return 0;
}

// Validate address is within current memory map and get the offset into VRAM
let offset = match self.plane_bounds_check(address) {
Some(offset) => offset,
None => return 0
};

self.planes[0].buf[offset]
}

fn mmio_peek_u16(&self, address: usize) -> u16 {
// RAM Enable disables memory mapped IO
if !self.misc_output_register.enable_ram() {
return 0;
}

// Validate address is within current memory map and get the offset into VRAM
let offset = match self.plane_bounds_check(address) {
Some(offset) => offset,
None => return 0
};

(self.planes[0].buf[offset] as u16) << 8 | self.planes[0].buf[offset + 1] as u16
}

fn mmio_write_u8(&mut self, address: usize, byte: u8, _cycles: u32) -> u32 {

// RAM Enable disables memory mapped IO
Expand Down
30 changes: 30 additions & 0 deletions core/src/devices/vga/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1980,6 +1980,36 @@ impl MemoryMappedDevice for VGACard {
((ho_byte as u16) << 8 | lo_byte as u16, wait1 + wait2)
}

fn mmio_peek_u8(&self, address: usize) -> u8 {
// RAM Enable disables memory mapped IO
if !self.misc_output_register.enable_ram() {
return 0;
}

// Validate address is within current memory map and get the offset into VRAM
let offset = match self.plane_bounds_check(address) {
Some(offset) => offset,
None => return 0
};

self.planes[0].buf[offset]
}

fn mmio_peek_u16(&self, address: usize) -> u16 {
// RAM Enable disables memory mapped IO
if !self.misc_output_register.enable_ram() {
return 0;
}

// Validate address is within current memory map and get the offset into VRAM
let offset = match self.plane_bounds_check(address) {
Some(offset) => offset,
None => return 0
};

(self.planes[0].buf[offset] as u16) << 8 | self.planes[0].buf[offset + 1] as u16
}

fn mmio_write_u8(&mut self, address: usize, byte: u8, _cycles: u32) -> u32 {

// RAM Enable disables memory mapped IO
Expand Down
2 changes: 1 addition & 1 deletion frontends/martypc_pixels_desktop/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1805,7 +1805,7 @@ pub fn run() {
None => (0,0)
};

let mem_dump_vec = machine.bus().dump_flat_tokens(mem_dump_addr as usize, addr as usize, 256);
let mem_dump_vec = machine.bus().dump_flat_tokens_ex(mem_dump_addr as usize, addr as usize, 256);

//framework.gui.memory_viewer.set_row(mem_dump_addr as usize);
framework.gui.memory_viewer.set_memory(mem_dump_vec);
Expand Down

0 comments on commit 6e8607c

Please sign in to comment.