Questions on writing a new Mega CD emulator

Ask anything your want about Mega/SegaCD programming.

Moderator: Mask of Destiny

Post Reply
Near
Very interested
Posts: 109
Joined: Thu Feb 28, 2008 4:45 pm

Questions on writing a new Mega CD emulator

Post by Near » Thu Apr 25, 2019 1:35 pm

What have I gotten myself into ... so, this'll be long. Lingo: CPU = main-68K, MCD = sub-68k.
I'd really appeciate any help if anyone's up for it! ^-^;;

For some reason, I have both CPUs running and the MCD is even playing the PCM audio correctly for the Mega CD BIOS screen, and the main CPU is running well enough to be able to enter the CD menu, look around at backup RAM (though not this far on Sega CD US BIOS), etc and yet ... I'm not getting any audio from the YM2612. Just silent. I presume if the system were frozen I wouldn't be able to navigate around the BIOS, so what gives with the missing audio? ;_;

I have the APU able to access the CPU bus, which will then access the expansion port mapped to 000000-3fffff, which will get it to the BIOS.

Code: Select all

auto APU::read(uint16 address) -> uint8 {
...
  if(address >= 0x4000 && address <= 0x4003) return ym2612.readStatus();
  if((address & 0x8000) == 0x8000) return cpu.read(Byte, io.bank << 15 | (uint15)address, 0x00);
}
auto APU::write(uint16 address, uint8 data) -> void {
...
  if(address == 0x4000) return ym2612.writeAddress(0 << 8 | data);
  if(address == 0x4001) return ym2612.writeData(data);
  if(address == 0x4002) return ym2612.writeAddress(1 << 8 | data);
  if(address == 0x4003) return ym2612.writeData(data);
  if(address == 0x6000) {  //1-bit shift register
    io.bank = data.bit(0) << 8 | io.bank >> 1;
    return;
  }
  if((address & 0x8000) == 0x8000) {
    return cpu.write(Byte, io.bank << 15 | (uint15)address, data);
  }
}
...

Registers. I presume they are in $a120xx (CPU) and $ff80xx (MCD).
I've seen people say they mirror every $40 bytes and every $200 bytes. That they only map to a120xx/ff80xx or that they map to a12000-a12fff/ff8000-ffffff.

Every emulator seems to implement separate byte/word handlers with missing parts in some. I wanted to emulate it like so:

Code: Select all

