summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author grantek <gk_gh@grantekinc.net>2022-08-18 10:54:08 +1000
committer GitHub <noreply@github.com>2022-08-17 20:54:08 -0400
commitaa2c20398e4da2336b64776202b7439ac68808a2 (patch)
tree8c9ed7ecf113f8635a0e5aa2b442cca4bb39e1cd
parentfbf2f3e394f74d13d299220dd62aa71a919bb57b (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.cpp61
-rw-r--r--src/devices/machine/8530scc.h1
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);