- [NEW] Començant a implementar la APU
This commit is contained in:
112
APU.cpp
Normal file
112
APU.cpp
Normal file
@@ -0,0 +1,112 @@
|
||||
#include "APU.h"
|
||||
|
||||
namespace APU
|
||||
{
|
||||
#define apu_enabled (NR52&0x80)
|
||||
#define DAC1_enabled ((NR12&0xf8)!=0)
|
||||
|
||||
struct channel_t
|
||||
{
|
||||
bool enabled = false;
|
||||
uint8_t length_timer = 0;
|
||||
bool length_timer_expired = true;
|
||||
bool length_enable = false;
|
||||
};
|
||||
|
||||
channel_t channels[4];
|
||||
|
||||
uint8_t NR10 = 0; // 0xff10 - Sound channel 1 sweep
|
||||
uint8_t NR11 = 0; // 0xff11 - Sound channel 1 length timer & duty cycle
|
||||
uint8_t NR12 = 0; // 0xff12 - Sound channel 1 volume & envelope
|
||||
uint8_t NR13 = 0; // 0xff13 - Sound channel 1 period low
|
||||
uint8_t NR14 = 0; // 0xff14 - Sound channel 1 period high & control
|
||||
// 0xff15 - Not used?
|
||||
uint8_t NR21 = 0; // 0xff16 - Sound channel 2 length timer & duty cycle
|
||||
uint8_t NR22 = 0; // 0xff17 - Sound channel 2 volume & envelope
|
||||
uint8_t NR23 = 0; // 0xff18 - Sound channel 2 period low
|
||||
uint8_t NR24 = 0; // 0xff19 - Sound channel 2 period high & control
|
||||
uint8_t NR30 = 0; // 0xff1a - Sound channel 3 DAC enable
|
||||
uint8_t NR31 = 0; // 0xff1b - Sound channel 3 length timer
|
||||
uint8_t NR32 = 0; // 0xff1c - Sound channel 3 output level
|
||||
uint8_t NR33 = 0; // 0xff1d - Sound channel 3 period low
|
||||
uint8_t NR34 = 0; // 0xff1e - Sound channel 3 period high & control
|
||||
// 0xff1f - Not used?
|
||||
uint8_t NR41 = 0; // 0xff20 - Sound channel 4 length timer
|
||||
uint8_t NR42 = 0; // 0xff21 - Sound channel 4 volume & envelope
|
||||
uint8_t NR43 = 0; // 0xff22 - Sound channel 4 frequency & randomness
|
||||
uint8_t NR44 = 0; // 0xff23 - Sound channel 4 control
|
||||
uint8_t NR50 = 0; // 0xff24 - Master volume & VIN panning
|
||||
uint8_t NR51 = 0; // 0xff25 - Sound panning
|
||||
uint8_t NR52 = 0; // 0xff26 - Sound on/off
|
||||
// 0xff27-0xff2f - Not used?
|
||||
uint8_t WaveRAM[16]; // 0xff30-0xff3f
|
||||
|
||||
void reset()
|
||||
{
|
||||
NR10 = 0;
|
||||
NR11 = 0;
|
||||
NR12 = 0;
|
||||
NR13 = 0;
|
||||
NR14 = 0;
|
||||
NR21 = 0;
|
||||
NR22 = 0;
|
||||
NR23 = 0;
|
||||
NR24 = 0;
|
||||
NR30 = 0;
|
||||
NR31 = 0;
|
||||
NR32 = 0;
|
||||
NR33 = 0;
|
||||
NR34 = 0;
|
||||
NR41 = 0;
|
||||
NR42 = 0;
|
||||
NR43 = 0;
|
||||
NR44 = 0;
|
||||
NR50 = 0;
|
||||
NR51 = 0;
|
||||
NR52 = 0;
|
||||
}
|
||||
|
||||
void trigger(uint8_t channel)
|
||||
{
|
||||
channels[channel].enabled = true;
|
||||
// length timer expired is reset
|
||||
// period divider is set to the contents of NR13 and NR14
|
||||
// envelope timer is reset
|
||||
// volume is set to contents of NR12 initial volume
|
||||
// sweep does several things (check documentation)
|
||||
}
|
||||
|
||||
uint8_t readRegister(uint16_t address)
|
||||
{
|
||||
switch(address)
|
||||
{
|
||||
case 0xff10: return NR10; break;
|
||||
case 0xff11: return NR11 & 0xc0; break;
|
||||
case 0xff12: return NR12; break;
|
||||
case 0xff13: return 0x00; break;
|
||||
case 0xff14: return NR14 & 0x40; break;
|
||||
|
||||
case 0xff24: return NR50; break;
|
||||
case 0xff25: return NR51; break;
|
||||
case 0xff26: return NR52; break;
|
||||
}
|
||||
}
|
||||
|
||||
void writeRegister(uint16_t address, uint8_t value)
|
||||
{
|
||||
if (!apu_enabled && (address!=0xff26)) return;
|
||||
|
||||
switch(address)
|
||||
{
|
||||
case 0xff10: NR10 = value; break;
|
||||
case 0xff11: NR11 = value; break;
|
||||
case 0xff12: NR12 = value; break;
|
||||
case 0xff13: NR13 = value; break;
|
||||
case 0xff14: NR14 = value; if (value&0x80) trigger(1); break;
|
||||
|
||||
case 0xff24: NR50 = value; break;
|
||||
case 0xff25: NR51 = value; break;
|
||||
case 0xff26: if (value&0x80) reset(); NR52 = (value&0x80) | (NR52 & 0x0f); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user