#![allow(dead_code)]
use mos6502::{CPU_FREQ, CPU};
use memory::CPUBus;
pub trait Speaker {
fn queue(&mut self, sample: u16);
}
const CPU_SAMPLE_FREQ: u32 = 240;
pub const AUDIO_SAMPLE_FREQ: u32 = 44100;
const TRI_SEQ_TABLE: [u8; 32] = [
15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
];
const LEN_TABLE: [u8; 32] = [
10, 254, 20, 2, 40, 4, 80, 6, 160, 8, 60, 10, 14, 12, 26, 14,
12, 16, 24, 18, 48, 20, 96, 22, 192, 24, 72, 26, 16, 28, 32, 30,
];
const DUTY_TABLE: [u8; 4] = [
0b00000010,
0b00000110,
0b00011110,
0b11111001,
];
const PULSE_TABLE: [u16; 31] = [
0x0000, 0x02f8, 0x05df, 0x08b4, 0x0b78, 0x0e2b,
0x10cf, 0x1363, 0x15e9, 0x1860, 0x1ac9, 0x1d25,
0x1f75, 0x21b7, 0x23ee, 0x2618, 0x2837, 0x2a4c,
0x2c55, 0x2e54, 0x3049, 0x3234, 0x3416, 0x35ee,
0x37be, 0x3985, 0x3b43, 0x3cf9, 0x3ea7, 0x404d,
0x41ec
];
const NOISE_PERIOD_TABLE: [u16; 16] = [
4, 8, 16, 32, 64, 96, 128, 160, 202, 254, 380, 508, 762, 1016, 2034, 4068
];
const DMC_TABLE: [u16; 16] = [
214, 190, 170, 160, 143, 127, 113, 107, 95, 80, 71, 64, 53, 42, 36, 27,
];
const TND_TABLE: [u16; 203] = [
0x0000, 0x01b7, 0x036a, 0x051a, 0x06c6, 0x086f,
0x0a15, 0x0bb7, 0x0d56, 0x0ef2, 0x108a, 0x121f,
0x13b1, 0x1540, 0x16cc, 0x1855, 0x19da, 0x1b5d,
0x1cdd, 0x1e59, 0x1fd3, 0x214a, 0x22be, 0x2430,
0x259e, 0x270a, 0x2874, 0x29da, 0x2b3e, 0x2c9f,
0x2dfe, 0x2f5a, 0x30b4, 0x320b, 0x335f, 0x34b2,
0x3601, 0x374f, 0x389a, 0x39e2, 0x3b29, 0x3c6d,
0x3dae, 0x3eee, 0x402b, 0x4166, 0x429f, 0x43d6,
0x450a, 0x463d, 0x476d, 0x489c, 0x49c8, 0x4af2,
0x4c1b, 0x4d41, 0x4e65, 0x4f87, 0x50a8, 0x51c6,
0x52e3, 0x53fe, 0x5517, 0x562e, 0x5743, 0x5856,
0x5968, 0x5a78, 0x5b86, 0x5c93, 0x5d9d, 0x5ea6,
0x5fae, 0x60b3, 0x61b7, 0x62ba, 0x63bb, 0x64ba,
0x65b7, 0x66b3, 0x67ae, 0x68a7, 0x699e, 0x6a94,
0x6b88, 0x6c7b, 0x6d6d, 0x6e5d, 0x6f4b, 0x7038,
0x7124, 0x720e, 0x72f7, 0x73de, 0x74c4, 0x75a9,
0x768c, 0x776e, 0x784f, 0x792e, 0x7a0d, 0x7ae9,
0x7bc5, 0x7c9f, 0x7d78, 0x7e50, 0x7f26, 0x7ffc,
0x80d0, 0x81a3, 0x8274, 0x8345, 0x8414, 0x84e2,
0x85af, 0x867b, 0x8746, 0x880f, 0x88d8, 0x899f,
0x8a65, 0x8b2b, 0x8bef, 0x8cb2, 0x8d74, 0x8e35,
0x8ef4, 0x8fb3, 0x9071, 0x912e, 0x91ea, 0x92a4,
0x935e, 0x9417, 0x94cf, 0x9586, 0x963c, 0x96f0,
0x97a4, 0x9857, 0x990a, 0x99bb, 0x9a6b, 0x9b1a,
0x9bc9, 0x9c76, 0x9d23, 0x9dcf, 0x9e7a, 0x9f24,
0x9fcd, 0xa075, 0xa11c, 0xa1c3, 0xa269, 0xa30e,
0xa3b2, 0xa455, 0xa4f7, 0xa599, 0xa63a, 0xa6da,
0xa779, 0xa818, 0xa8b5, 0xa952, 0xa9ef, 0xaa8a,
0xab25, 0xabbe, 0xac58, 0xacf0, 0xad88, 0xae1f,
0xaeb5, 0xaf4a, 0xafdf, 0xb073, 0xb107, 0xb199,
0xb22b, 0xb2bd, 0xb34d, 0xb3dd, 0xb46c, 0xb4fb,
0xb589, 0xb616, 0xb6a3, 0xb72f, 0xb7ba, 0xb845,
0xb8cf, 0xb958, 0xb9e1, 0xba69, 0xbaf1, 0xbb78,
0xbbfe, 0xbc84, 0xbd09, 0xbd8d, 0xbe11
];
pub struct Sampler {
freq2: u32,
q0: u32,
r0: u32,
ddl: (u32, u32),
cnt: u32,
sec_cnt: u32
}
impl Sampler {
pub fn new(freq1: u32, freq2: u32) -> Self {
let q0 = freq1 / freq2;
let r0 = freq1 - q0 * freq2;
Sampler {
freq2,
q0,
r0,
ddl: (q0, r0),
cnt: 0,
sec_cnt: 0
}
}
pub fn tick(&mut self) -> (bool, bool) {
let (q, r) = self.ddl;
if self.cnt == q {
let nr = r + self.r0;
self.ddl = if nr > self.freq2 {
(self.q0, nr - self.freq2)
} else {
(self.q0 - 1, nr)
};
self.cnt = 0;
self.sec_cnt += 1;
let sec = self.sec_cnt == self.freq2;
if sec {
self.sec_cnt = 0
}
(true, sec)
} else {
self.cnt += 1;
(false, false)
}
}
}
pub struct Pulse {
/* envelope */
env_period: u8,
env_lvl: u8,
decay_lvl: u8,
env_start: bool,
env_loop: bool,
env_const: bool,
env_vol: u8,
/* sweep */
swp_count: u8,
swp_period: u8,
swp_lvl: u8,
swp_en: bool,
swp_neg: bool,
swp_rld: bool,
muted: bool,
/* length counter */
len_lvl: u8,
/* timer */
timer_period: u16,
timer_lvl: u16,
/* sequencer */
seq_wave: u8,
seq_cnt: u8,
/* channel */
enabled: bool,
comple: bool,
}
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 {
self.env_lvl = self.env_period;
if self.decay_lvl == 0 {
if self.env_loop {
self.decay_lvl = 0xf;
}
} else {
self.decay_lvl -= 1;
}
} else {
self.env_lvl -= 1;
}
} else {
self.decay_lvl = 0xf;
self.env_start = false;
self.env_lvl = self.env_period;
}
}
fn tick_sweep(&mut self) {
let mut reload = self.swp_rld;
if self.swp_lvl == 0 {
reload = true;
if self.swp_en {
let mut p: u16 = self.timer_period;
let mut delta = p >> self.swp_count;
if self.swp_neg {
delta = !delta;
if self.comple { delta += 1; } /* two's complement */
}
p = p.wrapping_add(delta);
self.muted = p < 8 || (p >> 11 != 0);
if !self.muted && self.swp_count != 0 {
self.timer_period = p;
}
}
} else {
self.swp_lvl -= 1;
}
if reload {
self.swp_lvl = self.swp_period;
self.swp_rld = false;
}
}
fn tick_length(&mut self) {
if self.len_lvl > 0 && !self.env_loop {
self.len_lvl -= 1
}
}
fn tick_timer(&mut self) {
if self.timer_lvl == 0 {
self.timer_lvl = self.timer_period;
if self.seq_cnt == 7 {
self.seq_cnt = 0
} else {
self.seq_cnt += 1
}
} else {
self.timer_lvl -= 1
}
}
#[inline(always)]
fn disable(&mut self) {
self.len_lvl = 0;
self.enabled = false;
}
#[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]
}
}
#[inline(always)]
fn set_timer_period(&mut self, p: u16) {
self.muted = p < 8;
self.timer_period = p;
}
}
pub struct Triangle {
/* linear counter */
cnt_rld: bool,
cnt_lvl: u8,
cnt_rld_val: u8,
/* length counter */
len_lvl: u8,
/* timer */
timer_period: u16,
timer_lvl: u16,
/* sequencer */
seq_cnt: u8,
enabled: bool,
/* misc */
ctrl: bool
}
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
} else if self.cnt_lvl > 0 {
self.cnt_lvl -= 1
}
if !self.ctrl {
self.cnt_rld = false
}
}
fn tick_length(&mut self) {
if self.len_lvl > 0 && !self.ctrl {
self.len_lvl -= 1
}
}
fn tick_timer(&mut self) {
if self.len_lvl > 0 && self.cnt_lvl > 0 {
if self.timer_lvl == 0 {
self.timer_lvl = self.timer_period;
if self.seq_cnt == 31 {
self.seq_cnt = 0
} else {
self.seq_cnt += 1
}
} else {
self.timer_lvl -= 1
}
}
}
#[inline(always)]
fn disable(&mut self) {
self.len_lvl = 0;
self.enabled = false;
}
#[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 struct Noise {
/* envelope */
env_period: u8,
env_lvl: u8,
decay_lvl: u8,
env_start: bool,
env_loop: bool,
env_const: bool,
env_vol: u8,
/* length counter */
len_lvl: u8,
/* timer */
timer_period: u16,
timer_lvl: u16,
/* rng */
shift_reg: u16,
loop_noise: bool,
/* channel */
enabled: bool,
}
impl Noise {
pub fn new() -> Self {
Noise {env_period: 0, env_lvl: 0, decay_lvl: 0,
env_start: false, env_loop: false, env_const: false, env_vol: 0,
len_lvl: 0, timer_period: 0, timer_lvl: 0,
shift_reg: 1, loop_noise: false,
enabled: false}
}
pub fn write_reg1(&mut self, data: u8) {
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_reg3(&mut self, data: u8) {
self.loop_noise = (data >> 7) == 1;
self.timer_period = NOISE_PERIOD_TABLE[data as usize & 0xf];
}
pub fn write_reg4(&mut self, data: u8) {
self.set_len(data >> 3);
self.env_start = true;
}
pub fn output(&self) -> u8 {
let env = if self.env_const { self.env_vol } else { self.decay_lvl };
let len = self.len_lvl > 0;
let shift = self.shift_reg & 1 == 0;
if self.enabled && shift && len { env } else { 0 }
}
fn tick_env(&mut self) {
if !self.env_start {
if self.env_lvl == 0 {
self.env_lvl = self.env_period;
if self.decay_lvl == 0 {
if self.env_loop {
self.decay_lvl = 0xf;
}
} else {
self.decay_lvl -= 1;
}
} else {
self.env_lvl -= 1;
}
} else {
self.decay_lvl = 0xf;
self.env_start = false;
self.env_lvl = self.env_period;
}
}
fn tick_length(&mut self) {
if self.len_lvl > 0 && !self.env_loop {
self.len_lvl -= 1
}
}
fn tick_timer(&mut self) {
if self.timer_lvl == 0 {
self.timer_lvl = self.timer_period;
/* shift register is clocked */
let bit = if self.loop_noise {6} else {1};
let feedback = (self.shift_reg & 1) ^ ((self.shift_reg >> bit) & 1);
self.shift_reg = (self.shift_reg >> 1) | (feedback << 14);
} else {
self.timer_lvl -= 1
}
}
#[inline(always)]
fn disable(&mut self) {
self.len_lvl = 0;
self.enabled = false;
}
#[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 struct DMC {
dmc_loop: bool,
dmc_cnt: u8,
irq_enabled: bool,
sample_addr: u16,
sample_len: u16,
shift_reg: u8,
cur_addr: u16,
rem_len: u16,
level: u8,
/* timer */
timer_lvl: u16,
timer_period: u16,
/* channel */
enabled: bool
}
impl DMC {
pub fn new() -> Self {
DMC {
dmc_loop: false, dmc_cnt: 8,
irq_enabled: false, sample_addr: 0, sample_len: 0,
shift_reg: 0, cur_addr: 0, rem_len: 0, level: 0,
timer_lvl: 0, timer_period: 0, enabled: false
}
}
pub fn write_reg1(&mut self, data: u8) {
self.irq_enabled = (data >> 7) == 1;
self.dmc_loop = data & 0x40 == 0x40;
self.timer_period = DMC_TABLE[(data & 0xf) as usize];
}
pub fn write_reg2(&mut self, data: u8) {
self.level = data & 0x7f
}
pub fn write_reg3(&mut self, data: u8) {
self.sample_addr = 0xc000 | ((data as u16) << 6)
}
pub fn write_reg4(&mut self, data: u8) {
self.sample_len = ((data as u16) << 4) | 0x1
}
fn restart(&mut self) {
self.cur_addr = self.sample_addr;
self.rem_len = self.sample_len;
}
fn try_refill(&mut self, cpu: &mut CPU) {
if self.rem_len > 0 && self.dmc_cnt == 0 {
cpu.cycle += 4;
self.shift_reg = cpu.mem.read_without_tick(self.cur_addr);
self.dmc_cnt = 8;
self.cur_addr = self.cur_addr.wrapping_add(1);
if self.cur_addr == 0x0 {
self.cur_addr = 0x8000
}
self.rem_len -= 1;
if self.rem_len == 0 {
if self.dmc_loop {
self.restart()
} else if self.irq_enabled {
cpu.trigger_irq()
}
}
}
}
fn shift(&mut self) {
if self.dmc_cnt == 0 { return }
if self.shift_reg & 1 == 1 {
if self.level < 126 {
self.level += 2
}
} else {
if self.level > 1 {
self.level -= 2
}
}
self.shift_reg >>= 1;
self.dmc_cnt -= 1;
}
fn tick_timer(&mut self, cpu: &mut CPU) {
if !self.enabled { return }
self.try_refill(cpu);
if self.timer_lvl == 0 {
self.timer_lvl = self.timer_period;
self.shift();
} else {
self.timer_lvl -= 1
}
}
#[inline(always)]
fn get_len(&self) -> u16 { self.rem_len }
#[inline(always)]
fn disable(&mut self) {
self.enabled = false;
self.rem_len = 0;
}
#[inline(always)]
fn enable(&mut self) {
self.enabled = true;
if self.rem_len == 0 {
self.restart()
}
}
#[inline(always)]
fn output(&self) -> u8 { self.level }
}
pub struct APU<'a> {
pub pulse1: Pulse,
pub pulse2: Pulse,
pub triangle: Triangle,
pub noise: Noise,
pub dmc: DMC,
frame_lvl: u8,
frame_mode: bool, /* true for 5-step mode */
frame_inh: bool,
frame_int: bool,
cpu_sampler: Sampler,
audio_sampler: Sampler,
cycle_even: bool,
spkr: &'a mut Speaker,
}
impl<'a> APU<'a> {
pub fn new(spkr: &'a mut Speaker/*, bus: &'a CPUBus<'a>*/) -> Self {
APU {
pulse1: Pulse::new(false), pulse2: Pulse::new(true),
triangle: Triangle::new(),
noise: Noise::new(),
dmc: DMC::new(),
frame_lvl: 0, frame_mode: false, frame_int: false, frame_inh: true,
cpu_sampler: Sampler::new(CPU_FREQ, CPU_SAMPLE_FREQ),
audio_sampler: Sampler::new(CPU_FREQ, AUDIO_SAMPLE_FREQ),
cycle_even: false,
spkr
}
}
pub fn tick(&mut self, bus: &CPUBus) -> bool {
let mut irq = false;
if let (true, _) = self.cpu_sampler.tick() {
irq = self.tick_frame_counter();
}
if let (true, _) = self.audio_sampler.tick() {
let sample = self.output();
self.spkr.queue(sample);
}
self.tick_timer(bus.get_cpu());
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];
let tnd_out = TND_TABLE[(self.triangle.output() * 3 +
self.noise.output() * 2 +
self.dmc.output()) as usize];
pulse_out + tnd_out
}
pub fn read_status(&mut self) -> u8 {
let res = if self.pulse1.get_len() > 0 { 1 } else { 0 } |
(if self.pulse2.get_len() > 0 { 1 } else { 0 }) << 1 |
(if self.triangle.get_len() > 0 { 1 } else { 0 }) << 2 |
(if self.noise.get_len() > 0 { 1 } else { 0 }) << 3 |
(if self.dmc.get_len() > 0 { 1 } else { 0 }) << 4 |
(if self.frame_int { 1 } else { 0 }) << 6;
if self.frame_lvl != 3 {
self.frame_int = false; /* clear interrupt flag */
}
res
}
pub fn write_status(&mut self, data: u8) {
match data & 0x1 {
0 => self.pulse1.disable(),
_ => self.pulse1.enable()
}
match data & 0x2 {
0 => self.pulse2.disable(),
_ => self.pulse2.enable()
}
match data & 0x4 {
0 => self.triangle.disable(),
_ => self.triangle.enable()
}
match data & 0x8 {
0 => self.noise.disable(),
_ => self.noise.enable()
}
match data & 0x10 {
0 => self.dmc.disable(),
_ => self.dmc.enable()
}
}
pub fn write_frame_counter(&mut self, data: u8) {
self.frame_inh = data & 0x40 == 0x40;
self.frame_mode = data >> 7 == 1;
if self.frame_mode {
self.tick_len_swp()
}
}
fn tick_timer(&mut self, cpu: &mut CPU) {
if self.cycle_even {
self.pulse1.tick_timer();
self.pulse2.tick_timer();
self.noise.tick_timer();
self.dmc.tick_timer(cpu);
}
self.triangle.tick_timer();
}
fn tick_env_cnt(&mut self) {
self.pulse1.tick_env();
self.pulse2.tick_env();
self.triangle.tick_counter();
self.noise.tick_env();
}
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();
self.noise.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_cnt(),
2 => {
self.tick_env_cnt();
self.tick_len_swp();
},
_ => {
self.tick_env_cnt();
self.tick_len_swp();
if !self.frame_inh {
self.frame_int = true;
}
},
};
},
true => {
self.frame_lvl = if f == 4 { 0 } else { f + 1 };
match f {
1 | 3 => self.tick_env_cnt(),
0 | 2 => {
self.tick_env_cnt();
self.tick_len_swp();
},
_ => self.tick_env_cnt()
}
}
}
self.frame_int
}
}