aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/apu.rs263
-rw-r--r--src/bin.rs61
-rw-r--r--src/memory.rs61
-rw-r--r--src/mos6502.rs8
-rw-r--r--src/ppu.rs1
5 files changed, 192 insertions, 202 deletions
diff --git a/src/apu.rs b/src/apu.rs
index 3ca81aa..3ad780c 100644
--- a/src/apu.rs
+++ b/src/apu.rs
@@ -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
- }
}
diff --git a/src/bin.rs b/src/bin.rs
index faf6962..b10f21c 100644
--- a/src/bin.rs
+++ b/src/bin.rs
@@ -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;
}
diff --git a/src/ppu.rs b/src/ppu.rs
index faf0664..945100a 100644
--- a/src/ppu.rs
+++ b/src/ppu.rs
@@ -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);
}