Merge pull request #7 from skidau/HLE-BIOS-SndDriver-PhantasyStarColl

HLE BIOS functions for sound driver
This commit is contained in:
skidau 2015-10-17 10:40:53 +11:00
commit 06ffccc3f9
3 changed files with 731 additions and 0 deletions

View File

@ -2342,6 +2342,28 @@ void CPUSoftwareInterrupt(int comment)
else
soundResume();
break;
case 0x1A:
BIOS_SndDriverInit();
SWITicks = 252000;
break;
case 0x1B:
BIOS_SndDriverMode();
SWITicks = 280000;
break;
case 0x1C:
BIOS_SndDriverMain();
SWITicks = 11050;//avg
break;
case 0x1D:
BIOS_SndDriverVSync();
SWITicks = 44;
break;
case 0x1E:
BIOS_SndChannelClear();
break;
case 0x28:
BIOS_SndDriverVSyncOff();
break;
case 0x1F:
BIOS_MidiKey2Freq();
break;

View File

@ -1108,6 +1108,709 @@ void BIOS_Sqrt()
#endif
}
#define ADBITS_MASK 0x3FU
u32 const base1 = 0x040000C0;
u32 const base2 = 0x04000080;
static bool BIOS_SndDriver_ba4(u32 r0, u32 r4r12) // 0xba4
{
if (r4r12)
{
r4r12 = r4r12 & ~0xFE000000;
r4r12 += r0;
if (!((r0 & 0x0E000000) && (r4r12 & 0x0E000000)))
return true;
}
return false;
}
static void BIOS_SndDriver_b4c(u32 r0, u32 r1, u32 r2) // 0xb4c
{
// @r4
u32 r4 = 4 * r2 & 0x7FFFFF;
bool ok = BIOS_SndDriver_ba4(r0, r4); // aka b9c
#if 0
int v3; // r4@1
int v4; // r0@1
int v5; // r1@1
int v6; // r2@1
char v7; // zf@1
signed int v8; // r5@2
int v9; // r5@4
int v10; // r3@6
int v11; // r3@10
unsigned int v12; // r4@11
unsigned short v13; // r3@13
#endif
// 0b56
if ( !ok )
{
u32 r5 = 0; //v8
if ( r2 >= (1<<(27-1)) ) //v6
{
r5 = r1 + r4;
if ( r2 >= (1<<(25-1)) )
{
u32 r3 = CPUReadMemory(r0);
while ( r1 < r5 )
{
CPUWriteMemory(r1, r3);
r1 += 4;
}
}
else // @todo 0b6e
{
#if 0
while ( v5 < v9 )
{
v11 = *(_DWORD *)v4;
v4 += 4;
*(_DWORD *)v5 = v11;
v5 += 4;
}
#endif
}
}
else // @todo 0b78
{
#if 0
v12 = (unsigned int)v3 >> 1;
if ( __CFSHR__(v6, 25) )
{
v13 = *(_WORD *)v4;
while ( v8 < (signed int)v12 )
{
*(_WORD *)(v5 + v8) = v13;
v8 += 2;
}
}
else
{
while ( v8 < (signed int)v12 )
{
*(_WORD *)(v5 + v8) = *(_WORD *)(v4 + v8);
v8 += 2;
}
}
#endif
}
}
// 0x0b96
}
static s32 BIOS_SndDriver_3e4(u32 const r0a, u32 const r1a) // 0x3e4
{
s32 r0 = r1a;
s32 r1 = r0a;
u32 v5 = r0 & 0x80000000;
s32 r12;
s32 r2;
bool gtr;
if ( (r1 & 0x80000000 & 0x80000000) != 0 )
r1 = -r1;
r12 = r0; //v5 ^ (r0 >> 32);
if ( r0 < 0 )
r0 = -r0;
r2 = r1;
do
{
gtr = (r2 >= r0 >> 1);
if ( r2 <= r0 >> 1 )
r2 *= 2;
} while ( !gtr );
while ( 1 )
{
v5 += (r0 >= (u32)r2) + v5;
if ( r0 >= (u32)r2 )
r0 -= r2;
if ( r2 == r1 )
break;
r2 = (u32)r2 >> 1;
}
if ( !(r12 << 1) )
return -v5;
else
return v5;
}
static void BIOS_SndDriverSub1(u32 p1) // 0x170a
{
u8 local1 = (p1 & 0x000F0000) >> 16; // param is r0
u32 const puser1 = CPUReadMemory(0x3007FF0); // 7FC0 + 0x30
// Store something
CPUWriteByte(puser1+8, local1);
u32 r0 = (0x31e8 + (local1 << 1)) - 0x20;
// @todo read from bios region
if (r0 == 0x31D0)
{
r0 = 0xE0;
}
else if (r0 == 0x31E0)
{
r0 = 0x2C0;
}
else r0 = CPUReadHalfWord(r0+0x1E);
CPUWriteMemory(puser1+0x10, r0);
u32 r1 = 0x630;
u32 const r4 = r0;
// 0x172c
r0 = BIOS_SndDriver_3e4(r0, r1);
CPUWriteByte(puser1+0xB, r0);
u32 x = 0x91d1b * r4;
r1 = x + 0x1388;
r0 = 0x1388 << 1;
r0 = BIOS_SndDriver_3e4(r0, r1);
CPUWriteMemory(puser1+0x14, r0);
r1 = 1 << 24;
r0 = BIOS_SndDriver_3e4(r0, r1) + 1;
r0 /= 2;
CPUWriteMemory(puser1+0x18, r0);
// 0x1750
u32 r4basesnd = 0x4000100;
r0 = r4;
r1 = 0x44940;
CPUWriteHalfWord(r4basesnd+2, 0);
r0 = BIOS_SndDriver_3e4(r0, r1);
r0 = (1<<16)-r0;
CPUWriteHalfWord(r4basesnd+0, r0);
// sub 0x18c8 is unrolled here
r1 = 0x5b << 9;
CPUWriteHalfWord(base1+6 , r1);
CPUWriteHalfWord(base1+12 , r1);
// 0x176a, @todo busy loop here
r0 = 0x4000000;
//do
{
r1 = CPUReadByte(r0+6);
} //while (r1 != 0x9F);
CPUWriteHalfWord(r4basesnd+2, 0x80);
}
void BIOS_SndDriverInit() // 0x166a
{
#ifdef GBA_LOGGING
if(systemVerbose & VERBOSE_SWI) {
log("SndDriverInit: WaveData=%08x mk=%08x fp=%08x\n",
reg[0].I,
reg[1].I,
reg[2].I);
}
#endif
// 7FC0 + 0x30
u32 const puser1 = 0x3007FF0;
u32 const user1 = reg[0].I;
u32 base3 = 0x040000BC;
//u32 base4 = 0x03007FF0;
CPUWriteHalfWord(base1+6 , 0);
CPUWriteHalfWord(base1+12, 0);
CPUWriteHalfWord(base2+4, 0x8F);
CPUWriteHalfWord(base2+2, 0xA90E);
u16 val9 = CPUReadHalfWord(base2+9);
CPUWriteHalfWord(base2+9, val9&ADBITS_MASK); // DA?
CPUWriteMemory(base3+0, (user1 + 0x350)); //0x350, 640int
CPUWriteMemory(base1+0, 0x40000A0);
CPUWriteMemory(base1+8, 2224); //0x980
CPUWriteMemory(base1+12, 0x40000A4);
CPUWriteMemory(puser1, user1);
u32 const r2 = 0x050003EC;
u32 const sp = reg[13].I; // 0x03003c98;
CPUWriteMemory(sp, 0);
BIOS_SndDriver_b4c(sp, user1, r2);
// 0x16b0
CPUWriteByte(user1+0x6, 0x8);
CPUWriteByte(user1+0x7, 0xF);
CPUWriteMemory(user1+0x38, 0x2425);
CPUWriteMemory(user1+0x28, 0x1709);
CPUWriteMemory(user1+0x2C, 0x1709);
CPUWriteMemory(user1+0x30, 0x1709);
CPUWriteMemory(user1+0x3C, 0x1709);
CPUWriteMemory(user1+0x34, 0x3738);
BIOS_SndDriverSub1(0x40000);
CPUWriteMemory(user1, 0x68736D53); // this ret is common among funcs
}
void BIOS_SndDriverMode() //0x179c
{
u32 input = reg[0].I;
u32 const puser1 = CPUReadMemory(0x3007FF0); // 7FC0 + 0x30
u32 user1 = CPUReadMemory(puser1);
if ( user1 == 0x68736D53 )
{
CPUWriteMemory(puser1, (++user1)); // this guard is common for funcs, unify
// reverb values at bits 0...7
u8 revb = (input & 0xFF);
if ( revb )
{
revb>>=1; // shift out the 7th enable bit
CPUWriteByte(puser1+5, revb);
}
// direct sound multi channels at bits 8...11
u8 chc = (input & 0xF00)>>8;
if ( chc > 0 )
{
CPUWriteByte(puser1+6, chc);
u32 puser2 = puser1 + 7 + 0x49;
int count=12;
while (count--)
{
CPUWriteByte(puser2, 0);
puser2+=0x40;
}
}
// direct sound master volume at bits 12...15
u8 chv = (input & 0xF000)>>12;
if ( chv > 0 )
{
CPUWriteByte(puser1+7, chv);
}
// DA converter bits at bits 20...23
u32 dab = (input & 0x00B00000);
if ( dab )
{
dab &= 0x00300000;
dab >>= 0xE;
u8 adv = CPUReadByte(puser1+9) & ADBITS_MASK; // @todo verify offset
dab |= adv;
CPUWriteByte(puser1+9, dab);
}
// Playback frequency at bits 16...19
u32 pbf = (input & 0x000F0000);
if ( pbf )
{
// Modifies puser1/user1
BIOS_SndDriverVSyncOff();
// another sub at 180c
BIOS_SndDriverSub1(pbf);
}
CPUWriteMemory(puser1, (--user1));
}
}
void BIOS_SndDriverMain() // 0x1dc4 -> 0x08004024 phantasy star
{
//// Usually addr 0x2010928
u32 const puser1 = CPUReadMemory(0x3007FF0); // 7FC0 + 0x30, //@+sp14
u32 user1 = CPUReadMemory(puser1);
if ( user1 != 0x68736D53 )
return;
// main
CPUWriteMemory(puser1, (++user1)); // this guard is common for funcs, unify
int const user2 = CPUReadMemory(puser1 + 0x20);
if ( user2 )
{
int const par1 = CPUReadMemory(puser1 + 0x24);
// Call 0x2102 sub_16A8 - -> param r1
}
int const userfunc = CPUReadMemory(puser1 + 0x28);
switch (userfunc)
{
case 0x1709: //phantasy star
default:
break;
}
u32 const v2 = CPUReadMemory(puser1 + 0x10); //r8
u8 const user4 = CPUReadByte(puser1+4) - 1;
u32 user41 = 0;
if ( user4 > 0 )
{
user41 = CPUReadByte(puser1 + 0x0B);
user41 -= user4;
user41 *= v2;
}
u32 r5;
u32 const r5c = puser1 + 0x350 + user41; //r5 @sp+8
int user6 = r5c + 0x630; //r6
int user5 = CPUReadByte(puser1 + 0x5); //r3
if ( user5 )
{
// @todo 0x1e1a
}
else // 0x1e74
{
r5 = r5c;
int count = v2>>4; //r1...v13
if ( !(v2 >> 3) )
{
CPUWriteMemory(r5, 0);
CPUWriteMemory(user6, 0);
r5+=4; user6+=4;
}
if ( !(v2 >> 1) ) //0x1e7c
{
CPUWriteMemory(r5, 0);
CPUWriteMemory(user6, 0);
r5+=4; user6+=4;
CPUWriteMemory(r5, 0);
CPUWriteMemory(user6, 0);
r5+=4; user6+=4;
}
do // 0x1e8e
{
// @todo optimize this memset
CPUWriteMemory(r5, 0);
CPUWriteMemory(user6, 0);
r5+=4; user6+=4;
CPUWriteMemory(r5, 0);
CPUWriteMemory(user6, 0);
r5+=4; user6+=4;
CPUWriteMemory(r5, 0);
CPUWriteMemory(user6, 0);
r5+=4; user6+=4;
CPUWriteMemory(r5, 0);
CPUWriteMemory(user6, 0);
r5+=4; user6+=4;
count -= 1;
} while (count > 0);
}
//0x1ea2
u32 r4 = puser1; // apparenty ch ptr?
int r9 = CPUReadMemory(r4+0x14);
int r12 = CPUReadMemory(r4+0x18);
u32 i = CPUReadByte(r4+0x6);
for (r4+=0x10; i > 0; i-- )
{
r4+=0x40;
/*lbl_0x1eb0:*/
u32 r3 = CPUReadMemory(r4+0x24);
u8 r6 = CPUReadByte(r4);
if ( (r6 & 0xC7) == 0 ) // 0x1ebc
continue; //goto lbl_20e4;
if ( (r6 & 0x80) && ((r6 & 0x40) == 0) ) // 0x1ec4
{
r6 = 0x3;
CPUWriteByte(r4, r6);
CPUWriteMemory(r4+0x28, r3+0x10);
int r0t1 = CPUReadMemory(r3+0xC);
CPUWriteMemory(r4+0x18, r0t1);
r5=0;
CPUWriteByte(r4+0x9, 0);
CPUWriteMemory(r4+0x1c, 0);
u8 r2a = CPUReadByte(r3+0x3); // seems to be LABEL_20e4
if ((r2a & 0xC0)) // 1ee4
{
}
goto lbl_0x1f46;
}
else
{
//lbl_0x1eee:
r5 = CPUReadByte(r4+0x9); //
if ( (r6 & 0x4) != 0) // @todo 0x1ef4
{
}
if ( (r6 & 0x40) != 0) // @todo 0x1f08
{
}
if ( (r6 & 0x03) == 2) // 0x1f2a
{
u8 mul1 = CPUReadByte(r4+0x5);
r5*=mul1;
r5>>=8;
u8 cmp1 = CPUReadByte(r4+0x6);
if (r5 <= cmp1)
{
r5=cmp1;
// @todo beq @ 0x1f3a -> ??
r6--;
CPUWriteByte(r4, r6);
}
}
else if ( (r6 & 0x03) == 3) // 0x1f44
{
lbl_0x1f46: //@todo check if there is really another path to here
u8 add1 = CPUReadByte(r4+0x4);
r5+=add1;
if (r5>=0xff)
{
r6--;
r5=0xff;
CPUWriteByte(r4, r6);
}
}
}
{
//lbl_0x1f54:
CPUWriteByte(r4+0x9, r5);
u32 user0 = CPUReadByte(puser1+0x7); // @sp+10
user0++;
user0*=r5;
r5=user0>>4;
user0 = CPUReadByte(r4+0x2);
user0*=r5;
user0>>=8;
CPUWriteByte(r4+0xA, user0);
user0 = CPUReadByte(r4+0x3);
user0*=r5;
user0>>=8;
CPUWriteByte(r4+0xB, user0);
user0 = r6&0x10;
if ( user0 != 0) // @todo 0x1f76
{
}
r5 = r5c; // @todo below r5 is used and updated
u32 r2 = CPUReadMemory(r4+0x18);
r3 = CPUReadMemory(r4+0x28);
u32 r8 = v2;
u8 r10 = CPUReadByte(r4+0xA);
u8 r11 = CPUReadByte(r4+0xB);
u8 r0a = CPUReadByte(r4+0x1);
if ((r0a & 8)) //@todo 0x1fa8
{
}
u32 r7 = CPUReadMemory(r4+0x1c);
u32 r14 = CPUReadMemory(r4+0x20);
lbl_0x2004:// LABEL_52:
while ( r7 >= 4 * r9 )
{
if ( r2 <= 4 )// @todo 0x2008, no phant
goto lbl_204c;
r2 -= 4;
r3 += 4;
r7 -= 4 * r9;
}
if ( r7 >= 2 * r9 )
{
if ( r2 <= 2 ) // @todo 0x2008, no phant
goto lbl_204c;
r2 -= 2;
r3 += 2;
r7 -= 2 * r9;
}
if ( r7 < r9 )
goto lbl_207c;
do
{
lbl_204c: // LABEL_59:
--r2;
if ( r2 )
{
++r3;
}
else
{
r2 = user0; //0x2054
if ( r2 )
{
r3 = CPUReadMemory(reg[13].I+0xC); // @todo stack pull 0x205c
}
else
{
CPUWriteByte(r4, r2);
goto lbl_20e4;
}
}
r7 -= r9;
} while ( r7 >= r9 );
lbl_207c:
while ( 1 )
{
s32 r0a = CPUReadByte(r3);
s32 r1a = CPUReadByte(r3+0x1);
r1a-=r0a;
s32 r6a = r1a*(s32)r7;
r1a = r6a * r12; // 208c
r6a = (r0a + ((s8)(r1a>>23)));
r1a = r6a * (s32)r11;
r0a = CPUReadByte(r5 + 0x630);
r0a = (r0a + ((s8)(r1a>>8)));
CPUWriteByte(r5 + 0x630, r0a);
r1a = r6a * (s32)r10;
r0a = CPUReadByte(r5);
r0a = (r0a + ((s8)(r1a>>8)));
CPUWriteByte(r5++, r0a); //ptr inc +1 not +4
r7+=r14;
--r8;
if ( !r8 )
break;
if ( r7 >= r9 )
goto lbl_0x2004;
}
CPUWriteMemory(r4+0x1c, r7);
//lbl_20cc:
CPUWriteMemory(r4+0x18, r2);
CPUWriteMemory(r4+0x28, r3);
}
lbl_20e4:
(void)r5;
}
// 0x20EE
CPUWriteMemory(puser1, 0x68736D53); // this guard is common for funcs, unify
}
// fully implemented @ 0x210c
void BIOS_SndDriverVSync()
{
u32 const puser1 = CPUReadMemory(0x3007FF0); // @todo some sound area, make it common.
u32 const user1 = CPUReadMemory(puser1);
if ( user1 == 0x68736D53 )
{
u8 v1 = CPUReadByte(puser1+4);
s8 v1i = v1-1;
CPUWriteByte(puser1+4, v1i);
if ( v1 <= 1 )
{
u8 v2 = CPUReadByte(puser1+0xB); //11
u32 base2 = 0x040000D2;
CPUWriteByte(puser1+4, v2);
CPUWriteHalfWord(base1+0x6 , 0);
CPUWriteHalfWord(base2, 0);
CPUWriteHalfWord(base1+0x6 , 0xB600);
CPUWriteHalfWord(base2, 0xB600); //-18944
}
}
}
void BIOS_SndDriverVSyncOff() // 0x1878
{
u32 const puser1 = CPUReadMemory(0x3007FF0); // 7FC0 + 0x30
u32 user1 = CPUReadMemory(puser1);
if ( user1 == 0x68736D53 || user1 == 0x68736D54 )
{
CPUWriteMemory(puser1, (++user1)); // this guard is common for funcs, unify
CPUWriteHalfWord(base1+0x6 , 0);
CPUWriteHalfWord(base1+0x12 , 0);
CPUWriteByte(puser1+4, 0);
u32 r1 = puser1+0x350;
u32 r2 = 0x05000318;
u32 sp = reg[13].I; //0x03003c94;
CPUWriteMemory(sp, 0);
BIOS_SndDriver_b4c(sp, r1, r2);
user1 = CPUReadMemory(puser1); // 0x18aa
CPUWriteMemory(puser1, (--user1)); // this ret is common among funcs
}
//0x18b0
}
// 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, ....
void BIOS_SndChannelClear() //0x1824
{
u32 const puser1 = CPUReadMemory(0x3007FF0); // 7FC0 + 0x30
u32 user1 = CPUReadMemory(puser1);
if ( user1 == 0x68736D53 )
{
CPUWriteMemory(puser1, (++user1));
u32 puser2 = puser1 + 0x7 + 0x49;
int count=12;
while (count--)
{
CPUWriteByte(puser2, 0);
puser2+=0x40;
}
reg[4].I = CPUReadMemory(puser1 + 0x1c); //r5 -> some user thing
if ( reg[4].I != 0 )
{
reg[3].I = 1; // r4 -> channel counter?
int puser4 = puser1 + 0x2c;
//reg[0].I = reg[3].I = 1; // r0 & r4 => 1
while (reg[3].I <= 4)
{
// @todo does user func modify these?
reg[0].I = reg[3].I << 24;
reg[0].I >>= 24;
// Get ptr to user func
reg[1].I = CPUReadMemory(puser4);
// @todo here we jump where r1 points; user func?
// @todo might modify r6 also?
// After call routines
reg[3].I += 1; // r4 -> channel counter?
reg[4].I += 0x40;// r5 -> some user thing
}
CPUWriteByte(reg[4].I, 0); // terminating record?
}
CPUWriteMemory(puser1, 0x68736D53);
}
}
void BIOS_MidiKey2Freq()
{
#ifdef GBA_LOGGING

View File

@ -25,5 +25,11 @@ extern void BIOS_SoftReset();
extern void BIOS_Sqrt();
extern void BIOS_MidiKey2Freq();
extern void BIOS_SndDriverJmpTableCopy();
extern void BIOS_SndDriverInit();
extern void BIOS_SndDriverMode();
extern void BIOS_SndDriverMain();
extern void BIOS_SndDriverVSync();
extern void BIOS_SndDriverVSyncOff();
extern void BIOS_SndChannelClear();
#endif // BIOS_H