Trait spectrusty_core::memory::ZxMemory
source · pub trait ZxMemory {
const ROM_SIZE: usize;
const RAMTOP: u16;
const PAGES_MAX: u8;
const SCR_BANKS_MAX: usize;
const ROM_BANKS_MAX: usize;
const RAM_BANKS_MAX: usize;
const PAGE_SIZE: usize = 16_384usize;
Show 35 methods
fn reset(&mut self);
fn read(&self, addr: u16) -> u8;
fn read16(&self, addr: u16) -> u16;
fn read_screen(&self, screen_bank: usize, addr: u16) -> u8;
fn write(&mut self, addr: u16, val: u8);
fn write16(&mut self, addr: u16, val: u16);
fn mem_ref(&self) -> &[u8] ⓘ;
fn mem_mut(&mut self) -> &mut [u8] ⓘ;
fn screen_ref(&self, screen_bank: usize) -> Result<&ScreenArray>;
fn screen_mut(&mut self, screen_bank: usize) -> Result<&mut ScreenArray>;
fn page_kind(&self, page: u8) -> Result<MemoryKind>;
fn page_bank(&self, page: u8) -> Result<(MemoryKind, usize)>;
fn page_ref(&self, page: u8) -> Result<&[u8]>;
fn page_mut(&mut self, page: u8) -> Result<&mut [u8]>;
fn rom_bank_ref(&self, rom_bank: usize) -> Result<&[u8]>;
fn rom_bank_mut(&mut self, rom_bank: usize) -> Result<&mut [u8]>;
fn ram_bank_ref(&self, ram_bank: usize) -> Result<&[u8]>;
fn ram_bank_mut(&mut self, ram_bank: usize) -> Result<&mut [u8]>;
fn map_rom_bank(&mut self, rom_bank: usize, page: u8) -> Result<()>;
fn map_ram_bank(&mut self, ram_bank: usize, page: u8) -> Result<()>;
fn map_exrom(&mut self, _exrom_bank: ExRom, _page: u8) -> Result<()> { ... }
fn unmap_exrom(&mut self, _exrom_bank: &ExRom) { ... }
fn is_exrom_at(&self, _page: u8) -> bool { ... }
fn has_mapped_exrom(&self, _exrom_bank: &ExRom) -> bool { ... }
fn page_index_at(&self, address: u16) -> Result<MemPageOffset> { ... }
fn rom_ref(&self) -> &[u8] ⓘ { ... }
fn rom_mut(&mut self) -> &mut [u8] ⓘ { ... }
fn ram_ref(&self) -> &[u8] ⓘ { ... }
fn ram_mut(&mut self) -> &mut [u8] ⓘ { ... }
fn load_into_rom<R: Read>(&mut self, rd: R) -> Result<()> { ... }
fn load_into_rom_bank<R: Read>(
&mut self,
rom_bank: usize,
rd: R
) -> Result<()> { ... }
fn iter_pages<A: RangeBounds<u16>>(
&self,
address_range: A
) -> Result<MemPageRefIter<'_, Self>> { ... }
fn for_each_page_mut<A: RangeBounds<u16>, F>(
&mut self,
address_range: A,
f: F
) -> Result<()>
where
for<'a> F: FnMut(PageMutSlice<'a>) -> Result<()>,
{ ... }
fn load_into_mem<A: RangeBounds<u16>, R: Read>(
&mut self,
address_range: A,
rd: R
) -> Result<()> { ... }
fn fill_mem<R, F>(&mut self, address_range: R, f: F) -> Result<()>
where
R: RangeBounds<u16>,
F: FnMut() -> u8,
{ ... }
}
Expand description
A trait for interfacing ZX Spectrum’s various memory types.
Required Associated Constants§
sourceconst SCR_BANKS_MAX: usize
const SCR_BANKS_MAX: usize
A maximum value allowed for a screen_bank
argument
sourceconst ROM_BANKS_MAX: usize
const ROM_BANKS_MAX: usize
A maximum value allowed for a rom_bank
argument
sourceconst RAM_BANKS_MAX: usize
const RAM_BANKS_MAX: usize
A maximum value allowed for a ram_bank
argument
Provided Associated Constants§
Required Methods§
sourcefn read(&self, addr: u16) -> u8
fn read(&self, addr: u16) -> u8
If addr
is above RAMTOP
the function should return std::u8::MAX.
sourcefn read16(&self, addr: u16) -> u16
fn read16(&self, addr: u16) -> u16
If addr
is above RAMTOP
the function should return std::u16::MAX.
sourcefn read_screen(&self, screen_bank: usize, addr: u16) -> u8
fn read_screen(&self, screen_bank: usize, addr: u16) -> u8
Reads a byte from screen memory at the given addr
.
The screen banks are different from memory banks.
E.g. for Spectrum 128k then screen bank 0
resides in a memory bank 5 and screen bank 1
resides in a memory bank 7. For 16k/48k Spectrum, there is only one screen bank: 0
.
addr
is in screen address space (0 addresses the first byte of screen memory).
Panics
If addr
is above the upper limit of screen memory address space the function should panic.
If screen_bank
doesn’t exist the function should also panic.
sourcefn write(&mut self, addr: u16, val: u8)
fn write(&mut self, addr: u16, val: u8)
If addr
is above RAMTOP
the function should do nothing.
sourcefn write16(&mut self, addr: u16, val: u16)
fn write16(&mut self, addr: u16, val: u16)
If addr is above RAMTOP
the function should do nothing.
sourcefn mem_ref(&self) -> &[u8] ⓘ
fn mem_ref(&self) -> &[u8] ⓘ
Provides a continuous view into the whole memory (all banks: ROM + RAM).
sourcefn mem_mut(&mut self) -> &mut [u8] ⓘ
fn mem_mut(&mut self) -> &mut [u8] ⓘ
Provides a continuous view into the whole memory (all banks: ROM + RAM).
sourcefn screen_ref(&self, screen_bank: usize) -> Result<&ScreenArray>
fn screen_ref(&self, screen_bank: usize) -> Result<&ScreenArray>
Returns a reference to the screen memory.
See ZxMemory::read_screen for an explanation of screen_bank
argument.
sourcefn screen_mut(&mut self, screen_bank: usize) -> Result<&mut ScreenArray>
fn screen_mut(&mut self, screen_bank: usize) -> Result<&mut ScreenArray>
Returns a mutable reference to the screen memory.
See ZxMemory::read_screen for an explanation of screen_bank
argument.
sourcefn page_kind(&self, page: u8) -> Result<MemoryKind>
fn page_kind(&self, page: u8) -> Result<MemoryKind>
Returns an enum describing what kind of memory is currently paged at the specified page
.
If an EX-ROM bank is currently mapped at the specified page
a MemoryKind::Rom will be returned
in this instance.
page
should be less or equal to PAGES_MAX.
sourcefn page_bank(&self, page: u8) -> Result<(MemoryKind, usize)>
fn page_bank(&self, page: u8) -> Result<(MemoryKind, usize)>
Returns a tuple of an enum describing what kind of memory and which bank of that memory is
currently paged at the specified page
.
Note
Unlike ZxMemory::page_kind this method ignores if an EX-ROM bank is currently mapped at the
specified page
. In this instance, the returned value corresponds to a memory bank that would
be mapped at the page
if the EX-ROM bank wasn’t mapped.
page
should be less or equal to PAGES_MAX.
sourcefn page_mut(&mut self, page: u8) -> Result<&mut [u8]>
fn page_mut(&mut self, page: u8) -> Result<&mut [u8]>
page
should be less or equal to PAGES_MAX.
sourcefn rom_bank_ref(&self, rom_bank: usize) -> Result<&[u8]>
fn rom_bank_ref(&self, rom_bank: usize) -> Result<&[u8]>
rom_bank
should be less or equal to ROM_BANKS_MAX
.
sourcefn rom_bank_mut(&mut self, rom_bank: usize) -> Result<&mut [u8]>
fn rom_bank_mut(&mut self, rom_bank: usize) -> Result<&mut [u8]>
rom_bank
should be less or equal to ROM_BANKS_MAX
.
sourcefn ram_bank_ref(&self, ram_bank: usize) -> Result<&[u8]>
fn ram_bank_ref(&self, ram_bank: usize) -> Result<&[u8]>
ram_bank
should be less or equal to RAM_BANKS_MAX
.
sourcefn ram_bank_mut(&mut self, ram_bank: usize) -> Result<&mut [u8]>
fn ram_bank_mut(&mut self, ram_bank: usize) -> Result<&mut [u8]>
ram_bank
should be less or equal to RAM_BANKS_MAX
.
Provided Methods§
sourcefn map_exrom(&mut self, _exrom_bank: ExRom, _page: u8) -> Result<()>
fn map_exrom(&mut self, _exrom_bank: ExRom, _page: u8) -> Result<()>
Maps EX-ROM bank at the specified page
.
exrom_bank
should be one of the attachable EX-ROMS and page
should be less or equal to PAGES_MAX.
Only one EX-ROM can be mapped at the same time. If an EX-ROM bank is already mapped when calling this function it will be unmapped first, regardless of the page, the previous EX-ROM bank has been mapped at.
Not all types of memory support attaching external ROMs.
sourcefn unmap_exrom(&mut self, _exrom_bank: &ExRom)
fn unmap_exrom(&mut self, _exrom_bank: &ExRom)
Unmaps an external ROM if the currently mapped EX-ROM bank is the same as in the argument. Otherwise does nothing.
sourcefn is_exrom_at(&self, _page: u8) -> bool
fn is_exrom_at(&self, _page: u8) -> bool
Returns true
if an EX-ROM bank is currently being mapped at the specified memory page
.
sourcefn has_mapped_exrom(&self, _exrom_bank: &ExRom) -> bool
fn has_mapped_exrom(&self, _exrom_bank: &ExRom) -> bool
Returns true
if a specified EX-ROM bank is currently being mapped.
sourcefn page_index_at(&self, address: u16) -> Result<MemPageOffset>
fn page_index_at(&self, address: u16) -> Result<MemPageOffset>
Returns Ok(MemPageOffset)
if address is equal to or less than ZxMemory::RAMTOP.
Examples found in repository?
357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411
fn next(&mut self) -> Option<Self::Item> {
let cursor = self.cursor;
let end = self.end;
if cursor < end {
let MemPageOffset { index, offset, .. } = self.mem.page_index_at(cursor as u16).unwrap();
let offset = offset as usize;
let page = self.mem.page_ref(index).unwrap();
let read_len = end - cursor;
let read_end = page.len().min(offset + read_len);
let read_page = &page[offset..read_end];
self.cursor += read_page.len();
Some(read_page)
}
else {
None
}
}
}
struct MemPageMutIter<'a, Z: ?Sized> {
mem: &'a mut Z,
cursor: usize,
end: usize
}
impl<'a, Z: ZxMemory + ?Sized> Iterator for MemPageMutIter<'a, Z> {
type Item = PageMutSlice<'a>;
fn next(&mut self) -> Option<Self::Item> {
let cursor = self.cursor;
let end = self.end;
if cursor < end {
let MemPageOffset { kind, index, offset } = self.mem.page_index_at(cursor as u16).unwrap();
let offset = offset as usize;
let page = self.mem.page_mut(index).unwrap();
// this may lead to yielding pages that view the same memory bank slices;
// so this struct isn't public, and it's only used internally when no
// two iterated pages are allowed to be accessed at once.
let page = unsafe { core::mem::transmute::<&mut[u8], &'a mut[u8]>(page) };
let read_len = end - cursor;
let read_end = page.len().min(offset + read_len);
let read_page = &mut page[offset..read_end];
self.cursor += read_page.len();
match kind {
MemoryKind::Rom => {
Some(PageMutSlice::Rom(read_page))
},
MemoryKind::Ram => {
Some(PageMutSlice::Ram(read_page))
}
}
}
else {
None
}
}
sourcefn rom_mut(&mut self) -> &mut [u8] ⓘ
fn rom_mut(&mut self) -> &mut [u8] ⓘ
Provides a continuous mutable view into the ROM memory (all banks).
sourcefn load_into_rom<R: Read>(&mut self, rd: R) -> Result<()>
fn load_into_rom<R: Read>(&mut self, rd: R) -> Result<()>
The data read depends on how big ROM is ZxMemory::ROM_SIZE.
Results in an error when the ROM data size is less than the ROM_SIZE
.
sourcefn load_into_rom_bank<R: Read>(&mut self, rom_bank: usize, rd: R) -> Result<()>
fn load_into_rom_bank<R: Read>(&mut self, rom_bank: usize, rd: R) -> Result<()>
Results in an error when the ROM data size is less than the ROM bank’s size.
sourcefn iter_pages<A: RangeBounds<u16>>(
&self,
address_range: A
) -> Result<MemPageRefIter<'_, Self>>
fn iter_pages<A: RangeBounds<u16>>(
&self,
address_range: A
) -> Result<MemPageRefIter<'_, Self>>
Returns an iterator of memory page slice references intersecting with a given address range.
Errors
May return an ZxMemoryError::UnsupportedAddressRange error.
sourcefn for_each_page_mut<A: RangeBounds<u16>, F>(
&mut self,
address_range: A,
f: F
) -> Result<()>where
for<'a> F: FnMut(PageMutSlice<'a>) -> Result<()>,
fn for_each_page_mut<A: RangeBounds<u16>, F>(
&mut self,
address_range: A,
f: F
) -> Result<()>where
for<'a> F: FnMut(PageMutSlice<'a>) -> Result<()>,
Iterates over mutable memory page slices PageMutSlice intersecting with a given address range
passing the slices to the closure f
.
Errors
May return an ZxMemoryError::UnsupportedAddressRange error or an error returned by the provided closure.
Examples found in repository?
321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346
fn load_into_mem<A: RangeBounds<u16>, R: Read>(&mut self, address_range: A, mut rd: R) -> Result<()> {
self.for_each_page_mut(address_range, |page| {
match page {
PageMutSlice::Rom(slice)|PageMutSlice::Ram(slice) => {
rd.read_exact(slice).map_err(ZxMemoryError::Io)
}
}
})
}
/// Fills currently paged-in pages with the data produced by the closure F.
///
/// Useful to fill RAM with random bytes.
///
/// Provide the address range.
///
/// *NOTE*: this will overwrite both ROM and RAM locations.
fn fill_mem<R, F>(&mut self, address_range: R, mut f: F) -> Result<()>
where R: RangeBounds<u16>, F: FnMut() -> u8
{
self.for_each_page_mut(address_range, |page| {
for p in page.into_mut_slice().iter_mut() {
*p = f()
}
Ok(())
})
}
sourcefn load_into_mem<A: RangeBounds<u16>, R: Read>(
&mut self,
address_range: A,
rd: R
) -> Result<()>
fn load_into_mem<A: RangeBounds<u16>, R: Read>(
&mut self,
address_range: A,
rd: R
) -> Result<()>
Reads data into a paged-in memory area at the given address range.
sourcefn fill_mem<R, F>(&mut self, address_range: R, f: F) -> Result<()>where
R: RangeBounds<u16>,
F: FnMut() -> u8,
fn fill_mem<R, F>(&mut self, address_range: R, f: F) -> Result<()>where
R: RangeBounds<u16>,
F: FnMut() -> u8,
Fills currently paged-in pages with the data produced by the closure F.
Useful to fill RAM with random bytes.
Provide the address range.
NOTE: this will overwrite both ROM and RAM locations.