palette and pattern tables
This commit is contained in:
78
src/main.rs
78
src/main.rs
@@ -61,8 +61,8 @@ fn main() -> Result<(), Error> {
|
|||||||
// Prepare window and drawing resources
|
// Prepare window and drawing resources
|
||||||
|
|
||||||
// debugger + scaled nes resolution + border
|
// debugger + scaled nes resolution + border
|
||||||
let window_width = 300 + 256 * 2 + 5;
|
let window_width = 300 + 256 * 3 + 5;
|
||||||
let window_height = 40 + 240*2 + 5;
|
let window_height = 40 + 240 * 3 + 5;
|
||||||
let mut window: PistonWindow = WindowSettings::new("xXx NESemu xXx", [window_width, window_height])
|
let mut window: PistonWindow = WindowSettings::new("xXx NESemu xXx", [window_width, window_height])
|
||||||
.exit_on_esc(true).graphics_api(OpenGL::V3_2).build().unwrap();
|
.exit_on_esc(true).graphics_api(OpenGL::V3_2).build().unwrap();
|
||||||
let mut event_settings = EventSettings::new();
|
let mut event_settings = EventSettings::new();
|
||||||
@@ -78,33 +78,87 @@ fn main() -> Result<(), Error> {
|
|||||||
// fps counter
|
// fps counter
|
||||||
let mut fps = FPSCounter::new();
|
let mut fps = FPSCounter::new();
|
||||||
|
|
||||||
// main screen texture
|
// screen textures
|
||||||
let mut texture_ctx = TextureContext {
|
let mut texture_ctx = TextureContext {
|
||||||
factory: window.factory.clone(),
|
factory: window.factory.clone(),
|
||||||
encoder: window.factory.create_command_buffer().into(),
|
encoder: window.factory.create_command_buffer().into(),
|
||||||
};
|
};
|
||||||
let mut texture: G2dTexture = Texture::from_image(
|
|
||||||
|
// main screen
|
||||||
|
let mut main_texture: G2dTexture = Texture::from_image(
|
||||||
&mut texture_ctx,
|
&mut texture_ctx,
|
||||||
&nes.ppu.borrow().canvas_main,
|
&nes.ppu.borrow().canvas_main,
|
||||||
&TextureSettings::new()
|
&TextureSettings::new()
|
||||||
).unwrap();
|
).unwrap();
|
||||||
|
|
||||||
|
// pattern table textures
|
||||||
|
let mut pattern_table_textures: Vec<G2dTexture> = (0..2).map({|i|
|
||||||
|
Texture::from_image(
|
||||||
|
&mut texture_ctx,
|
||||||
|
&nes.ppu.borrow().pattern_tables[i],
|
||||||
|
&TextureSettings::new()
|
||||||
|
).unwrap()
|
||||||
|
}).collect();
|
||||||
|
|
||||||
|
// palette textures
|
||||||
|
let mut palette_textures: Vec<G2dTexture> = (0..8).map({|i|
|
||||||
|
Texture::from_image(
|
||||||
|
&mut texture_ctx,
|
||||||
|
&nes.ppu.borrow().palettes[i],
|
||||||
|
&TextureSettings::new()
|
||||||
|
).unwrap()
|
||||||
|
}).collect();
|
||||||
|
|
||||||
// Main loop
|
// Main loop
|
||||||
let mut run = false;
|
let mut run = true;
|
||||||
while let Some(event) = events.next(&mut window) {
|
while let Some(event) = events.next(&mut window) {
|
||||||
if let Some(_) = event.render_args() {
|
if let Some(_) = event.render_args() {
|
||||||
// Run enough clocks to render the next frame
|
// Run enough clocks to render the next frame
|
||||||
// if run { nes.clock_frame(); }
|
// if run { nes.clock_frame(); }
|
||||||
if run { nes.clock_scanline(); }
|
if run { nes.clock_frame(); }
|
||||||
|
|
||||||
|
{
|
||||||
texture.update(&mut texture_ctx, &nes.ppu.borrow().canvas_main).unwrap();
|
let mut ppu = nes.ppu.borrow_mut();
|
||||||
|
let ppu_bus = nes.ppu_bus.borrow();
|
||||||
|
// main_texture.update(&mut texture_ctx, &ppu.canvas_main).unwrap();
|
||||||
|
pattern_table_textures[0].update(&mut texture_ctx, &ppu.get_pattern_table(&*ppu_bus, 0, 1)).unwrap();
|
||||||
|
pattern_table_textures[1].update(&mut texture_ctx, &ppu.get_pattern_table(&*ppu_bus, 1, 1)).unwrap();
|
||||||
|
palette_textures[0].update(&mut texture_ctx, &ppu.get_palette(&*ppu_bus, 0)).unwrap();
|
||||||
|
palette_textures[1].update(&mut texture_ctx, &ppu.get_palette(&*ppu_bus, 1)).unwrap();
|
||||||
|
palette_textures[2].update(&mut texture_ctx, &ppu.get_palette(&*ppu_bus, 2)).unwrap();
|
||||||
|
palette_textures[3].update(&mut texture_ctx, &ppu.get_palette(&*ppu_bus, 3)).unwrap();
|
||||||
|
palette_textures[4].update(&mut texture_ctx, &ppu.get_palette(&*ppu_bus, 4)).unwrap();
|
||||||
|
palette_textures[5].update(&mut texture_ctx, &ppu.get_palette(&*ppu_bus, 5)).unwrap();
|
||||||
|
palette_textures[6].update(&mut texture_ctx, &ppu.get_palette(&*ppu_bus, 6)).unwrap();
|
||||||
|
palette_textures[7].update(&mut texture_ctx, &ppu.get_palette(&*ppu_bus, 7)).unwrap();
|
||||||
|
}
|
||||||
window.draw_2d(&event, |c, g, d| {
|
window.draw_2d(&event, |c, g, d| {
|
||||||
clear(BG_COLOR, g);
|
clear(BG_COLOR, g);
|
||||||
texture_ctx.encoder.flush(d);
|
texture_ctx.encoder.flush(d);
|
||||||
let transform = c.transform.trans(300.0, 40.0).scale(2.0, 2.0);
|
let transform = c.transform.trans(300.0, 40.0).scale(3.0, 3.0);
|
||||||
image(&texture, transform, g);
|
image(&main_texture, transform, g);
|
||||||
|
|
||||||
|
let mut transform = c.transform.trans(10.0, 480.0).scale(7.0, 7.0);
|
||||||
|
image(&palette_textures[0], transform, g);
|
||||||
|
transform = transform.trans(5.0, 0.0);
|
||||||
|
image(&palette_textures[1], transform, g);
|
||||||
|
transform = transform.trans(5.0, 0.0);
|
||||||
|
image(&palette_textures[2], transform, g);
|
||||||
|
transform = transform.trans(5.0, 0.0);
|
||||||
|
image(&palette_textures[3], transform, g);
|
||||||
|
transform = transform.trans(5.0, 0.0);
|
||||||
|
image(&palette_textures[4], transform, g);
|
||||||
|
transform = transform.trans(5.0, 0.0);
|
||||||
|
image(&palette_textures[5], transform, g);
|
||||||
|
transform = transform.trans(5.0, 0.0);
|
||||||
|
image(&palette_textures[6], transform, g);
|
||||||
|
transform = transform.trans(5.0, 0.0);
|
||||||
|
image(&palette_textures[7], transform, g);
|
||||||
|
|
||||||
|
let mut transform = c.transform.trans(10.0, 490.0).scale(1.0, 1.0);
|
||||||
|
image(&pattern_table_textures[0], transform, g);
|
||||||
|
transform = transform.trans(148.0, 0.0).scale(1.0, 1.0);
|
||||||
|
image(&pattern_table_textures[1], transform, g);
|
||||||
|
|
||||||
// fps
|
// fps
|
||||||
let fps = fps.tick();
|
let fps = fps.tick();
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ pub struct NES {
|
|||||||
pub cpu: CPU,
|
pub cpu: CPU,
|
||||||
pub bus: Bus,
|
pub bus: Bus,
|
||||||
pub ppu: Rc<RefCell<PPU>>,
|
pub ppu: Rc<RefCell<PPU>>,
|
||||||
pub ppu_bus: PPUBus,
|
pub ppu_bus: Rc<RefCell<PPUBus>>,
|
||||||
pub clock_count: u64,
|
pub clock_count: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ impl NES {
|
|||||||
cpu: CPU::new(),
|
cpu: CPU::new(),
|
||||||
bus: Bus::new(ppu.clone(), ppu_bus.clone()),
|
bus: Bus::new(ppu.clone(), ppu_bus.clone()),
|
||||||
ppu: ppu.clone(),
|
ppu: ppu.clone(),
|
||||||
ppu_bus: PPUBus::new(),
|
ppu_bus: ppu_bus.clone(),
|
||||||
clock_count: 0,
|
clock_count: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -53,7 +53,7 @@ impl NES {
|
|||||||
// both buses need to be connected to the cartridge
|
// both buses need to be connected to the cartridge
|
||||||
let cart = Rc::new(RefCell::new(cartridge));
|
let cart = Rc::new(RefCell::new(cartridge));
|
||||||
self.bus.insert_cartridge(cart.clone());
|
self.bus.insert_cartridge(cart.clone());
|
||||||
self.ppu_bus.insert_cartridge(cart.clone())
|
self.ppu_bus.borrow_mut().insert_cartridge(cart.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initializes the NES CPU programm pointer
|
// Initializes the NES CPU programm pointer
|
||||||
@@ -74,7 +74,7 @@ impl NES {
|
|||||||
if self.clock_count % 3 == 0 {
|
if self.clock_count % 3 == 0 {
|
||||||
self.cpu.clock(&mut self.bus);
|
self.cpu.clock(&mut self.bus);
|
||||||
}
|
}
|
||||||
self.ppu.borrow_mut().clock(&mut self.ppu_bus);
|
self.ppu.borrow_mut().clock(&mut *self.ppu_bus.borrow_mut());
|
||||||
if self.clock_count % 100000 == 0 {
|
if self.clock_count % 100000 == 0 {
|
||||||
info!("clock {}", self.clock_count);
|
info!("clock {}", self.clock_count);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -99,7 +99,8 @@ pub struct PPU {
|
|||||||
pub cycle: u16,
|
pub cycle: u16,
|
||||||
pub scanline: u16,
|
pub scanline: u16,
|
||||||
pub canvas_main: Sprite,
|
pub canvas_main: Sprite,
|
||||||
pattern_table: [Sprite; 2],
|
pub pattern_tables: [Sprite; 2],
|
||||||
|
pub palettes: [Sprite; 8],
|
||||||
pub frame_ready: bool,
|
pub frame_ready: bool,
|
||||||
addr_latch_set: bool,
|
addr_latch_set: bool,
|
||||||
data_buffer: Byte,
|
data_buffer: Byte,
|
||||||
@@ -112,7 +113,20 @@ impl PPU {
|
|||||||
cycle: 0,
|
cycle: 0,
|
||||||
scanline: 0,
|
scanline: 0,
|
||||||
canvas_main: ImageBuffer::from_pixel(256, 240, PALETTE[&0x00]),
|
canvas_main: ImageBuffer::from_pixel(256, 240, PALETTE[&0x00]),
|
||||||
pattern_table: [ImageBuffer::new(128, 128), ImageBuffer::new(128, 128)],
|
pattern_tables: [
|
||||||
|
ImageBuffer::from_pixel(128, 128, PALETTE[&0x00]),
|
||||||
|
ImageBuffer::from_pixel(128, 128, PALETTE[&0x00])
|
||||||
|
],
|
||||||
|
palettes: [
|
||||||
|
ImageBuffer::from_pixel(4, 1, PALETTE[&0x00]),
|
||||||
|
ImageBuffer::from_pixel(4, 1, PALETTE[&0x00]),
|
||||||
|
ImageBuffer::from_pixel(4, 1, PALETTE[&0x00]),
|
||||||
|
ImageBuffer::from_pixel(4, 1, PALETTE[&0x00]),
|
||||||
|
ImageBuffer::from_pixel(4, 1, PALETTE[&0x00]),
|
||||||
|
ImageBuffer::from_pixel(4, 1, PALETTE[&0x00]),
|
||||||
|
ImageBuffer::from_pixel(4, 1, PALETTE[&0x00]),
|
||||||
|
ImageBuffer::from_pixel(4, 1, PALETTE[&0x00]),
|
||||||
|
],
|
||||||
frame_ready: false,
|
frame_ready: false,
|
||||||
addr_latch_set: false,
|
addr_latch_set: false,
|
||||||
data_buffer: 0
|
data_buffer: 0
|
||||||
@@ -207,7 +221,7 @@ impl PPU {
|
|||||||
// palette memory
|
// palette memory
|
||||||
let data = self.data_buffer;
|
let data = self.data_buffer;
|
||||||
self.data_buffer = mem.readb_ppu(addr);
|
self.data_buffer = mem.readb_ppu(addr);
|
||||||
|
|
||||||
if addr > 0x3F00 { // everything above 0x3F00 is palette
|
if addr > 0x3F00 { // everything above 0x3F00 is palette
|
||||||
self.data_buffer
|
self.data_buffer
|
||||||
} else {
|
} else {
|
||||||
@@ -265,6 +279,30 @@ impl PPU {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get a colored pixel using the NES color palette for given palette_id
|
||||||
|
// and pixel value
|
||||||
|
fn get_color_from_ram<T: PPUMemory>(&self, mem: &T, palette_id: u8, pixel: u8) -> Pixel {
|
||||||
|
// 0x3F00: Start of palette memory
|
||||||
|
// palette << 2: Palette size is 4
|
||||||
|
// pixel: pixel index is 0,1,2 or 3
|
||||||
|
// 0x3F (63): limits reading to PALETTE size
|
||||||
|
let palette_idx_addr = 0x3F00 + ((palette_id as Word) << 2) + pixel as Word;
|
||||||
|
// println!(palette_id_addr);
|
||||||
|
let palette_idx = mem.readb_ppu(palette_idx_addr) & 0x3F;
|
||||||
|
PALETTE[&palette_idx]
|
||||||
|
}
|
||||||
|
|
||||||
|
// updates the palette from VRAM and returns a sprite with the 4 colors
|
||||||
|
pub fn get_palette<T: PPUMemory>(&mut self, mem: &T, palette_id: u8) -> &Sprite {
|
||||||
|
for i in 0..4 {
|
||||||
|
self.palettes[palette_id as usize].put_pixel(
|
||||||
|
i, 0,
|
||||||
|
self.get_color_from_ram(mem, palette_id, i as u8)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
&self.palettes[palette_id as usize]
|
||||||
|
}
|
||||||
|
|
||||||
// Get the correct color for the pixel from the given palette
|
// Get the correct color for the pixel from the given palette
|
||||||
fn get_color(&self, pixel: Byte, _palette: Byte) -> Pixel {
|
fn get_color(&self, pixel: Byte, _palette: Byte) -> Pixel {
|
||||||
// TODO: not implemented yet. returns some black and white color
|
// TODO: not implemented yet. returns some black and white color
|
||||||
@@ -278,7 +316,7 @@ impl PPU {
|
|||||||
|
|
||||||
// Get one of the two pattern tables of the PPU
|
// Get one of the two pattern tables of the PPU
|
||||||
// This also initializes/updates the pattern table
|
// This also initializes/updates the pattern table
|
||||||
fn get_pattern_table<T: PPUMemory>(&mut self, index: usize, _palette: Byte, mem: &T) -> &Sprite {
|
pub fn get_pattern_table<T: PPUMemory>(&mut self, mem: &T, index: usize, palette_id: Byte) -> &Sprite {
|
||||||
// 16 x 16 tiles of 8x8px sprites per pattern table => 128x128px
|
// 16 x 16 tiles of 8x8px sprites per pattern table => 128x128px
|
||||||
for x in 0..16 { // tile row
|
for x in 0..16 { // tile row
|
||||||
for y in 0..16 { // tile column
|
for y in 0..16 { // tile column
|
||||||
@@ -298,10 +336,10 @@ impl PPU {
|
|||||||
let mut tile_msb = mem.readb_ppu(tile_addr + 8);
|
let mut tile_msb = mem.readb_ppu(tile_addr + 8);
|
||||||
for col in 0..8 {
|
for col in 0..8 {
|
||||||
let pixel = (tile_lsb & 0x01) + (tile_msb & 0x01);
|
let pixel = (tile_lsb & 0x01) + (tile_msb & 0x01);
|
||||||
self.pattern_table[index].put_pixel(
|
self.pattern_tables[index].put_pixel(
|
||||||
(x * 8 + (7-col)) as u32, // x starts on the right, sprit is from left
|
(x * 8 + (7-col)) as u32, // x starts on the right, sprit is from left
|
||||||
(y * 8 + row) as u32,
|
(y * 8 + row) as u32,
|
||||||
self.get_color(123, pixel));
|
self.get_color_from_ram(mem, palette_id, pixel));
|
||||||
tile_lsb >>= 1;
|
tile_lsb >>= 1;
|
||||||
tile_msb >>= 1;
|
tile_msb >>= 1;
|
||||||
}
|
}
|
||||||
@@ -309,14 +347,14 @@ impl PPU {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&self.pattern_table[index]
|
&self.pattern_tables[index]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::nes::memory::PPUBus;
|
use crate::nes::ppubus::PPUBus;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_set_flags() {
|
fn test_set_flags() {
|
||||||
|
|||||||
@@ -37,8 +37,13 @@ impl PPUMemory for PPUBus {
|
|||||||
fn readb_ppu(&self, addr: Addr) -> Byte {
|
fn readb_ppu(&self, addr: Addr) -> Byte {
|
||||||
// Palette is never mapped to cartridge
|
// Palette is never mapped to cartridge
|
||||||
if PALETTE_ADDR_RANGE[0] <= addr && addr <= PALETTE_ADDR_RANGE[1] {
|
if PALETTE_ADDR_RANGE[0] <= addr && addr <= PALETTE_ADDR_RANGE[1] {
|
||||||
let rel_addr = addr - 0x3F00;
|
let mut rel_addr = addr - 0x3F00;
|
||||||
return self.palette_memory[(rel_addr % 0x0020) as usize]
|
rel_addr = rel_addr % 0x0020;
|
||||||
|
if rel_addr == 0x0010 { rel_addr = 0x0000 }
|
||||||
|
if rel_addr == 0x0014 { rel_addr = 0x0004 }
|
||||||
|
if rel_addr == 0x0018 { rel_addr = 0x0008 }
|
||||||
|
if rel_addr == 0x001C { rel_addr = 0x000C }
|
||||||
|
return self.palette_memory[(rel_addr) as usize]
|
||||||
}
|
}
|
||||||
|
|
||||||
// give the cartridge a chance to handle the rest
|
// give the cartridge a chance to handle the rest
|
||||||
@@ -71,7 +76,12 @@ impl PPUMemory for PPUBus {
|
|||||||
fn writeb_ppu(&mut self, addr: Addr, data: Byte) {
|
fn writeb_ppu(&mut self, addr: Addr, data: Byte) {
|
||||||
// Palette is never mapped to cartridge
|
// Palette is never mapped to cartridge
|
||||||
if PALETTE_ADDR_RANGE[0] <= addr && addr <= PALETTE_ADDR_RANGE[1] {
|
if PALETTE_ADDR_RANGE[0] <= addr && addr <= PALETTE_ADDR_RANGE[1] {
|
||||||
let rel_addr = addr - 0x3F00;
|
let mut rel_addr = addr - 0x3F00;
|
||||||
|
rel_addr = rel_addr % 0x0020;
|
||||||
|
if rel_addr == 0x0010 { rel_addr = 0x0000 }
|
||||||
|
if rel_addr == 0x0014 { rel_addr = 0x0004 }
|
||||||
|
if rel_addr == 0x0018 { rel_addr = 0x0008 }
|
||||||
|
if rel_addr == 0x001C { rel_addr = 0x000C }
|
||||||
self.palette_memory[(rel_addr % 0x0020) as usize] = data;
|
self.palette_memory[(rel_addr % 0x0020) as usize] = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -246,14 +256,29 @@ 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() {
|
||||||
assert_eq!(0, mem.readb_ppu(addr));
|
|
||||||
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
// assert palette are initialized correctly
|
// assert palette are initialized correctly
|
||||||
for (idx, addr) in (0x3F00 .. 0x3F1F + 1).enumerate() {
|
// mirroring makes this look a bit strange, but this is the expected
|
||||||
assert_eq!(idx as Byte, mem.readb_ppu(addr));
|
// result for writing numbers to 0x3F00 to 0x3F1F
|
||||||
|
let expected = [
|
||||||
|
16,
|
||||||
|
1, 2, 3, 20,
|
||||||
|
5, 6, 7, 24,
|
||||||
|
9, 10, 11, 28,
|
||||||
|
13, 14, 15, 16,
|
||||||
|
17, 18, 19, 20,
|
||||||
|
21, 22, 23, 24,
|
||||||
|
25, 26, 27, 28,
|
||||||
|
29, 30, 31,
|
||||||
|
];
|
||||||
|
|
||||||
|
for (addr, expected) in (0x3F00 .. 0x3F1F + 1).zip(expected.iter()) {
|
||||||
|
assert_eq!(expected, &mem.readb_ppu(addr),
|
||||||
|
"{:#08x}", addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -280,47 +305,83 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ppu_memory_palette_internal_mirroring() {
|
||||||
|
|
||||||
|
let wired_mirrors = [
|
||||||
|
(0x3F10, 0x3F00),
|
||||||
|
(0x3F14, 0x3F04),
|
||||||
|
(0x3F18, 0x3F08),
|
||||||
|
(0x3F1C, 0x3F0C),
|
||||||
|
];
|
||||||
|
for (idx, (addr, true_addr)) in wired_mirrors.iter().enumerate() {
|
||||||
|
let mut mem = PPUBus::new();
|
||||||
|
mem.writeb_ppu(*true_addr as Addr, idx as Byte);
|
||||||
|
assert_eq!(idx as Byte, mem.readb_ppu(*true_addr as Addr));
|
||||||
|
assert_eq!(idx as Byte, mem.readb_ppu(*addr as Addr));
|
||||||
|
mem.writeb_ppu(*true_addr as Addr, idx as Byte + 1);
|
||||||
|
assert_eq!(idx as Byte + 1, mem.readb_ppu(*true_addr as Addr));
|
||||||
|
assert_eq!(idx as Byte + 1, mem.readb_ppu(*addr as Addr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_ppu_memory_palette_mirroring() {
|
fn test_ppu_memory_palette_mirroring() {
|
||||||
let mut mem = PPUBus::new();
|
let mut mem = PPUBus::new();
|
||||||
|
|
||||||
// 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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// assert palette are initialized correctly
|
||||||
|
// mirroring makes this look a bit strange, but this is the expected
|
||||||
|
// result for writing numbers to 0x3F00 to 0x3F1F
|
||||||
|
let expected = [
|
||||||
|
16,
|
||||||
|
1, 2, 3, 20,
|
||||||
|
5, 6, 7, 24,
|
||||||
|
9, 10, 11, 28,
|
||||||
|
13, 14, 15, 16,
|
||||||
|
17, 18, 19, 20,
|
||||||
|
21, 22, 23, 24,
|
||||||
|
25, 26, 27, 28,
|
||||||
|
29, 30, 31,
|
||||||
|
];
|
||||||
|
|
||||||
// mirror memory should have the same data
|
// mirror memory should have the same data
|
||||||
for (idx, addr) in (0x3F20 .. 0x3F3F + 1).enumerate() {
|
for (idx, addr) in (0x3F20 .. 0x3F3F + 1).enumerate() {
|
||||||
assert_eq!(idx as Byte, mem.readb_ppu(addr));
|
assert_eq!(expected[idx], mem.readb_ppu(addr));
|
||||||
}
|
}
|
||||||
for (idx, addr) in (0x3F40 .. 0x3F5F + 1).enumerate() {
|
for (idx, addr) in (0x3F40 .. 0x3F5F + 1).enumerate() {
|
||||||
assert_eq!(idx as Byte, mem.readb_ppu(addr));
|
assert_eq!(expected[idx], mem.readb_ppu(addr));
|
||||||
}
|
}
|
||||||
for (idx, addr) in (0x3F60 .. 0x3F7F + 1).enumerate() {
|
for (idx, addr) in (0x3F60 .. 0x3F7F + 1).enumerate() {
|
||||||
assert_eq!(idx as Byte, mem.readb_ppu(addr));
|
assert_eq!(expected[idx], mem.readb_ppu(addr));
|
||||||
}
|
}
|
||||||
for (idx, addr) in (0x3F80 .. 0x3F9F + 1).enumerate() {
|
for (idx, addr) in (0x3F80 .. 0x3F9F + 1).enumerate() {
|
||||||
assert_eq!(idx as Byte, mem.readb_ppu(addr));
|
assert_eq!(expected[idx], mem.readb_ppu(addr));
|
||||||
}
|
}
|
||||||
for (idx, addr) in (0x3FA0 .. 0x3FBF + 1).enumerate() {
|
for (idx, addr) in (0x3FA0 .. 0x3FBF + 1).enumerate() {
|
||||||
assert_eq!(idx as Byte, mem.readb_ppu(addr));
|
assert_eq!(expected[idx], mem.readb_ppu(addr));
|
||||||
}
|
}
|
||||||
for (idx, addr) in (0x3FC0 .. 0x3FDF + 1).enumerate() {
|
for (idx, addr) in (0x3FC0 .. 0x3FDF + 1).enumerate() {
|
||||||
assert_eq!(idx as Byte, mem.readb_ppu(addr));
|
assert_eq!(expected[idx], mem.readb_ppu(addr));
|
||||||
}
|
}
|
||||||
for (idx, addr) in (0x3FE0 .. 0x3FFF + 1).enumerate() {
|
for (idx, addr) in (0x3FE0 .. 0x3FFF + 1).enumerate() {
|
||||||
assert_eq!(idx as Byte, mem.readb_ppu(addr));
|
assert_eq!(expected[idx], mem.readb_ppu(addr));
|
||||||
}
|
}
|
||||||
|
|
||||||
// write data to mirrored addr range
|
// write data to mirrored addr range
|
||||||
for (idx, addr) in (0x3FC0 .. 0x3FDF + 1).enumerate() {
|
for (idx, addr) in (0x3FC0 .. 0x3FDF + 1).enumerate() {
|
||||||
mem.writeb_ppu(addr, idx as Byte + 1);
|
mem.writeb_ppu(addr, expected[idx] + 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// start memory should have the same data
|
// start memory should have the same data
|
||||||
for (idx, addr) in (0x3F00 .. 0x3F1F + 1).enumerate() {
|
for (idx, addr) in (0x3F00 .. 0x3F1F + 1).enumerate() {
|
||||||
assert_eq!(idx as Byte + 1, mem.readb_ppu(addr));
|
assert_eq!(expected[idx] + 2, mem.readb_ppu(addr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user