From 4459f5b8c6c50147e8ee8ecc762217fe3a76bcfc Mon Sep 17 00:00:00 2001 From: hrydgard Date: Fri, 10 Jul 2009 19:25:11 +0000 Subject: [PATCH] DSPLLE: attempt at RE of parts of the zelda volume code ... git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@3733 8ced0084-cf51-0410-be5f-012b33b47a6e --- docs/DSP/DSP_UC_Zelda.txt | 605 +++++++++++++++++++++++--------------- 1 file changed, 361 insertions(+), 244 deletions(-) diff --git a/docs/DSP/DSP_UC_Zelda.txt b/docs/DSP/DSP_UC_Zelda.txt index 74b10bb717..9ef507c751 100644 --- a/docs/DSP/DSP_UC_Zelda.txt +++ b/docs/DSP/DSP_UC_Zelda.txt @@ -1122,9 +1122,9 @@ void 0243_COMMAND_02() // sync frame if ((*0x0484 & 0x1f) != 0x00) { // 02ed 00de 038f lr $AC0.M, @0x038f - // 02ef 5c00 sub $ACC0, $AC1.L + // 02ef 5c00 sub $ACC0, $ACC1 // 02f0 00fe 038f sr @0x038f, $AC0.M - (*0x038f) -= AC1.L; // where did AC1.L get its value? should be 0, unless sub is wrong? + (*0x038f) -= AC1.M; // 02f2 1c7e mrr $AR3, $AC0.M // 02f3 0080 0440 lri $AR0, #0x0440 @@ -1187,39 +1187,61 @@ void 0243_COMMAND_02() // sync frame } } + // 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) + + if (*0x042c != 0) // Volume mode != 0 { // 0339 02bf 0cd3 call 0x0cd3 // 033b 029f 03b2 jmp 0x03b2 - 0cd3_Unk() + 0cd3_VolumeMixer1() // The complex one, probably with surround and stuff } else { - 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 + // Volume mode == 0 - simple 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) + if (*0x0407 != 0) // Unknown, in zelda always 0x10, apparently. { - 0348 00c3 038f lr $AR3, @0x038f - 034a 0007 dar $AR3 - 034b 0080 0477 lri $AR0, #0x0477 - 034d 0084 ffff lri $IX0, #0xffff - 034f 0087 ffff lri $IX3, #0xffff - 0351 199a lrrn $AX0.H, @$AR0 - 0352 6554 movr'ln $ACC1, $AX0.H : $AX0.H, @$AR0 - 0353 005e loop $AC0.M - 0354 65ad movr'lsnm $ACC1, $AX0.H : $AX0.H, $AC1.M + // Seems like this all boils down to a backwards copy of + // 0x0470-0x0477 to *(*(0x038f)); + + // 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 @@ -1228,66 +1250,112 @@ void 0243_COMMAND_02() // sync frame if (*0x0485 != 0) { 035a 8900 clr $ACC1 - 035b 0086 0005 lri $IX2, #0x0005 // Why? + 035b 0086 0005 lri $IX2, #0x0005 // 5 - 1 = 4, see loop 035d 0082 040a lri $AR2, #0x040a - 035f 1106 0363 bloopi #0x06, 0x0363 - // Sum up 0x040a->0x040f, at the same time store the sums back? don't get it? + // 035f 1106 0363 bloopi #0x06, 0x0363 + + // Store half of every 4th value from 0x040a onwards in the position before. (!!!!) + // 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, $AC0.L : @$AR2, $AC0.M + // 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 + // 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 + // 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 - + // 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. + // BUT not quite - looks like it can vary and some of these words + // can be dropped... damnit. + // 0370 1106 039b bloopi #0x06, 0x039b - for (int i=0; i<6; i++) + for (int i = 0; i < 6; i++) { - 0372 8100 clr $ACC0 - 0373 195e lrri $AC0.M, @$AR2 - 0374 1200 sbclr #0x00 - 0375 b100 tst $ACC0 - 0376 0275 ifz - 0377 1300 sbset #0x00 + // 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 + + 0379 195e lrri $AC0.M, @$AR2 // Load the two volume values 037a 195f lrri $AC1.M, @$AR2 - 037b 5c00 sub $ACC0, $AC1.L - 037c 14fb asr $ACC0, #-5 - 037d 1f5e mrr $AX0.H, $AC0.M - 037e 1f1c mrr $AX0.L, $AC0.L - 037f 185e lrr $AC0.M, @$AR2 - 0380 0240 00ff andi $AC0.M, #0x00ff - 0382 1f7e mrr $AX1.H, $AC0.M - 0383 185e lrr $AC0.M, @$AR2 - 0384 1478 lsr $ACC0, #-8 - 0385 009c 0000 lri $AC0.L, #0x0000 + + // 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 .. + + // 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; + + // Seems like we might be dealing with variable + // length data here... $AR2 is never restored + // after the zany if thing below. 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 ifs - 038e 7800 decm $AC0.M - 038f 1a5e srr @$AR2, $AC0.M + 038a 185e lrr $AC0.M, @$AR2 + 038b 0272 ifg + 038c 7400 incm $AC0.M + 038d 0271 ifs + 038e 7800 decm $AC0.M + 038f 1a5e srr @$AR2, $AC0.M 0390 0006 dar $AR2 + + // Here's this 0x038f again.. what is it? 0391 00de 038f lr $AC0.M, @0x038f 0393 5600 subr $ACC0, $AX1.H - 0394 029d 0399 jlz 0x0399 - 0396 1c1e mrr $AR0, $AC0.M - 0397 02bf 0ca9 call 0x0ca9 + + // 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 + 0x0ca9_RampedMultiplyBuffer(...) + } 0399 0000 nop - 039a 1b5f srri @$AR2, $AC1.M - 039b 000a iar $AR2 + // 039a 1b5f srri @$AR2, $AC1.M + *$AR2++ = $AC1.M; + // 039b 000a iar $AR2 + $AR2++; // Next block of four volumes. } # 039c 8e00 set16 @@ -1365,7 +1433,6 @@ void 0243_COMMAND_02() // sync frame // 03df 02bf 00eb call 0x00eb 00eb_Unk_BufferMultWithDest(0x09a0, 0x0d00, 0x50, 0x5a82) - // 03e1 0080 09a0 lri $AR0, #0x09a0 // 03e3 0083 0d60 lri $AR3, #0x0d60 // 03e5 0f50 lris $AC1.M, #0x50 @@ -1568,7 +1635,7 @@ void 04d0_Unk() { // 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, $AC1.L + 04d6 4c00 add $ACC0, $ACC1 04d7 1c1e mrr $AR0, $AC0.M 04d8 181e lrr $AC0.M, @$AR0 @@ -1642,7 +1709,7 @@ void 04f3_strange() { 0514 00fe 0b4b sr @0x0b4b, $AC0.M 0516 009e 0b00 lri $AC0.M, #0x0b00 - 0518 4c00 add $ACC0, $AC1.L // The value is in AC1.M, this must be wrong disasm + 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] @@ -1795,7 +1862,7 @@ void 0573_Mystery_Write(InBuffer($AR1), SourceBuffer(AC1.M), _COUNT(AX0.H)) { void 0580_COMMAND_04() - { +{ // commando looks buggy... // it copies data to the switch casement data address... sounds like BS @@ -1832,7 +1899,7 @@ void 0592_COMMAND_05() void 05A4_ResetAccelerator() - { +{ 05a4 0092 00ff lri $CR, #0x00ff 05a6 009e ffff lri $AC0.M, #0xffff 05a8 2ed4 srs @ACSAH, $AC0.M @@ -1956,7 +2023,7 @@ EndOfMailException: } void 05f0_HaltUCode() - { +{ 05f0 009a 0002 lri $AX0.H, #0x0002 05f2 00fa 03a3 sr @0x03a3, $AX0.H 05f4 00e0 03f9 sr @0x03f9, $AR0 @@ -1997,7 +2064,7 @@ void 0603_Unk(_returnAddr($AR0)) // 060e 27ff lrs $AC1.M, @CMBL // 060f 009e 05ff lri $AC0.M, #0x05ff - // 0611 4c00 add $ACC0, $AC1.L + // 0611 4c00 add $ACC0, $ACC1 AC0.M = 0x05ff + *CMBL // 0612 1c7e mrr $AR3, $AC0.M @@ -2397,7 +2464,7 @@ void EarlyOutFrom_073d_DECODE_0x05_0x09() { 06f9_Unk_PrepareSampleDecode() 0710 8100 clr $ACC0 0711 2632 lrs $AC0.M, @0x0032 - 0712 5c00 sub $ACC0, $AC1.L + 0712 5c00 sub $ACC0, $ACC1 0713 2e32 srs @0x0032, $AC0.M 0714 0092 00ff lri $CR, #0x00ff 0716 02df ret @@ -2501,7 +2568,7 @@ void 073d_DECODE_0x05_0x09(_dest($AR3), _numberOfSamples($AC1.M), _len(AX1)) / 0757 0291 07ab js 0x07ab if () { - // math how much samples we have to copy + // compute how many samples we have to copy 0759 8100 clr $ACC0 075a 1fdf mrr $AC0.M, $AC1.M 075b 040f addis $ACC0, #0x0f @@ -2521,7 +2588,7 @@ void 073d_DECODE_0x05_0x09(_dest($AR3), _numberOfSamples($AC1.M), _len(AX1)) / { 0768 8100 clr $ACC0 0769 263b lrs $AC0.M, @0x003b - 076a 5c00 sub $ACC0, $AC1.L + 076a 5c00 sub $ACC0, $ACC1 076b 2e32 srs @0x0032, $AC0.M 076c 8100 clr $ACC0 076d 2e3a srs @0x003a, $AC0.M @@ -2534,7 +2601,7 @@ void 073d_DECODE_0x05_0x09(_dest($AR3), _numberOfSamples($AC1.M), _len(AX1)) / 0772 2c3b srs @0x003b, $AC0.L 0773 0c00 lris $AC0.L, #0x00 0774 1fd8 mrr $AC0.M, $AX0.L - 0775 5c00 sub $ACC0, $AC1.L + 0775 5c00 sub $ACC0, $ACC1 0776 2e32 srs @0x0032, $AC0.M } @@ -2595,7 +2662,7 @@ void 073d_DECODE_0x05_0x09(_dest($AR3), _numberOfSamples($AC1.M), _len(AX1)) / { 07ab b100 tst $ACC0 07ac 0295 07bb jz 0x07bb - 07ae 5d00 sub $ACC1, $AC0.L + 07ae 5d00 sub $ACC1, $ACC0 07af 040f addis $ACC0, #0x0f 07b0 147c lsr $ACC0, #-4 07b1 0c00 lris $AC0.L, #0x00 @@ -2616,7 +2683,6 @@ void 073d_DECODE_0x05_0x09(_dest($AR3), _numberOfSamples($AC1.M), _len(AX1)) / 07be 0295 07e3 jz 0x07e3 // stop rendering, see below 7e3 - 07c0 2380 lrs $AX1.H, @0xff80 07c1 2688 lrs $AC0.M, @0xff88 07c2 2489 lrs $AC0.L, @0xff89 @@ -2687,7 +2753,7 @@ void 07eb_AFCDecoder(_numberOfSample(AC0.M)) // 07f9 2280 lrs $AX0.H, @0xff80 // 07fa d000 mulc $AC1.M, $AX0.H // 07fb 6f00 movp $ACC1 - // 07fc 4c00 add $ACC0, $AC1.L + // 07fc 4c00 add $ACC0, $ACC1 // 07fd 2e38 srs @0x0038, $AC0.M // 07fe 2c39 srs @0x0039, $AC0.L //inrease sample offset in ARAM @@ -2831,44 +2897,25 @@ void 07eb_AFCDecoder(_numberOfSample(AC0.M)) 086e 02df ret } + + - - - - - - - - - - - - - - - - - - - - - - - - // unreachable + // probably unreachable { - 086f b100 tst $ACC0 - 0870 02d5 retz + // 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 js 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 + 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 } @@ -2973,9 +3020,9 @@ void 08c2_Decoder0x3_RectangleWave(ACC0, AR0, AX0.L) { // 08cf 1b1b srri @$AR0, $AX1.H //08d0 027d iflz // 08d1 1b19 srri @$AR0, $AX1.L - //08d2 4c00 add $ACC0, $AC1.L + //08d2 4c00 add $ACC0, $ACC1 - if(($AC0.M & 3) == 3) + if (($AC0.M & 3) == 3) *$AR0++ = 0x4000; else *$AR0++ = 0xc000; @@ -3002,7 +3049,7 @@ void 08d5_Decoder0x2_SquareSaw(ACC0, AR0, AX0.L) { 08e7 183d lrr $AC1.L, @$AR1 08e8 4900 addax $ACC1, $AX0.L 08e9 1fe2 mrr $AC1.M, $AR2 - 08ea 4c39 add's $ACC0, $AC1.L : @$AR1, $AC1.M + 08ea 4c39 add's $ACC0, $ACC1 : @$AR1, $AC1.M 08eb 147f lsr $ACC0, #-1 // 08ec 02df ret } @@ -3015,19 +3062,17 @@ void 08ed_Decoder0x1_SawWave(ACC0, AR0, AX0.L) { // 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, $AC1.L : @$AR0, $AC0.L - ACC0 += AC1.L; - + // 08f1 4c20 add's $ACC0, $ACC1 : @$AR0, $AC0.L + ACC0 += ACC1; *$AR0++ = AC0.L; } // 08f2 02df ret } + void 08f3_Unk() { 08f3 0082 0180 lri $AR2, #0x0180 // Three entrances 08f5 029f 08fd jmp 0x08fd @@ -3049,7 +3094,7 @@ void 08f3_Unk() { 090b 001a addarn $AR2, $IX2 090c 3400 andr $AC0.M, $AX0.H 090d 1150 0913 bloopi #0x50, 0x0913 - 090f 4c4a add'l $ACC0, $AC1.L : $AX1.L, @$AR2 + 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 @@ -3083,7 +3128,7 @@ void 091c_Decoder0x7_WaveTable(ACC0, AR0, AX0.L) { 092c 001a addarn $AR2, $IX2 092d 3400 andr $AC0.M, $AX0.H 092e 1150 0934 bloopi #0x50, 0x0934 - 0930 4c4a add'l $ACC0, $AC1.L : $AX1.L, @$AR2 + 0930 4c4a add'l $ACC0, $ACC1 : $AX1.L, @$AR2 0931 3606 andr'dr $AC0.M, $AX1.H : $AR2 0932 1cde mrr $IX2, $AC0.M 0933 340e andr'nr $AC0.M, $AX0.H : $AR2 @@ -3115,7 +3160,7 @@ void 093a_Unk() { 0952 140a lsl $ACC0, #10 0953 4e00 addp $ACC0 0954 1476 lsr $ACC0, #-10 - 0955 4c4a add'l $ACC0, $AC1.L : $AX1.L, @$AR2 + 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 @@ -3182,7 +3227,7 @@ void Decoder0x08() { 0991 2002 lrs $AX0.L, @0x0002 0992 8100 clr $ACC0 0993 8900 clr $ACC1 - 0994 2430 lrs $AC0.L, @0x0030 + 0994 2430 lrs $AC0.L, @0x0030 // CurSampleFrac 0995 8d00 set15 0996 0950 lris $AX1.L, #0x50 0997 a000 mulx $AX0.L, $AX1.L @@ -3232,7 +3277,7 @@ void Decoder0x08() { 09c9 b100 tst $ACC0 09ca 0294 09d9 jnz 0x09d9 09cc 263b lrs $AC0.M, @0x003b - 09cd 5c00 sub $ACC0, $AC1.L + 09cd 5c00 sub $ACC0, $ACC1 09ce 0290 09d9 jns 0x09d9 09d0 223b lrs $AX0.H, @0x003b @@ -3252,7 +3297,7 @@ void Decoder0x08() { 09e1 1570 lsr $ACC1, #-16 09e2 0a01 lris $AX0.H, #0x01 09e3 0081 0405 lri $AR1, #0x0405 - 09e5 5c00 sub $ACC0, $AC1.L + 09e5 5c00 sub $ACC0, $ACC1 09e6 b100 tst $ACC0 09e7 0275 ifz 09e8 1a3a srr @$AR1, $AX0.H @@ -3308,11 +3353,11 @@ void 0a0a_UsedBy08Decoder() { 0a12 1b7e srri @$AR3, $AC0.M // 0a13 02df ret } - - + //////////////////////////////////////////// 0x10 DECODER -// This should be the easiest decoder to decipher in full. +// This should be the easiest decoder to decipher in full -- except the really +// trivial ones like the synths. void Decoder_0x10() { 0a14 0092 0004 lri $CR, #0x0004 0a16 2002 lrs $AX0.L, @0x0002 @@ -3384,7 +3429,7 @@ void Decoder_0x10() { 0a4f 0294 0a5e jnz 0x0a5e if (!*0x043a) { 0a51 263b lrs $AC0.M, @0x003b - 0a52 5c00 sub $ACC0, $AC1.L + 0a52 5c00 sub $ACC0, $ACC1 0a53 0290 0a5e jns 0x0a5e if (0x43b <= ACC1) { // not sure, but .. not enough samples? 0a55 223b lrs $AX0.H, @0x003b @@ -3405,7 +3450,7 @@ void Decoder_0x10() { 0a66 1570 lsr $ACC1, #-16 0a67 0a01 lris $AX0.H, #0x01 0a68 0081 0405 lri $AR1, #0x0405 - 0a6a 5c00 sub $ACC0, $AC1.L + 0a6a 5c00 sub $ACC0, $ACC1 0a6b b100 tst $ACC0 0a6c 0275 ifz 0a6d 1a3a srr @$AR1, $AX0.H @@ -3584,7 +3629,7 @@ void 0ab3_Decoder0x21Core(AC1.M, AR3) { AC0.M = *0x048a; AC1.M = *0x0434; - // 0ad7 5c00 sub $ACC0, $AC1.L + // 0ad7 5c00 sub $ACC0, $ACC1 // 0ad8 2e36 srs @0x0036, $AC0.M ACC0 -= AC1.L; @@ -3671,7 +3716,7 @@ void 0af6_Decoder0x21_MoreStuff($AR0, $AR3) { // 0b02 8900 clr $ACC1 // 0b03 2534 lrs $AC1.L, @0x0034 // 0b04 1501 lsl $ACC1, #1 - // 0b05 4c00 add $ACC0, $AC1.L + // 0b05 4c00 add $ACC0, $ACC1 // 0b06 5a00 subax $ACC0, $AX1.L // 0b07 5a00 subax $ACC0, $AX1.L @@ -4018,16 +4063,16 @@ void 0c1c_Unk() 0c22 8900 clr $ACC1 0c23 009f 00a0 lri $AC1.M, #0x00a0 0c25 00de 03f1 lr $AC0.M, @0x03f1 - 0c27 5d00 sub $ACC1, $AC0.L + 0c27 5d00 sub $ACC1, $ACC0 0c28 0e50 lris $AC0.M, #0x50 0c29 0750 cmpis $ACC1, #0x50 0c2a 0270 ifns - 0c2b 5d00 sub $ACC1, $AC0.L + 0c2b 5d00 sub $ACC1, $ACC0 0c2c 00da 03f2 lr $AX0.H, @0x03f2 0c2e 8600 tstaxh $AX0.H 0c2f 0290 0c4d jns 0x0c4d 0c31 00de 03f3 lr $AC0.M, @0x03f3 - 0c33 5c00 sub $ACC0, $AC1.L + 0c33 5c00 sub $ACC0, $ACC1 0c34 0293 0c38 jle 0x0c38 0c36 029f 0c52 jmp 0x0c52 0c38 00db 03f7 lr $AX1.H, @0x03f7 @@ -4046,7 +4091,7 @@ void 0c1c_Unk() 0c4b 029f 0c52 jmp 0x0c52 0c4d 00de 03f4 lr $AC0.M, @0x03f4 - 0c4f 5d00 sub $ACC1, $AC0.L + 0c4f 5d00 sub $ACC1, $ACC0 0c50 0293 0c3f jle 0x0c3f 0c52 8900 clr $ACC1 @@ -4064,7 +4109,7 @@ void 0c1c_Unk() // 0c5e 1150 0c65 bloopi #0x50, 0x0c65 for (int i = 0; i < 0x50; i++) { 0c60 1878 lrr $AX0.L, @$AR3 - 0c61 4c00 add $ACC0, $AC1.L + 0c61 4c00 add $ACC0, $ACC1 0c62 1cfe mrr $IX3, $AC0.M 0c63 001f addarn $AR3, $IX3 0c64 1fd9 mrr $AC0.M, $AX1.L @@ -4073,7 +4118,7 @@ void 0c1c_Unk() 0c66 009f 0a60 lri $AC1.M, #0x0a60 0c68 1fc3 mrr $AC0.M, $AR3 - 0c69 5c00 sub $ACC0, $AC1.L + 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 @@ -4117,7 +4162,7 @@ void 0c84_ModifySample(_sampleAddr($AR0)) 0c96 0084 0000 lri $IX0, #0x0000 0c98 1150 0ca1 bloopi #0x50, 0x0ca1 0c9a 199e lrrn $AC0.M, @$AR0 - 0c9b 5c7c sub'ln $ACC0, $AC1.L : $AC1.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 @@ -4131,36 +4176,52 @@ void 0c84_ModifySample(_sampleAddr($AR0)) 0ca8 02df ret } -// Called from loop in 0cd3_Unk -void 0ca9_Unk($ACC1, $AR0, $AR3) { +// Called from both volume handlers. +// ACC1 is volume, AX is volume delta. +void 0ca9_RampedMultiplyBuffer($ACC1, $AX0, $AR0, $AR3) { 0ca9 b900 tst $ACC1 0caa 0294 0caf jnz 0x0caf - if (!ACC0) { - 0cac 6800 movax $ACC0, $AX0.L - 0cad b100 tst $ACC0 - 0cae 02d5 retz - - ACC0 = AX0.L - if (!ACC0) + 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 + + // Load multiplier from AR0, twice? 0cb1 191b lrri $AX1.H, @$AR0 + + // 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. + // What it turns into if you unwind it is something like: + // + // todo + // + // Produce the first result, so it's ready in the prod register. 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 + 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 + 0cb8 6231 movr's $ACC0, $AX1.L : @$AR1, $AC0.M // Store 1 + + // Walk the ramp. 0cb9 4900 addax $ACC1, $AX0.L } + // 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 } @@ -4169,6 +4230,9 @@ void 0ca9_Unk($ACC1, $AR0, $AR3) { // 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 32 (0x20) samples! + 0cc0 02df ret } @@ -4193,125 +4257,178 @@ void 0cc1_UnkFilter(_pBuffer(AR3)) // 0cd2 02df ret } - + + // called from sync frame if (*0x042c != 0) -void 0cd3_Unk() +// 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 + // 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 - 0cde b100 tst $ACC0 - 0cdf 0294 0ce5 jnz 0x0ce5 - 0ce1 009a 0001 lri $AX0.H, #0x0001 - 0ce3 00fa 0401 sr @0x0401, $AX0.H + // 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 - 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 + // 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, $AC1.L # broken disasm? this doesn't make much sense. - 0cfc 1c1e mrr $AR0, $AC0.M - 0cfd 1818 lrr $AX0.L, @$AR0 - 0cfe 1fda mrr $AC0.M, $AX0.H - 0cff 4c00 add $ACC0, $AC1.L - 0d00 1c1e mrr $AR0, $AC0.M - 0d01 181a lrr $AX0.H, @$AR0 - 0d02 1fd9 mrr $AC0.M, $AX1.L - 0d03 4c00 add $ACC0, $AC1.L - 0d04 1c1e mrr $AR0, $AC0.M - 0d05 1819 lrr $AX1.L, @$AR0 - 0d06 1fdb mrr $AC0.M, $AX1.H - 0d07 4c00 add $ACC0, $AC1.L - 0d08 1c1e mrr $AR0, $AC0.M - 0d09 181b lrr $AX1.H, @$AR0 + // 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; - 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 - 0d12 0080 0b00 lri $AR0, #0x0b00 - 0d14 0081 0b04 lri $AR1, #0x0b04 - 0d16 00da 042a lr $AX0.H, @0x042a - 0d18 02bf 0d62 call 0x0d62 + // 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; - 0d1a 0081 0b08 lri $AR1, #0x0b08 - 0d1c 0080 0b04 lri $AR0, #0x0b04 - 0d1e 00da 042a lr $AX0.H, @0x042a - 0d20 00de 0429 lr $AC0.M, @0x0429 - 0d22 c000 mulc $AC0.M, $AX0.H - 0d23 6e00 movp $ACC0 - 0d24 1481 asl $ACC0, #1 - 0d25 1f5e mrr $AX0.H, $AC0.M - 0d26 02bf 0d62 call 0x0d62 + // 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 - 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 - 0d30 00df 042a lr $AC1.M, @0x042a - 0d32 00fe 042a sr @0x042a, $AC0.M - 0d34 5c00 sub $ACC0, $AC1.L - 0d35 1f5e mrr $AX0.H, $AC0.M - 0d36 02bf 0d6b call 0x0d6b + // 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_TrickyMul(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_TrickyMul(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_TrickierMul(0xb00, 0x0b0c, (*(0x042a) - *(0x042b))) + + // 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_TrickyMul(0x0b0c, 0x0b10, *(0x0429)); - 0d38 0080 0b0c lri $AR0, #0x0b0c - 0d3a 0081 0b10 lri $AR1, #0x0b10 - 0d3c 00da 0429 lr $AX0.H, @0x0429 - 0d3e 02bf 0d62 call 0x0d62 0d40 0081 0b04 lri $AR1, #0x0b04 - 0d42 0082 0b0c lri $AR2, #0x0b0c // Load buffer index from 0b0c + 0d42 0082 0b0c lri $AR2, #0x0b0c 0d44 0083 0d77 lri $AR3, #0x0d77 // 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 - 0d4c 193f lrri $AC1.M, @$AR1 - 0d4d 00e1 0b24 sr @0x0b24, $AR1 - 0d4f 00e2 0b25 sr @0x0b25, $AR2 - 0d51 021b ilrri $AC0.M, @$AR3 // Table lookup (see above) - 0d52 00e3 0b26 sr @0x0b26, $AR3 - 0d54 1c7e mrr $AR3, $AC0.M - 0d55 00c0 038f lr $AR0, @0x038f - 0d57 02bf 0ca9 call 0x0ca9 + // 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 + 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 above) + // 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_RampedMultiplyBuffer(... $AR3) + // Restore AR1, AR2, AR3. 0d59 00c1 0b24 lr $AR1, @0x0b24 0d5b 00c2 0b25 lr $AR2, @0x0b25 0d5d 00c3 0b26 lr $AR3, @0x0b26 0d5f 0000 nop - } + } + + // So basically the above loop is: + // For i in 0 to 8: + // Call 0x0ca9_RampedMultiplyBuffer($AR0 = *0x038f, $AR3=0x0d77[i], AX0=0xb0c[i]<<11, AC1.M=0x0b04[i]) 0d60 8e00 set16 - 0d61 02df ret + // 0d61 02df ret } -void 0d62_Unk() { +void 0d62_TrickyMul(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 @@ -4323,7 +4440,7 @@ void 0d62_Unk() { // 0d6a 02df ret } -void 0d6b_Unk() { +void 0d6b_TrickierMul(in_buffer($AR0), out_buffer($AR1)) { 0d6b 8d00 set15 0d6c 1f7e mrr $AX1.H, $AC0.M 0d6d 1918 lrri $AX0.L, @$AR0