diff options
author | 2022-08-18 10:54:08 +1000 | |
---|---|---|
committer | 2022-08-17 20:54:08 -0400 | |
commit | aa2c20398e4da2336b64776202b7439ac68808a2 (patch) | |
tree | 8c9ed7ecf113f8635a0e5aa2b442cca4bb39e1cd | |
parent | fbf2f3e394f74d13d299220dd62aa71a919bb57b (diff) |
Implement SCC baud rate calculation (#10181)
- Also fix baud counter registers
Reference: http://www.zilog.com/docs/serial/ps0117.pdf
The X68000 uses the Clock Mode feature of the SCC, which multiplies the baud period by 16. Combined with a bug that read the baud counter from the wrong registers, this meant the emulator had two baud rate expiry callbacks running at some MHz.
-rw-r--r-- | src/devices/machine/8530scc.cpp | 61 | ||||
-rw-r--r-- | src/devices/machine/8530scc.h | 1 |
2 files changed, 34 insertions, 28 deletions
diff --git a/src/devices/machine/8530scc.cpp b/src/devices/machine/8530scc.cpp index a2e066500e3..7438ccce738 100644 --- a/src/devices/machine/8530scc.cpp +++ b/src/devices/machine/8530scc.cpp @@ -111,22 +111,44 @@ void scc8530_legacy_device::resetchannel(int ch) } /*------------------------------------------------- - baud_expire - baud rate timer expiry + updatebaudtimer - baud rate timer calculation -------------------------------------------------*/ -TIMER_CALLBACK_MEMBER(scc8530_legacy_device::baud_expire) +void scc8530_legacy_device::updatebaudtimer(int ch) { - Chan *pChan = &channel[param]; - int brconst = pChan->reg_val[13] << 8 | pChan->reg_val[14]; - int rate = 0; + Chan *pChan = &channel[ch]; + // BR Generator Enable + if(!BIT(pChan->reg_val[14], 0)) + { + pChan->baudtimer->adjust(attotime::never, ch, attotime::never); + return; + } + + // BR Time Constant + int brconst = pChan->reg_val[13] << 8 | pChan->reg_val[12]; - if (brconst) + // Clock Mode is 1x, 16x, 32x, or 64x + int clockmode = pChan->reg_val[4] >> 6; + int clockrate = 1; + if (clockmode) { - rate = clock() / brconst; + clockrate = 8 << clockmode; } - // is baud counter IRQ enabled on this channel? - // always flag pending in case it's enabled after this + int baudrate = clock() / ((brconst + 2) * 2 * clockrate); + attotime attorate = attotime::from_hz(baudrate); + pChan->baudtimer->adjust(attorate, ch, attorate); +} + +/*------------------------------------------------- + baud_expire - baud rate timer expiry +-------------------------------------------------*/ + +TIMER_CALLBACK_MEMBER(scc8530_legacy_device::baud_expire) +{ + Chan *pChan = &channel[param]; + + // always flag IRQ pending in case baud IRQ is enabled after this pChan->baudIRQPending = 1; if (pChan->baudIRQEnable) { @@ -137,17 +159,7 @@ TIMER_CALLBACK_MEMBER(scc8530_legacy_device::baud_expire) updateirqs(); } } - - // reset timer according to current register values - if (rate) - { - attotime attorate = attotime::from_hz(rate); - channel[param].baudtimer->adjust(attorate, param, attorate); - } - else - { - channel[param].baudtimer->adjust(attotime::never, param, attotime::never); - } + updatebaudtimer(param); } /*------------------------------------------------- @@ -213,7 +225,6 @@ void scc8530_legacy_device::acknowledge() uint8_t scc8530_legacy_device::getareg() { - /* Not yet implemented */ #if LOG_SCC printf("SCC: port A reg %d read 0x%02x\n", reg, channel[0].reg_val[reg]); #endif @@ -392,13 +403,7 @@ void scc8530_legacy_device::putreg(int ch, uint8_t data) break; case 14: // misc control bits - if (data & 0x01) // baud rate generator enable? - { - int brconst = pChan->reg_val[13]<<8 | pChan->reg_val[14]; - int rate = clock() / brconst; - - pChan->baudtimer->adjust(attotime::from_hz(rate), 0, attotime::from_hz(rate)); - } + updatebaudtimer(ch); break; case 15: // external/status interrupt control diff --git a/src/devices/machine/8530scc.h b/src/devices/machine/8530scc.h index fb1045861be..e4af88b3e97 100644 --- a/src/devices/machine/8530scc.h +++ b/src/devices/machine/8530scc.h @@ -86,6 +86,7 @@ private: devcb_write_line intrq_cb; + void updatebaudtimer(int ch); void updateirqs(); void initchannel(int ch); void resetchannel(int ch); |