Found at 80012A0C
Summary
Executes the cd command at the queue entry passed in by the caller. There are two branches depending if the queue entry has a CdControl op code or the custom command code. The function is also in charge of registering the cd ready callback and updating CD library global variables used by it when using the custom command code.
Behavior
There are two branches taken for this function depending on whether the command queue entry we are executing is using the CdControl op codes or our CdLdReadN command.
Branch 1 command value is CdLdReadN:
Sets the global CD library variables used by cdlib_ready_callback to track the current read operation and copy the read data into RAM. These values are initialized from the queue entry’s args member, which in this branch is always a CdLdFile. Once the values are set, call CdControl with the ReadN opcode to execute the read. If the command was not accepted exit the function, we will try again shortly in the next state machine pump. If it was accepted register the cdlib_ready_callback, set the IO state to ReadN and update the command member in the queue entry to the CdlPause opcode then update the value for vblanks since start and return without updating the exec index.
Branch 2 using CdControl command op codes:
Zeroes out a global variable used by the cdlib_xa_manager, then calls CdControl with the values from our queue entry. If the command was not accepted exit the function, we will try again shortly in the next state machine pump. Otherwise enter a switch case and do the following based on the command sent:
- CdlSetloc: set the seek head to a sentinel value then seek the seek target to the location passed to CdControl. Both values are in LBA.
- CdlReadN: set the IO state to ReadN then set 800e38c4 to 2.
- CdlPause: set the IO state to Ready.
- CdlSetmode: set 800e38c8 to the exec index.
- CdlSeekL or CdlSeekP: set the IO state to Seek then set 800e38c4 to 2.
- CdlReadS: set the IO state to ReadS, 800e38c4 to 20 and the cdlib_manager_callctr to 0.
All commands whether they satisfy the above cases or not go through the default case which saves the last command executed into a global register and sets the command executed member in the queue entry to 1. Finally increment the exec index normalizing it so it stays within the circular buffer bounds and update the value for vblanks since start then return.
Notes
- cdlib_queue_exec_index points to the next command that will be executed.
- In Branch 1 we update the cmd code to CdlPause without moving the exec index because when the read is done the callback will set the io state to ready and since the exec index hasn’t been updated the next command executed will be the pause.
- There is no if (false) condition, looks like a decompilation artifact from optimized assembly for the switch. See unknowns.
- It looks like case CdlReadN is never taken. I have found no enqueue calls with ReadN as the command op code in the program.
Unknowns
-
The if (false) is more accurately decompiled to if cdCmd - 2 >= x1a go to the default case. I believe this is a compiler optimization. This specific switch statement is done through a jump table. To index the jump table we do cmdOpCode - 2 x 4 (size of a pointer). The jump table starts at case 2 and ends at case 1b. I think this is done for two reasons.
- It accounts for cases bigger than the last explicit listed case CdlReadS (x1b), as the compiler doesn’t know what values we will pass in.
- Using an unsigned instruction to subtract the 2 from the opcode you can take advantage of the branch before the switch for CdlNop as the op code for this command is 1 which wraps around to the largest the largest possible value when the operation is unsigned satisfying the branch condition and jumping to the default.
-
It looks like for the cd seeks and ReadN op codes in the switch case, both actually write the IO state in the label 80012b60 not their case branch. I’m thinking this was probably a compiler optimization since both cases set 800e8c4 to 2 just have both of them actually sw the io state in the label to save on instructions.
-
The cdlib_last_executed_cmd and 800e38c8 global variables are never read. These were probably used for debugging.
Parameters: 1
cdQueueEntryPtr: a pointer to the queue entry we want to execute
Returns
Always 1