diff options
| author | 2024-05-02 19:48:15 +0200 | |
|---|---|---|
| committer | 2024-05-02 19:50:14 +0200 | |
| commit | 055b4c669cd31a43b680e2031efdcad7b93fc475 (patch) | |
| tree | 78e36e94727fe1359a030d9d5075978f14786e10 /src/devices/cpu | |
| parent | 3b5e60b420b8c59d4373828dd4a2cf548523d810 (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')
| -rw-r--r-- | src/devices/cpu/h8/h8_adc.cpp | 2 | ||||
| -rw-r--r-- | src/devices/cpu/sh/sh7042.cpp | 220 | ||||
| -rw-r--r-- | src/devices/cpu/sh/sh7042.h | 53 | ||||
| -rw-r--r-- | src/devices/cpu/sh/sh_adc.cpp | 89 | ||||
| -rw-r--r-- | src/devices/cpu/sh/sh_adc.h | 48 | ||||
| -rw-r--r-- | src/devices/cpu/sh/sh_bsc.cpp | 139 | ||||
| -rw-r--r-- | src/devices/cpu/sh/sh_bsc.h | 47 | ||||
| -rw-r--r-- | src/devices/cpu/sh/sh_cmt.cpp | 31 | ||||
| -rw-r--r-- | src/devices/cpu/sh/sh_dmac.cpp | 115 | ||||
| -rw-r--r-- | src/devices/cpu/sh/sh_dmac.h | 59 | ||||
| -rw-r--r-- | src/devices/cpu/sh/sh_intc.cpp | 57 | ||||
| -rw-r--r-- | src/devices/cpu/sh/sh_intc.h | 7 | ||||
| -rw-r--r-- | src/devices/cpu/sh/sh_mtu.cpp | 527 | ||||
| -rw-r--r-- | src/devices/cpu/sh/sh_mtu.h | 182 | ||||
| -rw-r--r-- | src/devices/cpu/sh/sh_sci.cpp | 765 | ||||
| -rw-r--r-- | src/devices/cpu/sh/sh_sci.h | 151 |
16 files changed, 2400 insertions, 92 deletions
diff --git a/src/devices/cpu/h8/h8_adc.cpp b/src/devices/cpu/h8/h8_adc.cpp index 3ca7a0f19dc..eb4e852d63c 100644 --- a/src/devices/cpu/h8/h8_adc.cpp +++ b/src/devices/cpu/h8/h8_adc.cpp @@ -456,7 +456,7 @@ void h8_adc_2655_device::mode_update() m_mode = ACTIVE | (m_adcr & 0x08 ? REPEAT : 0); - if(m_adcsr & 0x03) { + if(m_adcr & 0x03) { m_mode |= BUFFER; } 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 |
