diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/apu.rs | 263 | ||||
-rw-r--r-- | src/bin.rs | 61 | ||||
-rw-r--r-- | src/memory.rs | 61 | ||||
-rw-r--r-- | src/mos6502.rs | 8 | ||||
-rw-r--r-- | src/ppu.rs | 1 |
5 files changed, 192 insertions, 202 deletions
@@ -149,6 +149,52 @@ pub struct Pulse { } impl Pulse { + pub fn new(comple: bool) -> Self { + Pulse {env_period: 0, env_lvl: 0, decay_lvl: 0, + env_start: false, env_loop: false, env_const: false, env_vol: 0, + swp_count: 0, swp_period: 0, swp_lvl: 0, + swp_en: false, swp_neg: false, swp_rld: false, muted: false, + len_lvl: 0, timer_period: 0, timer_lvl: 0, + seq_wave: 0, seq_cnt: 0, enabled: false, comple} + } + + pub fn write_reg1(&mut self, data: u8) { + self.seq_wave = DUTY_TABLE[(data >> 6) as usize]; + self.env_loop = data & 0x20 == 0x20; + self.env_const = data & 0x10 == 0x10; + self.env_period = data & 0xf; + self.env_vol = data & 0xf; + } + + pub fn write_reg2(&mut self, data: u8) { + self.swp_en = (data >> 7) == 1; + self.swp_period = (data >> 4) & 7; + self.swp_neg = data & 0x8 == 0x8; + self.swp_count = data & 7; + self.swp_rld = true; + } + + pub fn write_reg3(&mut self, data: u8) { + let p = (self.timer_period & 0xff00) | data as u16; + self.set_timer_period(p); + } + + pub fn write_reg4(&mut self, data: u8) { + self.set_len(data >> 3); + let p = (self.timer_period & 0x00ff) | ((data as u16 & 7) << 8); + self.set_timer_period(p); + self.seq_cnt = 0; + self.env_start = true; + } + + pub fn output(&self) -> u8 { + let env = if self.env_const { self.env_vol } else { self.decay_lvl }; + let swp = !self.muted; + let seq = (self.seq_wave >> self.seq_cnt) & 1 == 1; + let len = self.len_lvl > 0; + if self.enabled && swp && seq && len { env } else { 0 } + } + fn tick_env(&mut self) { if !self.env_start { if self.env_lvl == 0 { @@ -196,13 +242,6 @@ impl Pulse { } } - fn disable(&mut self) { - self.len_lvl = 0; - self.enabled = false; - } - - fn enable(&mut self) { self.enabled = true } - fn tick_length(&mut self) { if self.len_lvl > 0 && !self.env_loop { self.len_lvl -= 1 @@ -222,69 +261,28 @@ impl Pulse { } } - fn get_len(&self) -> u8 { self.len_lvl } - fn set_duty(&mut self, b: u8) { self.seq_wave = DUTY_TABLE[b as usize] } - fn set_loop(&mut self, b: bool) { self.env_loop = b } - fn set_const(&mut self, b: bool) { self.env_const = b } - fn set_env_period(&mut self, p: u8) { self.env_period = p } /* 4 bits */ - fn set_env_vol(&mut self, p: u8) { self.env_vol = p } - fn set_sweep(&mut self, d: u8) { - self.swp_en = (d >> 7) == 1; - self.swp_period = (d >> 4) & 7; - self.swp_neg = d & 0x8 == 0x8; - self.swp_count = d & 7; - self.swp_rld = true; + #[inline(always)] + fn disable(&mut self) { + self.len_lvl = 0; + self.enabled = false; } - fn set_timer_period(&mut self, p: u16) { - self.muted = p < 8; - self.timer_period = p; - } + #[inline(always)] + fn enable(&mut self) { self.enabled = true } + + #[inline(always)] fn get_len(&self) -> u8 { self.len_lvl } + #[inline(always)] fn set_len(&mut self, d: u8) { if self.enabled { self.len_lvl = LEN_TABLE[d as usize] } } - pub fn write_reg1(&mut self, data: u8) { - self.set_duty(data >> 6); - self.set_loop(data & 0x20 == 0x20); - self.set_const(data & 0x10 == 0x10); - self.set_env_period(data & 0xf); - self.set_env_vol(data & 0xf); - } - - pub fn write_reg2(&mut self, data: u8) { self.set_sweep(data) } - - pub fn write_reg3(&mut self, data: u8) { - let p = (self.timer_period & 0xff00) | data as u16; - self.set_timer_period(p); - } - - pub fn write_reg4(&mut self, data: u8) { - self.set_len(data >> 3); - let p = (self.timer_period & 0x00ff) | ((data as u16 & 7) << 8); - self.set_timer_period(p); - self.seq_cnt = 0; - self.env_start = true; - } - - pub fn output(&self) -> u8 { - let env = if self.env_const { self.env_vol } else { self.decay_lvl }; - let swp = !self.muted; - let seq = (self.seq_wave >> self.seq_cnt) & 1 == 1; - let len = self.len_lvl > 0; - if swp && seq && len { env } else { 0 } - } - - pub fn new(comple: bool) -> Self { - Pulse {env_period: 0, env_lvl: 0, decay_lvl: 0, - env_start: false, env_loop: false, env_const: false, env_vol: 0, - swp_count: 0, swp_period: 0, swp_lvl: 0, - swp_en: false, swp_neg: false, swp_rld: false, muted: false, - len_lvl: 0, timer_period: 0, timer_lvl: 0, - seq_wave: 0, seq_cnt: 0, enabled: false, comple} + #[inline(always)] + fn set_timer_period(&mut self, p: u16) { + self.muted = p < 8; + self.timer_period = p; } } @@ -306,6 +304,34 @@ pub struct Triangle { } impl Triangle { + fn new() -> Self { + Triangle { + cnt_rld: false, cnt_lvl: 0, cnt_rld_val: 0, + len_lvl: 0, timer_period: 0, timer_lvl: 0, + seq_cnt: 0, enabled: false, ctrl: false + } + } + + pub fn write_reg1(&mut self, data: u8) { + self.cnt_rld_val = data & 0x7f; + self.ctrl = data >> 7 == 1; + } + + pub fn write_reg3(&mut self, data: u8) { + self.timer_period = (self.timer_period & 0xff00) | data as u16; + } + + pub fn write_reg4(&mut self, data: u8) { + self.set_len(data >> 3); + self.timer_period = (self.timer_period & 0x00ff) | ((data as u16 & 7) << 8); + self.timer_lvl = self.timer_period; + self.cnt_rld = true; + } + + pub fn output(&self) -> u8 { + if self.enabled { TRI_SEQ_TABLE[self.seq_cnt as usize] } else { 0 } + } + fn tick_counter(&mut self) { if self.cnt_rld { self.cnt_lvl = self.cnt_rld_val @@ -339,48 +365,23 @@ impl Triangle { } } + #[inline(always)] fn disable(&mut self) { self.len_lvl = 0; self.enabled = false; } + #[inline(always)] fn enable(&mut self) { self.enabled = true } - fn new() -> Self { - Triangle { - cnt_rld: false, cnt_lvl: 0, cnt_rld_val: 0, - len_lvl: 0, timer_period: 0, timer_lvl: 0, - seq_cnt: 0, enabled: false, ctrl: false - } - } - - fn get_len(&self) -> u8 { self.len_lvl } - fn set_cnt_lvl(&mut self, d: u8) { self.cnt_lvl = d } - fn set_ctrl(&mut self, b: bool) { self.ctrl = b } - fn set_cnt_rld_val(&mut self, d: u8) { self.cnt_rld_val = d } + #[inline(always)] fn get_len(&self) -> u8 { self.len_lvl } + + #[inline(always)] fn set_len(&mut self, d: u8) { if self.enabled { self.len_lvl = LEN_TABLE[d as usize] } } - - pub fn write_reg1(&mut self, data: u8) { - self.set_cnt_rld_val(data & 0x7f); - self.set_ctrl(data >> 7 == 1); - } - - pub fn write_reg3(&mut self, data: u8) { - self.timer_period = (self.timer_period & 0xff00) | data as u16; - } - - pub fn write_reg4(&mut self, data: u8) { - self.set_len(data >> 3); - self.timer_period = (self.timer_period & 0x00ff) | ((data as u16 & 7) << 8); - self.timer_lvl = self.timer_period; - self.cnt_rld = true; - } - - fn output(&self) -> u8 { TRI_SEQ_TABLE[self.seq_cnt as usize] } } pub struct APU<'a> { @@ -398,20 +399,6 @@ pub struct APU<'a> { } impl<'a> APU<'a> { - fn tick_env(&mut self) { - self.pulse1.tick_env(); - self.pulse2.tick_env(); - self.triangle.tick_counter(); - } - - fn tick_len_swp(&mut self) { - self.pulse1.tick_length(); - self.pulse1.tick_sweep(); - self.pulse2.tick_length(); - self.pulse2.tick_sweep(); - self.triangle.tick_length(); - } - pub fn new(spkr: &'a mut Speaker) -> Self { APU { pulse1: Pulse::new(false), pulse2: Pulse::new(true), @@ -424,6 +411,26 @@ impl<'a> APU<'a> { } } + pub fn tick(&mut self) -> bool { + let mut irq = false; + if let (true, _) = self.cpu_sampler.tick() { + irq = self.tick_frame_counter(); + //print!("+"); + } + if let (true, sec) = self.audio_sampler.tick() { + let sample = self.output(); + self.spkr.queue(sample); + //print!("."); + if sec { + self.spkr.push(); + //println!("ok"); + } + } + self.tick_timer(); + self.cycle_even = !self.cycle_even; + irq + } + pub fn output(&self) -> u16 { let pulse_out = PULSE_TABLE[(self.pulse1.output() + self.pulse2.output()) as usize]; @@ -473,19 +480,33 @@ impl<'a> APU<'a> { self.triangle.tick_timer(); } + fn tick_env_cnt(&mut self) { + self.pulse1.tick_env(); + self.pulse2.tick_env(); + self.triangle.tick_counter(); + } + + fn tick_len_swp(&mut self) { + self.pulse1.tick_length(); + self.pulse1.tick_sweep(); + self.pulse2.tick_length(); + self.pulse2.tick_sweep(); + self.triangle.tick_length(); + } + fn tick_frame_counter(&mut self) -> bool { let f = self.frame_lvl; match self.frame_mode { false => { self.frame_lvl = if f == 3 { 0 } else { f + 1 }; match f { - 1 | 3 => self.tick_env(), + 1 | 3 => self.tick_env_cnt(), 2 => { - self.tick_env(); + self.tick_env_cnt(); self.tick_len_swp(); }, _ => { - self.tick_env(); + self.tick_env_cnt(); self.tick_len_swp(); if !self.frame_inh { self.frame_int = true; @@ -496,35 +517,15 @@ impl<'a> APU<'a> { true => { self.frame_lvl = if f == 4 { 0 } else { f + 1 }; match f { - 1 | 3 => self.tick_env(), + 1 | 3 => self.tick_env_cnt(), 0 | 2 => { - self.tick_env(); + self.tick_env_cnt(); self.tick_len_swp(); }, - _ => self.tick_env() + _ => self.tick_env_cnt() } } } self.frame_int } - - pub fn tick(&mut self) -> bool { - let mut irq = false; - if let (true, _) = self.cpu_sampler.tick() { - irq = self.tick_frame_counter(); - //print!("+"); - } - if let (true, sec) = self.audio_sampler.tick() { - let sample = self.output(); - self.spkr.queue(sample); - //print!("."); - if sec { - self.spkr.push(); - //println!("ok"); - } - } - self.tick_timer(); - self.cycle_even = !self.cycle_even; - irq - } } @@ -28,7 +28,7 @@ mod disasm; use mos6502::CPU; use ppu::PPU; use apu::APU; -use memory::{CPUMemory, PPUMemory, VMem}; +use memory::{CPUMemory, PPUMemory}; use cartridge::{BankType, MirrorType, Cartridge}; use controller::stdctl; @@ -231,28 +231,6 @@ struct SDLAudio<'a> { device: &'a sdl2::audio::AudioQueue<i16>, } -/* -fn gen_wave(bytes_to_write: i32) -> Vec<i16> { - // 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<'a> SDLAudio<'a> { fn new(device: &'a sdl2::audio::AudioQueue<i16>) -> Self { let t = SDLAudio { @@ -285,6 +263,21 @@ struct INesHeader { padding: [u8; 5] } +fn print_cpu_trace(cpu: &CPU) { + use disasm; + let pc = cpu.get_pc(); + let mem = cpu.get_mem(); + let opcode = mem.read_without_tick(pc) as usize; + let len = mos6502::INST_LENGTH[opcode]; + let mut code = vec![0; len as usize]; + for i in 0..len as u16 { + code[i as usize] = mem.read_without_tick(pc + i); + } + println!("0x{:04x} {} a:{:02x} x:{:02x} y:{:02x} s: {:02x} sp: {:02x}", + pc, disasm::parse(opcode as u8, &code[1..]), + cpu.get_a(), cpu.get_x(), cpu.get_y(), cpu.get_status(), cpu.get_sp()); +} + fn main() { let fname = std::env::args().nth(1).unwrap(); let mut file = File::open(fname).unwrap(); @@ -377,27 +370,13 @@ fn main() { let mut apu = APU::new(&mut spkr); let cpu_ptr = &mut cpu as *mut CPU; cpu.mem.bus.attach(cpu_ptr, &mut ppu, &mut apu); - cpu.start(); + cpu.powerup(); loop { + /* consume the leftover cycles from the last instruction */ while cpu.cycle > 0 { - cpu.mem.ppu_tick() - } - /* - { - use disasm; - let pc = cpu.get_pc(); - let mem = cpu.get_mem(); - let opcode = mem.read(pc) as usize; - let len = mos6502::INST_LENGTH[opcode]; - let mut code = vec![0; len as usize]; - for i in 0..len as u16 { - code[i as usize] = mem.read(pc + i); - } - println!("0x{:04x} {} a:{:02x} x:{:02x} y:{:02x} s: {:02x} sp: {:02x}", - pc, disasm::parse(opcode as u8, &code[1..]), - cpu.get_a(), cpu.get_x(), cpu.get_y(), cpu.get_status(), cpu.get_sp()); + cpu.mem.bus.tick() } - */ + //print_cpu_trace(&cpu); cpu.step(); } } diff --git a/src/memory.rs b/src/memory.rs index e57bdf4..ecafe86 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -13,17 +13,17 @@ pub trait VMem { fn write(&mut self, addr: u16, data: u8); } -pub struct Bus<'a> { +pub struct CPUBus<'a> { cpu: *mut CPU<'a>, ppu: *mut PPU<'a>, apu: *mut APU<'a> } -impl<'a> Bus<'a> { +impl<'a> CPUBus<'a> { pub fn new() -> Self { - Bus {ppu: null_mut(), - cpu: null_mut(), - apu: null_mut()} + CPUBus {ppu: null_mut(), + cpu: null_mut(), + apu: null_mut()} } pub fn attach(&mut self, cpu: *mut CPU<'a>, @@ -37,11 +37,24 @@ impl<'a> Bus<'a> { #[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 fn tick(&self) { + let cpu = self.get_cpu(); + let ppu = self.get_ppu(); + let apu = self.get_apu(); + if ppu.tick() || ppu.tick() || ppu.tick() { + cpu.trigger_nmi() + } + if apu.tick() { + cpu.trigger_irq() + } + cpu.tick(); + } } pub struct CPUMemory<'a> { sram: [u8; 2048], - pub bus: Bus<'a>, + pub bus: CPUBus<'a>, mapper: &'a RefCell<&'a mut Mapper>, ctl1: Option<&'a Controller>, ctl2: Option<&'a Controller> @@ -53,27 +66,15 @@ impl<'a> CPUMemory<'a> { ctl1: Option<&'a Controller>, ctl2: Option<&'a Controller>) -> Self { CPUMemory{sram: [0; 2048], - bus: Bus::new(), + bus: CPUBus::new(), mapper, ctl1, ctl2} } - 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() - } - if apu.tick() { - cpu.trigger_irq() - } - cpu.tick(); + pub fn get_bus(&'a self) -> &'a CPUBus<'a> { + &self.bus } -} -impl<'a> VMem for CPUMemory<'a> { - fn read(&self, addr: u16) -> u8 { - self.ppu_tick(); + pub fn read_without_tick(&self, addr: u16) -> u8 { let cpu = self.bus.get_cpu(); let ppu = self.bus.get_ppu(); if addr < 0x2000 { @@ -100,8 +101,7 @@ impl<'a> VMem for CPUMemory<'a> { } } - fn write(&mut self, addr: u16, data: u8) { - self.ppu_tick(); + pub fn write_without_tick(&mut self, addr: u16, data: u8) { let cpu = self.bus.get_cpu(); let ppu = self.bus.get_ppu(); if addr < 0x2000 { @@ -154,6 +154,18 @@ impl<'a> VMem for CPUMemory<'a> { } } +impl<'a> VMem for CPUMemory<'a> { + fn read(&self, addr: u16) -> u8 { + self.bus.tick(); + self.read_without_tick(addr) + } + + fn write(&mut self, addr: u16, data: u8) { + self.bus.tick(); + self.write_without_tick(addr, data); + } +} + pub struct PPUMemory<'a> { nametable: [u8; 0x800], palette: [u8; 0x20], @@ -251,5 +263,4 @@ impl<'a> VMem for PPUMemory<'a> { panic!("invalid ppu write access at 0x{:04x}", addr) } } - } diff --git a/src/mos6502.rs b/src/mos6502.rs index a9fac8c..122a549 100644 --- a/src/mos6502.rs +++ b/src/mos6502.rs @@ -511,7 +511,7 @@ mod ops { mod addr { use memory::VMem; - use mos6502::{CPU}; + use mos6502::CPU; make_addrtable!(ADDR_MODES, fn (&mut CPU) -> u8); fn acc(cpu: &mut CPU) -> u8 { @@ -630,7 +630,7 @@ impl<'a> CPU<'a> { #[inline(always)] pub fn get_y(&self) -> u8 { self.y } #[inline(always)] pub fn get_status(&self) -> u8 { self.status } #[inline(always)] pub fn get_sp(&self) -> u8 { self.sp } - #[inline(always)] pub fn get_mem(&self) -> &VMem{ &self.mem } + #[inline(always)] pub fn get_mem(&self) -> &CPUMemory<'a> { &self.mem } #[inline(always)] pub fn get_pc(&self) -> u16 { self.pc } #[inline(always)] pub fn get_carry(&self) -> u8 { (self.status >> 0) & 1 } @@ -657,7 +657,7 @@ impl<'a> CPU<'a> { mem, elapsed: 0, sec_callback} } - pub fn start(&mut self) { + pub fn powerup(&mut self) { self.cycle = 2; self.pc = read16!(self.mem, RESET_VECTOR as u16); } @@ -701,10 +701,10 @@ impl<'a> CPU<'a> { } pub fn reset(&mut self) { + self.cycle = 2; self.pc = read16!(self.mem, RESET_VECTOR as u16); self.sp = self.sp.wrapping_sub(3); self.status |= INT_FLAG; - self.cycle = 0; self.int = None; } @@ -4,7 +4,6 @@ use mos6502::CPU; use core::intrinsics::transmute; pub trait Screen { - #[inline(always)] fn put(&mut self, x: u8, y: u8, color: u8); fn render(&mut self); } |