Skip to content

Commit

Permalink
[bios] Fix lz77 and add BIOS_SndDriverVsyncOn
Browse files Browse the repository at this point in the history
The lz77 uncompresssion software BIOS implementation was exiting early
when uncompressing data, if the overall length was larger than
advertised in the function parameter. However, real GBA BIOS does read
further than the advertised length, so we do here too. This fixes
Advance Wars title screen.

This also adds a SoundDriverVSyncOn implementation, silencing an error
for some Shrek games, though they still cannot properly boot with an
emulated BIOS.

Fixes #789
  • Loading branch information
Steelskin authored and rkitover committed May 27, 2023
1 parent 4c8b54d commit e26f807
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 65 deletions.
15 changes: 9 additions & 6 deletions src/gba/GBA.cpp
Expand Up @@ -2083,8 +2083,8 @@ void CPUSoftwareInterrupt(int comment)
case 0x02:
#ifdef GBA_LOGGING
if (systemVerbose & VERBOSE_SWI) {
/*log("Halt: (VCOUNT = %2d)\n",
VCOUNT);*/
log("Halt: (VCOUNT = %2d)\n",
VCOUNT);
}
#endif
holdState = true;
Expand All @@ -2094,8 +2094,8 @@ void CPUSoftwareInterrupt(int comment)
case 0x03:
#ifdef GBA_LOGGING
if (systemVerbose & VERBOSE_SWI) {
/*log("Stop: (VCOUNT = %2d)\n",
VCOUNT);*/
log("Stop: (VCOUNT = %2d)\n",
VCOUNT);
}
#endif
holdState = true;
Expand Down Expand Up @@ -2271,11 +2271,14 @@ void CPUSoftwareInterrupt(int comment)
case 0x1E:
BIOS_SndChannelClear();
break;
case 0x1F:
BIOS_MidiKey2Freq();
break;
case 0x28:
BIOS_SndDriverVSyncOff();
break;
case 0x1F:
BIOS_MidiKey2Freq();
case 0x29:
BIOS_SndDriverVSyncOn();
break;
case 0xE0:
case 0xE1:
Expand Down
126 changes: 67 additions & 59 deletions src/gba/bios.cpp
Expand Up @@ -688,34 +688,18 @@ void BIOS_LZ77UnCompVram()
while (len > 0) {
uint8_t d = CPUReadByte(source++);

if (d) {
for (int i = 0; i < 8; i++) {
if (d & 0x80) {
uint16_t data = CPUReadByte(source++) << 8;
data |= CPUReadByte(source++);
int length = (data >> 12) + 3;
int offset = (data & 0x0FFF);
uint32_t windowOffset = dest + byteCount - offset - 1;
for (int i2 = 0; i2 < length; i2++) {
writeValue |= (CPUReadByte(windowOffset++) << byteShift);
byteShift += 8;
byteCount++;

if (byteCount == 2) {
CPUWriteHalfWord(dest, DowncastU16(writeValue));
dest += 2;
byteCount = 0;
byteShift = 0;
writeValue = 0;
}
len--;
if (len == 0)
return;
}
} else {
writeValue |= (CPUReadByte(source++) << byteShift);
for (int i = 0; i < 8; i++) {
if (d & 0x80) {
uint16_t data = CPUReadByte(source++) << 8;
data |= CPUReadByte(source++);
int length = (data >> 12) + 3;
int offset = (data & 0x0FFF);
uint32_t windowOffset = dest + byteCount - offset - 1;
for (int i2 = 0; i2 < length; i2++) {
writeValue |= (CPUReadByte(windowOffset++) << byteShift);
byteShift += 8;
byteCount++;

if (byteCount == 2) {
CPUWriteHalfWord(dest, DowncastU16(writeValue));
dest += 2;
Expand All @@ -724,29 +708,34 @@ void BIOS_LZ77UnCompVram()
writeValue = 0;
}
len--;
if (len == 0)
return;
}
d <<= 1;
}
} else {
for (int i = 0; i < 8; i++) {
} else {
writeValue |= (CPUReadByte(source++) << byteShift);
byteShift += 8;
byteCount++;
if (byteCount == 2) {
CPUWriteHalfWord(dest, DowncastU16(writeValue));
dest += 2;
byteShift = 0;
byteCount = 0;
byteShift = 0;
writeValue = 0;
}
len--;
if (len == 0)
return;
}

d <<= 1;

if (len <= 0) {
// This can happen if the parameter was incorrectly set. Real
// hardware does a buffer overflow so we do it here too.
break;
}
}
}

reg[0].I = source;
reg[1].I = dest;
reg[3].I = 0;
}

void BIOS_LZ77UnCompWram()
Expand All @@ -772,37 +761,35 @@ void BIOS_LZ77UnCompWram()
while (len > 0) {
uint8_t d = CPUReadByte(source++);

if (d) {
for (int i = 0; i < 8; i++) {
if (d & 0x80) {
uint16_t data = CPUReadByte(source++) << 8;
data |= CPUReadByte(source++);
int length = (data >> 12) + 3;
int offset = (data & 0x0FFF);
uint32_t windowOffset = dest - offset - 1;
for (int i2 = 0; i2 < length; i2++) {
CPUWriteByte(dest++, CPUReadByte(windowOffset++));
len--;
if (len == 0)
return;
}
} else {
CPUWriteByte(dest++, CPUReadByte(source++));
for (int i = 0; i < 8; i++) {
if (d & 0x80) {
uint16_t data = CPUReadByte(source++) << 8;
data |= CPUReadByte(source++);
int length = (data >> 12) + 3;
int offset = (data & 0x0FFF);
uint32_t windowOffset = dest - offset - 1;
for (int i2 = 0; i2 < length; i2++) {
CPUWriteByte(dest++, CPUReadByte(windowOffset++));
len--;
if (len == 0)
return;
}
d <<= 1;
}
} else {
for (int i = 0; i < 8; i++) {
} else {
CPUWriteByte(dest++, CPUReadByte(source++));
len--;
if (len == 0)
return;
}

d <<= 1;

if (len <= 0) {
// This can happen if the parameter was incorrectly set. Real
// hardware does a buffer overflow so we do it here too.
break;
}
}
}

reg[0].I = source;
reg[1].I = dest;
reg[3].I = 0;
}

void BIOS_ObjAffineSet()
Expand Down Expand Up @@ -1695,6 +1682,13 @@ void BIOS_SndDriverVSync()

void BIOS_SndDriverVSyncOff() // 0x1878
{
#ifdef GBA_LOGGING
if (systemVerbose & VERBOSE_SWI) {
log("SndDriverVSyncOff: (VCOUNT = %2d)\n",
VCOUNT);
}
#endif

uint32_t const puser1 = CPUReadMemory(0x3007FF0); // 7FC0 + 0x30
uint32_t user1 = CPUReadMemory(puser1);

Expand All @@ -1718,6 +1712,20 @@ void BIOS_SndDriverVSyncOff() // 0x1878
//0x18b0
}

void BIOS_SndDriverVSyncOn()
{
#ifdef GBA_LOGGING
if (systemVerbose & VERBOSE_SWI) {
log("SndDriverVSyncOn: (VCOUNT = %2d)\n",
VCOUNT);
}
#endif

const uint16_t r1 = 0x8600; // 91 << 9
CPUWriteHalfWord(base1 + 0x6, r1);
CPUWriteHalfWord(base1 + 0x12, r1);
}

// This functions is verified but lacks proper register settings before calling user func
// it might be that user func modifies or uses those?
// r7 should be puser1, r6 should be flags, ....
Expand Down
1 change: 1 addition & 0 deletions src/gba/bios.h
Expand Up @@ -30,6 +30,7 @@ extern void BIOS_SndDriverMode();
extern void BIOS_SndDriverMain();
extern void BIOS_SndDriverVSync();
extern void BIOS_SndDriverVSyncOff();
extern void BIOS_SndDriverVSyncOn();
extern void BIOS_SndChannelClear();

#endif // BIOS_H

0 comments on commit e26f807

Please sign in to comment.