Here are a few more things I've found out about the YM2612 over the last few days:
1. Status registers
The YM2608 manual describes 3 separate status registers that can be read. Significantly, one of them reportedly returns an ID number for the chip, when the status register is read while register location $FF is latched. After testing, I can confirm that this does not apply to the YM2612. The normal status register appears to be returned from the YM2612 under all circumstances, regardless of the address the YM2612 is being read from (part 1 address/data or part 2 address/data), or the register that is latched at the time the status register is read.
2. Prescaler registers
The YM2608 manual describes registers $2D, $2E, and $2F as prescaler register addresses, which reportedly simply latching will adjust the multipliers used to calculate the internal clock for the FM generator. This does not seem to exist in the YM2612. Latching or writing to these registers had no noticeable effect.
3. Interrupts
I've conducted a full set of tests on the behaviour of the interrupt (INT) line of the YM2612. Even though it's not connected in the Mega Drive, it's still a functional part of the YM2612, and for the sake of completeness if nothing else, I wanted to confirm how it operated. Emulators like MAME could make use of this info too.
First and foremost, I've confirmed that interrupt control flags for the YM2608 in register $29 do not exist on the YM2608.
The interrupt line can be triggered by either Timer A or Timer B. Using the terms applied in the YM2608 manual, when a timer is "loaded" (bits 0 and 1 of reg $27), it starts with a number loaded into it as specified in the counter registers for each timer, and will count down at a regular rate, until it tries to count down from 0 and overflows. At this time, it will re-load the counter. What else happens as a result of a timer overflowing depends on the setting of the "enable" flag (bits 2 and 3 of reg $27). As described in the documentation, when the enable bit is set and the timer overflows, it will set the overflow flag for that timer in the status register, and trigger an interrupt.
And now for the new stuff. Although not mentioned in the documentation, the reset flag directly affects interrupt generation. When a timer overflows, the YM2612 checks the current state of the timer overflow bit for that timer in the status register. The YM2612 will only generate an interrupt for that timer if the overflow bit is currently unset. If the overflow bit is unset, and the enable flag is set in the timer control register, the INT line will be asserted. The INT line will remain asserted, until the reset bit for that timer is set to 1 in the timer control register, or until the timer overflows again. If the reset bit for the timer is cleared at any time, the interrupt line will immediately be negated. If the timer overflows while INT is still asserted, that is, without reset being written to, the interrupt line will immediately be negated. From this point on, no interrupts will be generated for that timer until the reset bit is set. Once the reset bit has been set when an interrupt has been missed, the INT line will not immediately be asserted. The INT line will remain negated until the timer overflows again.
This means in order to use the YM2612 interrupt line, the interrupt handler must always write the reset bit for that timer before exiting the interrupt handler. This tells the YM2612 to stop asserting the INT line for that timer, and prepares the YM2612 to trigger another interrupt when the timer overflows again. Additionally, in periods where the YM2612 interrupt is masked, it may be possible for a YM2612 interrupt to be missed, requiring the reset bit to be written in order to resume interrupt generation. The overflow bit in the status register would allow missed interrupts to be detected. The overflow bit should only be asserted in the interrupt handler where YM2612 interrupts are being used, as the overflow bit is set at the same time as the interrupt is generated, and the reset operation when leaving the interrupt handler clears this flag.
Sorry if that's confusing. It's easier to understand when you're just looking at the oscilloscope. I might put some pictures up for this later on. I'm not sure that I explained this very well.
4. Timers
Two things here. First of all, I've tested the timer A registers, and confirmed that they are NOT "ganged together" like the frequency registers are. Changes to either register $24 or $25 affect Timer A the next time it overflows or is loaded, regardless of the order the registers are written to.
Secondly, I've confirmed the timer periods in the YM2612 are half the rate of the timers described in the YM2608 documentation, or in other words, the YM2612 timers take twice as long to count down as the timers in the YM2608. Here are the formulae to calculate the correct timer periods for the YM2612:
Code: Select all
To calculate Timer A period in microseconds:
TimerA = 144 * (1024 - NA) / M
NA: 0~1023
M: Master clock (MHz)
Eg, where clock = 7.61Mhz
TimerA(MAX) = 144 * (1024 - 0) / 7.61 = 19376.61 microseconds
TimerA(MIN) = 144 * (1024 - 1023) / 7.61 = 18.92 microseconds
To calculate Timer B period in microseconds:
TimerB = (144*16) * (256 - NA) / M
NB: 0~255
M: Master clock (MHz)
Eg, where clock = 7.61Mhz
TimerB(MAX) = (144*16) * (256 - 0) / 7.61 = 77506.44 microseconds
TimerB(MIN) = (144*16) * (256 - 255) / 7.61 = 302.76 microseconds
I think that's about it so far. I'm finding so many bits out about this chip that I probably will end up compiling it all into a "YM2612 Undocumented" reference of some kind, at some point in the future.
As for what's still to come, I'm making very significant progress on SSG-EG. I hope to have a full description of SSG-EG completed within the next few days, so that should be of interest to some people. I also plan to revisit the detune overflow bug as well, as I haven't got all the needed info in order to emulate that correctly yet.