@tmustier/pi-nes 0.2.4 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +89 -1
- package/README.md +78 -49
- package/extensions/nes/native/nes-core/Cargo.lock +0 -2
- package/extensions/nes/native/nes-core/Cargo.toml +1 -1
- package/extensions/nes/native/nes-core/index.d.ts +5 -0
- package/extensions/nes/native/nes-core/index.node +0 -0
- package/extensions/nes/native/nes-core/native.d.ts +5 -0
- package/extensions/nes/native/nes-core/src/lib.rs +25 -0
- package/extensions/nes/native/nes-core/vendor/nes_rust/.cargo-ok +1 -0
- package/extensions/nes/native/nes-core/vendor/nes_rust/.cargo_vcs_info.json +5 -0
- package/extensions/nes/native/nes-core/vendor/nes_rust/.travis.yml +3 -0
- package/extensions/nes/native/nes-core/vendor/nes_rust/Cargo.toml +23 -0
- package/extensions/nes/native/nes-core/vendor/nes_rust/LICENSE +21 -0
- package/extensions/nes/native/nes-core/vendor/nes_rust/README.md +59 -0
- package/extensions/nes/native/nes-core/vendor/nes_rust/src/apu.rs +1114 -0
- package/extensions/nes/native/nes-core/vendor/nes_rust/src/audio.rs +6 -0
- package/extensions/nes/native/nes-core/vendor/nes_rust/src/button.rs +23 -0
- package/extensions/nes/native/nes-core/vendor/nes_rust/src/cpu.rs +2364 -0
- package/extensions/nes/native/nes-core/vendor/nes_rust/src/default_audio.rs +49 -0
- package/extensions/nes/native/nes-core/vendor/nes_rust/src/default_display.rs +47 -0
- package/extensions/nes/native/nes-core/vendor/nes_rust/src/default_input.rs +33 -0
- package/extensions/nes/native/nes-core/vendor/nes_rust/src/display.rs +10 -0
- package/extensions/nes/native/nes-core/vendor/nes_rust/src/input.rs +7 -0
- package/extensions/nes/native/nes-core/vendor/nes_rust/src/joypad.rs +86 -0
- package/extensions/nes/native/nes-core/vendor/nes_rust/src/lib.rs +168 -0
- package/extensions/nes/native/nes-core/vendor/nes_rust/src/mapper.rs +502 -0
- package/extensions/nes/native/nes-core/vendor/nes_rust/src/memory.rs +73 -0
- package/extensions/nes/native/nes-core/vendor/nes_rust/src/ppu.rs +1378 -0
- package/extensions/nes/native/nes-core/vendor/nes_rust/src/register.rs +560 -0
- package/extensions/nes/native/nes-core/vendor/nes_rust/src/rom.rs +231 -0
- package/extensions/nes/nes-core.ts +27 -4
- package/package.json +1 -1
|
@@ -0,0 +1,1114 @@
|
|
|
1
|
+
use register::Register;
|
|
2
|
+
use audio::Audio;
|
|
3
|
+
|
|
4
|
+
/*
|
|
5
|
+
* Audio Processing Unit implementation. Consists of
|
|
6
|
+
* - Pulse 1/2 channel
|
|
7
|
+
* - Triangle channel
|
|
8
|
+
* - Noise channel
|
|
9
|
+
* - DMC channel
|
|
10
|
+
* Refer to https://wiki.nesdev.com/w/index.php/APU
|
|
11
|
+
*/
|
|
12
|
+
pub struct Apu {
|
|
13
|
+
cycle: u32,
|
|
14
|
+
step: u16,
|
|
15
|
+
|
|
16
|
+
// CPU memory mapped sub units/registers
|
|
17
|
+
|
|
18
|
+
pulse1: ApuPulse, // 0x4000 - 0x4003
|
|
19
|
+
pulse2: ApuPulse, // 0x4004 - 0x4007
|
|
20
|
+
triangle: ApuTriangle, // 0x4008 - 0x400B
|
|
21
|
+
noise: ApuNoise, // 0x400C - 0x400F
|
|
22
|
+
dmc: ApuDmc, // 0x4010 - 0x4013
|
|
23
|
+
status: Register<u8>, // 0x4015
|
|
24
|
+
frame: ApuFrameRegister, // 0x4017
|
|
25
|
+
|
|
26
|
+
sample_period: u32,
|
|
27
|
+
frame_irq_active: bool,
|
|
28
|
+
dmc_irq_active: bool,
|
|
29
|
+
pub irq_interrupted: bool,
|
|
30
|
+
|
|
31
|
+
audio: Box<dyn Audio>
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
static LENGTH_TABLE: [u8; 32] = [
|
|
35
|
+
0x0A, 0xFE, 0x14, 0x02, 0x28, 0x04, 0x50, 0x06,
|
|
36
|
+
0xA0, 0x08, 0x3C, 0x0A, 0x0E, 0x0C, 0x1A, 0x0E,
|
|
37
|
+
0x0C, 0x10, 0x18, 0x12, 0x30, 0x14, 0x60, 0x16,
|
|
38
|
+
0xC0, 0x18, 0x48, 0x1A, 0x10, 0x1C, 0x20, 0x1E
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
impl Apu {
|
|
42
|
+
pub fn new(audio: Box<dyn Audio>) -> Self {
|
|
43
|
+
Apu {
|
|
44
|
+
cycle: 0,
|
|
45
|
+
step: 0,
|
|
46
|
+
pulse1: ApuPulse::new(ApuPulseChannel::Channel1),
|
|
47
|
+
pulse2: ApuPulse::new(ApuPulseChannel::Channel2),
|
|
48
|
+
triangle: ApuTriangle::new(),
|
|
49
|
+
noise: ApuNoise::new(),
|
|
50
|
+
dmc: ApuDmc::new(),
|
|
51
|
+
status: Register::<u8>::new(),
|
|
52
|
+
frame: ApuFrameRegister::new(),
|
|
53
|
+
sample_period: 1764000 / 44100, // @TODO: Fix me
|
|
54
|
+
frame_irq_active: false,
|
|
55
|
+
dmc_irq_active: false,
|
|
56
|
+
irq_interrupted: false,
|
|
57
|
+
audio: audio
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
pub fn bootup(&mut self) {
|
|
62
|
+
self.status.store(0x00);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
pub fn reset(&mut self) {
|
|
66
|
+
self.status.store(0x00);
|
|
67
|
+
// @TODO: Implement properly
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
pub fn get_mut_audio(&mut self) -> &mut Box<dyn Audio> {
|
|
71
|
+
&mut self.audio
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Expects being called at CPU clock rate
|
|
75
|
+
pub fn step(&mut self, dmc_sample_data: u8) {
|
|
76
|
+
self.cycle += 1;
|
|
77
|
+
|
|
78
|
+
// Samping at sample rate timing
|
|
79
|
+
// @TODO Fix me, more precise timing
|
|
80
|
+
|
|
81
|
+
if (self.cycle % self.sample_period) == 0 {
|
|
82
|
+
self.sample();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Timers
|
|
86
|
+
// Clocked on every CPU cycles for triangle and
|
|
87
|
+
// every two CPU cycles for others
|
|
88
|
+
|
|
89
|
+
if (self.cycle % 2) == 0 {
|
|
90
|
+
self.pulse1.drive_timer();
|
|
91
|
+
self.pulse2.drive_timer();
|
|
92
|
+
self.noise.drive_timer();
|
|
93
|
+
// @TODO: Add note
|
|
94
|
+
if self.dmc.drive_timer(dmc_sample_data) {
|
|
95
|
+
self.dmc_irq_active = true;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
self.triangle.drive_timer();
|
|
100
|
+
|
|
101
|
+
// 240Hz Frame sequencer
|
|
102
|
+
// @TODO: Fix me, more precise timing
|
|
103
|
+
|
|
104
|
+
if (self.cycle % 7457) == 0 {
|
|
105
|
+
if self.frame.five_step_mode() {
|
|
106
|
+
// Five-step sequence
|
|
107
|
+
//
|
|
108
|
+
// 0 1 2 3 4 function
|
|
109
|
+
// ----------- -----------------------------
|
|
110
|
+
// - - - - - IRQ (if bit 6 is clear)
|
|
111
|
+
// l - l - - Length counter and sweep
|
|
112
|
+
// e e e e - Envelope and linear counter
|
|
113
|
+
|
|
114
|
+
if self.step < 4 {
|
|
115
|
+
self.pulse1.drive_envelope();
|
|
116
|
+
self.pulse2.drive_envelope();
|
|
117
|
+
self.triangle.drive_linear();
|
|
118
|
+
self.noise.drive_envelope();
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if self.step == 0 || self.step == 2 {
|
|
122
|
+
self.pulse1.drive_length();
|
|
123
|
+
self.pulse1.drive_sweep();
|
|
124
|
+
self.pulse2.drive_length();
|
|
125
|
+
self.pulse2.drive_sweep();
|
|
126
|
+
self.triangle.drive_length();
|
|
127
|
+
self.noise.drive_length()
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
self.step = (self.step + 1) % 5;
|
|
131
|
+
} else {
|
|
132
|
+
// Four-step sequence
|
|
133
|
+
//
|
|
134
|
+
// 0 1 2 3 function
|
|
135
|
+
// --------- -----------------------------
|
|
136
|
+
// - - - f IRQ (if bit 6 is clear)
|
|
137
|
+
// - l - l Length counter and sweep
|
|
138
|
+
// e e e e Envelope and linear counter
|
|
139
|
+
|
|
140
|
+
self.pulse1.drive_envelope();
|
|
141
|
+
self.pulse2.drive_envelope();
|
|
142
|
+
self.triangle.drive_linear();
|
|
143
|
+
self.noise.drive_envelope();
|
|
144
|
+
|
|
145
|
+
if self.step == 1 || self.step == 3 {
|
|
146
|
+
self.pulse1.drive_length();
|
|
147
|
+
self.pulse1.drive_sweep();
|
|
148
|
+
self.pulse2.drive_length();
|
|
149
|
+
self.pulse2.drive_sweep();
|
|
150
|
+
self.triangle.drive_length();
|
|
151
|
+
self.noise.drive_length();
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if self.step == 3 && !self.frame.irq_disabled() {
|
|
155
|
+
self.frame_irq_active = true;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Seems like keep invoking IRQ once frame IRQ flag is on
|
|
159
|
+
// until IRQ flag is cleared or it's disabled...?
|
|
160
|
+
|
|
161
|
+
if self.frame_irq_active && !self.frame.irq_disabled() {
|
|
162
|
+
self.irq_interrupted = true;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
self.step = (self.step + 1) % 4;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// @TODO: check sending IRQ timing
|
|
169
|
+
if self.dmc_irq_active {
|
|
170
|
+
self.irq_interrupted = true;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
pub fn load_register(&mut self, address: u16) -> u8 {
|
|
176
|
+
match address {
|
|
177
|
+
0x4015 => {
|
|
178
|
+
// Loading status register
|
|
179
|
+
//
|
|
180
|
+
// bit
|
|
181
|
+
// 7: DMC interrupt
|
|
182
|
+
// 6: Frame interrupt
|
|
183
|
+
// 4: DMC remaining bytes > 0
|
|
184
|
+
// 3: Noise length counter > 0
|
|
185
|
+
// 2: Triangle length couter > 0
|
|
186
|
+
// 1: Pulse2 length counter > 0
|
|
187
|
+
// 0: Pulse1 length counter > 0
|
|
188
|
+
|
|
189
|
+
let mut value = 0;
|
|
190
|
+
|
|
191
|
+
if self.dmc_irq_active {
|
|
192
|
+
value |= 0x80;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if self.frame_irq_active && !self.frame.irq_disabled() {
|
|
196
|
+
value |= 0x40;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if self.dmc.remaining_bytes_counter > 0 {
|
|
200
|
+
value |= 0x10;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if self.noise.length_counter > 0 {
|
|
204
|
+
value |= 0x08;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if self.triangle.length_counter > 0 {
|
|
208
|
+
value |= 0x04;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if self.pulse2.length_counter > 0 {
|
|
212
|
+
value |= 0x02;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if self.pulse1.length_counter > 0 {
|
|
216
|
+
value |= 0x01;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Loading status register clears the frame IRQ flag
|
|
220
|
+
|
|
221
|
+
self.frame_irq_active = false;
|
|
222
|
+
|
|
223
|
+
value
|
|
224
|
+
},
|
|
225
|
+
_ => 0
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
pub fn store_register(&mut self, address: u16, value: u8) {
|
|
230
|
+
match address {
|
|
231
|
+
0x4000..=0x4003 => self.pulse1.store_register(address, value),
|
|
232
|
+
0x4004..=0x4007 => self.pulse2.store_register(address, value),
|
|
233
|
+
0x4008..=0x400B => self.triangle.store_register(address, value),
|
|
234
|
+
0x400C..=0x400F => self.noise.store_register(address, value),
|
|
235
|
+
0x4010..=0x4013 => self.dmc.store_register(address, value),
|
|
236
|
+
0x4015 => {
|
|
237
|
+
// Storing status register
|
|
238
|
+
//
|
|
239
|
+
// bit: Enable(1) / Disable(0)
|
|
240
|
+
// 4: DMC unit
|
|
241
|
+
// 3: Noise unit
|
|
242
|
+
// 2: Triangle unit
|
|
243
|
+
// 1: Pulse2 unit
|
|
244
|
+
// 0: Pulse1 unit
|
|
245
|
+
//
|
|
246
|
+
// Writing a zero to any of channel enables bits will
|
|
247
|
+
// set its length counter/remaining bytes to zero.
|
|
248
|
+
|
|
249
|
+
self.status.store(value);
|
|
250
|
+
|
|
251
|
+
self.dmc.set_enable((value & 0x10) == 0x10);
|
|
252
|
+
self.noise.set_enable((value & 0x8) == 0x8);
|
|
253
|
+
self.triangle.set_enable((value & 0x4) == 0x4);
|
|
254
|
+
self.pulse2.set_enable((value & 0x2) == 0x2);
|
|
255
|
+
self.pulse1.set_enable((value & 0x1) == 0x1);
|
|
256
|
+
|
|
257
|
+
// Storing status register clears the DMC interrupt flag
|
|
258
|
+
|
|
259
|
+
self.dmc_irq_active = false;
|
|
260
|
+
},
|
|
261
|
+
0x4017 => {
|
|
262
|
+
// Storing frame counter register
|
|
263
|
+
self.frame.store(value);
|
|
264
|
+
|
|
265
|
+
// If interrupt inhibit flag is set, the frame IRQ flag is cleared.
|
|
266
|
+
|
|
267
|
+
if self.frame.irq_disabled() {
|
|
268
|
+
self.frame_irq_active = false;
|
|
269
|
+
}
|
|
270
|
+
},
|
|
271
|
+
_ => {}
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// See cpu.step() for what the following two methods are for
|
|
276
|
+
// @TODO: A bit hacky. Simplify.
|
|
277
|
+
|
|
278
|
+
pub fn dmc_needs_cpu_memory_data(&self) -> bool {
|
|
279
|
+
(self.cycle % 2) == 1 && self.dmc.needs_cpu_memory_data()
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
pub fn dmc_sample_address(&self) -> u16 {
|
|
283
|
+
self.dmc.address_counter
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
fn sample(&mut self) {
|
|
287
|
+
// Calculates the audio output within the range of 0.0 to 1.0.
|
|
288
|
+
// Refer to https://wiki.nesdev.com/w/index.php/APU_Mixer
|
|
289
|
+
|
|
290
|
+
let pulse1 = self.pulse1.output() as f32;
|
|
291
|
+
let pulse2 = self.pulse2.output() as f32;
|
|
292
|
+
let triangle = self.triangle.output() as f32;
|
|
293
|
+
let noise = self.noise.output() as f32;
|
|
294
|
+
let dmc = self.dmc.output() as f32;
|
|
295
|
+
|
|
296
|
+
let mut pulse_out = 0.0;
|
|
297
|
+
let mut tnd_out = 0.0;
|
|
298
|
+
|
|
299
|
+
if pulse1 != 0.0 || pulse2 != 0.0 {
|
|
300
|
+
pulse_out = 95.88 / ((8128.0 / (pulse1 + pulse2)) + 100.0);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
if triangle != 0.0 || noise != 0.0 || dmc != 0.0 {
|
|
304
|
+
tnd_out = 159.79 / (1.0 / (triangle / 8227.0 + noise / 12241.0 + dmc / 22638.0) + 100.0);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
self.audio.push(pulse_out + tnd_out);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Apu Pulse channel. Consists of
|
|
313
|
+
* - Timer
|
|
314
|
+
* - Length counter
|
|
315
|
+
* - Envelope
|
|
316
|
+
* - Sweep
|
|
317
|
+
*/
|
|
318
|
+
struct ApuPulse {
|
|
319
|
+
channel: ApuPulseChannel,
|
|
320
|
+
register0: Register<u8>, // 0x4000, 0x4004
|
|
321
|
+
register1: Register<u8>, // 0x4001, 0x4005
|
|
322
|
+
register2: Register<u8>, // 0x4002, 0x4006
|
|
323
|
+
register3: Register<u8>, // 0x4003, 0x4007
|
|
324
|
+
enabled: bool,
|
|
325
|
+
|
|
326
|
+
timer_counter: u16,
|
|
327
|
+
timer_period: u16,
|
|
328
|
+
timer_sequence: u8,
|
|
329
|
+
|
|
330
|
+
envelope_start_flag: bool,
|
|
331
|
+
envelope_counter: u8,
|
|
332
|
+
envelope_decay_level_counter: u8,
|
|
333
|
+
|
|
334
|
+
length_counter: u8,
|
|
335
|
+
|
|
336
|
+
sweep_reload_flag: bool,
|
|
337
|
+
sweep_counter: u8
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
static DUTY_TABLE: [u8; 32] = [
|
|
341
|
+
0, 1, 0, 0, 0, 0, 0, 0,
|
|
342
|
+
0, 1, 1, 0, 0, 0, 0, 0,
|
|
343
|
+
0, 1, 1, 1, 1, 0, 0, 0,
|
|
344
|
+
1, 0, 0, 1, 1, 1, 1, 1
|
|
345
|
+
];
|
|
346
|
+
|
|
347
|
+
enum ApuPulseChannel {
|
|
348
|
+
Channel1,
|
|
349
|
+
Channel2
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
impl ApuPulse {
|
|
353
|
+
fn new(channel: ApuPulseChannel) -> Self {
|
|
354
|
+
ApuPulse {
|
|
355
|
+
channel: channel,
|
|
356
|
+
register0: Register::<u8>::new(),
|
|
357
|
+
register1: Register::<u8>::new(),
|
|
358
|
+
register2: Register::<u8>::new(),
|
|
359
|
+
register3: Register::<u8>::new(),
|
|
360
|
+
enabled: false,
|
|
361
|
+
timer_counter: 0,
|
|
362
|
+
timer_period: 0,
|
|
363
|
+
timer_sequence: 0,
|
|
364
|
+
envelope_start_flag: true,
|
|
365
|
+
envelope_counter: 0,
|
|
366
|
+
envelope_decay_level_counter: 0,
|
|
367
|
+
length_counter: 0,
|
|
368
|
+
sweep_reload_flag: false,
|
|
369
|
+
sweep_counter: 0
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
fn store_register(&mut self, address: u16, value: u8) {
|
|
374
|
+
match address & 0x4003 {
|
|
375
|
+
0x4000 => self.register0.store(value),
|
|
376
|
+
0x4001 => {
|
|
377
|
+
self.register1.store(value);
|
|
378
|
+
self.sweep_reload_flag = true;
|
|
379
|
+
},
|
|
380
|
+
0x4002 => {
|
|
381
|
+
self.register2.store(value);
|
|
382
|
+
self.timer_period = self.timer();
|
|
383
|
+
},
|
|
384
|
+
0x4003 => {
|
|
385
|
+
self.register3.store(value);
|
|
386
|
+
|
|
387
|
+
// Side effects
|
|
388
|
+
// - If the enabled flag is set, the length counter is reloaded
|
|
389
|
+
// - The envelope is restarted
|
|
390
|
+
// - The sequencer is immediately restarted at the first value of the current
|
|
391
|
+
// sequence. The period divider is not reset.
|
|
392
|
+
|
|
393
|
+
if self.enabled {
|
|
394
|
+
self.length_counter = LENGTH_TABLE[self.length_counter_index() as usize];
|
|
395
|
+
}
|
|
396
|
+
self.timer_period = self.timer();
|
|
397
|
+
self.timer_sequence = 0;
|
|
398
|
+
self.envelope_start_flag = true;
|
|
399
|
+
},
|
|
400
|
+
_ => {} // @TODO: Throw an error?
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
fn set_enable(&mut self, enabled: bool) {
|
|
405
|
+
self.enabled = enabled;
|
|
406
|
+
|
|
407
|
+
// When the enabled bit is cleared (via $4015), the length counter is forced to 0
|
|
408
|
+
|
|
409
|
+
if !enabled {
|
|
410
|
+
self.length_counter = 0;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
fn drive_timer(&mut self) {
|
|
415
|
+
if self.timer_counter > 0 {
|
|
416
|
+
self.timer_counter -= 1;
|
|
417
|
+
} else {
|
|
418
|
+
self.timer_counter = self.timer_period;
|
|
419
|
+
self.timer_sequence += 1;
|
|
420
|
+
|
|
421
|
+
// 8-step sequencer
|
|
422
|
+
if self.timer_sequence == 8 {
|
|
423
|
+
self.timer_sequence = 0
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
fn drive_length(&mut self) {
|
|
429
|
+
if !self.envelope_loop_enabled() && self.length_counter > 0 {
|
|
430
|
+
self.length_counter -= 1;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
fn drive_envelope(&mut self) {
|
|
435
|
+
if self.envelope_start_flag {
|
|
436
|
+
self.envelope_counter = self.envelope_period();
|
|
437
|
+
self.envelope_decay_level_counter = 0xF;
|
|
438
|
+
self.envelope_start_flag = false;
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
if self.envelope_counter > 0 {
|
|
443
|
+
self.envelope_counter -= 1;
|
|
444
|
+
} else {
|
|
445
|
+
self.envelope_counter = self.envelope_period();
|
|
446
|
+
if self.envelope_decay_level_counter > 0 {
|
|
447
|
+
self.envelope_decay_level_counter -= 1;
|
|
448
|
+
} else if self.envelope_decay_level_counter == 0 && self.envelope_loop_enabled() {
|
|
449
|
+
self.envelope_decay_level_counter = 0xF;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
fn drive_sweep(&mut self) {
|
|
455
|
+
if self.sweep_counter == 0 &&
|
|
456
|
+
self.sweep_enabled() &&
|
|
457
|
+
self.sweep_shift_amount() != 0 &&
|
|
458
|
+
self.timer_period >= 8 &&
|
|
459
|
+
self.timer_period <= 0x7FF {
|
|
460
|
+
|
|
461
|
+
let change = self.timer_period >> self.sweep_shift_amount();
|
|
462
|
+
|
|
463
|
+
// In negated mode, Pulse 1 adds the ones' complement while
|
|
464
|
+
// Pulse 2 adds the twos' complement
|
|
465
|
+
|
|
466
|
+
self.timer_period += match self.negated_sweep() {
|
|
467
|
+
// @TODO: Fix me
|
|
468
|
+
true => match self.channel {
|
|
469
|
+
ApuPulseChannel::Channel1 => !change,
|
|
470
|
+
ApuPulseChannel::Channel2 => !change + 1
|
|
471
|
+
},
|
|
472
|
+
false => change
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
if self.sweep_reload_flag || self.sweep_counter == 0 {
|
|
477
|
+
self.sweep_reload_flag = false;
|
|
478
|
+
self.sweep_counter = self.sweep_period();
|
|
479
|
+
} else {
|
|
480
|
+
self.sweep_counter -= 1;
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
fn output(&self) -> u8 {
|
|
485
|
+
if self.length_counter == 0 ||
|
|
486
|
+
self.timer_period < 8 ||
|
|
487
|
+
self.timer_period > 0x7FF ||
|
|
488
|
+
DUTY_TABLE[(self.duty() * 8 + self.timer_sequence) as usize] == 0 {
|
|
489
|
+
return 0;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// 4-bit output
|
|
493
|
+
0x0F & match self.envelope_disabled() {
|
|
494
|
+
true => self.envelope_period(),
|
|
495
|
+
false => self.envelope_decay_level_counter
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
fn duty(&self) -> u8 {
|
|
500
|
+
self.register0.load_bits(6, 2)
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
fn envelope_loop_enabled(&self) -> bool {
|
|
504
|
+
self.register0.is_bit_set(5)
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
fn envelope_disabled(&self) -> bool {
|
|
508
|
+
self.register0.is_bit_set(4)
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
fn envelope_period(&self) -> u8 {
|
|
512
|
+
self.register0.load_bits(0, 4)
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
fn sweep_enabled(&self) -> bool {
|
|
516
|
+
self.register1.is_bit_set(7)
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
fn sweep_period(&self) -> u8 {
|
|
520
|
+
self.register1.load_bits(4, 3)
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
fn negated_sweep(&self) -> bool {
|
|
524
|
+
self.register1.is_bit_set(3)
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
fn sweep_shift_amount(&self) -> u8 {
|
|
528
|
+
self.register1.load_bits(0, 3)
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
fn timer_low(&self) -> u8 {
|
|
532
|
+
self.register2.load()
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
fn timer_high(&self) -> u8 {
|
|
536
|
+
self.register3.load_bits(0, 3)
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
fn timer(&self) -> u16 {
|
|
540
|
+
((self.timer_high() as u16) << 8) | self.timer_low() as u16
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
fn length_counter_index(&self) -> u8 {
|
|
544
|
+
self.register3.load_bits(3, 5)
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
/*
|
|
549
|
+
* Apu Triangle channel. Consists of
|
|
550
|
+
* - Timer
|
|
551
|
+
* - Length counter
|
|
552
|
+
* - Linear counter
|
|
553
|
+
*/
|
|
554
|
+
struct ApuTriangle {
|
|
555
|
+
register0: Register<u8>, // 0x4008
|
|
556
|
+
register1: Register<u8>, // 0x4009
|
|
557
|
+
register2: Register<u8>, // 0x400A
|
|
558
|
+
register3: Register<u8>, // 0x400B
|
|
559
|
+
enabled: bool,
|
|
560
|
+
|
|
561
|
+
timer_counter: u16,
|
|
562
|
+
timer_sequence: u8,
|
|
563
|
+
|
|
564
|
+
length_counter: u8,
|
|
565
|
+
|
|
566
|
+
linear_reload_flag: bool,
|
|
567
|
+
linear_counter: u8
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
static SEQUENCE_TABLE: [u8; 32] = [
|
|
571
|
+
15, 14, 13, 12, 11, 10, 9, 8,
|
|
572
|
+
7, 6, 5, 4, 3, 2, 1, 0,
|
|
573
|
+
0, 1, 2, 3, 4, 5, 6, 7,
|
|
574
|
+
8, 9, 10, 11, 12, 13, 14, 15
|
|
575
|
+
];
|
|
576
|
+
|
|
577
|
+
impl ApuTriangle {
|
|
578
|
+
fn new() -> Self {
|
|
579
|
+
ApuTriangle {
|
|
580
|
+
register0: Register::<u8>::new(),
|
|
581
|
+
register1: Register::<u8>::new(),
|
|
582
|
+
register2: Register::<u8>::new(),
|
|
583
|
+
register3: Register::<u8>::new(),
|
|
584
|
+
enabled: false,
|
|
585
|
+
timer_counter: 0,
|
|
586
|
+
timer_sequence: 0,
|
|
587
|
+
length_counter: 0,
|
|
588
|
+
linear_reload_flag: false,
|
|
589
|
+
linear_counter: 0
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
fn store_register(&mut self, address: u16, value: u8) {
|
|
594
|
+
match address {
|
|
595
|
+
0x4008 => self.register0.store(value),
|
|
596
|
+
0x4009 => self.register1.store(value),
|
|
597
|
+
0x400A => self.register2.store(value),
|
|
598
|
+
0x400B => {
|
|
599
|
+
self.register3.store(value);
|
|
600
|
+
|
|
601
|
+
// Side effects
|
|
602
|
+
// - If the enabled flag is set, the length counter is reloaded
|
|
603
|
+
// - Sets the linear counter reload flag
|
|
604
|
+
// - The sequencer is immediately restarted at the first value of the current
|
|
605
|
+
// sequence. The period divider is not reset.
|
|
606
|
+
if self.enabled {
|
|
607
|
+
self.length_counter = LENGTH_TABLE[self.length_counter_index() as usize];
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
self.linear_reload_flag = true;
|
|
611
|
+
},
|
|
612
|
+
_ => {} // @TODO: Throw an error?
|
|
613
|
+
};
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
fn set_enable(&mut self, enabled: bool) {
|
|
617
|
+
self.enabled = enabled;
|
|
618
|
+
|
|
619
|
+
// When the enabled bit is cleared (via $4015), the length counter is forced to 0
|
|
620
|
+
|
|
621
|
+
if !enabled {
|
|
622
|
+
self.length_counter = 0;
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
fn drive_timer(&mut self) {
|
|
627
|
+
if self.timer_counter > 0 {
|
|
628
|
+
self.timer_counter -= 1;
|
|
629
|
+
} else {
|
|
630
|
+
self.timer_counter = self.timer();
|
|
631
|
+
|
|
632
|
+
// The sequencer is clocked by the timer as long as
|
|
633
|
+
// both the linear counter and the length counter are nonzero.
|
|
634
|
+
|
|
635
|
+
if self.length_counter > 0 && self.linear_counter > 0 {
|
|
636
|
+
self.timer_sequence += 1;
|
|
637
|
+
|
|
638
|
+
// 32-step sequencer
|
|
639
|
+
|
|
640
|
+
if self.timer_sequence == 32 {
|
|
641
|
+
self.timer_sequence = 0;
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
fn drive_linear(&mut self) {
|
|
648
|
+
if self.linear_reload_flag {
|
|
649
|
+
self.linear_counter = self.linear_counter();
|
|
650
|
+
} else if self.linear_counter > 0 {
|
|
651
|
+
self.linear_counter -= 1;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
if !self.length_counter_disabled() {
|
|
655
|
+
self.linear_reload_flag = false;
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
fn drive_length(&mut self) {
|
|
660
|
+
if !self.length_counter_disabled() && self.length_counter > 0 {
|
|
661
|
+
self.length_counter -= 1;
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
fn output(&self) -> u8 {
|
|
666
|
+
if !self.enabled ||
|
|
667
|
+
self.length_counter == 0 ||
|
|
668
|
+
self.linear_counter == 0 ||
|
|
669
|
+
self.timer() < 2 {
|
|
670
|
+
return 0;
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
// 4-bit output
|
|
674
|
+
return SEQUENCE_TABLE[self.timer_sequence as usize] & 0xF;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
fn linear_counter(&self) -> u8 {
|
|
678
|
+
self.register0.load_bits(0, 7)
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
fn length_counter_disabled(&self) -> bool {
|
|
682
|
+
self.register0.is_bit_set(7)
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
fn timer_low(&self) -> u8 {
|
|
686
|
+
self.register2.load()
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
fn length_counter_index(&self) -> u8 {
|
|
690
|
+
self.register3.load_bits(3, 5)
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
fn timer_high(&self) -> u8 {
|
|
694
|
+
self.register3.load_bits(0, 3)
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
fn timer(&self) -> u16 {
|
|
698
|
+
((self.timer_high() as u16) << 8) | self.timer_low() as u16
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
/*
|
|
703
|
+
* Apu Noise channel. Consists of
|
|
704
|
+
* - Timer
|
|
705
|
+
* - Length counter
|
|
706
|
+
* - Envelope
|
|
707
|
+
* - Linear feedback shift register
|
|
708
|
+
*/
|
|
709
|
+
struct ApuNoise {
|
|
710
|
+
register0: Register<u8>, // 0x400C
|
|
711
|
+
register1: Register<u8>, // 0x400D
|
|
712
|
+
register2: Register<u8>, // 0x400E
|
|
713
|
+
register3: Register<u8>, // 0x400F
|
|
714
|
+
|
|
715
|
+
enabled: bool,
|
|
716
|
+
|
|
717
|
+
timer_counter: u16,
|
|
718
|
+
timer_period: u16,
|
|
719
|
+
|
|
720
|
+
envelope_start_flag: bool,
|
|
721
|
+
envelope_counter: u8,
|
|
722
|
+
envelope_decay_level_counter: u8,
|
|
723
|
+
|
|
724
|
+
length_counter: u8,
|
|
725
|
+
|
|
726
|
+
shift_register: u16 // 15-bit register
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
static NOISE_TIMER_TABLE: [u16; 16] = [
|
|
730
|
+
0x004, 0x008, 0x010, 0x020,
|
|
731
|
+
0x040, 0x060, 0x080, 0x0A0,
|
|
732
|
+
0x0CA, 0x0FE, 0x17C, 0x1FC,
|
|
733
|
+
0x2FA, 0x3F8, 0x7F2, 0xFE4
|
|
734
|
+
];
|
|
735
|
+
|
|
736
|
+
impl ApuNoise {
|
|
737
|
+
fn new() -> Self {
|
|
738
|
+
ApuNoise {
|
|
739
|
+
register0: Register::<u8>::new(),
|
|
740
|
+
register1: Register::<u8>::new(),
|
|
741
|
+
register2: Register::<u8>::new(),
|
|
742
|
+
register3: Register::<u8>::new(),
|
|
743
|
+
enabled: false,
|
|
744
|
+
timer_counter: 0,
|
|
745
|
+
timer_period: 0,
|
|
746
|
+
envelope_start_flag: false,
|
|
747
|
+
envelope_counter: 0,
|
|
748
|
+
envelope_decay_level_counter: 0,
|
|
749
|
+
length_counter: 0,
|
|
750
|
+
shift_register: 1
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
fn store_register(&mut self, address: u16, value: u8) {
|
|
755
|
+
match address {
|
|
756
|
+
0x400C => self.register0.store(value),
|
|
757
|
+
0x400D => self.register1.store(value),
|
|
758
|
+
0x400E => {
|
|
759
|
+
self.register2.store(value);
|
|
760
|
+
self.timer_period = NOISE_TIMER_TABLE[self.timer_index() as usize];
|
|
761
|
+
},
|
|
762
|
+
0x400F => {
|
|
763
|
+
self.register3.store(value);
|
|
764
|
+
|
|
765
|
+
// Side effects
|
|
766
|
+
// - If the enabled flag is set, the length counter is reloaded
|
|
767
|
+
// - The envelope is restarted
|
|
768
|
+
|
|
769
|
+
if self.enabled {
|
|
770
|
+
self.length_counter = LENGTH_TABLE[self.length_counter_index() as usize];
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
self.envelope_start_flag = true;
|
|
774
|
+
},
|
|
775
|
+
_ => {} // @TODO: Throw an error?
|
|
776
|
+
};
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
fn set_enable(&mut self, enabled: bool) {
|
|
780
|
+
self.enabled = enabled;
|
|
781
|
+
|
|
782
|
+
// When the enabled bit is cleared (via $4015), the length counter is forced to 0
|
|
783
|
+
|
|
784
|
+
if !enabled {
|
|
785
|
+
self.length_counter = 0;
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
|
|
790
|
+
fn drive_timer(&mut self) {
|
|
791
|
+
if self.timer_counter > 0 {
|
|
792
|
+
self.timer_counter -= 1;
|
|
793
|
+
} else {
|
|
794
|
+
self.timer_counter = self.timer_period;
|
|
795
|
+
|
|
796
|
+
// Feedback is calculated as the exclusive-OR of bit 0
|
|
797
|
+
// and another bit: bit 6 if Mode flag is set, otherwise bit 1.
|
|
798
|
+
|
|
799
|
+
let feedback = (self.shift_register & 1) ^
|
|
800
|
+
(((self.shift_register >> match self.is_random() { true => 6, false => 1 })) & 1);
|
|
801
|
+
|
|
802
|
+
self.shift_register = ((feedback as u16) << 14) | (self.shift_register >> 1);
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
fn drive_envelope(&mut self) {
|
|
807
|
+
if self.envelope_start_flag {
|
|
808
|
+
self.envelope_counter = self.envelope_period();
|
|
809
|
+
self.envelope_decay_level_counter = 0xF;
|
|
810
|
+
self.envelope_start_flag = false;
|
|
811
|
+
return;
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
if self.envelope_counter > 0 {
|
|
815
|
+
self.envelope_counter -= 1;
|
|
816
|
+
} else {
|
|
817
|
+
self.envelope_counter = self.envelope_period();
|
|
818
|
+
|
|
819
|
+
if self.envelope_decay_level_counter > 0 {
|
|
820
|
+
self.envelope_decay_level_counter -= 1;
|
|
821
|
+
} else if self.envelope_decay_level_counter == 0 &&
|
|
822
|
+
self.length_counter_disabled() {
|
|
823
|
+
self.envelope_decay_level_counter = 0xF;
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
fn drive_length(&mut self) {
|
|
829
|
+
if !self.length_counter_disabled() && self.length_counter > 0 {
|
|
830
|
+
self.length_counter -= 1;
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
fn output(&self) -> u8 {
|
|
835
|
+
if self.length_counter == 0 ||
|
|
836
|
+
(self.shift_register & 1) == 1 {
|
|
837
|
+
return 0;
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
// 4-bit output
|
|
841
|
+
0x0F & match self.envelope_disabled() {
|
|
842
|
+
true => self.envelope_period(),
|
|
843
|
+
false => self.envelope_decay_level_counter
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
fn length_counter_disabled(&self) -> bool {
|
|
848
|
+
self.register0.is_bit_set(5)
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
fn envelope_disabled(&self) -> bool {
|
|
852
|
+
self.register0.is_bit_set(4)
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
fn envelope_period(&self) -> u8 {
|
|
856
|
+
self.register0.load_bits(0, 4)
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
fn is_random(&self) -> bool {
|
|
860
|
+
self.register2.is_bit_set(7)
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
fn timer_index(&self) -> u8 {
|
|
864
|
+
self.register2.load_bits(0, 4)
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
fn length_counter_index(&self) -> u8 {
|
|
868
|
+
self.register3.load_bits(3, 5)
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
/*
|
|
873
|
+
* Apu DMC channel. Consists of
|
|
874
|
+
* - Timer
|
|
875
|
+
* - Memory reader
|
|
876
|
+
* - Sample buffer
|
|
877
|
+
* - Output unit
|
|
878
|
+
*/
|
|
879
|
+
struct ApuDmc {
|
|
880
|
+
register0: Register<u8>, // 0x4010
|
|
881
|
+
register1: Register<u8>, // 0x4011
|
|
882
|
+
register2: Register<u8>, // 0x4012
|
|
883
|
+
register3: Register<u8>, // 0x4013
|
|
884
|
+
|
|
885
|
+
enabled: bool,
|
|
886
|
+
|
|
887
|
+
timer_period: u16,
|
|
888
|
+
timer_counter: u16,
|
|
889
|
+
|
|
890
|
+
delta_counter: u8,
|
|
891
|
+
address_counter: u16,
|
|
892
|
+
remaining_bytes_counter: u16,
|
|
893
|
+
|
|
894
|
+
sample_buffer: u8,
|
|
895
|
+
sample_buffer_is_empty: bool,
|
|
896
|
+
|
|
897
|
+
shift_register: u8,
|
|
898
|
+
remaining_bits_counter: u8,
|
|
899
|
+
|
|
900
|
+
silence_flag: bool
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
static DMC_TIMER_TABLE: [u16; 16] = [
|
|
904
|
+
0x1AC, 0x17C, 0x154, 0x140,
|
|
905
|
+
0x11E, 0x0FE, 0x0E2, 0x0D6,
|
|
906
|
+
0x0BE, 0x0A0, 0x08E, 0x080,
|
|
907
|
+
0x06A, 0x054, 0x048, 0x036
|
|
908
|
+
];
|
|
909
|
+
|
|
910
|
+
impl ApuDmc {
|
|
911
|
+
fn new() -> Self {
|
|
912
|
+
ApuDmc {
|
|
913
|
+
register0: Register::<u8>::new(),
|
|
914
|
+
register1: Register::<u8>::new(),
|
|
915
|
+
register2: Register::<u8>::new(),
|
|
916
|
+
register3: Register::<u8>::new(),
|
|
917
|
+
enabled: false,
|
|
918
|
+
timer_period: 0,
|
|
919
|
+
timer_counter: 0,
|
|
920
|
+
delta_counter: 0,
|
|
921
|
+
address_counter: 0,
|
|
922
|
+
remaining_bytes_counter: 0,
|
|
923
|
+
sample_buffer: 0,
|
|
924
|
+
sample_buffer_is_empty: true,
|
|
925
|
+
shift_register: 0,
|
|
926
|
+
remaining_bits_counter: 0,
|
|
927
|
+
silence_flag: true
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
fn store_register(&mut self, address: u16, value: u8) {
|
|
932
|
+
match address {
|
|
933
|
+
0x4010 => {
|
|
934
|
+
self.register0.store(value);
|
|
935
|
+
self.timer_period = DMC_TIMER_TABLE[self.timer_index() as usize] >> 1;
|
|
936
|
+
},
|
|
937
|
+
0x4011 => {
|
|
938
|
+
self.register1.store(value);
|
|
939
|
+
self.delta_counter = self.delta_counter();
|
|
940
|
+
},
|
|
941
|
+
0x4012 => {
|
|
942
|
+
self.register2.store(value);
|
|
943
|
+
self.address_counter = ((self.sample_address() as u16) << 6) | 0xC000;
|
|
944
|
+
},
|
|
945
|
+
0x4013 => {
|
|
946
|
+
self.register3.store(value);
|
|
947
|
+
self.remaining_bytes_counter = ((self.sample_length() as u16) << 4) | 1;
|
|
948
|
+
},
|
|
949
|
+
_ => {} // @TODO
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
fn set_enable(&mut self, enabled: bool) {
|
|
954
|
+
self.enabled = enabled;
|
|
955
|
+
|
|
956
|
+
// If DMC enable flag is set via 0x4015,
|
|
957
|
+
// the DMC sample will be restarted only if its remaining bytes is 0.
|
|
958
|
+
|
|
959
|
+
if enabled {
|
|
960
|
+
if self.remaining_bytes_counter == 0 {
|
|
961
|
+
self.start();
|
|
962
|
+
}
|
|
963
|
+
} else {
|
|
964
|
+
self.remaining_bytes_counter = 0;
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
fn start(&mut self) {
|
|
969
|
+
self.delta_counter = self.delta_counter();
|
|
970
|
+
self.address_counter = ((self.sample_address() as u16) << 6) | 0xC000;
|
|
971
|
+
self.remaining_bytes_counter = ((self.sample_length() as u16) << 4) | 1;
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
// See cpu.step() for what this method is for
|
|
975
|
+
// @TODO: Solution to remove this workaround
|
|
976
|
+
fn needs_cpu_memory_data(&self) -> bool {
|
|
977
|
+
self.timer_counter == 0 &&
|
|
978
|
+
self.remaining_bytes_counter > 0 &&
|
|
979
|
+
self.sample_buffer_is_empty
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
fn drive_timer(&mut self, sample_data: u8) -> bool {
|
|
983
|
+
let mut irq_active = false;
|
|
984
|
+
if self.timer_counter > 0 {
|
|
985
|
+
self.timer_counter -= 1;
|
|
986
|
+
} else {
|
|
987
|
+
self.timer_counter = self.timer_period;
|
|
988
|
+
|
|
989
|
+
// Memory reader
|
|
990
|
+
|
|
991
|
+
if self.remaining_bytes_counter > 0 && self.sample_buffer_is_empty {
|
|
992
|
+
self.sample_buffer = sample_data;
|
|
993
|
+
|
|
994
|
+
// if address exceeds 0xFFFF, it is wrapped around to 0x8000.
|
|
995
|
+
self.address_counter = match self.address_counter {
|
|
996
|
+
0xFFFF => 0x8000,
|
|
997
|
+
_ => self.address_counter + 1
|
|
998
|
+
};
|
|
999
|
+
|
|
1000
|
+
self.sample_buffer_is_empty = false;
|
|
1001
|
+
|
|
1002
|
+
// If the bytes remaining counter becomes zero
|
|
1003
|
+
// - the sample is restarted if the loop flag is set
|
|
1004
|
+
// - otherwise, the interrupt flag is set if IRQ enabled flag is set
|
|
1005
|
+
|
|
1006
|
+
self.remaining_bytes_counter -= 1;
|
|
1007
|
+
|
|
1008
|
+
if self.remaining_bytes_counter == 0 {
|
|
1009
|
+
if self.is_loop() {
|
|
1010
|
+
self.start();
|
|
1011
|
+
} else if self.irq_enabled() {
|
|
1012
|
+
irq_active = true;
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
// Output unit
|
|
1018
|
+
|
|
1019
|
+
if self.remaining_bits_counter == 0 {
|
|
1020
|
+
self.remaining_bits_counter = 8;
|
|
1021
|
+
if self.sample_buffer_is_empty {
|
|
1022
|
+
self.silence_flag = true;
|
|
1023
|
+
} else {
|
|
1024
|
+
self.silence_flag = false;
|
|
1025
|
+
self.sample_buffer_is_empty = true;
|
|
1026
|
+
self.shift_register = self.sample_buffer;
|
|
1027
|
+
self.sample_buffer = 0;
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
if !self.silence_flag {
|
|
1032
|
+
if (self.shift_register & 1) == 0 {
|
|
1033
|
+
if self.delta_counter > 1 {
|
|
1034
|
+
self.delta_counter -= 2;
|
|
1035
|
+
}
|
|
1036
|
+
} else {
|
|
1037
|
+
if self.delta_counter < 126 {
|
|
1038
|
+
self.delta_counter += 2;
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
// The bits-remaining counter is updated whenever the timer outputs a clock
|
|
1044
|
+
self.remaining_bits_counter -= 1;
|
|
1045
|
+
self.shift_register = self.shift_register >> 1;
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
irq_active
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
fn output(&self) -> u8 {
|
|
1052
|
+
// Seems like we should ignore enable bit set via 0x4015
|
|
1053
|
+
// (or no enable bit in DMC unit?)
|
|
1054
|
+
|
|
1055
|
+
// if !self.enabled {
|
|
1056
|
+
// return 0;
|
|
1057
|
+
// }
|
|
1058
|
+
|
|
1059
|
+
if self.silence_flag {
|
|
1060
|
+
return 0;
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
// 7-bit output
|
|
1064
|
+
self.delta_counter & 0x7F
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
fn irq_enabled(&self) -> bool {
|
|
1068
|
+
self.register0.is_bit_set(7)
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
fn is_loop(&self) -> bool {
|
|
1072
|
+
self.register0.is_bit_set(6)
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
fn timer_index(&self) -> u8 {
|
|
1076
|
+
self.register0.load_bits(0, 4)
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
fn delta_counter(&self) -> u8 {
|
|
1080
|
+
self.register1.load_bits(0, 7)
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
fn sample_address(&self) -> u8 {
|
|
1084
|
+
self.register2.load()
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
fn sample_length(&self) -> u8 {
|
|
1088
|
+
self.register3.load()
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
struct ApuFrameRegister {
|
|
1093
|
+
register: Register<u8>
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
impl ApuFrameRegister {
|
|
1097
|
+
fn new() -> Self {
|
|
1098
|
+
ApuFrameRegister {
|
|
1099
|
+
register: Register::<u8>::new()
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
fn store(&mut self, value: u8) {
|
|
1104
|
+
self.register.store(value);
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
fn five_step_mode(&self) -> bool {
|
|
1108
|
+
self.register.is_bit_set(7)
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
fn irq_disabled(&mut self) -> bool {
|
|
1112
|
+
self.register.is_bit_set(6)
|
|
1113
|
+
}
|
|
1114
|
+
}
|