implement nametable mirroring
This commit is contained in:
@@ -18,19 +18,22 @@ struct Header {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Header {
|
impl Header {
|
||||||
|
// parse the 16 Byte header of the file
|
||||||
fn new(f: &mut File) -> Result<Self, Error> {
|
fn new(f: &mut File) -> Result<Self, Error> {
|
||||||
f.seek(SeekFrom::Start(0))?;
|
f.seek(SeekFrom::Start(0))?;
|
||||||
|
|
||||||
// assert NES "NES"
|
// Byte 0-3 are the "NES" format header and just say NES
|
||||||
f.seek(SeekFrom::Start(4))?;
|
f.seek(SeekFrom::Start(4))?;
|
||||||
|
|
||||||
|
// Byte 4 and 5 are prg and chr rom sizes
|
||||||
let mut rom_sizes = [0; 2]; // prg size in 16K and chr size in 8K
|
let mut rom_sizes = [0; 2]; // prg size in 16K and chr size in 8K
|
||||||
f.read_exact(&mut rom_sizes)?;
|
f.read_exact(&mut rom_sizes)?;
|
||||||
|
|
||||||
|
// Byte 6-10 are various flags
|
||||||
let mut flags = [0; 5];
|
let mut flags = [0; 5];
|
||||||
f.read_exact(&mut flags)?;
|
f.read_exact(&mut flags)?;
|
||||||
|
|
||||||
// Unused
|
// Byte 11-15 are unused
|
||||||
f.seek(SeekFrom::Current(5))?;
|
f.seek(SeekFrom::Current(5))?;
|
||||||
|
|
||||||
Ok(Header {
|
Ok(Header {
|
||||||
@@ -54,12 +57,28 @@ impl Header {
|
|||||||
hi | lo
|
hi | lo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_mirror_mode(&self) -> MirrorMode {
|
||||||
|
if (self.mapper1 & 0x01) == 0 {
|
||||||
|
MirrorMode::HORIZONTAL
|
||||||
|
} else {
|
||||||
|
MirrorMode::VERTICAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nametable mirroring mode
|
||||||
|
#[derive(PartialEq,Debug,Copy,Clone)]
|
||||||
|
pub enum MirrorMode {
|
||||||
|
HORIZONTAL,
|
||||||
|
VERTICAL,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Cartridge {
|
pub struct Cartridge {
|
||||||
prg_rom: Vec<Byte>,
|
prg_rom: Vec<Byte>,
|
||||||
chr_rom: Vec<Byte>,
|
chr_rom: Vec<Byte>,
|
||||||
mapper: Box<dyn Mapper>,
|
mapper: Box<dyn Mapper>,
|
||||||
|
mirror: MirrorMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Cartridge {
|
impl Cartridge {
|
||||||
@@ -79,26 +98,28 @@ impl Cartridge {
|
|||||||
let mut chr_rom = vec!(0; header.chr_rom_chunks as usize * 8192);
|
let mut chr_rom = vec!(0; header.chr_rom_chunks as usize * 8192);
|
||||||
f.read_exact(&mut chr_rom)?;
|
f.read_exact(&mut chr_rom)?;
|
||||||
|
|
||||||
|
|
||||||
let mapper = match header.get_mapper_id() {
|
let mapper = match header.get_mapper_id() {
|
||||||
0 => { Mapper0::new(header.prg_rom_chunks, header.chr_rom_chunks) }
|
0 => { Mapper0::new(header.prg_rom_chunks, header.chr_rom_chunks) }
|
||||||
id => bail!("Mapper {:04} not supported", id)
|
id => bail!("Mapper {:04} not supported", id)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let mirror = header.get_mirror_mode();
|
||||||
|
|
||||||
debug!("Cartrige loaded. mapper: {:?}", &mapper);
|
debug!("Cartrige loaded. mapper: {:?}", &mapper);
|
||||||
Ok(Cartridge {
|
Ok(Cartridge {
|
||||||
prg_rom: prg_rom,
|
prg_rom: prg_rom,
|
||||||
chr_rom: chr_rom,
|
chr_rom: chr_rom,
|
||||||
mapper: Box::new(mapper)
|
mapper: Box::new(mapper),
|
||||||
|
mirror: mirror,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dummy() -> Self {
|
pub fn dummy(mirror: MirrorMode) -> Self {
|
||||||
Cartridge {
|
Cartridge {
|
||||||
prg_rom: vec![0; 16384],
|
prg_rom: vec![0; 16384],
|
||||||
chr_rom: vec![0; 8192],
|
chr_rom: vec![0; 8192],
|
||||||
mapper: Box::new(Mapper0::new(1, 1))
|
mapper: Box::new(Mapper0::new(1, 1)),
|
||||||
|
mirror: mirror,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,6 +155,12 @@ impl Cartridge {
|
|||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get cartrige mirror mode
|
||||||
|
// TODO can be changed by mapper
|
||||||
|
pub fn get_mirror_mode(&self) -> MirrorMode {
|
||||||
|
self.mirror
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -179,6 +206,31 @@ mod tests {
|
|||||||
assert_eq!(255, header.get_mapper_id());
|
assert_eq!(255, header.get_mapper_id());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_header_get_mirror_mode() {
|
||||||
|
let header = Header {
|
||||||
|
prg_rom_chunks: 1,
|
||||||
|
chr_rom_chunks: 1,
|
||||||
|
mapper1: 0x00,
|
||||||
|
mapper2: 0x00,
|
||||||
|
prg_ram_size: 0x00,
|
||||||
|
tv1: 0x00,
|
||||||
|
tv2: 0x00
|
||||||
|
};
|
||||||
|
assert_eq!(header.get_mirror_mode(), MirrorMode::HORIZONTAL);
|
||||||
|
let header = Header {
|
||||||
|
prg_rom_chunks: 1,
|
||||||
|
chr_rom_chunks: 1,
|
||||||
|
mapper1: 0x01,
|
||||||
|
mapper2: 0x00,
|
||||||
|
prg_ram_size: 0x00,
|
||||||
|
tv1: 0x00,
|
||||||
|
tv2: 0x00
|
||||||
|
};
|
||||||
|
assert_eq!(header.get_mirror_mode(), MirrorMode::VERTICAL);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_header_has_trainer() {
|
fn test_header_has_trainer() {
|
||||||
let header = Header {
|
let header = Header {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use crate::nes::ppu::PPU;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use core::cell::RefCell;
|
use core::cell::RefCell;
|
||||||
use crate::nes::cartridge::Cartridge;
|
use crate::nes::cartridge::Cartridge;
|
||||||
use crate::nes::types::*;
|
use crate::nes::types::*;
|
||||||
|
use crate::nes::cartridge::MirrorMode;
|
||||||
|
|
||||||
pub const PATTERN_MEMORY_SIZE: usize = 4096;
|
pub const PATTERN_MEMORY_SIZE: usize = 4096;
|
||||||
pub const PATTERN_ADDR_RANGE: [Addr; 2] = [0x000, 0x1FFF];
|
pub const PATTERN_ADDR_RANGE: [Addr; 2] = [0x000, 0x1FFF];
|
||||||
@@ -13,7 +13,7 @@ pub const PALETTE_ADDR_RANGE: [Addr; 2] = [0x3F00, 0x3FFF];
|
|||||||
|
|
||||||
pub struct PPUBus {
|
pub struct PPUBus {
|
||||||
pattern_memory: [[Byte; PATTERN_MEMORY_SIZE]; 2], // 8kb pattern memory
|
pattern_memory: [[Byte; PATTERN_MEMORY_SIZE]; 2], // 8kb pattern memory
|
||||||
nametable_memory: [[Byte; NAMETABLE_MEMORY_SIZE] ;4], // 2kb nametables
|
nametable_memory: [[Byte; NAMETABLE_MEMORY_SIZE] ;2], // 2kb nametables
|
||||||
palette_memory: [Byte; PALETTE_MEMORY_SIZE], // palettes
|
palette_memory: [Byte; PALETTE_MEMORY_SIZE], // palettes
|
||||||
cartridge: Option<Rc<RefCell<Cartridge>>>
|
cartridge: Option<Rc<RefCell<Cartridge>>>
|
||||||
}
|
}
|
||||||
@@ -22,7 +22,7 @@ impl PPUBus {
|
|||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
PPUBus {
|
PPUBus {
|
||||||
pattern_memory: [[0; PATTERN_MEMORY_SIZE]; 2],
|
pattern_memory: [[0; PATTERN_MEMORY_SIZE]; 2],
|
||||||
nametable_memory: [[0; NAMETABLE_MEMORY_SIZE] ;4],
|
nametable_memory: [[0; NAMETABLE_MEMORY_SIZE] ;2],
|
||||||
palette_memory: [0; PALETTE_MEMORY_SIZE],
|
palette_memory: [0; PALETTE_MEMORY_SIZE],
|
||||||
cartridge: None,
|
cartridge: None,
|
||||||
}
|
}
|
||||||
@@ -51,20 +51,44 @@ impl PPUBus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// maps a nametable address to the corresponding index in the memory
|
// maps a nametable address to the corresponding index in the memory
|
||||||
// array
|
// array. Method required an inserted cartrige to read the mirroring mode.
|
||||||
fn map_nametable_addr(&self, addr: Addr) -> (usize, usize) {
|
// Returns none if no cartrige is inserted
|
||||||
let table = if addr < 0x2400 {
|
fn map_nametable_addr(&self, addr: Addr) -> Option<(usize, usize)> {
|
||||||
|
if let Some(cartridge) = &self.cartridge {
|
||||||
|
// sovle mirroring
|
||||||
|
let addr = addr % 0x1000;
|
||||||
|
|
||||||
|
// There are four theoretical nametables
|
||||||
|
let nametable_idx = if addr < 0x0400 {
|
||||||
0
|
0
|
||||||
} else if addr < 0x2800 {
|
} else if addr < 0x0800 {
|
||||||
1
|
1
|
||||||
} else if addr < 0x2C00 {
|
} else if addr < 0x0C00 {
|
||||||
2
|
2
|
||||||
} else {
|
} else {
|
||||||
3
|
3
|
||||||
};
|
};
|
||||||
let rel_addr = (addr - 0x2000) % 0x400;
|
|
||||||
|
|
||||||
(table as usize, rel_addr as usize)
|
// nametable 2,3 are actually mirrored depending on the cartriges
|
||||||
|
// mirror mode
|
||||||
|
let mirror_mode = cartridge.borrow().get_mirror_mode();
|
||||||
|
let table_id = if mirror_mode == MirrorMode::VERTICAL {
|
||||||
|
match nametable_idx {
|
||||||
|
0 | 2 => 0,
|
||||||
|
1 | 3 => 1,
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
match nametable_idx {
|
||||||
|
0 | 1 => 0,
|
||||||
|
2 | 3 => 1,
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let rel_addr = addr % 0x400;
|
||||||
|
return Some((table_id as usize, rel_addr as usize))
|
||||||
|
}
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,9 +112,10 @@ impl PPUMemory for PPUBus {
|
|||||||
return self.pattern_memory[idx.0][idx.1]
|
return self.pattern_memory[idx.0][idx.1]
|
||||||
}
|
}
|
||||||
if NAMETABLE_ADDR_RANGE[0] <= addr && addr <= NAMETABLE_ADDR_RANGE[1] {
|
if NAMETABLE_ADDR_RANGE[0] <= addr && addr <= NAMETABLE_ADDR_RANGE[1] {
|
||||||
let idx = &self.map_nametable_addr(addr);
|
if let Some(idx) = &self.map_nametable_addr(addr) {
|
||||||
return self.nametable_memory[idx.0][idx.1]
|
return self.nametable_memory[idx.0][idx.1]
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
0x00
|
0x00
|
||||||
}
|
}
|
||||||
@@ -114,10 +139,11 @@ impl PPUMemory for PPUBus {
|
|||||||
self.pattern_memory[idx.0][idx.1] = data;
|
self.pattern_memory[idx.0][idx.1] = data;
|
||||||
}
|
}
|
||||||
if NAMETABLE_ADDR_RANGE[0] <= addr && addr <= NAMETABLE_ADDR_RANGE[1] {
|
if NAMETABLE_ADDR_RANGE[0] <= addr && addr <= NAMETABLE_ADDR_RANGE[1] {
|
||||||
let idx = &self.map_nametable_addr(addr);
|
if let Some(idx) = &self.map_nametable_addr(addr) {
|
||||||
self.nametable_memory[idx.0][idx.1] = data;
|
self.nametable_memory[idx.0][idx.1] = data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// PPU interface to allow read/write of memory
|
// PPU interface to allow read/write of memory
|
||||||
@@ -191,13 +217,19 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn dummy_ppu_bus(mirror: MirrorMode) -> PPUBus {
|
||||||
|
let mut mem = PPUBus::new();
|
||||||
|
let mut cart = Cartridge::dummy(mirror);
|
||||||
|
mem.insert_cartridge(Rc::new(RefCell::new(cart)));
|
||||||
|
mem
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_ppu_memory_nametable_rw() {
|
fn test_ppu_memory_nametable_rw() {
|
||||||
let mut mem = PPUBus::new();
|
let mut mem = dummy_ppu_bus(MirrorMode::VERTICAL);
|
||||||
|
|
||||||
// read/write something to nametable memory
|
// read/write something to nametable memory
|
||||||
for (idx, addr) in (0x2000 .. 0x2FFF + 1).enumerate() {
|
for (idx, addr) in (0x2000 .. 0x2FFF + 1).enumerate() {
|
||||||
assert_eq!(0, mem.readb_ppu(addr));
|
|
||||||
mem.writeb_ppu(addr, idx as Byte);
|
mem.writeb_ppu(addr, idx as Byte);
|
||||||
assert_eq!(idx as Byte, mem.readb_ppu(addr));
|
assert_eq!(idx as Byte, mem.readb_ppu(addr));
|
||||||
}
|
}
|
||||||
@@ -210,7 +242,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_ppu_memory_nametable_not_overwritten() {
|
fn test_ppu_memory_nametable_not_overwritten() {
|
||||||
let mut mem = PPUBus::new();
|
let mut mem = dummy_ppu_bus(MirrorMode::VERTICAL);
|
||||||
|
|
||||||
// write some value to whole nametable space
|
// write some value to whole nametable space
|
||||||
for addr in 0x2000 .. 0x3EFF + 1 {
|
for addr in 0x2000 .. 0x3EFF + 1 {
|
||||||
@@ -227,33 +259,103 @@ mod tests {
|
|||||||
// Namestables should not have changed
|
// Namestables should not have changed
|
||||||
for addr in 0x2000 .. 0x3EFF + 1 {
|
for addr in 0x2000 .. 0x3EFF + 1 {
|
||||||
assert_eq!(0x1, mem.readb_ppu(addr),
|
assert_eq!(0x1, mem.readb_ppu(addr),
|
||||||
"Nametable changed unxexpected at position {:#08x}", addr);
|
"Nametable changed unxexpected at position {:#06x}", addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ppu_memory_nametable_mirrormode_vertical() {
|
||||||
|
let mut mem = dummy_ppu_bus(MirrorMode::VERTICAL);
|
||||||
|
// write something to nametable memory and check if vertical mirror
|
||||||
|
// has the same data
|
||||||
|
|
||||||
|
// vertical left
|
||||||
|
for (idx, addr) in (0x2000 .. 0x23FF + 1).enumerate() {
|
||||||
|
mem.writeb_ppu(addr, idx as Byte);
|
||||||
|
assert_eq!(idx as Byte, mem.readb_ppu(addr));
|
||||||
|
assert_eq!(idx as Byte, mem.readb_ppu(addr+0x800));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (idx, addr) in (0x2800 .. 0x2BFF + 1).enumerate() {
|
||||||
|
let val = (idx as Byte).wrapping_add(1);
|
||||||
|
mem.writeb_ppu(addr, val);
|
||||||
|
assert_eq!(val, mem.readb_ppu(addr));
|
||||||
|
assert_eq!(val, mem.readb_ppu(addr-0x800));
|
||||||
|
}
|
||||||
|
|
||||||
|
// vertical right
|
||||||
|
for (idx, addr) in (0x2400 .. 0x27FF + 1).enumerate() {
|
||||||
|
mem.writeb_ppu(addr, idx as Byte);
|
||||||
|
assert_eq!(idx as Byte, mem.readb_ppu(addr));
|
||||||
|
assert_eq!(idx as Byte, mem.readb_ppu(addr+0x800));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (idx, addr) in (0x2C00 .. 0x2EFF + 1).enumerate() {
|
||||||
|
let val = (idx as Byte).wrapping_add(1);
|
||||||
|
mem.writeb_ppu(addr, val);
|
||||||
|
assert_eq!(val, mem.readb_ppu(addr));
|
||||||
|
assert_eq!(val, mem.readb_ppu(addr-0x800));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ppu_memory_nametable_mirrormode_horizontal() {
|
||||||
|
let mut mem = dummy_ppu_bus(MirrorMode::HORIZONTAL);
|
||||||
|
// write something to nametable memory and check if horizontal mirror
|
||||||
|
// has the same data
|
||||||
|
|
||||||
|
// horizontal top
|
||||||
|
for (idx, addr) in (0x2000 .. 0x23FF + 1).enumerate() {
|
||||||
|
mem.writeb_ppu(addr, idx as Byte);
|
||||||
|
assert_eq!(idx as Byte, mem.readb_ppu(addr));
|
||||||
|
assert_eq!(idx as Byte, mem.readb_ppu(addr+0x400));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (idx, addr) in (0x2400 .. 0x27FF + 1).enumerate() {
|
||||||
|
let val = (idx as Byte).wrapping_add(1);
|
||||||
|
mem.writeb_ppu(addr, val);
|
||||||
|
assert_eq!(val, mem.readb_ppu(addr));
|
||||||
|
assert_eq!(val, mem.readb_ppu(addr-0x400));
|
||||||
|
}
|
||||||
|
|
||||||
|
// horizontal bottom
|
||||||
|
for (idx, addr) in (0x2800 .. 0x2BFF + 1).enumerate() {
|
||||||
|
mem.writeb_ppu(addr, idx as Byte);
|
||||||
|
assert_eq!(idx as Byte, mem.readb_ppu(addr));
|
||||||
|
assert_eq!(idx as Byte, mem.readb_ppu(addr+0x400));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (idx, addr) in (0x2C00 .. 0x2EFF + 1).enumerate() {
|
||||||
|
let val = (idx as Byte).wrapping_add(1);
|
||||||
|
mem.writeb_ppu(addr, val);
|
||||||
|
assert_eq!(val, mem.readb_ppu(addr));
|
||||||
|
assert_eq!(val, mem.readb_ppu(addr-0x400));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_ppu_memory_nametable_mirroring() {
|
fn test_ppu_memory_nametable_mirroring() {
|
||||||
let mut mem = PPUBus::new();
|
let mut mem = dummy_ppu_bus(MirrorMode::VERTICAL);
|
||||||
|
|
||||||
// read/write something to nametable memory
|
// read/write something to nametable memory
|
||||||
for (idx, addr) in (0x2000 .. 0x2FFF + 1).enumerate() {
|
for (idx, addr) in (0x2000 .. 0x27FF + 1).enumerate() {
|
||||||
mem.writeb_ppu(addr, idx as Byte);
|
mem.writeb_ppu(addr, idx as Byte);
|
||||||
assert_eq!(idx as Byte, mem.readb_ppu(addr));
|
assert_eq!(idx as Byte, mem.readb_ppu(addr));
|
||||||
}
|
}
|
||||||
|
|
||||||
// mirror memory should have the same data
|
// mirror memory should have the same data
|
||||||
for (idx, addr) in (0x3000 .. 0x3EFF + 1).enumerate() {
|
for (idx, addr) in (0x3000 .. 0x37FF + 1).enumerate() {
|
||||||
assert_eq!(idx as Byte, mem.readb_ppu(addr));
|
assert_eq!(idx as Byte, mem.readb_ppu(addr));
|
||||||
}
|
}
|
||||||
|
|
||||||
// write data to mirrored addr range
|
// write data to mirrored addr range
|
||||||
for (idx, addr) in (0x3000 .. 0x3EFF + 1).enumerate() {
|
for (idx, addr) in (0x3000 .. 0x37FF + 1).enumerate() {
|
||||||
mem.writeb_ppu(addr, idx as Byte);
|
mem.writeb_ppu(addr, idx as Byte);
|
||||||
assert_eq!(idx as Byte, mem.readb_ppu(addr));
|
assert_eq!(idx as Byte, mem.readb_ppu(addr));
|
||||||
}
|
}
|
||||||
|
|
||||||
// start memory should have the same data
|
// start memory should have the same data
|
||||||
for (idx, addr) in (0x2000 .. 0x2FFF + 1).enumerate() {
|
for (idx, addr) in (0x2000 .. 0x27FF + 1).enumerate() {
|
||||||
assert_eq!(idx as Byte, mem.readb_ppu(addr));
|
assert_eq!(idx as Byte, mem.readb_ppu(addr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -265,7 +367,6 @@ mod tests {
|
|||||||
// read/write something to palette memory
|
// read/write something to palette memory
|
||||||
for (idx, addr) in (0x3F00 .. 0x3F1F + 1).enumerate() {
|
for (idx, addr) in (0x3F00 .. 0x3F1F + 1).enumerate() {
|
||||||
mem.writeb_ppu(addr, idx as Byte);
|
mem.writeb_ppu(addr, idx as Byte);
|
||||||
println!("Written {} to {:#08x}", idx, addr);
|
|
||||||
assert_eq!(idx as Byte, mem.readb_ppu(addr));
|
assert_eq!(idx as Byte, mem.readb_ppu(addr));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -340,7 +441,6 @@ mod tests {
|
|||||||
// read/write something to palette memory
|
// read/write something to palette memory
|
||||||
for (idx, addr) in (0x3F00 .. 0x3F1F + 1).enumerate() {
|
for (idx, addr) in (0x3F00 .. 0x3F1F + 1).enumerate() {
|
||||||
mem.writeb_ppu(addr, idx as Byte);
|
mem.writeb_ppu(addr, idx as Byte);
|
||||||
println!("Written {} to {:#08x}", idx, addr);
|
|
||||||
assert_eq!(idx as Byte, mem.readb_ppu(addr));
|
assert_eq!(idx as Byte, mem.readb_ppu(addr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user