Last active
July 11, 2016 18:14
-
-
Save freem/357e622263e08a9bf28f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
notes on the SM1 driver | |
======================= | |
[Introduction] | |
The main purpose of this document is to figure out how the SM1 driver accepts | |
parameters for some of its commands. | |
Examples are: | |
* Command $0A: Fade Out | |
* Command $14: Stop ADPCM-A sound? | |
* Command $18: Start ADPCM-A sound? | |
* Command $19: Start ADPCM-B sound? | |
* routine sub_DDA | |
* routine sub_E1D | |
All of these set byte_FE58 to a nonzero value. This variable is used to tell | |
the NMI to skip its normal behavior and jump to loc_A8 instead. | |
================================================================================ | |
[Variables] | |
So throughout all of this, we have a few variables to keep track of. | |
* processParam (0xFE2C): I originally thought this controlled param parsing. | |
It is related to it, but it seems to only be used in the loops where the | |
param is being waited for. A more accurate name would be "waitForParam"? | |
* byte_FE39: used in handleCommand and various param-taking commands. | |
Its value is sometimes written to byte_FE3A. | |
* byte_FE3A: used in pcmaCommandHandler, pcmbCommandHandler, ssgCommandHandler, | |
sub_498, loc_7E8, sub_881. At the beginning of the PCMA, PCMB, and SSG | |
handlers, byte_FE3A is set to the value in byte_FE39. | |
* byte_FE47: the current index into the command buffer? Used in the NMI, sub_1AD, | |
and sub_B66. | |
* byte_FE48-0xFE57: command buffer? | |
unsure of the final address in the buffer, but byte_FE48 is where it begins. | |
* byte_FE58: the overall "parse the next command as a parameter" var. | |
Checked in NMI, cleared in Main Loop. Set with command_18, command_19, | |
command_14, command_0A, sub_DDA, sub_E1D. | |
* byte_FE5C: related to command buffer index? | |
only used in Main Loop and sub_B66. | |
* byte_FE66: Infinite loop in RAM variable? | |
Set to 0 in main loop; set to 1 at loc_BF3. | |
Unrelated to sound driver parameter design. | |
================================================================================ | |
[The NMI] | |
As in a typical sound driver, the command from the 68K is received and | |
checked for specific values. After those checks, the value in byte_FE58 is | |
compared. If it's nonzero, the execution jumps to loc_A8. | |
Otherwise... | |
sub_B66 is called with a = 0x80. The routine at sub_b66 "compares values at | |
0xFE5C and 0xFE47 (increments 0xFE47 if match)". Not sure what purpose this | |
serves. | |
After this, byte_FE47 is read into a, masked with 7, and used as an index | |
into byte_FE48 (Command buffer?). 0xFF is written to this location, followed | |
by the value in b. a is incremented, masked with 7, and stored into byte_FE47. | |
processParam is set to 0, and NMI_reply is jumped to. | |
(loc_A8) | |
loc_A8 copies b back to a (as the reverse was done just after the byte was | |
grabbed from the 68K), sets byte_FE39 to the value in a, then clears the | |
processParam (0xFE2C) variable. The NMI continues as usual (e.g. falls | |
through to NMI_reply). | |
(NMI_reply) | |
replyto68K is loaded (set in the main loop), the top bit is masked, and the | |
final value is written to ports 0x0C and 0x00. | |
================================================================================ | |
[The Main Loop] | |
Understanding this one is tough. | |
First, byte_FE58 (parse next command as param) and byte_FE66 (used in slot | |
switching) are set to 0. Interrupts are enabled. | |
soundBufIndex (not the same as byte_FE47) is loaded into a, masked with 7, | |
and stored into byte_FE5C. This value is used as the index into the command | |
buffer (byte_FE48). soundBufIndex is updated after being added to the | |
command buffer, and a value from the buffer is read into a. handleCommand is | |
called if the command is nonzero. | |
Execution continues... | |
Interrupts are enabled again, byte_FE65 is read; if zero, execution begins at | |
the beginning of the loop again. If not, a random byte is written to the 68K, | |
the top bit is OR'd, and sent to port 0x0C. main loop continues from the top. | |
================================================================================ | |
[handleCommand routine] | |
The handleCommand routine sets processParam to 0xFF, clears the command at the | |
current buffer position, reads the next value from the buffer, and sets | |
byte_FE39 to that value. That value is compared as though it was a sent command. | |
If the command was not handled, byte_FE3B and bye_FE39 are set to 0. | |
================================================================================ | |
[Command Example: command $0A - Fade Out] | |
1) byte_FE58 is set to 0xFF | |
2) processParam is loaded into a; if nonzero, keep looping. | |
after the loop stops... | |
1) processParam is set to 0xFF | |
2) unk_FABE is loaded into iy | |
3) byte_FE39 is loaded into a | |
4) write a to 2(iy) | |
5) write 1 to byte_FE23 | |
6) write 2 to byte_FE36, FE37 | |
================================================================================ | |
[Command Example: command $18 - Start ADPCM-A sound?] | |
1) byte_FE58 is set to 0xFF | |
2) processParam is loaded into a; if nonzero, keep looping. | |
after the loop stops... | |
1) processParam is set to 0xFF | |
2) byte_FE39 is loaded into a. | |
3) This is then compared to 0x10. If "C" is set, jump to loc_175. | |
4) If not, byte_4499 is loaded into hl, bc is pushed, and sub_c66 is called. | |
bc is then popped after this runs. | |
5) or A, return if zero. | |
6) load byte_FE39 into a, disable interrupts, and jump to loc_1CE. | |
[Addendum: loc_175] | |
loc_175 is handleCommand after the param stuff is dealt with. see above. | |
[Addendum: loc_1CE] | |
loc_1CE is the normal ADPCM-A command handler after param stuff is handled. | |
[Addendum: sub_c66] | |
1) load a into c | |
2) and with 7 | |
3) load 3 into b (counter) | |
loc_c6B: | |
1) shift c right | |
2) djnz loc_C6B | |
after loop finishes... | |
3) add hl,bc | |
4) load a into b, 0x80 into c | |
5) or a, jump to loc_C7A if 0 | |
loc_c76: | |
1) shift c right | |
2) djnz loc_c76 | |
after loop finishes... | |
loc_C7A: | |
1) load c into a | |
2) and with value at hl and return | |
================================================================================ | |
[Trying to put it all together] | |
The parts of this system: | |
* The NMI | |
* The Main Loop | |
* The Commands that accept params | |
<NMI> | |
The NMI is pretty simple. | |
In the Mr.Pac v1.5b driver, the required commands are checked before the param | |
waiting variable (byte_FE58). I am not sure if this precludes certain values | |
from being sent as parameters. | |
If byte_FE58 is nonzero, the parameter handling routine is run. The original | |
byte (still in b) gets copied to byte_FE39, and processParam is set to 0. | |
<Main Loop> | |
byte_FE58 is one of the two variables that get set to 0 at the beginning of | |
the main loop. When it comes to params, the main loop doesn't do much. | |
<Commands that accept Params> | |
Commands that accept parameters seem to perform the following steps: | |
1) Set byte_FE58 to 0xFF (making the NMI use the "handle params" code) | |
2) Load processParam into a and check if it's nonzero. If it is nonzero, loop | |
back to the beginning of the command (in this case, step 1). | |
3) After the loop ends, processParam is set to 0xFF again (since it will be | |
re-set to 0 in the NMI). | |
4) The parameter value sent from the 68K seems to be in byte_FE39. | |
Do with it what you wish. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment