mirror of
https://github.com/holub/mame
synced 2025-06-16 17:29:27 +03:00
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.
This commit is contained in:
parent
fbf2f3e394
commit
aa2c20398e
@ -110,6 +110,36 @@ void scc8530_legacy_device::resetchannel(int ch)
|
|||||||
channel[ch].baudtimer->adjust(attotime::never, ch);
|
channel[ch].baudtimer->adjust(attotime::never, ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
updatebaudtimer - baud rate timer calculation
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
void scc8530_legacy_device::updatebaudtimer(int ch)
|
||||||
|
{
|
||||||
|
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];
|
||||||
|
|
||||||
|
// Clock Mode is 1x, 16x, 32x, or 64x
|
||||||
|
int clockmode = pChan->reg_val[4] >> 6;
|
||||||
|
int clockrate = 1;
|
||||||
|
if (clockmode)
|
||||||
|
{
|
||||||
|
clockrate = 8 << clockmode;
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
baud_expire - baud rate timer expiry
|
||||||
-------------------------------------------------*/
|
-------------------------------------------------*/
|
||||||
@ -117,16 +147,8 @@ void scc8530_legacy_device::resetchannel(int ch)
|
|||||||
TIMER_CALLBACK_MEMBER(scc8530_legacy_device::baud_expire)
|
TIMER_CALLBACK_MEMBER(scc8530_legacy_device::baud_expire)
|
||||||
{
|
{
|
||||||
Chan *pChan = &channel[param];
|
Chan *pChan = &channel[param];
|
||||||
int brconst = pChan->reg_val[13] << 8 | pChan->reg_val[14];
|
|
||||||
int rate = 0;
|
|
||||||
|
|
||||||
if (brconst)
|
// always flag IRQ pending in case baud IRQ is enabled after this
|
||||||
{
|
|
||||||
rate = clock() / brconst;
|
|
||||||
}
|
|
||||||
|
|
||||||
// is baud counter IRQ enabled on this channel?
|
|
||||||
// always flag pending in case it's enabled after this
|
|
||||||
pChan->baudIRQPending = 1;
|
pChan->baudIRQPending = 1;
|
||||||
if (pChan->baudIRQEnable)
|
if (pChan->baudIRQEnable)
|
||||||
{
|
{
|
||||||
@ -137,17 +159,7 @@ TIMER_CALLBACK_MEMBER(scc8530_legacy_device::baud_expire)
|
|||||||
updateirqs();
|
updateirqs();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
updatebaudtimer(param);
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------
|
/*-------------------------------------------------
|
||||||
@ -213,7 +225,6 @@ void scc8530_legacy_device::acknowledge()
|
|||||||
|
|
||||||
uint8_t scc8530_legacy_device::getareg()
|
uint8_t scc8530_legacy_device::getareg()
|
||||||
{
|
{
|
||||||
/* Not yet implemented */
|
|
||||||
#if LOG_SCC
|
#if LOG_SCC
|
||||||
printf("SCC: port A reg %d read 0x%02x\n", reg, channel[0].reg_val[reg]);
|
printf("SCC: port A reg %d read 0x%02x\n", reg, channel[0].reg_val[reg]);
|
||||||
#endif
|
#endif
|
||||||
@ -392,13 +403,7 @@ void scc8530_legacy_device::putreg(int ch, uint8_t data)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 14: // misc control bits
|
case 14: // misc control bits
|
||||||
if (data & 0x01) // baud rate generator enable?
|
updatebaudtimer(ch);
|
||||||
{
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 15: // external/status interrupt control
|
case 15: // external/status interrupt control
|
||||||
|
@ -86,6 +86,7 @@ private:
|
|||||||
|
|
||||||
devcb_write_line intrq_cb;
|
devcb_write_line intrq_cb;
|
||||||
|
|
||||||
|
void updatebaudtimer(int ch);
|
||||||
void updateirqs();
|
void updateirqs();
|
||||||
void initchannel(int ch);
|
void initchannel(int ch);
|
||||||
void resetchannel(int ch);
|
void resetchannel(int ch);
|
||||||
|
Loading…
Reference in New Issue
Block a user