Skip to content

Commit 3d87c5c

Browse files
committed
Improvements to channel 4 start delays, emulating channel 4 background behavior. Still not 100% complete, but should cover almost all real-world scenarios.
1 parent 11ba1df commit 3d87c5c

File tree

2 files changed

+140
-58
lines changed

2 files changed

+140
-58
lines changed

Core/apu.c

Lines changed: 136 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1016,8 +1016,8 @@ restart:;
10161016
}
10171017
}
10181018

1019-
// The noise channel can step even if inactive on the DMG
1020-
if (gb->apu.is_active[GB_NOISE] || !GB_is_cgb(gb)) {
1019+
// TODO: verify these conditions one a DMG somehow
1020+
if (gb->apu.noise_counter_active || gb->apu.noise_background_counter_active) {
10211021
uint16_t cycles_left = cycles;
10221022
unsigned divisor = (gb->io_registers[GB_IO_NR43] & 0x07) << 2;
10231023
if (!divisor) divisor = 2;
@@ -1027,25 +1027,33 @@ restart:;
10271027
// This while doesn't get an unlikely because the noise channel steps frequently enough
10281028
while (cycles_left >= gb->apu.noise_channel.counter_countdown) {
10291029
cycles_left -= gb->apu.noise_channel.counter_countdown;
1030-
gb->apu.noise_channel.counter_countdown = divisor + gb->apu.noise_channel.delta;
1031-
gb->apu.noise_channel.delta = 0;
1030+
gb->apu.noise_channel.counter_countdown = divisor;
10321031
uint16_t mask = 1 << (gb->io_registers[GB_IO_NR43] >> 4);
10331032
bool old_bit = gb->apu.noise_channel.counter & mask;
10341033
gb->apu.noise_channel.counter++;
10351034
gb->apu.noise_channel.counter &= 0x3FFF;
1035+
gb->apu.noise_channel.did_step_counter = true;
10361036
bool new_bit = gb->apu.noise_channel.counter & mask;
10371037

10381038
/* Step LFSR */
1039-
if (new_bit && !old_bit) {
1039+
if (new_bit && !old_bit && gb->apu.is_active[GB_NOISE]) {
10401040
if (cycles_left == 0 && gb->apu.samples[GB_NOISE] == 0 && !gb->cgb_double_speed) {
10411041
gb->apu.pcm_mask[1] &= 0x0F;
10421042
}
10431043
step_lfsr(gb, cycles - cycles_left);
10441044
}
1045+
if (divisor != 2) {
1046+
gb->apu.noise_background_counter_active = false;
1047+
if (unlikely(!gb->apu.noise_counter_active)) {
1048+
break;
1049+
}
1050+
}
10451051
}
10461052
if (cycles_left) {
1047-
gb->apu.noise_channel.counter_countdown -= cycles_left;
1048-
gb->apu.noise_channel.countdown_reloaded = false;
1053+
if (likely(gb->apu.noise_counter_active || gb->apu.noise_background_counter_active)) {
1054+
gb->apu.noise_channel.counter_countdown -= cycles_left;
1055+
gb->apu.noise_channel.countdown_reloaded = false;
1056+
}
10491057
}
10501058
else {
10511059
gb->apu.noise_channel.countdown_reloaded = true;
@@ -1319,6 +1327,124 @@ static noinline void nr10_write_glitch(GB_gameboy_t *gb, uint8_t value)
13191327

13201328
}
13211329

1330+
static void prepare_noise_start(GB_gameboy_t *gb)
1331+
{
1332+
/*
1333+
TODO: When restarting a channel right after starting it, before it has the chance to tick the counter, things
1334+
behave differently. Only certain behaviors of this edge case are emulated.
1335+
*/
1336+
1337+
/*
1338+
TODO: Restarting a channel in double speed mode under CGB-C and older is not accurate if the divisor is 0 or 1.
1339+
Specifically in the 0 case, the initial LFSR value seems to be deterministic, but dependant on various
1340+
parameters. It is neither 0 or the equaly unexplained 0x0055.
1341+
*/
1342+
gb->apu.noise_counter_active = gb->io_registers[GB_IO_NR42] & 0xF8; // Resets on APU off and DAC disable
1343+
unsigned divisor = (gb->io_registers[GB_IO_NR43] & 0x07);
1344+
bool was_background_counting = gb->apu.noise_background_counter_active;
1345+
gb->apu.noise_background_counter_active = divisor == 0;
1346+
bool instant_step = false;
1347+
bool div_1_glitch = false;
1348+
1349+
if (divisor > 1 && gb->apu.noise_channel.counter_countdown == 1) {
1350+
gb->apu.noise_channel.counter++;
1351+
gb->apu.noise_channel.counter &= 0x3FFF;
1352+
}
1353+
else if (divisor > 1 && gb->apu.noise_channel.counter_countdown == 2 && gb->apu.is_active[GB_NOISE] && gb->model <= GB_MODEL_CGB_C && gb->cgb_double_speed) {
1354+
gb->apu.noise_channel.counter++;
1355+
gb->apu.noise_channel.counter &= 0x3FFF;
1356+
}
1357+
else if (gb->apu.noise_channel.counter_countdown == 2 &&
1358+
(gb->apu.noise_channel.alignment & 3) == 0 &&
1359+
gb->apu.is_active[GB_NOISE]) {
1360+
if (divisor == 0) {
1361+
divisor = 8;
1362+
}
1363+
else if (divisor == 1) {
1364+
/* TODO: I'm not 100% sure this only affects NR43 = 1X */
1365+
if ((gb->io_registers[GB_IO_NR43] & 0xf0) == 0x10 && (gb->apu.noise_channel.counter & 1)) {
1366+
instant_step = true;
1367+
}
1368+
if (gb->apu.noise_channel.did_step_counter) {
1369+
gb->apu.noise_channel.counter++;
1370+
gb->apu.noise_channel.counter &= 0x3FFF;
1371+
}
1372+
/* TODO: needs further research, the conditions are very odd. What if NR43 changes before stepping? */
1373+
if ((gb->io_registers[GB_IO_NR43] & 0xf0) == 0x10 && !gb->apu.noise_channel.did_step_counter) {
1374+
div_1_glitch = true;
1375+
}
1376+
}
1377+
}
1378+
gb->apu.noise_channel.counter_countdown = divisor == 0? 6 : divisor * 4 + 6;
1379+
if (gb->apu.noise_channel.alignment & 1) {
1380+
if (!divisor) {
1381+
if (gb->model <= GB_MODEL_CGB_C) {
1382+
gb->apu.noise_channel.counter_countdown++;
1383+
}
1384+
else if (was_background_counting) {
1385+
gb->apu.noise_channel.counter_countdown--;
1386+
}
1387+
else {
1388+
gb->apu.noise_channel.counter_countdown++;
1389+
}
1390+
}
1391+
else {
1392+
if (gb->apu.noise_channel.alignment & 2) {
1393+
if (divisor == 1 && !gb->apu.is_active[GB_NOISE]) {
1394+
gb->apu.noise_channel.counter_countdown++;
1395+
}
1396+
else {
1397+
gb->apu.noise_channel.counter_countdown -= 3;
1398+
}
1399+
}
1400+
else {
1401+
gb->apu.noise_channel.counter_countdown--;
1402+
if (divisor == 1 && gb->apu.is_active[GB_NOISE]) {
1403+
gb->apu.noise_channel.counter_countdown -= 4;
1404+
}
1405+
}
1406+
}
1407+
}
1408+
else {
1409+
if (divisor) {
1410+
if (gb->apu.noise_channel.alignment & 2) {
1411+
if (gb->cgb_double_speed && gb->model <= GB_MODEL_CGB_C && divisor == 1) {
1412+
gb->apu.noise_channel.counter_countdown += 2;
1413+
}
1414+
else {
1415+
gb->apu.noise_channel.counter_countdown -= 2;
1416+
}
1417+
}
1418+
else if (divisor > 1 && (!gb->cgb_double_speed || gb->model > GB_MODEL_CGB_C)) {
1419+
gb->apu.noise_channel.counter_countdown -= 4;
1420+
}
1421+
}
1422+
else if (gb->cgb_double_speed && gb->model <= GB_MODEL_CGB_C) {
1423+
gb->apu.noise_channel.counter_countdown += 2;
1424+
}
1425+
}
1426+
1427+
/* TODO: This is weird, is the clock going out of sync? */
1428+
if (!divisor && gb->model <= GB_MODEL_CGB_C && was_background_counting && !gb->apu.is_active[GB_NOISE]) {
1429+
gb->apu.noise_channel.counter_countdown--;
1430+
}
1431+
if (div_1_glitch) {
1432+
gb->apu.noise_channel.counter_countdown -= 4;
1433+
}
1434+
1435+
if (!divisor && gb->apu.is_active[GB_NOISE] && (gb->apu.noise_channel.alignment & 3) == 3) {
1436+
/* TODO: I have no clue where this number comes from, but this number is confirmed for this edge case even for
1437+
side LFSR, despite being seemingly arbitrary. */
1438+
gb->apu.noise_channel.lfsr = 0x0055;
1439+
}
1440+
else {
1441+
gb->apu.noise_channel.lfsr = 0;
1442+
}
1443+
if (instant_step) {
1444+
step_lfsr(gb, 0);
1445+
}
1446+
}
1447+
13221448
void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value)
13231449
{
13241450
GB_apu_run(gb, true);
@@ -1692,6 +1818,7 @@ void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value)
16921818
gb->io_registers[reg] = value;
16931819
gb->apu.is_active[GB_NOISE] = false;
16941820
update_sample(gb, GB_NOISE, 0, 0);
1821+
gb->apu.noise_counter_active = false;
16951822
}
16961823
else if (gb->apu.is_active[GB_NOISE]) {
16971824
nrx2_glitch(gb, &gb->apu.noise_channel.current_volume,
@@ -1722,7 +1849,6 @@ void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value)
17221849
gb->apu.noise_channel.counter_countdown =
17231850
divisor + (divisor == 2? 0 : inline_const(uint8_t[], {2, 1, 4, 3})[(gb->apu.noise_channel.alignment) & 3]);
17241851
}
1725-
gb->apu.noise_channel.delta = 0;
17261852
}
17271853
/* Step LFSR */
17281854
if (new_bit && (!old_bit || gb->model <= GB_MODEL_CGB_C)) {
@@ -1747,59 +1873,12 @@ void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value)
17471873
gb->apu.noise_channel.dmg_delayed_start = 6;
17481874
}
17491875
else {
1750-
unsigned divisor = (gb->io_registers[GB_IO_NR43] & 0x07) << 2;
1751-
if (!divisor) divisor = 2;
1752-
gb->apu.noise_channel.delta = 0;
1753-
gb->apu.noise_channel.counter_countdown = divisor + 4;
1754-
if (divisor == 2) {
1755-
if (gb->model <= GB_MODEL_CGB_C) {
1756-
gb->apu.noise_channel.counter_countdown += gb->apu.lf_div;
1757-
if (!gb->cgb_double_speed) {
1758-
gb->apu.noise_channel.counter_countdown -= 1;
1759-
}
1760-
}
1761-
else {
1762-
gb->apu.noise_channel.counter_countdown += 1 - gb->apu.lf_div;
1763-
}
1764-
}
1765-
else {
1766-
if (gb->model <= GB_MODEL_CGB_C) {
1767-
gb->apu.noise_channel.counter_countdown += inline_const(uint8_t[], {2, 1, 4, 3})[gb->apu.noise_channel.alignment & 3];
1768-
}
1769-
else {
1770-
gb->apu.noise_channel.counter_countdown += inline_const(uint8_t[], {2, 1, 0, 3})[gb->apu.noise_channel.alignment & 3];
1771-
}
1772-
if (((gb->apu.noise_channel.alignment + 1) & 3) < 2) {
1773-
if ((gb->io_registers[GB_IO_NR43] & 0x07) == 1) {
1774-
gb->apu.noise_channel.counter_countdown -= 2;
1775-
gb->apu.noise_channel.delta = 2;
1776-
}
1777-
else {
1778-
gb->apu.noise_channel.counter_countdown -= 4;
1779-
}
1780-
}
1781-
}
1876+
prepare_noise_start(gb);
17821877

1783-
/* TODO: These are quite weird. Verify further */
1784-
if (gb->model <= GB_MODEL_CGB_C) {
1785-
if (gb->cgb_double_speed) {
1786-
if (!(gb->io_registers[GB_IO_NR43] & 0xF0) && (gb->io_registers[GB_IO_NR43] & 0x07)) {
1787-
gb->apu.noise_channel.counter_countdown -= 1;
1788-
}
1789-
else if ((gb->io_registers[GB_IO_NR43] & 0xF0) && !(gb->io_registers[GB_IO_NR43] & 0x07)) {
1790-
gb->apu.noise_channel.counter_countdown += 1;
1791-
}
1792-
}
1793-
else {
1794-
gb->apu.noise_channel.counter_countdown -= 2;
1795-
}
1796-
}
1797-
17981878
gb->apu.noise_channel.current_volume = gb->io_registers[GB_IO_NR42] >> 4;
1799-
1800-
gb->apu.noise_channel.lfsr = 0;
18011879
gb->apu.noise_channel.current_lfsr_sample = false;
18021880
gb->apu.noise_channel.volume_countdown = gb->io_registers[GB_IO_NR42] & 7;
1881+
gb->apu.noise_channel.did_step_counter = false;
18031882

18041883
if (gb->io_registers[GB_IO_NR42] & 0xF8) {
18051884
gb->apu.is_active[GB_NOISE] = true;

Core/apu.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ typedef struct
138138
uint8_t alignment; // If (NR43 & 7) != 0, samples are aligned to 512KHz clock instead of
139139
// 1MHz. This variable keeps track of the alignment.
140140
bool current_lfsr_sample;
141-
int8_t delta;
141+
bool did_step_counter;
142142
bool countdown_reloaded;
143143
uint8_t dmg_delayed_start;
144144
GB_envelope_clock_t envelope_clock;
@@ -153,6 +153,9 @@ typedef struct
153153

154154
bool apu_cycles_in_2mhz; // For compatibility with 0.16.x save states
155155
bool pending_envelope_tick;
156+
// Move to noise struct when breaking compat
157+
bool noise_counter_active;
158+
bool noise_background_counter_active;
156159
} GB_apu_t;
157160

158161
typedef enum {

0 commit comments

Comments
 (0)