Is ff8038-ff8041 writable? (CDD status registers.) I am guessing not, and that they're for the CDD to write to them.
Indeed they are not. They are written by the ASIC upon receiving CDD status words through the CDD interface (4 bits at a time).
The manual says that writing ReceiveStatus generates an INT4 IRQ, but I would presume it would actually be ReceiveStatus when the checksum is written.
Pretty sure the manual is correct. As said in a previous post, interrupt handler (which reads CDD status registers then update CDD command registers) does not run immediately when IRQ is trigerred, there is some latency because of 68k interrupt processing. They likely decided to trigger IRQ a little bit earlier to save some time for interrupt handler, the last CDD status registers (with checksum value) will still have been updated when the interrupt handler starts executing.
Are writes to ff8042-ff804b always word-based? The manual doesn't say so.
If nothing is indicated (cf. my previous post) then it means there are no restrictions, which is kinda logical since each byte address corresponds to one of the 10 command nibble. It is just that word-access is more efficient so probably all BIOS do that.
If not, will a write to ff804a trigger a CDD command process?
If you mean a byte write then no, since (according to the software manual) the ASIC waits for the last command 4-bit value to be updated (in ff804b) to start sending the command words on CDD interface.
If I trigger the CDD processing (check command and update status values) immediately, and fire a CDD IRQ immediately, the BIOS hangs forever with no text at the bottom of the screen.
That's because that is not how the hardware works. CDD starts processing the command shortly after the last command register has been updated (not immediately since it has to wait for the receipt of the 10 command nibbles through ASIC->CDD interface but emulating immediate transmission works fine since CDD is not emulated at low level anyway) BUT it waits for the next 75hz period start before asserting /IRQ signal on CDD->ASIC interface (which makes the ASIC start receiving next CDD status nibbles then triggering a level 4 interrupt when 8th nibble has been received).
Upon writing ff804b (command) ... if I set ff8036.d0=1 (DTS), then wait until the next CDD 75hz timing event to clear DTS and process the command, and then fire a CDD IRQ immediately there, things work, but still shows "PRESS START BUTTON".
This should work correctly, although emulating DTS bit is not necessary (it does not seem to be checked by BIOS as emulating immediate transmission works just fine and most likely it is cleared much sooner than what you are doing since the transfer of 4-bit command nibbles is quite fast, and CDD needs some time before next 75hz period to process it). It would also be more correct to process CDD command soon after the last command register rather than just before the next 75hz interrupt (but it does not really matters, as long as you updated CDD status registers before int4 handler is executed).
Upon writing ff804b ... if I immediately process the command, and then set ff8036.d1=1 (DRS), then wait until the next CDD 75hz timing event to clear DRS and fire a CDD IRQ, things also work, but still shows "PRESS START BUTTON".
Yes because it is similar to previous one (only difference is you process CDD command at a different time but, as explained above, it makes no difference from software point of view). Again, DRS bit likely does not work like this (it is probably set to 1 shortly before int4 triggering when the CDD status reception starts and cleared shortly after int4 is triggered once the 10th status nibble has been received by CDD interface in ASIC registers) and is not necessary to emulate (immediate status transfer works just fine).
What is the actual correct behavior? Does either DTS or DRS wait for the next 75hz CDD timing event? Or do they just take a small (but non-zero amount of time) to complete?
hardware behavior likely is the following:
1) CDD asserts /IRQ to indicate it is ready to send its status then wait for HOCK signal falling edge
2) Gate-Array asserts HOCK signal (if corresponding bit is set to 1 in register) to indicate it is ready to receive CDD status then wait for CDCK signal to reset HOCK signal
3) CDD asserts CDCK signal while transmitting first 4-bit data on interface then wait for next HOCK falling edge to send next nibble, etc
4) Gate-Array set DRS bit to 1, copy first nibble to first status register then assert HOCK signal again to get next nibble,etc
5) when 8th status nibble has been copied to internal register, Gate-Array triggers level 4 interrupt request
6) when 10th status nibble has been read, Gate-Array clears DRS bit and CDD waits for next HOCK falling edge indicating command transmission
7) when 10th command register is written by software (normally by BIOS during int4 processing), Gate-Array set DTS bit to 1, asserts HOCK signal while putting first command nibble on CDD interface then wait for CDCK before sending next nibble, etc
8 ) when 10th command nibble has been written to CDD interface, Gate-Array clears DTS bit then waits for next /IRQ edge from CDD, while CDD starts processing the received command (and updates its status) then waits for next 75hz period
As seen above, there are various ways to emulate this but what matters is that int4 occurs every 1/75s when communication is functional and that CDD command is processed and CDD status registers updated before next int4 processing by BIOS. And DTS and DRS bits can be left cleared all the time (simulating zero nibble transmission time on CDD interface) without issues (exact transmission timing is unknown).
Inside the CDD processing function ... the X-Eye manual states that command=0x0 is "no operation", but Genesis Plus GX states it's a latched copy of the status (cdd.status variable.)
In case of nop command, CDD still send its status to gate-array.
When Genesis Plus GX executes command 0x1 (stop drive), it sets status=0x0 (STOP), and then cdd.status=0xb (NO_DISC). It doesn't seem to matter whether I do this indirect latching or not, I still get "PRESS START BUTTON".
I only set status to 0xb if there is no disc (cdd.loaded=0), otherwise it is set to 0x9 (READ TOC). In latter case, this matches what is described in CDD_inf.txt: apparently, after the disc is stopped, status only briefly stays to 0x0 then change to 0x9. Not sure if Stef doc is 100% correct but it looks like drive is never really stopped and lead-in area is read again.
When Geneis Plus GX executes command=0x1, command=0x4 (first and last track numbers), it's returning 0x1 in status and 0x0 in status even when there is no disc present. I presume it should be 0x0 for both when there's no disc. But it doesn't seem to matter either way.
I guess you meant when command=0x2, that I still return first track value set to 01 without caring if there is a disc inserted or not. It's just I didn't bothered emulating these edge cases as they never happen, BIOS seem yo only send NOP command after the first status reporting NO_DISC.
I have no idea what values are set by CDD in RS1-RS8 in that case, maybe 0xf to indicate invalid status infos...or maybe 0x0 to indicate zero tracks, I don't know.
When Genesis Plus GX executes command=0x0, it does not clear status[1-8], unless status=0xf, as some sort of Lunar: Silver Star workaround, but at least in the BIOS, this condition isn't true. So I am only setting status=cdd.status here.
nop command let the status unchanged normally
This behavior is just to delay the update of status after a seek command because some games didn't liked that the status immediately returned at the first interrupt following seek command was already indicating seek destination so I have to force the status invalid (by setting RS1 to 0xf) for some interrupts to simulate seek time. After seek command, BIOS use nop command to continuously read the status until seek is finished so I used this to reset RS1-RS8 to some valid value after seek is finished because Lunar expected it to be valid at least once after seek before sending play command. I guess this could have been done in cdd_update function where cdd.latency is handled, not sure why this ended here but there must be some reason.
Upon processing a CDD command, Genesis Plus clears command and command = 0. Is this confirmed behavior? Is it really both words?
This doesn't even serve the purpose of truly invalidating the CDD command checksum, because if command[0-6]=0 and command=0xf, then the checksum would still be valid. So it feels like it should either erase command[0-9] or not bother erasing any of it.
Hum, this is just a dirty hack to indicate the latest command register has been written (by forcing it to zero, which I agree is not very clever either) so that I know when 75h period is over if int4 should be triggered or not
(indeed, as explained above, it seems that CDD stops triggering /IRQ and sending status if gate-array stops sending command so int4 is also stoped . I was apparently too lazy to use a separated boolean flag and thought it was a 'brillant' idea to reuse existing registers (CDD command checksum computed by BIOS is not verified so it didn't matter). I guess I should rework that part as it is indeed not very clean.
On real hardware, nothing get cleared by hardware off course (except on reset).
Upon powering on the system, things only seem to work if I clear status[0-8], set status=0xf (eg valid checksum), and have cdd.status=0xb (NO_DISC). If the checksum isn't valid, the BIOS hands forever. If I give status=0x0 (STOP), the BIOS goes to "CHECKING DISC" forever.
BIOS verifies CDD status checksum at the start of int4 processing so it must be properly updated, yes.
And it seems stop status is supposed to be only temporary as discussed above, it automatically changes to 0x9 (read toc) or 0xb (no disc) after some time.
It looks like GX is also setting regs[0x4a]=0x00 when a status result is pending, and regs[0x4a]=0xf0 when one isn't.
But command is a 4-bit value. It doesn't seem to make a difference if I emulate this behavior or not.
It does at least explain why ff804a writes in GX were clearing command[8-9] to 0x0.
Yes, it is related to hack above
Edit: well that's really annoying. It doens't say "No disc" on real hardware either. That might be a v2.21 BIOS thing, or something, I don't know.
Fom what I remember, "press start" message is correct on both Model 1 and Model 2 US/PAL BIOS. On Model 1, when there is no disc, it still let you enter the menu interface because that's the only way you can open the tray to insert a disc. Model 2 (2.00/2.11) BIOS apparently kept that behavior although the tray could only be opened manually, maybe to keep consistency with previous model.
2.21 is CDX/Multimega BIOS and it has indeed different behaviors because I think it can be used as portable CD player.