summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author AJR <ajrhacker@users.noreply.github.com>2021-05-08 10:54:37 -0400
committer AJR <ajrhacker@users.noreply.github.com>2021-05-08 10:57:47 -0400
commitc137f89f869ea13f6fb4bb48a416adedfdfedc19 (patch)
treecb41919404daf09c5176038dc31bf885fcb88f45
parent9e0e9fb978072781a46d6578b46177b1ebe43598 (diff)
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
-rw-r--r--src/devices/bus/epson_sio/pf10.cpp2
-rw-r--r--src/devices/cpu/m6800/m6801.cpp193
-rw-r--r--src/devices/cpu/m6800/m6801.h19
-rw-r--r--src/mame/drivers/novag_snova.cpp7
-rw-r--r--src/mame/drivers/ymtx81z.cpp4
5 files changed, 209 insertions, 16 deletions
diff --git a/src/devices/bus/epson_sio/pf10.cpp b/src/devices/bus/epson_sio/pf10.cpp
index d41b247ba53..418971e47d1 100644
--- a/src/devices/bus/epson_sio/pf10.cpp
+++ b/src/devices/bus/epson_sio/pf10.cpp
@@ -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));
}
//-------------------------------------------------
diff --git a/src/devices/cpu/m6800/m6801.cpp b/src/devices/cpu/m6800/m6801.cpp
index de9cae8e9fd..fecf48c0cd3 100644
--- a/src/devices/cpu/m6800/m6801.cpp
+++ b/src/devices/cpu/m6800/m6801.cpp
@@ -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();
diff --git a/src/devices/cpu/m6800/m6801.h b/src/devices/cpu/m6800/m6801.h
index 27e88dcb2c8..c88d0f3ba1c 100644
--- a/src/devices/cpu/m6800/m6801.h
+++ b/src/devices/cpu/m6800/m6801.h
@@ -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;
};
diff --git a/src/mame/drivers/novag_snova.cpp b/src/mame/drivers/novag_snova.cpp
index 43402b9ff1e..d8f248ae5ff 100644
--- a/src/mame/drivers/novag_snova.cpp
+++ b/src/mame/drivers/novag_snova.cpp
@@ -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
diff --git a/src/mame/drivers/ymtx81z.cpp b/src/mame/drivers/ymtx81z.cpp
index fbc4f6b94e1..68c367f23cc 100644
--- a/src/mame/drivers/ymtx81z.cpp
+++ b/src/mame/drivers/ymtx81z.cpp
@@ -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));