auto MCD::external_writeIO(uint1 size, uint24 address, uint16 data) -> void {
  //size 0 == Byte, size 1 == Word
  external_writeIO(address, data.byte(size));
  //I do ^1 here, but basically if size==Word && address&1, we have to throw an address exception
  if(size == Word) external_writeIO(address ^ 1, data.byte(zero));
}
auto MCD::external_writeIO(uint24 address, uint8 data) -> void {
  switch(address) {
  case 0xa12000:
    if(data.bit(0)) irq.external.raise();
    break;

  case 0xa12001:
  ...
Basically, share the code. Is this viable, or are there cases where this just won't work?

---

$a12003 and $ff8003. Oh lord.
d0 = RET
d1 = DMNA
d2 = MODE
Presume MODE=0 for this:
So, the CPU has to write DMNA=1 to give the MCD the WRAM. Picodrive makes a write with d1=1 set DMNA and clear RET.
But the dev manual says instead that writing DMNA will hold it at 1 until the transition has completed.
Similarly, the MCD setting d0=1 sets RET and clears DMNA right away.
It doesn't seem right that the CPU is clearing RET or that MCD is clearing DMNA.
The way it's designed, there doesn't appear to be any purpose to having two bits. If one flips the other always, then DMNA=!RET and RET=!DMNA.
So what's going on? Is this just bypassing emulation of a certain amount of cycles required for a raised bit to take effect?
When the change takes effect, are we really just flipping the other bit? Eg after raising DMNA from the CPU, then RET clears soon after?
So then writing to $a12003.d1=0 or $ff8003.d0=0 are no-ops to DMNA and RET?

Now then MODE=1. The value written to RET now means 0=first 1mbit of WRAM to CPU, second 1mbit to MCD and vice versa.
But now it's not based on having to write a 1-bit. So I guess, writing any value to $ff8003 when MODE=1 will clear DMNA?
If so, does this base itself on the old MODE bit, or the newly written one? I'd assume the latter.
In fact, I'm kind of assuming that perhaps writing to $ff8003 clears DMNA regardless of whether d0 is set or not?

Reading out $a12003 and $ff8003 would be the same for both CPUs.
d1 would be the DMNA state, but d0 doesn't appear to just be the value written to RET.
I can only get the BIOS to not instant lock if I treat d0 differently based on the current MODE:
When MODE=0, d0 = !DMNA, and when MODE=1, d0 = RET.

Unimportant tangent: The dev manual talks about at reset, DMNA==RET==0. It calls it a "neutral state", but doesn't imply what that means. I wonder what'd happen after reset if you never wrote either, could both access the same WRAM with bus conflicts?

...

Interrupt hell time.
Writing $a12000.d0=1 causes a level 2 interrupt. That then sets reading $a12000.d0=1. Does the pending bit clear after read? Guessing not.
Does writing $ff8033.d2=0 cause the interrupt to clear? Gens/GX implies it's needed for Batman Returns, but only does this for level 2 interrupts.
So then what about the others? If a CDC interrupt triggers, it has its pending bit set, and I disable CDC interrupts in $ff8033, then what ... does the pending bit just get stuck on? Or are there two status bits per interrupt, one for pending (eg the state of the line) and one for the readout bits (eg indication that an interrupt occurred)? Does an interrupt even get flagged as pending if it's disabled in $ff8033? I guess it's only really relevant to level 2, since the other interrupts don't have pending states ... except for the CDC.

...

CDC interrupts: these appear to be an amalgamation of four interrupts.
DECI = decoder, DTEI = date transfer end, CMDI = command buffer not empty, SYEIN = sync ... something. It's not documented.
(Tangent: the documentation is so bad. You have to read patents to find info on MBCKRQ as being mode byte check request.)
I don't see any interface to actually write command input bytes, and it seems nobody emulates it or SBOUT. Ah well, I did what I could.
Sanyo docs don't even confirm SBOUT is also an 8-byte FIFO, nor what happens when the FIFO overflows, but whatever. Tangents.
So I presume the CDC interrupt pending bit gets set if any of these four sources are currently sending an interrupt.
But with the CDC, you read STAT3 to clear DECI, read out all bytes in COMIN to clear CMDI, write DTACK to clear DTEI.
So if you clear all the sources, does this drop the parent pending CDC interrupt? Or does the interrupt remain around until it fires?
Because if it doesn't, then it makes CDC interrupts special like level 2 CPU interrupts.

...

CDC: can anyone elaborate more on STAT3.VALST? The official docs say both that VALST=0 means valid regs and VALST=1 means invalid regs.
Gens/GX seems to initialize it to being set. It clears it on cdc_update and clears it on STAT3 reads.

...

CDD: $ff8037.d2, HOCK. "Setting this bit causes communication with the CDD to commence."
I'm sorry that wasn't vague enough, could you be a little less specific?
Does writing to HOCK cause a CDD interrupt to trigger immediately? The BIOS seems to read back $ff8037 and get pissy if you don't set it quickly.
CDD interrupts fire at ~75hz. Okay, so clock rate 12.5MHz/384 (for PCM, stopwatch, timer, etc) then further /434 gets pretty close to 75hz.
Does the CDD clear HOCK every 75hz when it's set? Does it fire an interrupt when HOCK is set? Does the 75hz part care about HOCK at all?
What about writes to $ff408b (CDD command 9)? Does that fire an interrpt? Care about HOCK? Update CDD status 9's checksum?
Does reading $ff8037 clear HOCK?
My emulation of CDD gets stuck on checking disk unless I return tray open 0x5 for the status. Meh.
Is there a datasheet or part# for the CDD? Or is it totally custom and undocumented?

...

Well, I guess this post is long enough. Sure I'll have many more questions though. Haven't even begun work on the CDD, really ._.

Stef
Very interested
Posts: 3131
Joined: Thu Nov 30, 2006 9:46 pm
Location: France - Sevres
Contact:

Re: Questions on writing a new Mega CD emulator

Post by Stef » Thu Apr 25, 2019 2:58 pm

Just a quick reply but generally about port access i tend to think it's better to use the word handlers as default handlers as 68K CPU uses a 16 bit data bus then only return high/low byte on byte access (and of course you need to do the opposite for the Z80). I know it's a bit "wasteful" but that how things work internally aside some exceptions (and so probably less prone to bugs if you want accuracy over speed).

I will try to provide a more complete answer later to your question when i will be able to remember how i did these stuff in Gens (which are probably really broken in some parts) and if i can get back my hands to some some of my notes... but yeah definitely the MCD is a pain to emulate because of the poor documentation (specially the CD hardware / controller part).

Edit: I got a headache just looking for 5 min in my old code from Gens, what a mess... i just don't understand how i got that piece of crap working, the code is so bad. I'm sorry but i'm afraid i won't be able to help you right now but i may give another try later ^^

cero
Very interested
Posts: 338
Joined: Mon Nov 30, 2015 1:55 pm

Re: Questions on writing a new Mega CD emulator

Post by cero » Thu Apr 25, 2019 5:08 pm

(just how many emulators do you have under development at once? :P)
A byuu mcd emu would certainly be welcome, and ease dev for that system.

Near
Very interested
Posts: 109
Joined: Thu Feb 28, 2008 4:45 pm

Re: Questions on writing a new Mega CD emulator

Post by Near » Thu Apr 25, 2019 9:45 pm

Just a quick reply but generally about port access i tend to think it's better to use the word handlers as default handlers as 68K CPU uses a 16 bit data bus then only return high/low byte on byte access
I have been thinking about changing the read/write handlers like so:

Code: Select all

uint16 read(bool uds, bool lds, uint24 address, uint16 data) {  //input data = CPU MDR (open bus, last opcode)
  if(address >= 0x000000 && address <= 0x07ffff) {
    if(uds) data.byte(1) = pram[address ^ 0];  //big endian 16-bit chips
    if(lds) data.byte(0) = pram[address ^ 1];
  }
  return data;
}
Word reads would just set both.
I will try to provide a more complete answer later to your question
Thank you, that will be immensely helpful!
the MCD is a pain to emulate because of the poor documentation (specially the CD hardware / controller part).
I've said it a lot in the past, but this time I think I really will write documentation for this stuff.
Not the least because I really, really need it. Literally have to read datasheets from other CDCs that clone the Sanyo interface and raw patents just to get descriptions of some of these bits.

And that thing the CDC documentation does with the /BIT settings (eg logic low = enable/active, logic high = disable/inactive) is the most maddening thing in the world. Name the damn variables the inverse. If it's /ENABLE then call it DISABLE. It makes it so much more difficult when I have to perform nots on every variable being discussed in ADDITION to remembering what DTEN and DOUTEN map to and what they do. And why there's both ready and busy bits when there doesn't appear to be a way for them to ever desync, even momentarily. Sorry, more ranting >_>
Edit: I got a headache just looking for 5 min in my old code from Gens, what a mess... i just don't understand how i got that piece of crap working, the code is so bad.
I mean, so it's made to run games, and there was no documentation, so without hardware tests you had to guess. And I hear it has 100% compatibility! That's astounding. You did an amazing thing by emulating this system with no documentation *and* no Gens code to look at.

I won't lie, the code is very hard to read. As is Picodrive. And it's made much worse by aiming to be so performant.
Eg the MODE/DMNA/RET stuff has another multiple layers of abstraction through dynamically remapping pointer blocks on writes.
I just pay the small speed hit and will do ram[bank << N | address] on every read instead, which is slower, but much easier to understand.
And I'm an idiot, so if I don't write code I can understand, I can't ever maintain it. And I'll forget any code I haven't touched in a few months.
But again, this code is from so far back, and designed to work on low-power devices, so I understand why it is the way it is.

You and notaz should be very proud of what you created. No judgment here, even if I do complain because I'm too dumb to understand it ^-^;
(just how many emulators do you have under development at once? :P)
It gets hard to classify them (are MSX and MSX2 different systems?), but under the most generous classification (one system = one named machine type), this is my 25th emulator. I also maintain forks of all of them for performance, and yet another fork that sits in the middle of those two for the SNES.

Sik
Very interested
Posts: 939
Joined: Thu Apr 10, 2008 3:03 pm
Contact:

Re: Questions on writing a new Mega CD emulator

Post by Sik » Thu Apr 25, 2019 11:47 pm

byuu wrote:
Thu Apr 25, 2019 9:45 pm
And that thing the CDC documentation does with the /BIT settings (eg logic low = enable/active, logic high = disable/inactive) is the most maddening thing in the world. Name the damn variables the inverse. If it's /ENABLE then call it DISABLE. It makes it so much more difficult when I have to perform nots on every variable being discussed in ADDITION to remembering what DTEN and DOUTEN map to and what they do. And why there's both ready and busy bits when there doesn't appear to be a way for them to ever desync, even momentarily. Sorry, more ranting >_>
Are these pin names or register bits? Because it's extremely common to use low logic (i.e. low = true, high = false), which is what the / means. This is because generally floating pins (if not pulled by a resistor) are usually interpreted as high, so a lot of things use high for the "default" state.

When register bits use low logic for their naming it's a pain tho, yeah (like all those things saying BUSY as low logic instead of READY as high logic).
Sik is pronounced as "seek", not as "sick".

Near
Very interested
Posts: 109
Joined: Thu Feb 28, 2008 4:45 pm

Re: Questions on writing a new Mega CD emulator

Post by Near » Fri Apr 26, 2019 12:22 am

Oh, they're both. And they're not the same either.

The CDC will label both a register bit /FOO and a pin as /FOO, and then document that they actually behave slightly differently.

This chip was designed by sadists.

notaz
Very interested
Posts: 193
Joined: Mon Feb 04, 2008 11:58 pm
Location: Lithuania

Re: Questions on writing a new Mega CD emulator

Post by notaz » Fri Apr 26, 2019 10:51 am

byuu wrote:
Thu Apr 25, 2019 9:45 pm
I won't lie, the code is very hard to read. As is Picodrive. And it's made much worse by aiming to be so performant.
Hey at least I've done C fallbacks for all the ARM asm code.
It's also wrong, you'll inherit bugs if you follow it. That said I don't have any better suggestions for you, and I can't recall the details why it's wrong after > 10 years.
byuu wrote:
Thu Apr 25, 2019 9:45 pm
I just pay the small speed hit and will do ram[bank << N | address] on every read instead, which is slower, but much easier to understand.
Not when the goal is to run full speed on 200MHz ARM9...

Near
Very interested
Posts: 109
Joined: Thu Feb 28, 2008 4:45 pm

Re: Questions on writing a new Mega CD emulator

Post by Near » Fri Apr 26, 2019 1:09 pm

Rewrote all of my bus handling again. New design works pretty well, and models the data bus reads/writes exactly as the real 68K does. And surprisingly no speed penalty. Good optimizer I guess. Been going through years of notes on various forums to implement stuff. *Super* bizarre the Z80 can write to the main 68K's CPU RAM, but not read from it, meh.

So it turns out the Z80 is driving the YM2612, which is where my audio is missing. It hits this routine and dies:

https://github.com/DarkMorford/scd-bios ... g0.z#L1126

(0x1c09) is 0xe3, which calls dereferencePointerTable(0xe3-0xe0), which then loads hl with 0x21dd, which it then jumps to, which is unmapped memory. That byte is written inside of processCommand:

https://github.com/DarkMorford/scd-bios ... g0.z#L1802

But from there, my text editors on FreeBSD were being dumb about opening the trace logs, so I'll have to trace it back elsewhere. And hopefully find a good Sega CD emulator with a Z80 trace logger.
Not when the goal is to run full speed on 200MHz ARM9...
Mother of god. I could, on my best day, probably barely eke out 60fps on a 400MHz with the SNES. But on the Sega CD with 3 CPUs + FM + PSG + PCM + VDP? No chance in hell >_>

Hats off to you.

Sik
Very interested
Posts: 939
Joined: Thu Apr 10, 2008 3:03 pm
Contact:

Re: Questions on writing a new Mega CD emulator

Post by Sik » Sat Apr 27, 2019 2:38 am

byuu wrote:
Fri Apr 26, 2019 1:09 pm
*Super* bizarre the Z80 can write to the main 68K's CPU RAM, but not read from it, meh.
Seems like they tried getting it to work but couldn't fix it in time, from what I recall the problem is that some signals end up with the wrong timing and hence the Z80 ends up seeing garbage? (also don't get fooled, in some of the late revisions the writes also fail — mainly model 3 if I recall correctly)

EDIT: by the way, since you're doing Mega CD… the Z80 can access the word RAM, despite what the docs say (I recall somebody here had tried years ago?). It's possible the docs say otherwise simply to avoid all the headaches from programmers forgetting the part about word RAM being inaccessible when passed over to the sub CPU and then wondering why everything breaks.
Sik is pronounced as "seek", not as "sick".

Eke
Very interested
Posts: 884
Joined: Wed Feb 28, 2007 2:57 pm
Contact:

Re: Questions on writing a new Mega CD emulator

Post by Eke » Sat Apr 27, 2019 8:29 am

I will try to answer some of your questions later since I faced similar interrogations when adding Mega CD support in Genesis Plus GX but regarding pending int being cleared when disabled, that's something that was needed in Genesis Plus GX to fix some games freezing in some cases (hence the comments in the code) but it does not seem it was done in Gens/Picodrive when I looked at their sourcecode. Afaik, it is only needed for int1 (graphics operation) and not the case for int2 (I did it initially for int2 and it broke another game). It seemed logical to me as this interrupt is generated internally by the main ASIC while other interrupts (int4 and int5 at least) are generated by external chips (CDD and CDC respectively) so they can't be cleared from ASIC register (it's possible behavior is similar for timer/int3 interrupt but no games apparently rely on this so I can't confirm).

NB: Looking at your posts, it seems you are confusing Gens and Genesis Plus GX emulators although both are totally unrelated. Genesis Plus GX is based on Genesis Plus from Charles Mac Donald and I added Mega CD support from scratch myself in 2012 or so, using available documentation for most stuff and Gens / Picodrive source code for undocumented stuff (mostly CDD commands and interface protocol but also game specific bugs from code comments). I don't remember having that much difficulties with the documentation (there is one manual with more details but generally mixing infos from the various available sources was good enough, with also some reverse-engineering/wild-guessing at the end for some edge cases), just keep in mind that you don't need to emulate (or understand) every bits of every chips perfectly to achieve 100% compatibility (especially the CDC i.e LC915x chip stuff). If you are interested, here is a backup of my dev diary from back then on googlecode, with some of the issues I faced when advancing, some of them might be similar to the ones you or anyone implementing Sega CD emulation will eventually encounter: https://bitbucket.org/eke/genesis-plus- ... cd-support

See also this thread for some interesting discussions: viewtopic.php?f=5&t=908
Last edited by Eke on Sat Apr 27, 2019 1:02 pm, edited 4 times in total.

Eke
Very interested
Posts: 884
Joined: Wed Feb 28, 2007 2:57 pm
Contact:

Re: Questions on writing a new Mega CD emulator

Post by Eke » Sat Apr 27, 2019 12:30 pm

I've seen people say they mirror every $40 bytes and every $200 bytes. That they only map to a120xx/ff80xx or that they map to a12000-a12fff/ff8000-ffffff.
Main-CPU side was verified by Charles (see viewtopic.php?f=5&t=1276. Afaik, bus arbiter use VA23-VA8 for decoding so it's just a120xx.
On sub-CPU side, this is little different because Sega CD ASIC only get A1-A19 so registers are actually mirrored in xf8xxxx. I don't think the mirroring every $200 bytes was verified but it looks the most logical to only use A1-A8 for optimized hardware design as it covers full register range.
Basically, share the code. Is this viable, or are there cases where this just won't work?
It won't because the bus is 16-bit and many registers must be accessed as 16-bit words only (this is clearly mentionned in software manuals). Note that some registers are byte-only so word-wide access behavior actually depends on the register: sometimes MSB get ignored, sometimes LSB and MSB go to two consecutive 8-bit registers... and sometimes you have strange effect if you write a read-only register (CPU communication flags registers for example, which share consecutive addresses, it seems the ASIC is ignoring UDS/LDS on sub-CPU side so you end up with different behavior between word-wide and byte-wide writes).
So what's going on? Is this just bypassing emulation of a certain amount of cycles required for a raised bit to take effect?When the change takes effect, are we really just flipping the other bit? Eg after raising DMNA from the CPU, then RET clears soon after?
So then writing to $a12003.d1=0 or $ff8003.d0=0 are no-ops to DMNA and RET?
Yes, the clear is handled by hardware after the other bit has been set and there is likely a little delay on real hardware but it is not required by any games as they usually just poll until bit is cleared before accessing word-ram so better not emulate this than emulating it wrong (I don't think the delay on each sides was ever documented). Also keep in mind RET bit is only writable on Sub-CPU side and DMNA bit is only writable on Main-CPU side (this is clearly indicated in software manuals).
Now then MODE=1. The value written to RET now means 0=first 1mbit of WRAM to CPU, second 1mbit to MCD and vice versa.
But now it's not based on having to write a 1-bit. So I guess, writing any value to $ff8003 when MODE=1 will clear DMNA?
If so, does this base itself on the old MODE bit, or the newly written one? I'd assume the latter.
In fact, I'm kind of assuming that perhaps writing to $ff8003 clears DMNA regardless of whether d0 is set or not?
In 1M mode, only RET bit (and therefore Sub-CPU) can switch Word-RAM banks mapping, DMNA is just a command bit used by Main-CPU to tell Sub-CPU to switch banks. Contrary to what the manuals seem to imply (it is only briefly explained properly at one place in one of the manuals so it's easy to miss it), you actually need to write 0 to that bit from Main-CPU software to set the DMNA bit to 1 on Main-CPU and Sub-CPU side (on read). This can be used to request Sub-CPU to make the switch through RET bit switching. DMNA bit is reset to 0 by hardware after it has finished bank switching (again with some delay but no games are relying on switching latency, they just poll DMNA bit until it is set to 0).

As for MODE bit, I think it takes priority over RET bit (also remember it is writable on Sub-CPU side only, and DMNA bit is not modified on writes from Sub-CPU anyway) but I don't think any games attempt to modify both bits together.

Note that there are some undocumented stuff regarding the word-RAM assignment when MODE bit is switched to 2M, depending on the last value written to DMNA or RET bits on either sides during 1M mode, this is pretty summarized explained in one of the thread of this sub-forum by TascoDlx and is also documented in my GPGX source code comments (mem68k.c implements Main-CPU side function handlers, scd.c implements Sub-CPU side)

Unimportant tangent: The dev manual talks about at reset, DMNA==RET==0. It calls it a "neutral state", but doesn't imply what that means. I wonder what'd happen after reset if you never wrote either, could both access the same WRAM with bus conflicts?
The manual implies this is a temporary state, which means that, after a few cycles (nothing known about this one either and probably not visible from software), reset state is stabilized. The manual indicates initial state for this register is 0001h, which means 2M mode with Word-RAM assigned to Main-CPU.

Eke
Very interested
Posts: 884
Joined: Wed Feb 28, 2007 2:57 pm
Contact:

Re: Questions on writing a new Mega CD emulator

Post by Eke » Sat Apr 27, 2019 8:48 pm

Now, about CDC
CDC interrupts: these appear to be an amalgamation of four interrupts.
DECI = decoder, DTEI = date transfer end, CMDI = command buffer not empty, SYEIN = sync ... something. It's not documented.
I don't know anything about the later or where you get that from but I doubt it exists, IFSTAT/IFCTRL registers description in LC8951 user manual only describe 3 source of interrupts.
You can safely ignore CMD interrupt since Command register is unused by BIOS (Sega CD ASIC is both 'Host Computer' and 'System Controller' for the CDC so it has no need for command/status words) and unusable anyway (neither /CMD or /HWR inputs are connected in Mega CD according to service manuals).
DECI is triggered after each 2352 bytes sectors is decoded (when decoder is enabled).
DTEI is triggered at the end of a data transfer (either done through DMA or directly by CPU through CDC host data register read (FF8008h) when all bytes have been transfered.
(Tangent: the documentation is so bad. You have to read patents to find info on MBCKRQ as being mode byte check request.)
The documentation is 'so bad' because it is missing ONE bit description? C'mon... I would argue that the LC5951 user manual we have (which also seems to come from Sega official devkits) is very complete, detailled, comprehensive (chapter 12 in particular explains a lot how registers and interfaces are used) and without much (if any) errors. Also, as said before, you don't need to emulate every bits of every control registers for Mega CD emulation , only those used by BIOS and meaningful to the CD modes supported by Mega CD hardware. I had never heard about that patent personally.
I don't see any interface to actually write command input bytes, and it seems nobody emulates it or SBOUT. Ah well, I did what I could.
Sanyo docs don't even confirm SBOUT is also an 8-byte FIFO, nor what happens when the FIFO overflows, but whatever. Tangents.
As said above, required signals are not connected in Mega CD hardware so you can safely ignore this for Mega CD emulation. That said, chapter 12.1 in LC8951 user manual explicitely states that command writes are ignored once FIFO is full.
So if you clear all the sources, does this drop the parent pending CDC interrupt? Or does the interrupt remain around until it fires?
Because if it doesn't, then it makes CDC interrupts special like level 2 CPU interrupts.
If all interrupt sources within CDC get cleared (or disabled), the /INT output which is connected to main ASIC is set high so interrupt decoder within the ASIC will not generate INT5 interrupt anymore. Things are (presumaly) different for interrupts for which the source is internal to ASIC (gfx and timer interrupts) and not stored in a register (like main CPU interrupt).
can anyone elaborate more on STAT3.VALST? The official docs say both that VALST=0 means valid regs and VALST=1 means invalid regs.
Gens/GX seems to initialize it to being set. It clears it on cdc_update and clears it on STAT3 reads.
LC8951 user manual says that this bit is cleared when the decoder interrupt occurs (once the current data block has been fully decoded) then reset to 1 just before internal sync (which corresponds to the start of decoding of the next block). VALST=1 on reset because decoder is disabled by default. I don't emulate the reset behavior while next sector is decoded because it is not required and the timing seem to differ among LC591x models and apparently depend on the decoding mode (making emulation of this both complicated and useless).

Stef
Very interested
Posts: 3131
Joined: Thu Nov 30, 2006 9:46 pm
Location: France - Sevres
Contact:

Re: Questions on writing a new Mega CD emulator

Post by Stef » Sat Apr 27, 2019 9:15 pm

Oh it looks like Eke gave you almost all the important information :)
I remember now i had some hard time first with the DMNA / RET bit, just because i didn't understood than DMNA is control from m68K (request) where the RET bit is control from sub68k (request). I think i had to emulate the small delay for request done (or at least to fake it for a game, i think it's Mortal Kombat). For the interrupts indeed i don't remember that i needed to clear pending interrupt..
Ah yeah something important is about CPU sync, back in time we used to emulate CPU by scanline loop (so about 488 m68k cycles, 227 Z80 cycles...) and obviously for Sega CD i needed to reduce cycles chunck to allow better sync between the m68k and sub68k but i assume that won't be a problem for you as you are almost synching everything at master cycle level ;)

I found a very old document i wrote when i started to reverse engineering how CDD worked, unfortunately it's an early version of the document and i thing you can get much more info just browsing emulator sources but can still be useful:
https://www.dropbox.com/s/temebfgcog1fa ... f.txt?dl=0

Eke
Very interested
Posts: 884
Joined: Wed Feb 28, 2007 2:57 pm
Contact:

Re: Questions on writing a new Mega CD emulator

Post by Eke » Sat Apr 27, 2019 10:45 pm

Lastly, about CDD...
: $ff8037.d2, HOCK. "Setting this bit causes communication with the CDD to commence."
I'm sorry that wasn't vague enough, could you be a little less specific?
You have to understand that this register is not supposed to be used by game software developers for which those manuals were intended, only BIOS is supposed to touch it. I'm sure in-house BIOS developers had full CDD interface documentation (including access to sourcecode of this 4-bit micro-controller program).
Looking at available service manuals, you can see that there is a signal going from main ASIC to CDD micro-controller called HOCK and another coming from CDD called CDCK and that both are clock signals used to synchronize main ASIC and CDD during the exchange of status and command words so very likely this bit makes Mega CD ASIC starts generating HOCK signal and receiving CDD status words in associated registers.
Does writing to HOCK cause a CDD interrupt to trigger immediately? The BIOS seems to read back $ff8037 and get pissy if you don't set it quickly.
Yes, that is also what I figured myself. According to the software and service manuals, interrupt is triggered by CDD after it sent the 7th status word so logically, if switching HOCK bit to 1 starts reception of CDD status words, CDD interrupt is triggered shortly after that. In GPGX, I trigger it immediately because the timing is unknown (only the time between two status reception sequence is known) and BIOS is fine with it.
CDD interrupts fire at ~75hz. Okay, so clock rate 12.5MHz/384 (for PCM, stopwatch, timer, etc) then further /434 gets pretty close to 75hz.
CDD clock is not derived from Mega CD master clock (50 MHz) but use a separated oscillator (used by the rest of the CXA chips on CD board that are generally not emulated like CD-DSP, etc but also by CDD for block decoding) clocked at ~16MHz. CDD interrupt is generated using programmed timers within the micro-controller but it's safe to assume it's exactly 75Hz period as it also corresponds to the decoding period of one CD sector and the length of one CD audio frame (1/75 s).
Does the CDD clear HOCK every 75hz when it's set?
I think I've seen Gens (and maybe Picodrive as well) sourcecode doing this but I don't think it's true. First, the CDD has no way to stop that clock signal which is generated by the main ASIC and secondly, I don't think I have seen the BIOS setting this bit back to 1 except after a reset (power-on or internal reset). I left this bit set once set by sub-CPU and only clears it on reset and it works fine.
Does it fire an interrupt when HOCK is set? Does the 75hz part care about HOCK at all?
See above. That bit enables generation of clock signal used to synchronize communication with CDD and receive CDD status, which itself generate CDD interrupt. Very likely, when this bit is cleared, CDD interrupt does not occur anymore. That is not exactly how I emulate it because I only update CDD status once the last CDD command register has been written but it does not make and difference as the BIOS only updates CDD command registers once HOCK bit has been set and CDD interrupt has been processed, then never clears that bit.

EDIT: looking at Mega CD 1 service manual (there are some pages in Japanese describing signal interfaces that would need to be translated but figures are somehow explicit), int4 is not directly triggered by CDD chip but instead the /IRQ output pin of CDD is used to tell Mega CD ASIC to initiate a new status /command exchange sequence (through HOCK and CDCK clock signals) and it's the CDD interface in Mega CD ASIC which asserts an interrupt request to interrupt priority controller once the first seven status words have been stored in associated registers.
What about writes to $ff408b (CDD command 9)? Does that fire an interrpt? Care about HOCK? Update CDD status 9's checksum?
Writes to CDD command 9 only starts transfer of command words to CDD (still using HOCK and CDCK signals for synchronization so HOCK bit likely needs to remain set). Presumaly, CDD waits for the command words processing before sending next status words sequence so CDD interrupt would not occur if command word 9 is not written anymore (not sure about this one but this is how it is emulated and it does not cause issues) although technically it is the receiving of next status word 7 which triggers the interrupt, not the setting of command words 9.
As for CDD status checksum, it is part of status words sent by CDD, it is just that the interrupt occurs shortly before the last word for some reason, maybe to take care of interrupt latency?
In an emulator, you can process CDD status immediately after the last command word is written, so that status registers are updated when the next interrupt occurs, because again, these registers are only read by BIOS, in interrupt handler.
Does reading $ff8037 clear HOCK?
I don't think so, this would have no purpose, it's not a refresh or ack bit that is switched by hardware, it's a command bit.
My emulation of CDD gets stuck on checking disk unless I return tray open 0x5 for the status. Meh.
Is there a datasheet or part# for the CDD? Or is it totally custom and undocumented?
It is partially custom (4-bit known micro-controller with unknown programmable ROM) and only partially documented:
- pinout can be seen in service manuals and can help understanding how it works / interfaces with the rest of the system
- CDD command/status words format was partially reverse-engineered, with enough information to get all games running.
There is also some good information in X-Eye technical manuals that appeared recently, see this thread: viewtopic.php?f=5&t=2707
Last edited by Eke on Tue Apr 30, 2019 8:07 am, edited 3 times in total.

TmEE co.(TM)
Very interested
Posts: 2440
Joined: Tue Dec 05, 2006 1:37 pm
Location: Estonia, Rapla City
Contact:

Re: Questions on writing a new Mega CD emulator

Post by TmEE co.(TM) » Sat Apr 27, 2019 11:01 pm

The CD section clock is 44100 * 384 = 16934400Hz
Mida sa loed ? Nagunii aru ei saa ;)
http://www.tmeeco.eu
Files of all broken links and images of mine are found here : http://www.tmeeco.eu/FileDen

Post Reply