mirror of
https://github.com/holub/mame
synced 2025-04-21 07:52:35 +03:00
hd6301x, hd6301y & derivatives: Updates to internal peripheral emulation
- Add Timer 2 and its associated interrupt and allow it to clock the serial port - Change divider for external serial clock to 16 - Remove timer hack in supremo
This commit is contained in:
parent
9e0e9fb978
commit
c137f89f86
@ -118,7 +118,7 @@ void epson_pf10_device::device_start()
|
||||
|
||||
void epson_pf10_device::device_reset()
|
||||
{
|
||||
m_timer->adjust(attotime::zero, 0, attotime::from_hz(38400 * 8));
|
||||
m_timer->adjust(attotime::zero, 0, attotime::from_hz(38400 * 16));
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
|
@ -82,6 +82,7 @@ enum
|
||||
#define TAKE_OCI enter_interrupt("take OCI\n",0xfff4)
|
||||
#define TAKE_TOI enter_interrupt("take TOI\n",0xfff2)
|
||||
#define TAKE_SCI enter_interrupt("take SCI\n",0xfff0)
|
||||
#define TAKE_CMI enter_interrupt("take CMI\n",0xffec)
|
||||
|
||||
/* mnemonics for the Timer Control and Status Register bits */
|
||||
#define TCSR_OLVL 0x01
|
||||
@ -276,9 +277,9 @@ void hd6301x_cpu_device::hd6301x_io(address_map &map)
|
||||
map(0x0018, 0x0018).rw(FUNC(hd6301x_cpu_device::p7_data_r), FUNC(hd6301x_cpu_device::p7_data_w)); // TODO: external except in single-chip mode
|
||||
map(0x0019, 0x0019).rw(FUNC(hd6301x_cpu_device::ocr2h_r), FUNC(hd6301x_cpu_device::ocr2h_w));
|
||||
map(0x001a, 0x001a).rw(FUNC(hd6301x_cpu_device::ocr2l_r), FUNC(hd6301x_cpu_device::ocr2l_w));
|
||||
//map(0x001b, 0x001b).rw(FUNC(hd6301x_cpu_device::tcsr3_r), FUNC(hd6301x_cpu_device::tcsr3_w));
|
||||
//map(0x001c, 0x001c).rw(FUNC(hd6301x_cpu_device::ff_r), FUNC(hd6301x_cpu_device::tconr_w));
|
||||
//map(0x001d, 0x001d).rw(FUNC(hd6301x_cpu_device::t2cnt_r), FUNC(hd6301x_cpu_device::t2cnt_w));
|
||||
map(0x001b, 0x001b).rw(FUNC(hd6301x_cpu_device::tcsr3_r), FUNC(hd6301x_cpu_device::tcsr3_w));
|
||||
map(0x001c, 0x001c).rw(FUNC(hd6301x_cpu_device::ff_r), FUNC(hd6301x_cpu_device::tconr_w));
|
||||
map(0x001d, 0x001d).rw(FUNC(hd6301x_cpu_device::t2cnt_r), FUNC(hd6301x_cpu_device::t2cnt_w));
|
||||
//map(0x001f, 0x001f).rw(FUNC(hd6301x_cpu_device::tstreg_r), FUNC(hd6301x_cpu_device::tstreg_w));
|
||||
}
|
||||
|
||||
@ -318,6 +319,7 @@ m6801_cpu_device::m6801_cpu_device(const machine_config &mconfig, device_type ty
|
||||
, m_out_port_func(*this)
|
||||
, m_out_sc2_func(*this)
|
||||
, m_out_sertx_func(*this)
|
||||
, m_sclk_divider(8)
|
||||
{
|
||||
}
|
||||
|
||||
@ -356,6 +358,7 @@ hd6301x_cpu_device::hd6301x_cpu_device(const machine_config &mconfig, device_typ
|
||||
, m_in_portx_func(*this)
|
||||
, m_out_portx_func(*this)
|
||||
{
|
||||
m_sclk_divider = 16;
|
||||
}
|
||||
|
||||
hd6301x0_cpu_device::hd6301x0_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
@ -433,6 +436,10 @@ void hd6301x_cpu_device::m6800_check_irq2()
|
||||
{
|
||||
TAKE_TOI;
|
||||
}
|
||||
else if ((m_tcsr3 & 0xc0) == 0xc0)
|
||||
{
|
||||
TAKE_CMI;
|
||||
}
|
||||
else if (((m_trcsr & (M6801_TRCSR_RIE|M6801_TRCSR_RDRF)) == (M6801_TRCSR_RIE|M6801_TRCSR_RDRF)) ||
|
||||
((m_trcsr & (M6801_TRCSR_RIE|M6801_TRCSR_ORFE)) == (M6801_TRCSR_RIE|M6801_TRCSR_ORFE)) ||
|
||||
((m_trcsr & (M6801_TRCSR_TIE|M6801_TRCSR_TDRE)) == (M6801_TRCSR_TIE|M6801_TRCSR_TDRE)))
|
||||
@ -572,7 +579,7 @@ void hd6301x_cpu_device::check_timer_event()
|
||||
modified_tcsr();
|
||||
}
|
||||
|
||||
if (m_irq2 & (TCSR_OCF | TCSR_TOF))
|
||||
if ((m_irq2 & (TCSR_OCF | TCSR_TOF)) || (m_tcsr3 & 0xc0) == 0xc0)
|
||||
{
|
||||
if (m_wai_state & M6800_SLP)
|
||||
m_wai_state &= ~M6800_SLP;
|
||||
@ -591,6 +598,40 @@ void m6801_cpu_device::increment_counter(int amount)
|
||||
check_timer_event();
|
||||
}
|
||||
|
||||
void hd6301x_cpu_device::increment_counter(int amount)
|
||||
{
|
||||
m6800_cpu_device::increment_counter(amount);
|
||||
if (m_t2cnt_written)
|
||||
m_t2cnt_written = false;
|
||||
else if (BIT(m_tcsr3, 4))
|
||||
{
|
||||
switch (m_tcsr3 & 0x03)
|
||||
{
|
||||
case 0x00:
|
||||
// Timer 2 input = E clock
|
||||
increment_t2cnt(amount);
|
||||
break;
|
||||
|
||||
case 0x01:
|
||||
// Timer 2 input = E clock/8
|
||||
increment_t2cnt((amount + (CTD & 0x0007)) >> 3);
|
||||
break;
|
||||
|
||||
case 0x02:
|
||||
// Timer 2 input = E clock/128
|
||||
increment_t2cnt((amount + (CTD & 0x007f)) >> 7);
|
||||
break;
|
||||
|
||||
case 0x03:
|
||||
// Timer 2 input = external Tclk
|
||||
break;
|
||||
}
|
||||
}
|
||||
CTD += amount;
|
||||
if (CTD >= m_timer_next || (m_tcsr3 & 0xc0) == 0xc0)
|
||||
check_timer_event();
|
||||
}
|
||||
|
||||
void m6801_cpu_device::EAT_CYCLES()
|
||||
{
|
||||
int cycles_to_eat = std::min(int(m_timer_next - CTD), m_icount);
|
||||
@ -648,6 +689,44 @@ void m6801_cpu_device::set_rmcr(uint8_t data)
|
||||
}
|
||||
}
|
||||
|
||||
void hd6301x_cpu_device::set_rmcr(uint8_t data)
|
||||
{
|
||||
if (m_rmcr == data) return;
|
||||
|
||||
m_rmcr = data;
|
||||
|
||||
switch ((m_rmcr & 0x1c) >> 2)
|
||||
{
|
||||
case 0: // TODO: clock sync
|
||||
case 3:
|
||||
case 7: // external clock
|
||||
LOGSER("SCI: Using external serial clock: true\n");
|
||||
m_use_ext_serclock = true;
|
||||
m_sci_timer->enable(false);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
case 2:
|
||||
case 4: // TODO: clock sync
|
||||
case 5:
|
||||
case 6:
|
||||
if (BIT(m_rmcr, 5))
|
||||
{
|
||||
LOGSER("SCI: Using Timer 2 clock\n");
|
||||
m_sci_timer->enable(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
int divisor = M6801_RMCR_SS[m_rmcr & M6801_RMCR_SS_MASK];
|
||||
attotime period = cycles_to_attotime(divisor);
|
||||
LOGSER("SCI: Setting serial rate, Divisor: %d Hz: %d\n", divisor, period.as_hz());
|
||||
m_sci_timer->adjust(period, 0, period);
|
||||
}
|
||||
m_use_ext_serclock = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int m6801_cpu_device::m6800_rx()
|
||||
{
|
||||
return (m_in_port_func[1]() & M6801_PORT2_IO3) >> 3;
|
||||
@ -991,6 +1070,12 @@ void hd6301x_cpu_device::device_start()
|
||||
save_item(NAME(m_tcsr2));
|
||||
save_item(NAME(m_pending_tcsr2));
|
||||
save_item(NAME(m_output_compare2.d));
|
||||
|
||||
save_item(NAME(m_t2cnt));
|
||||
save_item(NAME(m_tconr));
|
||||
save_item(NAME(m_tcsr3));
|
||||
save_item(NAME(m_tout3));
|
||||
save_item(NAME(m_t2cnt_written));
|
||||
}
|
||||
|
||||
void m6801_cpu_device::device_reset()
|
||||
@ -1043,6 +1128,12 @@ void hd6301x_cpu_device::device_reset()
|
||||
m_tcsr2 = 0x00;
|
||||
m_pending_tcsr2 = 0x00;
|
||||
OC2D = 0xffff;
|
||||
|
||||
m_t2cnt = 0x00;
|
||||
m_tconr = 0xff;
|
||||
m_tcsr3 = 0x00;
|
||||
m_tout3 = false;
|
||||
m_t2cnt_written = false;
|
||||
}
|
||||
|
||||
|
||||
@ -1086,6 +1177,11 @@ void hd6301x_cpu_device::write_port2()
|
||||
data = (data & 0xef) | (m_tx << 4);
|
||||
ddr |= 0x10;
|
||||
}
|
||||
if ((m_tcsr3 & 0x0c) != 0)
|
||||
{
|
||||
data = (data & 0xbf) | (m_tout3 << 6);
|
||||
ddr |= 0x40;
|
||||
}
|
||||
|
||||
m_out_port_func[1](0, data, ddr);
|
||||
}
|
||||
@ -1540,6 +1636,93 @@ void hd6301x_cpu_device::ocr2l_w(uint8_t data)
|
||||
}
|
||||
|
||||
|
||||
void hd6301x_cpu_device::increment_t2cnt(int amount)
|
||||
{
|
||||
if (amount > uint8_t(m_tconr - m_t2cnt))
|
||||
{
|
||||
if (m_t2cnt > m_tconr)
|
||||
{
|
||||
amount -= 256 - m_t2cnt;
|
||||
m_t2cnt = 0;
|
||||
}
|
||||
m_t2cnt = (m_t2cnt + amount) % (m_tconr + 1);
|
||||
|
||||
if (BIT(m_tcsr3, 3))
|
||||
{
|
||||
if (m_tout3 != BIT(m_tcsr3, 2))
|
||||
{
|
||||
m_tout3 = BIT(m_tcsr3, 2);
|
||||
m_port2_written = true;
|
||||
write_port2();
|
||||
}
|
||||
}
|
||||
else if (BIT(m_tcsr3, 2))
|
||||
{
|
||||
m_tout3 = !m_tout3;
|
||||
m_port2_written = true;
|
||||
write_port2();
|
||||
}
|
||||
|
||||
if (BIT(m_rmcr, 5) && !m_use_ext_serclock)
|
||||
{
|
||||
if (m_ext_serclock + amount >= 32)
|
||||
{
|
||||
m_ext_serclock = (m_ext_serclock + amount) % 32;
|
||||
serial_transmit();
|
||||
serial_receive();
|
||||
}
|
||||
else
|
||||
m_ext_serclock += amount;
|
||||
}
|
||||
|
||||
m_tcsr3 |= 0x80;
|
||||
m_timer_next = 0; // HACK
|
||||
}
|
||||
else
|
||||
m_t2cnt += amount;
|
||||
}
|
||||
|
||||
uint8_t hd6301x_cpu_device::t2cnt_r()
|
||||
{
|
||||
return m_t2cnt;
|
||||
}
|
||||
|
||||
void hd6301x_cpu_device::t2cnt_w(uint8_t data)
|
||||
{
|
||||
m_t2cnt = data;
|
||||
m_t2cnt_written = true;
|
||||
}
|
||||
|
||||
void hd6301x_cpu_device::tconr_w(uint8_t data)
|
||||
{
|
||||
m_tconr = data;
|
||||
}
|
||||
|
||||
uint8_t hd6301x_cpu_device::tcsr3_r()
|
||||
{
|
||||
return m_tcsr3;
|
||||
}
|
||||
|
||||
void hd6301x_cpu_device::tcsr3_w(uint8_t data)
|
||||
{
|
||||
uint8_t tout3_last_enable = (m_tcsr3 & 0x0c) != 0;
|
||||
|
||||
// Bit 5 does not exist and Bit 7 can only be written with 0
|
||||
m_tcsr3 = data & (0x5f | (m_tcsr3 & 0x80));
|
||||
|
||||
if (m_tout3 && !BIT(data, 4))
|
||||
{
|
||||
m_tout3 = false;
|
||||
write_port2();
|
||||
}
|
||||
else if (tout3_last_enable ? (data & 0x0c) == 0 : (data & 0x0c) != 0)
|
||||
{
|
||||
m_port2_written = true;
|
||||
write_port2();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint8_t m6801_cpu_device::sci_rmcr_r()
|
||||
{
|
||||
return m_rmcr;
|
||||
@ -1655,7 +1838,7 @@ void m6801_cpu_device::m6801_clock_serial()
|
||||
{
|
||||
m_ext_serclock++;
|
||||
|
||||
if (m_ext_serclock >= 8)
|
||||
if (m_ext_serclock >= m_sclk_divider)
|
||||
{
|
||||
m_ext_serclock = 0;
|
||||
serial_transmit();
|
||||
|
@ -124,6 +124,8 @@ protected:
|
||||
devcb_write_line m_out_sc2_func;
|
||||
devcb_write_line m_out_sertx_func;
|
||||
|
||||
int m_sclk_divider;
|
||||
|
||||
/* internal registers */
|
||||
uint8_t m_port_ddr[4];
|
||||
uint8_t m_port_data[4];
|
||||
@ -167,7 +169,7 @@ protected:
|
||||
virtual void set_timer_event();
|
||||
virtual void modified_counters();
|
||||
virtual void check_timer_event();
|
||||
void set_rmcr(uint8_t data);
|
||||
virtual void set_rmcr(uint8_t data);
|
||||
virtual void write_port2();
|
||||
int m6800_rx();
|
||||
void serial_transmit();
|
||||
@ -281,12 +283,21 @@ protected:
|
||||
uint8_t ocr2l_r();
|
||||
void ocr2l_w(uint8_t data);
|
||||
|
||||
void increment_t2cnt(int amount);
|
||||
uint8_t t2cnt_r();
|
||||
void t2cnt_w(uint8_t data);
|
||||
void tconr_w(uint8_t data);
|
||||
uint8_t tcsr3_r();
|
||||
void tcsr3_w(uint8_t data);
|
||||
|
||||
virtual void m6800_check_irq2() override;
|
||||
virtual void modified_tcsr() override;
|
||||
virtual void set_timer_event() override;
|
||||
virtual void modified_counters() override;
|
||||
virtual void increment_counter(int amount) override;
|
||||
virtual void check_timer_event() override;
|
||||
virtual void CLEANUP_COUNTERS() override;
|
||||
virtual void set_rmcr(uint8_t data) override;
|
||||
|
||||
devcb_read8::array<2> m_in_portx_func;
|
||||
devcb_write8::array<3> m_out_portx_func;
|
||||
@ -297,6 +308,12 @@ protected:
|
||||
uint8_t m_tcsr2;
|
||||
uint8_t m_pending_tcsr2;
|
||||
PAIR m_output_compare2;
|
||||
|
||||
uint8_t m_t2cnt;
|
||||
uint8_t m_tconr;
|
||||
uint8_t m_tcsr3;
|
||||
bool m_tout3;
|
||||
bool m_t2cnt_written;
|
||||
};
|
||||
|
||||
|
||||
|
@ -7,7 +7,6 @@ Novag Super Nova & related chess computers. I believe the series started with
|
||||
Primo. The chess engine is by David Kittinger.
|
||||
|
||||
TODO:
|
||||
- remove timer hack for supremo (missing extra timer emulation in MCU core)
|
||||
- NMI on power-off switch, it sets 0x14 bit 7 for standby power (see below)
|
||||
- add nvram, MCU is missing standby power emulation
|
||||
- beeps are glitchy, as if interrupted for too long
|
||||
@ -324,10 +323,6 @@ void snova_state::supremo(machine_config &config)
|
||||
m_maincpu->set_clock(8_MHz_XTAL);
|
||||
m_maincpu->set_addrmap(AS_PROGRAM, &snova_state::supremo_map);
|
||||
|
||||
// THIS IS A HACK, vector @ 0xffec, use ROM_COPY
|
||||
const attotime irq_period = attotime::from_ticks(4 * 128 * 11, 8_MHz_XTAL);
|
||||
m_maincpu->set_periodic_int(FUNC(snova_state::irq0_line_hold), irq_period);
|
||||
|
||||
config.set_default_layout(layout_novag_supremo);
|
||||
|
||||
config.device_remove("rs232");
|
||||
@ -351,8 +346,6 @@ ROM_START( supremo )
|
||||
ROM_REGION( 0x10000, "maincpu", 0 )
|
||||
ROM_LOAD("sp_a10.u5", 0x8000, 0x8000, CRC(1db63786) SHA1(4f24452ed8955b31ba88f68cc95c357660930aa4) )
|
||||
|
||||
ROM_COPY("maincpu", 0xffec, 0xfff8, 2) // HACK
|
||||
|
||||
ROM_REGION( 50926, "screen", 0 )
|
||||
ROM_LOAD("nsnova.svg", 0, 50926, CRC(5ffa1b53) SHA1(8b1f862bfdf0be837a4e8dc94fea592d6ffff629) )
|
||||
ROM_END
|
||||
|
@ -41,7 +41,7 @@ private:
|
||||
|
||||
u8 p2_r();
|
||||
WRITE_LINE_MEMBER(midi_rx_r) { m_rx_data = state; }
|
||||
WRITE_LINE_MEMBER(midiclock_w) { if (state == ASSERT_LINE) m_maincpu->m6801_clock_serial();}
|
||||
WRITE_LINE_MEMBER(midiclock_w) { if (state) m_maincpu->m6801_clock_serial(); }
|
||||
|
||||
required_device<hd6303x_cpu_device> m_maincpu;
|
||||
required_ioport m_port2;
|
||||
@ -130,7 +130,7 @@ void ymtx81z_state::tx81z(machine_config &config)
|
||||
|
||||
NVRAM(config, "nvram", nvram_device::DEFAULT_ALL_0); // TC5564PL-15/-20 + CR2032 battery
|
||||
|
||||
auto &midiclock(CLOCK(config, "midiclock", 500_kHz_XTAL / 2)); // divider not verified
|
||||
auto &midiclock(CLOCK(config, "midiclock", 500_kHz_XTAL));
|
||||
midiclock.signal_handler().set(FUNC(ymtx81z_state::midiclock_w));
|
||||
|
||||
MIDI_PORT(config, "mdin", midiin_slot, "midiin").rxd_handler().set(FUNC(ymtx81z_state::midi_rx_r));
|
||||
|
Loading…
Reference in New Issue
Block a user