From 3fac7315288e066b9c31b85d55ec7751159b958e Mon Sep 17 00:00:00 2001 From: Determinant Date: Sun, 26 Nov 2017 12:46:37 -0500 Subject: ... --- src/bin.rs | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----- src/lib.rs | 4 ++- src/memory.rs | 28 ++++++++++++++++++--- 3 files changed, 103 insertions(+), 10 deletions(-) diff --git a/src/bin.rs b/src/bin.rs index beb41d9..852c88b 100644 --- a/src/bin.rs +++ b/src/bin.rs @@ -14,6 +14,7 @@ use sdl2::rect::Rect; use sdl2::pixels::PixelFormatEnum; use sdl2::event::Event; use sdl2::keyboard::Keycode; +use sdl2::audio::{AudioSpecDesired}; mod memory; #[macro_use] mod mos6502; @@ -26,7 +27,8 @@ mod disasm; use mos6502::CPU; use ppu::PPU; -use memory::{CPUMemory, PPUMemory}; +use apu::APU; +use memory::{CPUMemory, PPUMemory, VMem}; use cartridge::{BankType, MirrorType, Cartridge}; use controller::stdctl; @@ -107,9 +109,8 @@ macro_rules! gen_keymap { } impl<'a> SDLWindow<'a> { - fn new(p1_ctl: &'a stdctl::Joystick) -> Self { + fn new(sdl_context: &'a sdl2::Sdl, p1_ctl: &'a stdctl::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() @@ -183,6 +184,7 @@ fn get_rgb(color: u8) -> (u8, u8, u8) { ((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); @@ -218,13 +220,77 @@ impl<'a> ppu::Screen for SDLWindow<'a> { sleep(diff); //println!("{} faster", diff.subsec_nanos() as f64 / 1e6); } else { - //println!("{} slower", (e - duration_per_frame).subsec_nanos() as f64 / 1e6); + //println!("{} slower", (e - self.duration_per_frame).subsec_nanos() as f64 / 1e6); } self.timer = Instant::now(); //canvas.set_draw_color(Color::RGB(128, 128, 128)); } } +struct SDLAudio { + device: sdl2::audio::AudioQueue, + buffer: [i16; 1], + buffer_cnt: usize +} + +/* +fn gen_wave(bytes_to_write: i32) -> Vec { + // Generate a square wave + let tone_volume = 1_000i16; + let period = 48_000 / 256; + let sample_count = bytes_to_write; + let mut result = Vec::new(); + + for x in 0..sample_count { + result.push( + if (x / period) % 2 == 0 { + tone_volume + } + else { + -tone_volume + } + ); + } + result +} +*/ + +impl SDLAudio { + fn new(sdl_context: &sdl2::Sdl) -> Self { + let audio_subsystem = sdl_context.audio().unwrap(); + let desired_spec = AudioSpecDesired { + freq: Some(apu::AUDIO_SAMPLE_FREQ as i32), + channels: Some(1), + samples: Some(4096) + }; + let device = audio_subsystem.open_queue::(None, &desired_spec).unwrap(); + let t = SDLAudio { + device, buffer: [0; 1], buffer_cnt: 0 + }; + t.device.resume(); + t + } + + fn flush(&mut self) { + self.device.queue(&self.buffer[..self.buffer_cnt]); + self.buffer_cnt = 0; + } +} + +impl apu::Speaker for SDLAudio { + fn queue(&mut self, sample: u16) { + self.buffer[self.buffer_cnt] = sample.wrapping_sub(32768) as i16; + self.buffer_cnt += 1; + if self.buffer_cnt == self.buffer.len() { + self.flush() + } + } + + fn push(&mut self) { + self.flush(); + } +} + #[repr(C, packed)] struct INesHeader { magic: [u8; 4], @@ -294,9 +360,11 @@ fn main() { } } */ + let sdl_context = sdl2::init().unwrap(); let p1ctl = stdctl::Joystick::new(); let cart = SimpleCart::new(chr_rom, prg_rom, sram, mirror); - let mut win = SDLWindow::new(&p1ctl); + let mut win = SDLWindow::new(&sdl_context, &p1ctl); + let mut spkr = SDLAudio::new(&sdl_context); let mut m: Box = match mapper_id { 0 | 2 => Box::new(mapper::Mapper2::new(cart)), 1 => Box::new(mapper::Mapper1::new(cart)), @@ -305,8 +373,9 @@ fn main() { let mapper = RefCell::new(&mut (*m) as &mut mapper::Mapper); let mut cpu = CPU::new(CPUMemory::new(&mapper, Some(&p1ctl), None)); let mut ppu = PPU::new(PPUMemory::new(&mapper), &mut win); + let mut apu = APU::new(&mut spkr); let cpu_ptr = &mut cpu as *mut CPU; - cpu.mem.bus.attach(cpu_ptr, &mut ppu); + cpu.mem.bus.attach(cpu_ptr, &mut ppu, &mut apu); cpu.start(); loop { while cpu.cycle > 0 { diff --git a/src/lib.rs b/src/lib.rs index 266f8a6..6439124 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,9 @@ -#![no_std] +//#![no_std] +extern crate core; mod memory; #[macro_use] mod mos6502; mod ppu; +mod apu; mod cartridge; mod mapper; mod controller; diff --git a/src/memory.rs b/src/memory.rs index cfdf422..bea84fc 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -1,5 +1,6 @@ #![allow(dead_code)] use ppu::PPU; +use apu::APU; use mos6502::CPU; use cartridge::MirrorType; use mapper::Mapper; @@ -15,21 +16,27 @@ pub trait VMem { pub struct Bus<'a> { cpu: *mut CPU<'a>, ppu: *mut PPU<'a>, + apu: *mut APU<'a> } impl<'a> Bus<'a> { pub fn new() -> Self { Bus {ppu: null_mut(), - cpu: null_mut()} + cpu: null_mut(), + apu: null_mut()} } - pub fn attach(&mut self, cpu: *mut CPU<'a>, ppu: *mut PPU<'a>) { + pub fn attach(&mut self, cpu: *mut CPU<'a>, + ppu: *mut PPU<'a>, + apu: *mut APU<'a>) { self.ppu = ppu; self.cpu = cpu; + self.apu = apu; } #[inline(always)] fn get_cpu(&self) -> &'a mut CPU<'a> {unsafe{&mut *self.cpu}} #[inline(always)] fn get_ppu(&self) -> &'a mut PPU<'a> {unsafe{&mut *self.ppu}} + #[inline(always)] fn get_apu(&self) -> &'a mut APU<'a> {unsafe{&mut *self.apu}} } pub struct CPUMemory<'a> { @@ -53,8 +60,12 @@ impl<'a> CPUMemory<'a> { pub fn ppu_tick(&self) { let cpu = self.bus.get_cpu(); let ppu = self.bus.get_ppu(); + let apu = self.bus.get_apu(); if ppu.tick() || ppu.tick() || ppu.tick() { - cpu.trigger_nmi(); + cpu.trigger_nmi() + } + if apu.tick() { + cpu.trigger_irq() } cpu.cycle -= 1; } @@ -112,7 +123,18 @@ impl<'a> VMem for CPUMemory<'a> { _ => panic!("invalid ppu reg write access at 0x{:04x}", addr) } } else if addr < 0x4020 { + let apu = self.bus.get_apu(); match addr { + 0x4000 => apu.pulse1.write_reg1(data), + 0x4001 => apu.pulse1.write_reg2(data), + 0x4002 => apu.pulse1.write_reg3(data), + 0x4003 => apu.pulse1.write_reg4(data), + 0x4004 => apu.pulse2.write_reg1(data), + 0x4005 => apu.pulse2.write_reg2(data), + 0x4006 => apu.pulse2.write_reg3(data), + 0x4007 => apu.pulse2.write_reg4(data), + 0x4015 => apu.write_status(data), + 0x4017 => apu.write_frame_counter(data), 0x4014 => ppu.write_oamdma(data, cpu), 0x4016 => { if let Some(c) = self.ctl1 { c.write(data) } -- cgit v1.2.3-70-g09d2