summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/sh
diff options
context:
space:
mode:
author Olivier Galibert <galibert@pobox.com>2024-05-02 19:48:15 +0200
committer Olivier Galibert <galibert@pobox.com>2024-05-02 19:50:14 +0200
commit055b4c669cd31a43b680e2031efdcad7b93fc475 (patch)
tree78e36e94727fe1359a030d9d5075978f14786e10 /src/devices/cpu/sh
parent3b5e60b420b8c59d4373828dd4a2cf548523d810 (diff)
sh7042: Add dmac, mtu, adc, intc, sci, bsc. Separate A and non-A
psr540: Add the swx00 New machines marked as MACHINE_NOT_WORKING ------------------------------------------ Yamaha MU500 [Matt, O. Galibert] Yamaha MU1000 [Matt, O. Galibert] Yamaha MU2000 [Matt, O. Galibert]
Diffstat (limited to 'src/devices/cpu/sh')
-rw-r--r--src/devices/cpu/sh/sh7042.cpp220
-rw-r--r--src/devices/cpu/sh/sh7042.h53
-rw-r--r--src/devices/cpu/sh/sh_adc.cpp89
-rw-r--r--src/devices/cpu/sh/sh_adc.h48
-rw-r--r--src/devices/cpu/sh/sh_bsc.cpp139
-rw-r--r--src/devices/cpu/sh/sh_bsc.h47
-rw-r--r--src/devices/cpu/sh/sh_cmt.cpp31
-rw-r--r--src/devices/cpu/sh/sh_dmac.cpp115
-rw-r--r--src/devices/cpu/sh/sh_dmac.h59
-rw-r--r--src/devices/cpu/sh/sh_intc.cpp57
-rw-r--r--src/devices/cpu/sh/sh_intc.h7
-rw-r--r--src/devices/cpu/sh/sh_mtu.cpp527
-rw-r--r--src/devices/cpu/sh/sh_mtu.h182
-rw-r--r--src/devices/cpu/sh/sh_sci.cpp765
-rw-r--r--src/devices/cpu/sh/sh_sci.h151
15 files changed, 2399 insertions, 91 deletions
diff --git a/src/devices/cpu/sh/sh7042.cpp b/src/devices/cpu/sh/sh7042.cpp
index 66eb8dc10b8..1ce2b641f34 100644
--- a/src/devices/cpu/sh/sh7042.cpp
+++ b/src/devices/cpu/sh/sh7042.cpp
@@ -6,32 +6,63 @@
#include "emu.h"
#include "sh7042.h"
-DEFINE_DEVICE_TYPE(SH7042, sh7042_device, "sh7042", "Hitachi SH-2 (SH7042)")
-DEFINE_DEVICE_TYPE(SH7043, sh7043_device, "sh7043", "Hitachi SH-2 (SH7043)")
+DEFINE_DEVICE_TYPE(SH7042, sh7042_device, "sh7042", "Hitachi SH-2 (SH7042)")
+DEFINE_DEVICE_TYPE(SH7042A, sh7042a_device, "sh7042a", "Hitachi SH-2 (SH7042A)")
+DEFINE_DEVICE_TYPE(SH7043, sh7043_device, "sh7043", "Hitachi SH-2 (SH7043)")
+DEFINE_DEVICE_TYPE(SH7043A, sh7043a_device, "sh7043a", "Hitachi SH-2 (SH7043A)")
sh7042_device::sh7042_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
sh7042_device(mconfig, SH7042, tag, owner, clock)
{
+ m_die_a = false;
+}
+
+sh7042a_device::sh7042a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ sh7042_device(mconfig, SH7042A, tag, owner, clock)
+{
+ m_die_a = true;
}
sh7043_device::sh7043_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
sh7042_device(mconfig, SH7043, tag, owner, clock)
{
+ m_die_a = false;
+}
+
+sh7043a_device::sh7043a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ sh7042_device(mconfig, SH7043A, tag, owner, clock)
+{
+ m_die_a = true;
}
sh7042_device::sh7042_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
sh2_device(mconfig, type, tag, owner, clock, CPU_TYPE_SH2, address_map_constructor(FUNC(sh7042_device::map), this), 32, 0xffffffff),
m_intc(*this, "intc"),
- m_adc(*this, "adc"),
+ m_adc0(*this, "adc0"),
+ m_adc1(*this, "adc1"),
+ m_bsc(*this, "bsc"),
m_cmt(*this, "cmt"),
+ m_dmac(*this, "dmac"),
+ m_dmac0(*this, "dmac:0"),
+ m_dmac1(*this, "dmac:1"),
+ m_dmac2(*this, "dmac:2"),
+ m_dmac3(*this, "dmac:3"),
+ m_mtu(*this, "mtu"),
+ m_mtu0(*this, "mtu:0"),
+ m_mtu1(*this, "mtu:1"),
+ m_mtu2(*this, "mtu:2"),
+ m_mtu3(*this, "mtu:3"),
+ m_mtu4(*this, "mtu:4"),
m_porta(*this, "porta"),
m_portb(*this, "portb"),
m_portc(*this, "portc"),
m_portd(*this, "portd"),
m_porte(*this, "porte"),
m_portf(*this, "portf"),
+ m_sci(*this, "sci%d", 0),
m_read_adc(*this, 0),
m_sci_tx(*this),
+ m_sci_clk(*this),
m_read_port16(*this, 0xffff),
m_write_port16(*this),
m_read_port32(*this, 0xffffffff),
@@ -107,6 +138,11 @@ void sh7042_device::device_start()
m_pcf_if = 0;
}
+void sh7042_device::execute_set_input(int irqline, int state)
+{
+ m_intc->set_input(irqline, state);
+}
+
void sh7042_device::device_reset()
{
sh2_device::device_reset();
@@ -115,6 +151,66 @@ void sh7042_device::device_reset()
void sh7042_device::map(address_map &map)
{
+ map(0xffff81a0, 0xffff81a0).rw(m_sci[0], FUNC(sh_sci_device::smr_r), FUNC(sh_sci_device::smr_w));
+ map(0xffff81a1, 0xffff81a1).rw(m_sci[0], FUNC(sh_sci_device::brr_r), FUNC(sh_sci_device::brr_w));
+ map(0xffff81a2, 0xffff81a2).rw(m_sci[0], FUNC(sh_sci_device::scr_r), FUNC(sh_sci_device::scr_w));
+ map(0xffff81a3, 0xffff81a3).rw(m_sci[0], FUNC(sh_sci_device::tdr_r), FUNC(sh_sci_device::tdr_w));
+ map(0xffff81a4, 0xffff81a4).rw(m_sci[0], FUNC(sh_sci_device::ssr_r), FUNC(sh_sci_device::ssr_w));
+ map(0xffff81a5, 0xffff81a5).r(m_sci[0], FUNC(sh_sci_device::rdr_r));
+ map(0xffff81b0, 0xffff81b0).rw(m_sci[1], FUNC(sh_sci_device::smr_r), FUNC(sh_sci_device::smr_w));
+ map(0xffff81b1, 0xffff81b1).rw(m_sci[1], FUNC(sh_sci_device::brr_r), FUNC(sh_sci_device::brr_w));
+ map(0xffff81b2, 0xffff81b2).rw(m_sci[1], FUNC(sh_sci_device::scr_r), FUNC(sh_sci_device::scr_w));
+ map(0xffff81b3, 0xffff81b3).rw(m_sci[1], FUNC(sh_sci_device::tdr_r), FUNC(sh_sci_device::tdr_w));
+ map(0xffff81b4, 0xffff81b4).rw(m_sci[1], FUNC(sh_sci_device::ssr_r), FUNC(sh_sci_device::ssr_w));
+ map(0xffff81b5, 0xffff81b5).r(m_sci[1], FUNC(sh_sci_device::rdr_r));
+
+ map(0xffff8200, 0xffff8200).rw(m_mtu3, FUNC(sh_mtu_channel_device::tcr_r), FUNC(sh_mtu_channel_device::tcr_w));
+ map(0xffff8201, 0xffff8201).rw(m_mtu4, FUNC(sh_mtu_channel_device::tcr_r), FUNC(sh_mtu_channel_device::tcr_w));
+ map(0xffff8202, 0xffff8202).rw(m_mtu3, FUNC(sh_mtu_channel_device::tmdr_r), FUNC(sh_mtu_channel_device::tmdr_w));
+ map(0xffff8203, 0xffff8203).rw(m_mtu4, FUNC(sh_mtu_channel_device::tmdr_r), FUNC(sh_mtu_channel_device::tmdr_w));
+ map(0xffff8204, 0xffff8205).rw(m_mtu3, FUNC(sh_mtu_channel_device::tior_r), FUNC(sh_mtu_channel_device::tior_w));
+ map(0xffff8206, 0xffff8207).rw(m_mtu4, FUNC(sh_mtu_channel_device::tior_r), FUNC(sh_mtu_channel_device::tior_w));
+ map(0xffff8208, 0xffff8208).rw(m_mtu3, FUNC(sh_mtu_channel_device::tier_r), FUNC(sh_mtu_channel_device::tier_w));
+ map(0xffff8209, 0xffff8209).rw(m_mtu4, FUNC(sh_mtu_channel_device::tier_r), FUNC(sh_mtu_channel_device::tier_w));
+ map(0xffff820a, 0xffff820a).rw(m_mtu, FUNC(sh_mtu_device::toer_r), FUNC(sh_mtu_device::toer_w));
+ map(0xffff820b, 0xffff820b).rw(m_mtu, FUNC(sh_mtu_device::tocr_r), FUNC(sh_mtu_device::tocr_w));
+ map(0xffff820d, 0xffff820d).rw(m_mtu, FUNC(sh_mtu_device::tgcr_r), FUNC(sh_mtu_device::tgcr_w));
+ map(0xffff8210, 0xffff8211).rw(m_mtu3, FUNC(sh_mtu_channel_device::tcnt_r), FUNC(sh_mtu_channel_device::tcnt_w));
+ map(0xffff8212, 0xffff8213).rw(m_mtu4, FUNC(sh_mtu_channel_device::tcnt_r), FUNC(sh_mtu_channel_device::tcnt_w));
+ map(0xffff8214, 0xffff8215).rw(m_mtu, FUNC(sh_mtu_device::tcdr_r), FUNC(sh_mtu_device::tcdr_w));
+ map(0xffff8216, 0xffff8217).rw(m_mtu, FUNC(sh_mtu_device::tddr_r), FUNC(sh_mtu_device::tddr_w));
+ map(0xffff8218, 0xffff821b).rw(m_mtu3, FUNC(sh_mtu_channel_device::tgr_r), FUNC(sh_mtu_channel_device::tgr_w));
+ map(0xffff821c, 0xffff821f).rw(m_mtu4, FUNC(sh_mtu_channel_device::tgr_r), FUNC(sh_mtu_channel_device::tgr_w));
+ map(0xffff8220, 0xffff8221).rw(m_mtu, FUNC(sh_mtu_device::tcnts_r), FUNC(sh_mtu_device::tcnts_w));
+ map(0xffff8222, 0xffff8223).rw(m_mtu, FUNC(sh_mtu_device::tcbr_r), FUNC(sh_mtu_device::tcbr_w));
+ map(0xffff8224, 0xffff8227).rw(m_mtu3, FUNC(sh_mtu_channel_device::tgrc_r), FUNC(sh_mtu_channel_device::tgrc_w));
+ map(0xffff8228, 0xffff822b).rw(m_mtu4, FUNC(sh_mtu_channel_device::tgrc_r), FUNC(sh_mtu_channel_device::tgrc_w));
+ map(0xffff822c, 0xffff822c).rw(m_mtu3, FUNC(sh_mtu_channel_device::tsr_r), FUNC(sh_mtu_channel_device::tsr_w));
+ map(0xffff822d, 0xffff822d).rw(m_mtu4, FUNC(sh_mtu_channel_device::tsr_r), FUNC(sh_mtu_channel_device::tsr_w));
+ map(0xffff8240, 0xffff8240).rw(m_mtu, FUNC(sh_mtu_device::tstr_r), FUNC(sh_mtu_device::tstr_w));
+ map(0xffff8241, 0xffff8241).rw(m_mtu, FUNC(sh_mtu_device::tsyr_r), FUNC(sh_mtu_device::tsyr_w));
+ map(0xffff8260, 0xffff8260).rw(m_mtu0, FUNC(sh_mtu_channel_device::tcr_r), FUNC(sh_mtu_channel_device::tcr_w));
+ map(0xffff8261, 0xffff8261).rw(m_mtu0, FUNC(sh_mtu_channel_device::tmdr_r), FUNC(sh_mtu_channel_device::tmdr_w));
+ map(0xffff8262, 0xffff8263).rw(m_mtu0, FUNC(sh_mtu_channel_device::tior_r), FUNC(sh_mtu_channel_device::tior_w));
+ map(0xffff8264, 0xffff8264).rw(m_mtu0, FUNC(sh_mtu_channel_device::tier_r), FUNC(sh_mtu_channel_device::tier_w));
+ map(0xffff8265, 0xffff8265).rw(m_mtu0, FUNC(sh_mtu_channel_device::tsr_r), FUNC(sh_mtu_channel_device::tsr_w));
+ map(0xffff8266, 0xffff8267).rw(m_mtu0, FUNC(sh_mtu_channel_device::tcnt_r), FUNC(sh_mtu_channel_device::tcnt_w));
+ map(0xffff8268, 0xffff826f).rw(m_mtu0, FUNC(sh_mtu_channel_device::tgr_r), FUNC(sh_mtu_channel_device::tgr_w));
+ map(0xffff8280, 0xffff8280).rw(m_mtu1, FUNC(sh_mtu_channel_device::tcr_r), FUNC(sh_mtu_channel_device::tcr_w));
+ map(0xffff8281, 0xffff8281).rw(m_mtu1, FUNC(sh_mtu_channel_device::tmdr_r), FUNC(sh_mtu_channel_device::tmdr_w));
+ map(0xffff8282, 0xffff8283).rw(m_mtu1, FUNC(sh_mtu_channel_device::tior_r), FUNC(sh_mtu_channel_device::tior_w));
+ map(0xffff8284, 0xffff8284).rw(m_mtu1, FUNC(sh_mtu_channel_device::tier_r), FUNC(sh_mtu_channel_device::tier_w));
+ map(0xffff8285, 0xffff8285).rw(m_mtu1, FUNC(sh_mtu_channel_device::tsr_r), FUNC(sh_mtu_channel_device::tsr_w));
+ map(0xffff8286, 0xffff8287).rw(m_mtu1, FUNC(sh_mtu_channel_device::tcnt_r), FUNC(sh_mtu_channel_device::tcnt_w));
+ map(0xffff8288, 0xffff828b).rw(m_mtu1, FUNC(sh_mtu_channel_device::tgr_r), FUNC(sh_mtu_channel_device::tgr_w));
+ map(0xffff82a0, 0xffff82a0).rw(m_mtu2, FUNC(sh_mtu_channel_device::tcr_r), FUNC(sh_mtu_channel_device::tcr_w));
+ map(0xffff82a1, 0xffff82a1).rw(m_mtu2, FUNC(sh_mtu_channel_device::tmdr_r), FUNC(sh_mtu_channel_device::tmdr_w));
+ map(0xffff82a2, 0xffff82a3).rw(m_mtu2, FUNC(sh_mtu_channel_device::tior_r), FUNC(sh_mtu_channel_device::tior_w));
+ map(0xffff82a4, 0xffff82a4).rw(m_mtu2, FUNC(sh_mtu_channel_device::tier_r), FUNC(sh_mtu_channel_device::tier_w));
+ map(0xffff82a5, 0xffff82a5).rw(m_mtu2, FUNC(sh_mtu_channel_device::tsr_r), FUNC(sh_mtu_channel_device::tsr_w));
+ map(0xffff82a6, 0xffff82a7).rw(m_mtu2, FUNC(sh_mtu_channel_device::tcnt_r), FUNC(sh_mtu_channel_device::tcnt_w));
+ map(0xffff82a8, 0xffff82ab).rw(m_mtu2, FUNC(sh_mtu_channel_device::tgr_r), FUNC(sh_mtu_channel_device::tgr_w));
+
map(0xffff8348, 0xffff8357).rw(m_intc, FUNC(sh_intc_device::ipr_r), FUNC(sh_intc_device::ipr_w));
map(0xffff8358, 0xffff8359).rw(m_intc, FUNC(sh_intc_device::icr_r), FUNC(sh_intc_device::icr_w));
map(0xffff835a, 0xffff835b).rw(m_intc, FUNC(sh_intc_device::isr_r), FUNC(sh_intc_device::isr_w));
@@ -138,7 +234,6 @@ void sh7042_device::map(address_map &map)
map(0xffff83b4, 0xffff83b5).rw(m_porte, FUNC(sh_port16_device::io_r), FUNC(sh_port16_device::io_w));
map(0xffff83b8, 0xffff83bb).rw(FUNC(sh7042_device::pcf_e_r), FUNC(sh7042_device::pcf_e_w));
map(0xffff83c8, 0xffff83c9).rw(FUNC(sh7042_device::pcf_if_r), FUNC(sh7042_device::pcf_if_w));
-
map(0xffff83d0, 0xffff83d1).rw(m_cmt, FUNC(sh_cmt_device::cmstr_r), FUNC(sh_cmt_device::cmstr_w));
map(0xffff83d2, 0xffff83d3).rw(m_cmt, FUNC(sh_cmt_device::cmcsr0_r), FUNC(sh_cmt_device::cmcsr0_w));
map(0xffff83d4, 0xffff83d5).rw(m_cmt, FUNC(sh_cmt_device::cmcnt0_r), FUNC(sh_cmt_device::cmcnt0_w));
@@ -147,9 +242,44 @@ void sh7042_device::map(address_map &map)
map(0xffff83da, 0xffff83db).rw(m_cmt, FUNC(sh_cmt_device::cmcnt1_r), FUNC(sh_cmt_device::cmcnt1_w));
map(0xffff83dc, 0xffff83dd).rw(m_cmt, FUNC(sh_cmt_device::cmcor1_r), FUNC(sh_cmt_device::cmcor1_w));
- map(0xffff83e0, 0xffff83e0).rw(m_adc, FUNC(sh_adc_device::adcsr_r), FUNC(sh_adc_device::adcsr_w));
- map(0xffff83e1, 0xffff83e1).rw(m_adc, FUNC(sh_adc_device::adcr_r), FUNC(sh_adc_device::adcr_w));
- map(0xffff83f0, 0xffff83ff).r(m_adc, FUNC(sh_adc_device::addr_r));
+ if(!m_die_a) {
+ map(0xffff83e0, 0xffff83e0).rw(m_adc0, FUNC(sh_adc_device::adcsr_r), FUNC(sh_adc_device::adcsr_w));
+ map(0xffff83e1, 0xffff83e1).rw(m_adc0, FUNC(sh_adc_device::adcr_r), FUNC(sh_adc_device::adcr_w));
+ map(0xffff83f0, 0xffff83ff).r(m_adc0, FUNC(sh_adc_device::addr_r));
+ } else {
+ map(0xffff8400, 0xffff8407).r(m_adc0, FUNC(sh_adc_device::addr_r));
+ map(0xffff8408, 0xffff840f).r(m_adc1, FUNC(sh_adc_device::addr_r));
+ map(0xffff8410, 0xffff8410).rw(m_adc0, FUNC(sh_adc_device::adcsr_r), FUNC(sh_adc_device::adcsr_w));
+ map(0xffff8411, 0xffff8411).rw(m_adc1, FUNC(sh_adc_device::adcsr_r), FUNC(sh_adc_device::adcsr_w));
+ map(0xffff8412, 0xffff8412).rw(m_adc0, FUNC(sh_adc_device::adcr_r), FUNC(sh_adc_device::adcr_w));
+ map(0xffff8413, 0xffff8413).rw(m_adc1, FUNC(sh_adc_device::adcr_r), FUNC(sh_adc_device::adcr_w));
+ }
+
+ map(0xffff8620, 0xffff8621).rw(m_bsc, FUNC(sh_bsc_device::bcr1_r), FUNC(sh_bsc_device::bcr1_w));
+ map(0xffff8622, 0xffff8623).rw(m_bsc, FUNC(sh_bsc_device::bcr2_r), FUNC(sh_bsc_device::bcr2_w));
+ map(0xffff8624, 0xffff8625).rw(m_bsc, FUNC(sh_bsc_device::wcr1_r), FUNC(sh_bsc_device::wcr1_w));
+ map(0xffff8626, 0xffff8627).rw(m_bsc, FUNC(sh_bsc_device::wcr2_r), FUNC(sh_bsc_device::wcr2_w));
+ map(0xffff862a, 0xffff862b).rw(m_bsc, FUNC(sh_bsc_device::dcr_r), FUNC(sh_bsc_device::dcr_w));
+ map(0xffff862c, 0xffff862d).rw(m_bsc, FUNC(sh_bsc_device::rtcsr_r), FUNC(sh_bsc_device::rtcsr_w));
+ map(0xffff862e, 0xffff862f).rw(m_bsc, FUNC(sh_bsc_device::rtcnt_r), FUNC(sh_bsc_device::rtcnt_w));
+ map(0xffff8630, 0xffff8631).rw(m_bsc, FUNC(sh_bsc_device::rtcor_r), FUNC(sh_bsc_device::rtcor_w));
+ map(0xffff86b0, 0xffff86b1).rw(m_dmac, FUNC(sh_dmac_device::dmaor_r), FUNC(sh_dmac_device::dmaor_w));
+ map(0xffff86c0, 0xffff86c3).rw(m_dmac0, FUNC(sh_dmac_channel_device::sar_r), FUNC(sh_dmac_channel_device::sar_w));
+ map(0xffff86c4, 0xffff86c7).rw(m_dmac0, FUNC(sh_dmac_channel_device::dar_r), FUNC(sh_dmac_channel_device::dar_w));
+ map(0xffff86c8, 0xffff86cb).rw(m_dmac0, FUNC(sh_dmac_channel_device::dmatcr_r), FUNC(sh_dmac_channel_device::dmatcr_w));
+ map(0xffff86cc, 0xffff86cf).rw(m_dmac0, FUNC(sh_dmac_channel_device::chcr_r), FUNC(sh_dmac_channel_device::chcr_w));
+ map(0xffff86d0, 0xffff86d3).rw(m_dmac1, FUNC(sh_dmac_channel_device::sar_r), FUNC(sh_dmac_channel_device::sar_w));
+ map(0xffff86d4, 0xffff86d7).rw(m_dmac1, FUNC(sh_dmac_channel_device::dar_r), FUNC(sh_dmac_channel_device::dar_w));
+ map(0xffff86d8, 0xffff86db).rw(m_dmac1, FUNC(sh_dmac_channel_device::dmatcr_r), FUNC(sh_dmac_channel_device::dmatcr_w));
+ map(0xffff86dc, 0xffff86df).rw(m_dmac1, FUNC(sh_dmac_channel_device::chcr_r), FUNC(sh_dmac_channel_device::chcr_w));
+ map(0xffff86e0, 0xffff86e3).rw(m_dmac2, FUNC(sh_dmac_channel_device::sar_r), FUNC(sh_dmac_channel_device::sar_w));
+ map(0xffff86e4, 0xffff86e7).rw(m_dmac2, FUNC(sh_dmac_channel_device::dar_r), FUNC(sh_dmac_channel_device::dar_w));
+ map(0xffff86e8, 0xffff86eb).rw(m_dmac2, FUNC(sh_dmac_channel_device::dmatcr_r), FUNC(sh_dmac_channel_device::dmatcr_w));
+ map(0xffff86ec, 0xffff86ef).rw(m_dmac2, FUNC(sh_dmac_channel_device::chcr_r), FUNC(sh_dmac_channel_device::chcr_w));
+ map(0xffff86f0, 0xffff86f3).rw(m_dmac3, FUNC(sh_dmac_channel_device::sar_r), FUNC(sh_dmac_channel_device::sar_w));
+ map(0xffff86f4, 0xffff86f7).rw(m_dmac3, FUNC(sh_dmac_channel_device::dar_r), FUNC(sh_dmac_channel_device::dar_w));
+ map(0xffff86f8, 0xffff86fb).rw(m_dmac3, FUNC(sh_dmac_channel_device::dmatcr_r), FUNC(sh_dmac_channel_device::dmatcr_w));
+ map(0xffff86fc, 0xffff86ff).rw(m_dmac3, FUNC(sh_dmac_channel_device::chcr_r), FUNC(sh_dmac_channel_device::chcr_w));
map(0xfffff000, 0xffffffff).ram();
}
@@ -157,14 +287,73 @@ void sh7042_device::map(address_map &map)
void sh7042_device::device_add_mconfig(machine_config &config)
{
SH_INTC(config, m_intc, *this);
- SH_ADC(config, m_adc, *this, m_intc, 136);
+ if(m_die_a) {
+ SH_ADC_MS(config, m_adc0, *this, m_intc, 0, 136);
+ SH_ADC_MS(config, m_adc1, *this, m_intc, 4, 137);
+ } else
+ SH_ADC_HS(config, m_adc0, *this, m_intc, 136);
+ SH_BSC(config, m_bsc);
SH_CMT(config, m_cmt, *this, m_intc, 144, 148);
+ SH_DMAC(config, m_dmac, *this);
+ SH_DMAC_CHANNEL(config, m_dmac0, *this, m_intc);
+ SH_DMAC_CHANNEL(config, m_dmac1, *this, m_intc);
+ SH_DMAC_CHANNEL(config, m_dmac2, *this, m_intc);
+ SH_DMAC_CHANNEL(config, m_dmac3, *this, m_intc);
+ SH_MTU(config, m_mtu, *this, 5);
+ SH_MTU_CHANNEL(config, m_mtu0, *this, 4, 0x60, m_intc, 88,
+ sh_mtu_channel_device::DIV_1,
+ sh_mtu_channel_device::DIV_4,
+ sh_mtu_channel_device::DIV_16,
+ sh_mtu_channel_device::DIV_64,
+ sh_mtu_channel_device::INPUT_A,
+ sh_mtu_channel_device::INPUT_B,
+ sh_mtu_channel_device::INPUT_C,
+ sh_mtu_channel_device::INPUT_D);
+ SH_MTU_CHANNEL(config, m_mtu1, *this, 2, 0x4c, m_intc, 96,
+ sh_mtu_channel_device::DIV_1,
+ sh_mtu_channel_device::DIV_4,
+ sh_mtu_channel_device::DIV_16,
+ sh_mtu_channel_device::DIV_64,
+ sh_mtu_channel_device::INPUT_A,
+ sh_mtu_channel_device::INPUT_B,
+ sh_mtu_channel_device::DIV_256,
+ sh_mtu_channel_device::CHAIN).set_chain(m_mtu2);
+ SH_MTU_CHANNEL(config, m_mtu2, *this, 2, 0x4c, m_intc, 104,
+ sh_mtu_channel_device::DIV_1,
+ sh_mtu_channel_device::DIV_4,
+ sh_mtu_channel_device::DIV_16,
+ sh_mtu_channel_device::DIV_64,
+ sh_mtu_channel_device::INPUT_A,
+ sh_mtu_channel_device::INPUT_B,
+ sh_mtu_channel_device::INPUT_C,
+ sh_mtu_channel_device::DIV_1024);
+ SH_MTU_CHANNEL(config, m_mtu3, *this, 4, 0x60, m_intc, 112,
+ sh_mtu_channel_device::DIV_1,
+ sh_mtu_channel_device::DIV_4,
+ sh_mtu_channel_device::DIV_16,
+ sh_mtu_channel_device::DIV_64,
+ sh_mtu_channel_device::DIV_256,
+ sh_mtu_channel_device::DIV_1024,
+ sh_mtu_channel_device::INPUT_A,
+ sh_mtu_channel_device::INPUT_B);
+ SH_MTU_CHANNEL(config, m_mtu4, *this, 4, 0x60, m_intc, 120,
+ sh_mtu_channel_device::DIV_1,
+ sh_mtu_channel_device::DIV_4,
+ sh_mtu_channel_device::DIV_16,
+ sh_mtu_channel_device::DIV_64,
+ sh_mtu_channel_device::DIV_256,
+ sh_mtu_channel_device::DIV_1024,
+ sh_mtu_channel_device::INPUT_A,
+ sh_mtu_channel_device::INPUT_B);
SH_PORT32(config, m_porta, *this, 0, 0x00000000, 0xff000000);
SH_PORT16(config, m_portb, *this, 0, 0x0000, 0xfc00);
SH_PORT16(config, m_portc, *this, 1, 0x0000, 0x0000);
SH_PORT32(config, m_portd, *this, 1, 0x0000, 0x0000);
SH_PORT16(config, m_porte, *this, 2, 0x0000, 0x0000);
SH_PORT16(config, m_portf, *this, 3, 0x0000, 0xff00);
+ SH_SCI(config, m_sci[0], 0, *this, m_intc, 128, 129, 130, 131);
+ SH_SCI(config, m_sci[1], 1, *this, m_intc, 132, 133, 134, 135);
+
}
void sh7042_device::do_sci_w(int sci, int state)
@@ -204,8 +393,15 @@ void sh7042_device::internal_update(u64 current_time)
{
u64 event_time = 0;
- add_event(event_time, m_adc->internal_update(current_time));
+ add_event(event_time, m_adc0->internal_update(current_time));
+ if(m_adc1)
+ add_event(event_time, m_adc1->internal_update(current_time));
add_event(event_time, m_cmt->internal_update(current_time));
+ add_event(event_time, m_mtu0->internal_update(current_time));
+ add_event(event_time, m_mtu1->internal_update(current_time));
+ add_event(event_time, m_mtu2->internal_update(current_time));
+ add_event(event_time, m_mtu3->internal_update(current_time));
+ add_event(event_time, m_mtu4->internal_update(current_time));
recompute_timer(event_time);
}
@@ -304,3 +500,9 @@ void sh7042_device::set_internal_interrupt(int level, u32 vector)
m_internal_irq_vector = vector;
m_test_irq = 1;
}
+
+void sh7042_device::sh2_exception_internal(const char *message, int irqline, int vector)
+{
+ sh2_device::sh2_exception_internal(message, irqline, vector);
+ m_intc->interrupt_taken(irqline, vector);
+}
diff --git a/src/devices/cpu/sh/sh7042.h b/src/devices/cpu/sh/sh7042.h
index 9daa7ac03ab..b409c08a8c7 100644
--- a/src/devices/cpu/sh/sh7042.h
+++ b/src/devices/cpu/sh/sh7042.h
@@ -11,8 +11,12 @@
#include "sh2.h"
#include "sh_intc.h"
#include "sh_adc.h"
+#include "sh_bsc.h"
#include "sh_cmt.h"
+#include "sh_dmac.h"
+#include "sh_mtu.h"
#include "sh_port.h"
+#include "sh_sci.h"
class sh7042_device : public sh2_device
{
@@ -21,7 +25,13 @@ public:
template<int Port> auto read_adc() { return m_read_adc[Port].bind(); }
template<int Sci> void sci_rx_w(int state) { do_sci_w(Sci, state); }
+ template<int Sci> void sci_clk_w(int state) { m_sci[Sci]->do_clk_w(state); }
template<int Sci> auto write_sci_tx() { return m_sci_tx[Sci].bind(); }
+ template<int Sci> auto write_sci_clk() { return m_sci_clk[Sci].bind(); }
+
+ void sci_set_external_clock_period(int sci, const attotime &period) {
+ m_sci[sci].lookup()->do_set_external_clock_period(period);
+ }
auto read_porta() { return m_read_port32 [0].bind(); }
auto write_porta() { return m_write_port32[0].bind(); }
@@ -46,6 +56,9 @@ public:
void set_internal_interrupt(int level, u32 vector);
+ void do_sci_tx(int sci, int state) { m_sci_tx[sci](state); }
+ void do_sci_clk(int sci, int state) { m_sci_clk[sci](state); }
+
protected:
const char *m_port16_names;
const char *m_port32_names;
@@ -66,25 +79,43 @@ protected:
CR_BUF = 0x03
};
+ bool m_die_a;
+
sh7042_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock);
virtual void device_start() override;
virtual void device_reset() override;
virtual void device_add_mconfig(machine_config &config) override;
+ virtual void sh2_exception_internal(const char *message, int irqline, int vector) override;
+ virtual void execute_set_input(int irqline, int state) override;
private:
required_device<sh_intc_device> m_intc;
- required_device<sh_adc_device> m_adc;
+ required_device<sh_adc_device> m_adc0;
+ optional_device<sh_adc_device> m_adc1;
+ required_device<sh_bsc_device> m_bsc;
required_device<sh_cmt_device> m_cmt;
+ required_device<sh_dmac_device> m_dmac;
+ required_device<sh_dmac_channel_device> m_dmac0;
+ required_device<sh_dmac_channel_device> m_dmac1;
+ required_device<sh_dmac_channel_device> m_dmac2;
+ required_device<sh_dmac_channel_device> m_dmac3;
+ required_device<sh_mtu_device> m_mtu;
+ required_device<sh_mtu_channel_device> m_mtu0;
+ required_device<sh_mtu_channel_device> m_mtu1;
+ required_device<sh_mtu_channel_device> m_mtu2;
+ required_device<sh_mtu_channel_device> m_mtu3;
+ required_device<sh_mtu_channel_device> m_mtu4;
required_device<sh_port32_device> m_porta;
required_device<sh_port16_device> m_portb;
required_device<sh_port16_device> m_portc;
required_device<sh_port32_device> m_portd;
required_device<sh_port16_device> m_porte;
required_device<sh_port16_device> m_portf;
+ required_device_array<sh_sci_device, 2> m_sci;
devcb_read16::array<8> m_read_adc;
- devcb_write_line::array<2> m_sci_tx;
+ devcb_write_line::array<2> m_sci_tx, m_sci_clk;
devcb_read16::array<4> m_read_port16;
devcb_write16::array<4> m_write_port16;
devcb_read32::array<2> m_read_port32;
@@ -134,14 +165,28 @@ private:
void pcf_if_w(offs_t, u16 data, u16 mem_mask);
};
+class sh7042a_device : public sh7042_device
+{
+public:
+ sh7042a_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+};
+
class sh7043_device : public sh7042_device
{
public:
sh7043_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
};
+class sh7043a_device : public sh7042_device
+{
+public:
+ sh7043a_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+};
+
-DECLARE_DEVICE_TYPE(SH7042, sh7042_device)
-DECLARE_DEVICE_TYPE(SH7043, sh7043_device)
+DECLARE_DEVICE_TYPE(SH7042, sh7042_device)
+DECLARE_DEVICE_TYPE(SH7042A, sh7042a_device)
+DECLARE_DEVICE_TYPE(SH7043, sh7043_device)
+DECLARE_DEVICE_TYPE(SH7043A, sh7043a_device)
#endif // MAME_CPU_SH_SH7042_H
diff --git a/src/devices/cpu/sh/sh_adc.cpp b/src/devices/cpu/sh/sh_adc.cpp
index d9e1da01921..55f6833d853 100644
--- a/src/devices/cpu/sh/sh_adc.cpp
+++ b/src/devices/cpu/sh/sh_adc.cpp
@@ -11,24 +11,42 @@
// 1 = everything
static constexpr int V = 0;
-DEFINE_DEVICE_TYPE(SH_ADC, sh_adc_device, "sh_adc", "SH2/704x ADC")
+DEFINE_DEVICE_TYPE(SH_ADC_MS, sh_adc_ms_device, "sh_adc_ms", "SH2/704x ADC (medium speed)")
+DEFINE_DEVICE_TYPE(SH_ADC_HS, sh_adc_hs_device, "sh_adc_hs", "SH2/704x ADC (high speed)")
-sh_adc_device::sh_adc_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
- device_t(mconfig, SH_ADC, tag, owner, clock),
+sh_adc_device::sh_adc_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock) :
+ device_t(mconfig, type, tag, owner, clock),
m_cpu(*this, finder_base::DUMMY_TAG),
m_intc(*this, finder_base::DUMMY_TAG),
- m_intc_vector(0), m_adcsr(0), m_adcr(0), m_register_mask(0), m_trigger(0), m_start_mode(0), m_start_channel(0),
+ m_intc_vector(0), m_adcsr(0), m_adcr(0), m_trigger(0), m_start_mode(0), m_start_channel(0),
m_end_channel(0), m_start_count(0), m_mode(0), m_channel(0), m_count(0), m_analog_powered(false), m_adtrg(false), m_next_event(0)
{
- m_suspend_on_interrupt = true;
- m_register_mask = 7;
- m_analog_power_control = false;
}
+sh_adc_ms_device::sh_adc_ms_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
+ sh_adc_device(mconfig, SH_ADC_MS, tag, owner, clock)
+{
+ m_is_hs = false;
+ m_port_base = 0;
+ m_port_mask = 3;
+ m_port_shift = 6;
+ m_analog_powered = true;
+}
+
+sh_adc_hs_device::sh_adc_hs_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
+ sh_adc_device(mconfig, SH_ADC_HS, tag, owner, clock)
+{
+ m_is_hs = true;
+ m_port_base = 0;
+ m_port_mask = 7;
+ m_port_shift = 0;
+ m_analog_powered = false;
+}
+
+
u16 sh_adc_device::addr_r(offs_t offset)
{
- if(V>=1) logerror("addr_r %d %03x\n", offset, m_addr[offset]);
- return m_addr[offset];
+ return m_addr[offset] << m_port_shift;
}
u8 sh_adc_device::adcsr_r()
@@ -47,7 +65,7 @@ void sh_adc_device::adcsr_w(u8 data)
{
if(V>=1) logerror("adcsr_w %02x\n", data);
u8 prev = m_adcsr;
- m_adcsr = (data & 0x7f) | (m_adcsr & data & F_ADF);
+ m_adcsr = (data & (0x70 | m_port_mask)) | (m_adcsr & data & F_ADF);
mode_update();
if((prev & F_ADF) && !(m_adcsr & F_ADF)) {
if(m_mode & HALTED) {
@@ -98,7 +116,6 @@ void sh_adc_device::device_start()
save_item(NAME(m_end_channel));
save_item(NAME(m_start_count));
save_item(NAME(m_suspend_on_interrupt));
- save_item(NAME(m_analog_power_control));
save_item(NAME(m_mode));
save_item(NAME(m_channel));
save_item(NAME(m_count));
@@ -121,7 +138,6 @@ void sh_adc_device::device_reset()
m_count = 0;
m_next_event = 0;
mode_update();
- m_analog_powered = !m_analog_power_control;
m_adtrg = true;
}
@@ -154,13 +170,11 @@ void sh_adc_device::conversion_wait(bool first, bool poweron, u64 current_time)
void sh_adc_device::buffer_value(int port, int buffer)
{
- m_buf[buffer] = m_cpu->do_read_adc(port);
- if(V>=1) logerror("adc buffer %d -> %d:%03x\n", port, buffer, m_buf[buffer]);
+ m_buf[buffer] = m_cpu->do_read_adc(port + m_port_base);
}
void sh_adc_device::commit_value(int reg, int buffer)
{
- reg &= m_register_mask;
if(V>=1) logerror("adc commit %d -> %d:%03x\n", buffer, reg, m_buf[buffer]);
m_addr[reg] = m_buf[buffer];
}
@@ -259,27 +273,42 @@ int sh_adc_device::conversion_time(bool first, bool poweron)
void sh_adc_device::mode_update()
{
- m_trigger = 1 << ((m_adcr >> 4) & 3);
- m_analog_power_control = !(m_adcr & 0x40);
+ if(m_is_hs) {
+ m_trigger = 1 << ((m_adcr >> 4) & 3);
+ m_analog_power_control = !(m_adcr & 0x40);
- m_mode = ACTIVE | (m_adcr & 0x08 ? REPEAT : 0);
+ m_mode = ACTIVE | (m_adcr & 0x08 ? REPEAT : 0);
- if(m_adcsr & 0x03) {
- m_mode |= BUFFER;
+ if(m_adcr & 0x03) {
+ m_mode |= BUFFER;
- }
+ }
- if(m_adcsr & 0x08) {
- m_mode |= ROTATE;
- m_start_channel = 0;
- if(m_adcr & 0x04) {
- m_mode |= DUAL;
- m_end_channel = (m_adcsr & 6)+1;
+ if(m_adcsr & 0x08) {
+ m_mode |= ROTATE;
+ m_start_channel = 0;
+ if(m_adcr & 0x04) {
+ m_mode |= DUAL;
+ m_end_channel = (m_adcsr & 6)+1;
+ } else
+ m_end_channel = m_adcsr & 7;
} else
- m_end_channel = m_adcsr & 7;
- } else
- m_start_channel = m_end_channel = m_adcsr & 7;
+ m_start_channel = m_end_channel = m_adcsr & 7;
+
+ } else {
+ m_trigger = T_SOFT;
+
+ m_mode = ACTIVE;
+ if(m_adcsr & 0x08) {
+ m_mode |= ROTATE;
+ m_start_channel = 0;
+ m_end_channel = m_adcsr & 3;
+ } else
+ m_start_channel = m_end_channel = m_adcsr & 3;
+ if(m_start_channel == 2)
+ machine().debug_break();
+ }
}
void sh_adc_device::do_buffering(int buffer)
diff --git a/src/devices/cpu/sh/sh_adc.h b/src/devices/cpu/sh/sh_adc.h
index 9a48e3f804b..10f55c9793b 100644
--- a/src/devices/cpu/sh/sh_adc.h
+++ b/src/devices/cpu/sh/sh_adc.h
@@ -19,17 +19,6 @@ class sh_intc_device;
class sh_adc_device : public device_t {
public:
- sh_adc_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
-
- template<typename T, typename U> sh_adc_device(const machine_config &mconfig, const char *tag, device_t *owner,
- T &&cpu, U &&intc, int vect) :
- sh_adc_device(mconfig, tag, owner)
- {
- m_cpu.set_tag(std::forward<T>(cpu));
- m_intc.set_tag(std::forward<U>(intc));
- m_intc_vector = vect;
- }
-
u16 addr_r(offs_t offset);
u8 adcsr_r();
u8 adcr_r();
@@ -41,9 +30,13 @@ public:
u64 internal_update(u64 current_time);
protected:
+ sh_adc_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock);
+
required_device<sh7042_device> m_cpu;
required_device<sh_intc_device> m_intc;
+ int m_port_base, m_port_mask, m_port_shift;
int m_intc_vector;
+ bool m_is_hs;
enum {
T_SOFT = 1<<0,
@@ -95,6 +88,37 @@ protected:
int get_channel_index(int count);
};
-DECLARE_DEVICE_TYPE(SH_ADC, sh_adc_device)
+class sh_adc_ms_device : public sh_adc_device {
+public:
+ sh_adc_ms_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
+
+ template<typename T, typename U> sh_adc_ms_device(const machine_config &mconfig, const char *tag, device_t *owner,
+ T &&cpu, U &&intc, int port_base, int vect) :
+ sh_adc_ms_device(mconfig, tag, owner)
+ {
+ m_cpu.set_tag(std::forward<T>(cpu));
+ m_intc.set_tag(std::forward<U>(intc));
+ m_is_hs = false;
+ m_port_base = port_base;
+ m_intc_vector = vect;
+ }
+};
+
+class sh_adc_hs_device : public sh_adc_device {
+public:
+ sh_adc_hs_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
+
+ template<typename T, typename U> sh_adc_hs_device(const machine_config &mconfig, const char *tag, device_t *owner,
+ T &&cpu, U &&intc, int vect) :
+ sh_adc_hs_device(mconfig, tag, owner)
+ {
+ m_cpu.set_tag(std::forward<T>(cpu));
+ m_intc.set_tag(std::forward<U>(intc));
+ m_intc_vector = vect;
+ }
+};
+
+DECLARE_DEVICE_TYPE(SH_ADC_MS, sh_adc_ms_device)
+DECLARE_DEVICE_TYPE(SH_ADC_HS, sh_adc_hs_device)
#endif // MAME_CPU_SH_SH_ADC_H
diff --git a/src/devices/cpu/sh/sh_bsc.cpp b/src/devices/cpu/sh/sh_bsc.cpp
new file mode 100644
index 00000000000..1151b220928
--- /dev/null
+++ b/src/devices/cpu/sh/sh_bsc.cpp
@@ -0,0 +1,139 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert
+/***************************************************************************
+
+ sh_bsc.h
+
+ SH DMA controller
+
+***************************************************************************/
+
+#include "emu.h"
+#include "sh_bsc.h"
+
+DEFINE_DEVICE_TYPE(SH_BSC, sh_bsc_device, "sh_bsc", "SH Bus State Controller")
+
+sh_bsc_device::sh_bsc_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
+ device_t(mconfig, SH_BSC, tag, owner, clock)
+{
+}
+
+void sh_bsc_device::device_start()
+{
+ save_item(NAME(m_bcr1));
+ save_item(NAME(m_bcr2));
+ save_item(NAME(m_wcr1));
+ save_item(NAME(m_wcr2));
+ save_item(NAME(m_dcr));
+ save_item(NAME(m_rtcsr));
+ save_item(NAME(m_rtcnt));
+ save_item(NAME(m_rtcor));
+}
+
+void sh_bsc_device::device_reset()
+{
+ m_bcr1 = 0x200f;
+ m_bcr2 = 0xffff;
+ m_wcr1 = 0xffff;
+ m_wcr2 = 0x000f;
+ m_dcr = 0;
+ m_rtcsr = 0;
+ m_rtcnt = 0;
+ m_rtcor = 0;
+}
+
+u16 sh_bsc_device::bcr1_r()
+{
+ logerror("bcr1_r\n");
+ return m_bcr1;
+}
+
+void sh_bsc_device::bcr1_w(offs_t, u16 data, u16 mem_mask)
+{
+ COMBINE_DATA(&m_bcr1);
+ logerror("bcr1_w %04x\n", m_bcr1);
+}
+
+u16 sh_bsc_device::bcr2_r()
+{
+ logerror("bcr2_r\n");
+ return m_bcr2;
+}
+
+void sh_bsc_device::bcr2_w(offs_t, u16 data, u16 mem_mask)
+{
+ COMBINE_DATA(&m_bcr2);
+ logerror("bcr2_w %04x\n", m_bcr2);
+}
+
+u16 sh_bsc_device::wcr1_r()
+{
+ logerror("wcr1_r\n");
+ return m_wcr1;
+}
+
+void sh_bsc_device::wcr1_w(offs_t, u16 data, u16 mem_mask)
+{
+ COMBINE_DATA(&m_wcr1);
+ logerror("wcr1_w %04x\n", m_wcr1);
+}
+
+u16 sh_bsc_device::wcr2_r()
+{
+ logerror("wcr2_r\n");
+ return m_wcr2;
+}
+
+void sh_bsc_device::wcr2_w(offs_t, u16 data, u16 mem_mask)
+{
+ COMBINE_DATA(&m_wcr2);
+ logerror("wcr2_w %04x\n", m_wcr2);
+}
+
+u16 sh_bsc_device::dcr_r()
+{
+ logerror("dcr_r\n");
+ return m_dcr;
+}
+
+void sh_bsc_device::dcr_w(offs_t, u16 data, u16 mem_mask)
+{
+ COMBINE_DATA(&m_dcr);
+ logerror("dcr_w %04x\n", m_dcr);
+}
+
+u16 sh_bsc_device::rtcsr_r()
+{
+ logerror("rtcsr_r\n");
+ return m_rtcsr;
+}
+
+void sh_bsc_device::rtcsr_w(offs_t, u16 data, u16 mem_mask)
+{
+ COMBINE_DATA(&m_rtcsr);
+ logerror("rtcsr_w %04x\n", m_rtcsr);
+}
+
+u16 sh_bsc_device::rtcnt_r()
+{
+ logerror("rtcnt_r\n");
+ return m_rtcnt;
+}
+
+void sh_bsc_device::rtcnt_w(offs_t, u16 data, u16 mem_mask)
+{
+ COMBINE_DATA(&m_rtcnt);
+ logerror("rtcnt_w %04x\n", m_rtcnt);
+}
+
+u16 sh_bsc_device::rtcor_r()
+{
+ logerror("rtcor_r\n");
+ return m_rtcor;
+}
+
+void sh_bsc_device::rtcor_w(offs_t, u16 data, u16 mem_mask)
+{
+ COMBINE_DATA(&m_rtcor);
+ logerror("rtcor_w %04x\n", m_rtcor);
+}
diff --git a/src/devices/cpu/sh/sh_bsc.h b/src/devices/cpu/sh/sh_bsc.h
new file mode 100644
index 00000000000..574e57ccd64
--- /dev/null
+++ b/src/devices/cpu/sh/sh_bsc.h
@@ -0,0 +1,47 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert
+/***************************************************************************
+
+ sh_bsc.h
+
+ SH Bus State Controller
+
+***************************************************************************/
+
+#ifndef MAME_CPU_SH_SH_BSC_H
+#define MAME_CPU_SH_SH_BSC_H
+
+#pragma once
+
+class sh_bsc_device : public device_t {
+public:
+ sh_bsc_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
+
+ u16 bcr1_r();
+ void bcr1_w(offs_t, u16 data, u16 mem_mask);
+ u16 bcr2_r();
+ void bcr2_w(offs_t, u16 data, u16 mem_mask);
+ u16 wcr1_r();
+ void wcr1_w(offs_t, u16 data, u16 mem_mask);
+ u16 wcr2_r();
+ void wcr2_w(offs_t, u16 data, u16 mem_mask);
+ u16 dcr_r();
+ void dcr_w(offs_t, u16 data, u16 mem_mask);
+ u16 rtcsr_r();
+ void rtcsr_w(offs_t, u16 data, u16 mem_mask);
+ u16 rtcnt_r();
+ void rtcnt_w(offs_t, u16 data, u16 mem_mask);
+ u16 rtcor_r();
+ void rtcor_w(offs_t, u16 data, u16 mem_mask);
+
+
+protected:
+ u16 m_bcr1, m_bcr2, m_wcr1, m_wcr2, m_dcr, m_rtcsr, m_rtcnt, m_rtcor;
+
+ virtual void device_start() override;
+ virtual void device_reset() override;
+};
+
+DECLARE_DEVICE_TYPE(SH_BSC, sh_bsc_device)
+
+#endif
diff --git a/src/devices/cpu/sh/sh_cmt.cpp b/src/devices/cpu/sh/sh_cmt.cpp
index 1e659080e75..685fbc461d6 100644
--- a/src/devices/cpu/sh/sh_cmt.cpp
+++ b/src/devices/cpu/sh/sh_cmt.cpp
@@ -29,10 +29,21 @@ sh_cmt_device::sh_cmt_device(const machine_config &mconfig, const char *tag, dev
void sh_cmt_device::device_start()
{
+ save_item(NAME(m_next_event));
+ save_item(NAME(m_str));
+ save_item(NAME(m_csr));
+ save_item(NAME(m_cnt));
+ save_item(NAME(m_cor));
+
}
void sh_cmt_device::device_reset()
{
+ std::fill(m_next_event.begin(), m_next_event.end(), 0);
+ m_str = 0;
+ std::fill(m_csr.begin(), m_csr.end(), 0);
+ std::fill(m_cnt.begin(), m_cnt.end(), 0);
+ std::fill(m_cor.begin(), m_cor.end(), 0xffff);
}
u64 sh_cmt_device::internal_update(u64 current_time)
@@ -125,7 +136,6 @@ void sh_cmt_device::cmstr_w(offs_t, u16 data, u16 mem_mask)
cnt_update(1, m_cpu->current_cycles());
u16 old = m_str;
COMBINE_DATA(&m_str);
- logerror("active %c %c\n", m_str & 1 ? '0' : '-', m_str & 2 ? '1' : '-');
for(int i=0; i != 2; i++)
if(!BIT(old, i) && BIT(m_str, i))
clock_start(i);
@@ -137,18 +147,12 @@ void sh_cmt_device::cmstr_w(offs_t, u16 data, u16 mem_mask)
void sh_cmt_device::csr_w(int reg, u16 data, u16 mem_mask)
{
cnt_update(reg, m_cpu->current_cycles());
- u16 old = m_csr[reg];
COMBINE_DATA(&m_csr[reg]);
- if(!(old & 0x80))
- m_csr[reg] &= ~0x80;
- if((old ^ m_csr[reg]) & 0x7f)
- logerror("csr_w %d f=%d ie=%d div=%d\n", reg, BIT(m_csr[reg], 7), BIT(m_csr[reg], 6), 8 << (2*BIT(m_csr[reg], 0, 2)));
}
void sh_cmt_device::cnt_w(int reg, u16 data, u16 mem_mask)
{
COMBINE_DATA(&m_cnt[reg]);
- logerror("cnt_w %d, %04x\n", reg, m_cnt[reg]);
if((m_str >> reg) & 1) {
compute_next_event(reg);
m_cpu->internal_update();
@@ -159,7 +163,6 @@ void sh_cmt_device::cor_w(int reg, u16 data, u16 mem_mask)
{
cnt_update(reg, m_cpu->current_cycles());
COMBINE_DATA(&m_cor[reg]);
- logerror("cor_w %d, %04x\n", reg, m_cor[reg]);
if((m_str >> reg) & 1) {
compute_next_event(reg);
m_cpu->internal_update();
@@ -168,7 +171,7 @@ void sh_cmt_device::cor_w(int reg, u16 data, u16 mem_mask)
void sh_cmt_device::clock_start(int clk)
{
- logerror("start clock %d %dHz\n", clk, (m_cpu->clock() >> (3 + 2*BIT(m_csr[clk], 0, 2))) / (m_cor[clk] + 1));
+ // logerror("start clock %d %dHz\n", clk, (m_cpu->clock() >> (3 + 2*BIT(m_csr[clk], 0, 2))) / (m_cor[clk] + 1));
compute_next_event(clk);
}
@@ -190,8 +193,10 @@ void sh_cmt_device::cnt_update(int clk, u64 current_time)
if(!((m_str >> clk) & 1))
return;
u64 step = (m_cor[clk] + 1) << (3 + 2*BIT(m_csr[clk], 0, 2));
- while(current_time >= m_next_event[clk])
- m_next_event[clk] += step;
- u64 delta = m_next_event[clk] - current_time;
- m_cnt[clk] = m_cor[clk] - ((delta - 1) >> (3 + 2*BIT(m_csr[clk], 0, 2)));
+ if(m_next_event[clk]) {
+ while(current_time >= m_next_event[clk])
+ m_next_event[clk] += step;
+ u64 delta = m_next_event[clk] - current_time;
+ m_cnt[clk] = m_cor[clk] - ((delta - 1) >> (3 + 2*BIT(m_csr[clk], 0, 2)));
+ }
}
diff --git a/src/devices/cpu/sh/sh_dmac.cpp b/src/devices/cpu/sh/sh_dmac.cpp
new file mode 100644
index 00000000000..39775445ba9
--- /dev/null
+++ b/src/devices/cpu/sh/sh_dmac.cpp
@@ -0,0 +1,115 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert
+/***************************************************************************
+
+ sh_dmac.h
+
+ SH DMA controller
+
+***************************************************************************/
+
+#include "emu.h"
+#include "sh_dmac.h"
+#include "sh7042.h"
+
+DEFINE_DEVICE_TYPE(SH_DMAC, sh_dmac_device, "sh_dmac", "SH DMA controller")
+DEFINE_DEVICE_TYPE(SH_DMAC_CHANNEL, sh_dmac_channel_device, "sh_dmac_channel", "SH DMA controller channel")
+
+sh_dmac_device::sh_dmac_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
+ device_t(mconfig, SH_DMAC, tag, owner, clock),
+ m_cpu(*this, finder_base::DUMMY_TAG)
+{
+}
+
+void sh_dmac_device::device_start()
+{
+ save_item(NAME(m_dmaor));
+}
+
+void sh_dmac_device::device_reset()
+{
+ m_dmaor = 0;
+}
+
+u16 sh_dmac_device::dmaor_r()
+{
+ logerror("dmaor_r\n");
+ return m_dmaor;
+}
+
+void sh_dmac_device::dmaor_w(offs_t, u16 data, u16 mem_mask)
+{
+ COMBINE_DATA(&m_dmaor);
+ logerror("dmaor_w %04x\n", m_dmaor);
+}
+
+sh_dmac_channel_device::sh_dmac_channel_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
+ device_t(mconfig, SH_DMAC_CHANNEL, tag, owner, clock),
+ m_cpu(*this, finder_base::DUMMY_TAG),
+ m_intc(*this, finder_base::DUMMY_TAG)
+{
+}
+
+void sh_dmac_channel_device::device_start()
+{
+ save_item(NAME(m_sar));
+ save_item(NAME(m_dar));
+ save_item(NAME(m_dmatcr));
+ save_item(NAME(m_chcr));
+}
+
+void sh_dmac_channel_device::device_reset()
+{
+ m_sar = 0;
+ m_dar = 0;
+ m_dmatcr = 0;
+ m_chcr = 0;
+}
+
+u32 sh_dmac_channel_device::sar_r()
+{
+ logerror("sar_r\n");
+ return m_sar;
+}
+
+void sh_dmac_channel_device::sar_w(offs_t, u32 data, u32 mem_mask)
+{
+ COMBINE_DATA(&m_sar);
+ logerror("sar_w %08x\n", m_sar);
+}
+
+u32 sh_dmac_channel_device::dar_r()
+{
+ logerror("dar_r\n");
+ return m_dar;
+}
+
+void sh_dmac_channel_device::dar_w(offs_t, u32 data, u32 mem_mask)
+{
+ COMBINE_DATA(&m_dar);
+ logerror("dar_w %08x\n", m_dar);
+}
+
+u32 sh_dmac_channel_device::dmatcr_r()
+{
+ logerror("dmatcr_r\n");
+ return m_dmatcr;
+}
+
+void sh_dmac_channel_device::dmatcr_w(offs_t, u32 data, u32 mem_mask)
+{
+ COMBINE_DATA(&m_dmatcr);
+ logerror("dmatcr_w %08x\n", m_dmatcr);
+}
+
+u32 sh_dmac_channel_device::chcr_r()
+{
+ logerror("chcr_r\n");
+ return m_chcr;
+}
+
+void sh_dmac_channel_device::chcr_w(offs_t, u32 data, u32 mem_mask)
+{
+ COMBINE_DATA(&m_chcr);
+ logerror("chcr_w %08x\n", m_chcr);
+}
diff --git a/src/devices/cpu/sh/sh_dmac.h b/src/devices/cpu/sh/sh_dmac.h
index 25071765428..f5ae0bfeec5 100644
--- a/src/devices/cpu/sh/sh_dmac.h
+++ b/src/devices/cpu/sh/sh_dmac.h
@@ -2,49 +2,78 @@
// copyright-holders:Olivier Galibert
/***************************************************************************
- sh_dma.h
+ sh_dmac.h
SH DMA controller
***************************************************************************/
-#ifndef MAME_CPU_SH_SH_DMA_H
-#define MAME_CPU_SH_SH_DMA_H
+#ifndef MAME_CPU_SH_SH_DMAC_H
+#define MAME_CPU_SH_SH_DMAC_H
#pragma once
// To generalize eventually
class sh7042_device;
+class sh_intc_device;
-class sh_dma_device : public device_t {
+class sh_dmac_device : public device_t {
public:
- sh_dma_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
+ sh_dmac_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
- template <typename T> sh_dma_device(const machine_config &mconfig, const char *tag, device_t *owner, T &&cpu)
- : sh_dma_device(mconfig, tag, owner)
+ template <typename T> sh_dmac_device(const machine_config &mconfig, const char *tag, device_t *owner, T &&cpu)
+ : sh_dmac_device(mconfig, tag, owner)
{
set_info(cpu);
}
template<typename T> void set_info(T &&cpu) { m_cpu.set_tag(std::forward<T>(cpu)); }
- u16 addr_r(offs_t offset);
- u8 dmasr_r();
- u8 dmar_r();
- void dmasr_w(u8 data);
- void dmar_w(u8 data);
+ u16 dmaor_r();
+ void dmaor_w(offs_t, u16 data, u16 mem_mask);
+
protected:
required_device<sh7042_device> m_cpu;
- uint16_t m_addr[8];
- uint8_t m_dmasr, m_dmar;
+ u16 m_dmaor;
+
+ virtual void device_start() override;
+ virtual void device_reset() override;
+};
+
+class sh_dmac_channel_device : public device_t {
+public:
+ sh_dmac_channel_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
+
+ template <typename T, typename U> sh_dmac_channel_device(const machine_config &mconfig, const char *tag, device_t *owner, T &&cpu, U &&intc)
+ : sh_dmac_channel_device(mconfig, tag, owner)
+ {
+ set_info(cpu, intc);
+ }
+
+ template<typename T, typename U> void set_info(T &&cpu, U &&intc) { m_cpu.set_tag(std::forward<T>(cpu)); m_intc.set_tag(std::forward<U>(intc)); }
+
+ u32 sar_r();
+ void sar_w(offs_t, u32 data, u32 mem_mask);
+ u32 dar_r();
+ void dar_w(offs_t, u32 data, u32 mem_mask);
+ u32 dmatcr_r();
+ void dmatcr_w(offs_t, u32 data, u32 mem_mask);
+ u32 chcr_r();
+ void chcr_w(offs_t, u32 data, u32 mem_mask);
+
+protected:
+ required_device<sh7042_device> m_cpu;
+ required_device<sh_intc_device> m_intc;
+ u32 m_sar, m_dar, m_dmatcr, m_chcr;
virtual void device_start() override;
virtual void device_reset() override;
};
-DECLARE_DEVICE_TYPE(SH_DMA, sh_dma_device)
+DECLARE_DEVICE_TYPE(SH_DMAC, sh_dmac_device)
+DECLARE_DEVICE_TYPE(SH_DMAC_CHANNEL, sh_dmac_channel_device)
#endif
diff --git a/src/devices/cpu/sh/sh_intc.cpp b/src/devices/cpu/sh/sh_intc.cpp
index 21f7804efd8..bf08a6a5081 100644
--- a/src/devices/cpu/sh/sh_intc.cpp
+++ b/src/devices/cpu/sh/sh_intc.cpp
@@ -45,32 +45,75 @@ void sh_intc_device::device_start()
save_item(NAME(m_ipr));
save_item(NAME(m_icr));
save_item(NAME(m_isr));
+ save_item(NAME(m_pending));
+ save_item(NAME(m_lines));
std::fill(m_ipr.begin(), m_ipr.end(), 0);
m_isr = 0;
m_icr = 0;
+ m_lines = 0;
}
void sh_intc_device::device_reset()
{
+ std::fill(m_pending.begin(), m_pending.end(), 0);
}
-int sh_intc_device::interrupt_taken(int vector)
+void sh_intc_device::interrupt_taken(int irqline, int vector)
{
- return 0;
+ // Don't clear an external interrupt which is level and still active
+ if(vector < 64 || vector >= 72 || BIT(m_icr, 7-(vector & 7)) || !BIT(m_lines, vector & 7))
+ m_pending[vector >> 5] &= ~(1 << (vector & 31));
+
+ update_irq();
+}
+
+void sh_intc_device::update_irq()
+{
+ int best_level = -1;
+ int best_vector = 0;
+
+ for(u32 bv = 64/32; bv != 160/32; bv ++) {
+ if(!m_pending[bv])
+ continue;
+ for(u32 iv = 0; iv != 32; iv++) {
+ if(!BIT(m_pending[bv], iv))
+ continue;
+ u32 vector = bv*32 + iv;
+ u32 slot = pribit[vector];
+ u32 shift = 12-4*(slot & 3);
+ int level = (m_ipr[slot >> 2] >> shift) & 15;
+ if(level > best_level) {
+ best_level = level;
+ best_vector = vector;
+ }
+ }
+ }
+ m_cpu->set_internal_interrupt(best_level, best_vector);
}
void sh_intc_device::internal_interrupt(int vector)
{
- u32 slot = pribit[vector];
- u32 shift = 12-4*(slot & 3);
- u32 level = (m_ipr[slot >> 2] >> shift) & 15;
- logerror("Internal interrupt %d / %d (ipr%c %d-%d)\n", vector, level, 'a' + (slot >> 2), shift + 3, shift);
- m_cpu->set_internal_interrupt(level, vector);
+ m_pending[vector >> 5] |= 1 << (vector & 31);
+ update_irq();
}
void sh_intc_device::set_input(int inputnum, int state)
{
+ if(BIT(m_lines, inputnum) == state)
+ return;
+ if(BIT(m_icr, 7-inputnum)) {
+ // Level interrupt
+ if(state)
+ m_pending[64 >> 5] |= 1 << inputnum;
+ else
+ m_pending[64 >> 5] &= ~(1 << inputnum);
+ } else {
+ // Edge interrupt
+ if(state)
+ m_pending[64 >> 5] |= 1 << inputnum;
+ }
+ update_irq();
}
u16 sh_intc_device::icr_r()
diff --git a/src/devices/cpu/sh/sh_intc.h b/src/devices/cpu/sh/sh_intc.h
index be1c1a53633..d00f167b927 100644
--- a/src/devices/cpu/sh/sh_intc.h
+++ b/src/devices/cpu/sh/sh_intc.h
@@ -24,7 +24,7 @@ public:
m_cpu.set_tag(std::forward<T>(cpu));
}
- int interrupt_taken(int vector);
+ void interrupt_taken(int irqline, int vector);
void internal_interrupt(int vector);
void set_input(int inputnum, int state);
@@ -38,14 +38,19 @@ public:
protected:
static const u8 pribit[256];
+ std::array<u32, 8> m_pending;
std::array<u16, 8> m_ipr;
u16 m_isr, m_icr;
+ u8 m_lines;
+
required_device<sh7042_device> m_cpu;
virtual void device_start() override;
virtual void device_reset() override;
+
+ void update_irq();
};
DECLARE_DEVICE_TYPE(SH_INTC, sh_intc_device)
diff --git a/src/devices/cpu/sh/sh_mtu.cpp b/src/devices/cpu/sh/sh_mtu.cpp
new file mode 100644
index 00000000000..afb453f3e94
--- /dev/null
+++ b/src/devices/cpu/sh/sh_mtu.cpp
@@ -0,0 +1,527 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert
+/***************************************************************************
+
+ sh_mtu.h
+
+ SH DMA controller
+
+***************************************************************************/
+
+#include "emu.h"
+#include "sh_mtu.h"
+#include "sh7042.h"
+
+#define V 1
+
+DEFINE_DEVICE_TYPE(SH_MTU, sh_mtu_device, "sh_mtu", "SH Multifuntion timer pulse unit")
+DEFINE_DEVICE_TYPE(SH_MTU_CHANNEL, sh_mtu_channel_device, "sh_mtu_channel", "SH Multifuntion timer pulse unit channel")
+
+sh_mtu_device::sh_mtu_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
+ device_t(mconfig, SH_MTU, tag, owner, clock),
+ m_cpu(*this, finder_base::DUMMY_TAG),
+ m_timer_channel(*this, "%u", 0)
+{
+}
+
+void sh_mtu_device::device_start()
+{
+ save_item(NAME(m_tstr));
+ save_item(NAME(m_tsyr));
+ save_item(NAME(m_toer));
+ save_item(NAME(m_tocr));
+ save_item(NAME(m_tgcr));
+ save_item(NAME(m_tcdr));
+ save_item(NAME(m_tddr));
+ save_item(NAME(m_tcnts));
+ save_item(NAME(m_tcbr));
+}
+
+void sh_mtu_device::device_reset()
+{
+ m_tstr = 0;
+ m_tsyr = 0;
+ m_toer = 0xc0;
+ m_tocr = 0;
+ m_tgcr = 0x80;
+ m_tcdr = 0xffff;
+ m_tddr = 0xffff;
+ m_tcnts = 0;
+ m_tcbr = 0xffff;
+}
+
+u8 sh_mtu_device::tstr_r()
+{
+ logerror("tstr_r\n");
+ return m_tstr;
+}
+
+void sh_mtu_device::tstr_w(u8 data)
+{
+ m_tstr = data;
+ logerror("tstr_w %02x\n", m_tstr);
+ // To generalize
+ m_timer_channel[0]->set_enable(BIT(m_tstr, 0));
+ m_timer_channel[1]->set_enable(BIT(m_tstr, 1));
+ m_timer_channel[2]->set_enable(BIT(m_tstr, 2));
+ m_timer_channel[3]->set_enable(BIT(m_tstr, 6));
+ m_timer_channel[4]->set_enable(BIT(m_tstr, 7));
+}
+
+u8 sh_mtu_device::tsyr_r()
+{
+ logerror("tsyr_r\n");
+ return m_tsyr;
+}
+
+void sh_mtu_device::tsyr_w(u8 data)
+{
+ m_tsyr = data;
+ logerror("tsyr_w %02x\n", m_tsyr);
+}
+
+u8 sh_mtu_device::toer_r()
+{
+ logerror("toer_r\n");
+ return m_toer;
+}
+
+void sh_mtu_device::toer_w(u8 data)
+{
+ m_toer = data;
+ logerror("toer_w %02x\n", m_toer);
+}
+
+u8 sh_mtu_device::tocr_r()
+{
+ logerror("tocr_r\n");
+ return m_tocr;
+}
+
+void sh_mtu_device::tocr_w(u8 data)
+{
+ m_tocr = data;
+ logerror("tocr_w %02x\n", m_tocr);
+}
+
+u8 sh_mtu_device::tgcr_r()
+{
+ logerror("tgcr_r\n");
+ return m_tgcr;
+}
+
+void sh_mtu_device::tgcr_w(u8 data)
+{
+ m_tgcr = data;
+ logerror("tgcr_w %02x\n", m_tgcr);
+}
+
+u16 sh_mtu_device::tcdr_r()
+{
+ logerror("tcdr_r\n");
+ return m_tcdr;
+}
+
+void sh_mtu_device::tcdr_w(offs_t, u16 data, u16 mem_mask)
+{
+ COMBINE_DATA(&m_tcdr);
+ logerror("tcdr_w %04x\n", m_tcdr);
+}
+
+u16 sh_mtu_device::tddr_r()
+{
+ logerror("tddr_r\n");
+ return m_tddr;
+}
+
+void sh_mtu_device::tddr_w(offs_t, u16 data, u16 mem_mask)
+{
+ COMBINE_DATA(&m_tddr);
+ logerror("tddr_w %04x\n", m_tddr);
+}
+
+u16 sh_mtu_device::tcnts_r()
+{
+ logerror("tcnts_r\n");
+ return m_tcnts;
+}
+
+void sh_mtu_device::tcnts_w(offs_t, u16 data, u16 mem_mask)
+{
+ COMBINE_DATA(&m_tcnts);
+ logerror("tcnts_w %04x\n", m_tcnts);
+}
+
+u16 sh_mtu_device::tcbr_r()
+{
+ logerror("tcbr_r\n");
+ return m_tcbr;
+}
+
+void sh_mtu_device::tcbr_w(offs_t, u16 data, u16 mem_mask)
+{
+ COMBINE_DATA(&m_tcbr);
+ logerror("tcbr_w %04x\n", m_tcbr);
+}
+
+sh_mtu_channel_device::sh_mtu_channel_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
+ device_t(mconfig, SH_MTU_CHANNEL, tag, owner, clock),
+ m_cpu(*this, finder_base::DUMMY_TAG),
+ m_intc(*this, finder_base::DUMMY_TAG),
+ m_chained_timer(*this, finder_base::DUMMY_TAG)
+{
+}
+
+void sh_mtu_channel_device::device_start()
+{
+ m_channel_active = false;
+ device_reset();
+
+ save_item(NAME(m_tgr_count));
+ save_item(NAME(m_tbr_count));
+ save_item(NAME(m_tgr_clearing));
+ save_item(NAME(m_tcr));
+ save_item(NAME(m_tmdr));
+ save_item(NAME(m_tior));
+ save_item(NAME(m_tier));
+ save_item(NAME(m_tsr));
+ save_item(NAME(m_clock_type));
+ save_item(NAME(m_clock_divider));
+ save_item(NAME(m_tcnt));
+ save_item(NAME(m_tgr));
+ save_item(NAME(m_last_clock_update));
+ save_item(NAME(m_event_time));
+ save_item(NAME(m_phase));
+ save_item(NAME(m_counter_cycle));
+ save_item(NAME(m_counter_incrementing));
+ save_item(NAME(m_channel_active));
+
+ m_tsr = 0xc0;
+}
+
+void sh_mtu_channel_device::device_reset()
+{
+ // Don't touch channel_active here, top level device handles it.
+
+ m_tbr_count = 0;
+ m_tgr_clearing = TGR_CLEAR_NONE;
+ m_tcr = 0;
+ m_tmdr = 0xc0;
+ m_tior = 0;
+ m_tier = 0x40 & m_tier_mask;
+ m_clock_type = DIV_1;
+ m_clock_divider = 0;
+ m_tcnt = 0;
+ std::fill(m_tgr.begin(), m_tgr.end(), 0xffff);
+ m_last_clock_update = 0;
+ m_event_time = 0;
+ m_phase = 0;
+ m_counter_cycle = 0;
+ m_counter_incrementing = true;
+}
+
+u8 sh_mtu_channel_device::tcr_r()
+{
+ return m_tcr;
+}
+
+void sh_mtu_channel_device::tcr_w(u8 data)
+{
+ update_counter();
+ m_tcr = data;
+ logerror("tcr_w %02x\n", m_tcr);
+ switch(m_tcr & 0x60) {
+ case 0x00:
+ m_tgr_clearing = TGR_CLEAR_NONE;
+ if(V>=1) logerror("No automatic tcnt clearing\n");
+ break;
+ case 0x20: case 0x40: {
+ m_tgr_clearing = m_tcr & 0x20 ? 0 : 1;
+ if(m_tgr_count > 2 && (m_tcr & 0x80))
+ m_tgr_clearing += 2;
+ if(V>=1) logerror("Auto-clear on tgr%c\n", 'a'+m_tgr_clearing);
+ break;
+ }
+ case 0x60:
+ m_tgr_clearing = TGR_CLEAR_EXT;
+ if(V>=1) logerror("External sync clear\n");
+ break;
+ }
+
+ int count_type = m_count_types[m_tcr & 7];
+ if(count_type >= DIV_1 && m_clock_type <= DIV_4) {
+ m_clock_type = DIV_1;
+ m_clock_divider = count_type - DIV_1;
+ if(V>=1) logerror("clock divider %d (%d)\n", m_clock_divider, 1 << m_clock_divider);
+ if(!m_clock_divider)
+ m_phase = 0;
+ else {
+ switch(m_tcr & 0x18) {
+ case 0x00:
+ m_phase = 0;
+ if(V>=1) logerror("Phase 0\n");
+ break;
+ case 0x08:
+ m_phase = 1 << (m_clock_divider-1);
+ if(V>=1) logerror("Phase 180\n");
+ break;
+ case 0x10: case 0x18:
+ m_phase = 0;
+ m_clock_divider--;
+ if(V>=1) logerror("Phase 0+180\n");
+ break;
+ }
+ }
+
+ } else if(count_type == CHAIN) {
+ m_clock_type = CHAIN;
+ m_clock_divider = 0;
+ m_phase = 0;
+ if(V>=1) logerror("chained timer\n");
+
+ } else if(count_type >= INPUT_A && count_type <= INPUT_D) {
+ m_clock_type = count_type;
+ m_clock_divider = 0;
+ m_phase = 0;
+ if(V>=1) logerror("counting input %c\n", 'a'+count_type-INPUT_A);
+ }
+ recalc_event();
+}
+
+u8 sh_mtu_channel_device::tmdr_r()
+{
+ return m_tmdr;
+}
+
+void sh_mtu_channel_device::tmdr_w(u8 data)
+{
+ m_tmdr = data;
+ logerror("tmdr_w %02x\n", m_tmdr);
+}
+
+u8 sh_mtu_channel_device::tior_r()
+{
+ return m_tior;
+}
+
+void sh_mtu_channel_device::tior_w(u8 data)
+{
+ m_tior = data;
+}
+
+u8 sh_mtu_channel_device::tier_r()
+{
+ return m_tier;
+}
+
+void sh_mtu_channel_device::tier_w(u8 data)
+{
+ m_tier = data;
+ logerror("irq %c%c%c%c%c%c\n",
+ m_tier & IRQ_A ? 'a' : '.',
+ m_tier & IRQ_B ? 'b' : '.',
+ m_tier & IRQ_C ? 'c' : '.',
+ m_tier & IRQ_D ? 'd' : '.',
+ m_tier & IRQ_V ? 'v' : '.',
+ m_tier & IRQ_U ? 'u' : '.');
+ recalc_event();
+}
+
+u8 sh_mtu_channel_device::tsr_r()
+{
+ return m_tsr;
+}
+
+void sh_mtu_channel_device::tsr_w(u8 data)
+{
+ update_counter();
+ m_tsr = (data & 0x80) | (m_tsr & ~data & 0x7f);
+ recalc_event();
+}
+
+u16 sh_mtu_channel_device::tcnt_r()
+{
+ if(!machine().side_effects_disabled())
+ update_counter();
+ // Nedd to implement phase counting for the rotary controller on the psr540
+ if(m_tmdr & 0xf)
+ return 0;
+ return m_tcnt;
+}
+
+void sh_mtu_channel_device::tcnt_w(offs_t, u16 data, u16 mem_mask)
+{
+ update_counter();
+ COMBINE_DATA(&m_tcnt);
+ recalc_event();
+}
+
+u16 sh_mtu_channel_device::tgr_r(offs_t reg)
+{
+ return m_tgr[reg];
+}
+
+void sh_mtu_channel_device::tgr_w(offs_t reg, u16 data, u16 mem_mask)
+{
+ update_counter();
+ COMBINE_DATA(&m_tgr[reg]);
+ recalc_event();
+}
+
+u16 sh_mtu_channel_device::tgrc_r(offs_t reg)
+{
+ return tgr_r(reg + 2);
+}
+
+void sh_mtu_channel_device::tgrc_w(offs_t reg, u16 data, u16 mem_mask)
+{
+ tgr_w(reg + 2, data, mem_mask);
+}
+
+void sh_mtu_channel_device::set_enable(bool enable)
+{
+ update_counter();
+ m_channel_active = enable;
+ if(enable)
+ logerror("enabled\n");
+ else
+ logerror("disabled\n");
+ recalc_event();
+}
+
+u64 sh_mtu_channel_device::internal_update(u64 current_time)
+{
+ while(m_event_time && current_time >= m_event_time) {
+ update_counter(m_event_time);
+ recalc_event(m_event_time);
+ }
+
+ return m_event_time;
+}
+
+void sh_mtu_channel_device::recalc_event(u64 cur_time)
+{
+ if(!m_channel_active) {
+ m_event_time = 0;
+ return;
+ }
+
+ bool update_cpu = cur_time == 0;
+ u64 old_event_time = m_event_time;
+
+ if(m_clock_type != DIV_1) {
+ m_event_time = 0;
+ if(old_event_time && update_cpu)
+ m_cpu->internal_update();
+
+ return;
+ }
+
+ if(!cur_time)
+ cur_time = m_cpu->total_cycles();
+
+ if(m_counter_incrementing) {
+ u32 event_delay = 0xffffffff;
+ if(m_tgr_clearing >= 0)
+ m_counter_cycle = m_tgr[m_tgr_clearing] + 1;
+ else
+ m_counter_cycle = 0x10000;
+ if((m_tier & IRQ_V && m_interrupt[4] != -1) && (m_counter_cycle == 0x10000 || m_tcnt >= m_counter_cycle))
+ event_delay = 0x10000 - m_tcnt;
+
+ for(int i = 0; i < m_tgr_count; i++)
+ if(BIT(m_tier, i) && m_interrupt[i] != -1) {
+ u32 new_delay = 0xffffffff;
+ u16 cmp = m_tgr[i] + 1;
+ if(cmp > m_tcnt) {
+ if(m_tcnt >= m_counter_cycle || cmp <= m_counter_cycle)
+ new_delay = cmp - m_tcnt;
+ } else if(cmp <= m_counter_cycle) {
+ if(m_tcnt < m_counter_cycle)
+ new_delay = (m_counter_cycle - m_tcnt) + cmp;
+ else
+ new_delay = (0x10000 - m_tcnt) + cmp;
+ }
+
+ if(event_delay > new_delay)
+ event_delay = new_delay;
+ }
+ if(event_delay != 0xffffffff)
+ m_event_time = ((((cur_time + (1ULL << m_clock_divider) - m_phase) >> m_clock_divider) + event_delay - 1) << m_clock_divider) + m_phase;
+ else
+ m_event_time = 0;
+ } else {
+ logerror("decrementing counter\n");
+ exit(1);
+ }
+
+ if(old_event_time != m_event_time && update_cpu)
+ m_cpu->internal_update();
+}
+
+void sh_mtu_channel_device::update_counter(u64 cur_time)
+{
+ if(m_clock_type != DIV_1)
+ return;
+
+ if(!cur_time)
+ cur_time = m_cpu->total_cycles();
+
+ if(!m_channel_active) {
+ m_last_clock_update = cur_time;
+ return;
+ }
+
+ u64 base_time = m_last_clock_update;
+ m_last_clock_update = cur_time;
+ u64 new_time = cur_time;
+ if(m_clock_divider) {
+ base_time = (base_time + m_phase) >> m_clock_divider;
+ new_time = (new_time + m_phase) >> m_clock_divider;
+ }
+ if(new_time == base_time)
+ return;
+
+ if(m_counter_incrementing) {
+ u16 prev = m_tcnt;
+ u64 delta = new_time - base_time;
+ u64 tt = m_tcnt + delta;
+
+ if(prev >= m_counter_cycle) {
+ if(tt >= 0x10000)
+ m_tcnt = (tt - 0x10000) % m_counter_cycle;
+ else
+ m_tcnt = tt;
+ } else
+ m_tcnt = tt % m_counter_cycle;
+
+ for(int i = 0; i < m_tgr_count; i++) {
+ u16 cmp = m_tgr[i] + 1;
+ bool match = m_tcnt == cmp || (tt == cmp && tt == m_counter_cycle);
+ if(!match) {
+ // Need to do additional checks here for software that polls the flags with interrupts disabled, since recalc_event only schedules IRQ events.
+ if(prev >= m_counter_cycle)
+ match = (cmp > prev && tt >= cmp) || (cmp <= m_counter_cycle && m_tcnt < m_counter_cycle && (delta - (0x10000 - prev)) >= cmp);
+ else if(cmp <= m_counter_cycle)
+ match = delta >= m_counter_cycle || (prev < cmp && tt >= cmp) || (m_tcnt <= prev && m_tcnt >= cmp);
+
+ if(match && BIT(m_tier, i) && m_interrupt[i] != -1)
+ logerror("update_counter unexpected TGR %d IRQ\n", i);
+ }
+
+ if(match) {
+ m_tsr |= 1 << i;
+ if(BIT(m_tier, i) && m_interrupt[i] != -1)
+ m_intc->internal_interrupt(m_interrupt[i]);
+ }
+ }
+ if(tt >= 0x10000 && (m_counter_cycle == 0x10000 || prev >= m_counter_cycle)) {
+ m_tsr |= IRQ_V;
+ if(m_tier & IRQ_V && m_interrupt[4] != -1)
+ m_intc->internal_interrupt(m_interrupt[4]);
+ }
+ } else {
+ logerror("decrementing counter\n");
+ exit(1);
+ }
+}
diff --git a/src/devices/cpu/sh/sh_mtu.h b/src/devices/cpu/sh/sh_mtu.h
new file mode 100644
index 00000000000..9c90bc398bf
--- /dev/null
+++ b/src/devices/cpu/sh/sh_mtu.h
@@ -0,0 +1,182 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert
+/***************************************************************************
+
+ sh_mtu.h
+
+ SH Multifunction timer pulse unit
+
+***************************************************************************/
+
+#ifndef MAME_CPU_SH_SH_MTU_H
+#define MAME_CPU_SH_SH_MTU_H
+
+#pragma once
+
+// To generalize eventually
+class sh7042_device;
+class sh_intc_device;
+
+class sh_mtu_channel_device : public device_t {
+public:
+ enum {
+ CHAIN,
+ INPUT_A,
+ INPUT_B,
+ INPUT_C,
+ INPUT_D,
+ DIV_1,
+ DIV_2,
+ DIV_4,
+ DIV_8,
+ DIV_16,
+ DIV_32,
+ DIV_64,
+ DIV_128,
+ DIV_256,
+ DIV_512,
+ DIV_1024,
+ DIV_2048,
+ DIV_4096
+ };
+
+ enum {
+ TGR_CLEAR_NONE = -1,
+ TGR_CLEAR_EXT = -2
+ };
+
+ enum {
+ IRQ_A = 0x01,
+ IRQ_B = 0x02,
+ IRQ_C = 0x04,
+ IRQ_D = 0x08,
+ IRQ_V = 0x10,
+ IRQ_U = 0x20,
+ IRQ_E = 0x80
+ };
+
+ sh_mtu_channel_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
+
+ template <typename T, typename U> sh_mtu_channel_device(const machine_config &mconfig, const char *tag, device_t *owner, T &&cpu, int tgr_count, int tier_mask, U &&intc, int irq_base,
+ int t0, int t1, int t2, int t3, int t4, int t5, int t6, int t7)
+ : sh_mtu_channel_device(mconfig, tag, owner)
+ {
+ set_info(cpu, intc);
+ m_tgr_count = tgr_count;
+ m_tbr_count = 0;
+ m_tier_mask = tier_mask;
+
+ m_interrupt[0] = irq_base;
+ m_interrupt[1] = irq_base + 1;
+ m_interrupt[2] = tier_mask & 0x04 ? -1 : irq_base + 2;
+ m_interrupt[3] = tier_mask & 0x08 ? -1 : irq_base + 3;
+ m_interrupt[4] = irq_base + 4;
+ m_interrupt[5] = tier_mask & 0x20 ? -1 : irq_base + 5;
+
+ m_count_types[0] = t0;
+ m_count_types[1] = t1;
+ m_count_types[2] = t2;
+ m_count_types[3] = t3;
+ m_count_types[4] = t4;
+ m_count_types[5] = t5;
+ m_count_types[6] = t6;
+ m_count_types[7] = t7;
+ }
+
+ template<typename T, typename U> void set_info(T &&cpu, U &&intc) { m_cpu.set_tag(std::forward<T>(cpu)); m_intc.set_tag(std::forward<U>(intc)); }
+ template<typename T> void set_chain(T &&chain) { m_chained_timer.set_tag(std::forward<T>(chain)); }
+
+ u8 tcr_r();
+ void tcr_w(u8 data);
+ u8 tmdr_r();
+ void tmdr_w(u8 data);
+ u8 tior_r();
+ void tior_w(u8 data);
+ u8 tier_r();
+ void tier_w(u8 data);
+ u8 tsr_r();
+ void tsr_w(u8 data);
+ u16 tcnt_r();
+ void tcnt_w(offs_t, u16 data, u16 mem_mask);
+ u16 tgr_r(offs_t reg);
+ void tgr_w(offs_t reg, u16 data, u16 mem_mask);
+ u16 tgrc_r(offs_t reg);
+ void tgrc_w(offs_t reg, u16 data, u16 mem_mask);
+
+ void set_enable(bool enable);
+ u64 internal_update(u64 current_time);
+
+protected:
+ required_device<sh7042_device> m_cpu;
+ required_device<sh_intc_device> m_intc;
+ optional_device<sh_mtu_channel_device> m_chained_timer;
+ int m_interrupt[6];
+ u8 m_tier_mask;
+
+ int m_tgr_count, m_tbr_count;
+ int m_tgr_clearing;
+ u8 m_tcr, m_tmdr, m_tior, m_tier, m_tsr;
+ int m_clock_type, m_clock_divider;
+ u16 m_tcnt;
+ std::array<u16, 4> m_tgr;
+ u64 m_last_clock_update, m_event_time;
+ u32 m_phase, m_counter_cycle;
+ bool m_counter_incrementing;
+ bool m_channel_active;
+ std::array<int, 8> m_count_types;
+
+ virtual void device_start() override;
+ virtual void device_reset() override;
+ void update_counter(u64 cur_time = 0);
+ void recalc_event(u64 cur_time = 0);
+};
+
+class sh_mtu_device : public device_t {
+public:
+ sh_mtu_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
+
+ template <typename T> sh_mtu_device(const machine_config &mconfig, const char *tag, device_t *owner, T &&cpu, int timer_count)
+ : sh_mtu_device(mconfig, tag, owner)
+ {
+ set_info(cpu);
+ m_timer_count = timer_count;
+ }
+
+ template<typename T> void set_info(T &&cpu) { m_cpu.set_tag(std::forward<T>(cpu)); }
+
+ u8 tstr_r();
+ void tstr_w(u8 data);
+ u8 tsyr_r();
+ void tsyr_w(u8 data);
+ u8 toer_r();
+ void toer_w(u8 data);
+ u8 tocr_r();
+ void tocr_w(u8 data);
+ u8 tgcr_r();
+ void tgcr_w(u8 data);
+ u16 tcdr_r();
+ void tcdr_w(offs_t, u16 data, u16 mem_mask);
+ u16 tddr_r();
+ void tddr_w(offs_t, u16 data, u16 mem_mask);
+ u16 tcnts_r();
+ void tcnts_w(offs_t, u16 data, u16 mem_mask);
+ u16 tcbr_r();
+ void tcbr_w(offs_t, u16 data, u16 mem_mask);
+
+protected:
+ required_device<sh7042_device> m_cpu;
+ required_device_array<sh_mtu_channel_device, 5> m_timer_channel;
+
+ int m_timer_count;
+
+ u8 m_tstr, m_tsyr, m_toer, m_tocr, m_tgcr;
+ u16 m_tcdr, m_tddr, m_tcnts, m_tcbr;
+
+ virtual void device_start() override;
+ virtual void device_reset() override;
+};
+
+DECLARE_DEVICE_TYPE(SH_MTU, sh_mtu_device)
+DECLARE_DEVICE_TYPE(SH_MTU_CHANNEL, sh_mtu_channel_device)
+
+#endif
diff --git a/src/devices/cpu/sh/sh_sci.cpp b/src/devices/cpu/sh/sh_sci.cpp
new file mode 100644
index 00000000000..edb35d84489
--- /dev/null
+++ b/src/devices/cpu/sh/sh_sci.cpp
@@ -0,0 +1,765 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert
+
+#include "emu.h"
+#include "sh_sci.h"
+#include "sh7042.h"
+#include "sh_intc.h"
+
+#define LOG_REGS (1 << 1U) // Register writes
+#define LOG_RREGS (1 << 2U) // Register reads
+#define LOG_RATE (1 << 3U) // Bitrate setting
+#define LOG_DATA (1 << 4U) // Bytes transmitted
+#define LOG_CLOCK (1 << 5U) // Clock and transmission start/stop
+#define LOG_STATE (1 << 6U) // State machine states
+#define LOG_TICK (1 << 7U) // Clock ticks
+
+#define VERBOSE (LOG_DATA|LOG_RATE)
+
+#include "logmacro.h"
+
+DEFINE_DEVICE_TYPE(SH_SCI, sh_sci_device, "sh_sci", "SH Serial Communications Interface")
+
+
+// Clocking:
+// Async mode:
+// The circuit wants 16 events per bit.
+// * Internal clocking: the cpu clock is divided by one of (1, 4, 16, 64) from the cks field of smr
+// then by (brr+1) then by 2.
+// * External clocking: the external clock is supposed to be 16*bitrate.
+// Sync mode:
+// The circuit wants 2 events per bit, a positive and a negative edge.
+// * Internal clocking: the cpu clock is divided by one of (1, 4, 16, 64) from the cks field of smr
+// then by (brr+1) then by 2. Events are then interpreted has been alternatively positive and
+// negative (e.g. another divide-by-two, sync-wise).
+// * External clocking: the external clock is supposed to be at bitrate, both edges are used.
+//
+// Synchronization:
+// Async mode:
+// Both modes use a 4-bits counter incremented on every event (16/bit).
+//
+// * Transmit sets the counter to 0 at transmit start. Output data line changes value
+// on counter == 0. If the clock output is required, clk=1 outside of transmit,
+// clk=0 on counter==0, clk=1 on counter==8.
+//
+// * Receive sets the counter to 0 when the data line initially goes down (start bit)
+// Output line is read on counter==8. It is unknown whether the counter is reset
+// on every data line level change.
+//
+// Sync mode:
+// * Transmit changes the data line on negative edges, the clock line, following positive and
+// negative edge definition, is output as long as transmit is active and is otherwise 1.
+//
+// * Receive reads the data line on positive edges.
+//
+// Framing:
+// Async mode: 1 bit of start at 0, 7 or 8 bits of data, nothing or 1 bit of parity or 1 bit of multiprocessing, 1 or 2 bits of stop at 1.
+// Sync mode: 8 bits of data.
+//
+// Multiprocessing bit is an extra bit which value can be set on transmit in bit zero of ssr.
+// On receive when zero the byte is dropped.
+
+
+const char *const sh_sci_device::state_names[] = { "idle", "start", "bit", "parity", "stop", "last-tick" };
+
+sh_sci_device::sh_sci_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
+ device_t(mconfig, SH_SCI, tag, owner, clock),
+ m_cpu(*this, finder_base::DUMMY_TAG),
+ m_intc(*this, finder_base::DUMMY_TAG),
+ m_external_to_internal_ratio(0), m_internal_to_external_ratio(0), m_id(0), m_eri_int(0), m_rxi_int(0), m_txi_int(0), m_tei_int(0),
+ m_tx_state(0), m_rx_state(0), m_tx_bit(0), m_rx_bit(0), m_clock_state(0), m_tx_parity(0), m_rx_parity(0), m_tx_clock_counter(0), m_rx_clock_counter(0),
+ m_clock_mode(INTERNAL_ASYNC), m_ext_clock_value(false), m_rx_value(true),
+ m_rdr(0), m_tdr(0), m_smr(0), m_scr(0), m_ssr(0), m_brr(0), m_rsr(0), m_tsr(0), m_clock_event(0), m_divider(0)
+{
+ m_external_clock_period = attotime::never;
+}
+
+void sh_sci_device::do_set_external_clock_period(const attotime &period)
+{
+ m_external_clock_period = period;
+}
+
+void sh_sci_device::smr_w(u8 data)
+{
+ m_smr = data;
+
+ LOGMASKED(LOG_REGS, "smr_w %02x %s %c%c%c%s /%d (%06x)\n", data,
+ data & SMR_CA ? "sync" : "async",
+ data & SMR_CHR ? '7' : '8',
+ data & SMR_PE ? data & SMR_OE ? 'o' : 'e' : 'n',
+ data & SMR_STOP ? '2' : '1',
+ data & SMR_MP ? " mp" : "",
+ 1 << 2*(data & SMR_CKS),
+ m_cpu->pc());
+
+ clock_update();
+}
+
+u8 sh_sci_device::smr_r()
+{
+ LOGMASKED(LOG_RREGS, "smr_r %02x (%06x)\n", m_smr, m_cpu->pc());
+ return m_smr;
+}
+
+void sh_sci_device::brr_w(u8 data)
+{
+ m_brr = data;
+ LOGMASKED(LOG_REGS, "brr_w %02x (%06x)\n", m_brr, m_cpu->pc());
+ clock_update();
+}
+
+u8 sh_sci_device::brr_r()
+{
+ LOGMASKED(LOG_RREGS, "brr_r %02x (%06x)\n", m_brr, m_cpu->pc());
+ return m_brr;
+}
+
+bool sh_sci_device::is_sync_start() const
+{
+ return (m_smr & SMR_CA) && ((m_scr & (SCR_TE|SCR_RE)) == (SCR_TE|SCR_RE));
+}
+
+bool sh_sci_device::has_recv_error() const
+{
+ return m_ssr & (SSR_ORER|SSR_PER|SSR_FER);
+}
+
+void sh_sci_device::scr_w(u8 data)
+{
+ LOGMASKED(LOG_REGS, "scr_w %02x%s%s%s%s%s%s clk=%d (%06x)\n", data,
+ data & SCR_TIE ? " txi" : "",
+ data & SCR_RIE ? " rxi" : "",
+ data & SCR_TE ? " tx" : "",
+ data & SCR_RE ? " rx" : "",
+ data & SCR_MPIE ? " mpi" : "",
+ data & SCR_TEIE ? " tei" : "",
+ data & SCR_CKE,
+ m_cpu->pc());
+
+ u8 delta = m_scr ^ data;
+ m_scr = data;
+ clock_update();
+
+ if((delta & SCR_RE) && !(m_scr & SCR_RE)) {
+ m_rx_state = ST_IDLE;
+ clock_stop(CLK_RX);
+ }
+
+ if((delta & SCR_RE) && (m_scr & SCR_RE) && m_rx_state == ST_IDLE && !has_recv_error() && !is_sync_start())
+ rx_start();
+ if((delta & SCR_TIE) && (m_scr & SCR_TIE) && (m_ssr & SSR_TDRE))
+ m_intc->internal_interrupt(m_txi_int);
+ if((delta & SCR_TEIE) && (m_scr & SCR_TEIE) && (m_ssr & SSR_TEND))
+ m_intc->internal_interrupt(m_tei_int);
+ if((delta & SCR_RIE) && (m_scr & SCR_RIE) && (m_ssr & SSR_RDRF))
+ m_intc->internal_interrupt(m_rxi_int);
+ if((delta & SCR_RIE) && (m_scr & SCR_RIE) && has_recv_error())
+ m_intc->internal_interrupt(m_eri_int);
+}
+
+u8 sh_sci_device::scr_r()
+{
+ LOGMASKED(LOG_RREGS, "scr_r %02x (%06x)\n", m_scr, m_cpu->pc());
+ return m_scr;
+}
+
+void sh_sci_device::tdr_w(u8 data)
+{
+ LOGMASKED(LOG_REGS, "tdr_w %02x (%06x)\n", data, m_cpu->pc());
+ m_tdr = data;
+#if 0
+ if(m_cpu->access_is_dma()) {
+ m_ssr &= ~SSR_TDRE;
+ if(m_tx_state == ST_IDLE)
+ tx_start();
+ }
+#endif
+}
+
+u8 sh_sci_device::tdr_r()
+{
+ LOGMASKED(LOG_RREGS, "tdr_r %02x (%06x)\n", m_tdr, m_cpu->pc());
+ return m_tdr;
+}
+
+void sh_sci_device::ssr_w(u8 data)
+{
+ if(!(m_scr & SCR_TE)) {
+ data |= SSR_TDRE;
+ m_ssr |= SSR_TDRE;
+ }
+ if((m_ssr & SSR_TDRE) && !(data & SSR_TDRE))
+ m_ssr &= ~SSR_TEND;
+ m_ssr = ((m_ssr & ~SSR_MPBT) | (data & SSR_MPBT)) & (data | (SSR_TEND|SSR_MPB|SSR_MPBT));
+ LOGMASKED(LOG_REGS, "ssr_w %02x -> %02x (%06x)\n", data, m_ssr, m_cpu->pc());
+
+ if(m_tx_state == ST_IDLE && !(m_ssr & SSR_TDRE))
+ tx_start();
+
+ if((m_scr & SCR_RE) && m_rx_state == ST_IDLE && !has_recv_error() && !is_sync_start())
+ rx_start();
+}
+
+u8 sh_sci_device::ssr_r()
+{
+ LOGMASKED(LOG_RREGS, "ssr_r %02x (%06x)\n", m_ssr, m_cpu->pc());
+ return m_ssr;
+}
+
+u8 sh_sci_device::rdr_r()
+{
+ LOGMASKED(LOG_RREGS, "rdr_r %02x (%06x)\n", m_rdr, m_cpu->pc());
+
+#if 0
+ if(!machine().side_effects_disabled() && m_cpu->access_is_dma())
+ m_ssr &= ~SSR_RDRF;
+#endif
+ return m_rdr;
+}
+
+void sh_sci_device::scmr_w(u8 data)
+{
+ LOGMASKED(LOG_REGS, "scmr_w %02x (%06x)\n", data, m_cpu->pc());
+}
+
+u8 sh_sci_device::scmr_r()
+{
+ LOGMASKED(LOG_RREGS, "scmr_r (%06x)\n", m_cpu->pc());
+ return 0x00;
+}
+
+void sh_sci_device::clock_update()
+{
+ m_divider = 2 << (2*(m_smr & SMR_CKS));
+ m_divider *= m_brr+1;
+
+ if(m_smr & SMR_CA) {
+ if(m_scr & SCR_CKE1)
+ m_clock_mode = EXTERNAL_SYNC;
+ else
+ m_clock_mode = INTERNAL_SYNC_OUT;
+ } else {
+ if(m_scr & SCR_CKE1)
+ m_clock_mode = EXTERNAL_ASYNC;
+ else if(m_scr & SCR_CKE0)
+ m_clock_mode = INTERNAL_ASYNC_OUT;
+ else
+ m_clock_mode = INTERNAL_ASYNC;
+ }
+
+ if(m_clock_mode == EXTERNAL_ASYNC && !m_external_clock_period.is_never())
+ m_clock_mode = EXTERNAL_RATE_ASYNC;
+ if(m_clock_mode == EXTERNAL_SYNC && !m_external_clock_period.is_never())
+ m_clock_mode = EXTERNAL_RATE_SYNC;
+
+ if(VERBOSE & LOG_RATE) {
+ std::string new_message;
+ switch(m_clock_mode) {
+ case INTERNAL_ASYNC:
+ new_message = util::string_format("clock internal at %d Hz, async, bitrate %d bps\n", int(m_cpu->clock() / m_divider), int(m_cpu->clock() / (m_divider*16)));
+ break;
+ case INTERNAL_ASYNC_OUT:
+ new_message = util::string_format("clock internal at %d Hz, async, bitrate %d bps, output\n", int(m_cpu->clock() / m_divider), int(m_cpu->clock() / (m_divider*16)));
+ break;
+ case EXTERNAL_ASYNC:
+ new_message = "clock external, async\n";
+ break;
+ case EXTERNAL_RATE_ASYNC:
+ new_message = util::string_format("clock external at %d Hz, async, bitrate %d bps\n", int(m_cpu->clock()*m_internal_to_external_ratio), int(m_cpu->clock()*m_internal_to_external_ratio/16));
+ break;
+ case INTERNAL_SYNC_OUT:
+ new_message = util::string_format("clock internal at %d Hz, sync, output\n", int(m_cpu->clock() / (m_divider*2)));
+ break;
+ case EXTERNAL_SYNC:
+ new_message = "clock external, sync\n";
+ break;
+ case EXTERNAL_RATE_SYNC:
+ new_message = util::string_format("clock external at %d Hz, sync\n", int(m_cpu->clock()*m_internal_to_external_ratio));
+ break;
+ }
+ if(new_message != m_last_clock_message) {
+ (LOG_OUTPUT_FUNC)(new_message);
+ m_last_clock_message = std::move(new_message);
+ }
+ }
+}
+
+void sh_sci_device::device_start()
+{
+ if(m_external_clock_period.is_never()) {
+ m_internal_to_external_ratio = 0;
+ m_external_to_internal_ratio = 0;
+ } else {
+ m_external_to_internal_ratio = (m_external_clock_period*m_cpu->clock()).as_double();
+ m_internal_to_external_ratio = 1/m_external_to_internal_ratio;
+ }
+
+ save_item(NAME(m_tx_state));
+ save_item(NAME(m_rx_state));
+ save_item(NAME(m_tx_bit));
+ save_item(NAME(m_rx_bit));
+ save_item(NAME(m_clock_state));
+ save_item(NAME(m_tx_parity));
+ save_item(NAME(m_rx_parity));
+ save_item(NAME(m_tx_clock_counter));
+ save_item(NAME(m_rx_clock_counter));
+ save_item(NAME(m_clock_mode));
+ save_item(NAME(m_ext_clock_value));
+ save_item(NAME(m_rx_value));
+
+ save_item(NAME(m_rdr));
+ save_item(NAME(m_tdr));
+ save_item(NAME(m_smr));
+ save_item(NAME(m_scr));
+ save_item(NAME(m_ssr));
+ save_item(NAME(m_brr));
+ save_item(NAME(m_rsr));
+ save_item(NAME(m_tsr));
+ save_item(NAME(m_clock_event));
+ save_item(NAME(m_clock_step));
+ save_item(NAME(m_divider));
+}
+
+void sh_sci_device::device_reset()
+{
+ m_rdr = 0x00;
+ m_tdr = 0xff;
+ m_smr = 0x00;
+ m_scr = 0x00;
+ m_ssr = 0x84;
+ m_brr = 0xff;
+ m_rsr = 0x00;
+ m_tsr = 0xff;
+ m_rx_bit = 0;
+ m_tx_bit = 0;
+ m_tx_state = ST_IDLE;
+ m_rx_state = ST_IDLE;
+ m_clock_state = 0;
+ m_clock_mode = INTERNAL_ASYNC;
+ m_clock_event = 0;
+ clock_update();
+ m_ext_clock_value = true;
+ m_tx_clock_counter = 0;
+ m_rx_clock_counter = 0;
+ m_cpu->do_sci_clk(m_id, 1);
+ m_cpu->do_sci_tx(m_id, 1);
+}
+
+TIMER_CALLBACK_MEMBER(sh_sci_device::sync_tick)
+{
+ // Used only to force system-wide syncs
+}
+
+void sh_sci_device::do_rx_w(int state)
+{
+#if 0
+ if(m_cpu->standby()) {
+ m_rx_value = state;
+ return;
+ }
+#endif
+
+ if(state != m_rx_value && (m_clock_state & CLK_RX))
+ if(m_rx_clock_counter == 1 || m_rx_clock_counter == 15)
+ m_rx_clock_counter = 0;
+
+ m_rx_value = state;
+ if(!m_rx_value && !(m_clock_state & CLK_RX) && m_rx_state != ST_IDLE)
+ clock_start(CLK_RX);
+}
+
+void sh_sci_device::do_clk_w(int state)
+{
+ if(m_ext_clock_value == state)
+ return;
+
+ m_ext_clock_value = state;
+ if(!m_clock_state /* || m_cpu->standby() */)
+ return;
+
+ if(m_clock_mode == EXTERNAL_ASYNC) {
+ if(m_clock_state & CLK_TX)
+ tx_async_tick();
+ if(m_clock_state & CLK_RX)
+ rx_async_tick();
+ } else if(m_clock_mode == EXTERNAL_SYNC) {
+ if(m_clock_state & CLK_TX)
+ tx_sync_tick();
+ if(m_clock_state & CLK_RX)
+ rx_sync_tick();
+ }
+}
+
+u64 sh_sci_device::internal_update(u64 current_time)
+{
+ if(!m_clock_event || current_time < m_clock_event)
+ return m_clock_event;
+
+ if(m_clock_mode == INTERNAL_ASYNC || m_clock_mode == INTERNAL_ASYNC_OUT || m_clock_mode == EXTERNAL_RATE_ASYNC) {
+ if(m_clock_state & CLK_TX)
+ tx_async_tick();
+ if(m_clock_state & CLK_RX)
+ rx_async_tick();
+ } else if(m_clock_mode == INTERNAL_SYNC_OUT || m_clock_mode == EXTERNAL_RATE_SYNC) {
+ if(m_clock_state & CLK_TX)
+ tx_sync_tick();
+ if(m_clock_state & CLK_RX)
+ rx_sync_tick();
+ }
+
+ if(m_clock_state) {
+ if(m_clock_step)
+ m_clock_event += m_clock_step;
+ else if(m_clock_mode == EXTERNAL_RATE_ASYNC || m_clock_mode == EXTERNAL_RATE_SYNC)
+ m_clock_event = u64(u64(m_clock_event * m_internal_to_external_ratio + 1) * m_external_to_internal_ratio + 1);
+ else
+ m_clock_event = 0;
+
+ if(m_clock_event)
+ m_cpu->internal_update();
+
+ } else if(!m_clock_state) {
+ m_clock_event = 0;
+ if(m_clock_mode == INTERNAL_ASYNC_OUT || m_clock_mode == INTERNAL_SYNC_OUT)
+ m_cpu->do_sci_clk(m_id, 1);
+ }
+
+ return m_clock_event;
+}
+
+void sh_sci_device::clock_start(int mode)
+{
+ // Happens when back-to-back
+ if(m_clock_state & mode)
+ return;
+
+ if(mode == CLK_TX)
+ m_tx_clock_counter = 15;
+ else
+ m_rx_clock_counter = 15;
+
+ m_clock_state |= mode;
+ if(m_clock_state != mode)
+ return;
+
+ m_clock_step = 0;
+
+ switch(m_clock_mode) {
+ case INTERNAL_ASYNC:
+ case INTERNAL_ASYNC_OUT:
+ case INTERNAL_SYNC_OUT: {
+ LOGMASKED(LOG_CLOCK, "Starting internal clock\n");
+ m_clock_step = m_divider;
+ u64 now = m_cpu->current_cycles();
+ m_clock_event = (now / m_clock_step + 1) * m_clock_step;
+ m_cpu->internal_update();
+ break;
+ }
+
+ case EXTERNAL_RATE_ASYNC:
+ case EXTERNAL_RATE_SYNC: {
+ LOGMASKED(LOG_CLOCK, "Simulating external clock\n", m_clock_mode == EXTERNAL_RATE_ASYNC ? "async" : "sync");
+ u64 now = m_cpu->current_cycles();
+ m_clock_event = u64(u64(now * m_internal_to_external_ratio + 1) * m_external_to_internal_ratio + 1);
+ m_cpu->internal_update();
+ break;
+ }
+
+ case EXTERNAL_ASYNC:
+ case EXTERNAL_SYNC:
+ LOGMASKED(LOG_CLOCK, "Waiting for external clock\n");
+ break;
+ }
+}
+
+void sh_sci_device::clock_stop(int mode)
+{
+ m_clock_state &= ~mode;
+ if(!m_clock_state) {
+ m_clock_event = 0;
+ m_clock_step = 0;
+ LOGMASKED(LOG_CLOCK, "Stopping clocks\n");
+ }
+ m_cpu->internal_update();
+}
+
+void sh_sci_device::tx_start()
+{
+ m_ssr |= SSR_TDRE;
+ m_tsr = m_tdr;
+ m_tx_parity = m_smr & SMR_OE ? 0 : 1;
+ LOGMASKED(LOG_DATA, "start transmit %02x '%c'\n", m_tsr, m_tsr >= 32 && m_tsr < 127 ? m_tsr : '.');
+ if(m_scr & SCR_TIE)
+ m_intc->internal_interrupt(m_txi_int);
+ if(m_smr & SMR_CA) {
+ m_tx_state = ST_BIT;
+ m_tx_bit = 8;
+ } else {
+ m_tx_state = ST_START;
+ m_tx_bit = 1;
+ }
+ clock_start(CLK_TX);
+ if(m_rx_state == ST_IDLE && !has_recv_error() && is_sync_start())
+ rx_start();
+}
+
+void sh_sci_device::tx_async_tick()
+{
+ m_tx_clock_counter = (m_tx_clock_counter + 1) & 15;
+ LOGMASKED(LOG_TICK, "tx_async_tick %x\n", m_tx_clock_counter);
+ if(m_tx_clock_counter == 0) {
+ tx_async_step();
+
+ if(m_clock_mode == INTERNAL_ASYNC_OUT)
+ m_cpu->do_sci_clk(m_id, 0);
+
+ } else if(m_tx_clock_counter == 8 && m_clock_mode == INTERNAL_ASYNC_OUT)
+ m_cpu->do_sci_clk(m_id, 1);
+}
+
+void sh_sci_device::tx_async_step()
+{
+ LOGMASKED(LOG_STATE, "tx_async_step state=%s bit=%d\n", state_names[m_tx_state], m_tx_bit);
+ switch(m_tx_state) {
+ case ST_START:
+ m_cpu->do_sci_tx(m_id, false);
+ assert(m_tx_bit == 1);
+ m_tx_state = ST_BIT;
+ m_tx_bit = m_smr & SMR_CHR ? 7 : 8;
+ break;
+
+ case ST_BIT:
+ m_tx_parity ^= (m_tsr & 1);
+ m_cpu->do_sci_tx(m_id, m_tsr & 1);
+ m_tsr >>= 1;
+ m_tx_bit--;
+ if(!m_tx_bit) {
+ if(m_smr & SMR_CA) {
+ if(!(m_ssr & SSR_TDRE))
+ tx_start();
+ else {
+ m_tx_state = ST_LAST_TICK;
+ m_tx_bit = 0;
+ }
+ } else if(m_smr & SMR_PE) {
+ m_tx_state = ST_PARITY;
+ m_tx_bit = 1;
+ } else {
+ m_tx_state = ST_STOP;
+ m_tx_bit = m_smr & SMR_STOP ? 2 : 1;
+ }
+ }
+ break;
+
+ case ST_PARITY:
+ m_cpu->do_sci_tx(m_id, m_tx_parity);
+ assert(m_tx_bit == 1);
+ m_tx_state = ST_STOP;
+ m_tx_bit = m_smr & SMR_STOP ? 2 : 1;
+ break;
+
+ case ST_STOP:
+ m_cpu->do_sci_tx(m_id, true);
+ m_tx_bit--;
+ if(!m_tx_bit) {
+ if(!(m_ssr & SSR_TDRE))
+ tx_start();
+ else {
+ m_tx_state = ST_LAST_TICK;
+ m_tx_bit = 0;
+ }
+ }
+ break;
+
+ case ST_LAST_TICK:
+ m_tx_state = ST_IDLE;
+ m_tx_bit = 0;
+ clock_stop(CLK_TX);
+ m_cpu->do_sci_tx(m_id, 1);
+ m_ssr |= SSR_TEND;
+ if(m_scr & SCR_TEIE)
+ m_intc->internal_interrupt(m_tei_int);
+
+ // if there's more to send, start the transmitter
+ if((m_scr & SCR_TE) && !(m_ssr & SSR_TDRE))
+ tx_start();
+ break;
+
+ default:
+ abort();
+ }
+ LOGMASKED(LOG_STATE, " -> state=%s bit=%d\n", state_names[m_tx_state], m_tx_bit);
+}
+
+void sh_sci_device::tx_sync_tick()
+{
+ m_tx_clock_counter = (m_tx_clock_counter + 1) & 1;
+ LOGMASKED(LOG_TICK, "tx_sync_tick %x\n", m_tx_clock_counter);
+ if(m_tx_clock_counter == 0) {
+ tx_sync_step();
+
+ if(m_clock_mode == INTERNAL_SYNC_OUT && m_tx_state != ST_IDLE)
+ m_cpu->do_sci_clk(m_id, 0);
+
+ } else if(m_tx_clock_counter == 1 && m_clock_mode == INTERNAL_SYNC_OUT)
+ m_cpu->do_sci_clk(m_id, 1);
+}
+
+void sh_sci_device::tx_sync_step()
+{
+ LOGMASKED(LOG_STATE, "tx_sync_step bit=%d\n", m_tx_bit);
+ if(!m_tx_bit) {
+ m_tx_state = ST_IDLE;
+ clock_stop(CLK_TX);
+ m_cpu->do_sci_tx(m_id, 1);
+ m_ssr |= SSR_TEND;
+ if(m_scr & SCR_TEIE)
+ m_intc->internal_interrupt(m_tei_int);
+
+ // if there's more to send, start the transmitter
+ if((m_scr & SCR_TE) && !(m_ssr & SSR_TDRE))
+ tx_start();
+ } else {
+ m_cpu->do_sci_tx(m_id, m_tsr & 1);
+ m_tsr >>= 1;
+ m_tx_bit--;
+ }
+}
+
+void sh_sci_device::rx_start()
+{
+ m_rx_parity = m_smr & SMR_OE ? 0 : 1;
+ m_rsr = 0x00;
+ LOGMASKED(LOG_STATE, "start receive\n");
+ if(m_smr & SMR_CA) {
+ m_rx_state = ST_BIT;
+ m_rx_bit = 8;
+ clock_start(CLK_RX);
+ } else {
+ m_rx_state = ST_START;
+ m_rx_bit = 1;
+ if(!m_rx_value)
+ clock_start(CLK_RX);
+ }
+}
+
+void sh_sci_device::rx_done()
+{
+ if(!(m_ssr & SSR_FER)) {
+ if((m_smr & SMR_PE) && m_rx_parity) {
+ m_ssr |= SSR_PER;
+ LOGMASKED(LOG_DATA, "Receive parity error\n");
+ } else if(m_ssr & SSR_RDRF) {
+ m_ssr |= SSR_ORER;
+ LOGMASKED(LOG_DATA, "Receive overrun\n");
+ } else {
+ m_ssr |= SSR_RDRF;
+ LOGMASKED(LOG_DATA, "Received %02x '%c'\n", m_rsr, m_rsr >= 32 && m_rsr < 127 ? m_rsr : '.');
+ m_rdr = m_rsr;
+ }
+ }
+ if(m_scr & SCR_RIE) {
+ if(has_recv_error())
+ m_intc->internal_interrupt(m_eri_int);
+ else
+ m_intc->internal_interrupt(m_rxi_int);
+ }
+ if((m_scr & SCR_RE) && !has_recv_error() && !is_sync_start())
+ rx_start();
+ else {
+ clock_stop(CLK_RX);
+ m_rx_state = ST_IDLE;
+ }
+}
+
+void sh_sci_device::rx_async_tick()
+{
+ m_rx_clock_counter = (m_rx_clock_counter + 1) & 15;
+ LOGMASKED(LOG_TICK, "rx_async_tick %x\n", m_rx_clock_counter);
+ if(m_rx_clock_counter == 8)
+ rx_async_step();
+}
+
+void sh_sci_device::rx_async_step()
+{
+ LOGMASKED(LOG_STATE, "rx_async_step state=%s bit=%d\n", state_names[m_rx_state], m_rx_bit);
+ switch(m_rx_state) {
+ case ST_START:
+ if(m_rx_value) {
+ clock_stop(CLK_RX);
+ break;
+ }
+ m_rx_state = ST_BIT;
+ m_rx_bit = m_smr & SMR_CHR ? 7 : 8;
+ break;
+
+ case ST_BIT:
+ m_rx_parity ^= m_rx_value;
+ m_rsr >>= 1;
+ if(m_rx_value) {
+ m_rx_parity = !m_rx_parity;
+ m_rsr |= (m_smr & (SMR_CA|SMR_CHR)) == SMR_CHR ? 0x40 : 0x80;
+ }
+ m_rx_bit--;
+ if(!m_rx_bit) {
+ if(m_smr & SMR_CA)
+ rx_done();
+ else if(m_smr & SMR_PE) {
+ m_rx_state = ST_PARITY;
+ m_rx_bit = 1;
+ } else {
+ m_rx_state = ST_STOP;
+ m_rx_bit = 1; // Always 1 on rx
+ }
+ }
+ break;
+
+ case ST_PARITY:
+ m_rx_parity ^= m_rx_value;
+ assert(m_rx_bit == 1);
+ m_rx_state = ST_STOP;
+ m_rx_bit = 1;
+ break;
+
+ case ST_STOP:
+ assert(m_rx_bit == 1);
+ if(!m_rx_value)
+ m_ssr |= SSR_FER;
+ else if((m_smr & SMR_PE) && m_rx_parity)
+ m_ssr |= SSR_PER;
+ rx_done();
+ break;
+
+ default:
+ abort();
+ }
+ LOGMASKED(LOG_STATE, " -> state=%s, bit=%d\n", state_names[m_rx_state], m_rx_bit);
+}
+
+void sh_sci_device::rx_sync_tick()
+{
+ m_rx_clock_counter = (m_rx_clock_counter + 1) & 1;
+ LOGMASKED(LOG_TICK, "rx_sync_tick %x\n", m_rx_clock_counter);
+
+ if(m_rx_clock_counter == 0 && m_clock_mode == INTERNAL_SYNC_OUT)
+ m_cpu->do_sci_clk(m_id, 0);
+
+ else if(m_rx_clock_counter == 1) {
+ if(m_clock_mode == INTERNAL_SYNC_OUT)
+ m_cpu->do_sci_clk(m_id, 1);
+
+ rx_sync_step();
+ }
+}
+
+void sh_sci_device::rx_sync_step()
+{
+ LOGMASKED(LOG_STATE, "rx_sync_step bit=%d\n", m_rx_value);
+ m_rsr >>= 1;
+ if(m_rx_value)
+ m_rsr |= 0x80;
+ m_rx_bit--;
+
+ if(!m_rx_bit)
+ rx_done();
+}
diff --git a/src/devices/cpu/sh/sh_sci.h b/src/devices/cpu/sh/sh_sci.h
new file mode 100644
index 00000000000..bb1890c3c8b
--- /dev/null
+++ b/src/devices/cpu/sh/sh_sci.h
@@ -0,0 +1,151 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert
+/***************************************************************************
+
+ sh_sci.h
+
+ SH Serial Communications Interface
+
+
+***************************************************************************/
+
+#ifndef MAME_CPU_SH_SH_SCI_H
+#define MAME_CPU_SH_SH_SCI_H
+
+#pragma once
+
+class sh7042_device;
+class sh_intc_device;
+
+class sh_sci_device : public device_t {
+public:
+ sh_sci_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+ template<typename T, typename U> sh_sci_device(const machine_config &mconfig, const char *tag, device_t *owner, int id, T &&cpu, U &&intc, int eri, int rxi, int txi, int tei)
+ : sh_sci_device(mconfig, tag, owner, 0)
+ {
+ m_cpu.set_tag(std::forward<T>(cpu));
+ m_intc.set_tag(std::forward<U>(intc));
+ m_id = id;
+ m_eri_int = eri;
+ m_rxi_int = rxi;
+ m_txi_int = txi;
+ m_tei_int = tei;
+ }
+
+ void do_set_external_clock_period(const attotime &_period);
+
+ void smr_w(u8 data);
+ u8 smr_r();
+ void brr_w(u8 data);
+ u8 brr_r();
+ void scr_w(u8 data);
+ u8 scr_r();
+ void tdr_w(u8 data);
+ u8 tdr_r();
+ void ssr_w(u8 data);
+ u8 ssr_r();
+ u8 rdr_r();
+ void scmr_w(u8 data);
+ u8 scmr_r();
+
+ void do_rx_w(int state);
+ void do_clk_w(int state);
+
+ u64 internal_update(u64 current_time);
+
+protected:
+ enum {
+ ST_IDLE, ST_START, ST_BIT, ST_PARITY, ST_STOP, ST_LAST_TICK
+ };
+
+ static const char *const state_names[];
+
+ enum {
+ CLK_TX = 1,
+ CLK_RX = 2
+ };
+
+ enum {
+ INTERNAL_ASYNC,
+ INTERNAL_ASYNC_OUT,
+ EXTERNAL_ASYNC,
+ EXTERNAL_RATE_ASYNC,
+ INTERNAL_SYNC_OUT,
+ EXTERNAL_SYNC,
+ EXTERNAL_RATE_SYNC
+ };
+
+ enum {
+ SMR_CA = 0x80,
+ SMR_CHR = 0x40,
+ SMR_PE = 0x20,
+ SMR_OE = 0x10,
+ SMR_STOP = 0x08,
+ SMR_MP = 0x04,
+ SMR_CKS = 0x03,
+
+ SCR_TIE = 0x80,
+ SCR_RIE = 0x40,
+ SCR_TE = 0x20,
+ SCR_RE = 0x10,
+ SCR_MPIE = 0x08,
+ SCR_TEIE = 0x04,
+ SCR_CKE = 0x03,
+ SCR_CKE1 = 0x02,
+ SCR_CKE0 = 0x01,
+
+ SSR_TDRE = 0x80,
+ SSR_RDRF = 0x40,
+ SSR_ORER = 0x20,
+ SSR_FER = 0x10,
+ SSR_PER = 0x08,
+ SSR_TEND = 0x04,
+ SSR_MPB = 0x02,
+ SSR_MPBT = 0x01
+ };
+
+ required_device<sh7042_device> m_cpu;
+ required_device<sh_intc_device> m_intc;
+ attotime m_external_clock_period;
+ double m_external_to_internal_ratio, m_internal_to_external_ratio;
+
+ int m_id, m_eri_int, m_rxi_int, m_txi_int, m_tei_int;
+
+ int m_tx_state, m_rx_state, m_tx_bit, m_rx_bit, m_clock_state, m_tx_parity, m_rx_parity, m_tx_clock_counter, m_rx_clock_counter;
+ u32 m_clock_mode;
+ bool m_ext_clock_value, m_rx_value;
+
+ u8 m_rdr, m_tdr, m_smr, m_scr, m_ssr, m_brr, m_rsr, m_tsr;
+ u64 m_clock_event, m_clock_step, m_divider;
+
+ std::string m_last_clock_message;
+
+ void device_start() override;
+ void device_reset() override;
+
+ TIMER_CALLBACK_MEMBER(sync_tick);
+
+ void clock_start(int mode);
+ void clock_stop(int mode);
+ void clock_update();
+
+ void tx_start();
+ void tx_async_tick();
+ void tx_async_step();
+ void tx_sync_tick();
+ void tx_sync_step();
+
+ void rx_start();
+ void rx_done();
+ void rx_async_tick();
+ void rx_async_step();
+ void rx_sync_tick();
+ void rx_sync_step();
+
+ bool is_sync_start() const;
+ bool has_recv_error() const;
+};
+
+DECLARE_DEVICE_TYPE(SH_SCI, sh_sci_device)
+
+#endif // MAME_CPU_SH_SH_SCI_H