GB Video: Fix LYC for scanline 0
Jeffrey Pfau jeffrey@endrift.com
Sat, 06 Feb 2016 18:44:19 -0800
2 files changed,
94 insertions(+),
11 deletions(-)
M
src/gb/audio.c
→
src/gb/audio.c
@@ -104,7 +104,14 @@
void GBAudioWriteNR14(struct GBAudio* audio, uint8_t value) { audio->ch1.control.frequency &= 0xFF; audio->ch1.control.frequency |= GBAudioRegisterControlGetFrequency(value << 8); + bool wasStop = audio->ch1.control.stop; audio->ch1.control.stop = GBAudioRegisterControlGetStop(value << 8); + if (!wasStop && audio->ch1.control.stop && audio->ch1.control.length && !(audio->frame & 1)) { + --audio->ch1.control.length; + if (audio->ch1.control.length == 0) { + audio->playingCh1 = false; + } + } if (GBAudioRegisterControlIsRestart(value << 8)) { if (audio->nextEvent == INT_MAX) { audio->eventDiff = 0;@@ -118,13 +125,25 @@ if (audio->ch1.envelope.currentVolume > 0) {
audio->ch1.envelope.dead = 0; } audio->ch1.sweepStep = audio->ch1.time; + if (audio->playingCh1 && audio->ch1.shift) { + audio->playingCh1 = _updateSweep(&audio->ch1); + } if (!audio->ch1.control.length) { audio->ch1.control.length = 64; + if (audio->ch1.control.stop && !(audio->frame & 1)) { + --audio->ch1.control.length; + } } - if (audio->playingCh1 && audio->ch1.shift) { - audio->playingCh1 = _updateSweep(&audio->ch1); + audio->nextEvent = audio->eventDiff; + if (audio->p) { + // TODO: Don't need + audio->p->cpu->nextEvent = audio->eventDiff; } - audio->nextEvent = 0; + } + // TODO: Don't need p + if (audio->p) { + audio->p->memory.io[REG_NR52] &= ~0x0001; + audio->p->memory.io[REG_NR52] |= audio->playingCh1; } }@@ -151,7 +170,14 @@
void GBAudioWriteNR24(struct GBAudio* audio, uint8_t value) { audio->ch2.control.frequency &= 0xFF; audio->ch2.control.frequency |= GBAudioRegisterControlGetFrequency(value << 8); + bool wasStop = audio->ch2.control.stop; audio->ch2.control.stop = GBAudioRegisterControlGetStop(value << 8); + if (!wasStop && audio->ch2.control.stop && audio->ch2.control.length && !(audio->frame & 1)) { + --audio->ch2.control.length; + if (audio->ch2.control.length == 0) { + audio->playingCh2 = false; + } + } if (GBAudioRegisterControlIsRestart(value << 8)) { audio->playingCh2 = audio->ch2.envelope.initialVolume || audio->ch2.envelope.direction; audio->ch2.envelope.currentVolume = audio->ch2.envelope.initialVolume;@@ -166,8 +192,20 @@ audio->nextCh2 = audio->eventDiff;
} if (!audio->ch2.control.length) { audio->ch2.control.length = 64; + if (audio->ch2.control.stop && !(audio->frame & 1)) { + --audio->ch2.control.length; + } + } + audio->nextEvent = audio->eventDiff; + if (audio->p) { + // TODO: Don't need + audio->p->cpu->nextEvent = audio->eventDiff; } - audio->nextEvent = 0; + } + // TODO: Don't need p + if (audio->p) { + audio->p->memory.io[REG_NR52] &= ~0x0002; + audio->p->memory.io[REG_NR52] |= audio->playingCh2 << 1; } }@@ -199,11 +237,21 @@
void GBAudioWriteNR34(struct GBAudio* audio, uint8_t value) { audio->ch3.rate &= 0xFF; audio->ch3.rate |= GBAudioRegisterControlGetRate(value << 8); + bool wasStop = audio->ch3.stop; audio->ch3.stop = GBAudioRegisterControlGetStop(value << 8); + if (!wasStop && audio->ch3.stop && audio->ch3.lengthShadow && !(audio->frame & 1)) { + --audio->ch3.lengthShadow; + if (audio->ch3.lengthShadow == 0) { + audio->playingCh3 = false; + } + } if (GBAudioRegisterControlIsRestart(value << 8)) { audio->playingCh3 = audio->ch3.enable; if (!audio->ch3.lengthShadow) { audio->ch3.lengthShadow = 256; + if (audio->ch3.stop && !(audio->frame & 1)) { + --audio->ch3.lengthShadow; + } } } if (audio->playingCh3) {@@ -211,7 +259,16 @@ if (audio->nextEvent == INT_MAX) {
audio->eventDiff = 0; } audio->nextCh3 = audio->eventDiff; - audio->nextEvent = 0; + audio->nextEvent = audio->eventDiff; + if (audio->p) { + // TODO: Don't need + audio->p->cpu->nextEvent = audio->eventDiff; + } + } + // TODO: Don't need p + if (audio->p) { + audio->p->memory.io[REG_NR52] &= ~0x0004; + audio->p->memory.io[REG_NR52] |= audio->playingCh3 << 2; } }@@ -237,7 +294,14 @@ audio->ch4.power = GBAudioRegisterNoiseFeedbackGetPower(value);
} void GBAudioWriteNR44(struct GBAudio* audio, uint8_t value) { + bool wasStop = audio->ch4.stop; audio->ch4.stop = GBAudioRegisterNoiseControlGetStop(value); + if (!wasStop && audio->ch4.stop && audio->ch4.length && !(audio->frame & 1)) { + --audio->ch4.length; + if (audio->ch4.length == 0) { + audio->playingCh4 = false; + } + } if (GBAudioRegisterNoiseControlIsRestart(value)) { audio->playingCh4 = audio->ch4.envelope.initialVolume || audio->ch4.envelope.direction; audio->ch4.envelope.currentVolume = audio->ch4.envelope.initialVolume;@@ -257,8 +321,20 @@ audio->nextCh4 = audio->eventDiff;
} if (!audio->ch4.length) { audio->ch4.length = 64; + if (audio->ch4.stop && !(audio->frame & 1)) { + --audio->ch4.length; + } } - audio->nextEvent = 0; + audio->nextEvent = audio->eventDiff; + if (audio->p) { + // TODO: Don't need + audio->p->cpu->nextEvent = audio->eventDiff; + } + } + // TODO: Don't need p + if (audio->p) { + audio->p->memory.io[REG_NR52] &= ~0x0008; + audio->p->memory.io[REG_NR52] |= audio->playingCh4 << 3; } }@@ -328,6 +404,8 @@ audio->p->memory.io[REG_NR50] = 0;
audio->p->memory.io[REG_NR51] = 0; audio->p->memory.io[REG_NR52] &= ~0x000F; } + } else { + audio->frame = 7; } }
M
src/gb/video.c
→
src/gb/video.c
@@ -125,12 +125,10 @@ }
GBUpdateIRQs(video->p); break; case 1: + // TODO: One M-cycle delay ++video->ly; video->stat = GBRegisterSTATSetLYC(video->stat, lyc == video->ly); - if (GBRegisterSTATIsLYCIRQ(video->stat) && lyc == video->ly) { - video->p->memory.io[REG_IF] |= (1 << GB_IRQ_LCDSTAT); - } - if (video->ly >= GB_VIDEO_VERTICAL_TOTAL_PIXELS) { + if (video->ly == GB_VIDEO_VERTICAL_TOTAL_PIXELS) { video->ly = 0; video->nextMode = GB_VIDEO_MODE_2_LENGTH; video->mode = 2;@@ -140,7 +138,14 @@ }
} else { video->nextMode = GB_VIDEO_HORIZONTAL_LENGTH; } - video->p->memory.io[REG_LY] = video->ly; + if (video->ly == GB_VIDEO_VERTICAL_TOTAL_PIXELS - 1) { + video->p->memory.io[REG_LY] = 0; + } else { + video->p->memory.io[REG_LY] = video->ly; + } + if (GBRegisterSTATIsLYCIRQ(video->stat) && lyc == video->ly) { + video->p->memory.io[REG_IF] |= (1 << GB_IRQ_LCDSTAT); + } GBUpdateIRQs(video->p); break; case 2: