diff --git a/examples/real_time.rs b/examples/real_time.rs index 85c87c7..be4bc59 100644 --- a/examples/real_time.rs +++ b/examples/real_time.rs @@ -3,8 +3,8 @@ extern crate sdl2; use rs_nes::cpu::*; use rs_nes::input::{Button, Input, InputBase}; -use rs_nes::memory::Memory; use rs_nes::memory::nes_memory::NesMemoryImpl; +use rs_nes::memory::Memory; use rs_nes::ppu::{Ppu, PpuImpl}; use rs_nes::rom::NesRom; use sdl2::event::Event; diff --git a/src/cpu/debugger/cpu_snapshot/mod.rs b/src/cpu/debugger/cpu_snapshot/mod.rs index 6c2dc0a..740b028 100644 --- a/src/cpu/debugger/cpu_snapshot/mod.rs +++ b/src/cpu/debugger/cpu_snapshot/mod.rs @@ -1,8 +1,8 @@ use base64; use cpu::Registers; use screen::Screen; -use serde::{Serialize, Serializer}; use serde::ser::SerializeStruct; +use serde::{Serialize, Serializer}; pub enum MemorySnapshot { NoChange(u64), // If no change, just send the hash. diff --git a/src/cpu/debugger/debugger_command/mod.rs b/src/cpu/debugger/debugger_command/mod.rs index eaf70a0..7720949 100644 --- a/src/cpu/debugger/debugger_command/mod.rs +++ b/src/cpu/debugger/debugger_command/mod.rs @@ -1,7 +1,7 @@ use super::CpuSnapshot; use screen::Screen; -use serde::{Serialize, Serializer}; use serde::ser::SerializeStruct; +use serde::{Serialize, Serializer}; // The web socket message sent from the debugger to the client pub enum DebuggerCommand { diff --git a/src/cpu/debugger/http_handlers/mod.rs b/src/cpu/debugger/http_handlers/mod.rs index 1bb5b3b..2787b70 100644 --- a/src/cpu/debugger/http_handlers/mod.rs +++ b/src/cpu/debugger/http_handlers/mod.rs @@ -1,15 +1,15 @@ use super::breakpoint_map::BreakpointMap; use cpu::registers::Registers; -use iron::{headers, status}; -use iron::Handler; use iron::modifier::Modifier; use iron::prelude::*; +use iron::Handler; +use iron::{headers, status}; use router::{Params, Router}; -use serde::{Serialize, Serializer}; use serde::ser::SerializeStruct; +use serde::{Serialize, Serializer}; use serde_json; -use std::sync::{Arc, Mutex}; use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::{Arc, Mutex}; use std::thread::Thread; impl Serialize for Registers { diff --git a/src/cpu/debugger/mod.rs b/src/cpu/debugger/mod.rs index 80e3730..1662329 100644 --- a/src/cpu/debugger/mod.rs +++ b/src/cpu/debugger/mod.rs @@ -1,15 +1,15 @@ -mod debugger_command; -mod http_handlers; mod breakpoint_map; mod cpu_snapshot; +mod debugger_command; +mod http_handlers; use byte_utils::from_lo_hi; use chan::{self, Receiver, Sender}; -use cpu::{Cpu, Interrupt}; use cpu::debugger::breakpoint_map::BreakpointMap; use cpu::debugger::cpu_snapshot::{CpuSnapshot, MemorySnapshot}; use cpu::debugger::debugger_command::{BreakReason, DebuggerCommand}; use cpu::debugger::http_handlers::*; +use cpu::{Cpu, Interrupt}; use input::Input; use iron::prelude::*; use memory::{Memory, ADDRESSABLE_MEMORY}; @@ -17,8 +17,8 @@ use router::Router; use screen::Screen; use serde::Serialize; use serde_json; -use std::sync::{Arc, Mutex}; use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::{Arc, Mutex}; use std::thread; use websocket::{Message as WsMessage, Server as WsServer}; diff --git a/src/cpu/length_and_timing_tests.rs b/src/cpu/length_and_timing_tests.rs index 17062bd..9ae5c15 100644 --- a/src/cpu/length_and_timing_tests.rs +++ b/src/cpu/length_and_timing_tests.rs @@ -15,7 +15,7 @@ use cpu::TestCpu; /// crossing for indirect indexed addressing modes /// macro_rules! assert_length_and_cycles { - ( $ asm : expr , $ expected_len : expr , $ expected_cycles : expr ) => {{ + ($asm:expr, $expected_len:expr, $expected_cycles:expr) => {{ let mut cpu = TestCpu::new_test(); cpu.registers.x = 1; cpu.registers.y = 1; @@ -32,21 +32,25 @@ macro_rules! assert_length_and_cycles { let actual_len = cpu.registers.pc - 0x200; if expected_len != actual_len { - panic!("Expected instruction length is {} but it was {}", - expected_len, actual_len) + panic!( + "Expected instruction length is {} but it was {}", + expected_len, actual_len + ) } if expected_cycles != cpu.cycles { - panic!("Expected number of executed cycles to be {} but it was {}", - expected_cycles, cpu.cycles) + panic!( + "Expected number of executed cycles to be {} but it was {}", + expected_cycles, cpu.cycles + ) } } } - }} + }}; } macro_rules! assert_cycles { - ( $ cpu : expr , $ asm : expr , $ expected_cycles : expr ) => {{ + ($cpu:expr, $asm:expr, $expected_cycles:expr) => {{ let asm = $asm; let mut cpu = $cpu; let mut buf = Vec::::new(); @@ -57,12 +61,14 @@ macro_rules! assert_cycles { let expected_cycles = $expected_cycles; cpu.step(); if expected_cycles != cpu.cycles { - panic!("Expected number of executed cycles to be {} but it was {}", - expected_cycles, cpu.cycles) + panic!( + "Expected number of executed cycles to be {} but it was {}", + expected_cycles, cpu.cycles + ) } } } - }} + }}; } /// Similar to the above macro, but for relative instructions. Instead of passing the instruction @@ -70,7 +76,7 @@ macro_rules! assert_cycles { /// Also, the program counter is set to 0x27f so that can cross the page boundary given a max /// offset (relative instruction length + 127 will push PC to 0x300). macro_rules! assert_length_and_cycles_relative { - ( $ cpu: expr, $ asm : expr , $ expected_len : expr , $ expected_cycles : expr ) => {{ + ($cpu:expr, $asm:expr, $expected_len:expr, $expected_cycles:expr) => {{ let mut cpu = $cpu; let asm = $asm; let mut buf = Vec::::new(); @@ -85,17 +91,21 @@ macro_rules! assert_length_and_cycles_relative { let actual_len = cpu.registers.pc - 0x27f; if expected_len != actual_len { - panic!("Expected instruction length is {} but it was {}", - expected_len, actual_len) + panic!( + "Expected instruction length is {} but it was {}", + expected_len, actual_len + ) } if expected_cycles != cpu.cycles { - panic!("Expected number of executed cycles to be {} but it was {}", - expected_cycles, cpu.cycles) + panic!( + "Expected number of executed cycles to be {} but it was {}", + expected_cycles, cpu.cycles + ) } } } - }} + }}; } #[test] diff --git a/src/cpu/mod.rs b/src/cpu/mod.rs index 032a38d..273b50f 100644 --- a/src/cpu/mod.rs +++ b/src/cpu/mod.rs @@ -10,8 +10,8 @@ mod length_and_timing_tests; #[cfg(feature = "debugger")] pub mod debugger; -mod registers; mod opcodes; +mod registers; use byte_utils::{from_lo_hi, lo_hi, wrapping_dec, wrapping_inc}; use cpu::registers::Registers; diff --git a/src/cpu/opcodes/am_test_utils.rs b/src/cpu/opcodes/am_test_utils.rs index 4610a73..7aed1f8 100644 --- a/src/cpu/opcodes/am_test_utils.rs +++ b/src/cpu/opcodes/am_test_utils.rs @@ -1,5 +1,5 @@ -use cpu::{TestCpu, TestMemory}; use cpu::opcodes::AddressingMode; +use cpu::{TestCpu, TestMemory}; use input::NoInput; use screen::NoScreen; use std::cell::Cell; diff --git a/src/cpu/opcodes/arithmetic_instr_spec_tests.rs b/src/cpu/opcodes/arithmetic_instr_spec_tests.rs index e4ae692..353fb60 100644 --- a/src/cpu/opcodes/arithmetic_instr_spec_tests.rs +++ b/src/cpu/opcodes/arithmetic_instr_spec_tests.rs @@ -1,5 +1,5 @@ -use cpu::*; use cpu::opcodes::*; +use cpu::*; /// ## Sign and zero flag tests /// diff --git a/src/cpu/opcodes/bitwise_and_shift_instr_spec_tests.rs b/src/cpu/opcodes/bitwise_and_shift_instr_spec_tests.rs index 238ca49..0dcc744 100644 --- a/src/cpu/opcodes/bitwise_and_shift_instr_spec_tests.rs +++ b/src/cpu/opcodes/bitwise_and_shift_instr_spec_tests.rs @@ -1,5 +1,5 @@ -use cpu::*; use cpu::opcodes::*; +use cpu::*; fn asl(cpu: &mut TestCpu, val: u8) -> (u8, bool) { Asl::execute(cpu, val); diff --git a/src/cpu/opcodes/branch_spec_tests.rs b/src/cpu/opcodes/branch_spec_tests.rs index 18d39e0..ee568ae 100644 --- a/src/cpu/opcodes/branch_spec_tests.rs +++ b/src/cpu/opcodes/branch_spec_tests.rs @@ -1,5 +1,5 @@ -use cpu::*; use cpu::opcodes::*; +use cpu::*; #[test] fn bpl_not_crossing_page_boundary_positive_offset() { diff --git a/src/cpu/opcodes/compare_spec_tests.rs b/src/cpu/opcodes/compare_spec_tests.rs index 662f44c..4a83d38 100644 --- a/src/cpu/opcodes/compare_spec_tests.rs +++ b/src/cpu/opcodes/compare_spec_tests.rs @@ -1,5 +1,5 @@ -use cpu::*; use cpu::opcodes::*; +use cpu::*; #[test] fn cmp_equal_flag_check() { diff --git a/src/cpu/opcodes/flag_instr_spec_tests.rs b/src/cpu/opcodes/flag_instr_spec_tests.rs index 03081b2..f699994 100644 --- a/src/cpu/opcodes/flag_instr_spec_tests.rs +++ b/src/cpu/opcodes/flag_instr_spec_tests.rs @@ -1,5 +1,5 @@ -use cpu::*; use cpu::opcodes::*; +use cpu::*; #[test] fn sei() { diff --git a/src/cpu/opcodes/inc_dec_spec_tests.rs b/src/cpu/opcodes/inc_dec_spec_tests.rs index 48b0260..3dd886d 100644 --- a/src/cpu/opcodes/inc_dec_spec_tests.rs +++ b/src/cpu/opcodes/inc_dec_spec_tests.rs @@ -1,6 +1,6 @@ -use cpu::*; -use cpu::opcodes::*; use cpu::opcodes::am_test_utils::*; +use cpu::opcodes::*; +use cpu::*; #[test] fn dec_test1() { diff --git a/src/cpu/opcodes/jump_and_returns_instr_spec_tests.rs b/src/cpu/opcodes/jump_and_returns_instr_spec_tests.rs index 112e3fa..476ccc4 100644 --- a/src/cpu/opcodes/jump_and_returns_instr_spec_tests.rs +++ b/src/cpu/opcodes/jump_and_returns_instr_spec_tests.rs @@ -1,7 +1,7 @@ // TODO: RTI, BRK tests -use cpu::*; use cpu::opcodes::*; +use cpu::*; #[test] fn jmp() { diff --git a/src/cpu/opcodes/loads_and_stores_spec_tests.rs b/src/cpu/opcodes/loads_and_stores_spec_tests.rs index da9b4df..795fc6a 100644 --- a/src/cpu/opcodes/loads_and_stores_spec_tests.rs +++ b/src/cpu/opcodes/loads_and_stores_spec_tests.rs @@ -1,6 +1,6 @@ -use cpu::*; -use cpu::opcodes::*; use cpu::opcodes::am_test_utils::*; +use cpu::opcodes::*; +use cpu::*; #[test] fn lda_value_set() { diff --git a/src/cpu/opcodes/reg_transfer_spec_tests.rs b/src/cpu/opcodes/reg_transfer_spec_tests.rs index 2bcf75a..c5739e6 100644 --- a/src/cpu/opcodes/reg_transfer_spec_tests.rs +++ b/src/cpu/opcodes/reg_transfer_spec_tests.rs @@ -1,7 +1,7 @@ // TODO: Tests to assert status flags -use cpu::*; use cpu::opcodes::*; +use cpu::*; #[test] fn tax() { diff --git a/src/lib.rs b/src/lib.rs index feaa856..7d68393 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -48,11 +48,11 @@ extern crate asm6502; #[cfg(test)] extern crate rand; -pub mod rom; -pub mod memory; +mod apu; +mod byte_utils; pub mod cpu; +pub mod input; +pub mod memory; pub mod ppu; +pub mod rom; pub mod screen; -pub mod input; -mod apu; -mod byte_utils; diff --git a/src/memory/nes_memory/mod.rs b/src/memory/nes_memory/mod.rs index 80f7618..c0d7807 100644 --- a/src/memory/nes_memory/mod.rs +++ b/src/memory/nes_memory/mod.rs @@ -14,14 +14,12 @@ use std::io::Write; use std::rc::Rc; macro_rules! dma_tick { - ( $mem : expr ) => { - { - let tick_action = $mem.tick(); - if tick_action != Interrupt::None { - panic!("unimplemented: nmi during dma") - } + ($mem:expr) => {{ + let tick_action = $mem.tick(); + if tick_action != Interrupt::None { + panic!("unimplemented: nmi during dma") } - }; + }}; } pub type NesMemoryImpl = NesMemoryBase; diff --git a/src/ppu/mod.rs b/src/ppu/mod.rs index f1b44e0..6b1d661 100644 --- a/src/ppu/mod.rs +++ b/src/ppu/mod.rs @@ -1,15 +1,15 @@ #[cfg(test)] mod spec_tests; -mod palette; +mod background_renderer; mod control_register; +mod cycle_table; mod mask_register; -mod status_register; +mod palette; mod sprite_renderer; +mod status_register; mod vram; mod write_latch; -mod background_renderer; -mod cycle_table; use self::write_latch::WriteLatch; use cpu::Interrupt; @@ -119,6 +119,71 @@ impl Ppu for PpuBase { } } + /// Accepts a PPU memory mapped address and writes it to the appropriate register + fn write(&mut self, addr: u16, val: u8) { + debug_assert!( + addr >= 0x2000 && addr < 0x4000, + "Invalid memory mapped ppu address" + ); + + match addr & 7 { + 0x0 => { + self.control.write(val); + self.vram.control_write(val); + } + 0x1 => self.mask.write(val), + 0x2 => (), // readonly + 0x3 => self.sprite_renderer.write_address(val), + 0x4 => self.sprite_renderer.write_data(val), + 0x5 => { + let latch_state = self.write_latch.write(val); + self.vram.scroll_write(latch_state); + } + 0x6 => { + let latch_state = self.write_latch.write(val); + self.vram.write_ppu_addr(latch_state); + } + 0x7 => { + let inc_amount = self.control.vram_addr_increment(); + self.vram.write_ppu_data(val, inc_amount) + } + _ => unreachable!(), + } + } + + /// Accepts a PPU memory mapped address and returns the value + fn read(&self, addr: u16) -> u8 { + debug_assert!( + addr >= 0x2000 && addr < 0x4000, + "Invalid memory mapped ppu address" + ); + + match addr & 7 { + 0x0 => *self.control, + 0x1 => *self.mask, + 0x2 => { + let status = self.status.read(); + self.status.clear_in_vblank(); + self.write_latch.clear(); + status + } + 0x4 => { + if self.status.in_vblank() || !self.mask.rendering_enabled() { + // No OAM addr increment during vblank or forced blank + self.sprite_renderer.read_data() + } else { + self.sprite_renderer.read_data_increment_addr() + } + } + 0x7 => { + let inc_amount = self.control.vram_addr_increment(); + self.vram.read_ppu_data(inc_amount) + } + 0x3 | 0x5 | 0x6 => 0, // Write-only + _ => unreachable!(), + } + } + #[allow(cyclomatic_complexity)] // TODO: Reduce branching! fn step(&mut self) -> Interrupt { let frame_cycle = self.cycles % CYCLES_PER_FRAME; @@ -469,69 +534,8 @@ impl Ppu for PpuBase { } } - /// Accepts a PPU memory mapped address and writes it to the appropriate register - fn write(&mut self, addr: u16, val: u8) { - debug_assert!( - addr >= 0x2000 && addr < 0x4000, - "Invalid memory mapped ppu address" - ); - - match addr & 7 { - 0x0 => { - self.control.write(val); - self.vram.control_write(val); - } - 0x1 => self.mask.write(val), - 0x2 => (), // readonly - 0x3 => self.sprite_renderer.write_address(val), - 0x4 => self.sprite_renderer.write_data(val), - 0x5 => { - let latch_state = self.write_latch.write(val); - self.vram.scroll_write(latch_state); - } - 0x6 => { - let latch_state = self.write_latch.write(val); - self.vram.write_ppu_addr(latch_state); - } - 0x7 => { - let inc_amount = self.control.vram_addr_increment(); - self.vram.write_ppu_data(val, inc_amount) - } - _ => unreachable!(), - } - } - - /// Accepts a PPU memory mapped address and returns the value - fn read(&self, addr: u16) -> u8 { - debug_assert!( - addr >= 0x2000 && addr < 0x4000, - "Invalid memory mapped ppu address" - ); - - match addr & 7 { - 0x0 => *self.control, - 0x1 => *self.mask, - 0x2 => { - let status = self.status.read(); - self.status.clear_in_vblank(); - self.write_latch.clear(); - status - } - 0x4 => { - if self.status.in_vblank() || !self.mask.rendering_enabled() { - // No OAM addr increment during vblank or forced blank - self.sprite_renderer.read_data() - } else { - self.sprite_renderer.read_data_increment_addr() - } - } - 0x7 => { - let inc_amount = self.control.vram_addr_increment(); - self.vram.read_ppu_data(inc_amount) - } - 0x3 | 0x5 | 0x6 => 0, // Write-only - _ => unreachable!(), - } + fn screen(&self) -> &NesScreen { + &self.screen } /// Dump register memory @@ -549,8 +553,4 @@ impl Ppu for PpuBase { writer.write_all(®s).unwrap() } - - fn screen(&self) -> &NesScreen { - &self.screen - } } diff --git a/src/ppu/spec_tests.rs b/src/ppu/spec_tests.rs index eb77746..77a5f53 100644 --- a/src/ppu/spec_tests.rs +++ b/src/ppu/spec_tests.rs @@ -1,5 +1,5 @@ -use super::*; use super::status_register::StatusRegister; +use super::*; #[test] fn write() { @@ -387,12 +387,9 @@ fn odd_frame_cycle_skip() { let frame_number = ppu.cycles / super::CYCLES_PER_FRAME; let was_odd_frame = frame_number % 2 == 1; assert_eq!( - ppu.odd_frame, - was_odd_frame, + ppu.odd_frame, was_odd_frame, "frame_number = {} ({},{})", - frame_number, - x, - scanline + frame_number, x, scanline ); ppu.step(); @@ -431,7 +428,6 @@ fn odd_frame_cycle_skip() { mod mocks { - use ppu::PpuBase; use ppu::background_renderer::BackgroundRenderer; use ppu::control_register::{ControlRegister, IncrementAmount}; use ppu::mask_register::MaskRegister; @@ -440,6 +436,7 @@ mod mocks { use ppu::status_register::StatusRegister; use ppu::vram::Vram; use ppu::write_latch::{LatchState, WriteLatch}; + use ppu::PpuBase; use rom::NesRom; use screen::NesScreen; use std::cell::Cell; diff --git a/src/ppu/sprite_renderer/mod.rs b/src/ppu/sprite_renderer/mod.rs index da58939..3ae9c02 100644 --- a/src/ppu/sprite_renderer/mod.rs +++ b/src/ppu/sprite_renderer/mod.rs @@ -8,11 +8,11 @@ mod sprite_evaluation; #[cfg(test)] mod spec_tests; -use ppu::SpriteSize; use ppu::control_register::ControlRegister; use ppu::palette::{self, Color, PALETTE}; use ppu::sprite_renderer::sprite_evaluation::SpriteEvaluation; use ppu::vram::Vram; +use ppu::SpriteSize; use std::cell::Cell; use std::num::Wrapping; diff --git a/src/rom/mod.rs b/src/rom/mod.rs index 367ddf6..d93901d 100644 --- a/src/rom/mod.rs +++ b/src/rom/mod.rs @@ -214,7 +214,10 @@ impl NesRom { // FIXME: Logic for determining Nes20 format is most certainly wrong. if bytes[7] & 0x0c == 0x08 && bytes[9] as usize <= bytes_read { RomFormat::Nes20 - } else if bytes[7] & 0x0c == 0x00 && bytes[12] == 0 && bytes[13] == 0 && bytes[14] == 0 + } else if bytes[7] & 0x0c == 0x00 + && bytes[12] == 0 + && bytes[13] == 0 + && bytes[14] == 0 && bytes[15] == 0 { RomFormat::INes diff --git a/src/screen/mod.rs b/src/screen/mod.rs index f19824a..bc7ee68 100644 --- a/src/screen/mod.rs +++ b/src/screen/mod.rs @@ -4,9 +4,9 @@ pub use self::nes_screen::NesScreen; #[cfg(feature = "debugger")] use png; #[cfg(feature = "debugger")] -use serde::{Serialize, Serializer}; -#[cfg(feature = "debugger")] use serde::ser::SerializeStruct; +#[cfg(feature = "debugger")] +use serde::{Serialize, Serializer}; pub trait Screen: Default + Clone + Send + 'static { fn put_pixel(&mut self, _: usize, _: usize, _: Color) {} diff --git a/src/screen/nes_screen/mod.rs b/src/screen/nes_screen/mod.rs index 78717f3..4c6c518 100644 --- a/src/screen/nes_screen/mod.rs +++ b/src/screen/nes_screen/mod.rs @@ -4,9 +4,9 @@ use base64; #[cfg(feature = "debugger")] use png::HasParameters; #[cfg(feature = "debugger")] -use serde::{Serialize, Serializer}; -#[cfg(feature = "debugger")] use serde::ser::SerializeStruct; +#[cfg(feature = "debugger")] +use serde::{Serialize, Serializer}; const SCREEN_WIDTH: usize = 256; const SCREEN_HEIGHT: usize = 240;