Split WASM and native versions, and move iced support code to native
This commit is contained in:
122
src/apu.rs
122
src/apu.rs
@@ -1,9 +1,5 @@
|
||||
use std::iter::repeat_n;
|
||||
|
||||
use iced::{
|
||||
Element, Font,
|
||||
widget::{column, text},
|
||||
};
|
||||
use tracing::debug;
|
||||
|
||||
macro_rules! lut {
|
||||
@@ -89,8 +85,10 @@ bitfield::bitfield! {
|
||||
struct PulseChannel {
|
||||
enabled: bool,
|
||||
duty_vol: DutyVol,
|
||||
|
||||
sweep: Sweep,
|
||||
sweep_reload: bool,
|
||||
sweep_counter: u8,
|
||||
|
||||
counter: LengthCounter,
|
||||
|
||||
@@ -102,15 +100,17 @@ struct PulseChannel {
|
||||
envelope_start: bool,
|
||||
envelope_counter: u8,
|
||||
envelope_divider: u8,
|
||||
extra: u16,
|
||||
}
|
||||
|
||||
impl PulseChannel {
|
||||
pub fn new() -> Self {
|
||||
pub fn new(extra: u16) -> Self {
|
||||
Self {
|
||||
enabled: false,
|
||||
duty_vol: DutyVol(0),
|
||||
sweep: Sweep(0),
|
||||
sweep_reload: false,
|
||||
sweep_counter: 0,
|
||||
counter: LengthCounter::new(),
|
||||
period: 0,
|
||||
period_timer: 0,
|
||||
@@ -119,6 +119,7 @@ impl PulseChannel {
|
||||
envelope_start: false,
|
||||
envelope_counter: 0,
|
||||
envelope_divider: 0,
|
||||
extra,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,7 +132,7 @@ impl PulseChannel {
|
||||
0x01 => {
|
||||
self.sweep.0 = val;
|
||||
self.sweep_reload = true;
|
||||
},
|
||||
}
|
||||
0x02 => self.period = self.period & 0x700 | (val as u16),
|
||||
0x03 => {
|
||||
let reg = LengthTimerHigh(val);
|
||||
@@ -143,7 +144,7 @@ impl PulseChannel {
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn volume(&self) -> u8 {
|
||||
if self.duty_vol.const_vol() {
|
||||
self.duty_vol.volume()
|
||||
@@ -151,7 +152,7 @@ impl PulseChannel {
|
||||
self.envelope_counter
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn clock(&mut self) {
|
||||
if !self.enabled {
|
||||
self.sample = 0;
|
||||
@@ -177,7 +178,7 @@ impl PulseChannel {
|
||||
// TODO
|
||||
}
|
||||
pub fn cur_sample(&self) -> u8 {
|
||||
if self.enabled && !self.counter.silenced() {
|
||||
if self.enabled && !self.counter.silenced() && !self.sweep_silenced() {
|
||||
self.sample
|
||||
} else {
|
||||
0
|
||||
@@ -205,30 +206,54 @@ impl PulseChannel {
|
||||
}
|
||||
}
|
||||
}
|
||||
fn target_period(&self) -> u16 {
|
||||
let amt = self.period >> self.sweep.shift();
|
||||
if self.sweep.negate() {
|
||||
self.period.saturating_sub(amt + self.extra)
|
||||
} else {
|
||||
self.period + amt
|
||||
}
|
||||
}
|
||||
fn sweep_silenced(&self) -> bool {
|
||||
self.period < 8 || self.target_period() > 0x7FF
|
||||
}
|
||||
pub fn h_frame_clock(&mut self) {
|
||||
self.q_frame_clock();
|
||||
if self.sweep.enable() {
|
||||
if self.sweep_reload {
|
||||
self.sweep_counter = self.sweep.period();
|
||||
self.sweep_reload = false;
|
||||
} else if self.sweep_counter == 0 {
|
||||
self.sweep_counter = self.sweep.period();
|
||||
if self.period < 8 || self.target_period() < 0x7FF {
|
||||
self.period = self.target_period();
|
||||
}
|
||||
} else {
|
||||
self.sweep_counter -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn view<T>(&self) -> Element<'_, T> {
|
||||
text!(
|
||||
pub fn view(&self) -> String {
|
||||
format!(
|
||||
"Square Channel
|
||||
Evelope Volume: {0:>3} ${0:02X}
|
||||
Evelope Volume: {0:>4} ${0:02X}
|
||||
Constant Volume: {1}
|
||||
Length Counter - Halted: {2}
|
||||
Duty: {3:>3} ${3:02X}
|
||||
Sweep - Shift: {4:>3} ${4:02X}
|
||||
Duty: {3:>4} ${3:02X}
|
||||
Sweep - Shift: {4:>4} ${4:02X}
|
||||
Sweep - Negate: {5}
|
||||
Sweep - Period: {6:>3} ${6:02X}
|
||||
Sweep - Period: {6:>4} ${6:02X}
|
||||
Sweep - Enabled: {7}
|
||||
Period: {8:>3} ${8:04X}
|
||||
Length Counter - Reload Value: {9:>3} ${9:04X}
|
||||
Period: {8:>4} ${8:04X}
|
||||
Length Counter - Reload Value: {9:>4} ${9:04X}
|
||||
Enabled: {10}
|
||||
Timer: {11:>3} ${11:04X}
|
||||
Duty Position: {12:>3} ${12:02X}
|
||||
Length Counter - Counter: {13:>3} ${13:02X}
|
||||
Envelope - Counter: {14:>3} ${14:02X}
|
||||
Envelope - Divider: {15:>3} ${15:02X}
|
||||
Output: {16:>3} ${16:02X}
|
||||
Timer: {11:>4} ${11:04X}
|
||||
Duty Position: {12:>4} ${12:02X}
|
||||
Length Counter - Counter: {13:>4} ${13:02X}
|
||||
Envelope - Counter: {14:>4} ${14:02X}
|
||||
Envelope - Divider: {15:>4} ${15:02X}
|
||||
Output: {16:>4} ${16:02X}
|
||||
",
|
||||
self.duty_vol.volume(),
|
||||
self.duty_vol.const_vol(),
|
||||
@@ -242,14 +267,12 @@ Output: {16:>3} ${16:02X}
|
||||
0,
|
||||
self.enabled,
|
||||
self.period_timer,
|
||||
self.cur, // ?
|
||||
self.cur, // ?
|
||||
self.counter.current,
|
||||
self.envelope_counter,
|
||||
self.envelope_divider,
|
||||
self.cur_sample(),
|
||||
)
|
||||
.font(Font::MONOSPACE)
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -344,8 +367,8 @@ impl TriangleChannel {
|
||||
self.q_frame_clock();
|
||||
}
|
||||
|
||||
pub fn view<T>(&self) -> Element<'_, T> {
|
||||
text!(
|
||||
pub fn view(&self) -> String {
|
||||
format!(
|
||||
"Triangle Channel
|
||||
Linear Counter - Reload: {0:>3} ${0:02X}
|
||||
Linear Counter - Halted: {1}
|
||||
@@ -372,8 +395,6 @@ Output: {10:>3} ${10:02X}
|
||||
self.reload,
|
||||
self.cur_sample(),
|
||||
)
|
||||
.font(Font::MONOSPACE)
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -465,8 +486,8 @@ impl NoiseChannel {
|
||||
self.q_frame_clock();
|
||||
}
|
||||
|
||||
pub fn view<T>(&self) -> Element<'_, T> {
|
||||
text!("").font(Font::MONOSPACE).into()
|
||||
pub fn view(&self) -> String {
|
||||
format!("")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -505,8 +526,8 @@ impl DeltaChannel {
|
||||
false
|
||||
}
|
||||
|
||||
pub fn view<T>(&self) -> Element<'_, T> {
|
||||
text!("").font(Font::MONOSPACE).into()
|
||||
pub fn view(&self) -> String {
|
||||
format!("")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -544,8 +565,8 @@ impl std::fmt::Debug for APU {
|
||||
impl APU {
|
||||
pub fn init() -> Self {
|
||||
Self {
|
||||
pulse_1: PulseChannel::new(),
|
||||
pulse_2: PulseChannel::new(),
|
||||
pulse_1: PulseChannel::new(1),
|
||||
pulse_2: PulseChannel::new(0),
|
||||
triangle: TriangleChannel::new(),
|
||||
noise: NoiseChannel::new(),
|
||||
dmc: DeltaChannel::new(),
|
||||
@@ -695,15 +716,26 @@ impl APU {
|
||||
pub fn irq_waiting(&mut self) -> bool {
|
||||
self.frame_counter.irq
|
||||
}
|
||||
}
|
||||
|
||||
pub fn view<'s, T: 's>(&'s self) -> Element<'s, T> {
|
||||
column![
|
||||
self.pulse_1.view(),
|
||||
self.pulse_2.view(),
|
||||
self.triangle.view(),
|
||||
self.noise.view(),
|
||||
self.dmc.view(),
|
||||
]
|
||||
.into()
|
||||
#[cfg(feature = "iced")]
|
||||
mod apu_iced {
|
||||
use super::*;
|
||||
use iced::{
|
||||
Element, Font,
|
||||
widget::{column, text},
|
||||
};
|
||||
|
||||
impl APU {
|
||||
pub fn view<'s, T: 's>(&'s self) -> Element<'s, T> {
|
||||
column![
|
||||
text(self.pulse_1.view()).font(Font::MONOSPACE),
|
||||
text(self.pulse_2.view()).font(Font::MONOSPACE),
|
||||
text(self.triangle.view()).font(Font::MONOSPACE),
|
||||
text(self.noise.view()).font(Font::MONOSPACE),
|
||||
text(self.dmc.view()).font(Font::MONOSPACE),
|
||||
]
|
||||
.into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user