use crate::{M16, M3, M32, M8, REG_FIRST, REG_LAST};
use core::fmt;
pub const INPUT_ADDR: u64 = 0x4000_0000;
pub const MAX_INPUT_SIZE: u64 = 0x4000_0000; pub const FREE_INPUT_ADDR: u64 = INPUT_ADDR;
pub const RAM_ADDR: u64 = 0xa0000000;
pub const RAM_SIZE: u64 = 0x20000000; pub const STACK_ADDR: u64 = RAM_ADDR;
pub const STACK_SIZE: u64 = 0x400000; pub const SYS_ADDR: u64 = RAM_ADDR + STACK_SIZE;
pub const SYS_SIZE: u64 = 0x10000;
pub const OUTPUT_ADDR: u64 = SYS_ADDR + SYS_SIZE;
pub const OUTPUT_MAX_SIZE: u64 = 0x20000; pub const ROM_ENTRY: u64 = 0x1000;
pub const ROM_ENTRY_SIZE: u64 = 1 << 20;
pub const ROM_EXIT: u64 = 0x1004;
pub const MAX_ZISK_OS_ROM_ADDR: u64 = 0x10000000 - 1;
pub const ROM_ADDR: u64 = 0x80000000;
pub const ROM_SIZE: u64 = 0x08000000; pub const ROM_ADDR_MAX: u64 = ROM_ADDR + ROM_SIZE - 1;
pub const FLOAT_LIB_ROM_SIZE: u64 = 0x100000; pub const FLOAT_LIB_ROM_ADDR: u64 = ROM_ADDR + ROM_SIZE - FLOAT_LIB_ROM_SIZE;
pub const FLOAT_LIB_ROM_ADDR_MAX: u64 = FLOAT_LIB_ROM_ADDR + FLOAT_LIB_ROM_SIZE - 1;
pub const FLOAT_LIB_RAM_SIZE: u64 = 0x10000; pub const FLOAT_LIB_RAM_ADDR: u64 = RAM_ADDR + RAM_SIZE - FLOAT_LIB_RAM_SIZE;
pub const FLOAT_LIB_RAM_ADDR_MAX: u64 = FLOAT_LIB_RAM_ADDR + FLOAT_LIB_RAM_SIZE - 1;
pub const FLOAT_LIB_SP: u64 = RAM_ADDR + RAM_SIZE - 16;
pub const ARCH_ID_ZISK: u64 = 0xFFFEEEE;
pub const UART_ADDR: u64 = SYS_ADDR + 0x200;
pub const EXTRA_PARAMS_ADDR: u64 = SYS_ADDR + 0x0F00;
pub const FREG_FIRST: u64 = SYS_ADDR + 0x1000;
pub const CSR_ADDR: u64 = SYS_ADDR + 0x8000;
pub const MTVEC: u64 = CSR_ADDR + 0x305 * 8;
pub const FCSR: u64 = CSR_ADDR + 0x003 * 8;
pub const ARCH_ID_CSR: u64 = 0xF12;
pub const ARCH_ID_CSR_ADDR: u64 = CSR_ADDR + (ARCH_ID_CSR * 8);
#[derive(Debug, Clone)]
pub struct DataSection {
pub addr: u64,
pub data: Vec<u8>,
}
pub struct MemSection {
pub start: u64,
pub end: u64,
pub real_end: u64,
pub buffer: Vec<u8>,
}
impl Default for MemSection {
fn default() -> Self {
Self::new()
}
}
impl fmt::Debug for MemSection {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(&self.to_text())
}
}
impl MemSection {
pub fn new() -> MemSection {
MemSection { start: 0, end: 0, real_end: 0, buffer: Vec::new() }
}
pub fn to_text(&self) -> String {
format!(
"start={:x} real_end={:x} end={:x} diff={:x}={} buffer.len={:x}={}",
self.start,
self.real_end,
self.end,
self.end - self.start,
self.end - self.start,
self.buffer.len(),
self.buffer.len()
)
}
}
#[derive(Debug, Default)]
pub struct Mem {
pub read_sections: Vec<MemSection>,
pub write_section: MemSection,
pub free_input: u64,
}
impl Mem {
pub fn new() -> Mem {
Mem { read_sections: Vec::new(), write_section: MemSection::new(), free_input: 0 }
}
pub fn add_read_section(&mut self, start: u64, buffer: &[u8]) {
if (start & 0x07) != 0 {
panic!("Mem::add_read_section() got a start address={start:x} not alligned to 8 bytes");
}
let end = start + buffer.len() as u64;
for existing_section in self.read_sections.iter_mut() {
if existing_section.real_end == start {
assert!(existing_section.real_end <= existing_section.end);
assert!((existing_section.end - existing_section.real_end) < 8);
while existing_section.real_end > existing_section.end {
existing_section.buffer.pop();
existing_section.end -= 1;
}
existing_section.buffer.extend(buffer);
existing_section.real_end += buffer.len() as u64;
existing_section.end = existing_section.real_end;
while (existing_section.end & 0x07) != 0 {
existing_section.buffer.push(0);
existing_section.end += 1;
}
return;
}
}
let mut new_section = MemSection { start, end, real_end: end, buffer: buffer.to_owned() };
while (new_section.end & 0x07) != 0 {
new_section.buffer.push(0);
new_section.end += 1;
}
self.read_sections.push(new_section);
}
pub fn add_write_section(&mut self, start: u64, size: u64) {
if (start & 0x07) != 0 {
panic!(
"Mem::add_write_section() got a start address={start:x} not alligned to 8 bytes"
);
}
if start == 0 {
panic!("Mem::add_write_section() got invalid start={start}");
}
if self.write_section.start != 0 {
panic!(
"Mem::add_write_section() only one write section allowed, write_section.start={}",
self.write_section.start
);
}
let mem: Vec<u8> = vec![0; size as usize];
self.write_section.start = start;
self.write_section.end = start + mem.len() as u64;
self.write_section.buffer = mem;
}
#[inline(always)]
pub fn read(&self, addr: u64, width: u64) -> u64 {
debug_assert!(!Mem::address_is_register(addr));
if (addr >= self.write_section.start) && (addr <= (self.write_section.end - width)) {
let read_position: usize = (addr - self.write_section.start) as usize;
let value: u64 = match width {
1 => self.write_section.buffer[read_position] as u64,
2 => u16::from_le_bytes(
self.write_section.buffer[read_position..read_position + 2].try_into().unwrap(),
) as u64,
4 => u32::from_le_bytes(
self.write_section.buffer[read_position..read_position + 4].try_into().unwrap(),
) as u64,
8 => u64::from_le_bytes(
self.write_section.buffer[read_position..read_position + 8].try_into().unwrap(),
),
_ => panic!("Mem::read() invalid width={width}"),
};
return value;
}
if addr == INPUT_ADDR && width == 8 {
return self.free_input;
}
let section = if let Ok(section) = self.read_sections.binary_search_by(|section| {
if addr < section.start {
std::cmp::Ordering::Greater
} else if addr > section.end - width {
std::cmp::Ordering::Less
} else {
std::cmp::Ordering::Equal
}
}) {
&self.read_sections[section]
} else if addr >= (INPUT_ADDR + 8) && addr <= (INPUT_ADDR + MAX_INPUT_SIZE - width) {
match width {
1 | 2 | 4 | 8 => return 0,
_ => panic!("Mem::read() invalid width={width}"),
}
} else {
panic!("Mem::read() section not found for addr: {addr}={addr:x} with width: {width}");
};
let read_position: usize = (addr - section.start) as usize;
match width {
1 => section.buffer[read_position] as u64,
2 => u16::from_le_bytes(
section.buffer[read_position..read_position + 2].try_into().unwrap(),
) as u64,
4 => u32::from_le_bytes(
section.buffer[read_position..read_position + 4].try_into().unwrap(),
) as u64,
8 => u64::from_le_bytes(
section.buffer[read_position..read_position + 8].try_into().unwrap(),
),
_ => panic!("Mem::read() invalid width={width}"),
}
}
#[inline(always)]
pub fn read_slice(&self, addr: u64, count: u64) -> &[u8] {
debug_assert!(!Mem::address_is_register(addr));
if (addr >= self.write_section.start) && ((addr + count) <= self.write_section.end) {
let read_position: usize = (addr - self.write_section.start) as usize;
return &self.write_section.buffer[read_position..read_position + count as usize];
}
let section = if let Ok(section) = self.read_sections.binary_search_by(|section| {
if addr < section.start {
std::cmp::Ordering::Greater
} else if addr > section.end - count {
std::cmp::Ordering::Less
} else {
std::cmp::Ordering::Equal
}
}) {
&self.read_sections[section]
} else {
panic!("Mem::read() section not found for addr: {addr}={addr:x} with count: {count}");
};
let read_position: usize = (addr - section.start) as usize;
§ion.buffer[read_position..read_position + count as usize]
}
#[inline(always)]
pub fn read_required(&self, addr: u64, width: u64) -> (u64, Vec<u64>) {
let addr_req_1 = addr & 0xFFFF_FFFF_FFFF_FFF8; let addr_req_2 = (addr + width - 1) & 0xFFFF_FFFF_FFFF_FFF8; let is_full_aligned = ((addr & 0x07) == 0) && (width == 8);
let is_single_not_aligned = !is_full_aligned && (addr_req_1 == addr_req_2);
let is_double_not_aligned = !is_full_aligned && !is_single_not_aligned;
if (addr >= self.write_section.start) && (addr <= (self.write_section.end - width)) {
let read_position: usize = (addr - self.write_section.start) as usize;
let value: u64 = match width {
1 => self.write_section.buffer[read_position] as u64,
2 => u16::from_le_bytes(
self.write_section.buffer[read_position..read_position + 2].try_into().unwrap(),
) as u64,
4 => u32::from_le_bytes(
self.write_section.buffer[read_position..read_position + 4].try_into().unwrap(),
) as u64,
8 => u64::from_le_bytes(
self.write_section.buffer[read_position..read_position + 8].try_into().unwrap(),
),
_ => panic!("Mem::read() invalid width={width}"),
};
if is_single_not_aligned {
let mut additional_data: Vec<u64> = Vec::new();
assert!(addr_req_1 >= self.write_section.start);
let read_position_req: usize = (addr_req_1 - self.write_section.start) as usize;
let value_req = u64::from_le_bytes(
self.write_section.buffer[read_position_req..read_position_req + 8]
.try_into()
.unwrap(),
);
additional_data.push(value_req);
return (value, additional_data);
}
if is_double_not_aligned {
let mut additional_data: Vec<u64> = Vec::new();
assert!(addr_req_1 >= self.write_section.start);
let read_position_req_1: usize = (addr_req_1 - self.write_section.start) as usize;
let value_req_1 = u64::from_le_bytes(
self.write_section.buffer[read_position_req_1..read_position_req_1 + 8]
.try_into()
.unwrap(),
);
additional_data.push(value_req_1);
assert!(addr_req_2 >= self.write_section.start);
let read_position_req_2: usize = (addr_req_2 - self.write_section.start) as usize;
let value_req_2 = u64::from_le_bytes(
self.write_section.buffer[read_position_req_2..read_position_req_2 + 8]
.try_into()
.unwrap(),
);
additional_data.push(value_req_2);
return (value, additional_data);
}
return (value, Vec::new());
}
let section = if let Ok(section) = self.read_sections.binary_search_by(|section| {
if addr < section.start {
std::cmp::Ordering::Greater
} else if (addr + width) > section.end {
std::cmp::Ordering::Less
} else {
std::cmp::Ordering::Equal
}
}) {
&self.read_sections[section]
} else {
println!("sections: {:?}", self.read_sections);
panic!("Mem::read() section not found for addr: {addr} with width: {width}");
};
let read_position: usize = (addr - section.start) as usize;
let value: u64 = match width {
1 => section.buffer[read_position] as u64,
2 => u16::from_le_bytes(
section.buffer[read_position..read_position + 2].try_into().unwrap(),
) as u64,
4 => u32::from_le_bytes(
section.buffer[read_position..read_position + 4].try_into().unwrap(),
) as u64,
8 => u64::from_le_bytes(
section.buffer[read_position..read_position + 8].try_into().unwrap(),
),
_ => panic!(
"Mem::read() invalid addr:0x{addr:X} read_position:{read_position} width:{width}"
),
};
if is_single_not_aligned {
let mut additional_data: Vec<u64> = Vec::new();
assert!(addr_req_1 >= section.start);
let read_position_req: usize = (addr_req_1 - section.start) as usize;
let value_req = u64::from_le_bytes(
section.buffer[read_position_req..read_position_req + 8].try_into().unwrap(),
);
additional_data.push(value_req);
return (value, additional_data);
}
if is_double_not_aligned {
let mut additional_data: Vec<u64> = Vec::new();
assert!(addr_req_1 >= section.start);
let read_position_req_1: usize = (addr_req_1 - section.start) as usize;
let value_req_1 = u64::from_le_bytes(
section.buffer[read_position_req_1..read_position_req_1 + 8].try_into().unwrap(),
);
additional_data.push(value_req_1);
assert!(addr_req_2 >= section.start);
let read_position_req_2: usize = (addr_req_2 - section.start) as usize;
let value_req_2 = u64::from_le_bytes(
section.buffer[read_position_req_2..read_position_req_2 + 8].try_into().unwrap(),
);
additional_data.push(value_req_2);
return (value, additional_data);
}
(value, Vec::new())
}
pub fn init_write_section_data(&mut self, section: &DataSection) {
if section.data.is_empty() {
return;
}
if (section.addr < self.write_section.start)
|| ((section.addr + section.data.len() as u64) > self.write_section.end)
{
panic!(
"Mem::init_write_section_data() invalid section start={:x} end={:x} write section start={:x} end={:x}",
section.addr,
section.addr + section.data.len() as u64,
self.write_section.start,
self.write_section.end
);
}
let write_position: usize = (section.addr - self.write_section.start) as usize;
self.write_section.buffer[write_position..write_position + section.data.len()]
.copy_from_slice(§ion.data);
}
#[inline(always)]
pub fn write(&mut self, addr: u64, val: u64, width: u64) {
debug_assert!(!Mem::address_is_register(addr));
self.write_silent(addr, val, width);
if (addr == UART_ADDR) && (width == 1) {
print!("{}", String::from(val as u8 as char));
}
}
#[inline(always)]
pub fn write_silent(&mut self, addr: u64, val: u64, width: u64) {
debug_assert!(!Mem::address_is_register(addr));
let section = &mut self.write_section;
if (addr < section.start) || ((addr + width) > section.end) {
panic!(
"Mem::write_silent() invalid addr={}={:x} write section start={:x} end={:x}",
addr, addr, section.start, section.end
);
}
let write_position: usize = (addr - section.start) as usize;
match width {
1 => section.buffer[write_position] = val as u8,
2 => section.buffer[write_position..write_position + 2]
.copy_from_slice(&(val as u16).to_le_bytes()),
4 => section.buffer[write_position..write_position + 4]
.copy_from_slice(&(val as u32).to_le_bytes()),
8 => section.buffer[write_position..write_position + 8]
.copy_from_slice(&val.to_le_bytes()),
_ => panic!("Mem::write_silent() invalid width={width}"),
};
}
#[inline(always)]
pub fn write_silent_required(&mut self, addr: u64, val: u64, width: u64) -> Vec<u64> {
let section = if let Ok(section) = self.read_sections.binary_search_by(|section| {
if addr < section.start {
std::cmp::Ordering::Greater
} else if addr > (section.end - width) {
std::cmp::Ordering::Less
} else {
std::cmp::Ordering::Equal
}
}) {
&mut self.read_sections[section]
} else {
&mut self.write_section
};
if (addr < section.start) || ((addr + width) > section.end) {
panic!(
"Mem::write_silent() invalid addr={}={:x} write section start={:x} end={:x}",
addr, addr, section.start, section.end
);
}
let addr_req_1 = addr & 0xFFFF_FFFF_FFFF_FFF8; let addr_req_2 = (addr + width - 1) & 0xFFFF_FFFF_FFFF_FFF8; let is_full_aligned = ((addr & 0x07) == 0) && (width == 8);
let is_single_not_aligned = !is_full_aligned && (addr_req_1 == addr_req_2);
let is_double_not_aligned = !is_full_aligned && !is_single_not_aligned;
let mut additional_data: Vec<u64> = Vec::new();
if is_single_not_aligned {
assert!(
addr_req_1 >= section.start,
"addr_req_1: 0x{:X} 0x{:X}]",
addr_req_1,
section.start
);
let read_position_req: usize = (addr_req_1 - section.start) as usize;
let value_req = u64::from_le_bytes(
section.buffer[read_position_req..read_position_req + 8].try_into().unwrap(),
);
additional_data.push(value_req);
}
if is_double_not_aligned {
assert!(
addr_req_1 >= section.start,
"addr_req_1(d): 0x{:X} 0x{:X}]",
addr_req_1,
section.start
);
let read_position_req_1: usize = (addr_req_1 - section.start) as usize;
let value_req_1 = u64::from_le_bytes(
section.buffer[read_position_req_1..read_position_req_1 + 8].try_into().unwrap(),
);
additional_data.push(value_req_1);
assert!(
addr_req_2 >= section.start,
"addr_req_2(d): 0x{:X} 0x{:X}]",
addr_req_2,
section.start
);
let read_position_req_2: usize = (addr_req_2 - section.start) as usize;
let value_req_2 = u64::from_le_bytes(
section.buffer[read_position_req_2..read_position_req_2 + 8].try_into().unwrap(),
);
additional_data.push(value_req_2);
}
let write_position: usize = (addr - section.start) as usize;
match width {
1 => section.buffer[write_position] = val as u8,
2 => section.buffer[write_position..write_position + 2]
.copy_from_slice(&(val as u16).to_le_bytes()),
4 => section.buffer[write_position..write_position + 4]
.copy_from_slice(&(val as u32).to_le_bytes()),
8 => section.buffer[write_position..write_position + 8]
.copy_from_slice(&val.to_le_bytes()),
_ => panic!("Mem::write_silent() invalid width={width}"),
}
additional_data
}
#[inline(always)]
pub fn address_is_register(address: u64) -> bool {
((address & 0x7) == 0) && (REG_FIRST..=REG_LAST).contains(&address)
}
#[inline(always)]
pub fn address_to_register_index(address: u64) -> usize {
debug_assert!(Mem::address_is_register(address));
((address - REG_FIRST) >> 3) as usize
}
#[inline(always)]
pub fn is_full_aligned(address: u64, width: u64) -> bool {
((address & 0x07) == 0) && (width == 8)
}
#[inline(always)]
pub fn is_single_not_aligned(address: u64, width: u64) -> bool {
if Self::is_full_aligned(address, width) {
return true;
}
let (address_required_1, address_required_2) = Self::required_addresses(address, width);
address_required_1 == address_required_2
}
#[inline(always)]
pub fn is_double_not_aligned(address: u64, width: u64) -> bool {
if Self::is_full_aligned(address, width) {
return true;
}
let (address_required_1, address_required_2) = Self::required_addresses(address, width);
address_required_1 != address_required_2
}
#[inline(always)]
pub fn required_addresses(address: u64, width: u64) -> (u64, u64) {
(address & 0xFFFF_FFFF_FFFF_FFF8, (address + width - 1) & 0xFFFF_FFFF_FFFF_FFF8)
}
#[inline(always)]
pub fn get_single_not_aligned_data(address: u64, width: u64, raw_data: u64) -> u64 {
debug_assert!(width < 8);
let offset = address & M3;
let raw_data = raw_data >> (8 * offset);
match width {
1 => raw_data & M8,
2 => raw_data & M16,
4 => raw_data & M32,
_ => panic!("Mem::get_single_not_aligned_data() invalid width={width}"),
}
}
#[inline(always)]
pub fn get_double_not_aligned_data(
address: u64,
width: u64,
raw_data_1: u64,
raw_data_2: u64,
) -> u64 {
debug_assert!(width <= 8);
let offset = address & M3;
let raw_data = ((raw_data_1 as u128 + ((raw_data_2 as u128) << 64)) >> (8 * offset)) as u64;
match width {
1 => raw_data & M8,
2 => raw_data & M16,
4 => raw_data & M32,
8 => raw_data,
_ => panic!("Mem::get_double_not_aligned_data() invalid width={width}"),
}
}
#[inline(always)]
pub fn get_writeable_section(&mut self, addr: u64, count: u64) -> &mut MemSection {
if let Ok(section) = self.read_sections.binary_search_by(|section| {
if addr < section.start {
std::cmp::Ordering::Greater
} else if addr > (section.end - count) {
std::cmp::Ordering::Less
} else {
std::cmp::Ordering::Equal
}
}) {
panic!(
"Mem::get_write_section() invalid addr={addr}={addr:x},count={count} write section start={:x} end={:x} is read only section",
self.read_sections[section].start, self.read_sections[section].end);
};
let section = &mut self.write_section;
if (addr < section.start) || ((addr + count) > section.end) {
panic!(
"Mem::get_section() invalid addr={addr}={addr:x},count={count} write section start={:x} end={:x}",
section.start, section.end
);
}
section
}
#[inline(always)]
pub fn get_readable_section(&self, addr: u64, count: u64) -> &MemSection {
let section = if let Ok(section) = self.read_sections.binary_search_by(|section| {
if addr < section.start {
std::cmp::Ordering::Greater
} else if addr > (section.end - count) {
std::cmp::Ordering::Less
} else {
std::cmp::Ordering::Equal
}
}) {
&self.read_sections[section]
} else {
&self.write_section
};
if (addr < section.start) || ((addr + count) > section.end) {
panic!(
"Mem::get_read_section() invalid addr={addr}={addr:x},count={count} read section start={:x} end={:x}",
section.start, section.end
);
}
section
}
#[inline(always)]
pub fn memcpy(&mut self, dst: u64, src: u64, count: u64) {
if dst == src || count == 0 {
return;
}
let dst_end = dst + count;
let src_end = src + count;
let count_usize = count as usize;
let overlaps = (dst < src_end) && (src < dst_end);
if overlaps {
let temp_buffer: Vec<u8> = {
let src_section = self.get_readable_section(src, count);
let src_offset: usize = (src - src_section.start) as usize;
src_section.buffer[src_offset..src_offset + count_usize].to_vec()
};
let dst_section = self.get_writeable_section(dst, count);
let dst_offset: usize = (dst - dst_section.start) as usize;
dst_section.buffer[dst_offset..dst_offset + count_usize].copy_from_slice(&temp_buffer);
} else {
let data_to_copy: Vec<u8> = {
let src_section = self.get_readable_section(src, count);
let src_offset: usize = (src - src_section.start) as usize;
src_section.buffer[src_offset..src_offset + count_usize].to_vec()
};
let dst_section = self.get_writeable_section(dst, count);
let dst_offset: usize = (dst - dst_section.start) as usize;
dst_section.buffer[dst_offset..dst_offset + count_usize].copy_from_slice(&data_to_copy);
}
}
pub fn memcpy_from_data(&mut self, dst: u64, count: u64, data: &[u64], data_offset: usize) {
if count == 0 {
return;
}
let data_bytes: &[u8] =
unsafe { core::slice::from_raw_parts(data.as_ptr() as *const u8, data.len() * 8) };
let dst_section = self.get_writeable_section(dst, count);
let dst_offset: usize = (dst - dst_section.start) as usize;
let count = count as usize;
let bytes = &data_bytes[data_offset..data_offset + count];
dst_section.buffer[dst_offset..dst_offset + count].copy_from_slice(bytes);
}
pub fn memset(&mut self, dst: u64, count: u64, data: u8) {
if count == 0 {
return;
}
let dst_section = self.get_writeable_section(dst, count);
let dst_offset: usize = (dst - dst_section.start) as usize;
let count = count as usize;
dst_section.buffer[dst_offset..dst_offset + count].fill(data);
}
pub fn push_from_mem(&mut self, data: &mut Vec<u64>, addr: u64, count: u64) {
if count == 0 {
return;
}
let section = self.get_readable_section(addr, count);
let addr64 = addr >> 3;
let to_addr64 = (addr + count - 1) >> 3;
let count64 = (to_addr64 - addr64 + 1) as usize;
let addr_offset: usize = (addr - section.start) as usize & !0x07;
let addr_offset64: usize = addr_offset >> 3;
let mem64: &[u64] = unsafe {
core::slice::from_raw_parts(
section.buffer.as_ptr() as *const u64,
section.buffer.len() / 8,
)
};
data.extend_from_slice(&mem64[addr_offset64..addr_offset64 + count64]);
}
pub fn memcmp(&self, a: u64, b: u64, count: u64) -> (u64, usize) {
if count == 0 {
return (0, 0);
}
let count_usize = count as usize;
let a_section = self.get_readable_section(a, count);
let b_section = self.get_readable_section(b, count);
let a_offset: usize = (a - a_section.start) as usize;
let b_offset: usize = (b - b_section.start) as usize;
for i in 0..count_usize {
let byte_a = a_section.buffer[a_offset + i];
let byte_b = b_section.buffer[b_offset + i];
if byte_a != byte_b {
let diff = (byte_a as i64) - (byte_b as i64);
return (diff as u64, i + 1);
}
}
(0, count_usize)
}
pub fn memdump(&self, addr: u64, count: u64) -> String {
if count == 0 {
return String::new();
}
let count_usize = count as usize;
let section = self.get_readable_section(addr, count);
let offset: usize = (addr - section.start) as usize;
section.buffer[offset..offset + count_usize]
.iter()
.map(|byte| format!("{:02x}", byte))
.collect::<Vec<String>>()
.join("")
}
}