Emulate CGB-C PCM read glitch, fix a potential noise volume envelope bug
This commit is contained in:
parent
620ee3cf51
commit
3cba3e8e27
21
Core/apu.c
21
Core/apu.c
@ -283,6 +283,15 @@ static void tick_square_envelope(GB_gameboy_t *gb, enum GB_CHANNELS index)
|
|||||||
|
|
||||||
if (gb->apu.square_channels[index].volume_countdown || (nrx2 & 7)) {
|
if (gb->apu.square_channels[index].volume_countdown || (nrx2 & 7)) {
|
||||||
if (!gb->apu.square_channels[index].volume_countdown || !--gb->apu.square_channels[index].volume_countdown) {
|
if (!gb->apu.square_channels[index].volume_countdown || !--gb->apu.square_channels[index].volume_countdown) {
|
||||||
|
if (gb->cgb_double_speed) {
|
||||||
|
if (index == GB_SQUARE_1) {
|
||||||
|
gb->apu.pcm_mask[0] &= gb->apu.square_channels[GB_SQUARE_1].current_volume | 0xF1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gb->apu.pcm_mask[0] &= (gb->apu.square_channels[GB_SQUARE_2].current_volume << 2) | 0x1F;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ((nrx2 & 8) && gb->apu.square_channels[index].current_volume < 0xF) {
|
if ((nrx2 & 8) && gb->apu.square_channels[index].current_volume < 0xF) {
|
||||||
gb->apu.square_channels[index].current_volume++;
|
gb->apu.square_channels[index].current_volume++;
|
||||||
}
|
}
|
||||||
@ -305,7 +314,10 @@ static void tick_noise_envelope(GB_gameboy_t *gb)
|
|||||||
uint8_t nr42 = gb->io_registers[GB_IO_NR42];
|
uint8_t nr42 = gb->io_registers[GB_IO_NR42];
|
||||||
|
|
||||||
if (gb->apu.noise_channel.volume_countdown || (nr42 & 7)) {
|
if (gb->apu.noise_channel.volume_countdown || (nr42 & 7)) {
|
||||||
if (!--gb->apu.noise_channel.volume_countdown) {
|
if (!gb->apu.noise_channel.volume_countdown || !--gb->apu.noise_channel.volume_countdown) {
|
||||||
|
if (gb->cgb_double_speed) {
|
||||||
|
gb->apu.pcm_mask[0] &= (gb->apu.noise_channel.current_volume << 2) | 0x1F;
|
||||||
|
}
|
||||||
if ((nr42 & 8) && gb->apu.noise_channel.current_volume < 0xF) {
|
if ((nr42 & 8) && gb->apu.noise_channel.current_volume < 0xF) {
|
||||||
gb->apu.noise_channel.current_volume++;
|
gb->apu.noise_channel.current_volume++;
|
||||||
}
|
}
|
||||||
@ -455,6 +467,9 @@ void GB_apu_run(GB_gameboy_t *gb)
|
|||||||
gb->apu.square_channels[i].sample_countdown = (gb->apu.square_channels[i].sample_length ^ 0x7FF) * 2 + 1;
|
gb->apu.square_channels[i].sample_countdown = (gb->apu.square_channels[i].sample_length ^ 0x7FF) * 2 + 1;
|
||||||
gb->apu.square_channels[i].current_sample_index++;
|
gb->apu.square_channels[i].current_sample_index++;
|
||||||
gb->apu.square_channels[i].current_sample_index &= 0x7;
|
gb->apu.square_channels[i].current_sample_index &= 0x7;
|
||||||
|
if (cycles_left == 0 && gb->apu.samples[i] == 0) {
|
||||||
|
gb->apu.pcm_mask[0] &= i == GB_SQUARE_1? 0xF0 : 0x0F;
|
||||||
|
}
|
||||||
|
|
||||||
update_square_sample(gb, i);
|
update_square_sample(gb, i);
|
||||||
}
|
}
|
||||||
@ -506,6 +521,10 @@ void GB_apu_run(GB_gameboy_t *gb)
|
|||||||
|
|
||||||
gb->apu.current_lfsr_sample = gb->apu.noise_channel.lfsr & 1;
|
gb->apu.current_lfsr_sample = gb->apu.noise_channel.lfsr & 1;
|
||||||
|
|
||||||
|
if (cycles_left == 0 && gb->apu.samples[GB_NOISE] == 0) {
|
||||||
|
gb->apu.pcm_mask[1] &= 0x0F;
|
||||||
|
}
|
||||||
|
|
||||||
update_sample(gb, GB_NOISE,
|
update_sample(gb, GB_NOISE,
|
||||||
gb->apu.current_lfsr_sample ?
|
gb->apu.current_lfsr_sample ?
|
||||||
gb->apu.noise_channel.current_volume : 0,
|
gb->apu.noise_channel.current_volume : 0,
|
||||||
|
@ -119,6 +119,7 @@ typedef struct
|
|||||||
#define GB_SKIP_DIV_EVENT_SKIP 2
|
#define GB_SKIP_DIV_EVENT_SKIP 2
|
||||||
uint8_t skip_div_event;
|
uint8_t skip_div_event;
|
||||||
bool current_lfsr_sample;
|
bool current_lfsr_sample;
|
||||||
|
uint8_t pcm_mask[2]; // For CGB-0 to CGB-C PCM read glitch
|
||||||
} GB_apu_t;
|
} GB_apu_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@ -303,12 +303,12 @@ static uint8_t read_high_memory(GB_gameboy_t *gb, uint16_t addr)
|
|||||||
|
|
||||||
case GB_IO_PCM_12:
|
case GB_IO_PCM_12:
|
||||||
if (!GB_is_cgb(gb)) return 0xFF;
|
if (!GB_is_cgb(gb)) return 0xFF;
|
||||||
return (gb->apu.is_active[GB_SQUARE_2] ? (gb->apu.samples[GB_SQUARE_2] << 4) : 0) |
|
return ((gb->apu.is_active[GB_SQUARE_2] ? (gb->apu.samples[GB_SQUARE_2] << 4) : 0) |
|
||||||
(gb->apu.is_active[GB_SQUARE_1] ? (gb->apu.samples[GB_SQUARE_1]) : 0);
|
(gb->apu.is_active[GB_SQUARE_1] ? (gb->apu.samples[GB_SQUARE_1]) : 0)) & (gb->model <= GB_MODEL_CGB_C? gb->apu.pcm_mask[0] : 0xFF);
|
||||||
case GB_IO_PCM_34:
|
case GB_IO_PCM_34:
|
||||||
if (!GB_is_cgb(gb)) return 0xFF;
|
if (!GB_is_cgb(gb)) return 0xFF;
|
||||||
return (gb->apu.is_active[GB_NOISE] ? (gb->apu.samples[GB_NOISE] << 4) : 0) |
|
return ((gb->apu.is_active[GB_NOISE] ? (gb->apu.samples[GB_NOISE] << 4) : 0) |
|
||||||
(gb->apu.is_active[GB_WAVE] ? (gb->apu.samples[GB_WAVE]) : 0);
|
(gb->apu.is_active[GB_WAVE] ? (gb->apu.samples[GB_WAVE]) : 0)) & (gb->model <= GB_MODEL_CGB_C? gb->apu.pcm_mask[1] : 0xFF);
|
||||||
case GB_IO_JOYP:
|
case GB_IO_JOYP:
|
||||||
GB_timing_sync(gb);
|
GB_timing_sync(gb);
|
||||||
case GB_IO_TMA:
|
case GB_IO_TMA:
|
||||||
|
@ -215,6 +215,7 @@ static void advance_serial(GB_gameboy_t *gb, uint8_t cycles)
|
|||||||
|
|
||||||
void GB_advance_cycles(GB_gameboy_t *gb, uint8_t cycles)
|
void GB_advance_cycles(GB_gameboy_t *gb, uint8_t cycles)
|
||||||
{
|
{
|
||||||
|
gb->apu.pcm_mask[0] = gb->apu.pcm_mask[1] = 0xFF; // Sort of hacky, but too many cross-component interactions to do it right
|
||||||
// Affected by speed boost
|
// Affected by speed boost
|
||||||
gb->dma_cycles += cycles;
|
gb->dma_cycles += cycles;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user