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:
...
---
$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 ._.