aaronsgiles / ymfm

BSD-licensed Yamaha FM sound cores (OPM, OPN, OPL, and others)
BSD 3-Clause "New" or "Revised" License
259 stars 40 forks source link

restoring OPZ susL/relR etc overrides by responding to reg 0x08 writes #54

Open jariseon opened 1 year ago

jariseon commented 1 year ago

Hi Aaron and many thanks for a great library. i debugged TX81Z IRQ1 code using MAME to find out what's going on with the fastChannelMute overrides. replacing the current preset caching code in opz_registers::write() with the snippet below might do the trick:

// firmware writes to 0x08 to request a fast and graceful channel mute
if (index == 0x08)
{
   int chan = bitfield(data, 0, 3);

   // wait for EG_QUIETs on chan operators, or do this right away:
   const uint8_t STATUS_CHAN_FREE = 0x20;       // chan is available for a new kon
   uint8_t status = STATUS_CHAN_FREE | (chan << 2);
   m_fm.set_reset_status(status, ~status);          // assert IRQ line (??)
}
// tx81z then responds by restoring the overridden reg states
// after that is done, the firmware acks the IRQ by setting reg 0x14 bit 6:
else if (index == 0x14 && (data & 0x40)) {}         // reset chip's irq state here

i was unable to validate the logic with ymfm and MAME (and i don't have docs to support the claim), but a similar dance works in my custom emulation framework. sorry for not creating a proper PR, unsure if set_reset_status() is enough to raise a host mcu irq.

the idea is thus to assert the IRQ line upon receiving a reg 0x08 write, and then return (0x20 | (chan << 2)) when the firmware reads chip's status reg as a response. after receiving reg 0x14.bit6 ack, ~(0x20 | (chan << 2)) should be anded with the status reg to clear the internal irq state. pls let me know if the above is unclear :)

finally, tx81z may generate multiple reg 0x08 writes in series when it turns all notes off, or when there's a chord. that may require further irq stacking logic. in any case, the firmware seems to rely on 6303 timers instead of OPZ ones as it only reacts to opz status reg bit5 on. 6303 CMI and OCI timer irqs seem to provide control rate pitch/amp modulation and effects ticking, respectively, but iiuc those lines are unwired in ymtx81z.cpp driver. IRQ1 handler is at hi bank offset 0x8ff6. hope this makes sense.