mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2024-12-28 14:24:31 +01:00
0a3c150f69
hle the gba ucode git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6046 8ced0084-cf51-0410-be5f-012b33b47a6e
5095 lines
161 KiB
Plaintext
5095 lines
161 KiB
Plaintext
/* ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
/* ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
All code is now wrapped in void Function() {} - the new DSP LLE debugger
|
|
can parse this file and auto read symbols using those.
|
|
|
|
BIG Questions:
|
|
|
|
- Who resets the 0x0350 to the beginning of the command block? Wrap register?
|
|
- What does 00eb_Unk_BufferMultAddToDest??
|
|
- Why is a PB-Transfer from RAM to DMEM 0xC0 shorts long but DMEM to RAM just 0x80
|
|
|
|
DSP functionality to test:
|
|
- Interrupts (7)
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// */
|
|
//
|
|
// memory map
|
|
// todo - define syntax for this so it can be auto read.
|
|
|
|
//
|
|
0x0000 to 0x280 // Unknown table
|
|
0x0280 // command queue
|
|
|
|
///////////////////////////////////////////
|
|
|
|
0x0300 to 0x0320 // AFC COEF table
|
|
|
|
0x0342 // low part of the DSetupTable /(Luigi2us) thinks it is the number of PBs
|
|
0x0343 // current command code (the code for the switch - casement table) seems to be for debug... nobody loads it
|
|
0x0344 // high part of the (command & 0xFF) ... prolly some kind of paramter
|
|
0x0345 // low part of the command
|
|
|
|
0x034e (0x0000)
|
|
|
|
///////////////////////////////////////////
|
|
|
|
|
|
|
|
///////////////////////////////////////////
|
|
// Initialized at 0688_InitCommandBlock()
|
|
0x0350 (0x0280) // address to end of the command queue
|
|
0x0351 (0x0280) // address to start of the command queue
|
|
0x0352 (0x0000) // number of commands
|
|
|
|
|
|
0x0356[] // current command queue... eg: 0x81000040 for DsetupTable
|
|
0x0358 // first parameter of the command ...
|
|
|
|
|
|
0x0364 // Temp Buffer for AFC Decoder
|
|
|
|
///////////////////////////////////////////
|
|
0x0380 // RAM Address of the PBs
|
|
0x0381 //
|
|
|
|
0x038e // used by COMMAND_02 copies the low part of the command to this place
|
|
|
|
|
|
0x03a8 // COMMAND_02 copies a struct with the size of 0x40 to the place
|
|
|
|
///////////////////////////////////////////
|
|
// used by 05b8_NewMail() exception to store register and restore registers
|
|
0x03fa to 0x03ff
|
|
|
|
// shared and used by COMMAND_01 (DSetupTable)
|
|
0x03f0 // 0x00
|
|
0x03f1 // 0x96
|
|
0x03f2 // 0xFF
|
|
0x03f3 // 0x30
|
|
0x03f5 // 0x10
|
|
0x03f6 // 0x00
|
|
0x03f7 // 0x100 ... got some more math... have to recheck it
|
|
|
|
|
|
0x03f9 // used by COMMAND_02... if the program decides to continue the UCode it stores the continue address...
|
|
|
|
//////////////////////////////////////////////
|
|
// current PB in DSyncFrame
|
|
0x0400
|
|
.
|
|
.
|
|
.
|
|
0x04C0
|
|
|
|
|
|
///
|
|
0x0400 - must be != 0 to be a valid block
|
|
0x0401 - must be != 0 to be a valid block
|
|
|
|
0x0402 - Sample Decode Offset ?? Offset = (*0x402 * 0x50)
|
|
|
|
0x0404 - Initialize Sample Decoder
|
|
0x0406 - Direct Stream ... no sample decoder is needed.
|
|
At the end of the PB Handling 0x0404 is set to 0 if it is NOT a direct stream
|
|
|
|
0x0430 - Base Address ?? (0x0430 + Offset) << 4
|
|
|
|
0x042c flag if > 0 033d_unk() does something
|
|
|
|
|
|
0x0433 stored to 0x03f8 ... i think that is the current sample buffer
|
|
|
|
0x0458 hmmm....
|
|
|
|
0x0480 if 0x0406 is zero check how we have to decode this data...
|
|
|
|
0x0484 seems to contain filter settings...
|
|
0x0484 & 0x1f -> (02ed to 030f)
|
|
0x0484 & 0x20
|
|
|
|
0x04a8 if != zero sample is modified with function at 0x0c84.. perhaps an filter or volume
|
|
|
|
|
|
////////////////////////////////////////
|
|
0x04d3 "offset to sample data" ????
|
|
|
|
There's definitely a bunch of sample data stored in each PB but I don't know exactly how.
|
|
|
|
|
|
///////////////////////////////////////////
|
|
// Initialized at 0e14_Unk()
|
|
0x04e8 (0x8240)
|
|
0x04e9 (0x7FFF)
|
|
0x04ea (0x7DBF)
|
|
0x04eb (0x843f)
|
|
0x04ec (0x0000)
|
|
0x04ed (0x0000)
|
|
0x04ee (0x0000)
|
|
0x04ef (0x0000)
|
|
|
|
0x04f0 (0xb23b)
|
|
0x04f1 (0x7FFF)
|
|
0x04f2 (0x4dc4)
|
|
0x04f3 (0xd808)
|
|
0x04f4 (0x0000)
|
|
0x04f5 (0x0000)
|
|
0x04f6 (0x0000)
|
|
0x04f7 (0x0000)
|
|
|
|
///////////////////////////////////////////
|
|
0x04fc... // used for some kind of data exchange between SyncFrame and MailExceptionHandler
|
|
// It is like this:
|
|
// (0x04fc + lastRenderedFrame) must be "something" :)
|
|
|
|
0x0580.. Unresampled audio data is decoded to here
|
|
|
|
///////////////////////////////////////////
|
|
// Initialized at 04c0_Unk()... used by SyncFrame
|
|
0x0B00 to 0x0C00
|
|
// The memory at 0b00 seems to be generally used as scratch space for various things.
|
|
|
|
|
|
//////////////////////////////////////////
|
|
|
|
0x0dc0 -- ??????????
|
|
|
|
|
|
//
|
|
// exception vector
|
|
//
|
|
0000 029f 0012 jmp 0x0012 -> ResetVector()
|
|
0002 0000 nop
|
|
0003 0000 nop
|
|
0004 02ff rti
|
|
0005 0000 nop
|
|
0006 02ff rti
|
|
0007 0000 nop
|
|
0008 02ff rti
|
|
0009 0000 nop
|
|
000a 02ff rti
|
|
000b 0000 nop
|
|
000c 02ff rti
|
|
000d 0000 nop
|
|
000e 029f 05b8 jmp 0x05b8 -> 05b8_NewMail()
|
|
|
|
0010 029f 004e jmp 0x004e -> 004e_ContinueUCode() ???
|
|
|
|
// reset vector
|
|
|
|
void 0012_ResetVector()
|
|
{
|
|
// 0012 1205 sbclr #0x05
|
|
|
|
// 0013 02bf 0057 call 0x0057
|
|
0057_InitHardware()
|
|
|
|
/*
|
|
0015 8100 clr $ACC0
|
|
0016 009f 1000 lri $AC1.M, #0x1000
|
|
0018 0080 0000 lri $AR0, #0x0000
|
|
001a 005f loop $AC1.M
|
|
001b 1b1e srri @$AR0, $AC0.M
|
|
Clear memory
|
|
*/
|
|
{
|
|
short ACC0 = 0;
|
|
short AR0 = 0x0000;
|
|
for (int i=0; i<0x1000; i++)
|
|
{
|
|
*AR0 = ACC0;
|
|
AR0++;
|
|
}
|
|
}
|
|
|
|
// 001c 02bf 0688 call 0x0688
|
|
0688_InitCommandBlock();
|
|
|
|
// 001e 02bf 04c0 call 0x04c0
|
|
04c0_UnknownInit();
|
|
|
|
// 0020 02bf 0e14 call 0x0e14
|
|
0e14_DolbyInit(); // Init from 0x04e8 to 0x04f8
|
|
|
|
// 0022 0e00 lris $AC0.M, #0x00
|
|
// 0023 02bf 066a call 0x066a
|
|
SendMB_DCD1(0x0000)
|
|
|
|
// 0025 009e 1111 lri $AC0.M, #0x1111
|
|
// 0027 02bf 0674 call 0x0674
|
|
SendMB_F355(0x1111)
|
|
|
|
// 0029 0e00 lris $AC0.M, #0x00
|
|
// 002a 00fe 034e sr @0x034e, $AC0.M
|
|
*0x034e = 0x00
|
|
|
|
002c 1305 sbset #0x05
|
|
|
|
// 002d 029f 06c5 jmp 0x06c5
|
|
|
|
//
|
|
// an exception will be raised if a new mail is inside the mailbox
|
|
// the exception handler will copy the command to an address and the
|
|
// 06c5_CopyCommandBlock creates a copy of the command to 0x0356
|
|
//
|
|
:WaitForNewCommandBlock
|
|
while (06c5_CopyCommandBlock() == 0x002d);
|
|
|
|
// 002f 00df 0357 lr $AC1.M, @0x0357
|
|
// 0031 00ff 0345 sr @0x0345, $AC1.M
|
|
|
|
*0x0345 = *0x0357
|
|
|
|
// 0033 00de 0356 lr $AC0.M, @0x0356
|
|
// 0035 1ffe mrr $AC1.M, $AC0.M
|
|
// 0036 0340 00ff andi $AC1.M, #0x00ff
|
|
// 0038 00ff 0344 sr @0x0344, $AC1.M
|
|
|
|
short upperCommand = *0x0356 // AC0 = upperCommand
|
|
*0x0344 = upperCommand & 0x00FF
|
|
|
|
// 003a 1479 lsr $ACC0, #-7
|
|
// 003b 0240 007e andi $AC0.M, #0x007e
|
|
// 003d 00fe 0343 sr @0x0343, $AC0.M
|
|
upperCommand = (upperCommand >> 7) & 0x7e // F|RES: i think duddy is wrong here ... a negative must be a shift right
|
|
*0x0343 = upperCommand
|
|
|
|
// 003f 0200 0075 addi $AC0.M, #0x0075
|
|
// 0041 1c1e mrr $AR0, $AC0.M
|
|
// 0042 170f jmpr $AR0
|
|
// switch casement of the commands.. jump table is at 0075
|
|
|
|
switch (upperCommand >> 1) // command must be shift >> 1 in our source code because the jump table is aligned with 2 Bytes
|
|
{
|
|
// case 0x00: 0x0043
|
|
case 0x01: 0095_COMMAND_01(); break;
|
|
case 0x02: 0243_COMMAND_02(); break;
|
|
|
|
case 0x03: 0x0073
|
|
case 0x04: 0095_COMMAND_04(); break;
|
|
case 0x05: 0x0592
|
|
case 0x06: 0x0469
|
|
case 0x07: 0x041d
|
|
case 0x08: 0x0485
|
|
case 0x09: 0x044d
|
|
// case 0x0A: 0x0043
|
|
// case 0x0B: 0x0043
|
|
// case 0x0C: 0x0043
|
|
case 0x0D: 0x00b2
|
|
// case 0x0E: 0x0043
|
|
// case 0x0F: 0x0043
|
|
}
|
|
|
|
# 0043 0092 00ff lri $CR, #0x00ff
|
|
|
|
// 0045 0e04 lris $AC0.M, #0x04
|
|
// 0046 02bf 066a call 0x066a
|
|
SendMB_DCD1(0x0004)
|
|
|
|
// 0048 00de 0356 lr $AC0.M, @0x0356
|
|
// 004a 02bf 0674 call 0x0674
|
|
SendMB_F355(@0x0356)
|
|
|
|
// 004c 029f 002d jmp 0x002d
|
|
GOTO :WaitForNewCommandBlock
|
|
}
|
|
|
|
void 004e_ContinueUCode??()
|
|
{
|
|
# 004e 1205 sbclr #0x05
|
|
|
|
// 004f 02bf 0057 call 0x0057
|
|
0057_InitHardware()
|
|
|
|
// 0051 0e01 lris $AC0.M, #0x01
|
|
// 0052 02bf 066a call 0x066a
|
|
SendMB_DCD1(0x0001)
|
|
|
|
# 0054 1305 sbset #0x05
|
|
|
|
// 0055 029f 002d jmp 0x002d
|
|
GOTO :WaitForNewCommandBlock
|
|
}
|
|
|
|
void 0057_InitHardware()
|
|
{
|
|
0057 1202 sbclr #0x02
|
|
0058 1203 sbclr #0x03
|
|
0059 1204 sbclr #0x04
|
|
005a 1306 sbset #0x06
|
|
005b 8e00 set16
|
|
005c 8c00 clr15
|
|
005d 8b00 m0
|
|
|
|
// Set all indexing wrappers to max range.
|
|
005e 009e ffff lri $AC0.M, #0xffff
|
|
0060 1d1e mrr $WR0, $AC0.M
|
|
0061 1d3e mrr $WR1, $AC0.M
|
|
0062 1d5e mrr $WR2, $AC0.M
|
|
0063 1d7e mrr $WR3, $AC0.M
|
|
|
|
// Have CR point to the HW interface.
|
|
0064 0092 00ff lri $CR, #0x00ff
|
|
// 0066 02df ret
|
|
}
|
|
|
|
void 0067_CopyCommand(_destAddr($AR0), _loopCount($AC0.M))
|
|
{
|
|
// 0067 0090 0000 lri $AC0.H, #0x0000
|
|
// 0069 0c00 lris $AC0.L, #0x00
|
|
// 006a 0081 0358 lri $AR1, #0x0358
|
|
AC0.H = 0x0000
|
|
AC0.L = 0x00
|
|
AR1 = 0x0358
|
|
|
|
// 006c 007e 0071 bloop $AC0.M, 0x0071
|
|
// 006e 193e lrri $AC0.M, @$AR1
|
|
// 006f 1b1e srri @$AR0, $AC0.M
|
|
// 0070 193e lrri $AC0.M, @$AR1
|
|
// 0071 1b1e srri @$AR0, $AC0.M
|
|
|
|
for (int i=0; i<_loopCount; i++)
|
|
{
|
|
*_destAddr++ = *AR1.M++
|
|
*_destAddr++ = *AR1.M++
|
|
}
|
|
|
|
// 0072 02df ret
|
|
}
|
|
|
|
/*
|
|
0073 029f 0043 jmp 0x0043
|
|
0075 029f 0043 jmp 0x0043
|
|
0077 029f 0095 jmp 0x0095
|
|
0079 029f 0243 jmp 0x0243
|
|
007b 029f 0073 jmp 0x0073
|
|
007d 029f 0580 jmp 0x0580
|
|
007f 029f 0592 jmp 0x0592
|
|
0081 029f 0469 jmp 0x0469
|
|
0083 029f 041d jmp 0x041d
|
|
0085 029f 0485 jmp 0x0485
|
|
0087 029f 044d jmp 0x044d
|
|
0089 029f 0043 jmp 0x0043
|
|
008b 029f 0043 jmp 0x0043
|
|
008d 029f 0043 jmp 0x0043
|
|
008f 029f 00b2 jmp 0x00b2
|
|
0091 029f 0043 jmp 0x0043
|
|
0093 029f 0043 jmp 0x0043
|
|
jump table for command code decoding
|
|
*/
|
|
|
|
// DsetupTable
|
|
void 0095_COMMAND_01()
|
|
{
|
|
// 0095 0080 0380 lri $AR0, #0x0380
|
|
// 0097 0e04 lris $AC0.M, #0x04
|
|
// 0098 02bf 0067 call 0x0067
|
|
0067_CopyCommand(0x0380, 0x04)
|
|
|
|
// 009a 0081 0382 lri $AR1, #0x0382
|
|
// 009c 009f 0000 lri $AC1.M, #0x0000
|
|
// 009e 0080 0280 lri $AR0, #0x0280
|
|
// 00a0 02bf 0523 call 0x0523
|
|
0523_CopyRAMtoDMEM(0x0382, 0x0000, 0x0280)
|
|
|
|
// 00a2 0081 0384 lri $AR1, #0x0384
|
|
// 00a4 009f 0300 lri $AC1.M, #0x0300
|
|
// 00a6 0080 0020 lri $AR0, #0x0020
|
|
// 00a8 02bf 0523 call 0x0523
|
|
0523_CopyRAMtoDMEM(0x0384, 0x0300, 0x0020)
|
|
|
|
// 00aa 00de 0345 lr $AC0.M, @0x0345
|
|
// 00ac 00fe 0342 sr @0x0342, $AC0.M
|
|
*0x0342 = *0x0345
|
|
|
|
// 00ae 02bf 0bec call 0x0bec
|
|
0bec_Unk()
|
|
|
|
// 00b0 029f 0043 jmp 0x0043
|
|
}
|
|
|
|
// Command 0xD
|
|
void 00b2_Unk_CommandD() {
|
|
00b2 0080 0374 lri $AR0, #0x0374
|
|
00b4 0e01 lris $AC0.M, #0x01
|
|
00b5 00fe 0377 sr @0x0377, $AC0.M
|
|
00b7 00fe 037c sr @0x037c, $AC0.M
|
|
00b9 02bf 0067 call 0x0067 // CopyCommand
|
|
|
|
// 00bb 00de 0345 lr $AC0.M, @0x0345
|
|
// 00bd 00fe 0376 sr @0x0376, $AC0.M
|
|
*0x0376 = *0x0345;
|
|
|
|
00bf 029f 0043 jmp 0x0043
|
|
}
|
|
|
|
void 00c1_CopyPBToDMEM()
|
|
{
|
|
// 00c1 0081 034c lri $AR1, #0x034c
|
|
// 00c3 009f 0400 lri $AC1.M, #0x0400
|
|
// 00c5 0080 00c0 lri $AR0, #0x00c0
|
|
// 00c7 02bf 0523 call 0x0523
|
|
// 00c9 02df ret
|
|
|
|
0523_CopyRAMtoDMEM(0x034c, 0x0400, 0x00c0);
|
|
}
|
|
|
|
|
|
void 00ca_CopyPBToRAM()
|
|
{
|
|
// 00ca 0081 034c lri $AR1, #0x034c
|
|
// 00cc 009f 0400 lri $AC1.M, #0x0400
|
|
// 00ce 0080 0080 lri $AR0, #0x0080
|
|
// 00d0 0081 034c lri $AR1, #0x034c
|
|
AR1 = 0x034c
|
|
AC1.M = 0x0400
|
|
AR0 = 0x0080
|
|
|
|
// 00d2 193e lrri $AC0.M, @$AR1
|
|
// 00d3 193c lrri $AC0.L, @$AR1
|
|
AC0.M = *0x034c
|
|
AC0.L = *0x034d
|
|
|
|
// 00d4 0098 0000 lri $AX0.L, #0x0000
|
|
// 00d6 7000 addaxl $ACC0, $AX0.L
|
|
// 00d7 02bf 0532 call 0x0532
|
|
|
|
0532_DMEMtoRAM(0x0400, ACC0, 0x0080)
|
|
|
|
// 00d9 02df ret
|
|
}
|
|
|
|
|
|
void 00da_CopyBuffer(_src($AR0), _dest($AR3), LenMinusOne(_AC1.M))
|
|
{
|
|
00da 191e lrri $AC0.M, @$AR0
|
|
00db 191a lrri $AX0.H, @$AR0
|
|
00dc 005f loop $AC1.M
|
|
00dd 64a0 movr'ls $ACC0, $AX0.H : $AX0.H, $AC0.M
|
|
00de 1b7e srri @$AR3, $AC0.M
|
|
00df 1b7a srri @$AR3, $AX0.H
|
|
// 00e0 02df ret
|
|
}
|
|
|
|
|
|
void 00e1_XorBuffer( .., _LenInDWORDs(_AC1.M)) {
|
|
00e1 191e lrri $AC0.M, @$AR0
|
|
00e2 191a lrri $AX0.H, @$AR0
|
|
// 00e3 007f 00e8 bloop $AC1.M, 0x00e8
|
|
for (int i = 0; i < AC1.M; i++) {
|
|
00e5 32b2 xorr'sl $AC0.M, $AX1.H : $AC0.M, $AX1.H
|
|
00e6 65a0 movr'ls $ACC1, $AX0.H : $AX0.H, $AC0.M
|
|
00e7 33ba xorr'slm $AC1.M, $AX1.H : $AC0.M, $AX1.H
|
|
00e8 64a1 movr'ls $ACC0, $AX0.H : $AX0.H, $AC1.M
|
|
}
|
|
// 00e9 0000 nop
|
|
// 00ea 02df ret
|
|
}
|
|
|
|
|
|
// --- the disasm looks buggy... AR3 seems to be the destination but it isnt used at all... no idea
|
|
// Hm, SL actually is able to use AR3 implicitly.
|
|
void 00eb_Unk_BufferMultAddToDest(_Src=($AR0), _Dest($AR3), _size($AC1.M), _factor($AX0.L))
|
|
{
|
|
// 00eb 8a00 m2 // All multiplication results are multiplied by 2.
|
|
// 00ec 157f lsr $ACC1, #-1 //_size/2
|
|
00ed 1c20 mrr $AR1, $AR0
|
|
00ee 1c03 mrr $AR0, $AR3 // 'sl stores to AR0
|
|
|
|
// SW pipelineing strikes again...
|
|
00ef 193a lrri $AX0.H, @$AR1
|
|
00f0 9051 mul'l $AX0.L, $AX0.H : $AX0.H, @$AR1
|
|
00f1 925b mulmvz'l $AX0.L, $AX0.H, $ACC0 : $AX1.H, @$AR3
|
|
// 00f2 007f 00f7 bloop $AC1.M, 0x00f7
|
|
for (int i = 0; i < _size/2; i++) {
|
|
AX0.H = *AR1;
|
|
PROD = *
|
|
// 00f4 4651 addr'l $ACC0, $AX1.H : $AX0.H, @$AR1
|
|
// 00f5 92b2 mulmvz'sl $AX0.L, $AX0.H, $ACC0 : $AC0.M, $AX1.H
|
|
// 00f6 4651 addr'l $ACC0, $AX1.H : $AX0.H, @$AR1
|
|
// 00f7 92b2 mulmvz'sl $AX0.L, $AX0.H, $ACC0 : $AC0.M, $AX1.H
|
|
ACC0 += AX1
|
|
AX0.H = *AR1;
|
|
*(AR3++) = AC0.M;
|
|
ACC0 = PROD;
|
|
PROD = AX0.L * AX0.H;
|
|
...
|
|
}
|
|
|
|
// In simplified form:
|
|
AR1 = AR0;
|
|
AR0 = AR3;
|
|
for (int i = 0; i < _size; i++) {
|
|
*AR0 = ((*AR0 << 16) + *AR1 * Factor) >> 16);
|
|
}
|
|
|
|
// 00f8 8b00 m0 // Restore multiplication results.
|
|
// 00f9 02df ret
|
|
}
|
|
|
|
void 00fa_BufferMultiply(src($AR0), dst($AR3), count($AC1.M), $mult($AX0.L))
|
|
{
|
|
//00fa 8a00 m2
|
|
00fb 191a lrri $AX0.H, @$AR0
|
|
00fc 9050 mul'l $AX0.L, $AX0.H : $AX0.H, @$AR0
|
|
00fd 9250 mulmvz'l $AX0.L, $AX0.H, $ACC0 : $AX0.H, @$AR0
|
|
00fe 005f loop $AC1.M
|
|
00ff 92a0 mulmvz'ls $AX0.L, $AX0.H, $ACC0 : $AX0.H, $AC0.M
|
|
|
|
//0100 8b00 m0
|
|
//0101 02df ret
|
|
}
|
|
|
|
|
|
// Clears the 0d00 and 0d60 buffers, plus a lot of other intermediate buffers.
|
|
// Also does some other things.
|
|
void 0102_PrepareFrameBuffers()
|
|
{
|
|
// 0102 8100 clr $ACC0
|
|
// 0103 8900 clr $ACC1
|
|
// 0104 0e50 lris $AC0.M, #0x50
|
|
ACC0 = 0
|
|
ACC1 = 0
|
|
AC0.M = 0x50
|
|
|
|
// 0105 0080 0d00 lri $AR0, #0x0d00
|
|
// 0107 005e loop $AC0.M
|
|
// 0108 1b1f srri @$AR0, $AC1.M
|
|
for (int i=0; i<0x50; i++)
|
|
*0x0d00++ = 0x00
|
|
|
|
// 0109 0080 0d60 lri $AR0, #0x0d60
|
|
// 010b 005e loop $AC0.M
|
|
// 010c 1b1f srri @$AR0, $AC1.M
|
|
for (int i=0; i<0x50; i++)
|
|
*0x0d60++ = 0x00
|
|
|
|
// 10d 02bf 0e3f call 0x0e3f
|
|
|
|
// This one adds and multiplies buffers together. Maybe surround or reverb stuff.
|
|
0e3f_DolbyMixdown()
|
|
|
|
// 010f 8100 clr $ACC0
|
|
// 0110 8900 clr $ACC1
|
|
// 0111 0e50 lris $AC0.M, #0x50
|
|
ACC0 = 0
|
|
ACC1 = 0
|
|
AC0.M = 0x50
|
|
|
|
// 0112 0080 0ca0 lri $AR0, #0x0ca0
|
|
// 0114 005e loop $AC0.M
|
|
// 0115 1b1f srri @$AR0, $AC1.M
|
|
for (int i=0; i<0x50; i++)
|
|
*0x0ca0++ = 0x00
|
|
|
|
// 0116 0080 0f40 lri $AR0, #0x0f40
|
|
// 0118 005e loop $AC0.M
|
|
// 0119 1b1f srri @$AR0, $AC1.M
|
|
for (int i=0; i<0x50; i++)
|
|
*0x0f40++ = 0x00
|
|
|
|
// 011a 0080 0fa0 lri $AR0, #0x0fa0
|
|
// 011c 005e loop $AC0.M
|
|
// 011d 1b1f srri @$AR0, $AC1.M
|
|
for (int i=0; i<0x50; i++)
|
|
*0x0fa0++ = 0x00
|
|
|
|
// 011e 0080 0a00 lri $AR0, #0x0a00
|
|
// 0120 005e loop $AC0.M
|
|
// 0121 1b1f srri @$AR0, $AC1.M
|
|
for (int i=0; i<0x50; i++)
|
|
*0x0a00++ = 0x00
|
|
|
|
// 0122 0080 09a0 lri $AR0, #0x09a0
|
|
// 0124 005e loop $AC0.M
|
|
// 0125 1b1f srri @$AR0, $AC1.M
|
|
for (int i=0; i<0x50; i++)
|
|
*0x09a0++ = 0x00
|
|
|
|
// 0126 02df ret
|
|
}
|
|
|
|
|
|
void 0127_Unk() {
|
|
0127 00c0 03a0 lr $AR0, @0x03a0
|
|
0129 191a lrri $AX0.H, @$AR0
|
|
012a 00df 03a1 lr $AC1.M, @0x03a1
|
|
012c 009b 00a0 lri $AX1.H, #0x00a0
|
|
012e 0081 0393 lri $AR1, #0x0393
|
|
0130 18bc lrrd $AC0.L, @$AR1
|
|
0131 b871 mulx'l $AX0.H, $AX1.H : $AC0.M, @$AR1
|
|
0132 bc00 mulxac $AX0.H, $AX1.H, $ACC0
|
|
0133 0080 0050 lri $AR0, #0x0050
|
|
0135 0508 addis $ACC1, #0x08
|
|
0136 02bf 0525 call 0x0525 // 0525_CopyRAMtoDMEM
|
|
// 0525_CopyRAMtoDMEM(... ,.. , 0x50)
|
|
|
|
// 0138 00de 0390 lr $AC0.M, @0x0390
|
|
// 013a 02a0 0001 andf $AC0.M, #0x0001
|
|
// 013c 029d 0145 jlz 0x0145
|
|
if (*0x0390 & 1) {
|
|
013e 0080 0398 lri $AR0, #0x0398
|
|
0140 0e08 lris $AC0.M, #0x08
|
|
0141 00c1 03a1 lr $AR1, @0x03a1
|
|
0143 02bf 0b2e call 0x0b2e // 0b2e_Unk_Multiply
|
|
}
|
|
0145 0f50 lris $AC1.M, #0x50
|
|
0146 00c0 03a1 lr $AR0, @0x03a1
|
|
0148 00da 0394 lr $AX0.H, @0x0394
|
|
// 014a 8600 tstaxh $AX0.H
|
|
// 014b 0295 0152 jz 0x0152
|
|
if (*0x0394 != 0) {
|
|
014d 1c7a mrr $AR3, $AX0.H
|
|
014e 00d8 0395 lr $AX0.L, @0x0395
|
|
0150 02bf 00eb call 0x00eb // 00eb_Unk_BufferMultAddToDest
|
|
}
|
|
0152 0f50 lris $AC1.M, #0x50
|
|
0153 00c0 03a1 lr $AR0, @0x03a1
|
|
0155 00da 0396 lr $AX0.H, @0x0396
|
|
0157 8600 tstaxh $AX0.H
|
|
0158 0295 015f jz 0x015f
|
|
015a 1c7a mrr $AR3, $AX0.H
|
|
015b 00d8 0397 lr $AX0.L, @0x0397
|
|
015d 02bf 00eb call 0x00eb // 00eb_Unk_BufferMultAddToDest
|
|
|
|
// 015f 00de 0390 lr $AC0.M, @0x0390
|
|
// 0161 02a0 0002 andf $AC0.M, #0x0002
|
|
// 0163 02dd retlz
|
|
if (*0x390 & 2)
|
|
return;
|
|
|
|
0164 0080 0398 lri $AR0, #0x0398
|
|
0166 0e08 lris $AC0.M, #0x08
|
|
0167 00c1 03a1 lr $AR1, @0x03a1
|
|
0169 02bf 0b2e call 0x0b2e // 0b2e_Unk_Multiply
|
|
016b 02df ret
|
|
}
|
|
|
|
|
|
// Looks similar to something else...
|
|
void 016c_Unk_SetupMemAt_0c00()
|
|
{
|
|
016c 8900 clr $ACC1
|
|
|
|
// 016d 009f 0dc0 lri $AC1.M, #0x0dc0
|
|
// 016f 00ff 03a1 sr @0x03a1, $AC1.M
|
|
*0x03a1 = 0x0dc0;
|
|
// 0171 009f 03a8 lri $AC1.M, #0x03a8
|
|
// 0173 00ff 03a2 sr @0x03a2, $AC1.M
|
|
*0x03a2 = 0x03a8;
|
|
// 0175 009f 03a4 lri $AC1.M, #0x03a4
|
|
// 0177 00ff 03a0 sr @0x03a0, $AC1.M
|
|
*0x03a0 = 0x03a4;
|
|
|
|
// Dangerous bloopi! It points to the SECOND HALF of a 2-word instruction so
|
|
// a naive check won't catch it! I think our current code does, though.
|
|
|
|
// 0179 1104 019f bloopi #0x04, 0x019f
|
|
for (int i = 0; i < 4; i++) {
|
|
// 017b 00c0 03a2 lr $AR0, @0x03a2
|
|
// 017d 0083 0390 lri $AR3, #0x0390
|
|
// 017f 0f0e lris $AC1.M, #0x0e
|
|
// 0180 02bf 00da call 0x00da
|
|
00da_CopyBuffer(@0x03a2, 0x0390, 0x0e)
|
|
|
|
0182 00da 0390 lr $AX0.H, @0x0390
|
|
0184 8600 tstaxh $AX0.H
|
|
0185 0295 0191 jz 0x0191
|
|
if (*0x0390) {
|
|
0187 00df 03a1 lr $AC1.M, @0x03a1
|
|
0189 1c7f mrr $AR3, $AC1.M
|
|
018a 0550 addis $ACC1, #0x50
|
|
|
|
// 018b 1c1f mrr $AR0, $AC1.M
|
|
// 018c 0f06 lris $AC1.M, #0x06
|
|
// 018d 02bf 00da call 0x00da
|
|
00da_CopyBuffer($AC1.M, $AR3, 0x06);
|
|
|
|
// 018f 02bf 0127 call 0x0127
|
|
0127_Unk();
|
|
}
|
|
// 0191 00de 03a2 lr $AC0.M, @0x03a2
|
|
// 0193 0410 addis $ACC0, #0x10
|
|
// 0194 00fe 03a2 sr @0x03a2, $AC0.M
|
|
(*0x03a2) += 0x10;
|
|
|
|
// 0196 00de 03a1 lr $AC0.M, @0x03a1
|
|
// 0198 0460 addis $ACC0, #0x60
|
|
// 0199 00fe 03a1 sr @0x03a1, $AC0.M
|
|
(*0x03a1) += 0x60;
|
|
|
|
// 019b 00de 03a0 lr $AC0.M, @0x03a0
|
|
// 019d 7400 incm $AC0.M
|
|
// 019e 00fe 03a0 sr @0x03a0, $AC0.M
|
|
(*0x0ea0)++;
|
|
}
|
|
|
|
// 01a0 0f50 lris $AC1.M, #0x50
|
|
// 01a1 0080 0c00 lri $AR0, #0x0c00
|
|
// 01a3 0083 0e80 lri $AR3, #0x0e80
|
|
// 01a5 0098 7fff lri $AX0.L, #0x7fff
|
|
// 01a7 02bf 00eb call 0x00eb
|
|
00eb_Unk_BufferMultAddToDest(_Src(0x0c00), _Dest(0x0e80), _size(0x50), _factor(0x7fff))
|
|
|
|
// 01a9 0f50 lris $AC1.M, #0x50
|
|
// 01aa 0080 0c00 lri $AR0, #0x0c00
|
|
// 01ac 0083 0ee0 lri $AR3, #0x0ee0
|
|
// 01ae 0098 b820 lri $AX0.L, #0xb820
|
|
// 01b0 02bf 00eb call 0x00eb
|
|
00eb_Unk_BufferMultAddToDest(_Src(0x0c00), _Dest(0x0ee0), _size(0x50), _factor(0xb820))
|
|
|
|
// 01b2 0f28 lris $AC1.M, #0x28
|
|
// 01b3 0080 0c78 lri $AR0, #0x0c78
|
|
// 01b5 0083 0e80 lri $AR3, #0x0e80
|
|
// 01b7 0098 b820 lri $AX0.L, #0xb820
|
|
// 01b9 02bf 00eb call 0x00eb
|
|
00eb_Unk_BufferMultAddToDest(_Src(0x0c78), _Dest(0x0e80), _size(0x28), _factor(0xb820))
|
|
// 01bb 0f28 lris $AC1.M, #0x28
|
|
// 01bc 0080 0c78 lri $AR0, #0x0c78
|
|
// 01be 0083 0ee0 lri $AR3, #0x0ee0
|
|
// 01c0 0098 7fff lri $AX0.L, #0x7fff
|
|
// 01c2 02bf 00eb call 0x00eb
|
|
00eb_Unk_BufferMultAddToDest(_Src(0x0c78), _Dest(0x0e80), _size(0x28), _factor(0x7fff))
|
|
|
|
// Zero the temporary buffers 0x0c00 and 0x0c50
|
|
01c4 8100 clr $ACC0
|
|
01c5 8900 clr $ACC1
|
|
01c6 0e50 lris $AC0.M, #0x50
|
|
01c7 0080 0c00 lri $AR0, #0x0c00
|
|
01c9 005e loop $AC0.M
|
|
01ca 1b1f srri @$AR0, $AC1.M
|
|
01cb 0080 0c50 lri $AR0, #0x0c50
|
|
01cd 005e loop $AC0.M
|
|
01ce 1b1f srri @$AR0, $AC1.M
|
|
|
|
// 01cf 02df ret
|
|
}
|
|
|
|
void 01d0_Unk() {
|
|
// 01d0 00c0 03a0 lr $AR0, @0x03a0
|
|
// 01d2 181a lrr $AX0.H, @$AR0
|
|
AX0.H = *0x03a0;
|
|
|
|
// 01d3 8100 clr $ACC0
|
|
// 01d4 181e lrr $AC0.M, @$AR0
|
|
AC0.M = *0x03a0;
|
|
|
|
// 01d5 00db 0391 lr $AX1.H, @0x0391
|
|
AX1.H = *0x0391;
|
|
|
|
// 01d7 7400 incm $AC0.M
|
|
AC0.M++;
|
|
|
|
// 01d8 d100 cmpar $ACC1, $AX0.H
|
|
// 01d9 0270 ifge
|
|
if (ACC1 - AX0.H >= 0) {
|
|
01da 8100 clr $ACC0
|
|
}
|
|
|
|
01db 1b1e srri @$AR0, $AC0.M
|
|
01dc 00df 03a1 lr $AC1.M, @0x03a1
|
|
01de 009b 00a0 lri $AX1.H, #0x00a0
|
|
01e0 0081 0393 lri $AR1, #0x0393
|
|
01e2 18bc lrrd $AC0.L, @$AR1
|
|
01e3 b871 mulx'l $AX0.H, $AX1.H : $AC0.M, @$AR1
|
|
01e4 bc00 mulxac $AX0.H, $AX1.H, $ACC0
|
|
|
|
// 01e5 0080 0050 lri $AR0, #0x0050
|
|
// 01e7 02bf 0532 call 0x0532
|
|
0532_DMEMtoRAM(_DMEM(AC1.M), _pMemAddr(ACC0), 0x50)
|
|
|
|
01e9 02df ret
|
|
}
|
|
|
|
void 01ea_Unk() {
|
|
01ea 8900 clr $ACC1
|
|
// 01eb 0f28 lris $AC1.M, #0x28 // half of 0x50
|
|
// 01ec 0080 0c50 lri $AR0, #0x0c50
|
|
// 01ee 0083 0ea8 lri $AR3, #0x0ea8
|
|
// 01f0 0098 b820 lri $AX0.L, #0xb820
|
|
// 01f2 02bf 00eb call 0x00eb
|
|
00eb_Unk_BufferMultAddToDest(_Src=($AR0), _Dest($AR3), _size($AC1.M), _factor($AX0.L))
|
|
|
|
01f4 8900 clr $ACC1
|
|
// 01f5 0f28 lris $AC1.M, #0x28
|
|
// 01f6 0080 0c50 lri $AR0, #0x0c50
|
|
// 01f8 0083 0f08 lri $AR3, #0x0f08
|
|
// 01fa 0098 7fff lri $AX0.L, #0x7fff
|
|
// 01fc 02bf 00eb call 0x00eb
|
|
00eb_Unk_BufferMultAddToDest(_Src=($AR0), _Dest($AR3), _size($AC1.M), _factor($AX0.L))
|
|
|
|
|
|
// 01fe 009f 0dc0 lri $AC1.M, #0x0dc0
|
|
// 0200 00ff 03a1 sr @0x03a1, $AC1.M
|
|
// 0202 009f 03a8 lri $AC1.M, #0x03a8
|
|
// 0204 00ff 03a2 sr @0x03a2, $AC1.M
|
|
// 0206 009f 03a4 lri $AC1.M, #0x03a4
|
|
// 0208 00ff 03a0 sr @0x03a0, $AC1.M
|
|
(*0x03a1) = 0x0dc0;
|
|
(*0x03a2) = 0x03a8;
|
|
(*0x03a0) = 0x03a4;
|
|
|
|
// Dangerous bloopi! It points to the SECOND HALF of a 2-word instruction so
|
|
// a naive check won't catch it! I think our current code does, though.
|
|
|
|
// 020a 1104 0228 bloopi #0x04, 0x0228
|
|
for (int i = 0; i < 4; i++) {
|
|
// 020c 00c0 03a2 lr $AR0, @0x03a2
|
|
// 020e 0083 0390 lri $AR3, #0x0390
|
|
// 0210 0f0e lris $AC1.M, #0x0e
|
|
// 0211 02bf 00da call 0x00da
|
|
00da_CopyBuffer(_src(*0x03a2), _dest(0x0390), _LenInDWORDs(0xE))
|
|
|
|
// 0213 00da 0390 lr $AX0.H, @0x0390
|
|
// 0215 8600 tstaxh $AX0.H
|
|
// 0216 0295 021a jz 0x021a
|
|
if (*0x0390) {
|
|
// 0218 02bf 01d0 call 0x01d0
|
|
|
|
// Copy some buffer to RAM?
|
|
01d0_Unk();
|
|
}
|
|
|
|
// 021a 00de 03a2 lr $AC0.M, @0x03a2
|
|
// 021c 0410 addis $ACC0, #0x10
|
|
// 021d 00fe 03a2 sr @0x03a2, $AC0.M
|
|
(*0x03a2) += 0x10;
|
|
|
|
// 021f 00de 03a1 lr $AC0.M, @0x03a1
|
|
// 0221 0460 addis $ACC0, #0x60
|
|
// 0222 00fe 03a1 sr @0x03a1, $AC0.M
|
|
(*0x03a1) += 0x60;
|
|
|
|
// 0224 00de 03a0 lr $AC0.M, @0x03a0
|
|
// 0226 7400 incm $AC0.M
|
|
// 0227 00fe 03a0 sr @0x03a0, $AC0.M
|
|
(*0x03a0)++;
|
|
}
|
|
0229 02df ret
|
|
}
|
|
|
|
|
|
void 022a_Copy_XXX_From_RAM_To_0x03a8()
|
|
{
|
|
// 022a 0081 0386 lri $AR1, #0x0386
|
|
// 022c 009f 03a8 lri $AC1.M, #0x03a8
|
|
// 022e 0080 0040 lri $AR0, #0x0040
|
|
// 0230 02bf 0523 call 0x0523
|
|
0523_CopyRAMtoDMEM(0x0386, 0x03a8, 0x0040);
|
|
|
|
// 0232 02df ret
|
|
}
|
|
|
|
|
|
void 0233_Increase_32BitAddress_InMem(_MemAddr(AR0), _Bytes(AX0.L))
|
|
{
|
|
// 0233 191e lrri $AC0.M, @$AR0
|
|
// 0234 189c lrrd $AC0.L, @$AR0
|
|
// 0235 4800 addax $ACC0, $AX0
|
|
// 0236 1b1e srri @$AR0, $AC0.M
|
|
// 0237 1b1c srri @$AR0, $AC0.L
|
|
|
|
*((u32*)AR0) += AX0
|
|
|
|
// 0238 02df ret
|
|
}
|
|
|
|
|
|
void 0239_WaitUntilLastFrameGotSynced()
|
|
{
|
|
// 0239 8100 clr $ACC0
|
|
// 023a 8900 clr $ACC1
|
|
// 023b 00df 0354 lr $AC1.M, @0x0354
|
|
// 023d 00de 034e lr $AC0.M, @0x034e
|
|
// 023f 8200 cmp
|
|
// 0240 0293 0239 jle 0x0239 // loop
|
|
do {
|
|
|
|
} while (*0x0354 > *0x034e); // TODO: CHECK
|
|
|
|
// 0242 02df ret
|
|
}
|
|
|
|
/////////////////////////
|
|
//
|
|
//
|
|
// 0x0341: Number of Frames to render ...
|
|
|
|
// 0x034c + 0x034d: RAM address of the current PB block
|
|
|
|
// 0x034e: Last Sync message for rendered frame
|
|
// 0x0354: PB loop counter
|
|
|
|
// 0x0355: Current Frame
|
|
|
|
// 0x0380: ???
|
|
// 0x0381: ???
|
|
|
|
// 0x0388: RAM Address of Output Buffer1
|
|
// 0x038a: RAM Address of Output Buffer2
|
|
//
|
|
// 0x038f: Output Buffer Address (0x0520 most of the time)
|
|
//
|
|
// 0x03f8: *0x0433
|
|
// 0x0520: Some kind of sample buffer
|
|
|
|
// 0x0d00: Left mix buffer
|
|
// 0x0d60: Right mix buffer
|
|
|
|
void 0243_COMMAND_02() // sync frame
|
|
{
|
|
// 0243 0080 0388 lri $AR0, #0x0388
|
|
// 0245 0081 0067 lri $AR1, #0x0067
|
|
// 0247 0e02 lris $AC0.M, #0x02
|
|
// 0248 173f callr $AR1
|
|
0067_CopyCommand(0x0388, 0x02);
|
|
|
|
// 0249 00de 0344 lr $AC0.M, @0x0344
|
|
// 024b 00fe 0341 sr @0x0341, $AC0.M
|
|
*0x0341 = *0x0344;
|
|
|
|
// 024d 00de 0345 lr $AC0.M, @0x0345
|
|
// 024f 00fe 038e sr @0x038e, $AC0.M
|
|
*0x038e = *0x0345;
|
|
|
|
// 0251 8100 clr $ACC0
|
|
// 0252 00fe 0355 sr @0x0355, $AC0.M
|
|
*0x0355 = 0x00;
|
|
|
|
// 0254 02bf 022a call 0x022a
|
|
022a_Copy_XXX_From_RAM_To_0x03a8(); // perhaps an PB ??
|
|
|
|
// 0256 02bf 05a4 call 0x05a4
|
|
05A4_ResetAccelerator();
|
|
|
|
|
|
// 0258 00de 0341 lr $AC0.M, @0x0341
|
|
// 025a 007e 0418 bloop $AC0.M, 0x0418
|
|
|
|
// Frame size is 0xa0 * *0x0341
|
|
for (int j=0; j< *0x0341; j++) // 0x0341 = high part of the (command & 0xFF) ... perhaps number of frames to render??
|
|
{
|
|
// 025c 02bf 0102 call 0x0102
|
|
0102_PrepareFrameBuffers();
|
|
|
|
// 025e 02bf 016c call 0x016c
|
|
016c_Unk_SetupMemAt_0c00();
|
|
|
|
// 0260 02bf 095f call 0x095f
|
|
095f_Unk_SetupMemAt0_0180();
|
|
|
|
// 0262 00de 0355 lr $AC0.M, @0x0355
|
|
// 0264 7400 incm $AC0.M
|
|
// 0265 00fe 0355 sr @0x0355, $AC0.M
|
|
(*0x0355)++;
|
|
|
|
// 0267 8100 clr $ACC0
|
|
// 0268 00fe 0354 sr @0x0354, $AC0.M
|
|
*0x0354 = 0; // PB counter
|
|
|
|
// 026a 00de 0342 lr $AC0.M, @0x0342
|
|
// 026c 007e 03c0 bloop $AC0.M, 0x03c0
|
|
for (int i=0; i<*0x0342; i++) // 0x0342 - low part of the DSetupTable Command. Number of PBs?
|
|
{
|
|
// 026e 02bf 0239 call 0x0239
|
|
0239_WaitUntilLastFrameGotSynced();
|
|
|
|
// 0270 8100 clr $ACC0
|
|
// 0271 8900 clr $ACC1
|
|
ACC0 = 0;
|
|
ACC1 = 0;
|
|
|
|
// this block is for masking out PBs... the lower part of the sync messages are updating this mask
|
|
// but i am not 100 percent sure how it works
|
|
{
|
|
// 0272 00de 0354 lr $AC0.M, @0x0354
|
|
// 0274 147c lsr $ACC0, #-4
|
|
// 0275 0200 04fc addi $AC0.M, #0x04fc
|
|
// 0277 1c1e mrr $AR0, $AC0.M
|
|
AC0.M = *0x0354 >> 4;
|
|
AR0 = AC0.M + 0x04fc;
|
|
|
|
0278 181f lrr $AC1.M, @$AR0
|
|
0279 00de 0354 lr $AC0.M, @0x0354
|
|
027b 0240 000f andi $AC0.M, #0x000f
|
|
// 027d 3d80 lsrnr
|
|
ACC1 <<= ACC0
|
|
|
|
027e 03c0 8000 andcf $AC1.M, #0x8000
|
|
// 0280 029c 03bc jlnz 0x03bc
|
|
GOTO NEXT_BLOCK:
|
|
}
|
|
|
|
// 0282 00d8 0354 lr $AX0.L, @0x0354
|
|
// 0284 009a 0180 lri $AX0.H, #0x0180
|
|
// 0286 8100 clr $ACC0
|
|
// 0287 00de 0380 lr $AC0.M, @0x0380
|
|
// 0289 00dc 0381 lr $AC0.L, @0x0381
|
|
// 028b 9000 mul $AX0.L, $AX0.H
|
|
// 028c 9400 mulac $AX0.L, $AX0.H, $ACC0
|
|
// 028d 00fe 034c sr @0x034c, $AC0.M
|
|
// 028f 00fc 034d sr @0x034d, $AC0.L
|
|
AX0.L = *0x0354 // number of rendered frames
|
|
AX0.H = 0x0180 // PB Size with dummy buffer
|
|
ACC0 = (*0x0380 << 16) | *0x0381
|
|
ACC0 += AX0.L * AX0.H
|
|
|
|
// Compute the RAM address of the current PB.
|
|
*0x034C = AC0.M
|
|
*0x034D = AC0.L
|
|
|
|
// Copy the current PB to 0x400, so we can access it from DSP code.
|
|
// 0291 02bf 00c1 call 0x00c1
|
|
00c1_CopyPBToDMEM()
|
|
|
|
// 0293 00da 0400 lr $AX0.H, @0x0400
|
|
// 0295 8600 tstaxh $AX0.H
|
|
// 0296 0295 03bc jz 0x03bc
|
|
if (*0x0400 == 0x00)
|
|
GOTO NEXT_BLOCK:
|
|
|
|
// 0298 00da 0401 lr $AX0.H, @0x0401
|
|
// 029a 8600 tstaxh $AX0.H
|
|
// 029b 0294 03bc jnz 0x03bc
|
|
if (*0x0401 != 0x00)
|
|
GOTO NEXT_BLOCK:
|
|
|
|
// 029d 00da 0433 lr $AX0.H, @0x0433
|
|
// 029f 00fa 03f8 sr @0x03f8, $AX0.H
|
|
*0x03f8 = *0x0433
|
|
|
|
// 02a1 00da 0406 lr $AX0.H, @0x0406
|
|
// 02a3 8600 tstaxh $AX0.H
|
|
// 02a4 0294 0dff jnz 0x0dff
|
|
if (*0x0406 != 0x00)
|
|
{
|
|
// The Code at 0x0dff sets the value from *0x0433 to 0x50 shorts at 0x0520.
|
|
// Then it JMPs to ContinueWithBlock.
|
|
0dff_Zero520_50().
|
|
}
|
|
else
|
|
{
|
|
// 02a6 8100 clr $ACC0
|
|
// 02a7 00de 0480 lr $AC0.M, @0x0480
|
|
// 02a9 0609 cmpis $ACC0, #0x09
|
|
// 02aa 0295 02bd jz 0x02bd
|
|
// 02ac 0605 cmpis $ACC0, #0x05
|
|
// 02ad 0295 02bd jz 0x02bd
|
|
// 02af 0608 cmpis $ACC0, #0x08
|
|
// 02b0 0295 098f jz 0x098f
|
|
// 02b2 0610 cmpis $ACC0, #0x10
|
|
// 02b3 0295 0a14 jz 0x0a14
|
|
// 02b5 0620 cmpis $ACC0, #0x20
|
|
// 02b6 0295 0a9a jz 0x0a9a
|
|
// 02b8 0621 cmpis $ACC0, #0x21
|
|
// 02b9 0295 0aa2 jz 0x0aa2
|
|
// 02bb 029f 087c jmp 0x087c
|
|
|
|
switch(*0x0480)
|
|
{
|
|
case 0x05:
|
|
case 0x09: GOTO 02BD:
|
|
case 0x08: GOTO 098f:
|
|
case 0x10: GOTO 0a14:
|
|
case 0x20: GOTO 0a9a:
|
|
case 0x21: GOTO 0aa2:
|
|
default: GOTO 087C:
|
|
}
|
|
|
|
// This is the common decoding prep for 0x05 and 0x09.
|
|
|
|
// 02bd 00d8 0402 lr $AX0.L, @0x0402 // delta?
|
|
// 02bf 8100 clr $ACC0
|
|
// 02c0 8900 clr $ACC1
|
|
// 02c1 00dc 0430 lr $AC0.L, @0x0430 // current fraction?
|
|
// 02c3 8d00 set15 // unsigned multiplication
|
|
// 02c4 0950 lris $AX1.L, #0x50
|
|
// 02c5 a000 mulx $AX0.L, $AX1.L
|
|
// 02c6 a400 mulxac $AX0.L, $AX1.L, $ACC0
|
|
// 02c7 1404 lsl $ACC0, #4
|
|
// 02c8 8c00 clr15
|
|
|
|
// 0x0402 is delta ("Ratio").
|
|
// Is this a computation of the starting point for decoding?
|
|
// If so 0x430 is the current sample position fraction and
|
|
AX0.L = *0x0402
|
|
ACC0 = *0x430 + (AX0.L * 0x50)
|
|
ACC0 >>= 4
|
|
|
|
// 02c9 1ffe mrr $AC1.M, $AC0.M
|
|
// 02ca 0083 0580 lri $AR3, #0x0580
|
|
// 02cc 02bf 073d call 0x073d
|
|
|
|
// AC1.M here is ACC0.M! Effectively a shift right 16. The above fraction stuff seems to make sense.
|
|
073d_DECODE_0x05_0x09(0x0580, AC1.M, 0x50)
|
|
|
|
// NOP jump here.
|
|
// 02ce 029f 02d0 jmp 0x02d0
|
|
|
|
Resample_From0580To0520:
|
|
// 02d0 0080 0580 lri $AR0, #0x0580
|
|
// 02d2 0081 0520 lri $AR1, #0x0520
|
|
// 02d4 0099 0000 lri $AX1.L, #0x0000
|
|
// 02d6 02bf 0d7f call 0x0d7f
|
|
0d7f_ResampleAudioData(0x0580, 0x0520, 0x0000);
|
|
}
|
|
|
|
// A block of audio is now present at 0x520.
|
|
|
|
ContinueWithBlock:
|
|
// Apply various per-voice effects.
|
|
|
|
// First up, a trivial in-place filter, if $0x04a8 is set.
|
|
|
|
// 02d8 00da 04a8 lr $AX0.H, @0x04a8
|
|
// 02da 8600 tstaxh $AX0.H
|
|
// 02db 0295 02e1 jz 0x02e1
|
|
// 02dd 0080 0520 lri $AR0, #0x0520
|
|
// 02df 02bf 0c84 call 0x0c84
|
|
if (0x04a8 != 0)
|
|
void 0c84_FilterBufferInPlace(_sampleAddr($AR0), multiplier($AX0.H))
|
|
|
|
// 02e1 009e 0520 lri $AC0.M, #0x0520
|
|
// 02e3 00fe 038f sr @0x038f, $AC0.M
|
|
*0x038f = 0x0520
|
|
|
|
// 02e5 8900 clr $ACC1
|
|
// 02e6 00df 0484 lr $AC1.M, @0x0484
|
|
// 02e8 0340 001f andi $AC1.M, #0x001f
|
|
// 02ea b900 tst $ACC1
|
|
// 02eb 0295 0311 jz 0x0311
|
|
if ((*0x0484 & 0x1f) != 0x00)
|
|
{
|
|
// 02ed 00de 038f lr $AC0.M, @0x038f
|
|
// 02ef 5c00 sub $ACC0, $ACC1
|
|
// 02f0 00fe 038f sr @0x038f, $AC0.M
|
|
(*0x038f) -= AC1.M;
|
|
|
|
// 02f2 1c7e mrr $AR3, $AC0.M
|
|
// 02f3 0080 0440 lri $AR0, #0x0440
|
|
// 02f5 05fe addis $ACC1, #0xfe
|
|
// 02f6 02bf 00da call 0x00da
|
|
00da_CopyBuffer(0x0440, (*0x038f), (*0x0484) + 0xfe)
|
|
|
|
// 02f8 0080 0490 lri $AR0, #0x0490
|
|
// 02fa 00c1 038f lr $AR1, @0x038f
|
|
// 02fc 8900 clr $ACC1
|
|
// 02fd 00df 0484 lr $AC1.M, @0x0484
|
|
// 02ff 0340 001f andi $AC1.M, #0x001f
|
|
// 0301 02bf 0b4d call 0x0b4d
|
|
0b4d_IIR_Filter(In(0x0490), Out(*0x038f), FilterLength(*0x0484 & 0x1f))
|
|
|
|
0303 00de 038f lr $AC0.M, @0x038f
|
|
0305 0450 addis $ACC0, #0x50
|
|
0306 1c1e mrr $AR0, $AC0.M
|
|
// 0307 0083 0440 lri $AR3, #0x0440
|
|
0309 8900 clr $ACC1
|
|
030a 00df 0484 lr $AC1.M, @0x0484
|
|
030c 0340 001f andi $AC1.M, #0x001f
|
|
030e 05fe addis $ACC1, #0xfe
|
|
// 030f 02bf 00da call 0x00da
|
|
00da_CopyBuffer(, 0x0440)
|
|
}
|
|
|
|
// 0311 00de 0484 lr $AC0.M, @0x0484
|
|
// 0313 0240 0020 andi $AC0.M, #0x0020
|
|
// 0315 0295 0333 jz 0x0333
|
|
if ((*0x0484 & 0x0020) != 0)
|
|
{
|
|
0317 0080 04a4 lri $AR0, #0x04a4
|
|
0319 00c1 038f lr $AR1, @0x038f
|
|
031b 0082 0454 lri $AR2, #0x0454
|
|
031d 0083 04a7 lri $AR3, #0x04a7
|
|
|
|
// 031f 18fa lrrd $AX0.H, @$AR3
|
|
// 0320 8600 tstaxh $AX0.H
|
|
// 0321 0294 0331 jnz 0x0331
|
|
if (!*0x04a7) {
|
|
// 0323 18fa lrrd $AX0.H, @$AR3
|
|
// 0324 8600 tstaxh $AX0.H
|
|
// 0325 0294 0331 jnz 0x0331
|
|
if (!*0x04a6) {
|
|
// 0327 18fa lrrd $AX0.H, @$AR3
|
|
// 0328 8600 tstaxh $AX0.H
|
|
// 0329 0294 0331 jnz 0x0331
|
|
if (!*0x04a5) {
|
|
// 032b 8100 clr $ACC0
|
|
// 032c 18fe lrrd $AC0.M, @$AR3
|
|
// 032d 0280 7fff cmpi $AC0.M, #0x7fff
|
|
// 032f 0295 0333 jz 0x0333
|
|
if (*0x04a4 != 0x7FFF) {
|
|
// 0331 02bf 0b68 call 0x0b68
|
|
0b68_4TapFIR(InBuffer($AR2), FilterBuffer($AR0), OutBuffer($AR1));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check volume mode, apply volume as appropriate
|
|
|
|
// 0333 8100 clr $ACC0
|
|
// 0334 00de 042c lr $AC0.M, @0x042c
|
|
// 0336 b100 tst $ACC0
|
|
// 0337 0295 033d jz 0x033d
|
|
|
|
if (*0x042c != 0) // Volume mode != 0
|
|
{
|
|
// 0339 02bf 0cd3 call 0x0cd3
|
|
// 033b 029f 03b2 jmp 0x03b2
|
|
0cd3_VolumeMixer1() // The complex one, probably with surround and stuff
|
|
}
|
|
else
|
|
{
|
|
// Volume mode == 0 - simple(r) volumes
|
|
// 033d 8100 clr $ACC0
|
|
// 033e 1c9e mrr $IX0, $AC0.M
|
|
// 033f 1cde mrr $IX2, $AC0.M
|
|
// 0340 7400 incm $AC0.M
|
|
// 0341 1cfe mrr $IX3, $AC0.M
|
|
// 0342 8100 clr $ACC0
|
|
$IX0 = 0;
|
|
$IX2 = 0;
|
|
$IX3 = 1;
|
|
|
|
// 0343 00de 0407 lr $AC0.M, @0x0407
|
|
// 0345 b100 tst $ACC0
|
|
// 0346 0295 0355 jz 0x0355
|
|
if (*0x0407 != 0) // Unknown, in zelda always 0x10, apparently.
|
|
{
|
|
// Seems like this all boils down to a backwards copy of
|
|
// 0x0470-0x0477 to *(*(0x038f));
|
|
// Is that where we save samples in the PB, so that filters
|
|
// have something to read from at the start of each block?
|
|
|
|
// 0348 00c3 038f lr $AR3, @0x038f
|
|
// 034a 0007 dar $AR3
|
|
$AR3 = *(0x038f) - 1;
|
|
// 034b 0080 0477 lri $AR0, #0x0477
|
|
// 034d 0084 ffff lri $IX0, #0xffff
|
|
// 034f 0087 ffff lri $IX3, #0xffff
|
|
$AR0 = 0x477;
|
|
$IX0 = -1;
|
|
$IX3 = -1;
|
|
// 0351 199a lrrn $AX0.H, @$AR0
|
|
AX0.H = *$AR0;
|
|
AR0 += IX0;
|
|
|
|
// 0352 6554 movr'ln $ACC1, $AX0.H : $AX0.H, @$AR0
|
|
$ACC1 = $AX0.H;
|
|
$AX0.H = *$AR0;
|
|
$AR0 += IX0;
|
|
// 0353 005e loop $AC0.M
|
|
for (int i = 0; i < AC0.M; i++) {
|
|
0354 65ad movr'lsnm $ACC1, $AX0.H : $AX0.H, $AC1.M
|
|
}
|
|
}
|
|
|
|
// 0355 00da 0485 lr $AX0.H, @0x0485
|
|
// 0357 8600 tstaxh $AX0.H
|
|
// 0358 0295 036b jz 0x036b
|
|
if (*0x0485 != 0)
|
|
{
|
|
035a 8900 clr $ACC1
|
|
035b 0086 0005 lri $IX2, #0x0005 // 5 - 1 = 4, see loop
|
|
035d 0082 040a lri $AR2, #0x040a
|
|
// 035f 1106 0363 bloopi #0x06, 0x0363
|
|
|
|
// Store half of every 4th value from 0x040a onwards in the position before. (!!!!)
|
|
// This really doesn't make a lot of sense.
|
|
// At the same time, keep their sum in ACC1.
|
|
for (int i = 0; i < 0x6; i++) {
|
|
// 0361 18de lrrd $AC0.M, @$AR2
|
|
// 0362 147f lsr $ACC0, #-1
|
|
// 0363 4d36 add'sn $ACC1, $ACC0 : @$AR2, $AC0.M
|
|
$AC0.M = *$AR2 >> 1;
|
|
$AR2--;
|
|
$ACC1 += $ACC0;
|
|
*$AR2 = $ACC0;
|
|
$AR2 += 5;
|
|
}
|
|
// 0364 b900 tst $ACC1
|
|
// 0365 0294 036b jnz 0x036b
|
|
|
|
// Volume has dropped to 0 on all channels, stop sound?
|
|
if (sum == 0) {
|
|
// 0367 009a 0001 lri $AX0.H, #0x0001
|
|
// 0369 00fa 0401 sr @0x0401, $AX0.H // Write 1 to KeyOff.
|
|
}
|
|
}
|
|
|
|
// 036b 8f00 set40
|
|
// 036c 0086 0002 lri $IX2, #0x0002
|
|
// 036e 0082 0408 lri $AR2, #0x0408
|
|
$IX2 = 0x0002;
|
|
$AR2 = 0x0408;
|
|
|
|
// Volume data starts at 0x0408, it's like this:
|
|
// 1 word controls sbset #0x00 apparently
|
|
// 2 volume values
|
|
// 1 other word.
|
|
|
|
// 0370 1106 039b bloopi #0x06, 0x039b
|
|
for (int i = 0; i < 6; i++)
|
|
{
|
|
// 0372 8100 clr $ACC0
|
|
// 0373 195e lrri $AC0.M, @$AR2
|
|
// 0374 1200 sbclr #0x00 // W T F???
|
|
// 0375 b100 tst $ACC0
|
|
// 0376 0275 ifz
|
|
// 0377 1300 sbset #0x00
|
|
// sbset #0x00 is logic zero ... we use it to store a bit here. see 0394
|
|
if (*$AR2 == 0) {
|
|
sbset #0x00
|
|
} else {
|
|
sbclr #0x00
|
|
}
|
|
|
|
0378 1c7e mrr $AR3, $AC0.M
|
|
|
|
0379 195e lrri $AC0.M, @$AR2 // Load the two volume values
|
|
037a 195f lrri $AC1.M, @$AR2
|
|
|
|
// 037b 5c00 sub $ACC0, $ACC1 // Subtract them - find volume delta?
|
|
// 037c 14fb asr $ACC0, #-5
|
|
// 037d 1f5e mrr $AX0.H, $AC0.M
|
|
// 037e 1f1c mrr $AX0.L, $AC0.L
|
|
$AX0 = (vol1 - vol2) >> 5; // 32 steps ..
|
|
|
|
// Read the value after the volumes.
|
|
|
|
// 037f 185e lrr $AC0.M, @$AR2
|
|
// 0380 0240 00ff andi $AC0.M, #0x00ff
|
|
// 0382 1f7e mrr $AX1.H, $AC0.M
|
|
$AX1.H = *$AR2 & 0xFF;
|
|
|
|
// 0383 185e lrr $AC0.M, @$AR2
|
|
// 0384 1478 lsr $ACC0, #-8
|
|
// 0385 009c 0000 lri $AC0.L, #0x0000
|
|
$AC0.M = *$AR2 >> 8;
|
|
|
|
// ACC1 is here the second volume. Compare to delta.
|
|
// Adjust *$AR2 for some reason accordingly...
|
|
|
|
// 0387 d100 cmpar $ACC1, $AX0.H
|
|
// 0388 0295 0390 jz 0x0390
|
|
// 038a 185e lrr $AC0.M, @$AR2
|
|
// 038b 0272 ifg
|
|
// 038c 7400 incm $AC0.M
|
|
// 038d 0271 ifl
|
|
// 038e 7800 decm $AC0.M
|
|
// 038f 1a5e srr @$AR2, $AC0.M
|
|
if ($ACC1 < $AX0.H) {
|
|
(*$AR2)--;
|
|
} else if ($ACC1 > $AX0.H) {
|
|
(*$AR2)++
|
|
}
|
|
|
|
// 0390 0006 dar $AR2
|
|
$AR2--;
|
|
|
|
// $AR2 again points at the second volume.
|
|
|
|
0391 00de 038f lr $AC0.M, @0x038f
|
|
|
|
// Per channel mini-delay?
|
|
0393 5600 subr $ACC0, $AX1.H // see 0382
|
|
|
|
// Use that stored logic zero bit, to skip mixing if the first word is (or isn't? not sure) 0.
|
|
// 0394 029d 0399 jlz 0x0399
|
|
if (!logic zero) {
|
|
// 0396 1c1e mrr $AR0, $AC0.M
|
|
// 0397 02bf 0ca9 call 0x0ca9
|
|
0ca9_RampedMultiplyAddBuffer(Volume($ACC1), VolumeDelta($AX0), MultiplierData($AR0), Buffer($AR3))
|
|
}
|
|
// 0399 0000 nop
|
|
// 039a 1b5f srri @$AR2, $AC1.M
|
|
// Update the second volume.
|
|
*($AR2++) = $AC1.M;
|
|
// 039b 000a iar $AR2
|
|
$AR2++; // Next block of four values.
|
|
}
|
|
|
|
// 039c 8e00 set16
|
|
|
|
// 039d 8100 clr $ACC0
|
|
// 039e 00de 0407 lr $AC0.M, @0x0407
|
|
// 03a0 b100 tst $ACC0
|
|
// 03a1 0295 03b2 jz 0x03b2
|
|
if (*0x0407 != 0)
|
|
{
|
|
// Stash away the last bunch of samples into 0x0477 and backwards,
|
|
// so that filter kernels and resampler have some previous data to
|
|
// read from the next time.
|
|
03a3 00c3 038f lr $AR3, @0x038f
|
|
03a5 0087 004f lri $IX3, #0x004f
|
|
03a7 001f addarn $AR3, $IX3
|
|
03a8 0080 0477 lri $AR0, #0x0477
|
|
03aa 0084 ffff lri $IX0, #0xffff
|
|
03ac 0087 ffff lri $IX3, #0xffff
|
|
03ae 19fa lrrn $AX0.H, @$AR3
|
|
03af 6557 movr'ln $ACC1, $AX0.H : $AX0.H, @$AR3
|
|
03b0 005e loop $AC0.M
|
|
03b1 65af movr'slnm $ACC1, $AX0.H : $AC1.M, $AX0.H
|
|
}
|
|
}
|
|
|
|
// 03b2 00da 0406 lr $AX0.H, @0x0406
|
|
// 03b4 8600 tstaxh $AX0.H
|
|
// 03b5 0294 03ba jnz 0x03ba
|
|
if (*0x0406 == 0)
|
|
{
|
|
// 03b7 8100 clr $ACC0
|
|
// 03b8 00fe 0404 sr @0x0404, $AC0.M
|
|
*0x0404 = 0x0000
|
|
}
|
|
|
|
// 03ba 02bf 00ca call 0x00ca
|
|
00ca_CopyPBToRAM()
|
|
|
|
NEXT_BLOCK:
|
|
03bc 00de 0354 lr $AC0.M, @0x0354
|
|
03be 7400 incm $AC0.M
|
|
03bf 00fe 0354 sr @0x0354, $AC0.M
|
|
}
|
|
|
|
// Done mixing all voices, sync up with host before the final mixdown.
|
|
|
|
// 03c1 0e00 lris $AC0.M, #0x00
|
|
// 03c2 00fe 034e sr @0x034e, $AC0.M
|
|
*0x034e = 0x00
|
|
|
|
// 03c4 0e04 lris $AC0.M, #0x04
|
|
// 03c5 02bf 066a call 0x066a
|
|
SendMB_DCD1(0x0004)
|
|
|
|
// 03c7 00de 0355 lr $AC0.M, @0x0355
|
|
// 03c9 0260 ff00 ori $AC0.M, #0xff00
|
|
// 03cb 02bf 0674 call 0x0674
|
|
SendMB_F355(*0x0355 | 0xFF00) // *0x0355 - current frame
|
|
|
|
|
|
// Buffer 0D00 and 0D60 are the final L & R mixing buffers.
|
|
|
|
// This is where global effects are applied, and final mixdown is done.
|
|
|
|
// 03cd 02bf 0c0a call 0x0c0a
|
|
0c0a_Unk() // Copy 0a00 to 0a60?
|
|
|
|
// 03cf 02bf 0c1c call 0x0c1c
|
|
0c1c_ComputeReverbFrom0a60To0a00() // Not sure if this really is reverb but could be.
|
|
|
|
// 03d1 02bf 0c71 call 0x0c71
|
|
0c71_AddBufferA00ToD60AndD00(); // add A00 on top of 0x0D00 and 0x0D60
|
|
|
|
// 03d3 00de 0341 lr $AC0.M, @0x0341
|
|
// 03d5 7800 decm $AC0.M
|
|
// 03d6 00fe 0341 sr @0x0341, $AC0.M
|
|
|
|
(*0x0341)--;
|
|
|
|
// The audio at 09a0 is added to both channels,
|
|
// then the channel buffers are copied to RAM.
|
|
// For unknown reasons, the audio at 0x0fa0 is ONLY added to the right channel.
|
|
|
|
// 03d8 0080 09a0 lri $AR0, #0x09a0
|
|
// 03da 0083 0d00 lri $AR3, #0x0d00
|
|
// 03dc 0f50 lris $AC1.M, #0x50
|
|
// 03dd 0098 5a82 lri $AX0.L, #0x5a82
|
|
// 03df 02bf 00eb call 0x00eb
|
|
00eb_Unk_BufferMultAddToDest(0x09a0, 0x0d00, 0x50, 0x5a82)
|
|
|
|
// 03e1 0080 09a0 lri $AR0, #0x09a0
|
|
// 03e3 0083 0d60 lri $AR3, #0x0d60
|
|
// 03e5 0f50 lris $AC1.M, #0x50
|
|
// 03e6 02bf 00eb call 0x00eb
|
|
00eb_Unk_BufferMultAddToDest(0x09a0, 0x0d60, 0x50, 0x5a82)
|
|
|
|
// 03e8 0083 0d00 lri $AR3, #0x0d00
|
|
// 03ea 02bf 0cc1 call 0x0cc1
|
|
0cc1_StrangeORRFilter(0x0d00)
|
|
|
|
// 03ec 0081 0388 lri $AR1, #0x0388
|
|
// 03ee 009f 0d00 lri $AC1.M, #0x0d00
|
|
// 03f0 0080 0050 lri $AR0, #0x0050
|
|
// 03f2 02bf 0530 call 0x0530
|
|
0530_DMEMtoRAM_Ind(0x0d00, 0x0388, 0x050)
|
|
|
|
// 03f4 0080 0fa0 lri $AR0, #0x0fa0
|
|
// 03f6 0083 0d60 lri $AR3, #0x0d60
|
|
// 03f8 0f50 lris $AC1.M, #0x50
|
|
// 03f9 0098 8000 lri $AX0.L, #0x8000
|
|
// 03fb 02bf 00eb call 0x00eb
|
|
00eb_Unk_BufferMultAddToDest(0x0fa0, 0x0d60, 0x50, 0x8000)
|
|
|
|
// 03fd 0083 0d60 lri $AR3, #0x0d60
|
|
// 03ff 02bf 0cc1 call 0x0cc1
|
|
0cc1_StrangeORRFilter(0x0d60)
|
|
|
|
// 0401 0081 038a lri $AR1, #0x038a
|
|
// 0403 009f 0d60 lri $AC1.M, #0x0d60
|
|
// 0405 0080 0050 lri $AR0, #0x0050
|
|
// 0407 02bf 0530 call 0x0530
|
|
0530_DMEMtoRAM_Ind(0x0d60, 0x038a, 0x050)
|
|
|
|
|
|
// Move both RAM output buffer pointers forward, 0xa0 bytes (0x50 samples).
|
|
|
|
// 0409 009a 0000 lri $AX0.H, #0x0000
|
|
// 040b 0098 00a0 lri $AX0.L, #0x00a0
|
|
// 040d 0080 0388 lri $AR0, #0x0388
|
|
// 040f 02bf 0233 call 0x0233
|
|
0233_Increase_32BitAddress_InMem(0x0388, 0xa0)
|
|
// 0411 0080 038a lri $AR0, #0x038a
|
|
// 0413 02bf 0233 call 0x0233
|
|
0233_Increase_32BitAddress_InMem(0x038a, 0xa0)
|
|
|
|
|
|
// 0415 02bf 01ea call 0x01ea
|
|
01ea_Unk();
|
|
|
|
0417 0000 nop
|
|
0418 0000 nop
|
|
}
|
|
|
|
// 0419 0080 002d lri $AR0, #0x002d
|
|
// 041b 029f 0603 jmp 0x0603
|
|
0603_FinalizeFrame(0x02d)
|
|
}
|
|
|
|
// Command 07 - not seen used.
|
|
void 041d_Unk() {
|
|
041d 0080 0346 lri $AR0, #0x0346
|
|
// 041f 02bf 0067 call 0x0067
|
|
0067_CopyCommand(_destAddr(#0x0346), _loopCount($AC0.M))
|
|
// 0421 02bf 0067 call 0x0067
|
|
0067_CopyCommand(_destAddr(#0x0346), _loopCount($AC0.M))
|
|
|
|
0423 0081 0346 lri $AR1, #0x0346
|
|
0425 193e lrri $AC0.M, @$AR1
|
|
0426 193c lrri $AC0.L, @$AR1
|
|
0427 009f 0400 lri $AC1.M, #0x0400
|
|
0429 00c0 0345 lr $AR0, @0x0345
|
|
042b 02bf 0525 call 0x0525 // 0525_CopyRAMtoDMEM
|
|
042d 0081 0348 lri $AR1, #0x0348
|
|
042f 193e lrri $AC0.M, @$AR1
|
|
0430 193c lrri $AC0.L, @$AR1
|
|
0431 009f 0800 lri $AC1.M, #0x0800
|
|
0433 00c0 0345 lr $AR0, @0x0345
|
|
0435 02bf 0525 call 0x0525 // 0525_CopyRAMtoDMEM
|
|
0437 0081 0346 lri $AR1, #0x0346
|
|
0439 193e lrri $AC0.M, @$AR1
|
|
043a 193c lrri $AC0.L, @$AR1
|
|
043b 009f 0800 lri $AC1.M, #0x0800
|
|
043d 00c0 0345 lr $AR0, @0x0345
|
|
043f 02bf 0532 call 0x0532
|
|
0441 0081 0348 lri $AR1, #0x0348
|
|
0443 193e lrri $AC0.M, @$AR1
|
|
0444 193c lrri $AC0.L, @$AR1
|
|
0445 009f 0400 lri $AC1.M, #0x0400
|
|
0447 00c0 0345 lr $AR0, @0x0345
|
|
0449 02bf 0532 call 0x0532
|
|
044b 029f 0043 jmp 0x0043
|
|
}
|
|
|
|
void 044d_COMMAND_07()
|
|
{
|
|
044d 0080 0346 lri $AR0, #0x0346
|
|
044f 02bf 0067 call 0x0067
|
|
0451 02bf 0067 call 0x0067
|
|
0453 0081 0346 lri $AR1, #0x0346
|
|
0455 193e lrri $AC0.M, @$AR1
|
|
0456 193c lrri $AC0.L, @$AR1
|
|
0457 009f 0400 lri $AC1.M, #0x0400
|
|
0459 00c0 0345 lr $AR0, @0x0345
|
|
045b 02bf 0525 call 0x0525 // 0525_CopyRAMtoDMEM
|
|
045d 0081 0348 lri $AR1, #0x0348
|
|
045f 193e lrri $AC0.M, @$AR1
|
|
0460 193c lrri $AC0.L, @$AR1
|
|
0461 009f 0400 lri $AC1.M, #0x0400
|
|
0463 00c0 0345 lr $AR0, @0x0345
|
|
0465 02bf 0532 call 0x0532
|
|
0467 029f 0043 jmp 0x0043
|
|
}
|
|
|
|
void 0469_COMMAND_06_09()
|
|
{
|
|
0469 0080 0346 lri $AR0, #0x0346
|
|
046b 02bf 0067 call 0x0067
|
|
046d 02bf 0067 call 0x0067
|
|
046f 0081 0346 lri $AR1, #0x0346
|
|
0471 193e lrri $AC0.M, @$AR1
|
|
0472 193c lrri $AC0.L, @$AR1
|
|
0473 009f 0400 lri $AC1.M, #0x0400
|
|
0475 00c0 0345 lr $AR0, @0x0345
|
|
// 0477 02bf 0555 call 0x0555 // ReadFromMysteryReg
|
|
0555_UnknownReadFromMysteryReg(ARAMAddress(ACC0), DestBuffer(AC1.M), Length(AC0.M)) {
|
|
|
|
0479 0081 0348 lri $AR1, #0x0348
|
|
047b 193e lrri $AC0.M, @$AR1
|
|
047c 193c lrri $AC0.L, @$AR1
|
|
047d 009f 0400 lri $AC1.M, #0x0400
|
|
047f 00c0 0345 lr $AR0, @0x0345
|
|
0481 02bf 0532 call 0x0532
|
|
0483 029f 0043 jmp 0x0043
|
|
}
|
|
|
|
void 0485_COMMAND_08()
|
|
{
|
|
0485 0080 0346 lri $AR0, #0x0346
|
|
0487 02bf 0067 call 0x0067
|
|
0489 02bf 0067 call 0x0067
|
|
048b 0081 0346 lri $AR1, #0x0346
|
|
048d 193e lrri $AC0.M, @$AR1
|
|
048e 193c lrri $AC0.L, @$AR1
|
|
048f 009f 0400 lri $AC1.M, #0x0400
|
|
0491 00c0 0344 lr $AR0, @0x0344
|
|
0493 02bf 0525 call 0x0525 // 0525_CopyRAMtoDMEM
|
|
0495 0081 0348 lri $AR1, #0x0348
|
|
0497 193e lrri $AC0.M, @$AR1
|
|
0498 193c lrri $AC0.L, @$AR1
|
|
0499 009f 0800 lri $AC1.M, #0x0800
|
|
049b 00c0 0344 lr $AR0, @0x0344
|
|
049d 02bf 0525 call 0x0525 // 0525_CopyRAMtoDMEM
|
|
049f 0080 0400 lri $AR0, #0x0400
|
|
04a1 0083 0800 lri $AR3, #0x0800
|
|
04a3 0084 0000 lri $IX0, #0x0000
|
|
04a5 00da 0345 lr $AX0.H, @0x0345
|
|
04a7 00df 0344 lr $AC1.M, @0x0344
|
|
04a9 8f00 set40
|
|
04aa 197b lrri $AX1.H, @$AR3
|
|
04ab b800 mulx $AX0.H, $AX1.H
|
|
04ac 197b lrri $AX1.H, @$AR3
|
|
04ad 007f 04b2 bloop $AC1.M, 0x04b2
|
|
04af 199e lrrn $AC0.M, @$AR0
|
|
04b0 bc00 mulxac $AX0.H, $AX1.H, $ACC0
|
|
04b1 80b2 nx'sl : $AC0.M, $AX1.H
|
|
04b2 0000 nop
|
|
04b3 8e00 set16
|
|
04b4 0081 0346 lri $AR1, #0x0346
|
|
04b6 193e lrri $AC0.M, @$AR1
|
|
04b7 193c lrri $AC0.L, @$AR1
|
|
04b8 009f 0400 lri $AC1.M, #0x0400
|
|
04ba 00c0 0344 lr $AR0, @0x0344
|
|
04bc 02bf 0532 call 0x0532
|
|
04be 029f 0043 jmp 0x0043
|
|
}
|
|
|
|
|
|
// Zeroes 256 words @ 0x0b00, calls 0x0573
|
|
void 04c0_UnknownInit()
|
|
{
|
|
04c0 0092 00ff lri $CR, #0x00ff
|
|
04c2 8100 clr $ACC0
|
|
04c3 0080 0b00 lri $AR0, #0x0b00
|
|
04c5 10ff loopi #0xff
|
|
04c6 1b1e srri @$AR0, $AC0.M
|
|
04c7 1b1e srri @$AR0, $AC0.M
|
|
04c8 8100 clr $ACC0
|
|
04c9 009f 0b00 lri $AC1.M, #0x0b00
|
|
04cb 0080 0100 lri $AR0, #0x0100
|
|
04cd 02bf 0573 call 0x0573
|
|
|
|
04cf 02df ret
|
|
}
|
|
|
|
|
|
void 04d0_Unk() {
|
|
// 04d0 02bf 04e1 call 0x04e1
|
|
04e1_Read0x40WordsFromZeroTo0b00()
|
|
|
|
// 04fb is incremented when you reset a voice
|
|
04d2 00df 04fb lr $AC1.M, @0x04fb
|
|
04d4 009e 0b00 lri $AC0.M, #0x0b00
|
|
04d6 4c00 add $ACC0, $ACC1
|
|
04d7 1c1e mrr $AR0, $AC0.M
|
|
|
|
04d8 181e lrr $AC0.M, @$AR0
|
|
04d9 7400 incm $AC0.M
|
|
04da 1a1e srr @$AR0, $AC0.M
|
|
*(AR0)++
|
|
|
|
04db 02bf 04ea call 0x04ea
|
|
04dd 8100 clr $ACC0
|
|
04de 00fe 04fb sr @0x04fb, $AC0.M
|
|
04e0 02df ret
|
|
}
|
|
|
|
void 04e1_Read0x40WordsFromZeroTo0b00() {
|
|
04e1 0092 00ff lri $CR, #0x00ff
|
|
04e3 8100 clr $ACC0
|
|
04e4 009f 0b00 lri $AC1.M, #0x0b00
|
|
04e6 0080 0040 lri $AR0, #0x0040
|
|
// 04e8 029f 0555 jmp 0x0555
|
|
GOTO 0555_UnknownReadFromMysteryReg(ARAMAddress(ACC0), DestBuffer(AC1.M), Length(AR0)) {
|
|
}
|
|
|
|
void 04ea_Call0573With0b00And0050() {
|
|
04ea 8100 clr $ACC0
|
|
04eb 009f 0b00 lri $AC1.M, #0x0b00
|
|
04ed 0080 0050 lri $AR0, #0x0050
|
|
04ef 029f 0573 jmp 0x0573
|
|
// I don't get it, the above doesn't match the parameters
|
|
0573_Mystery_Write(InBuffer($AR1), _COUNT(AX0.H));
|
|
}
|
|
|
|
|
|
void 04f1_Read0x40WordsFromZeroTo0b00() {
|
|
// 04f1 02bf 04e1 call 0x04e1
|
|
04e1_Read0x40WordsFromZeroTo0b00();
|
|
}
|
|
|
|
void 04f3_strange() {
|
|
04f3 8900 clr $ACC1
|
|
04f4 0080 04fc lri $AR0, #0x04fc
|
|
04f6 8100 clr $ACC0
|
|
|
|
// Count the masked voices, look at all four mask words
|
|
// 04f7 1104 0505 bloopi #0x04, 0x0505
|
|
for (int j = 0; j < 4; j++) {
|
|
04f9 0000 nop
|
|
04fa 191e lrri $AC0.M, @$AR0
|
|
04fb 0000 nop
|
|
|
|
04fc 1110 0503 bloopi #0x10, 0x0503
|
|
for (int i = 0; i < 0x10; i++) {
|
|
04fe 02c0 0001 andcf $AC0.M, #0x0001
|
|
0500 027d iflz
|
|
0501 7500 incm $AC1.M // count up
|
|
0502 147f lsr $ACC0, #-1
|
|
0503 0000 nop
|
|
}
|
|
0504 0000 nop
|
|
0505 0000 nop
|
|
}
|
|
// AC1.M now contains the count of all voices masked/unmasked (not sure which)
|
|
|
|
// Copy the voice masks to 0x0b48 ...
|
|
0506 00de 04fc lr $AC0.M, @0x04fc
|
|
0508 00fe 0b48 sr @0x0b48, $AC0.M
|
|
050a 00de 04fd lr $AC0.M, @0x04fd
|
|
050c 00fe 0b49 sr @0x0b49, $AC0.M
|
|
050e 00de 04fe lr $AC0.M, @0x04fe
|
|
0510 00fe 0b4a sr @0x0b4a, $AC0.M
|
|
0512 00de 04ff lr $AC0.M, @0x04ff
|
|
0514 00fe 0b4b sr @0x0b4b, $AC0.M
|
|
|
|
0516 009e 0b00 lri $AC0.M, #0x0b00
|
|
0518 4c00 add $ACC0, $ACC1 // The value is in AC1.M, this must be wrong disasm
|
|
0519 1c1e mrr $AR0, $AC0.M
|
|
|
|
// Increment the counter at [ #0b00 + masked voice count]
|
|
// why would you do this? making bucket histogram over the number of active voices?
|
|
051a 181e lrr $AC0.M, @$AR0
|
|
051b 7400 incm $AC0.M
|
|
051c 1a1e srr @$AR0, $AC0.M
|
|
|
|
051d 02bf 04ea call 0x04ea // 04ea_Call0573With0b00And0050()
|
|
051f 02df ret
|
|
}
|
|
|
|
void PointlessFunction_Unused() {
|
|
0520 02bf 04ea call 0x04ea // 04ea_Call0573With0b00And0050()
|
|
0522 02df ret
|
|
}
|
|
|
|
|
|
// the first parameter is a pointer to the real RAM addr
|
|
void 0523_CopyRAMtoDMEM(&_srcRAM($AR1), _destDMEM($AC1.M), _len($AR0))
|
|
{
|
|
// 0523 193e lrri $AC0.M, @$AR1
|
|
// 0524 193c lrri $AC0.L, @$AR1
|
|
AC0 = *AR1++ << 16 | *AR1
|
|
|
|
void 0525_CopyRAMtoDMEM(_srcRAM($AR1), _destDMEM($AC1.M), _len($AR0))
|
|
{
|
|
0525 2fcd srs @DSPA, $AC1.M
|
|
0526 0f00 lris $AC1.M, #0x00
|
|
|
|
// ugly jump to share code... i am not going to document it ^^
|
|
0527 2fc9 srs @DSCR, $AC1.M
|
|
0528 2ece srs @DSMAH, $AC0.M
|
|
0529 2ccf srs @DSMAL, $AC0.L
|
|
052a 1fe0 mrr $AC1.M, $AR0
|
|
052b 1501 lsl $ACC1, #1
|
|
052c 2fcb srs @DSBL, $AC1.M
|
|
|
|
// 052d 02bf 0536 call 0x0536
|
|
0536_WaitForDMATransfer()
|
|
|
|
// 052f 02df ret
|
|
}
|
|
|
|
void 0530_DMEMtoRAM_Ind(_DMEM(AC1.M), _pMemAddr(AR1), _len(AR0))
|
|
{
|
|
// 0530 193e lrri $AC0.M, @$AR1
|
|
// 0531 193c lrri $AC0.L, @$AR1
|
|
AC0 = *AR1++ << 16 | *AR1
|
|
// continues....
|
|
|
|
void 0532_DMEMtoRAM(_DMEM(AC1.M), _pMemAddr(ACC0), _len(AR0))
|
|
{
|
|
0532 2fcd srs @DSPA, $AC1.M
|
|
0533 0f01 lris $AC1.M, #0x01
|
|
0534 029f 0527 jmp 0x0527
|
|
}
|
|
|
|
void 0536_WaitForDMATransfer()
|
|
{
|
|
0536 26c9 lrs $AC0.M, @DSCR
|
|
0537 02a0 0004 andf $AC0.M, #0x0004
|
|
0539 029c 0536 jlnz 0x0536
|
|
053b 02df ret
|
|
}
|
|
|
|
// Can't find any calls to this one.
|
|
void 053c_Unk_Unused() {
|
|
053c 193e lrri $AC0.M, @$AR1
|
|
053d 193c lrri $AC0.L, @$AR1
|
|
053e 00ff ffcd sr @DSPA, $AC1.M
|
|
0540 0f00 lris $AC1.M, #0x00
|
|
0541 00ff ffc9 sr @DSCR, $AC1.M
|
|
0543 00fe ffce sr @DSMAH, $AC0.M
|
|
0545 00fc ffcf sr @DSMAL, $AC0.L
|
|
0547 1fe0 mrr $AC1.M, $AR0
|
|
0548 1501 lsl $ACC1, #1
|
|
0549 00ff ffcb sr @DSBL, $AC1.M
|
|
054b 02df ret
|
|
}
|
|
|
|
void 054c_WaitForDMATransfer2_Unused() {
|
|
054c 00de ffc9 lr $AC0.M, @DSCR
|
|
054e 02a0 0004 andf $AC0.M, #0x0004
|
|
0550 029c 054c jlnz 0x054c
|
|
0552 02df ret
|
|
}
|
|
|
|
void 0553_UnknownReadFromMysteryReg_Unused() {
|
|
0553 193e lrri $AC0.M, @$AR1
|
|
0554 193c lrri $AC0.L, @$AR1
|
|
// continues...
|
|
|
|
void 0555_UnknownReadFromMysteryReg(ARAMAddress(ACC0), DestBuffer(AC1.M), Length(AC0.M)) {
|
|
// 0555 0240 7fff andi $AC0.M, #0x7fff
|
|
// 0557 02bf 0561 call 0x0561
|
|
0561_SetupAcceleratorForMysteryAccess(ACC0 & 0x7FFFFFFF, AR0, AC1.M);
|
|
// After that, length is now in AX0.H
|
|
|
|
// 0559 007a 055f bloop $AX0.H, 0x055f
|
|
for (int i = 0; i < AX0.H; i++) {
|
|
// 055b 26d3 lrs $AC0.M, @Unk Zelda
|
|
// 055c 1b3e srri @$AR1, $AC0.M
|
|
*(AR1++) = ReadFromUnknownAcceleratorRegister();
|
|
}
|
|
// 055d 0000 nop
|
|
// 055e 0000 nop
|
|
// 055f 0000 nop
|
|
// 0560 02df ret
|
|
}
|
|
|
|
void 0561_SetupAcceleratorForMysteryAccess(ARAMAddress(ACC0), DestBuffer(AC1.M), Length(AR0)) {
|
|
0561 1c3f mrr $AR1, $AC1.M
|
|
0562 0f0a lris $AC1.M, #0x0a
|
|
0563 2fd1 srs @SampleFormat, $AC1.M
|
|
0564 1f5e mrr $AX0.H, $AC0.M
|
|
0565 1f1c mrr $AX0.L, $AC0.L
|
|
// Store 0xFFFFFFFF value as end address - Zelda does not use the looping hardware
|
|
0566 009e ffff lri $AC0.M, #0xffff
|
|
0568 2ed6 srs @ACEAH, $AC0.M // end address
|
|
0569 2ed7 srs @ACEAL, $AC0.M
|
|
056a 1fda mrr $AC0.M, $AX0.H
|
|
056b 1f98 mrr $AC0.L, $AX0.L
|
|
// Divide "current" address by 2.
|
|
056c 147f lsr $ACC0, #-1
|
|
056d 2ed8 srs @ACCAH, $AC0.M // Current address
|
|
056e 2cd9 srs @ACCAL, $AC0.L
|
|
056f 1f40 mrr $AX0.H, $AR0
|
|
0570 02df ret
|
|
}
|
|
|
|
// Writes to UnkZelda, nops
|
|
void 0571_Mystery_Write_FirstLoadTwoRegs_Unused() {
|
|
0571 193e lrri $AC0.M, @$AR1
|
|
0572 193c lrri $AC0.L, @$AR1
|
|
|
|
void 0573_Mystery_Write(InBuffer($AR1), SourceBuffer(AC1.M), _COUNT(AX0.H)) {
|
|
0573 0090 0001 lri $AC0.H, #0x0001
|
|
// 0575 02bf 0561 call 0x0561
|
|
0561_SetupAcceleratorForMysteryAccess(ACC0, AR0, AC1.M);
|
|
0577 007a 057e bloop $AX0.H, 0x057e
|
|
0579 193e lrri $AC0.M, @$AR1
|
|
057a 2ed3 srs @Unk Zelda, $AC0.M
|
|
057b 0000 nop // seems the above store takes some time,
|
|
057c 0000 nop // whatever it does, so ... 4 nops does the trick I guess
|
|
057d 0000 nop
|
|
057e 0000 nop
|
|
057f 02df ret
|
|
}
|
|
|
|
|
|
void 0580_COMMAND_04()
|
|
{
|
|
// commando looks buggy...
|
|
// it copies data to the switch casement data address... sounds like BS
|
|
|
|
0580 0080 0346 lri $AR0, #0x0346
|
|
0582 02bf 0067 call 0x0067
|
|
0584 02bf 0067 call 0x0067
|
|
|
|
0067_CopyCommand(0x0346, mssing AC0.M??)
|
|
|
|
0586 0081 0346 lri $AR1, #0x0346
|
|
0588 00df 0349 lr $AC1.M, @0x0349
|
|
058a 0340 ffff andi $AC1.M, #0xffff
|
|
058c 00c0 0345 lr $AR0, @0x0345
|
|
058e 02bf 0523 call 0x0523
|
|
0590 029f 0043 jmp 0x0043
|
|
}
|
|
|
|
void 0592_COMMAND_05()
|
|
{
|
|
0592 0080 0346 lri $AR0, #0x0346
|
|
0594 02bf 0067 call 0x0067
|
|
0596 02bf 0067 call 0x0067
|
|
|
|
// 0598 0081 0346 lri $AR1, #0x0346
|
|
// 059a 00df 0349 lr $AC1.M, @0x0349
|
|
// 059c 0340 ffff andi $AC1.M, #0xffff
|
|
// 059e 00c0 0345 lr $AR0, @0x0345
|
|
// 05a0 02bf 0530 call 0x0530
|
|
0530_DMEMtoRAM_Ind((*0x0349)&0xFFFF, 0x0346, *0x0345)
|
|
|
|
// 05a2 029f 0043 jmp 0x0043
|
|
// jumps back to send sync messages ....
|
|
}
|
|
|
|
|
|
void 05A4_ResetAccelerator()
|
|
{
|
|
05a4 0092 00ff lri $CR, #0x00ff
|
|
05a6 009e ffff lri $AC0.M, #0xffff
|
|
05a8 2ed4 srs @ACSAH, $AC0.M
|
|
05a9 2ed5 srs @ACSAL, $AC0.M
|
|
05aa 2ed6 srs @ACEAH, $AC0.M
|
|
05ab 2ed7 srs @ACEAL, $AC0.M
|
|
05ac 02df ret
|
|
}
|
|
|
|
|
|
void 05ad_SetupAccelerator(_acceleratorH(AC0.M), _accleratorL(AC0.L), _format(AC1.M))
|
|
{
|
|
// 05ad 00ff ffd1 sr @SampleFormat, $AC1.M
|
|
*SampleFormat = AC1.M
|
|
|
|
// 05af 0340 0003 andi $AC1.M, #0x0003
|
|
// 05b1 7900 decm $AC1.M
|
|
// 05b2 02ca lsrn // ACC0 >>= AC1.M
|
|
// 05b3 00fe ffd8 sr @ACCAH, $AC0.M
|
|
// 05b5 00fc ffd9 sr @ACCAL, $AC0.L
|
|
|
|
*ACCAH/ACCAL = address >> ((sampleFormat & 3) - 1);
|
|
// ACCAH/ACCAL is current read address
|
|
// Hm, this seems to imply some direct relationship between the sample format number and
|
|
// the nibbles-per-sample value
|
|
|
|
// 05b7 02df ret
|
|
}
|
|
|
|
void 05b8_NewMail() {
|
|
# 05b8 1205 sbclr #0x05
|
|
# 05b9 8e00 set16
|
|
|
|
/*
|
|
05ba 00f0 03fd sr @0x03fd, $AC0.H
|
|
05bc 00fc 03ff sr @0x03ff, $AC0.L
|
|
05be f400 lsr16 $ACC0
|
|
05bf 00fc 03fe sr @0x03fe, $AC0.L
|
|
05c1 00fa 03fa sr @0x03fa, $AX0.H
|
|
05c3 8100 clr $ACC0
|
|
|
|
save AC0 register
|
|
*/
|
|
|
|
*0x03fd = AC0.H
|
|
*0x03ff = AC0.L
|
|
ACC0 >>= 16
|
|
*0x03fe = AC0.L
|
|
*0x03fa = AX0.H
|
|
|
|
// 05c4 00de fffe lr $AC0.M, @CMBH
|
|
// 05c6 02c0 8000 andcf $AC0.M, #0x8000
|
|
// 05c8 029c 06b9 jlnz 0x06b9
|
|
if (@CMBH & 0x8000 > 0)
|
|
{
|
|
!MISSING!
|
|
}
|
|
|
|
// 05ca 00da ffff lr $AX0.H, @CMBL
|
|
// 05cc 8600 tstaxh $AX0.H
|
|
// 05cd 0294 0692 jnz 0x0692
|
|
if (*CMBL != 0)
|
|
{
|
|
!MISSING!
|
|
}
|
|
|
|
|
|
// 05cf 00de fffe lr $AC0.M, @CMBH
|
|
// 05d1 02c0 8000 andcf $AC0.M, #0x8000
|
|
// 05d3 029c 05cf jlnz 0x05cf
|
|
while(@CMBH & 0x8000 > 0);
|
|
|
|
|
|
// 05d5 0240 000f andi $AC0.M, #0x000f
|
|
// 05d7 1f5e mrr $AX0.H, $AC0.M
|
|
// 05d8 7400 incm $AC0.M
|
|
// 05d9 0c00 lris $AC0.L, #0x00
|
|
// 05da 1404 lsl $ACC0, #4
|
|
// 05db 00fe 034e sr @0x034e, $AC0.M
|
|
AC0.M = *CMBH & 0x000F
|
|
AX0.H = AC0.M
|
|
*0x034e = (AC0.M++) << 4
|
|
|
|
|
|
// 05dd 1fda mrr $AC0.M, $AX0.H
|
|
// 05de 1f40 mrr $AX0.H, $AR0
|
|
// 05df 0200 04fc addi $AC0.M, #0x04fc
|
|
// 05e1 1c1e mrr $AR0, $AC0.M
|
|
|
|
AX0.H = AR0 // save AR0
|
|
|
|
AC0.M = *CMBH & 0x000F
|
|
AC0.M += 0x04fc
|
|
AR0 = AC0.M
|
|
|
|
// 05e2 00de ffff lr $AC0.M, @CMBL
|
|
// 05e4 1a1e srr @$AR0, $AC0.M
|
|
// 05e5 1c1a mrr $AR0, $AX0.H
|
|
AC0.M = *CMBL
|
|
*AR0 = AC0.M
|
|
AR0 = AX.H // restore AR0
|
|
|
|
|
|
EndOfMailException:
|
|
|
|
/*
|
|
05e6 00de 03fe lr $AC0.M, @0x03fe
|
|
05e8 00dc 03ff lr $AC0.L, @0x03ff
|
|
05ea 00d0 03fd lr $AC0.H, @0x03fd
|
|
05ec 00da 03fa lr $AX0.H, @0x03fa
|
|
restore AC0 register
|
|
*/
|
|
AC0.M = *0x03fe
|
|
AC0.L = *0x03ff
|
|
AC0.H = *0x03fd
|
|
AX0.H = *0x03fa
|
|
|
|
# 05ee 1305 sbset #0x05
|
|
|
|
05ef 02ff rti
|
|
}
|
|
|
|
void 05f0_HaltUCode()
|
|
{
|
|
05f0 009a 0002 lri $AX0.H, #0x0002
|
|
05f2 00fa 03a3 sr @0x03a3, $AX0.H
|
|
05f4 00e0 03f9 sr @0x03f9, $AR0
|
|
/*
|
|
05f6 02bf 067c call 0x067c
|
|
*/
|
|
067c_Unk()
|
|
|
|
05f8 16fc dcd1 si @DMBH, #0xdcd1
|
|
05fa 16fd 0002 si @DMBL, #0x0002
|
|
05fc 16fb 0001 si @DIRQ, #0x0001
|
|
05fe 0021 halt
|
|
}
|
|
|
|
// Sync Table
|
|
05ff 0617 cmpis $ACC0, #0x17
|
|
0600 0618 cmpis $ACC0, #0x18
|
|
0601 0658 cmpis $ACC0, #0x58
|
|
0602 065b cmpis $ACC0, #0x5b
|
|
|
|
// at the end of a frame, we get a mail telling ucode what to do next
|
|
void 0603_FinalizeFrame(_returnAddr($AR0))
|
|
{
|
|
// 0603 00e0 03f9 sr @0x03f9, $AR0
|
|
0x03f9 = _returnAddr
|
|
|
|
// 0605 009e 0005 lri $AC0.M, #0x0005
|
|
// 0607 02bf 066a call 0x066a
|
|
SendMB_DCD1(0x0005)
|
|
|
|
# 0609 8e00 set16
|
|
// 060a 8100 clr $ACC0
|
|
// 060b 8900 clr $ACC1
|
|
ACC0 = 0
|
|
ACC1 = 0
|
|
|
|
// 060c 02bf 065e call 0x065e
|
|
065e_WaitForCPUMailBox_AC0()
|
|
|
|
// 060e 27ff lrs $AC1.M, @CMBL
|
|
// 060f 009e 05ff lri $AC0.M, #0x05ff
|
|
// 0611 4c00 add $ACC0, $ACC1
|
|
AC0.M = 0x05ff + *CMBL
|
|
|
|
// 0612 1c7e mrr $AR3, $AC0.M
|
|
// 0613 0313 ilrr $AC1.M, @$AR3
|
|
// 0614 1c7f mrr $AR3, $AC1.M
|
|
AR3 = *AC0.M <- "BUT FROM Instrcution Memory (look at sync table about)"
|
|
|
|
// 0615 176f jmpr $AR3
|
|
switch(AR3 - 0x05FF)
|
|
{
|
|
case 0x00: HALT(); break;
|
|
case 0x01: 0618_PrepareBootUcode(); break;
|
|
case 0x02: 0658_SoftReset(); break;
|
|
case 0x03: 065b_ContinueWithUCode(); break;
|
|
default: HALT();
|
|
// 0616 0021 halt
|
|
}
|
|
}
|
|
|
|
0617 0021 halt
|
|
|
|
// Sets up info needed to dma in a chunk to iram or dram,
|
|
// and calls irom to do actual dma. irom returns to address given in AR0
|
|
void 0618_PrepareBootUcode() {
|
|
// Dunno what that's about...
|
|
0618 009a 0002 lri $AX0.H, #0x0002
|
|
061a 00fa 03a3 sr @0x03a3, $AX0.H
|
|
|
|
061c 8100 clr $ACC0
|
|
061d 8900 clr $ACC1
|
|
|
|
//061e 02bf 065e call 0x065e
|
|
065e_WaitForCPUMailBox_AC0()
|
|
|
|
0620 24ff lrs $AC0.L, @CMBL
|
|
|
|
//0621 02bf 0664 call 0x0664
|
|
0664_WaitForCPUMailBox_AC1()
|
|
|
|
0623 25ff lrs $AC1.L, @CMBL
|
|
|
|
//0624 02bf 0664 call 0x0664
|
|
0664_WaitForCPUMailBox_AC1()
|
|
|
|
0626 27ff lrs $AC1.M, @CMBL
|
|
0627 2ece srs @DSMAH, $AC0.M
|
|
0628 2ccf srs @DSMAL, $AC0.L // 0
|
|
0629 16c9 0001 si @DSCR, #0x0001
|
|
062b 2fcd srs @DSPA, $AC1.M // 2
|
|
062c 2dcb srs @DSBL, $AC1.L // 1
|
|
|
|
062d 8100 clr $ACC0
|
|
062e 8900 clr $ACC1
|
|
|
|
//062f 02bf 065e call 0x065e
|
|
065e_WaitForCPUMailBox_AC0()
|
|
|
|
0631 24ff lrs $AC0.L, @CMBL
|
|
0632 1c9e mrr $IX0, $AC0.M
|
|
0633 1cbc mrr $IX1, $AC0.L
|
|
//0634 02bf 0664 call 0x0664
|
|
0664_WaitForCPUMailBox_AC1()
|
|
|
|
0636 25ff lrs $AC1.L, @CMBL
|
|
|
|
//0637 02bf 0664 call 0x0664
|
|
0664_WaitForCPUMailBox_AC1()
|
|
|
|
0639 27ff lrs $AC1.M, @CMBL
|
|
063a 1cdf mrr $IX2, $AC1.M
|
|
063b 1cfd mrr $IX3, $AC1.L
|
|
063c 8100 clr $ACC0
|
|
|
|
//063d 02bf 065e call 0x065e
|
|
065e_WaitForCPUMailBox_AC0()
|
|
|
|
063f 26ff lrs $AC0.M, @CMBL
|
|
0640 1c1e mrr $AR0, $AC0.M
|
|
0641 8900 clr $ACC1
|
|
//0642 02bf 0664 call 0x0664
|
|
0664_WaitForCPUMailBox_AC1()
|
|
|
|
0644 20ff lrs $AX0.L, @CMBL
|
|
0645 1f5f mrr $AX0.H, $AC1.M
|
|
//0646 02bf 065e call 0x065e
|
|
065e_WaitForCPUMailBox_AC0()
|
|
|
|
0648 21ff lrs $AX1.L, @CMBL
|
|
|
|
//0649 02bf 065e call 0x065e
|
|
065e_WaitForCPUMailBox_AC0()
|
|
|
|
064b 23ff lrs $AX1.H, @CMBL
|
|
|
|
// Make sure dma is ready
|
|
// 064c 26c9 lrs $AC0.M, @DSCR
|
|
// 064d 02a0 0004 andf $AC0.M, #0x0004
|
|
// 064f 029c 064c jlnz 0x064c
|
|
|
|
// Reset some of the state
|
|
// 0651 1206 sbclr #0x06
|
|
// 0652 1203 sbclr #0x03
|
|
// 0653 1204 sbclr #0x04
|
|
// 0654 1205 sbclr #0x05
|
|
|
|
// 0655 029f 80b5 jmp 0x80b5
|
|
80b5_BootUcode();
|
|
|
|
// Should not reach here
|
|
0657 0021 halt
|
|
}
|
|
|
|
void 0658_SoftReset() {
|
|
0658 029f 8000 jmp 0x8000
|
|
065a 0021 halt
|
|
}
|
|
|
|
void 065b_ContinueWithUCode()
|
|
{
|
|
// 065b 00c0 03f9 lr $AR0, @0x03f9
|
|
// 065d 170f jmpr $AR0
|
|
GOTO *0x03f9;
|
|
}
|
|
|
|
|
|
void 065e_WaitForCPUMailBox_AC0()
|
|
{
|
|
065e 26fe lrs $AC0.M, @CMBH
|
|
065f 02c0 8000 andcf $AC0.M, #0x8000
|
|
0661 029c 065e jlnz 0x065e
|
|
0663 02df ret
|
|
}
|
|
|
|
void 0664_WaitForCPUMailBox_AC1()
|
|
{
|
|
0664 27fe lrs $AC1.M, @CMBH
|
|
0665 03c0 8000 andcf $AC1.M, #0x8000
|
|
0667 029c 0664 jlnz 0x0664
|
|
0669 02df ret
|
|
}
|
|
void SendMB_DCD1(_low)
|
|
{
|
|
// 066a 02bf 0682 call 0x0682
|
|
WaitForEmptyDSPMailBox_ovAC1();
|
|
|
|
// 066c 16fc dcd1 si @DMBH, #0xdcd1
|
|
// 066e 2efd srs @DMBL, $AC0.M
|
|
// 066f 16fb 0001 si @DIRQ, #0x0001
|
|
|
|
*DMBH = 0xDCD1
|
|
*DMBL = _low
|
|
*DIRQ = 0x0001
|
|
|
|
// 0671 02bf 0682 call 0x0682
|
|
WaitForEmptyDSPMailBox_ovAC1()
|
|
|
|
// 0673 02df ret
|
|
}
|
|
|
|
|
|
void SendMB_F355(_low)
|
|
{
|
|
// 0674 02bf 0682 call 0x0682
|
|
WaitForEmptyDSPMailBox_ovAC1();
|
|
|
|
// 0676 16fc f355 si @DMBH, #0xf355
|
|
// 0678 2efd srs @DMBL, $AC0.M
|
|
|
|
*DMBH = 0xf355
|
|
*DMBL = _low
|
|
|
|
// 0679 02bf 0682 call 0x0682
|
|
WaitForEmptyDSPMailBox_ovAC1();
|
|
|
|
// 067b 02df ret
|
|
}
|
|
|
|
|
|
void 067c_Unk()
|
|
{
|
|
067c 26fc lrs $AC0.M, @DMBH
|
|
067d 02c0 8000 andcf $AC0.M, #0x8000
|
|
067f 029d 067c jlz 0x067c
|
|
0681 02df ret
|
|
}
|
|
|
|
|
|
void WaitForEmptyDSPMailBox_ovAC1.M()
|
|
{
|
|
// 0682 27fc lrs $AC1.M, @DMBH
|
|
// 0683 03c0 8000 andcf $AC1.M, #0x8000
|
|
// 0685 029d 0682 jlz 0x0682
|
|
while (*DMBH & 0x8000);
|
|
|
|
// 0687 02df ret
|
|
}
|
|
|
|
|
|
void 0688_InitCommandBlock()
|
|
{
|
|
// 0688 009a 0280 lri $AX0.H, #0x0280
|
|
// 068a 00fa 0350 sr @0x0350, $AX0.H
|
|
// 068c 00fa 0351 sr @0x0351, $AX0.H
|
|
*0x0350 = 0x0280
|
|
*0x0351 = 0x0280
|
|
|
|
// 068e 0a00 lris $AX0.H, #0x00
|
|
// 068f 00fa 0352 sr @0x0352, $AX0.H
|
|
*0x0352 = 0x00
|
|
|
|
// 0691 02df ret
|
|
}
|
|
|
|
//
|
|
// this block is called by the new mail exception
|
|
// it seems to copy a new command to the address @0x0350 and increase the
|
|
// number of commands at 0x0352
|
|
//
|
|
{
|
|
0692 00e0 03fb sr @0x03fb, $AR0
|
|
0694 00e8 03fc sr @0x03fc, $WR0
|
|
0696 00c0 0350 lr $AR0, @0x0350
|
|
0698 0088 002f lri $WR0, #0x002f
|
|
|
|
do {
|
|
069a 1b1a srri @$AR0, $AX0.H
|
|
|
|
// 069b 00de fffe lr $AC0.M, @CMBH
|
|
// 069d 02c0 8000 andcf $AC0.M, #0x8000
|
|
// 069f 029c 069b jlnz 0x069b
|
|
while (!CMBH & 0x8000)
|
|
;
|
|
06a1 00dc ffff lr $AC0.L, @CMBL
|
|
06a3 1b1e srri @$AR0, $AC0.M
|
|
06a4 1b1c srri @$AR0, $AC0.L
|
|
06a5 1fda mrr $AC0.M, $AX0.H
|
|
06a6 7800 decm $AC0.M
|
|
06a7 1f5e mrr $AX0.H, $AC0.M
|
|
|
|
// 06a8 8600 tstaxh $AX0.H
|
|
// 06a9 0294 069b jnz 0x069b
|
|
} while (AX0.H);
|
|
|
|
/*
|
|
06ab 8100 clr $ACC0
|
|
06ac 00de 0352 lr $AC0.M, @0x0352
|
|
06ae 7400 incm $AC0.M
|
|
06af 00fe 0352 sr @0x0352, $AC0.M
|
|
increase number of commands
|
|
*/
|
|
*0x0352 = *0x0352++
|
|
|
|
|
|
06b1 00e0 0350 sr @0x0350, $AR0
|
|
06b3 00c0 03fb lr $AR0, @0x03fb
|
|
06b5 00c8 03fc lr $WR0, @0x03fc
|
|
|
|
// 06b7 029f 05e6 jmp 0x05e6
|
|
GOTO EndOfMailException // return values and leave exception
|
|
|
|
// looks like a read from ring buffer [0x350, 0x37f]
|
|
// note the use of the wrap register WR0.
|
|
06b9 00e0 03fb sr @0x03fb, $AR0
|
|
06bb 00e8 03fc sr @0x03fc, $WR0
|
|
06bd 00c0 0350 lr $AR0, @0x0350
|
|
06bf 0088 002f lri $WR0, #0x002f
|
|
06c1 0a00 lris $AX0.H, #0x00
|
|
06c2 1b1a srri @$AR0, $AX0.H
|
|
06c3 029f 06ab jmp 0x06ab
|
|
}
|
|
|
|
|
|
void 06c5_CopyCommandBlock()
|
|
{
|
|
// 06c5 00c0 0351 lr $AR0, @0x0351
|
|
short srcCommandQueueAddr = *0x0351
|
|
|
|
// 06c7 0088 002f lri $WR0, #0x002f
|
|
$WR0 = #0x002f
|
|
|
|
|
|
:start
|
|
/*
|
|
06c9 00da 0352 lr $AX0.H, @0x0352
|
|
06cb 8600 tstaxh $AX0.H
|
|
06cc 0295 06ed jz 0x06ed
|
|
check how many commands are inside the "queue"
|
|
*/
|
|
|
|
if (*0x352 == 0)
|
|
{
|
|
$WR0 = #0xffff
|
|
return 0x2d;
|
|
}
|
|
|
|
/*
|
|
06ce 1205 sbclr #0x05
|
|
06cf 00da 0352 lr $AX0.H, @0x0352
|
|
06d1 1fda mrr $AC0.M, $AX0.H
|
|
06d2 7800 decm $AC0.M
|
|
06d3 00fe 0352 sr @0x0352, $AC0.M
|
|
06d5 1305 sbset #0x05
|
|
decrement number of commands in queue
|
|
*/
|
|
*0x352--;
|
|
|
|
// 06d6 0081 0356 lri $AR1, #0x0356
|
|
short destCommandQueueAddr = 0x0356
|
|
|
|
// 06d8 191e lrri $AC0.M, @$AR0
|
|
// 06d9 02c0 8000 andcf $AC0.M, #0x8000
|
|
// 06db 029d 06f1 jlz 0x06f1
|
|
// 06dd 1f5e mrr $AX0.H, $AC0.M
|
|
// 06de 8600 tstaxh $AX0.H
|
|
// 06df 0295 06f5 jz 0x06f5
|
|
|
|
// check if command is valid
|
|
|
|
short numCommands = *srcCommandQueueAddr++
|
|
numCommands &= 0x8000
|
|
if (numCommands < 0)
|
|
{
|
|
*0x0351 = srcCommandQueueAddr
|
|
GOTO :start
|
|
}
|
|
|
|
if (numCommands == 0)
|
|
{
|
|
05f0_HaltUCode()
|
|
}
|
|
|
|
/*
|
|
06e1 007a 06e6 bloop $AX0.H, 0x06e6
|
|
06e3 191e lrri $AC0.M, @$AR0
|
|
06e4 1b3e srri @$AR1, $AC0.M
|
|
06e5 191e lrri $AC0.M, @$AR0
|
|
06e6 1b3e srri @$AR1, $AC0.M
|
|
|
|
copy command queue
|
|
*/
|
|
|
|
for (int i=0; i<numCommands; i++)
|
|
{
|
|
*destCommandQueueAddr++ = *srcCommandQueueAddr++
|
|
*destCommandQueueAddr++ = *srcCommandQueueAddr++
|
|
}
|
|
|
|
// 06e7 00e0 0351 sr @0x0351, $AR0
|
|
*0x0351 = srcCommandQueueAddr
|
|
|
|
# 06e9 0088 ffff lri $WR0, #0xffff
|
|
|
|
// 06eb 029f 002f jmp 0x002f
|
|
return 0x2f
|
|
|
|
/*
|
|
06ed 0088 ffff lri $WR0, #0xffff
|
|
06ef 029f 002d jmp 0x002d
|
|
early out
|
|
*/
|
|
|
|
/*
|
|
06f1 00e0 0351 sr @0x0351, $AR0
|
|
06f3 029f 06c9 jmp 0x06c9
|
|
next command
|
|
*/
|
|
|
|
/*
|
|
06f5 0080 06c5 lri $AR0, #0x06c5
|
|
06f7 029f 05f0 jmp 0x05f0
|
|
05f0_HaltUCode()
|
|
*/
|
|
}
|
|
|
|
|
|
void 06f9_Unk_PrepareSampleDecode()
|
|
{
|
|
06f9 8100 clr $ACC0
|
|
06fa 0e10 lris $AC0.M, #0x10
|
|
06fb 2232 lrs $AX0.H, @0x0032
|
|
// 06fc 8600 tstaxh $AX0.H
|
|
// 06fd 02d5 retz
|
|
if (!*0x0432)
|
|
return;
|
|
|
|
06fe 5400 subr $ACC0, $AX0.H
|
|
06ff 0200 0458 addi $AC0.M, #0x0458
|
|
0701 1c1e mrr $AR0, $AC0.M
|
|
0702 1fda mrr $AC0.M, $AX0.H
|
|
0703 04fe addis $ACC0, #0xfe
|
|
0704 1f1e mrr $AX0.L, $AC0.M
|
|
0705 191e lrri $AC0.M, @$AR0
|
|
// 0706 0291 070c jl 0x070c
|
|
if ( .. ?? ..) {
|
|
0708 191a lrri $AX0.H, @$AR0
|
|
// Copy-loop
|
|
0709 0058 loop $AX0.L
|
|
070a 64a0 movr'ls $ACC0, $AX0.H : $AX0.H, $AC0.M
|
|
070b 6433 movr's $ACC0, $AX0.H : @$AR3, $AC0.M
|
|
}
|
|
070c 1b7e srri @$AR3, $AC0.M
|
|
070d 02df ret
|
|
}
|
|
|
|
|
|
// early out for 073d_DECODE_0x05_0x09
|
|
void EarlyOutFrom_073d_DECODE_0x05_0x09() {
|
|
//070e 02bf 06f9 call 0x06f9
|
|
06f9_Unk_PrepareSampleDecode()
|
|
// 0710 8100 clr $ACC0
|
|
// 0711 2632 lrs $AC0.M, @0x0032
|
|
// 0712 5c00 sub $ACC0, $ACC1
|
|
// 0713 2e32 srs @0x0032, $AC0.M
|
|
|
|
*0x0432 -= _numberOfSamples // PB.CurBlock
|
|
|
|
// 0714 0092 00ff lri $CR, #0x00ff
|
|
// 0716 02df ret
|
|
}
|
|
|
|
// Here, CR is 0x04 and thus these are not hw regs.
|
|
void 0717_InitializeDecoderState() // 0xff88 to 0xff8B
|
|
{
|
|
// 0717 00de 04fb lr $AC0.M, @0x04fb
|
|
// 0719 7400 incm $AC0.M
|
|
// 071a 00fe 04fb sr @0x04fb, $AC0.M
|
|
|
|
(*0x4fb)++;
|
|
|
|
// 071c 8100 clr $ACC0
|
|
// 071d 2e32 srs @0x0032, $AC0.M
|
|
// 071e 2e66 srs @0x0066, $AC0.M
|
|
// 071f 2e67 srs @0x0067, $AC0.M
|
|
|
|
PB.CurBlock = 0
|
|
PB.YN1 = 0
|
|
PB.YN2 = 0
|
|
|
|
// 0720 268a lrs $AC0.M, @0xff8a
|
|
// 0721 248b lrs $AC0.L, @0xff8b
|
|
// 0722 2e3a srs @0x003a, $AC0.M
|
|
// 0723 2c3b srs @0x003b, $AC0.L
|
|
|
|
PB.RemLength = PB.Length
|
|
|
|
// 0724 268c lrs $AC0.M, @0xff8c
|
|
// 0725 248d lrs $AC0.L, @0xff8d
|
|
// 0726 2e38 srs @0x0038, $AC0.M
|
|
// 0727 2c39 srs @0x0039, $AC0.L
|
|
|
|
PB.CurAddr = PB.StartAddr
|
|
|
|
// 0728 02df ret
|
|
}
|
|
|
|
void 0729_UpdateDecoderState()
|
|
{
|
|
// 0729 8100 clr $ACC0
|
|
// 072a 2689 lrs $AC0.M, @0xff89
|
|
// 072b 0240 000f andi $AC0.M, #0x000f
|
|
|
|
$AC0.M = PB.LoopStartPos & 0xf;
|
|
|
|
// 072d 1f5e mrr $AX0.H, $AC0.M
|
|
// 072e 8100 clr $ACC0
|
|
// 072f 0e10 lris $AC0.M, #0x10
|
|
// 0730 5400 subr $ACC0, $AX0.H
|
|
|
|
$AC0.M = 0x10 - (PB.LoopStartPos & 0xf)
|
|
|
|
// 0731 2e32 srs @0x0032, $AC0.M
|
|
|
|
PB.CurBlock = 0x10 - (PB.LoopStartPos & 0xf);
|
|
|
|
// 0732 268a lrs $AC0.M, @0xff8a
|
|
// 0733 248b lrs $AC0.L, @0xff8b
|
|
// 0734 2288 lrs $AX0.H, @0xff88
|
|
// 0735 2089 lrs $AX0.L, @0xff89
|
|
// 0736 5800 subax $ACC0, $AX0
|
|
|
|
$ACC0 = PB.Length[8a,8b] - PB.LoopStartPos[88,89];
|
|
|
|
// 0737 0a00 lris $AX0.H, #0x00
|
|
// 0738 2032 lrs $AX0.L, @0x0032
|
|
// 0739 5800 subax $ACC0, $AX0
|
|
|
|
$ACC0 -= PB.CurBlock (*0x0432);
|
|
|
|
// 073a 2e3a srs @0x003a, $AC0.M
|
|
// 073b 2c3b srs @0x003b, $AC0.L
|
|
|
|
PB.RemLength[3a,3b] = PB.Length[8a,8b] - (PB.LoopStartPos[88,89] + PB.CurBlock[32]);
|
|
|
|
// 073c 02df ret
|
|
}
|
|
|
|
|
|
// SAMPLER DECODER FOR FORMAT 0x05, 0x09
|
|
void 073d_DECODE_0x05_0x09(_dest($AR3), _numberOfSamples($AC1.M), _len(AX1)) // AX1 is 0x50 all the time
|
|
{
|
|
073d 0092 0004 lri $CR, #0x0004
|
|
073f 8100 clr $ACC0
|
|
// 0740 2604 lrs $AC0.M, @0x0004
|
|
// 0741 b100 tst $ACC0
|
|
// 0742 02b4 0717 callne 0x0717
|
|
if (*0x0404)
|
|
0717_InitializeDecoderState()
|
|
|
|
// 0744 8100 clr $ACC0
|
|
// 0745 2601 lrs $AC0.M, @0x0001
|
|
// 0746 b100 tst $ACC0
|
|
|
|
if (0x0401 != 0)
|
|
{
|
|
// 0747 0294 07e5 jnz 0x07e5 // early out
|
|
GOTO 0x07e5;
|
|
}
|
|
|
|
0749 2232 lrs $AX0.H, @0x0032
|
|
074a c900 cmpar $ACC0, $AX1.H
|
|
074b 0293 070e jle 0x070e // another early out
|
|
074d 5500 subr $ACC1, $AX0.H
|
|
|
|
// 074e 02bf 06f9 call 0x06f9
|
|
06f9_Unk_PrepareSampleDecode()
|
|
|
|
// check if there are samples left ...
|
|
0750 223a lrs $AX0.H, @0x003a
|
|
0751 8600 tstaxh $AX0.H
|
|
0752 0294 0759 jnz 0x0759
|
|
|
|
0754 8100 clr $ACC0
|
|
0755 263b lrs $AC0.M, @0x003b
|
|
0756 8200 cmp
|
|
0757 0291 07ab jl 0x07ab
|
|
if ()
|
|
{
|
|
// compute how many samples we have to copy
|
|
0759 8100 clr $ACC0
|
|
075a 1fdf mrr $AC0.M, $AC1.M
|
|
075b 040f addis $ACC0, #0x0f
|
|
075c 147c lsr $ACC0, #-4
|
|
075d 1f7e mrr $AX1.H, $AC0.M
|
|
|
|
075e 0c00 lris $AC0.L, #0x00
|
|
075f 1404 lsl $ACC0, #4
|
|
0760 1f1e mrr $AX0.L, $AC0.M
|
|
0761 0a00 lris $AX0.H, #0x00
|
|
0762 8100 clr $ACC0
|
|
0763 263a lrs $AC0.M, @0x003a
|
|
0764 243b lrs $AC0.L, @0x003b
|
|
0765 5800 subax $ACC0, $AX0
|
|
0766 0290 0771 jge 0x0771
|
|
if ()
|
|
{
|
|
0768 8100 clr $ACC0
|
|
0769 263b lrs $AC0.M, @0x003b
|
|
076a 5c00 sub $ACC0, $ACC1
|
|
076b 2e32 srs @0x0032, $AC0.M
|
|
076c 8100 clr $ACC0
|
|
076d 2e3a srs @0x003a, $AC0.M
|
|
076e 2e3b srs @0x003b, $AC0.M
|
|
// 076f 029f 0777 jmp 0x0777
|
|
}
|
|
else
|
|
{
|
|
0771 2e3a srs @0x003a, $AC0.M
|
|
0772 2c3b srs @0x003b, $AC0.L
|
|
0773 0c00 lris $AC0.L, #0x00
|
|
0774 1fd8 mrr $AC0.M, $AX0.L
|
|
0775 5c00 sub $ACC0, $ACC1
|
|
0776 2e32 srs @0x0032, $AC0.M
|
|
}
|
|
|
|
|
|
0777 8100 clr $ACC0
|
|
0778 1fdb mrr $AC0.M, $AX1.H
|
|
|
|
// 0779 02bf 07eb call 0x07eb
|
|
07eb_AFCDecoder();
|
|
|
|
077b 2232 lrs $AX0.H, @0x0032
|
|
077c 8600 tstaxh $AX0.H
|
|
077d 0295 07a8 jz 0x07a8
|
|
077f 0a10 lris $AX0.H, #0x10
|
|
0780 8100 clr $ACC0
|
|
0781 1fc3 mrr $AC0.M, $AR3
|
|
0782 5400 subr $ACC0, $AX0.H
|
|
0783 1c7e mrr $AR3, $AC0.M
|
|
0784 0080 0458 lri $AR0, #0x0458
|
|
0786 197e lrri $AC0.M, @$AR3
|
|
0787 197a lrri $AX0.H, @$AR3
|
|
0788 100e loopi #0x0e
|
|
0789 64a2 movr'sl $ACC0, $AX0.H : $AC0.M, $AX0.H
|
|
078a 1b1e srri @$AR0, $AC0.M
|
|
078b 1b1a srri @$AR0, $AX0.H
|
|
// 078c 8100 clr $ACC0
|
|
// 078d 263a lrs $AC0.M, @0x003a
|
|
// 078e 243b lrs $AC0.L, @0x003b
|
|
// 078f b100 tst $ACC0
|
|
// 0790 0294 07a8 jnz 0x07a8
|
|
if (![3a,3b]) {
|
|
0792 2232 lrs $AX0.H, @0x0032
|
|
0793 8600 tstaxh $AX0.H
|
|
0794 0295 07a8 jz 0x07a8
|
|
0796 0080 0467 lri $AR0, #0x0467
|
|
// 0798 8100 clr $ACC0
|
|
// 0799 268b lrs $AC0.M, @0xff8b
|
|
// 079a b100 tst $ACC0
|
|
// 079b 0295 07a8 jz 0x07a8
|
|
if (*0x048b) {
|
|
// Round up
|
|
079d 0200 000f addi $AC0.M, #0x000f
|
|
079f 0240 000f andi $AC0.M, #0x000f
|
|
07a1 0200 0458 addi $AC0.M, #0x0458
|
|
07a3 1c7e mrr $AR3, $AC0.M
|
|
// backwards copy loop
|
|
07a4 007a 07a7 bloop $AX0.H, 0x07a7
|
|
07a6 18fe lrrd $AC0.M, @$AR3
|
|
07a7 1a9e srrd @$AR0, $AC0.M
|
|
}
|
|
}
|
|
07a8 0092 00ff lri $CR, #0x00ff
|
|
|
|
// 07aa 02df ret
|
|
return
|
|
}
|
|
else
|
|
{
|
|
07ab b100 tst $ACC0
|
|
07ac 0295 07bb jz 0x07bb
|
|
07ae 5d00 sub $ACC1, $ACC0
|
|
07af 040f addis $ACC0, #0x0f
|
|
07b0 147c lsr $ACC0, #-4
|
|
07b1 0c00 lris $AC0.L, #0x00
|
|
07b2 00e3 0363 sr @0x0363, $AR3
|
|
|
|
// 07b4 02bf 07eb call 0x07eb
|
|
07eb_AFCDecoder();
|
|
|
|
07b6 00de 0363 lr $AC0.M, @0x0363
|
|
07b8 223b lrs $AX0.H, @0x003b
|
|
07b9 4400 addr $ACC0, $AX0.H
|
|
07ba 1c7e mrr $AR3, $AC0.M
|
|
|
|
|
|
07bb 8100 clr $ACC0
|
|
|
|
// Check repeat mode.
|
|
07bc 2681 lrs $AC0.M, @0xff81
|
|
07bd b100 tst $ACC0
|
|
07be 0295 07e3 jz 0x07e3 // stop rendering, see below 7e3
|
|
|
|
// Repeat.
|
|
// 07c0 2380 lrs $AX1.H, @0xff80
|
|
// 07c1 2688 lrs $AC0.M, @0xff88
|
|
// 07c2 2489 lrs $AC0.L, @0xff89
|
|
// 07c3 1408 lsl $ACC0, #8
|
|
// 07c4 14f4 asr $ACC0, #-12
|
|
|
|
$ACC0 = PB.LoopStartPos >> 4
|
|
|
|
//07c5 2380 lrs $AX1.H, @0xff80
|
|
//07c6 8d00 set15
|
|
//07c7 c810 mulc'mv $AC0.M, $AX1.H : $AX0.L, $AC0.L
|
|
|
|
$AX0.l = (PB.LoopStartPos >> 4) & 0xffff;
|
|
prod = (PB.LoopStartPos >> 4 & 0xffff0000)*PB.Format;
|
|
|
|
//07c8 ae00 mulxmv $AX0.L, $AX1.H, $ACC0
|
|
|
|
$ACC0 = (PB.LoopStartPos >> 4 & 0xffff0000)*PB.Format;
|
|
prod = ((PB.LoopStartPos >> 4) & 0xffff)*PB.Format;
|
|
|
|
//07c9 8c00 clr15
|
|
//07ca f000 lsl16 $ACC0
|
|
|
|
$ACC0 = (((PB.LoopStartPos >> 4) & 0xffff0000)*PB.Format)<<16
|
|
|
|
//07cb 4e00 addp $ACC0
|
|
|
|
$ACC0 = ((((PB.LoopStartPos >> 4) & 0xffff0000)*PB.Format)<<16)+
|
|
(((PB.LoopStartPos >> 4) & 0xffff)*PB.Format)
|
|
|
|
// 07cc 238c lrs $AX1.H, @0xff8c
|
|
// 07cd 218d lrs $AX1.L, @0xff8d
|
|
// 07ce 4a00 addax $ACC0, $AX1
|
|
|
|
$ACC0 = (((((PB.LoopStartPos >> 4) & 0xffff0000)*PB.Format)<<16)+
|
|
(((PB.LoopStartPos >> 4) & 0xffff)*PB.Format))+PB.StartAddr
|
|
|
|
// 07cf 2e38 srs @0x0038, $AC0.M
|
|
// 07d0 2c39 srs @0x0039, $AC0.L
|
|
|
|
PB.CurAddr = $ACC0 & 0xffffffff;
|
|
|
|
// 07d1 2682 lrs $AC0.M, @0xff82
|
|
// 07d2 2e67 srs @0x0067, $AC0.M
|
|
// 07d3 2683 lrs $AC0.M, @0xff83
|
|
// 07d4 2e66 srs @0x0066, $AC0.M
|
|
//Unconditionally (!) copy YN1 and YN2 from loopyn2 and loopyn1
|
|
|
|
PB.YN1 = PB.LoopYN1;
|
|
PB.YN2 = PB.LoopYN2;
|
|
|
|
07d5 00e3 0363 sr @0x0363, $AR3
|
|
07d7 0083 0458 lri $AR3, #0x0458
|
|
07d9 8100 clr $ACC0
|
|
07da 0e01 lris $AC0.M, #0x01
|
|
|
|
// 07db 02bf 07eb call 0x07eb
|
|
07eb_AFCDecoder();
|
|
|
|
07dd 00c3 0363 lr $AR3, @0x0363
|
|
07df 02bf 0729 call 0x0729
|
|
07e1 029f 0749 jmp 0x0749
|
|
|
|
// No repeat
|
|
// stop rendering of this PB (0x401 == 1) and clear the output buffer with zeroes...
|
|
//07e3 0e01 lris $AC0.M, #0x01
|
|
//07e4 2e01 srs @0x0001, $AC0.M
|
|
|
|
PB.KeyOff = 1;
|
|
|
|
early_out:
|
|
// Zero the buffer.
|
|
07e5 8100 clr $ACC0
|
|
07e6 005f loop $AC1.M
|
|
07e7 1b7e srri @$AR3, $AC0.M
|
|
07e8 0092 00ff lri $CR, #0x00ff
|
|
|
|
// 07ea 02df ret
|
|
return
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
void 07eb_AFCDecoder(_numberOfSample(AC0.M))
|
|
{
|
|
// 07eb 00ff 0360 sr @0x0360, $AC1.M
|
|
// 07ed 00fe 0361 sr @0x0361, $AC0.M
|
|
// 07ef 2638 lrs $AC0.M, @0x0038
|
|
// 07f0 2439 lrs $AC0.L, @0x0039
|
|
// 07f1 0f05 lris $AC1.M, #0x05
|
|
// 07f2 02bf 05ad call 0x05ad
|
|
05ad_SetupAccelerator(AC0.M, AC0.L, AC1.M)
|
|
|
|
// 07f4 2638 lrs $AC0.M, @0x0038
|
|
// 07f5 2439 lrs $AC0.L, @0x0039
|
|
// 07f6 8900 clr $ACC1
|
|
// 07f7 00df 0361 lr $AC1.M, @0x0361
|
|
// 07f9 2280 lrs $AX0.H, @0xff80
|
|
// 07fa d000 mulc $AC1.M, $AX0.H
|
|
// 07fb 6f00 movp $ACC1
|
|
// 07fc 4c00 add $ACC0, $ACC1
|
|
// 07fd 2e38 srs @0x0038, $AC0.M
|
|
// 07fe 2c39 srs @0x0039, $AC0.L
|
|
// increase sample offset in ARAM
|
|
AC0 = (*0x0038 << 16) | *0x0039
|
|
AC1 = AC0 + _numberOfSample * *0x0480 // bytes per sample
|
|
*0x0038 = AC0.M
|
|
*0x0039 = AC0.L
|
|
|
|
|
|
// 07ff 8100 clr $ACC0
|
|
// 0800 00de 0361 lr $AC0.M, @0x0361
|
|
//0802 007e 086b bloop $AC0.M, 0x086b
|
|
for (int i = 0; i < _numberOfSample; i++)
|
|
{
|
|
// Look for the lrrn below to find the ARAM reads.
|
|
|
|
// FFD3 seems to be some interface to do plain single byte reads
|
|
// from ARAM with no ADPCM fanciness or similar.
|
|
|
|
// It loads through AR0 loaded with immediate #ffd3, not through
|
|
// lrs, so CR doesn't affect the effective address.
|
|
|
|
0804 0080 ffd3 lri $AR0, #0xffd3
|
|
0806 0084 0000 lri $IX0, #0x0000
|
|
0808 199e lrrn $AC0.M, @$AR0
|
|
0809 8900 clr $ACC1
|
|
080a 1ffe mrr $AC1.M, $AC0.M
|
|
080b 1401 lsl $ACC0, #1
|
|
080c 0240 001e andi $AC0.M, #0x001e
|
|
080e 0200 0300 addi $AC0.M, #0x0300 // AFC COEF Table
|
|
0810 1c3e mrr $AR1, $AC0.M
|
|
0811 157c lsr $ACC1, #-4
|
|
0812 0340 000f andi $AC1.M, #0x000f
|
|
0814 0a11 lris $AX0.H, #0x11
|
|
0815 5500 subr $ACC1, $AX0.H
|
|
|
|
// 0816 8100 clr $ACC0
|
|
// 0817 2680 lrs $AC0.M, @0xff80
|
|
// 0818 0605 cmpis $ACC0, #0x05
|
|
// 0819 0295 0832 jz 0x0832
|
|
if (*0x480 != 0x5) // ( == 0x09)
|
|
{
|
|
081b 009a 00f0 lri $AX0.H, #0x00f0
|
|
081d 0b0f lris $AX1.H, #0x0f
|
|
081e 0082 0364 lri $AR2, #0x0364
|
|
0820 1998 lrrn $AX0.L, @$AR0
|
|
0821 6000 movr $ACC0, $AX0.L
|
|
|
|
// Unpack 14 of the nibbles..
|
|
0822 1107 0829 bloopi #0x07, 0x0829
|
|
for (int j=0; j<7; j++)
|
|
{
|
|
0824 3400 andr $AC0.M, $AX0.H
|
|
0825 1408 lsl $ACC0, #8
|
|
0826 6032 movr's $ACC0, $AX0.L : @$AR2, $AC0.M
|
|
|
|
0827 3644 andr'ln $AC0.M, $AX1.H : $AX0.L, @$AR0
|
|
0828 140c lsl $ACC0, #12
|
|
0829 6032 movr's $ACC0, $AX0.L : @$AR2, $AC0.M
|
|
}
|
|
// Then do the last two ..
|
|
082a 3400 andr $AC0.M, $AX0.H
|
|
082b 1408 lsl $ACC0, #8
|
|
082c 6032 movr's $ACC0, $AX0.L : @$AR2, $AC0.M
|
|
082d 3600 andr $AC0.M, $AX1.H
|
|
082e 140c lsl $ACC0, #12
|
|
082f 1b5e srri @$AR2, $AC0.M
|
|
|
|
0830 029f 0852 jmp 0x0852
|
|
}
|
|
else // (*0x480 == 5)
|
|
{
|
|
0832 009a c000 lri $AX0.H, #0xc000
|
|
0834 0082 0364 lri $AR2, #0x0364
|
|
0836 1998 lrrn $AX0.L, @$AR0
|
|
0837 6000 movr $ACC0, $AX0.L
|
|
|
|
// Unpack half nibbles (half quality, ~half space)
|
|
//0838 1103 0845 bloopi #0x03, 0x0845
|
|
for (j=0; j<3; j++)
|
|
{
|
|
083a 1408 lsl $ACC0, #8
|
|
083b 3400 andr $AC0.M, $AX0.H
|
|
083c 6032 movr's $ACC0, $AX0.L : @$AR2, $AC0.M
|
|
083d 140a lsl $ACC0, #10
|
|
083e 3400 andr $AC0.M, $AX0.H
|
|
083f 6032 movr's $ACC0, $AX0.L : @$AR2, $AC0.M
|
|
0840 140c lsl $ACC0, #12
|
|
0841 3400 andr $AC0.M, $AX0.H
|
|
0842 6032 movr's $ACC0, $AX0.L : @$AR2, $AC0.M
|
|
0843 140e lsl $ACC0, #14
|
|
0844 3444 andr'ln $AC0.M, $AX0.H : $AX0.L, @$AR0
|
|
0845 6032 movr's $ACC0, $AX0.L : @$AR2, $AC0.M
|
|
}
|
|
|
|
0846 1408 lsl $ACC0, #8
|
|
0847 3400 andr $AC0.M, $AX0.H
|
|
0848 6032 movr's $ACC0, $AX0.L : @$AR2, $AC0.M
|
|
0849 140a lsl $ACC0, #10
|
|
084a 3400 andr $AC0.M, $AX0.H
|
|
084b 6032 movr's $ACC0, $AX0.L : @$AR2, $AC0.M
|
|
084c 140c lsl $ACC0, #12
|
|
084d 3400 andr $AC0.M, $AX0.H
|
|
084e 6032 movr's $ACC0, $AX0.L : @$AR2, $AC0.M
|
|
084f 140e lsl $ACC0, #14
|
|
0850 3400 andr $AC0.M, $AX0.H
|
|
0851 1b5e srri @$AR2, $AC0.M
|
|
}
|
|
|
|
0852 8f00 set40
|
|
0853 1f7f mrr $AX1.H, $AC1.M
|
|
0854 2066 lrs $AX0.L, @0x0066
|
|
0855 2767 lrs $AC1.M, @0x0067
|
|
0856 193a lrri $AX0.H, @$AR1
|
|
0857 1939 lrri $AX1.L, @$AR1
|
|
0858 0080 0364 lri $AR0, #0x0364
|
|
085a 1c80 mrr $IX0, $AR0
|
|
085b a000 mulx $AX0.L, $AX1.L
|
|
085c ea70 maddc'l $AC1.M, $AX1.L : $AC0.M, @$AR0
|
|
|
|
// ADPCM decoding main loop.
|
|
085d 1108 0866 bloopi #0x08, 0x0866
|
|
for (int i=0; i<8; i++)
|
|
{
|
|
085f 3a93 orr'sl $AC0.M, $AX1.H : $AC1.M, $AX1.L
|
|
0860 a478 mulxac'l $AX0.L, $AX1.L, $ACC0 : $AC1.M, @$AR0
|
|
0861 1485 asl $ACC0, #5
|
|
0862 e833 maddc's $AC0.M, $AX1.L : @$AR3, $AC0.M
|
|
0863 3b92 orr'sl $AC1.M, $AX1.H : $AC0.M, $AX1.L
|
|
0864 a570 mulxac'l $AX0.L, $AX1.L, $ACC1 : $AC0.M, @$AR0
|
|
0865 1585 asl $ACC1, #5
|
|
0866 ea3b maddc's $AC1.M, $AX1.L : @$AR3, $AC1.M
|
|
}
|
|
0867 2f67 srs @0x0067, $AC1.M
|
|
0868 8e00 set16
|
|
0869 1ff8 mrr $AC1.M, $AX0.L
|
|
086a 2f66 srs @0x0066, $AC1.M
|
|
086b 8900 clr $ACC1
|
|
}
|
|
086c 00df 0360 lr $AC1.M, @0x0360
|
|
086e 02df ret
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// probably unreachable
|
|
{
|
|
// 086f b100 tst $ACC0
|
|
// 0870 02d5 retz
|
|
if (!$ACC0) return;
|
|
|
|
0871 04fe addis $ACC0, #0xfe
|
|
0872 1f1e mrr $AX0.L, $AC0.M
|
|
0873 191e lrri $AC0.M, @$AR0
|
|
0874 0291 087a jl 0x087a
|
|
0876 191a lrri $AX0.H, @$AR0
|
|
0877 0058 loop $AX0.L
|
|
0878 64a0 movr'ls $ACC0, $AX0.H : $AX0.H, $AC0.M
|
|
0879 6433 movr's $ACC0, $AX0.H : @$AR3, $AC0.M
|
|
087a 1b7e srri @$AR3, $AC0.M
|
|
087b 02df ret
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////// DEFAULT DECODER
|
|
void 087c_DefaultDecoder()
|
|
{
|
|
// 087c 8100 clr $ACC0
|
|
// 087d 1f5e mrr $AX0.H, $AC0.M
|
|
// 087e 00d8 0402 lr $AX0.L, @0x0402
|
|
|
|
ACC0 = 0;
|
|
AX0.L = *0x0402; // == PB.RatioInt
|
|
|
|
// Sample fraction is stored in a common way, but sample position is not, so
|
|
// it's in the individual decoders. Some decoders, like square wave, only care about
|
|
// fractional sample position. So here we just load up the fractional sample
|
|
// position before handing control over.
|
|
|
|
// 0880 00dc 0430 lr $AC0.L, @0x0430
|
|
// 0882 0080 0520 lri $AR0, #0x0520
|
|
|
|
AC0.L = *0x430; // == PB.CurSampleFrac
|
|
AR0 = 0x0520;
|
|
|
|
// 0884 00df 0480 lr $AC1.M, @0x0480
|
|
// 0886 1501 lsl $ACC1, #1
|
|
// 0887 0340 007e andi $AC1.M, #0x007e
|
|
// 0889 0300 0891 addi $AC1.M, #0x0891
|
|
// 088b 1c5f mrr $AR2, $AC1.M
|
|
// 088c 175f callr $AR2 // (*$AR2)() <-- See jump table at 0x0891
|
|
|
|
AC1.M = ((*0x480 * 2) & 0x007e) + 0x0891; // == ((PB.Format * 2) & 0x007e) + 0x0891
|
|
AR2 = AC1.M;
|
|
|
|
JumpTable0891(PB.Format);
|
|
|
|
//088d 00fc 0430 sr @0x0430, $AC0.L
|
|
*0x430 = AC0.L; // *0x430 == PB.CurSampleFrac
|
|
|
|
// 088f 029f 02d8 jmp 0x02d8
|
|
GOTO ContinueWithBlock: // in SyncFrame
|
|
}
|
|
|
|
|
|
// Jump table
|
|
// switch(PB.Format)
|
|
0891 029f 08b2 jmp 0x08b2 // case 0x0 // 08b2_Decoder0x0_SquareWave (used in ZWW)
|
|
0893 029f 08ed jmp 0x08ed // case 0x1 // 08ed_Decoder0x1_SawWave (used in ZWW)
|
|
0895 029f 08d5 jmp 0x08d5 // case 0x2 // 08d5_Decoder0x2_SquareSaw (hasn't been spotted)
|
|
0897 029f 08c2 jmp 0x08c2 // case 0x3 // 08c2_Decoder0x3_RectangleWave (hasn't been spotted)
|
|
0899 029f 08fb jmp 0x08fb // case 0x4 // void 08f3_Decoder0x4_0xb_0xc_WaveTable (used in Pikmin)
|
|
089b 029f 08b1 jmp 0x08b1 // case 0x5 (can never happen)
|
|
089d 029f 0919 jmp 0x0919 // case 0x6 // 0919_Decoder0x6_Constant (hasn't been spotted)
|
|
089f 029f 091c jmp 0x091c // case 0x7 // 091c_Decoder0x7_WaveTable (used in Pikmin)
|
|
08a1 029f 08b1 jmp 0x08b1 // case 0x8 (can never happen)
|
|
08a3 029f 08b1 jmp 0x08b1 // case 0x9 (can never happen)
|
|
08a5 029f 093a jmp 0x093a // case 0xa (hasn't been spotted)
|
|
08a7 029f 08f3 jmp 0x08f3 // case 0xb // void 08f3_Decoder0x4_0xb_0xc_WaveTable (used in Pikmin) (used in Pikmin)
|
|
08a9 029f 08f7 jmp 0x08f7 // case 0xc // void 08f3_Decoder0x4_0xb_0xc_WaveTable (used in Pikmin) (Zelda force field in temple of gods)
|
|
08ab 029f 08b1 jmp 0x08b1 // case 0xd (unused)
|
|
08ad 029f 08b1 jmp 0x08b1 // case 0xe (unused)
|
|
08af 029f 08b1 jmp 0x08b1 // case 0xf (unused)
|
|
08b1 02df ret
|
|
|
|
void 08b2_Decoder0x0_SquareWave(ACC0, AR0, AX0.L) {
|
|
// 08b2 1401 lsl $ACC0, #1
|
|
t = samplePosition * 2;
|
|
|
|
// Set up sound buffers
|
|
// 08b3 009b c000 lri $AX1.H, #0xc000
|
|
// 08b5 0099 4000 lri $AX1.L, #0x4000
|
|
|
|
// 08b7 1150 08bf bloopi #0x50, 0x08bf
|
|
for(int i = 0; i < 80; i++) {
|
|
//08b9 02c0 0001 andcf $AC0.M, #0x0001
|
|
//08bb 027c iflnz
|
|
// 08bc 1b1b srri @$AR0, $AX1.H
|
|
//08bd 027d iflz
|
|
// 08be 1b19 srri @$AR0, $AX1.L
|
|
if(($AC0.M & 1) == 1)
|
|
*$AR0++ = 0x4000;
|
|
else
|
|
*$AR0++ = 0xc000;
|
|
|
|
// 08bf 4800 addax $ACC0, $AX0
|
|
t += PB.Ratio;
|
|
}
|
|
// 08c0 147f lsr $ACC0, #-1
|
|
t /= 2;
|
|
|
|
// 08c1 02df ret
|
|
}
|
|
|
|
void 08c2_Decoder0x3_RectangleWave(ACC0, AR0, AX0.L) {
|
|
08c2 1402 lsl $ACC0, #2 // t = PB.CurSampleFrac * 4
|
|
08c3 8900 clr $ACC1 // ACC1 = 0
|
|
08c4 1fb8 mrr $AC1.L, $AX0.L // AC1.L = PB.RatioInt
|
|
08c5 1501 lsl $ACC1, #1 // ACC1 *= 2
|
|
08c6 009b c000 lri $AX1.H, #0xc000
|
|
08c8 0099 4000 lri $AX1.L, #0x4000
|
|
// 08ca 1150 08d2 bloopi #0x50, 0x08d2
|
|
for(int i = 0; i < 80; i++) {
|
|
// 08cc 02c0 0003 andcf $AC0.M, #0x0003
|
|
// 08ce 027c iflnz
|
|
// 08cf 1b1b srri @$AR0, $AX1.H
|
|
// 08d0 027d iflz
|
|
// 08d1 1b19 srri @$AR0, $AX1.L
|
|
// 08d2 4c00 add $ACC0, $ACC1
|
|
|
|
if (($AC0.M & 3) == 3)
|
|
*$AR0++ = 0x4000;
|
|
else
|
|
*$AR0++ = 0xc000;
|
|
|
|
t += (PB.RatioInt * 2);
|
|
}
|
|
// 08d3 147e lsr $ACC0, #-2
|
|
t /= 4;
|
|
|
|
// 08d4 02df ret
|
|
}
|
|
|
|
void 08d5_Decoder0x2_SquareSaw(ACC0, AR0, AX0.L) {
|
|
08d5 1401 lsl $ACC0, #1
|
|
08d6 0081 0ca0 lri $AR1, #0x0ca0
|
|
08d8 009b c000 lri $AX1.H, #0xc000
|
|
08da 0099 4000 lri $AX1.L, #0x4000
|
|
08dc 8900 clr $ACC1
|
|
08dd 0082 0000 lri $AR2, #0x0000
|
|
08df 1150 08ea bloopi #0x50, 0x08ea
|
|
08e1 02c0 0001 andcf $AC0.M, #0x0001
|
|
08e3 027c iflnz
|
|
08e4 1b1b srri @$AR0, $AX1.H
|
|
08e5 027d iflz
|
|
08e6 1b19 srri @$AR0, $AX1.L
|
|
08e7 183d lrr $AC1.L, @$AR1
|
|
08e8 4900 addax $ACC1, $AX0
|
|
08e9 1fe2 mrr $AC1.M, $AR2
|
|
08ea 4c39 add's $ACC0, $ACC1 : @$AR1, $AC1.M
|
|
08eb 147f lsr $ACC0, #-1
|
|
// 08ec 02df ret
|
|
}
|
|
|
|
void 08ed_Decoder0x1_SawWave(ACC0, AR0, AX0.L) {
|
|
// 08ed 8900 clr $ACC1
|
|
// 08ee 1fb8 mrr $AC1.L, $AX0.L
|
|
// 08ef 157f lsr $ACC1, #-1
|
|
|
|
// At this point AX0.L is PB.RatioInt and AC0.L is PB.CurSampleFrac
|
|
ACC1 = 0;
|
|
AC1.L = AX0.L * 2;
|
|
|
|
// 08f0 1050 loopi #0x50
|
|
for(int i = 0; i < 0x50; i++) {
|
|
// 08f1 4c20 add's $ACC0, $ACC1 : @$AR0, $AC0.L
|
|
ACC0 += ACC1;
|
|
*$AR0++ = AC0.L;
|
|
}
|
|
// 08f2 02df ret
|
|
}
|
|
|
|
|
|
void 08f3_Decoder0x4_0xb_0xc_WaveTable(ACC0, AR0, AX0.L) {
|
|
// See 091c
|
|
|
|
08f3 0082 0180 lri $AR2, #0x0180 // Entrance 1, 0x0b
|
|
08f5 029f 08fd jmp 0x08fd
|
|
|
|
08f7 0082 01c0 lri $AR2, #0x01c0 // Entrance 2, 0x0c
|
|
08f9 029f 08fd jmp 0x08fd
|
|
|
|
08fb 0082 0140 lri $AR2, #0x0140 // Entrance 3, 0x04
|
|
|
|
08fd 008a 003f lri $WR2, #0x003f
|
|
08ff 0086 0000 lri $IX2, #0x0000
|
|
0901 1406 lsl $ACC0, #6
|
|
0902 8900 clr $ACC1
|
|
0903 1fb8 mrr $AC1.L, $AX0.L
|
|
0904 1505 lsl $ACC1, #5
|
|
0905 009b 003f lri $AX1.H, #0x003f
|
|
0907 009a 0000 lri $AX0.H, #0x0000
|
|
0909 3600 andr $AC0.M, $AX1.H
|
|
090a 1cde mrr $IX2, $AC0.M
|
|
090b 001a addarn $AR2, $IX2
|
|
090c 3400 andr $AC0.M, $AX0.H
|
|
090d 1150 0913 bloopi #0x50, 0x0913
|
|
090f 4c4a add'l $ACC0, $ACC1 : $AX1.L, @$AR2
|
|
0910 3606 andr'dr $AC0.M, $AX1.H : $AR2
|
|
0911 1cde mrr $IX2, $AC0.M
|
|
0912 340e andr'nr $AC0.M, $AX0.H : $AR2
|
|
0913 1b19 srri @$AR0, $AX1.L
|
|
0914 1fc2 mrr $AC0.M, $AR2
|
|
0915 147a lsr $ACC0, #-6
|
|
0916 008a ffff lri $WR2, #0xffff
|
|
// 0918 02df ret
|
|
}
|
|
|
|
void 0919_Decoder0x6_Constant(AR0, AX0.L) {
|
|
// case 0x6: Fills the buffer with PB.RatioInt (zero?)
|
|
|
|
// 0919 1050 loopi #0x50
|
|
// 091a 1b18 srri @$AR0, $AX0.L
|
|
|
|
for(int i = 0; i < 0x50; i++)
|
|
*AR0++ = AX0.L; // PB.RatioInt
|
|
|
|
// 091b 02df ret
|
|
}
|
|
|
|
void 091c_Decoder0x7_WaveTable(ACC0, AR0, AX0.L) {
|
|
// So AR2 is where it reads the data from, and it updates ACC0 to the final read address in the end
|
|
// Questions: How does the wrap register change the data access?
|
|
|
|
// 091c 0082 0100 lri $AR2, #0x0100
|
|
// 091e 008a 003f lri $WR2, #0x003f
|
|
// 0920 0086 0000 lri $IX2, #0x0000
|
|
// 0922 1406 lsl $ACC0, #6
|
|
// 0923 8900 clr $ACC1
|
|
// 0924 1fb8 mrr $AC1.L, $AX0.L
|
|
// 0925 1505 lsl $ACC1, #5
|
|
|
|
|
|
WR2 = 0x003f;
|
|
ACC0 <<= 6;
|
|
ACC1 = AX0.L << 5;
|
|
|
|
|
|
// 0926 009b 003f lri $AX1.H, #0x003f
|
|
// 0928 009a 0000 lri $AX0.H, #0x0000
|
|
// 092a 3600 andr $AC0.M, $AX1.H
|
|
// 092b 1cde mrr $IX2, $AC0.M
|
|
// 092c 001a addarn $AR2, $IX2
|
|
// 092d 3400 andr $AC0.M, $AX0.H
|
|
|
|
AC0.M &= 0x003f;
|
|
IX2 = AC0.M;
|
|
AR2 = 0x0100 + IX2;
|
|
|
|
AC0.M = 0;
|
|
|
|
|
|
// 092e 1150 0934 bloopi #0x50, 0x0934
|
|
for(int i = 0; i < 0x50; i++) {
|
|
// 0930 4c4a add'l $ACC0, $ACC1 : $AX1.L, @$AR2
|
|
|
|
ACC0 += ACC1;
|
|
AX1.L = *AR2++;
|
|
|
|
// 0931 3606 andr'dr $AC0.M, $AX1.H : $AR2
|
|
AC0.M &= 0x003f;
|
|
AR2--;
|
|
|
|
// 0932 1cde mrr $IX2, $AC0.M
|
|
IX2 = AC0.M;
|
|
|
|
// 0933 340e andr'nr $AC0.M, $AX0.H : $AR2
|
|
AC0.M = 0;
|
|
AR2 += IX2;
|
|
|
|
// 0934 1b19 srri @$AR0, $AX1.L
|
|
*AR0++ = AX1.L;
|
|
|
|
}
|
|
|
|
// 0935 1fc2 mrr $AC0.M, $AR2
|
|
// 0936 147a lsr $ACC0, #-6
|
|
// 0937 008a ffff lri $WR2, #0xffff
|
|
|
|
AC0.M = AR2;
|
|
ACC0 >>= 6;
|
|
WR2 = 0xffff;
|
|
|
|
// 0939 02df ret
|
|
}
|
|
|
|
void 093a_Unk() {
|
|
093a 0082 0100 lri $AR2, #0x0100
|
|
093c 008a 003f lri $WR2, #0x003f
|
|
093e 0086 0000 lri $IX2, #0x0000
|
|
0940 0081 0ca0 lri $AR1, #0x0ca0
|
|
0942 1406 lsl $ACC0, #6
|
|
0943 8900 clr $ACC1
|
|
0944 1fb8 mrr $AC1.L, $AX0.L
|
|
0945 1505 lsl $ACC1, #5
|
|
0946 009b 003f lri $AX1.H, #0x003f
|
|
0948 009a 0000 lri $AX0.H, #0x0000
|
|
094a 3600 andr $AC0.M, $AX1.H
|
|
094b 1cde mrr $IX2, $AC0.M
|
|
094c 001a addarn $AR2, $IX2
|
|
094d 3400 andr $AC0.M, $AX0.H
|
|
094e 1150 0959 bloopi #0x50, 0x0959
|
|
0950 1939 lrri $AX1.L, @$AR1
|
|
0951 a000 mulx $AX0.L, $AX1.L
|
|
0952 140a lsl $ACC0, #10
|
|
0953 4e00 addp $ACC0
|
|
0954 1476 lsr $ACC0, #-10
|
|
0955 4c4a add'l $ACC0, $ACC1 : $AX1.L, @$AR2
|
|
0956 3606 andr'dr $AC0.M, $AX1.H : $AR2
|
|
0957 1cde mrr $IX2, $AC0.M
|
|
0958 340e andr'nr $AC0.M, $AX0.H : $AR2
|
|
0959 1b19 srri @$AR0, $AX1.L
|
|
095a 1fc2 mrr $AC0.M, $AR2
|
|
095b 147a lsr $ACC0, #-6
|
|
095c 008a ffff lri $WR2, #0xffff
|
|
095e 02df ret
|
|
}
|
|
|
|
void 095f_Unk_SetupMemAt0_0180() {
|
|
095f 0080 01be lri $AR0, #0x01be
|
|
0961 1918 lrri $AX0.L, @$AR0
|
|
0962 191a lrri $AX0.H, @$AR0
|
|
0963 0080 0180 lri $AR0, #0x0180
|
|
0965 0083 0180 lri $AR3, #0x0180
|
|
0967 9070 mul'l $AX0.L, $AX0.H : $AC0.M, @$AR0
|
|
0968 1ffe mrr $AC1.M, $AC0.M
|
|
// 0969 1120 0970 bloopi #0x20, 0x0970
|
|
for (int i = 0; i < 0x20; i++) {
|
|
096b 7c00 neg $ACC0
|
|
096c d450 mulcac'l $AC1.M, $AX0.H, $ACC0 : $AX0.H, @$AR0
|
|
096d 6533 movr's $ACC1, $AX0.H : @$AR3, $AC0.M
|
|
096e c550 mulcac'l $AC0.M, $AX0.H, $ACC1 : $AX0.H, @$AR0
|
|
096f 1501 lsl $ACC1, #1
|
|
0970 643b movr's $ACC0, $AX0.H : @$AR3, $AC1.M
|
|
}
|
|
0971 0080 01fe lri $AR0, #0x01fe
|
|
0973 191a lrri $AX0.H, @$AR0
|
|
0974 1918 lrri $AX0.L, @$AR0
|
|
0975 0080 01c0 lri $AR0, #0x01c0
|
|
0977 0083 01c0 lri $AR3, #0x01c0
|
|
0979 1ff8 mrr $AC1.M, $AX0.L
|
|
097a 9070 mul'l $AX0.L, $AX0.H : $AC0.M, @$AR0
|
|
097b f800 addpaxz $ACC0, $AX0.H
|
|
097c 0240 01ff andi $AC0.M, #0x01ff
|
|
097e 0260 2000 ori $AC0.M, #0x2000
|
|
|
|
//0980 02bf 0983 call 0x0983
|
|
0983_WriteRamp($ACC0, $ACC1, Dest($AR3))
|
|
|
|
// 0982 02df ret
|
|
}
|
|
|
|
void 0983_WriteRamp(ACC0, ACC1, Dest($AR3)) {
|
|
// 0983 b900 tst $ACC1
|
|
// 0984 0272 ifg
|
|
// 0985 7c00 neg $ACC0
|
|
if ($ACC1 > 0) {
|
|
$ACC0 = -$ACC0;
|
|
}
|
|
|
|
// 0986 1f7e mrr $AX1.H, $AC0.M
|
|
// 0987 4700 addr $ACC1, $AX1.H
|
|
|
|
// 0988 1110 098d bloopi #0x10, 0x098d
|
|
for (int i = 0; i < 0x10; i++) {
|
|
098a 473b addr's $ACC1, $AX1.H : @$AR3, $AC1.M
|
|
098b 473b addr's $ACC1, $AX1.H : @$AR3, $AC1.M
|
|
098c 473b addr's $ACC1, $AX1.H : @$AR3, $AC1.M
|
|
098d 473b addr's $ACC1, $AX1.H : @$AR3, $AC1.M
|
|
}
|
|
098e 02df ret
|
|
}
|
|
|
|
//////////////////////////////////////////// 0x08 DECODER
|
|
// Hardcoded destination 0x0580.
|
|
void Decoder0x08() {
|
|
098f 0092 0004 lri $CR, #0x0004
|
|
0991 2002 lrs $AX0.L, @0x0002
|
|
0992 8100 clr $ACC0
|
|
0993 8900 clr $ACC1
|
|
0994 2430 lrs $AC0.L, @0x0030 // CurSampleFrac
|
|
|
|
// 0995 8d00 set15
|
|
// 0996 0950 lris $AX1.L, #0x50
|
|
// 0997 a000 mulx $AX0.L, $AX1.L
|
|
// 0998 a400 mulxac $AX0.L, $AX1.L, $ACC0
|
|
// 0999 1404 lsl $ACC0, #4
|
|
// 099a 8c00 clr15
|
|
// Compute how much data we need to read, to get 0x50 samples after resampling.
|
|
// AC0.L is cursamplefrace, AX0.L is ratio.
|
|
$ACC0 = PB.CurrentSampleFrac + 0x50 * PB.Ratio;
|
|
|
|
099b 1ffe mrr $AC1.M, $AC0.M
|
|
099c 0083 0580 lri $AR3, #0x0580
|
|
099e 2201 lrs $AX0.H, @0x0001
|
|
099f 8600 tstaxh $AX0.H
|
|
09a0 0294 09b1 jnz 0x09b1
|
|
|
|
// 09a2 2204 lrs $AX0.H, @0x0004
|
|
// 09a3 8600 tstaxh $AX0.H
|
|
// 09a4 02b4 09f9 callne 0x09f9
|
|
if (*0x0404) { // NeedsReset
|
|
09f9_UpdateSampleCounters8();
|
|
}
|
|
|
|
09a6 8100 clr $ACC0
|
|
09a7 2605 lrs $AC0.M, @0x0005
|
|
09a8 b100 tst $ACC0
|
|
09a9 0295 09be jz 0x09be
|
|
|
|
label09ab:
|
|
09ab 8100 clr $ACC0
|
|
09ac 2e05 srs @0x0005, $AC0.M
|
|
09ad 2281 lrs $AX0.H, @0xff81
|
|
09ae 8600 tstaxh $AX0.H
|
|
09af 0294 09b8 jnz 0x09b8
|
|
09b1 8100 clr $ACC0
|
|
09b2 005f loop $AC1.M
|
|
09b3 1b7e srri @$AR3, $AC0.M
|
|
09b4 7400 incm $AC0.M
|
|
09b5 2e01 srs @0x0001, $AC0.M
|
|
09b6 029f 09f2 jmp 0x09f2
|
|
09b8 2688 lrs $AC0.M, @0xff88
|
|
09b9 2489 lrs $AC0.L, @0xff89
|
|
09ba 2e34 srs @0x0034, $AC0.M
|
|
09bb 2c35 srs @0x0035, $AC0.L
|
|
// 09bc 02bf 09f9 call 0x09f9
|
|
09f9_UpdateSampleCounters8();
|
|
|
|
09be 00ff 0360 sr @0x0360, $AC1.M
|
|
|
|
09c0 2638 lrs $AC0.M, @0x0038
|
|
09c1 2439 lrs $AC0.L, @0x0039
|
|
09c2 0f05 lris $AC1.M, #0x05 // Sample format 5
|
|
// 09c3 02bf 05ad call 0x05ad
|
|
05ad_SetupAccelerator(AC0.M, AC0.L, AC1.M)
|
|
|
|
09c5 00df 0360 lr $AC1.M, @0x0360
|
|
09c7 8100 clr $ACC0
|
|
// 09c8 263a lrs $AC0.M, @0x003a
|
|
// 09c9 b100 tst $ACC0
|
|
// 09ca 0294 09d9 jnz 0x09d9
|
|
if (*(0x043a)) {
|
|
09cc 263b lrs $AC0.M, @0x003b
|
|
09cd 5c00 sub $ACC0, $ACC1
|
|
09ce 0290 09d9 jge 0x09d9
|
|
|
|
09d0 223b lrs $AX0.H, @0x003b
|
|
// 09d1 02bf 0a0a call 0x0a0a // Load more samples.
|
|
0a0a_ReadFromAccelerator8To16(OutBuffer($AR3), Count($AX0.H))
|
|
|
|
09d3 5500 subr $ACC1, $AX0.H
|
|
// 09d4 0a01 lris $AX0.H, #0x01
|
|
// 09d5 00fa 0405 sr @0x0405, $AX0.H
|
|
*0x405 = 1; // PB.ReachedEnd = 1;
|
|
|
|
09d7 029f 09ab jmp 0x09ab
|
|
}
|
|
|
|
09d9 1f5f mrr $AX0.H, $AC1.M
|
|
// 09da 02bf 0a0a call 0x0a0a // Load more samples.
|
|
0a0a_ReadFromAccelerator8To16(OutBuffer($AR3), Count($AX0.H));
|
|
|
|
// Stash AX0.H away, it gets read again at 09ef.
|
|
09dc 00fa 0362 sr @0x0362, $AX0.H
|
|
|
|
09de 8100 clr $ACC0
|
|
09df 263a lrs $AC0.M, @0x003a
|
|
09e0 243b lrs $AC0.L, @0x003b
|
|
09e1 1570 lsr $ACC1, #-16
|
|
|
|
// 09e2 0a01 lris $AX0.H, #0x01
|
|
// 09e3 0081 0405 lri $AR1, #0x0405
|
|
// 09e5 5c00 sub $ACC0, $ACC1
|
|
// 09e6 b100 tst $ACC0
|
|
// 09e7 0275 ifz
|
|
// 09e8 1a3a srr @$AR1, $AX0.H
|
|
|
|
ACC0 -= ACC1;
|
|
if(ACC0 == 0)
|
|
*0x405 = 1; // PB.ReachedEnd = 1
|
|
|
|
09e9 2e3a srs @0x003a, $AC0.M
|
|
09ea 2c3b srs @0x003b, $AC0.L
|
|
09eb 2638 lrs $AC0.M, @0x0038
|
|
09ec 2439 lrs $AC0.L, @0x0039
|
|
09ed 00d8 0362 lr $AX0.L, @0x0362
|
|
09ef 7000 addaxl $ACC0, $AX0.L
|
|
09f0 2c39 srs @0x0039, $AC0.L
|
|
09f1 2e38 srs @0x0038, $AC0.M
|
|
|
|
// 09f2 0092 00ff lri $CR, #0x00ff
|
|
// 09f4 029f 02d0 jmp 0x02d0
|
|
GOTO Resample_From0580To0520:
|
|
}
|
|
|
|
|
|
// unreachable code
|
|
void Unreachable() {
|
|
09f6 8100 clr $ACC0
|
|
09f7 2e34 srs @0x0034, $AC0.M
|
|
09f8 2e35 srs @0x0035, $AC0.M
|
|
}
|
|
|
|
void 09f9_UpdateSampleCounters8() {
|
|
09f9 2334 lrs $AX1.H, @0x0034
|
|
09fa 2135 lrs $AX1.L, @0x0035
|
|
09fb 268a lrs $AC0.M, @0xff8a
|
|
09fc 248b lrs $AC0.L, @0xff8b
|
|
09fd 5a00 subax $ACC0, $AX1
|
|
09fe 2e3a srs @0x003a, $AC0.M
|
|
09ff 2c3b srs @0x003b, $AC0.L
|
|
0a00 2634 lrs $AC0.M, @0x0034
|
|
0a01 2435 lrs $AC0.L, @0x0035
|
|
0a02 238c lrs $AX1.H, @0xff8c
|
|
0a03 218d lrs $AX1.L, @0xff8d
|
|
0a04 4a00 addax $ACC0, $AX1
|
|
0a05 2e38 srs @0x0038, $AC0.M
|
|
0a06 2c39 srs @0x0039, $AC0.L
|
|
0a07 8100 clr $ACC0
|
|
0a08 2e05 srs @0x0005, $AC0.M
|
|
// 0a09 02df ret
|
|
}
|
|
|
|
void 0a0a_ReadFromAccelerator8To16(OutBuffer($AR3), Count($AX0.H)) {
|
|
// Read from ARAM. Convert 8-bit samples to 16-bit.
|
|
// 0a0a 0080 ffd3 lri $AR0, #0xffd3
|
|
// 0a0c 0084 0000 lri $IX0, #0x0000
|
|
// 0a0e 007a 0a12 bloop $AX0.H, 0x0a12
|
|
// 0a10 199e lrrn $AC0.M, @$AR0
|
|
// 0a11 1488 asl $ACC0, #8
|
|
// 0a12 1b7e srri @$AR3, $AC0.M
|
|
// 0a13 02df ret
|
|
for (int i = 0; i < $AX0.H; i++) {
|
|
*($AR3++) = (*0xffd3) << 8; // ffd3 is the non-adpcm alternative read address for the accelerator.
|
|
}
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////// 0x10 DECODER
|
|
// Hardcoded destination 0x0580.
|
|
// This should be the easiest decoder to decipher in full -- except the really
|
|
// trivial ones like the synths.
|
|
// It's almost identical to Decoder0x08
|
|
void Decoder0x10() {
|
|
// 0a14 0092 0004 lri $CR, #0x0004
|
|
0a16 2002 lrs $AX0.L, @0x0002
|
|
0a17 8100 clr $ACC0
|
|
0a18 8900 clr $ACC1
|
|
// 0a19 2430 lrs $AC0.L, @0x0030
|
|
0a1a 8d00 set15
|
|
|
|
// 0a1b 0950 lris $AX1.L, #0x50
|
|
// 0a1c a000 mulx $AX0.L, $AX1.L
|
|
// 0a1d a400 mulxac $AX0.L, $AX1.L, $ACC0
|
|
// 0a1e 1404 lsl $ACC0, #4
|
|
// 0a1f 8c00 clr15
|
|
|
|
// Compute how much data we need to read, to get 0x50 samples after resampling.
|
|
// AC0.L is cursamplefrac, AX0.L is ratio.
|
|
$ACC0 = (PB.CurrentSampleFrac + 0x50 * PB.Ratio) << 4;
|
|
|
|
0a20 1ffe mrr $AC1.M, $AC0.M
|
|
0a21 0083 0580 lri $AR3, #0x0580
|
|
0a23 2201 lrs $AX0.H, @0x0001
|
|
0a24 8600 tstaxh $AX0.H
|
|
0a25 0294 0a36 jnz 0x0a36 /// Jump! See jump destination below.
|
|
|
|
0a27 2204 lrs $AX0.H, @0x0004
|
|
0a28 8600 tstaxh $AX0.H
|
|
0a29 02b4 0a7f callne 0x0a7f
|
|
if (*0x0404) // "NeedsReset"
|
|
{
|
|
0a7f_UpdateSampleCounters10()
|
|
}
|
|
|
|
0a2b 8100 clr $ACC0
|
|
|
|
0a2c 2605 lrs $AC0.M, @0x0005
|
|
0a2d b100 tst $ACC0
|
|
0a2e 0295 0a43 jz 0x0a43
|
|
if (*0x405) {
|
|
|
|
retry_0a30:
|
|
0a30 8100 clr $ACC0
|
|
0a31 2e05 srs @0x0005, $AC0.M
|
|
0a32 2281 lrs $AX0.H, @0xff81
|
|
0a33 8600 tstaxh $AX0.H
|
|
0a34 0294 0a3d jnz 0x0a3d
|
|
if (!*401) { //// <<<<<<<<<<<< Jump destination
|
|
0a36 8100 clr $ACC0
|
|
0a37 005f loop $AC1.M
|
|
0a38 1b7e srri @$AR3, $AC0.M
|
|
0a39 7400 incm $AC0.M
|
|
0a3a 2e01 srs @0x0001, $AC0.M
|
|
0a3b 029f 0a78 jmp 0x0a78 // quit
|
|
} else {
|
|
// Copy [88,89] to [34,35]
|
|
0a3d 2688 lrs $AC0.M, @0xff88
|
|
0a3e 2489 lrs $AC0.L, @0xff89
|
|
0a3f 2e34 srs @0x0034, $AC0.M
|
|
0a40 2c35 srs @0x0035, $AC0.L
|
|
0a41 02bf 0a7f call 0x0a7f
|
|
0a7f_UpdateSampleCounters10()
|
|
}
|
|
}
|
|
|
|
0a43:
|
|
0a43 00ff 0360 sr @0x0360, $AC1.M
|
|
0a45 2638 lrs $AC0.M, @0x0038
|
|
0a46 2439 lrs $AC0.L, @0x0039
|
|
0a47 0f06 lris $AC1.M, #0x06 // Sample format 6
|
|
// 0a48 02bf 05ad call 0x05ad
|
|
05ad_SetupAccelerator(AC0.M, AC0.L, AC1.M)
|
|
|
|
0a4a 00df 0360 lr $AC1.M, @0x0360
|
|
0a4c 8100 clr $ACC0
|
|
0a4d 263a lrs $AC0.M, @0x003a
|
|
0a4e b100 tst $ACC0
|
|
0a4f 0294 0a5e jnz 0x0a5e
|
|
if (!*0x043a) {
|
|
0a51 263b lrs $AC0.M, @0x003b
|
|
0a52 5c00 sub $ACC0, $ACC1
|
|
0a53 0290 0a5e jge 0x0a5e
|
|
if (0x43b <= ACC1) { // not sure, but .. not enough samples?
|
|
0a55 223b lrs $AX0.H, @0x003b
|
|
// 0a56 02bf 0a91 call 0x0a91 // Read more samples
|
|
0a91_ReadFromAccelerator(OutBuffer($AR3), Count($AX0.H));
|
|
0a58 5500 subr $ACC1, $AX0.H
|
|
// 0a59 0a01 lris $AX0.H, #0x01
|
|
// 0a5a 00fa 0405 sr @0x0405, $AX0.H
|
|
*0x405 = 1; // PB.ReachedEnd
|
|
|
|
0a5c 029f 0a30 jmp 0x0a30 // GOTO retry_0a30;
|
|
}
|
|
}
|
|
|
|
0a5e 1f5f mrr $AX0.H, $AC1.M
|
|
// 0a5f 02bf 0a91 call 0x0a91 // Read more samples
|
|
0a91_ReadFromAccelerator(OutBuffer($AR3), Count($AX0.H))
|
|
|
|
// Stash AX0.H away, it gets read again at 0a72.
|
|
0a61 00fa 0362 sr @0x0362, $AX0.H
|
|
|
|
0a63 8100 clr $ACC0
|
|
0a64 263a lrs $AC0.M, @0x003a
|
|
0a65 243b lrs $AC0.L, @0x003b
|
|
0a66 1570 lsr $ACC1, #-16
|
|
// 0a67 0a01 lris $AX0.H, #0x01
|
|
// 0a68 0081 0405 lri $AR1, #0x0405
|
|
// 0a6a 5c00 sub $ACC0, $ACC1
|
|
// 0a6b b100 tst $ACC0
|
|
// 0a6c 0275 ifz
|
|
// 0a6d 1a3a srr @$AR1, $AX0.H
|
|
|
|
ACC0 -= ACC1;
|
|
if(ACC0 == 0)
|
|
*0x405 = 1; // PB.ReachedEnd = 1
|
|
|
|
0a6e 2e3a srs @0x003a, $AC0.M
|
|
0a6f 2c3b srs @0x003b, $AC0.L
|
|
0a70 2638 lrs $AC0.M, @0x0038
|
|
0a71 2439 lrs $AC0.L, @0x0039
|
|
0a72 00d8 0362 lr $AX0.L, @0x0362
|
|
0a74 7000 addaxl $ACC0, $AX0.L
|
|
0a75 7000 addaxl $ACC0, $AX0.L
|
|
0a76 2c39 srs @0x0039, $AC0.L
|
|
0a77 2e38 srs @0x0038, $AC0.M
|
|
|
|
// 0a78 0092 00ff lri $CR, #0x00ff
|
|
// 0a7a 029f 02d0 jmp 0x02d0
|
|
GOTO Resample_From0580To0520:
|
|
}
|
|
|
|
void 0a7c_UnkUnused() {
|
|
0a7c 8100 clr $ACC0
|
|
0a7d 2e34 srs @0x0034, $AC0.M
|
|
0a7e 2e35 srs @0x0035, $AC0.M
|
|
|
|
// used by 0x10 decoder
|
|
void 0a7f_UpdateSampleCounters10() {
|
|
0a7f 2334 lrs $AX1.H, @0x0034
|
|
0a80 2135 lrs $AX1.L, @0x0035
|
|
0a81 268a lrs $AC0.M, @0xff8a
|
|
0a82 248b lrs $AC0.L, @0xff8b
|
|
0a83 5a00 subax $ACC0, $AX1 // Subtract [34,35] from [8a, 8b]
|
|
0a84 2e3a srs @0x003a, $AC0.M
|
|
0a85 2c3b srs @0x003b, $AC0.L
|
|
0a86 2634 lrs $AC0.M, @0x0034
|
|
0a87 2435 lrs $AC0.L, @0x0035
|
|
0a88 1401 lsl $ACC0, #1 // This shift is not done in UpdateSampleCounters8.
|
|
0a89 238c lrs $AX1.H, @0xff8c
|
|
0a8a 218d lrs $AX1.L, @0xff8d
|
|
0a8b 4a00 addax $ACC0, $AX1 // Add [34,35]<<1 to [8c, 8d]
|
|
0a8c 2e38 srs @0x0038, $AC0.M
|
|
0a8d 2c39 srs @0x0039, $AC0.L
|
|
0a8e 8100 clr $ACC0
|
|
0a8f 2e05 srs @0x0005, $AC0.M
|
|
0a90 02df ret
|
|
}
|
|
|
|
|
|
// Read AX0.H samples from the accelerator.
|
|
void 0a91_ReadFromAccelerator(OutBuffer($AR3), Count($AX0.H)) {
|
|
// 0a91 0080 ffd3 lri $AR0, #0xffd3
|
|
// 0a93 0084 0000 lri $IX0, #0x0000
|
|
// 0a95 007a 0a98 bloop $AX0.H, 0x0a98
|
|
// 0a97 199e lrrn $AC0.M, @$AR0
|
|
// 0a98 1b7e srri @$AR3, $AC0.M
|
|
// 0a99 02df ret
|
|
|
|
for (int i = 0; i < $AX0.H; i++) {
|
|
*($AR3++) = *0xffd3; // ffd3 is the non-adpcm alternative read address for the accelerator.
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////// 0x20 DECODER
|
|
// Same as 0x21 but with no resampling.
|
|
{
|
|
// 0a9a 8900 clr $ACC1
|
|
// 0a9b 0f50 lris $AC1.M, #0x50
|
|
// 0a9c 0083 0520 lri $AR3, #0x0520
|
|
// 0a9e 02bf 0ab3 call 0x0ab3
|
|
|
|
ACC1 = 0;
|
|
AC1.M = 0x50;
|
|
AR3 = 0x520;
|
|
|
|
0ab3_Decoder0x21Core(AC1.M=0x50, AR3=#0x0520);
|
|
|
|
// 0aa0 029f 02d8 jmp 0x02d8
|
|
GOTO ContinueWithBlock: // in SyncFrame
|
|
}
|
|
|
|
//////////////////////////////////////////// 0x21 DECODER
|
|
void 0aa2_Decoder0x21() {
|
|
// 0aa2 00d8 0402 lr $AX0.L, @0x0402
|
|
// 0aa4 8100 clr $ACC0
|
|
// 0aa5 8900 clr $ACC1
|
|
AX0.L = *0x0402;
|
|
ACC0 = 0
|
|
ACC1 = 0
|
|
// 0aa6 00dc 0430 lr $AC0.L, @0x0430
|
|
// 0aa8 0a50 lris $AX0.H, #0x50
|
|
// 0aa9 9000 mul $AX0.L, $AX0.H
|
|
// 0aaa 9400 mulac $AX0.L, $AX0.H, $ACC0
|
|
// 0aab 1404 lsl $ACC0, #4
|
|
ACC0 = (*0x0430 + (*0x0402 * 0x50)) << 4;
|
|
|
|
// 0aac 1ffe mrr $AC1.M, $AC0.M
|
|
ACC1 = ACC0 & 0xFFFF0000;
|
|
|
|
// 0aad 0083 0580 lri $AR3, #0x0580
|
|
// 0aaf 02bf 0ab3 call 0x0ab3 // 0ab3_Decoder0x21Core
|
|
0ab3_Decoder0x21Core(AC1.M, AR3=#0x0580);
|
|
|
|
// 0ab1 029f 02d0 jmp 0x02d0
|
|
GOTO Resample_From0580To0520:
|
|
}
|
|
|
|
// 0x21 Decoder Core
|
|
// Decoder 0x21 simply streams raw audio from RAM (not ARAM!) by using DMA.
|
|
// Lots of buffer wrap trickery etc but no actual decoding.
|
|
void 0ab3_Decoder0x21Core(AC1.M, AR3) {
|
|
// 0ab3 0092 0004 lri $CR, #0x0004
|
|
// 0ab5 8100 clr $ACC0
|
|
// 0ab6 263a lrs $AC0.M, @0x003a
|
|
// 0ab7 243b lrs $AC0.L, @0x003b
|
|
// 0ab8 1f1f mrr $AX0.L, $AC1.M
|
|
// 0ab9 0a00 lris $AX0.H, #0x00
|
|
// 0aba 5800 subax $ACC0, $AX0
|
|
ACC0 = [0x043a,0x043b];
|
|
ACC0 -= AC1.M;
|
|
|
|
|
|
// 0abb 0292 0ad1 jg 0x0ad1
|
|
if ([0x043a,0x043b] <= AC1.M) {
|
|
// Happens when sound has finished playing?
|
|
|
|
// 0abd 8900 clr $ACC1
|
|
// 0abe 00c0 043b lr $AR0, @0x043b
|
|
ACC1 = 0;
|
|
AR0 = *0x043b;
|
|
|
|
// 0ac0 02bf 0af6 call 0x0af6 // 0af6_Decoder0x21_MoreStuff()
|
|
0af6_Decoder0x21_MoreStuff(AR0=*0x043b, AR3);
|
|
|
|
// 0ac2 8100 clr $ACC0
|
|
// 0ac3 1fd8 mrr $AC0.M, $AX0.L
|
|
// 0ac4 223b lrs $AX0.H, @0x003b
|
|
// 0ac5 5400 subr $ACC0, $AX0.H
|
|
// 0ac6 0007 dar $AR3
|
|
// 0ac7 1979 lrri $AX1.L, @$AR3
|
|
|
|
ACC0 = 0;
|
|
AX0.H = *0x043b;
|
|
AC0.M = AX0.L - *0x043b;
|
|
|
|
AX1.L = *$AR3;
|
|
|
|
// Looks like duplication of the first memory address AC0.M times
|
|
|
|
// 0ac8 005e loop $AC0.M
|
|
for(int i = 0; i < AC0.M; i++) {
|
|
// 0ac9 1b79 srri @$AR3, $AX1.L
|
|
*$AR3++ = AX1.L;
|
|
}
|
|
|
|
// 0aca 0f01 lris $AC1.M, #0x01
|
|
// 0acb 2f01 srs @0x0001, $AC1.M
|
|
// 0acc 8900 clr $ACC1
|
|
// 0acd 2f3b srs @0x003b, $AC1.M
|
|
|
|
ACC1 = 0;
|
|
|
|
// Looks like some finalization of the PB
|
|
*0x0401 = 1; // KeyOff
|
|
*0x043b = 0; // RemLength
|
|
|
|
|
|
0ace 0092 00ff lri $CR, #0x00ff
|
|
//0ad0 02df ret
|
|
return;
|
|
}
|
|
|
|
// 0ad1 2e3a srs @0x003a, $AC0.M
|
|
// 0ad2 2c3b srs @0x003b, $AC0.L
|
|
|
|
*0x043a = AC0.M;
|
|
*0x043b = AC0.L;
|
|
|
|
// 0ad3 8100 clr $ACC0
|
|
// 0ad4 8900 clr $ACC1
|
|
// 0ad5 268a lrs $AC0.M, @0xff8a
|
|
// 0ad6 2734 lrs $AC1.M, @0x0034
|
|
|
|
ACC0 = 0;
|
|
ACC1 = 0;
|
|
AC0.M = *0x048a;
|
|
AC1.M = *0x0434;
|
|
|
|
// 0ad7 5c00 sub $ACC0, $ACC1
|
|
// 0ad8 2e36 srs @0x0036, $AC0.M
|
|
|
|
ACC0 -= AC1.L;
|
|
*0x0436 = (ACC0 & 0xFFFF0000) >> 16;
|
|
|
|
// 0ad9 5000 subr $ACC0, $AX0.L
|
|
ACC0 -= AX0.L;
|
|
|
|
0ada 0290 0af0 jge 0x0af0
|
|
if (ACC0 < 0) {
|
|
// 0adc 00c0 0436 lr $AR0, @0x0436
|
|
// 0ade 02bf 0af6 call 0x0af6
|
|
0af6_Decoder0x21_MoreStuff(AR0=*0x0436, AR3);
|
|
|
|
// 0ae0 8100 clr $ACC0
|
|
// 0ae1 1fd8 mrr $AC0.M, $AX0.L
|
|
|
|
ACC0 = 0;
|
|
AC0.M = AX0.L;
|
|
|
|
// 0ae2 2236 lrs $AX0.H, @0x0036 // 0x0436
|
|
AX0.H = *0x0436;
|
|
|
|
// 0ae3 5400 subr $ACC0, $AX0.H
|
|
// 0ae4 1c1e mrr $AR0, $AC0.M
|
|
// 0ae5 8100 clr $ACC0
|
|
// 0ae6 2e34 srs @0x0034, $AC0.M
|
|
|
|
ACC0 -= AX0.H;
|
|
AR0 = (ACC0 & 0xFFFF0000) >> 16;
|
|
ACC0 = 0;
|
|
*0x0434 = 0;
|
|
|
|
// 0ae7 2688 lrs $AC0.M, @0xff88 // 0x0488
|
|
// 0ae8 2489 lrs $AC0.L, @0xff89 // 0x0489
|
|
// 0ae9 2e8c srs @0xff8c, $AC0.M
|
|
// 0aea 2c8d srs @0xff8d, $AC0.L
|
|
|
|
*0x048c = *0x0488;
|
|
*0x048d = *0x0489;
|
|
|
|
// 0aeb 02bf 0af6 call 0x0af6
|
|
0af6_Decoder0x21_MoreStuff(AR0=*0x0436, AR3);
|
|
|
|
0aed 0092 00ff lri $CR, #0x00ff
|
|
// 0aef 02df ret
|
|
return;
|
|
}
|
|
|
|
// 0af0 1c18 mrr $AR0, $AX0.L
|
|
// 0af1 02bf 0af6 call 0x0af6
|
|
|
|
AR0 = AX0.L;
|
|
0af6_Decoder0x21_MoreStuff(AR0=AX0.L, AR3);
|
|
|
|
0af3 0092 00ff lri $CR, #0x00ff
|
|
// 0af5 02df ret
|
|
}
|
|
|
|
|
|
|
|
// CR = 0x4
|
|
// Does strange stuff with PB[0x34] and the address PB[0x8c,d]
|
|
// Does not touch AX0.L
|
|
void 0af6_Decoder0x21_MoreStuff($AR0, $AR3) {
|
|
// 0af6 8100 clr $ACC0
|
|
// 0af7 1fc0 mrr $AC0.M, $AR0
|
|
// 0af8 b100 tst $ACC0
|
|
// 0af9 02d5 retz
|
|
if (!AR0)
|
|
return;
|
|
|
|
// 0afa 8900 clr $ACC1
|
|
// 0afb 2734 lrs $AC1.M, @0x0034
|
|
// 0afc 0340 0001 andi $AC1.M, #0x0001
|
|
// 0afe 0b00 lris $AX1.H, #0x00
|
|
// 0aff 1f3f mrr $AX1.L, $AC1.M
|
|
|
|
AX1.L = *0x0434 & 1;
|
|
|
|
// 0b00 268c lrs $AC0.M, @0xff8c
|
|
// 0b01 248d lrs $AC0.L, @0xff8d
|
|
// 0b02 8900 clr $ACC1
|
|
// 0b03 2534 lrs $AC1.L, @0x0034
|
|
// 0b04 1501 lsl $ACC1, #1
|
|
// 0b05 4c00 add $ACC0, $ACC1
|
|
|
|
// 0b06 5a00 subax $ACC0, $AX1
|
|
// 0b07 5a00 subax $ACC0, $AX1
|
|
|
|
ACC0 = [8c,8d] + *0x0434 * 2 - ((*0x0434 & 1) * 2);
|
|
|
|
// 0b08 1c20 mrr $AR1, $AR0
|
|
|
|
AR1 = AR0;
|
|
|
|
// 0b09 1fe0 mrr $AC1.M, $AR0
|
|
// 0b0a 0502 addis $ACC1, #0x02
|
|
ACC1 = ($AR0 << 16) + 0x20000;
|
|
|
|
//
|
|
// 0b0b 1c1f mrr $AR0, $AC1.M
|
|
// 0b0c 009f 0b00 lri $AC1.M, #0x0b00
|
|
0b0e 0092 00ff lri $CR, #0x00ff
|
|
|
|
AR0 = AC1.M;
|
|
AC1.M = 0x0b00;
|
|
|
|
// Load more audio from RAM by DMA??
|
|
|
|
// 0b10 02bf 0525 call 0x0525 // 0525_CopyRAMtoDMEM
|
|
0525_CopyRAMtoDMEM($AR1 == $ACC1 >> 16, 0x0b00, $AR0)
|
|
|
|
// 0b12 0092 0004 lri $CR, #0x0004
|
|
|
|
// 0b14 2734 lrs $AC1.M, @0x0034
|
|
// 0b15 1f61 mrr $AX1.H, $AR1
|
|
// 0b16 4700 addr $ACC1, $AX1.H
|
|
// 0b17 2f34 srs @0x0034, $AC1.M
|
|
*0x0434 += AR1;
|
|
|
|
// 0b18 0080 0b00 lri $AR0, #0x0b00
|
|
// 0b1a 8900 clr $ACC1
|
|
// 0b1b 1ff9 mrr $AC1.M, $AX1.L
|
|
// 0b1c b900 tst $ACC1
|
|
// 0b1d 0274 ifnz
|
|
if (AX1.L) {
|
|
// 0b1e 0008 iar $AR0
|
|
$AR0++;
|
|
}
|
|
// 0b1f 8900 clr $ACC1
|
|
// 0b20 1fe1 mrr $AC1.M, $AR1
|
|
// 0b21 191e lrri $AC0.M, @$AR0
|
|
// 0b22 0701 cmpis $ACC1, #0x01
|
|
ACC1 = 0;
|
|
AC1.M = AR1;
|
|
AC0.M = *$AR0++;
|
|
// 0b23 0293 0b2c jle 0x0b2c
|
|
if (AC1.M > 1) {
|
|
// 0b25 191a lrri $AX0.H, @$AR0
|
|
// 0b26 05fe addis $ACC1, #0xfe
|
|
AX0.H = *$AR0++;
|
|
ACC1 += 0xfe0000;
|
|
|
|
// 0b27 005f loop $AC1.M
|
|
for(int i = 0; i < AC1.M; i++) {
|
|
// 0b28 64a0 movr'ls $ACC0, $AX0.H : $AX0.H, $AC0.M
|
|
AC0.L = 0;
|
|
AC0.H = AX0.H;
|
|
AC0.M = AX0.H;
|
|
AX0.H = *$AR0++;
|
|
*$AR3++ = AC0.M;
|
|
}
|
|
//0b29 1b7e srri @$AR3, $AC0.M
|
|
//0b2a 1b7a srri @$AR3, $AX0.H
|
|
//0b2b 02df ret
|
|
|
|
*$AR3++ = AC0.M;
|
|
*$AR3++ = AX0.H;
|
|
} else {
|
|
//0b2c 1b7e srri @$AR3, $AC0.M
|
|
//0b2d 02df ret
|
|
*$AR3++ = AC0.M;
|
|
}
|
|
}
|
|
|
|
|
|
void 0b2e_Unk_Multiply() { // ZWW: 01c2_Unk
|
|
0b2e 8a00 m2
|
|
0b2f 0083 03e8 lri $AR3, #0x03e8
|
|
0b31 191e lrri $AC0.M, @$AR0
|
|
0b32 191a lrri $AX0.H, @$AR0
|
|
0b33 1006 loopi #0x06
|
|
0b34 64a0 movr'ls $ACC0, $AX0.H : $AX0.H, $AC0.M
|
|
0b35 1b7e srri @$AR3, $AC0.M
|
|
0b36 1b7a srri @$AR3, $AX0.H
|
|
0b37 0080 03e8 lri $AR0, #0x03e8
|
|
0b39 0088 0007 lri $WR0, #0x0007
|
|
0b3b 1150 0b48 bloopi #0x50, 0x0b48
|
|
for (int i = 0; i < 0x50; i++) {
|
|
0b3d 1c61 mrr $AR3, $AR1
|
|
0b3e 84c3 clrp'ld : $AX0.L, $AX1.L, @$AR3
|
|
0b3f f2c3 madd'ld $AX0.L, $AX0.H : $AX0.L, $AX1.L, @$AR3
|
|
0b40 f2c3 madd'ld $AX0.L, $AX0.H : $AX0.L, $AX1.L, @$AR3
|
|
0b41 f2c3 madd'ld $AX0.L, $AX0.H : $AX0.L, $AX1.L, @$AR3
|
|
0b42 f2c3 madd'ld $AX0.L, $AX0.H : $AX0.L, $AX1.L, @$AR3
|
|
0b43 f2c3 madd'ld $AX0.L, $AX0.H : $AX0.L, $AX1.L, @$AR3
|
|
0b44 f2c3 madd'ld $AX0.L, $AX0.H : $AX0.L, $AX1.L, @$AR3
|
|
0b45 f2c3 madd'ld $AX0.L, $AX0.H : $AX0.L, $AX1.L, @$AR3
|
|
0b46 f200 madd $AX0.L, $AX0.H
|
|
0b47 fe00 movpz $ACC0
|
|
0b48 1b3e srri @$AR1, $AC0.M
|
|
}
|
|
0b49 0088 ffff lri $WR0, #0xffff
|
|
0b4b 8b00 m0
|
|
0b4c 02df ret
|
|
}
|
|
|
|
// looks kind of like a IIR filter?
|
|
// Hardcoded buffer length = 0x50
|
|
void 0b4d_IIR_Filter(InBuffer($AR0), OutBuffer($AR1), FilterLength(AC1.M)) {
|
|
0b4d 8a00 m2
|
|
0b4e 05fe addis $ACC1, #0xfe
|
|
0b4f 0083 03e8 lri $AR3, #0x03e8
|
|
0b51 191e lrri $AC0.M, @$AR0
|
|
0b52 191a lrri $AX0.H, @$AR0
|
|
0b53 005f loop $AC1.M
|
|
0b54 64a0 movr'ls $ACC0, $AX0.H : $AX0.H, $AC0.M
|
|
|
|
0b55 1b7e srri @$AR3, $AC0.M
|
|
0b56 1b7a srri @$AR3, $AX0.H
|
|
0b57 0080 03e8 lri $AR0, #0x03e8
|
|
0b59 0501 addis $ACC1, #0x01
|
|
0b5a 1d1f mrr $WR0, $AC1.M
|
|
// 0b5b 1150 0b63 bloopi #0x50, 0x0b63
|
|
for (int i = 0; i < 0x50; i++) {
|
|
0b5d 1c61 mrr $AR3, $AR1
|
|
0b5e 84c3 clrp'ld : $AX0.L, $AX1.L, @$AR3
|
|
0b5f 005f loop $AC1.M
|
|
0b60 f2c3 madd'ld $AX0.L, $AX0.H : $AX0.L, $AX1.L, @$AR3
|
|
0b61 f200 madd $AX0.L, $AX0.H
|
|
0b62 fe00 movpz $ACC0
|
|
0b63 1b3e srri @$AR1, $AC0.M
|
|
}
|
|
0b64 0088 ffff lri $WR0, #0xffff
|
|
0b66 8b00 m0
|
|
0b67 02df ret
|
|
}
|
|
|
|
// Looks like a 4-tap FIR filter.
|
|
// Hardcoded buffer length = 0x50
|
|
// Uses 0x03e8 as some scratch space, i think .
|
|
void 0b68_4TapFIR(InBuffer($AR2), FilterBuffer($AR0), OutBuffer($AR1)) {
|
|
0b68 0083 03e8 lri $AR3, #0x03e8
|
|
0b6a 191e lrri $AC0.M, @$AR0
|
|
0b6b 191a lrri $AX0.H, @$AR0
|
|
0b6c 64a0 movr'ls $ACC0, $AX0.H : $AX0.H, $AC0.M
|
|
0b6d 64a0 movr'ls $ACC0, $AX0.H : $AX0.H, $AC0.M
|
|
0b6e 1b7e srri @$AR3, $AC0.M
|
|
0b6f 1b7a srri @$AR3, $AX0.H
|
|
0b70 0080 03e8 lri $AR0, #0x03e8
|
|
0b72 0088 0003 lri $WR0, #0x0003 // That's a short wrap - filter coefs?
|
|
0b74 0085 0000 lri $IX1, #0x0000
|
|
0b76 0087 0000 lri $IX3, #0x0000
|
|
0b78 1fc2 mrr $AC0.M, $AR2
|
|
0b79 195b lrri $AX1.H, @$AR2
|
|
0b7a 1959 lrri $AX1.L, @$AR2
|
|
0b7b 195f lrri $AC1.M, @$AR2
|
|
0b7c 195a lrri $AX0.H, @$AR2
|
|
0b7d 1c5e mrr $AR2, $AC0.M
|
|
0b7e 1fda mrr $AC0.M, $AX0.H
|
|
0b7f 1c61 mrr $AR3, $AR1
|
|
0b80 8a00 m2
|
|
0b81 8f00 set40
|
|
0b82 191a lrri $AX0.H, @$AR0
|
|
0b83 b850 mulx'l $AX0.H, $AX1.H : $AX0.H, @$AR0
|
|
0b84 e250 maddx'l $AX0.H, $AX1.L : $AX0.H, @$AR0
|
|
0b85 ea50 maddc'l $AC1.M, $AX1.L : $AX0.H, @$AR0
|
|
0b86 e8e8 maddc'ldm $AC0.M, $AX1.L : $AX0.H, $AX1.L, @$AR0
|
|
0b87 b650 mulxmv'l $AX0.H, $AX1.L, $ACC0 : $AX0.H, @$AR0
|
|
0b88 1127 0b93 bloopi #0x27, 0x0b93
|
|
for (int i = 0; i < 0x27; i++) {
|
|
0b8a e3a8 maddx'lsm $AX0.H, $AX1.H : $AX0.H, $AC0.M // end of first iteration
|
|
|
|
0b8b 197e lrri $AC0.M, @$AR3
|
|
0b8c e850 maddc'l $AC0.M, $AX1.L : $AX0.H, @$AR0
|
|
0b8d eaf8 maddc'ldm $AC1.M, $AX1.L : $AX0.H, $AX1.H, @$AR0
|
|
0b8e bf50 mulxmv'l $AX0.H, $AX1.H, $ACC1 : $AX0.H, @$AR0
|
|
0b8f e2a9 maddx'lsm $AX0.H, $AX1.L : $AX0.H, $AC1.M // e
|
|
|
|
0b90 197f lrri $AC1.M, @$AR3 // start of first iteration
|
|
0b91 ea50 maddc'l $AC1.M, $AX1.L : $AX0.H, @$AR0
|
|
0b92 e8e8 maddc'ldm $AC0.M, $AX1.L : $AX0.H, $AX1.L, @$AR0
|
|
0b93 b650 mulxmv'l $AX0.H, $AX1.L, $ACC0 : $AX0.H, @$AR0
|
|
}
|
|
0b94 e3a8 maddx'lsm $AX0.H, $AX1.H : $AX0.H, $AC0.M
|
|
0b95 197e lrri $AC0.M, @$AR3
|
|
0b96 e850 maddc'l $AC0.M, $AX1.L : $AX0.H, @$AR0
|
|
0b97 eaf8 maddc'ldm $AC1.M, $AX1.L : $AX0.H, $AX1.H, @$AR0
|
|
0b98 bf00 mulxmv $AX0.H, $AX1.H, $ACC1
|
|
0b99 1bff srrn @$AR3, $AC1.M
|
|
0b9a 197f lrri $AC1.M, @$AR3
|
|
0b9b 8e00 set16
|
|
0b9c 8b00 m0
|
|
0b9d 0088 ffff lri $WR0, #0xffff
|
|
0b9f 1b5b srri @$AR2, $AX1.H
|
|
0ba0 1b59 srri @$AR2, $AX1.L
|
|
0ba1 1b5f srri @$AR2, $AC1.M
|
|
0ba2 1b5e srri @$AR2, $AC0.M
|
|
0ba3 02df ret
|
|
}
|
|
|
|
// Fixed length 0x50.
|
|
void 0ba4_UnknownFilter(params($AR0), buffer($AR1), filter_state($AR2)) {
|
|
0ba4 0083 03e8 lri $AR3, #0x03e8
|
|
|
|
// Load 4 parameters from *$AR0, copy them into the tiny ring buffer
|
|
// later handled by $AR0/$WR0 (filter state?)
|
|
0ba6 191e lrri $AC0.M, @$AR0
|
|
0ba7 191a lrri $AX0.H, @$AR0
|
|
0ba8 64a0 movr'ls $ACC0, $AX0.H : $AX0.H, $AC0.M
|
|
0ba9 64a0 movr'ls $ACC0, $AX0.H : $AX0.H, $AC0.M
|
|
0baa 1b7e srri @$AR3, $AC0.M
|
|
0bab 1b7a srri @$AR3, $AX0.H
|
|
0bac 0080 03e8 lri $AR0, #0x03e8
|
|
0bae 0088 0003 lri $WR0, #0x0003 // That's a short wrap - filter coefs?
|
|
0bb0 0085 0000 lri $IX1, #0x0000
|
|
0bb2 0087 0000 lri $IX3, #0x0000
|
|
|
|
// Load more parameters from *$AR2
|
|
0bb4 1fc2 mrr $AC0.M, $AR2
|
|
0bb5 195b lrri $AX1.H, @$AR2
|
|
0bb6 1959 lrri $AX1.L, @$AR2
|
|
0bb7 195f lrri $AC1.M, @$AR2
|
|
0bb8 195a lrri $AX0.H, @$AR2
|
|
|
|
0bb9 1c5e mrr $AR2, $AC0.M
|
|
0bba 1fda mrr $AC0.M, $AX0.H
|
|
|
|
// Setup AR3, now ready to read in data.
|
|
0bbb 1c61 mrr $AR3, $AR1
|
|
0bbc 8a00 m2
|
|
0bbd 8f00 set40
|
|
|
|
// Start the pipeline
|
|
0bbe 191a lrri $AX0.H, @$AR0
|
|
0bbf b800 mulx $AX0.H, $AX1.H
|
|
0bc0 e350 maddx'l $AX0.H, $AX1.H : $AX0.H, @$AR0
|
|
0bc1 e250 maddx'l $AX0.H, $AX1.L : $AX0.H, @$AR0
|
|
0bc2 ea00 maddc $AC1.M, $AX1.L
|
|
0bc3 ea50 maddc'l $AC1.M, $AX1.L : $AX0.H, @$AR0
|
|
0bc4 e877 maddc'ln $AC0.M, $AX1.L : $AC0.M, @$AR3
|
|
0bc5 ece8 msubc'ldm $AC0.M, $AX1.L : $AX0.H, $AX1.L, @$AR0
|
|
0bc6 b200 mulxmvz $AX0.H, $AX1.L, $ACC0
|
|
|
|
0bc7 1127 0bd8 bloopi #0x27, 0x0bd8
|
|
// (half of 0x50) - 1, -1 due to the software pipelining.
|
|
for (int i = 0; i < 0x27; i++) {
|
|
0bc9 e250 maddx'l $AX0.H, $AX1.L : $AX0.H, @$AR0
|
|
0bca e3a8 maddx'lsm $AX0.H, $AX1.H : $AX0.H, $AC0.M
|
|
|
|
0bcb 197e lrri $AC0.M, @$AR3
|
|
0bcc e800 maddc $AC0.M, $AX1.L
|
|
0bcd e850 maddc'l $AC0.M, $AX1.L : $AX0.H, @$AR0
|
|
0bce ea7f maddc'ln $AC1.M, $AX1.L : $AC1.M, @$AR3
|
|
0bcf eef8 msubc'ldm $AC1.M, $AX1.L : $AX0.H, $AX1.H, @$AR0
|
|
0bd0 bb00 mulxmvz $AX0.H, $AX1.H, $ACC1
|
|
0bd1 e350 maddx'l $AX0.H, $AX1.H : $AX0.H, @$AR0
|
|
0bd2 e2a9 maddx'lsm $AX0.H, $AX1.L : $AX0.H, $AC1.M
|
|
|
|
0bd3 197f lrri $AC1.M, @$AR3
|
|
0bd4 ea00 maddc $AC1.M, $AX1.L
|
|
0bd5 ea50 maddc'l $AC1.M, $AX1.L : $AX0.H, @$AR0
|
|
0bd6 e877 maddc'ln $AC0.M, $AX1.L : $AC0.M, @$AR3
|
|
0bd7 ece8 msubc'ldm $AC0.M, $AX1.L : $AX0.H, $AX1.L, @$AR0
|
|
0bd8 b200 mulxmvz $AX0.H, $AX1.L, $ACC0
|
|
}
|
|
0bd9 e250 maddx'l $AX0.H, $AX1.L : $AX0.H, @$AR0
|
|
0bda e3a8 maddx'lsm $AX0.H, $AX1.H : $AX0.H, $AC0.M
|
|
|
|
0bdb 197e lrri $AC0.M, @$AR3
|
|
0bdc e800 maddc $AC0.M, $AX1.L
|
|
0bdd e850 maddc'l $AC0.M, $AX1.L : $AX0.H, @$AR0
|
|
0bde ea7f maddc'ln $AC1.M, $AX1.L : $AC1.M, @$AR3
|
|
0bdf eef8 msubc'ldm $AC1.M, $AX1.L : $AX0.H, $AX1.H, @$AR0
|
|
0be0 bb00 mulxmvz $AX0.H, $AX1.H, $ACC1
|
|
0be1 1bff srrn @$AR3, $AC1.M
|
|
|
|
0be2 197f lrri $AC1.M, @$AR3
|
|
0be3 8e00 set16
|
|
0be4 8b00 m0
|
|
0be5 0088 ffff lri $WR0, #0xffff
|
|
0be7 1b5b srri @$AR2, $AX1.H
|
|
0be8 1b59 srri @$AR2, $AX1.L
|
|
0be9 1b5f srri @$AR2, $AC1.M
|
|
0bea 1b5e srri @$AR2, $AC0.M
|
|
// 0beb 02df ret
|
|
}
|
|
|
|
void 0bec_Unk() {
|
|
// 0bec 0eff lris $AC0.M, #0xff
|
|
// 0bed 00fe 03f2 sr @0x03f2, $AC0.M
|
|
*0x03f2 = 0xFF
|
|
|
|
// 0bef 8100 clr $ACC0
|
|
// 0bf0 00fe 03f0 sr @0x03f0, $AC0.M
|
|
// 0bf2 00fe 03f6 sr @0x03f6, $AC0.M
|
|
*0x03f0 = 0x00
|
|
*0x03f6 = 0x00
|
|
|
|
// 0bf4 009e 0100 lri $AC0.M, #0x0100
|
|
// 0bf6 00fe 03f7 sr @0x03f7, $AC0.M
|
|
*0x03f7 = 0x100
|
|
|
|
0bf8 00da 03f7 lr $AX0.H, @0x03f7
|
|
0bfa 009e 8000 lri $AC0.M, #0x8000
|
|
0bfc 5400 subr $ACC0, $AX0.H
|
|
0bfd 00fe 03f5 sr @0x03f5, $AC0.M
|
|
|
|
// 0bff 0e30 lris $AC0.M, #0x30
|
|
// 0c00 00fe 03f3 sr @0x03f3, $AC0.M
|
|
*0x03f3 = 0x0030
|
|
|
|
// 0c02 0e10 lris $AC0.M, #0x10
|
|
// 0c03 00fe 03f4 sr @0x03f4, $AC0.M
|
|
*0x03f5 = 0x0010
|
|
|
|
// 0c05 009e 0096 lri $AC0.M, #0x0096
|
|
// 0c07 00fe 03f1 sr @0x03f1, $AC0.M
|
|
*0x03f1 = 0x0096
|
|
|
|
// 0c09 02df ret
|
|
}
|
|
|
|
void 0c0a_Unk() {
|
|
// 0c0a 0080 0a00 lri $AR0, #0x0a00
|
|
// 0c0c 8100 clr $ACC0
|
|
// 0c0d 00de 03f0 lr $AC0.M, @0x03f0
|
|
// 0c0f 8900 clr $ACC1
|
|
// 0c10 b100 tst $ACC0
|
|
|
|
// 0c11 0275 ifz
|
|
// 0c12 0550 addis $ACC1, #0x50
|
|
$AC0.M = *(0x03f0);
|
|
if (*(0x03f0) == 0) {
|
|
$ACC1 = 0x50 << 16;
|
|
}
|
|
// 0c13 00ff 03f0 sr @0x03f0, $AC1.M
|
|
*(0x03f0) = $ACC1;
|
|
|
|
// 0c15 0200 0a60 addi $AC0.M, #0x0a60
|
|
// 0c17 1c7e mrr $AR3, $AC0.M
|
|
// 0c18 0f4e lris $AC1.M, #0x4e
|
|
|
|
$AC0.M += 0xa60;
|
|
$AR3 = $AC0.M
|
|
$AC1.M = 0x4e;
|
|
|
|
// 0c19 02bf 00da call 0x00da
|
|
00da_CopyBuffer(src=0x0a00, dst=$AC0.M, #0x4e)
|
|
|
|
// 0c1b 02df ret
|
|
}
|
|
|
|
// The control flow of this thing is NOT easy ...
|
|
// Reads from buffer at 0x0a60
|
|
// Writes to buffer at 0x0a00
|
|
void 0c1c_ComputeReverbFrom0a60To0a00()
|
|
{
|
|
// 0c1c 00de 03f1 lr $AC0.M, @0x03f1
|
|
// 0c1e 0200 0a60 addi $AC0.M, #0x0a60
|
|
// 0c20 1c7e mrr $AR3, $AC0.M
|
|
$AR3 = 0x0a60 + *(0x03f1);
|
|
|
|
0c21 8100 clr $ACC0
|
|
0c22 8900 clr $ACC1
|
|
0c23 009f 00a0 lri $AC1.M, #0x00a0
|
|
0c25 00de 03f1 lr $AC0.M, @0x03f1
|
|
0c27 5d00 sub $ACC1, $ACC0
|
|
0c28 0e50 lris $AC0.M, #0x50
|
|
0c29 0750 cmpis $ACC1, #0x50
|
|
0c2a 0270 ifge
|
|
0c2b 5d00 sub $ACC1, $ACC0
|
|
0c2c 00da 03f2 lr $AX0.H, @0x03f2
|
|
0c2e 8600 tstaxh $AX0.H
|
|
0c2f 0290 0c4d jge 0x0c4d
|
|
0c31 00de 03f3 lr $AC0.M, @0x03f3
|
|
0c33 5c00 sub $ACC0, $ACC1
|
|
0c34 0293 0c38 jle 0x0c38
|
|
0c36 029f 0c52 jmp 0x0c52 // done:
|
|
|
|
0c38 00db 03f7 lr $AX1.H, @0x03f7
|
|
0c3a 009e 8000 lri $AC0.M, #0x8000
|
|
0c3c 4600 addr $ACC0, $AX1.H
|
|
0c3d 029f 0c44 jmp 0x0c44
|
|
|
|
0c3f 00db 03f7 lr $AX1.H, @0x03f7
|
|
0c41 009e 8000 lri $AC0.M, #0x8000
|
|
0c43 5600 subr $ACC0, $AX1.H
|
|
|
|
0c44 00fe 03f5 sr @0x03f5, $AC0.M
|
|
0c46 1fda mrr $AC0.M, $AX0.H
|
|
0c47 7c00 neg $ACC0
|
|
0c48 1f5e mrr $AX0.H, $AC0.M
|
|
0c49 00fe 03f2 sr @0x03f2, $AC0.M
|
|
0c4b 029f 0c52 jmp 0x0c52 // done:
|
|
|
|
0c4d 00de 03f4 lr $AC0.M, @0x03f4
|
|
0c4f 5d00 sub $ACC1, $ACC0
|
|
0c50 0293 0c3f jle 0x0c3f
|
|
|
|
done:
|
|
0c52 8900 clr $ACC1
|
|
0c53 00dd 03f5 lr $AC1.L, @0x03f5
|
|
0c55 1501 lsl $ACC1, #1
|
|
0c56 8100 clr $ACC0
|
|
0c57 00dc 03f6 lr $AC0.L, @0x03f6
|
|
0c59 008b 009f lri $WR3, #0x009f // 0xa0 wrap
|
|
0c5b 0080 0a00 lri $AR0, #0x0a00
|
|
0c5d 0900 lris $AX1.L, #0x00
|
|
|
|
// This is the loop that used to go crazy in the LLE emulation
|
|
// before we fixed addarn to obey the wrapping register.
|
|
|
|
// Feels like some crazy delay function with a slowly drifting delay time.
|
|
|
|
// Could this be part of a reverb? Or just a flanger?
|
|
|
|
// 0c5e 1150 0c65 bloopi #0x50, 0x0c65
|
|
for (int i = 0; i < 0x50; i++) {
|
|
0c60 1878 lrr $AX0.L, @$AR3
|
|
0c61 4c00 add $ACC0, $ACC1
|
|
0c62 1cfe mrr $IX3, $AC0.M
|
|
0c63 001f addarn $AR3, $IX3
|
|
0c64 1fd9 mrr $AC0.M, $AX1.L
|
|
0c65 1b18 srri @$AR0, $AX0.L
|
|
|
|
$AX0.L = *AR3;
|
|
$ACC0 += $ACC1;
|
|
$IX3 = $AC0.M;
|
|
$AR3 += $IX3;
|
|
$AC0.M = $AX1.L;
|
|
*(AR0++) = $AX0.L;
|
|
}
|
|
|
|
0c66 009f 0a60 lri $AC1.M, #0x0a60
|
|
0c68 1fc3 mrr $AC0.M, $AR3
|
|
0c69 5c00 sub $ACC0, $ACC1
|
|
0c6a 00fe 03f1 sr @0x03f1, $AC0.M
|
|
0c6c 00fc 03f6 sr @0x03f6, $AC0.L
|
|
0c6e 008b ffff lri $WR3, #0xffff // restore wrap
|
|
// 0c70 02df ret
|
|
}
|
|
|
|
|
|
void 0c71_AddBufferA00ToD60AndD00()
|
|
{
|
|
// 0c71 0f50 lris $AC1.M, #0x50
|
|
// 0c72 0080 0a00 lri $AR0, #0x0a00
|
|
// 0c74 0083 0d60 lri $AR3, #0x0d60
|
|
// 0c76 0098 3fff lri $AX0.L, #0x3fff
|
|
// 0c78 02bf 00eb call 0x00eb
|
|
00eb_Unk_BufferMultAddToDest(0x0a00, 0x0d60, 0x50, 0x3fff)
|
|
|
|
// 0c7a 0f50 lris $AC1.M, #0x50
|
|
// 0c7b 0080 0a00 lri $AR0, #0x0a00
|
|
// 0c7d 0083 0d00 lri $AR3, #0x0d00
|
|
// 0c7f 0098 3fff lri $AX0.L, #0x3fff
|
|
// 0c81 02bf 00eb call 0x00eb
|
|
00eb_Unk_BufferMultAddToDest(0x0a00, 0x0d00, 0x50, 0x3fff)
|
|
|
|
// 0c83 02df ret
|
|
}
|
|
|
|
void 0c84_FilterBufferInPlace(_sampleAddr($AR0), multiplier($AX0.H))
|
|
{
|
|
// 0c84 8a00 m2
|
|
// 0c85 8f00 set40
|
|
// 0c86 8100 clr $ACC0
|
|
// 0c87 00de 0404 lr $AC0.M, @0x0404
|
|
// 0c89 b100 tst $ACC0
|
|
// 0c8a 0295 0c91 jz 0x0c91
|
|
if (*(0x0404)) {
|
|
// 0c8c 8100 clr $ACC0
|
|
// 0c8d 00fe 0478 sr @0x0478, $AC0.M
|
|
// 0c8f 00fe 0479 sr @0x0479, $AC0.M
|
|
*0x0478 = 0;
|
|
*0x0479 = 0;
|
|
}
|
|
// 0c91 00df 0479 lr $AC1.M, @0x0479
|
|
// 0c93 00db 0478 lr $AX1.H, @0x0478
|
|
// 0c95 0900 lris $AX1.L, #0x00
|
|
// 0c96 0084 0000 lri $IX0, #0x0000
|
|
// 0c98 1150 0ca1 bloopi #0x50, 0x0ca1
|
|
$AC1.M = *0x0479;
|
|
$AX1.H = *0x0478;
|
|
|
|
// ACC1 always contains the value from the previous iteration.
|
|
for (int i = 0; i < 0x50; i++) {
|
|
// 0c9a 199e lrrn $AC0.M, @$AR0
|
|
// 0c9b 5c7c sub'ln $ACC0, $ACC1 : $AC1.M, @$AR0
|
|
// 0c9c c000 mulc $AC0.M, $AX0.H // Where does AX0.H get set?
|
|
// 0c9d 6e00 movp $ACC0
|
|
// 0c9e 1488 asl $ACC0, #8
|
|
// 0c9f 4a00 addax $ACC0, $AX1
|
|
// 0ca0 1b1e srri @$AR0, $AC0.M
|
|
// 0ca1 1f7e mrr $AX1.H, $AC0.M
|
|
*$AC0.M = *$AR0;
|
|
$ACC0 -= $ACC1;
|
|
( $AC1.M = *AR0; )
|
|
$ACC0 = ($AC0.M * $AX0.H * 2 << 8) + ($AX1.L);
|
|
*($AR0++) = $AC0.M;
|
|
$AX1.H = $AC0.M;
|
|
|
|
// Write back
|
|
0ca2 00fb 0478 sr @0x0478, $AX1.H
|
|
0ca4 00ff 0479 sr @0x0479, $AC1.M
|
|
|
|
// 0ca6 8b00 m0
|
|
// 0ca7 8e00 set16
|
|
// 0ca8 02df ret
|
|
}
|
|
|
|
// Called from both volume handlers.
|
|
// ACC1 is volume, AX is volume delta.
|
|
void 0ca9_RampedMultiplyAddBuffer(Volume($ACC1), Delta($AX0), InBuffer($AR0), Buffer($AR3)) {
|
|
// 0ca9 b900 tst $ACC1
|
|
// 0caa 0294 0caf jnz 0x0caf
|
|
if (!ACC1) {
|
|
// 0cac 6800 movax $ACC0, $AX0.L
|
|
// 0cad b100 tst $ACC0
|
|
// 0cae 02d5 retz
|
|
if (!AX0.L)
|
|
// If incoming volume is zero and ramp delta is zero,
|
|
// not really much point to do anything.
|
|
return
|
|
}
|
|
0caf 1c23 mrr $AR1, $AR3
|
|
0cb0 197e lrri $AC0.M, @$AR3
|
|
|
|
// This is another heavily software pipelined loop, so it's very confusing.
|
|
// See the docs for mulc and mulcac if you want to have any hope of understanding it.
|
|
//
|
|
// Produce the first result, so it's ready in the prod register.
|
|
0cb1 191b lrri $AX1.H, @$AR0
|
|
0cb2 d858 mulc'l $AC1.M, $AX1.H : $AX1.H, @$AR0
|
|
|
|
// 0cb3 1120 0cb9 bloopi #0x20, 0x0cb9
|
|
for (int i = 0; i < 0x20; i++) {
|
|
0cb5 dcd3 mulcac'ld $AC1.M, $AX1.H, $ACC0 : $AX0.L, $AX1.H, @$AR3
|
|
0cb6 6231 movr's $ACC0, $AX1.L : @$AR1, $AC0.M
|
|
|
|
0cb7 dcd3 mulcac'ld $AC1.M, $AX1.H, $ACC0 : $AX0.L, $AX1.H, @$AR3
|
|
0cb8 6231 movr's $ACC0, $AX1.L : @$AR1, $AC0.M // Store 1
|
|
|
|
// Walk the ramp. Somewhat odd that it's done only every 2 samples.
|
|
0cb9 4900 addax $ACC1, $AX0
|
|
}
|
|
|
|
// 0cba 1108 0cbf bloopi #0x08, 0x0cbf
|
|
for (int i = 0; i < 0x8; i++) {
|
|
0cbc dcd3 mulcac'ld $AC1.M, $AX1.H, $ACC0 : $AX0.L, $AX1.H, @$AR3
|
|
0cbd 6231 movr's $ACC0, $AX1.L : @$AR1, $AC0.M
|
|
|
|
0cbe dcd3 mulcac'ld $AC1.M, $AX1.H, $ACC0 : $AX0.L, $AX1.H, @$AR3
|
|
0cbf 6231 movr's $ACC0, $AX1.L : @$AR1, $AC0.M
|
|
}
|
|
|
|
// NOTE - The above two loops are very similar and the sum of their lengths is
|
|
// 0x28 - which is half of 0x50. And each does two loads and two stores, so together
|
|
// it's 50. Just strange that the addax is missing in the second loop.
|
|
|
|
// It looks like we're dealing with crappy volume ramping - the delta is computed using
|
|
// (vol2 - vol1) >> 5! That's why it can only ramp the volume the first 64 (0x20 * 2) samples!
|
|
|
|
0cc0 02df ret
|
|
}
|
|
|
|
|
|
// What a strange filter .. ORR?
|
|
void 0cc1_StrangeORRFilter(_pBuffer(AR3))
|
|
{
|
|
0cc1 8f00 set40
|
|
0cc2 8d00 set15 // X multiplications unsigned
|
|
0cc3 1c03 mrr $AR0, $AR3
|
|
0cc4 00d9 038e lr $AX1.L, @0x038e
|
|
0cc6 0b04 lris $AX1.H, #0x04
|
|
|
|
// pipeline starts here.
|
|
0cc7 197a lrri $AX0.H, @$AR3
|
|
0cc8 b053 mulx'l $AX0.H, $AX1.L : $AX0.H, @$AR3
|
|
0cc9 b600 mulxmv $AX0.H, $AX1.L, $ACC0
|
|
0cca 1128 0ccf bloopi #0x28, 0x0ccf
|
|
0ccc 3ad3 orr'ld $AC0.M, $AX1.H : $AX0.L, $AX1.H, @$AR3
|
|
0ccd b630 mulxmv's $AX0.H, $AX1.L, $ACC0 : @$AR0, $AC0.M
|
|
0cce 3ad3 orr'ld $AC0.M, $AX1.H : $AX0.L, $AX1.H, @$AR3
|
|
0ccf b630 mulxmv's $AX0.H, $AX1.L, $ACC0 : @$AR0, $AC0.M
|
|
0cd0 8c00 clr15
|
|
0cd1 8e00 set16
|
|
|
|
// 0cd2 02df ret
|
|
}
|
|
|
|
|
|
// called from sync frame if (*0x042c != 0)
|
|
// That is, if volume mode != 0.
|
|
// It first seems to compute a lot of parameters and store them at 0x0b00 forwards.
|
|
// Then it uses those as input for the usual (ramped?) mixes.
|
|
void 0cd3_VolumeMixer1()
|
|
{
|
|
// 0cd3 00da 0485 lr $AX0.H, @0x0485
|
|
// 0cd5 8600 tstaxh $AX0.H
|
|
// 0cd6 0295 0ce5 jz 0x0ce5
|
|
if (*0x0485 != 0) {
|
|
// 0cd8 8100 clr $ACC0
|
|
// 0cd9 00de 042a lr $AC0.M, @0x042a
|
|
// 0cdb 147f lsr $ACC0, #-1
|
|
// 0cdc 00fe 042b sr @0x042b, $AC0.M
|
|
*(0x042b) = *(0x042a) >> 1;
|
|
|
|
// 0cde b100 tst $ACC0
|
|
// 0cdf 0294 0ce5 jnz 0x0ce5
|
|
if (*0x042b == 0) {
|
|
// 0ce1 009a 0001 lri $AX0.H, #0x0001
|
|
// 0ce3 00fa 0401 sr @0x0401, $AX0.H
|
|
*(0x0401) = 1; // KeyOff
|
|
}
|
|
}
|
|
|
|
// 0ce5 8f00 set40
|
|
// 0ce6 8100 clr $ACC0
|
|
// 0ce7 00de 0428 lr $AC0.M, @0x0428
|
|
// 0ce9 1478 lsr $ACC0, #-8
|
|
(ACC0 = *(0x0428) << 8);
|
|
|
|
// 0cea 00df 0428 lr $AC1.M, @0x0428
|
|
// 0cec 0340 007f andi $AC1.M, #0x007f
|
|
// 0cee 1f1e mrr $AX0.L, $AC0.M
|
|
// 0cef 1f5f mrr $AX0.H, $AC1.M
|
|
// 0cf0 0220 007f xori $ACC0, #0x007f
|
|
// 0cf2 1f3e mrr $AX1.L, $AC0.M
|
|
// 0cf3 0320 007f xori $ACC1, #0x007f
|
|
// 0cf5 1f7f mrr $AX1.H, $AC1.M
|
|
AX0.L = *(0x0428) >> 8;
|
|
AX0.H = *(0x0428) & 0x7F;
|
|
AX1.L = AX0.L ^ 0x7f;
|
|
AX1.H = AX1.H ^ 0x7f;
|
|
|
|
// 0cf6 8100 clr $ACC0
|
|
// 0cf7 8900 clr $ACC1
|
|
// 0cf8 009f 0200 lri $AC1.M, #0x0200
|
|
|
|
// 0cfa 1fd8 mrr $AC0.M, $AX0.L
|
|
// 0cfb 4c00 add $ACC0, $ACC1 # broken disasm? this doesn't make much sense.
|
|
// 0cfc 1c1e mrr $AR0, $AC0.M
|
|
// 0cfd 1818 lrr $AX0.L, @$AR0
|
|
AR0 = AX0.L + 0x0200;
|
|
AX0.L = *AR0;
|
|
|
|
// 0cfe 1fda mrr $AC0.M, $AX0.H
|
|
// 0cff 4c00 add $ACC0, $ACC1
|
|
// 0d00 1c1e mrr $AR0, $AC0.M
|
|
// 0d01 181a lrr $AX0.H, @$AR0
|
|
AR0 = AX0.H + 0x200;
|
|
AX0.H = *AR0;
|
|
|
|
// 0d02 1fd9 mrr $AC0.M, $AX1.L
|
|
// 0d03 4c00 add $ACC0, $ACC1
|
|
// 0d04 1c1e mrr $AR0, $AC0.M
|
|
// 0d05 1819 lrr $AX1.L, @$AR0
|
|
AR0 = AX1.L + 0x200;
|
|
AX1.L = *AR0
|
|
|
|
// 0d06 1fdb mrr $AC0.M, $AX1.H
|
|
// 0d07 4c00 add $ACC0, $ACC1
|
|
// 0d08 1c1e mrr $AR0, $AC0.M
|
|
// 0d09 181b lrr $AX1.H, @$AR0
|
|
AR0 = AX1.H + 0x200;
|
|
AX1.H = *AR0;
|
|
|
|
// 0d0a 0080 0b00 lri $AR0, #0x0b00
|
|
// 0d0c 9800 mul $AX1.L, $AX1.H
|
|
// 0d0d ae00 mulxmv $AX0.L, $AX1.H, $ACC0
|
|
// 0d0e b630 mulxmv's $AX0.H, $AX1.L, $ACC0 : @$AR0, $AC0.M
|
|
// 0d0f 9630 mulmv's $AX0.L, $AX0.H, $ACC0 : @$AR0, $AC0.M
|
|
// 0d10 6e30 movp's $ACC0 : @$AR0, $AC0.M
|
|
// 0d11 1b1e srri @$AR0, $AC0.M
|
|
|
|
// The above is heavily "sw-pipelined" but I think it turns into:
|
|
$AR0 = 0x0b00;
|
|
*$AR0++ = AX1.L * AX1.H;
|
|
*$AR0++ = AX0.L * AX1.H;
|
|
*$AR0++ = AX0.H * AX1.L;
|
|
*$AR0++ = AX0.L * AX0.H;
|
|
|
|
// 0d12 0080 0b00 lri $AR0, #0x0b00
|
|
// 0d14 0081 0b04 lri $AR1, #0x0b04
|
|
// 0d16 00da 042a lr $AX0.H, @0x042a
|
|
// 0d18 02bf 0d62 call 0x0d62 // some tricky multiplication
|
|
0d62_Mul4ByAX0H(0x0b00, 0x0b04, *(0x042a));
|
|
|
|
// 0d1a 0081 0b08 lri $AR1, #0x0b08
|
|
// 0d1c 0080 0b04 lri $AR0, #0x0b04
|
|
// 0d1e 00da 042a lr $AX0.H, @0x042a // interesting
|
|
// 0d20 00de 0429 lr $AC0.M, @0x0429 // interesting
|
|
// 0d22 c000 mulc $AC0.M, $AX0.H
|
|
// 0d23 6e00 movp $ACC0
|
|
// 0d24 1481 asl $ACC0, #1
|
|
// 0d25 1f5e mrr $AX0.H, $AC0.M
|
|
|
|
0d62_Mul4ByAX0H(0x0b00, 0x0b04, (*(0x042a) * *(0x0429) << 1) >> 16);
|
|
// 0d26 02bf 0d62 call 0x0d62 // some tricky multiplication
|
|
|
|
// 0d28 0080 0b00 lri $AR0, #0x0b00
|
|
// 0d2a 0081 0b0c lri $AR1, #0x0b0c
|
|
// 0d2c 8100 clr $ACC0
|
|
// 0d2d 8900 clr $ACC1
|
|
// 0d2e 00de 042b lr $AC0.M, @0x042b // interesting
|
|
// 0d30 00df 042a lr $AC1.M, @0x042a // interesting
|
|
// 0d32 00fe 042a sr @0x042a, $AC0.M
|
|
*(0x042a) = *(0x042b);
|
|
|
|
// 0d34 5c00 sub $ACC0, $ACC1
|
|
// 0d35 1f5e mrr $AX0.H, $AC0.M
|
|
// 0d36 02bf 0d6b call 0x0d6b // some other tricky multiplication
|
|
0d6b_Mul4ByAC0M_Unsigned(0xb00, 0x0b0c, $AC0.M(*(0x042a) - *(0x042b))) // does not touch AX0.H
|
|
|
|
// 0d38 0080 0b0c lri $AR0, #0x0b0c
|
|
// 0d3a 0081 0b10 lri $AR1, #0x0b10
|
|
// 0d3c 00da 0429 lr $AX0.H, @0x0429 // interesting
|
|
0d3e 02bf 0d62 call 0x0d62 // some tricky multiplication
|
|
0d62_Mul4ByAX0H(0x0b0c, 0x0b10, *(0x0429));
|
|
|
|
// 0d40 0081 0b04 lri $AR1, #0x0b04
|
|
// 0d42 0082 0b0c lri $AR2, #0x0b0c
|
|
// 0d44 0083 0d77 lri $AR3, #0x0d77
|
|
|
|
// So basically the below loop is:
|
|
// For i in 0 to 8:
|
|
// Call 0ca9_RampedMultiplyAddBuffer($AR0 = *0x038f, $AR3=0x0d77[i], AX0=0xb0c[i]<<11, AC1.M=0x0b04[i])
|
|
|
|
// 0d46 1108 0d5f bloopi #0x08, 0x0d5f
|
|
for (int i = 0; i < 8; i++) {
|
|
// 0d48 195f lrri $AC1.M, @$AR2
|
|
// 0d49 15fb asr $ACC1, #-5
|
|
// 0d4a 1f1d mrr $AX0.L, $AC1.L
|
|
// 0d4b 1f5f mrr $AX0.H, $AC1.M
|
|
// Compute volume delta
|
|
AX0 = *AR2++ << 11;
|
|
|
|
// 0d4c 193f lrri $AC1.M, @$AR1
|
|
AC1.M = *AR1++;
|
|
|
|
// 0d4d 00e1 0b24 sr @0x0b24, $AR1
|
|
// 0d4f 00e2 0b25 sr @0x0b25, $AR2
|
|
// 0d51 021b ilrri $AC0.M, @$AR3 // Buffer address table lookup (see below)
|
|
// 0d52 00e3 0b26 sr @0x0b26, $AR3
|
|
(Stash AR1, AR2, AR3)
|
|
// 0d54 1c7e mrr $AR3, $AC0.M
|
|
// 0d55 00c0 038f lr $AR0, @0x038f
|
|
// 0d57 02bf 0ca9 call 0x0ca9
|
|
0ca9_RampedMultiplyAddBuffer(Volume($ACC1), Delta($AX0), InBuffer($AR0), Buffer($AR3))
|
|
|
|
// 0d59 00c1 0b24 lr $AR1, @0x0b24
|
|
// 0d5b 00c2 0b25 lr $AR2, @0x0b25
|
|
// 0d5d 00c3 0b26 lr $AR3, @0x0b26
|
|
(Restore AR1, AR2, AR3)
|
|
0d5f 0000 nop
|
|
}
|
|
|
|
// 0d60 8e00 set16
|
|
// 0d61 02df ret
|
|
}
|
|
|
|
void 0d62_Mul4ByAX0H(in_buffer($AR0), out_buffer($AR1), multiplicand($AX0.H)) {
|
|
// 0d62 191f lrri $AC1.M, @$AR0
|
|
// 0d63 d078 mulc'l $AC1.M, $AX0.H : $AC1.M, @$AR0
|
|
// 0d64 d678 mulcmv'l $AC1.M, $AX0.H, $ACC0 : $AC1.M, @$AR0
|
|
// 0d65 d631 mulcmv's $AC1.M, $AX0.H, $ACC0 : @$AR1, $AC0.M
|
|
// 0d66 191f lrri $AC1.M, @$AR0
|
|
// 0d67 d631 mulcmv's $AC1.M, $AX0.H, $ACC0 : @$AR1, $AC0.M
|
|
// 0d68 6e31 movp's $ACC0 : @$AR1, $AC0.M
|
|
// 0d69 1b3e srri @$AR1, $AC0.M
|
|
// 0d6a 02df ret
|
|
// The above is a crazy sw-pipelined way to write:
|
|
for (int i = 0; i < 4; i++) {
|
|
out_buffer[i] = (s16)in_buffer[i] * (s16)multiplicand >> 16;
|
|
}
|
|
}
|
|
|
|
void 0d6b_Mul4ByAC0M_Unsigned(in_buffer($AR0), out_buffer($AR1), multiplicand($AX1.H)) {
|
|
// 0d6b 8d00 set15
|
|
// 0d6c 1f7e mrr $AX1.H, $AC0.M
|
|
// 0d6d 1918 lrri $AX0.L, @$AR0
|
|
// 0d6e a840 mulx'l $AX0.L, $AX1.H : $AX0.L, @$AR0
|
|
// 0d6f ae40 mulxmv'l $AX0.L, $AX1.H, $ACC0 : $AX0.L, @$AR0
|
|
// 0d70 ae31 mulxmv's $AX0.L, $AX1.H, $ACC0 : @$AR1, $AC0.M
|
|
// 0d71 1918 lrri $AX0.L, @$AR0
|
|
// 0d72 ae31 mulxmv's $AX0.L, $AX1.H, $ACC0 : @$AR1, $AC0.M
|
|
// 0d73 6e31 movp's $ACC0 : @$AR1, $AC0.M
|
|
// 0d74 1b3e srri @$AR1, $AC0.M
|
|
// 0d75 8c00 clr15
|
|
// 0d76 02df ret
|
|
// The above is a crazy sw-pipelined way to write:
|
|
for (int i = 0; i < 4; i++) {
|
|
out_buffer[i] = in_buffer[i] * multiplicand >> 16; //(unsigned multiplication)
|
|
}
|
|
}
|
|
|
|
// table for 0cd3_Unk
|
|
// This is a bunch of buffer addresses!
|
|
short table = {0x0d00, 0x0d60, 0x0f40, 0x0ca0, 0x0e80, 0x0ee0, 0x0c00, 0x0c50};
|
|
|
|
0d77 0d00
|
|
0d78 0d60
|
|
0d79 0f40
|
|
0d7a 0ca0
|
|
0d7b 0e80
|
|
0d7c 0ee0
|
|
0d7d 0c00
|
|
0d7e 0c50
|
|
|
|
void 0d7f_ResampleAudioData(_src($AR0), _dest($AR1), param(AX1.L) = 0, _option??)
|
|
{
|
|
0d7f 00f9 0361 sr @0x0361, $AX1.L // always 0
|
|
|
|
// 0d81 1fc0 mrr $AC0.M, $AR0
|
|
// 0d82 0200 fffc addi $AC0.M, #0xfffc
|
|
// 0d84 1c1e mrr $AR0, $AC0.M
|
|
// 0d85 1c5e mrr $AR2, $AC0.M
|
|
|
|
// We read a little bit BEFORE the input. The next piece of code takes care of that...
|
|
$AR0 = $AR0 - 4;
|
|
$AR2 = $AR0;
|
|
|
|
// 0x043c to 0x043f is storage for old sample data.
|
|
0d86 0083 043c lri $AR3, #0x043c
|
|
|
|
// Pipelined tiny memcpy - first four are loads, last four are stores. middle two overlap.
|
|
// 0d88 197e lrri $AC0.M, @$AR3
|
|
// 0d89 197f lrri $AC1.M, @$AR3
|
|
// 0d8a 80a2 nx'sl : $AC0.M, $AX0.H
|
|
// 0d8b 64a3 movr'sl $ACC0, $AX0.H : $AC1.M, $AX0.H
|
|
// 0d8c 6530 movr's $ACC1, $AX0.H : @$AR0, $AC0.M
|
|
// 0d8d 1b1f srri @$AR0, $AC1.M
|
|
for (int i = 0; i < 4; i++)
|
|
*($AR0++) = *($AR3++);
|
|
|
|
// Point $AR0 back at 4 words before the start of the in buffer.
|
|
// 0d8e 1c02 mrr $AR0, $AR2
|
|
|
|
0d8f 8100 clr $ACC0
|
|
// 0d90 00de 0402 lr $AC0.M, @0x0402 // Ratio int
|
|
// 0d92 00fe 0362 sr @0x0362, $AC0.M
|
|
// 0d94 1474 lsr $ACC0, #-12
|
|
// 0d95 1f7e mrr $AX1.H, $AC0.M
|
|
// 0d96 1f3c mrr $AX1.L, $AC0.L
|
|
*0x0362 = PB.Ratio;
|
|
$AX1 = PB.Ratio << 4;
|
|
|
|
0d97 8900 clr $ACC1
|
|
0d98 00dd 0430 lr $AC1.L, @0x0430 // Sample position frac
|
|
0d9a 1504 lsl $ACC1, #4
|
|
|
|
// $ACC0 here still contains ratio << 12;
|
|
0d9b 0604 cmpis $ACC0, #0x04
|
|
// 0d9c 0290 0df3 jge 0x0df3 // subroutine
|
|
|
|
// If ratio too low, don't bother resampling?
|
|
GOTONS JustCopyWithoutResampling;
|
|
|
|
0d9e 1fdd mrr $AC0.M, $AC1.L
|
|
0d9f 0082 02b0 lri $AR2, #0x02b0
|
|
|
|
// Store a ramp at 0x2b0? Lookup table for read addresses?
|
|
0da1 1050 loopi #0x50
|
|
0da2 4b2a addax's $ACC1, $AX1 : @$AR2, $AC1.L
|
|
|
|
0da3 1fbe mrr $AC1.L, $AC0.M
|
|
0da4 00fe 0360 sr @0x0360, $AC0.M
|
|
0da6 8900 clr $ACC1
|
|
0da7 1fbe mrr $AC1.L, $AC0.M
|
|
|
|
0da8 0af8 lris $AX0.H, #0xf8
|
|
0da9 009b 00fc lri $AX1.H, #0x00fc
|
|
0dab 00d8 0361 lr $AX0.L, @0x0361 // parameter was stashed here.
|
|
|
|
// 0x02b0 is where the ramp from above is stored.
|
|
0dad 0082 02b0 lri $AR2, #0x02b0
|
|
0daf 0083 02b0 lri $AR3, #0x02b0
|
|
0db1 195e lrri $AC0.M, @$AR2
|
|
|
|
// I really don't understand what the purpose of this loop is.
|
|
0db2 3480 andr'ls $AC0.M, $AX0.H : $AX0.L, $AC0.M
|
|
// 0db3 1128 0db8 bloopi #0x28, 0x0db8
|
|
for (int i = 0; i < 0x50; i += 2) {
|
|
0db5 367a andr'l $AC0.M, $AX1.H : $AC1.M, @$AR2
|
|
0db6 35b3 andr'sl $AC1.M, $AX0.H : $AC1.M, $AX1.H
|
|
0db7 3772 andr'l $AC1.M, $AX1.H : $AC0.M, @$AR2
|
|
0db8 34bb andr'slm $AC0.M, $AX0.H : $AC1.M, $AX1.H
|
|
}
|
|
|
|
0db9 8a00 m2 // All muls doubled.
|
|
|
|
// 0x02b0 is where the ramp from above is stored.
|
|
0dba 0082 02b0 lri $AR2, #0x02b0
|
|
|
|
0dbc 00dd 0430 lr $AC1.L, @0x0430
|
|
0dbe 1504 lsl $ACC1, #4
|
|
0dbf 1fe0 mrr $AC1.M, $AR0
|
|
0dc0 8100 clr $ACC0
|
|
0dc1 00de 0362 lr $AC0.M, @0x0362
|
|
0dc3 1474 lsr $ACC0, #-12
|
|
0dc4 1f7e mrr $AX1.H, $AC0.M
|
|
0dc5 1f3c mrr $AX1.L, $AC0.L
|
|
|
|
// Resample with some nice filter of some sort, using unreadable
|
|
// pipelined DSP code... gah.
|
|
|
|
0dc6 8f00 set40 // Loaded ACx.M values extend to the entire ACC. Don't see any actual use though.
|
|
|
|
// Yep, this pretty much confirms that 0x02b0 is precomputed read addresses.
|
|
0dc7 1943 lrri $AR3, @$AR2
|
|
0dc8 4bc3 addax'ld $ACC1, $AX1 : $AX0.L, $AX1.L, @$AR3
|
|
0dc9 90c3 mul'ld $AX0.L, $AX0.H : $AX0.L, $AX1.L, @$AR3
|
|
0dca f2c3 madd'ld $AX0.L, $AX0.H : $AX0.L, $AX1.L, @$AR3
|
|
0dcb f2c3 madd'ld $AX0.L, $AX0.H : $AX0.L, $AX1.L, @$AR3
|
|
0dcc f200 madd $AX0.L, $AX0.H
|
|
0dcd fe00 movpz $ACC0
|
|
0dce 1c1f mrr $AR0, $AC1.M
|
|
0dcf 1943 lrri $AR3, @$AR2
|
|
0dd0 4bc3 addax'ld $ACC1, $AX1 : $AX0.L, $AX1.L, @$AR3
|
|
0dd1 90c3 mul'ld $AX0.L, $AX0.H : $AX0.L, $AX1.L, @$AR3
|
|
// 0dd2 114e 0dda bloopi #0x4e, 0x0dda
|
|
// Count the stores - 0x4e stores in the main loop, two more afterwards.
|
|
// Deeply pipelined.
|
|
for (int i = 0; i < 0x4e; i++) {
|
|
0dd4 f2c3 madd'ld $AX0.L, $AX0.H : $AX0.L, $AX1.L, @$AR3
|
|
0dd5 f2c3 madd'ld $AX0.L, $AX0.H : $AX0.L, $AX1.L, @$AR3
|
|
0dd6 f231 madd's $AX0.L, $AX0.H : @$AR1, $AC0.M
|
|
0dd7 1c1f mrr $AR0, $AC1.M
|
|
0dd8 1943 lrri $AR3, @$AR2
|
|
0dd9 4bc3 addax'ld $ACC1, $AX1 : $AX0.L, $AX1.L, @$AR3
|
|
0dda 92c3 mulmvz'ld $AX0.L, $AX0.H, $ACC0 : $AX0.L, $AX1.L, @$AR3
|
|
}
|
|
0ddb f2c3 madd'ld $AX0.L, $AX0.H : $AX0.L, $AX1.L, @$AR3
|
|
0ddc f2c3 madd'ld $AX0.L, $AX0.H : $AX0.L, $AX1.L, @$AR3
|
|
0ddd f231 madd's $AX0.L, $AX0.H : @$AR1, $AC0.M
|
|
0dde fe00 movpz $ACC0
|
|
0ddf 1b3e srri @$AR1, $AC0.M
|
|
|
|
// Things back to normal.
|
|
// 0de0 8b00 m0
|
|
// 0de1 8e00 set16
|
|
|
|
back_from_JustCopyWithoutResampling:
|
|
0de2 00fe 0433 sr @0x0433, $AC0.M
|
|
0de4 1c1f mrr $AR0, $AC1.M
|
|
0de5 150c lsl $ACC1, #12
|
|
0de6 0340 0fff andi $AC1.M, #0x0fff
|
|
0de8 00ff 0430 sr @0x0430, $AC1.M
|
|
|
|
// Store the last 4 samples or something undecoded
|
|
// back into the PB.
|
|
0dea 0083 043c lri $AR3, #0x043c
|
|
0dec 191e lrri $AC0.M, @$AR0
|
|
0ded 191f lrri $AC1.M, @$AR0
|
|
0dee 80a0 nx'ls : $AX0.H, $AC0.M
|
|
0def 64a1 movr'ls $AC0.M, $AX0.H : $AX0.H, $AC1.M
|
|
0df0 6533 movr's $AC1.M, $AX0.H : @$AR3, $AC0.M
|
|
0df1 1b7f srri @$AR3, $AC1.M
|
|
// 0df2 02df ret
|
|
return;
|
|
|
|
JustCopyWithoutResampling:
|
|
// 0df3 1fe0 mrr $AC1.M, $AR0
|
|
// 0df4 1c1f mrr $AR0, $AC1.M // This instruction looks very pointless.
|
|
|
|
// 0df5 1128 0dfc bloopi #0x28, 0x0dfc
|
|
// 0df7 4b70 addax'l $ACC1, $AX1 : $AC0.M, @$AR0
|
|
// 0df8 1b3e srri @$AR1, $AC0.M
|
|
// 0df9 1c1f mrr $AR0, $AC1.M
|
|
// 0dfa 4b70 addax'l $ACC1, $AX1 : $AC0.M, @$AR0
|
|
// 0dfb 1b3e srri @$AR1, $AC0.M
|
|
// 0dfc 1c1f mrr $AR0, $AC1.M
|
|
for (int i = 0; i < 0x50; i++) {
|
|
$ACC1 += $AX1; // This is to still advance the playback position.
|
|
$AC0.M = *($AR0++);
|
|
*($AR1++) = $AC0.M;
|
|
$AR0 = $AC1.M; // Undo the increment
|
|
}
|
|
|
|
// Looks like $AR0 stays unchanged, while $AR1 gets incremented by 0x50.
|
|
0dfd 029f 0de2 jmp 0x0de2
|
|
}
|
|
|
|
|
|
// Small utility jumped to from SyncFrame.
|
|
// sets 50 shorts from 0x520 to zero.
|
|
void 0dff_Zero520_50() {
|
|
0dff 0083 0520 lri $AR3, #0x0520
|
|
0e01 00de 0433 lr $AC0.M, @0x0433
|
|
0e03 1050 loopi #0x50
|
|
0e04 1b7e srri @$AR3, $AC0.M
|
|
// 0e05 029f 02d8 jmp 0x02d8
|
|
GOTO ContinueWithBlock: // in SyncFrame
|
|
}
|
|
|
|
// No-one calls this routine.
|
|
void 0e07_UnUsed() {
|
|
0e07 1c20 mrr $AR1, $AR0
|
|
0e08 185f lrr $AC1.M, @$AR2
|
|
0e09 1f7f mrr $AX1.H, $AC1.M
|
|
0e0a 193a lrri $AX0.H, @$AR1
|
|
0e0b 6400 movr $ACC0, $AX0.H
|
|
0e0c 0078 0e11 bloop $AX0.L, 0x0e11
|
|
0e0e 5659 subr'l $ACC0, $AX1.H : $AX1.H, @$AR1
|
|
0e0f 6730 movr's $ACC1, $AX1.H : @$AR0, $AC0.M
|
|
0e10 5551 subr'l $ACC1, $AX0.H : $AX0.H, @$AR1
|
|
0e11 6438 movr's $ACC0, $AX0.H : @$AR0, $AC1.M
|
|
0e12 1a5b srr @$AR2, $AX1.H
|
|
// 0e13 02df ret
|
|
}
|
|
|
|
void 0e14_DolbyInit()
|
|
{
|
|
// Init parameters/coefficients for UnknownFilter
|
|
0e14 0098 8240 lri $AX0.L, #0x8240
|
|
0e16 00f8 04e8 sr @0x04e8, $AX0.L
|
|
0e18 0098 7fff lri $AX0.L, #0x7fff
|
|
0e1a 00f8 04e9 sr @0x04e9, $AX0.L
|
|
0e1c 0098 7dbf lri $AX0.L, #0x7dbf
|
|
0e1e 00f8 04ea sr @0x04ea, $AX0.L
|
|
0e20 0098 843f lri $AX0.L, #0x843f
|
|
0e22 00f8 04eb sr @0x04eb, $AX0.L
|
|
0e24 0098 b23b lri $AX0.L, #0xb23b
|
|
0e26 00f8 04f0 sr @0x04f0, $AX0.L
|
|
0e28 0098 7fff lri $AX0.L, #0x7fff
|
|
0e2a 00f8 04f1 sr @0x04f1, $AX0.L
|
|
0e2c 0098 4dc4 lri $AX0.L, #0x4dc4
|
|
0e2e 00f8 04f2 sr @0x04f2, $AX0.L
|
|
0e30 0098 d808 lri $AX0.L, #0xd808
|
|
0e32 00f8 04f3 sr @0x04f3, $AX0.L
|
|
|
|
// Zero the UnknownFilter states.
|
|
0e34 0098 0000 lri $AX0.L, #0x0000
|
|
0e36 0080 04ec lri $AR0, #0x04ec
|
|
0e38 1004 loopi #0x04
|
|
0e39 1b18 srri @$AR0, $AX0.L
|
|
0e3a 0080 04f4 lri $AR0, #0x04f4
|
|
0e3c 1004 loopi #0x04
|
|
0e3d 1b18 srri @$AR0, $AX0.L
|
|
// 0e3e 02df ret
|
|
}
|
|
|
|
// I'm going to guess that this is Dolby mixing.
|
|
void 0e3f_DolbyMixdown()
|
|
{
|
|
0e3f 0080 0f40 lri $AR0, #0x0f40
|
|
0e41 0083 0b00 lri $AR3, #0x0b00
|
|
0e43 8900 clr $ACC1
|
|
0e44 0f50 lris $AC1.M, #0x50
|
|
0e45 0098 6784 lri $AX0.L, #0x6784
|
|
//0e47 02bf 00fa call 0x00fa // XorBuffer
|
|
00fa_BufferMultiply(src($AR0), dst($AR3), count($AC1.M), $mult($AX0.L))
|
|
|
|
0e49 0080 04e8 lri $AR0, #0x04e8
|
|
0e4b 0082 04ec lri $AR2, #0x04ec
|
|
0e4d 0081 0b00 lri $AR1, #0x0b00
|
|
0e4f 02bf 0ba4 call 0x0ba4 // 0ba4_UnknownFilter
|
|
0ba4_UnknownFilter(params($AR0), buffer($AR1), filter_state($AR2))
|
|
|
|
0e51 8900 clr $ACC1
|
|
0e52 0f50 lris $AC1.M, #0x50
|
|
0e53 0080 0b00 lri $AR0, #0x0b00
|
|
0e55 0083 0d00 lri $AR3, #0x0d00
|
|
0e57 0098 7fff lri $AX0.L, #0x7fff
|
|
// 0e59 02bf 00eb call 0x00eb
|
|
00eb_Unk_BufferMultAddToDest(_Src=($AR0), _Dest($AR3), _size($AC1.M), _factor($AX0.L))
|
|
|
|
0e5b 8900 clr $ACC1
|
|
0e5c 0f50 lris $AC1.M, #0x50
|
|
0e5d 0080 0b00 lri $AR0, #0x0b00
|
|
0e5f 0083 0d60 lri $AR3, #0x0d60
|
|
0e61 0098 b820 lri $AX0.L, #0xb820
|
|
// 0e63 02bf 00eb call 0x00eb
|
|
00eb_Unk_BufferMultAddToDest(_Src=($AR0), _Dest($AR3), _size($AC1.M), _factor($AX0.L))
|
|
|
|
0e65 0080 0ca0 lri $AR0, #0x0ca0
|
|
0e67 0083 0b00 lri $AR3, #0x0b00
|
|
0e69 8900 clr $ACC1
|
|
0e6a 0f50 lris $AC1.M, #0x50
|
|
0e6b 0098 6784 lri $AX0.L, #0x6784
|
|
// 0e6d 02bf 00fa call 0x00fa // XorBuffer
|
|
00fa_BufferMultiply(src($AR0), dst($AR3), count($AC1.M), $mult($AX0.L))
|
|
|
|
0e6f 0080 04e8 lri $AR0, #0x04e8
|
|
0e71 0082 04f4 lri $AR2, #0x04f4
|
|
0e73 0081 0b00 lri $AR1, #0x0b00
|
|
// 0e75 02bf 0ba4 call 0x0ba4 // 0ba4_UnknownFilter
|
|
0ba4_UnknownFilter(params($AR0), buffer($AR1), filter_state($AR2))
|
|
|
|
0e77 8900 clr $ACC1
|
|
0e78 0f50 lris $AC1.M, #0x50
|
|
0e79 0080 0b00 lri $AR0, #0x0b00
|
|
0e7b 0083 0d00 lri $AR3, #0x0d00
|
|
0e7d 0098 47e0 lri $AX0.L, #0x47e0
|
|
// 0e7f 02bf 00eb call 0x00eb
|
|
00eb_Unk_BufferMultAddToDest(_Src=($AR0), _Dest($AR3), _size($AC1.M), _factor($AX0.L))
|
|
|
|
0e81 8900 clr $ACC1
|
|
0e82 0f50 lris $AC1.M, #0x50
|
|
0e83 0080 0b00 lri $AR0, #0x0b00
|
|
0e85 0083 0d60 lri $AR3, #0x0d60
|
|
0e87 0098 8001 lri $AX0.L, #0x8001
|
|
// 0e89 02bf 00eb call 0x00eb
|
|
00eb_Unk_BufferMultAddToDest(_Src=($AR0), _Dest($AR3), _size($AC1.M), _factor($AX0.L))
|
|
|
|
// 0e8b 02df ret
|
|
}
|
|
|
|
|
|
void Nops() {
|
|
0e8c 0000 nop
|
|
0e8d 0000 nop
|
|
0e8e 0000 nop
|
|
0e8f 0000 nop
|
|
}
|