diff options
Diffstat (limited to 'src/main.rs')
-rw-r--r-- | src/main.rs | 282 |
1 files changed, 0 insertions, 282 deletions
diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index 6a350ff..0000000 --- a/src/main.rs +++ /dev/null @@ -1,282 +0,0 @@ -extern crate core; -mod memory; -mod mos6502; -mod ppu; -mod cartridge; -mod mapper; -mod controller; - -use std::fs::File; -use std::io::Read; -use core::cell::RefCell; -use core::intrinsics::transmute; -use cartridge::*; -use controller::stdctl::{Joystick, Button}; -use std::time::{Instant, Duration}; -use std::thread::sleep; - -extern crate sdl2; - -use sdl2::pixels::Color; -use sdl2::rect::Rect; -use sdl2::pixels::PixelFormatEnum; -use sdl2::event::Event; -use sdl2::keyboard::Keycode; - -const PIXEL_SIZE: u32 = 2; -const RGB_COLORS: [u32; 64] = [ - 0x666666, 0x002a88, 0x1412a7, 0x3b00a4, 0x5c007e, 0x6e0040, 0x6c0600, 0x561d00, - 0x333500, 0x0b4800, 0x005200, 0x004f08, 0x00404d, 0x000000, 0x000000, 0x000000, - 0xadadad, 0x155fd9, 0x4240ff, 0x7527fe, 0xa01acc, 0xb71e7b, 0xb53120, 0x994e00, - 0x6b6d00, 0x388700, 0x0c9300, 0x008f32, 0x007c8d, 0x000000, 0x000000, 0x000000, - 0xfffeff, 0x64b0ff, 0x9290ff, 0xc676ff, 0xf36aff, 0xfe6ecc, 0xfe8170, 0xea9e22, - 0xbcbe00, 0x88d800, 0x5ce430, 0x45e082, 0x48cdde, 0x4f4f4f, 0x000000, 0x000000, - 0xfffeff, 0xc0dfff, 0xd3d2ff, 0xe8c8ff, 0xfbc2ff, 0xfec4ea, 0xfeccc5, 0xf7d8a5, - 0xe4e594, 0xcfef96, 0xbdf4ab, 0xb3f3cc, 0xb5ebf2, 0xb8b8b8, 0x000000, 0x000000, -]; - -const PIX_WIDTH: usize = 256; -const PIX_HEIGHT: usize = 240; -const FB_PITCH: usize = PIX_WIDTH * 3 * (PIXEL_SIZE as usize); -const FB_SIZE: usize = PIX_HEIGHT * FB_PITCH * (PIXEL_SIZE as usize); -const WIN_WIDTH: u32 = PIX_WIDTH as u32 * PIXEL_SIZE; -const WIN_HEIGHT: u32 = PIX_HEIGHT as u32 * PIXEL_SIZE; - -struct SDLWindow<'a> { - canvas: sdl2::render::WindowCanvas, - events: sdl2::EventPump, - frame_buffer: [u8; FB_SIZE], - texture: sdl2::render::Texture, - timer: Instant, - duration_per_frame: Duration, - p1_button_states: [bool; 8], - p1_ctl: &'a Joystick, - p1_keymap: [Button; 256], -} - -macro_rules! gen_keymap { - ($tab: ident, [$($x: expr, $y: expr), *]) => { - { - $( - $tab[($x as usize) & 0xff] = $y; - )* - } - }; -} - -impl<'a> SDLWindow<'a> { - fn new(p1_ctl: &'a Joystick) -> Self { - use Keycode::*; - let sdl_context = sdl2::init().unwrap(); - let video_subsystem = sdl_context.video().unwrap(); - let window = video_subsystem.window("RuNES", WIN_WIDTH, WIN_HEIGHT) - .position_centered() - .opengl() - .build() - .unwrap(); - let mut canvas = window.into_canvas() - .accelerated() - .build().unwrap(); - let texture_creator = canvas.texture_creator(); - canvas.set_draw_color(Color::RGB(255, 255, 255)); - canvas.clear(); - canvas.present(); - let mut res = SDLWindow { - canvas, - events: sdl_context.event_pump().unwrap(), - frame_buffer: [0; FB_SIZE], - texture: texture_creator.create_texture_streaming( - PixelFormatEnum::RGB24, WIN_WIDTH, WIN_HEIGHT).unwrap(), - timer: Instant::now(), - duration_per_frame: Duration::from_millis(1000 / 60), - p1_button_states: [false; 8], - p1_ctl, p1_keymap: [Button::Null; 256] - }; - { - let keymap = &mut res.p1_keymap; - gen_keymap!(keymap, [I, Button::Up, - K, Button::Down, - J, Button::Left, - L, Button::Right, - Z, Button::A, - X, Button::B, - Return, Button::Start, - S, Button::Select, - Up, Button::Up, - Down, Button::Down, - Left, Button::Left, - Right, Button::Right - ]); - } - res - } - - #[inline] - fn poll(&mut self) -> bool { - use Keycode::*; - let p1_button_states = &mut self.p1_button_states; - let p1_keymap = &self.p1_keymap; - for event in self.events.poll_iter() { - match event { - Event::Quit {..} | Event::KeyDown { keycode: Some(Escape), .. } => { - return true; - }, - Event::KeyDown { keycode: Some(c), .. } => { - match p1_keymap[(c as usize) & 0xff] { - Button::Null => (), - i => { - p1_button_states[i as usize] = true; - self.p1_ctl.set(p1_button_states); - } - } - }, - Event::KeyUp { keycode: Some(c), .. } => { - match p1_keymap[(c as usize) & 0xff] { - Button::Null => (), - i => { - p1_button_states[i as usize] = false; - self.p1_ctl.set(p1_button_states); - } - } - }, - _ => () - } - } - false - } -} - -#[inline] -fn get_rgb(color: u8) -> (u8, u8, u8) { - let c = RGB_COLORS[color as usize]; - ((c >> 16) as u8, ((c >> 8) & 0xff) as u8, (c & 0xff) as u8) -} - -impl<'a> ppu::Screen for SDLWindow<'a> { - fn put(&mut self, x: u8, y: u8, color: u8) { - let (r, g, b) = get_rgb(color); - let mut base = ((y as u32 * PIXEL_SIZE) as usize * FB_PITCH) + - (x as u32 * 3 * PIXEL_SIZE) as usize; - for _ in 0..PIXEL_SIZE { - let slice = &mut self.frame_buffer[base..base + 3 * PIXEL_SIZE as usize]; - let mut j = 0; - for _ in 0..PIXEL_SIZE { - slice[j] = r; - slice[j + 1] = g; - slice[j + 2] = b; - j += 3; - } - base += FB_PITCH; - } - } - - fn render(&mut self) { - self.texture.update(None, &self.frame_buffer, FB_PITCH).unwrap(); - self.canvas.clear(); - self.canvas.copy(&self.texture, None, Some(Rect::new(0, 0, WIN_WIDTH, WIN_HEIGHT))).unwrap(); - self.canvas.present(); - if self.poll() {std::process::exit(0);} - let e = self.timer.elapsed(); - if self.duration_per_frame > e { - let diff = self.duration_per_frame - e; - sleep(diff); - //println!("{} faster", diff.subsec_nanos() as f64 / 1e6); - } else { - //println!("{} slower", (e - duration_per_frame).subsec_nanos() as f64 / 1e6); - } - self.timer = Instant::now(); - //canvas.set_draw_color(Color::RGB(128, 128, 128)); - } -} - -#[repr(C, packed)] -struct INesHeader { - magic: [u8; 4], - prg_rom_nbanks: u8, - chr_rom_nbanks: u8, - flags6: u8, - flags7: u8, - prg_ram_nbanks: u8, - flags9: u8, - flags10: u8, - padding: [u8; 5] -} - -fn main() { - let fname = std::env::args().nth(1).unwrap(); - let mut file = File::open(fname).unwrap(); - let mut rheader = [0; 16]; - println!("read {}", file.read(&mut rheader[..]).unwrap()); - let header = unsafe{transmute::<[u8; 16], INesHeader>(rheader)}; - let mirror = match ((header.flags6 >> 2) & 2) | (header.flags6 & 1) { - 0 => MirrorType::Horizontal, - 1 => MirrorType::Vertical, - 2 => MirrorType::Single0, - 3 => MirrorType::Single1, - _ => MirrorType::Four, - }; - let mapper_id = (header.flags7 & 0xf0) | (header.flags6 >> 4); - println!("maigc:{} prg:{} chr:{} mirror:{} mapper:{}", - std::str::from_utf8(&header.magic).unwrap(), - header.prg_rom_nbanks, - header.chr_rom_nbanks, - mirror as u8, - mapper_id); - if header.flags6 & 0x04 == 0x04 { - let mut trainer: [u8; 512] = unsafe{std::mem::uninitialized()}; - file.read(&mut trainer[..]).unwrap(); - println!("skipping trainer"); - } - - let prg_len = header.prg_rom_nbanks as usize * 0x4000; - let mut chr_len = header.chr_rom_nbanks as usize * 0x2000; - if chr_len == 0 { - chr_len = 0x2000; - } - let mut prg_rom = Vec::<u8>::with_capacity(prg_len); - let mut chr_rom = Vec::<u8>::with_capacity(chr_len); - unsafe { - prg_rom.set_len(prg_len); - chr_rom.set_len(chr_len); - } - let sram = vec![0; 0x4000]; - println!("read prg {}", file.read(&mut prg_rom[..]).unwrap()); - /* - for (i, v) in prg_rom.iter().enumerate() { - print!("{:02x} ", v); - if i & 15 == 15 { - println!(" {:04x}", i); - } - } - */ - println!("read chr {}", file.read(&mut chr_rom[..]).unwrap()); - /* - for (i, v) in chr_rom.iter().enumerate() { - print!("{:02x} ", v); - if i & 15 == 15 { - println!(""); - } - } - */ - let p1ctl = Joystick::new(); - let mut win = SDLWindow::new(&p1ctl); - let mut m = match mapper_id { - 0 | 2 => mapper::Mapper2::new(cartridge::Cartridge::new(chr_rom, prg_rom, sram, mirror)), - _ => panic!("unsupported mapper {}", mapper_id) - }; - let mt = m.get_cart().mirror_type; - let mapper = RefCell::new(&mut m as &mut memory::VMem); - let mut ppu = ppu::PPU::new(memory::PPUMemory::new(&mapper, mt), &mut win); - let mut cpu = mos6502::CPU::new(memory::CPUMemory::new(&mut ppu, &mapper, Some(&p1ctl), None)); - let ptr = &mut cpu as *mut mos6502::CPU; - cpu.mem.init(ptr); - loop { - cpu.step(); - while cpu.cycle > 0 { - if ppu.tick() || ppu.tick() || ppu.tick() { - cpu.trigger_delayed_nmi() - } - cpu.cycle -= 1; - } - } -} |