diff --git a/scripts/src/cpu.lua b/scripts/src/cpu.lua index f2fd8127e77..4bacfe9d524 100644 --- a/scripts/src/cpu.lua +++ b/scripts/src/cpu.lua @@ -903,12 +903,20 @@ if CPUS["SH"] then MAME_DIR .. "src/devices/cpu/sh/sh7042.h", MAME_DIR .. "src/devices/cpu/sh/sh_adc.cpp", MAME_DIR .. "src/devices/cpu/sh/sh_adc.h", + MAME_DIR .. "src/devices/cpu/sh/sh_bsc.cpp", + MAME_DIR .. "src/devices/cpu/sh/sh_bsc.h", MAME_DIR .. "src/devices/cpu/sh/sh_cmt.cpp", MAME_DIR .. "src/devices/cpu/sh/sh_cmt.h", + MAME_DIR .. "src/devices/cpu/sh/sh_dmac.cpp", + MAME_DIR .. "src/devices/cpu/sh/sh_dmac.h", MAME_DIR .. "src/devices/cpu/sh/sh_intc.cpp", MAME_DIR .. "src/devices/cpu/sh/sh_intc.h", + MAME_DIR .. "src/devices/cpu/sh/sh_mtu.cpp", + MAME_DIR .. "src/devices/cpu/sh/sh_mtu.h", MAME_DIR .. "src/devices/cpu/sh/sh_port.cpp", MAME_DIR .. "src/devices/cpu/sh/sh_port.h", + MAME_DIR .. "src/devices/cpu/sh/sh_sci.cpp", + MAME_DIR .. "src/devices/cpu/sh/sh_sci.h", MAME_DIR .. "src/devices/cpu/sh/sh7604_bus.cpp", MAME_DIR .. "src/devices/cpu/sh/sh7604_bus.h", MAME_DIR .. "src/devices/cpu/sh/sh7604_sci.cpp", diff --git a/scripts/src/machine.lua b/scripts/src/machine.lua index d38de5d4293..147271a2626 100644 --- a/scripts/src/machine.lua +++ b/scripts/src/machine.lua @@ -5365,3 +5365,14 @@ if (MACHINES["CAT702"]~=null) then MAME_DIR .. "src/devices/machine/cat702.h", } end + +--------------------------------------------------- +-- +--@src/devices/machine/sci4.h,MACHINES["SCI4"] = true +--------------------------------------------------- +if (MACHINES["SCI4"]~=null) then + files { + MAME_DIR .. "src/devices/machine/sci4.cpp", + MAME_DIR .. "src/devices/machine/sci4.h", + } +end diff --git a/src/devices/bus/plg1x0/plg150-ap.cpp b/src/devices/bus/plg1x0/plg150-ap.cpp index 7b92cf37666..964ec39108b 100644 --- a/src/devices/bus/plg1x0/plg150-ap.cpp +++ b/src/devices/bus/plg1x0/plg150-ap.cpp @@ -47,6 +47,7 @@ plg150_ap_device::~plg150_ap_device() void plg150_ap_device::midi_rx(int state) { + logerror("%s rx=%d\n", machine().time().to_string(), state); m_cpu->sci_rx_w<1>(state); } 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 auto read_adc() { return m_read_adc[Port].bind(); } template void sci_rx_w(int state) { do_sci_w(Sci, state); } + template void sci_clk_w(int state) { m_sci[Sci]->do_clk_w(state); } template auto write_sci_tx() { return m_sci_tx[Sci].bind(); } + template 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 m_intc; - required_device m_adc; + required_device m_adc0; + optional_device m_adc1; + required_device m_bsc; required_device m_cmt; + required_device m_dmac; + required_device m_dmac0; + required_device m_dmac1; + required_device m_dmac2; + required_device m_dmac3; + required_device m_mtu; + required_device m_mtu0; + required_device m_mtu1; + required_device m_mtu2; + required_device m_mtu3; + required_device m_mtu4; required_device m_porta; required_device m_portb; required_device m_portc; required_device m_portd; required_device m_porte; required_device m_portf; + required_device_array 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 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(cpu)); - m_intc.set_tag(std::forward(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 m_cpu; required_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 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(cpu)); + m_intc.set_tag(std::forward(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 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(cpu)); + m_intc.set_tag(std::forward(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 sh_dma_device(const machine_config &mconfig, const char *tag, device_t *owner, T &&cpu) - : sh_dma_device(mconfig, tag, owner) + template 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 void set_info(T &&cpu) { m_cpu.set_tag(std::forward(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 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; }; -DECLARE_DEVICE_TYPE(SH_DMA, sh_dma_device) +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 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 void set_info(T &&cpu, U &&intc) { m_cpu.set_tag(std::forward(cpu)); m_intc.set_tag(std::forward(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 m_cpu; + required_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_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(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 m_pending; std::array m_ipr; u16 m_isr, m_icr; + u8 m_lines; + required_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 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 void set_info(T &&cpu, U &&intc) { m_cpu.set_tag(std::forward(cpu)); m_intc.set_tag(std::forward(intc)); } + template void set_chain(T &&chain) { m_chained_timer.set_tag(std::forward(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 m_cpu; + required_device m_intc; + optional_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 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 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 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 void set_info(T &&cpu) { m_cpu.set_tag(std::forward(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 m_cpu; + required_device_array 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 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(cpu)); + m_intc.set_tag(std::forward(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 m_cpu; + required_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 diff --git a/src/devices/machine/sci4.cpp b/src/devices/machine/sci4.cpp new file mode 100644 index 00000000000..7ed8196d3e7 --- /dev/null +++ b/src/devices/machine/sci4.cpp @@ -0,0 +1,339 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert + +// Yamaha SCI4 / XV833A00, 7-lines serial chip with 4 multiplexed on one and the other 3 separated + +#include "emu.h" +#include "sci4.h" + +sci4_device::sci4_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + device_t(mconfig, SCI4, tag, owner, clock), + m_tx(*this), + m_irq(*this) +{ +} + + +void sci4_device::map(address_map &map) +{ + map(0x00, 0x3f).rw(FUNC(sci4_device::default_r), FUNC(sci4_device::default_w)); + + map(0x00, 0x00).rw(FUNC(sci4_device::data_r), FUNC(sci4_device::data_w)).select(0x18); + map(0x01, 0x01).rw(FUNC(sci4_device::enable_r), FUNC(sci4_device::enable_w)).select(0x18); + map(0x02, 0x02).r (FUNC(sci4_device::status_r)).select(0x18); + map(0x03, 0x03).rw(FUNC(sci4_device::datamode_r), FUNC(sci4_device::datamode_w)).select(0x18); + map(0x05, 0x05).r (FUNC(sci4_device::reset_r)).select(0x18); + + map(0x20, 0x20).w (FUNC(sci4_device::target_w)); +} + + +void sci4_device::device_start() +{ + save_item(NAME(m_rx)); + save_item(NAME(m_enable)); + save_item(NAME(m_status)); + save_item(NAME(m_datamode)); + save_item(NAME(m_div)); + save_item(NAME(m_cur_rx)); + save_item(NAME(m_tdr)); + save_item(NAME(m_tsr)); + save_item(NAME(m_tdr_full)); + save_item(NAME(m_tx_step)); + save_item(NAME(m_tx_active)); + save_item(NAME(m_rdr)); + save_item(NAME(m_rsr)); + save_item(NAME(m_rdr_full)); + save_item(NAME(m_rx_step)); + save_item(NAME(m_rx_active)); + + save_item(NAME(m_targets)); + + for(u32 i=0; i != 4; i++) { + m_tx_timer[i] = timer_alloc(FUNC(sci4_device::tx_tick), this); + m_rx_timer[i] = timer_alloc(FUNC(sci4_device::rx_tick), this); + } +} + +void sci4_device::device_reset() +{ + std::fill(m_rx.begin(), m_rx.end(), 1); + std::fill(m_enable.begin(), m_enable.end(), 0); + std::fill(m_status.begin(), m_status.end(), 0); + std::fill(m_datamode.begin(), m_datamode.end(), 0); + std::fill(m_div.begin(), m_div.end(), 0); + std::fill(m_cur_rx.begin(), m_cur_rx.end(), 1); + std::fill(m_tdr.begin(), m_tdr.end(), 0); + std::fill(m_tsr.begin(), m_tsr.end(), 0); + std::fill(m_tdr_full.begin(), m_tdr_full.end(), 0); + std::fill(m_tx_step.begin(), m_tx_step.end(), 0); + std::fill(m_tx_active.begin(), m_tx_active.end(), 0); + std::fill(m_rdr.begin(), m_rdr.end(), 0); + std::fill(m_rsr.begin(), m_rsr.end(), 0); + std::fill(m_rdr_full.begin(), m_rdr_full.end(), 0); + std::fill(m_rx_step.begin(), m_rx_step.end(), 0); + std::fill(m_rx_active.begin(), m_rx_active.end(), 0); + + m_targets = 0; +} + +void sci4_device::do_rx_w(int sci, int state) +{ + if(sci >= 30) + sci = sci - 30 + 3; + + m_rx[sci] = state; + if(sci < 3) { + if(state != m_cur_rx[sci]) { + m_cur_rx[sci] = state; + rx_changed(sci); + } + } + u8 rx = ((((m_rx[6] << 3) | (m_rx[5] << 2) | (m_rx[4] << 1) | m_rx[3]) | ~(m_targets >> 4)) & 0xf) == 0xf; + if(rx != m_cur_rx[3]) { + m_cur_rx[3] = rx; + rx_changed(3); + } +} + +void sci4_device::default_w(offs_t offset, u8 data) +{ + logerror("reg_w %02x, %02x (%s)\n", offset, data, machine().describe_context()); +} + +u8 sci4_device::default_r(offs_t offset) +{ + logerror("reg_r %02x (%s)\n", offset, machine().describe_context()); + return 0; +} + +void sci4_device::datamode_w(offs_t slot, u8 data) +{ + m_datamode[slot >> 3] = data; +} + +u8 sci4_device::datamode_r(offs_t slot) +{ + return m_datamode[slot >> 3]; +} + +void sci4_device::data_w(offs_t slot, u8 data) +{ + slot >>= 3; + if(m_datamode[slot] == 0x80) { + m_div[slot] = data; + if(data) + logerror("channel %d baud rate %dHz\n", slot, clock()/16/data); + else + logerror("channel %d off\n"); + } else if(m_datamode[slot] & 2) + fifo_w(slot, data); +} + +u8 sci4_device::data_r(offs_t slot) +{ + slot >>= 3; + if(m_datamode[slot] == 0x80) + return m_div[slot]; + else if(m_datamode[slot] & 1) + return fifo_r(slot); + else + return 0; +} + +void sci4_device::enable_w(offs_t slot, u8 data) +{ + slot >>= 3; + u8 old = m_enable[slot]; + m_enable[slot] = data; + if((data & 2) && !(old & 2)) + tx_enabled(slot); + + else if(!(data & 2) && (old & 2)) { + if(m_status[slot] == 2) { + m_status[slot] = 0; + m_irq[slot](0); + } + } +} + +u8 sci4_device::enable_r(offs_t slot) +{ + return m_enable[slot >> 3]; +} + +u8 sci4_device::status_r(offs_t slot) +{ + return m_status[slot >> 3]; +} + +u8 sci4_device::reset_r(offs_t slot) +{ + slot >>= 3; + m_status[slot] = 0; + m_tx_timer[slot]->adjust(attotime::never); + m_tx_active[slot] = 0; + tx_set(slot, 1); + m_tdr_full[slot] = 0; + m_irq[slot](0); + return 0; +} + + +void sci4_device::target_w(u8 data) +{ + if(data == 0x11 and m_targets == 0x07) + machine().debug_break(); + m_targets = data; + u8 rx = ((((m_rx[6] << 3) | (m_rx[5] << 2) | (m_rx[4] << 1) | m_rx[3]) | ~(m_targets >> 4)) & 0xf) == 0xf; + if(rx != m_cur_rx[3]) { + m_cur_rx[3] = rx; + rx_changed(3); + } + for(u32 i=0; i != 4; i++) + if(!(m_targets & (1<adjust(attotime::never); + } else + // Force a precise resync + wait(1, 0, chan); + } +} + +void sci4_device::tx_enabled(int chan) +{ + if(m_tdr_full[chan]) + tx_start(chan); + else { + m_status[chan] |= 2; + m_irq[chan](1); + } +} + +std::string sci4_device::chan_id(u8 chan, u8 target) +{ + return chan < 3 ? util::string_format("%d", chan) : util::string_format("3:%s%s%s%s", + target & 1 ? "0" : "", + target & 2 ? "1" : "", + target & 4 ? "2" : "", + target & 8 ? "3" : ""); +} + +void sci4_device::tx_start(int chan) +{ + m_tx_active[chan] = 1; + m_tsr[chan] = m_tdr[chan]; + m_tdr_full[chan] = 0; + m_status[chan] |= 2; + m_irq[chan](1); + + logerror("chan %s transmit %02x\n", + chan_id(chan, m_targets), + m_tsr[chan]); + + tx_set(chan, 0); + m_tx_step[chan] = 0; + wait(0, 1, chan); +} + +void sci4_device::wait(int timer, int full, int chan) +{ + u32 div = m_div[chan] ? m_div[chan] : 0x100; + u32 cycles = div*(full ? 16 : 8); + (timer ? m_rx_timer : m_tx_timer)[chan]->adjust(attotime::from_ticks(cycles, clock()), chan); +} + +TIMER_CALLBACK_MEMBER(sci4_device::tx_tick) +{ + u32 step = m_tx_step[param]++; + if(step < 9) { + tx_set(param, step == 8 ? 1 : (m_tsr[param] >> step) & 1); + wait(0, 1, param); + + } else { + if((m_enable[param] & 2) && m_tdr_full[param]) + tx_start(param); + else + m_tx_active[param] = 0; + } +} + +TIMER_CALLBACK_MEMBER(sci4_device::rx_tick) +{ + u32 step = m_rx_step[param]++; + if(step == 0) + wait(1, 1, param); // Value already checked in rx_changed + else if(step < 9) { + if(m_cur_rx[param]) + m_rsr[param] |= 1 << (step - 1); + wait(1, 1, param); + + } else { + if(!m_rx[param]) + logerror("chan %s framing error/break\n", chan_id(param, m_targets >> 4)); + else { + logerror("chan %s recieved %02x\n", chan_id(param, m_targets >> 4), m_rsr[param]); + m_rx_active[param] = 0; + m_rdr[param] = m_rsr[param]; + if(m_rdr_full[param] && (m_enable[param] & 4)) + m_status[param] = 6; + else + m_status[param] = 4; + m_irq[param](1); + } + } +} + +DEFINE_DEVICE_TYPE(SCI4, sci4_device, "sci4", "Yamaha SCI4 quad-serial gate array") diff --git a/src/devices/machine/sci4.h b/src/devices/machine/sci4.h new file mode 100644 index 00000000000..8790f814cc8 --- /dev/null +++ b/src/devices/machine/sci4.h @@ -0,0 +1,74 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert + +// Yamaha SCI4 / XV833A00, 7-lines serial chip with 4 multiplexed on one and the other 3 separated + +#ifndef DEVICES_MACHINE_SCI4_H +#define DEVICES_MACHINE_SCI4_H + +#pragma once + +class sci4_device : public device_t +{ +public: + sci4_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 8000000); + + // sci port numbers are 0..2 and 30..33 + template void rx_w(int state) { do_rx_w(Sci, state); } + template auto write_tx() { if(Sci < 3) return m_tx[Sci].bind(); else return m_tx[Sci - 30 + 3].bind(); } + + // irq line numbers are 0..3 + template auto write_irq() { return m_irq[irq].bind(); } + + void map(address_map &map); + +protected: + virtual void device_start() override; + virtual void device_reset() override; + +protected: + devcb_write_line::array<7> m_tx; + devcb_write_line::array<4> m_irq; + + emu_timer *m_tx_timer[4]; + emu_timer *m_rx_timer[4]; + + std::array m_rx; + std::array m_enable, m_status, m_datamode, m_div, m_cur_rx; + std::array m_tdr, m_tsr, m_tdr_full, m_tx_step, m_tx_active; + std::array m_rdr, m_rsr, m_rdr_full, m_rx_step, m_rx_active; + u8 m_targets; + + void do_rx_w(int sci, int state); + + void default_w(offs_t offset, u8 data); + u8 default_r(offs_t offset); + + void datamode_w(offs_t slot, u8 data); + u8 datamode_r(offs_t slot); + void data_w(offs_t slot, u8 data); + u8 data_r(offs_t slot); + void enable_w(offs_t slot, u8 data); + u8 enable_r(offs_t slot); + u8 status_r(offs_t slot); + u8 reset_r(offs_t slot); + + void target_w(u8 data); + + std::string chan_id(u8 chan, u8 target); + + void wait(int timer, int full, int chan); + void tx_enabled(int chan); + void tx_set(int slot, int state); + void tx_start(int chan); + void rx_changed(int chan); + void fifo_w(int chan, u8 data); + u8 fifo_r(int chan); + + TIMER_CALLBACK_MEMBER(tx_tick); + TIMER_CALLBACK_MEMBER(rx_tick); +}; + +DECLARE_DEVICE_TYPE(SCI4, sci4_device) + +#endif diff --git a/src/devices/sound/swp00.cpp b/src/devices/sound/swp00.cpp index 64d75b24531..17bbfd45ae3 100644 --- a/src/devices/sound/swp00.cpp +++ b/src/devices/sound/swp00.cpp @@ -346,7 +346,7 @@ void swp00_device::device_start() save_item(NAME(m_dpcm_address)); save_item(NAME(m_dpcm_sum)); - for(int i=0; i<128; i++) { + for(int i=0; i != 128; i++) { u32 v = 0; switch(i >> 3) { default: v = ((i & 7) + 8) << (1 + (i >> 3)); break; @@ -908,8 +908,6 @@ void swp00_device::keyon(int chan) m_lfo_phase[chan] = 0; m_sample_pos[chan] = -m_sample_start[chan] << 15; - m_sample_pos[chan] = 0; - m_active[chan] = true; m_decay[chan] = false; m_decay_done[chan] = false; diff --git a/src/devices/sound/swx00.cpp b/src/devices/sound/swx00.cpp index 4f21fe1a90f..1e0bc782777 100644 --- a/src/devices/sound/swx00.cpp +++ b/src/devices/sound/swx00.cpp @@ -420,7 +420,8 @@ u8 swx00_sound_device::state_r() } default: - logerror("state_r %02x\n", m_state_sel); + if(0) + logerror("state_r %02x\n", m_state_sel); break; } return 0; diff --git a/src/devices/video/hd44780.cpp b/src/devices/video/hd44780.cpp index 0c78d01da31..314c1a8a85a 100644 --- a/src/devices/video/hd44780.cpp +++ b/src/devices/video/hd44780.cpp @@ -753,7 +753,7 @@ u8 hd44780_device::control_read() void hd44780_device::data_write(u8 data) { - if (m_busy_flag) + if (false && m_busy_flag) { logerror("HD44780: Ignoring data write %02x due of busy flag\n", data); return; diff --git a/src/mame/layout/mu128.lay b/src/mame/layout/mu128.lay new file mode 100644 index 00000000000..762b6ae6e0c --- /dev/null +++ b/src/mame/layout/mu128.lay @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +// mu-plg1-plg2-plg3 + + + + + + + + diff --git a/src/mame/layout/mu2000.lay b/src/mame/layout/mu2000.lay new file mode 100644 index 00000000000..db1876d2c03 --- /dev/null +++ b/src/mame/layout/mu2000.lay @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mame/layout/mu50.lay b/src/mame/layout/mu50.lay new file mode 100644 index 00000000000..579f6ca073c --- /dev/null +++ b/src/mame/layout/mu50.lay @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mame/mame.lst b/src/mame/mame.lst index c909efb58ab..04b8ff059f0 100644 --- a/src/mame/mame.lst +++ b/src/mame/mame.lst @@ -46269,6 +46269,11 @@ mu100b // 1998 MU-100B @source:yamaha/ymmu128.cpp mu128 +@source:yamaha/ymmu2000.cpp +mu500 +mu1000 +mu2000 + @source:yamaha/ympcs30.cpp pcs30 // 1984 diff --git a/src/mame/yamaha/mulcd.cpp b/src/mame/yamaha/mulcd.cpp index d95c3538a84..da3e327ea8c 100644 --- a/src/mame/yamaha/mulcd.cpp +++ b/src/mame/yamaha/mulcd.cpp @@ -55,9 +55,9 @@ void mulcd_device::set_contrast(u8 contrast) m_contrast = contrast; } -void mulcd_device::set_leds(u8 leds) +void mulcd_device::set_leds(u16 leds) { - for(int x=0; x != 6; x++) + for(int x=0; x != 10; x++) m_led_outputs[x] = (leds >> x) & 1; } diff --git a/src/mame/yamaha/mulcd.h b/src/mame/yamaha/mulcd.h index 829fda1bd3f..b8dc159a177 100644 --- a/src/mame/yamaha/mulcd.h +++ b/src/mame/yamaha/mulcd.h @@ -20,7 +20,7 @@ public: mulcd_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0); void set_contrast(u8 contrast); - void set_leds(u8 leds); + void set_leds(u16 leds); u8 data_read() { return m_lcd->data_r(); } u8 control_read() { return m_lcd->control_r(); } void data_write(u8 data) { m_lcd->data_w(data); } @@ -36,7 +36,7 @@ private: required_device m_lcd; output_finder<64, 8, 5> m_outputs; output_finder<> m_contrast; - output_finder<6> m_led_outputs; + output_finder<10> m_led_outputs; void render_w(int state); }; diff --git a/src/mame/yamaha/ymmu100.cpp b/src/mame/yamaha/ymmu100.cpp index a6e2dae03c9..8a902775cfe 100644 --- a/src/mame/yamaha/ymmu100.cpp +++ b/src/mame/yamaha/ymmu100.cpp @@ -172,6 +172,7 @@ public: { } void mu100(machine_config &config); + void mu100b(machine_config &config); protected: virtual u16 adc_type_r(); @@ -184,7 +185,7 @@ protected: required_device m_maincpu; required_device m_swp30; - required_device m_lcd; + optional_device m_lcd; required_device m_ext1; optional_device m_ext2; required_ioport m_ioport_p7; @@ -312,15 +313,16 @@ void mu100_state::p1_w(u8 data) u8 mu100_state::p1_r() { - if((m_cur_p2 & P2_LCD_ENABLE)) { - if(m_cur_p2 & P2_LCD_RW) { - if(m_cur_p2 & P2_LCD_RS) - return m_lcd->data_read(); - else - return m_lcd->control_read(); - } else - return 0x00; - } + if(m_lcd) + if((m_cur_p2 & P2_LCD_ENABLE)) { + if(m_cur_p2 & P2_LCD_RW) { + if(m_cur_p2 & P2_LCD_RS) + return m_lcd->data_read(); + else + return m_lcd->control_read(); + } else + return 0x00; + } if(!(m_cur_pf & 0x02)) { u8 val = 0xff; @@ -336,16 +338,18 @@ u8 mu100_state::p1_r() void mu100_state::p2_w(u8 data) { + if(m_lcd) { // LCD enable edge - if((m_cur_p2 & P2_LCD_ENABLE) && !(data & P2_LCD_ENABLE)) { - if(!(m_cur_p2 & P2_LCD_RW)) { - if(m_cur_p2 & P2_LCD_RS) - m_lcd->data_write(m_cur_p1); - else - m_lcd->control_write(m_cur_p1); + if((m_cur_p2 & P2_LCD_ENABLE) && !(data & P2_LCD_ENABLE)) { + if(!(m_cur_p2 & P2_LCD_RW)) { + if(m_cur_p2 & P2_LCD_RS) + m_lcd->data_write(m_cur_p1); + else + m_lcd->control_write(m_cur_p1); + } } + m_lcd->set_contrast((data >> 3) & 7); } - m_lcd->set_contrast((data >> 3) & 7); m_cur_p2 = data; } @@ -390,7 +394,8 @@ void mu100_state::pf_w(u8 data) { if(!(m_cur_pf & 0x01) && (data & 0x01)) { m_cur_ic32 = m_cur_p1; - m_lcd->set_leds((m_cur_p1 & 0x1f) | ((m_cur_p1 & 0x80) >> 2)); + if(m_lcd) + m_lcd->set_leds((m_cur_p1 & 0x1f) | ((m_cur_p1 & 0x80) >> 2)); } m_cur_pf = data; m_cur_sw = (m_cur_sw & 0x7) | (BIT(m_cur_pf, 2) << 3); @@ -446,7 +451,7 @@ void mu100_state::swp30_map(address_map &map) map(0x800000, 0x9fffff).rom().region("swp30", 0x1000000).mirror(0x200000); } -void mu100_state::mu100(machine_config &config) +void mu100_state::mu100b(machine_config &config) { H8S2655(config, m_maincpu, 16_MHz_XTAL); m_maincpu->set_addrmap(AS_PROGRAM, &mu100_state::mu100_map); @@ -471,8 +476,6 @@ void mu100_state::mu100(machine_config &config) m_maincpu->write_portg().set(FUNC(mu100_state::pg_w)); m_maincpu->write_sci_tx<2>().set(FUNC(mu100_state::h8_tx)); - MULCD(config, m_lcd); - PLG1X0_CONNECTOR(config, m_ext1, plg1x0_intf, nullptr); m_ext1->midi_tx().set(FUNC(mu100_state::e1_tx)); @@ -497,6 +500,13 @@ void mu100_state::mu100(machine_config &config) m_maincpu->write_sci_tx<0>().set(mdout, FUNC(midi_port_device::write_txd)); } +void mu100_state::mu100(machine_config &config) +{ + mu100b(config); + + MULCD(config, m_lcd); +} + void mu100r_state::mu100r(machine_config &config) { mu100(config); @@ -535,7 +545,7 @@ ROM_END ROM_START( mu100b ) ROM_REGION( 0x200000, "maincpu", 0 ) // MU-100B v1.08 (Nov. 28, 1997) - ROM_LOAD16_WORD_SWAP( "xu50710-m27c160.bin", 0x000000, 0x200000, CRC(4b10bd27) SHA1(12d7c6e1bce7974b34916e1bfa5057ab55867476) ) + ROM_LOAD16_WORD_SWAP( "xu50710.bin", 0x000000, 0x200000, CRC(4b10bd27) SHA1(12d7c6e1bce7974b34916e1bfa5057ab55867476) ) ROM_REGION32_LE( 0x1800000, "swp30", ROMREGION_ERASE00 ) ROM_LOAD32_WORD( "sx518b0.ic34", 0x0000000, 0x400000, CRC(2550d44f) SHA1(fd3cce228c7d389a2fde25c808a5b26080588cba) ) @@ -551,4 +561,4 @@ ROM_END SYST( 1997, mu100, 0, 0, mu100, mu100, mu100_state, empty_init, "Yamaha", "MU100", MACHINE_NOT_WORKING ) SYST( 1997, mu100r, mu100, 0, mu100r, mu100, mu100r_state, empty_init, "Yamaha", "MU100 Rackable version", MACHINE_NOT_WORKING ) -SYST( 1998, mu100b, mu100, 0, mu100, mu100, mu100_state, empty_init, "Yamaha", "MU100 Screenless version", MACHINE_NOT_WORKING ) +SYST( 1998, mu100b, mu100, 0, mu100b, mu100, mu100_state, empty_init, "Yamaha", "MU100 Screenless version", MACHINE_NOT_WORKING ) diff --git a/src/mame/yamaha/ymmu128.cpp b/src/mame/yamaha/ymmu128.cpp index 94c402028ee..192eae9e56a 100644 --- a/src/mame/yamaha/ymmu128.cpp +++ b/src/mame/yamaha/ymmu128.cpp @@ -16,13 +16,14 @@ #include "bus/midi/midioutport.h" #include "cpu/sh/sh7042.h" #include "machine/i8251.h" -#include "sound/swp30.h" -#include "mulcd.h" +#include "machine/input_merger.h" #include "machine/nvram.h" +#include "sound/swp30.h" -#include "debugger.h" +#include "mulcd.h" #include "speaker.h" +#include "mu128.lh" namespace { @@ -53,6 +54,7 @@ private: required_device m_sci; required_shared_ptr m_ram; + u32 m_pa; u16 m_pe; void map(address_map &map); @@ -61,13 +63,17 @@ private: virtual void machine_start() override; virtual void machine_reset() override; + u32 pa_r(); + void pa_w(u32 data); u16 pe_r(); void pe_w(u16 data); }; void mu128_state::machine_start() { + save_item(NAME(m_pa)); save_item(NAME(m_pe)); + m_pa = 0; m_pe = 0; } @@ -75,20 +81,46 @@ void mu128_state::machine_reset() { } +// Port A: +// 8: sw5 +// 9: sw6 +// f: rer +// 10: reb +// 11: rea +// 12: swd +// 14: led1 +// 15: ry/by + +// Port B: +// 2: sw1 +// 3: sw2 +// 4: sw3 +// 5: sw4 + // Port E: -// 0: lcd-r/w -// 1: nc -// 2: lcd-rs -// 3: lcread (secondary functions on lcread edge) -// 4: lcd-e -// 5: 1mclk -// 6: siclk -// 7: sws -// 8-a: db 0-2, lcdc a-c -// b-c: db 3-4, mic/line -// d: db 5, swp reset -// e: db 6, sireset -// f: db 7, breset +// 0: lcd-r/w +// 1: nc +// 2: lcd-rs +// 3: lcread (secondary functions on lcread edge) +// 4: lcd-e +// 5: 1mclk +// 6: siclk +// 7: sws +// 8-a: db 0-2, lcdc a-c +// b-c: db 3-4, mic/line +// d: db 5, swp reset +// e: db 6, sireset +// f: db 7, breset + +u32 mu128_state::pa_r() +{ + return 0; +} + +void mu128_state::pa_w(u32 data) +{ + m_pa = data; +} u16 mu128_state::pe_r() { @@ -121,10 +153,17 @@ void mu128_state::pe_w(u16 data) void mu128_state::map(address_map &map) { + // 000000-3fffff: cs0 space, 32 bits, 2 wait states map(0x000000, 0x1fffff).rom().region("maincpu", 0); + + // 400000-7fffff: cs1 space, 16 bits, 2 wait states map(0x400000, 0x43ffff).ram().share(m_ram); + + // 800000-bfffff: cs2 space, 16 bits, cs assert extension, 3 wait states map(0x800000, 0x801fff).m(m_swp30m, FUNC(swp30_device::map)); map(0x802000, 0x803fff).m(m_swp30s, FUNC(swp30_device::map)); + + // c00000-ffffff: cs3 space, 8 bits, 2 wait states map(0xc00000, 0xc00000).rw(m_sci, FUNC(i8251_device::data_r), FUNC(i8251_device::data_w)).mirror(0x3ffffe); map(0xc00001, 0xc00001).rw(m_sci, FUNC(i8251_device::status_r), FUNC(i8251_device::control_w)).mirror(0x3ffffe); } @@ -136,8 +175,10 @@ void mu128_state::swp30_map(address_map &map) void mu128_state::mu128(machine_config &config) { - SH7043(config, m_maincpu, 7_MHz_XTAL * 4); + SH7043(config, m_maincpu, 7_MHz_XTAL * 4); // md=9, no on-chip rom, 32-bit space, pll 4x m_maincpu->set_addrmap(AS_PROGRAM, &mu128_state::map); + m_maincpu->read_porta().set(FUNC(mu128_state::pa_r)); + m_maincpu->write_porta().set(FUNC(mu128_state::pa_w)); m_maincpu->read_porte().set(FUNC(mu128_state::pe_r)); m_maincpu->write_porte().set(FUNC(mu128_state::pe_w)); @@ -158,7 +199,10 @@ void mu128_state::mu128(machine_config &config) m_swp30s->add_route(0, "lspeaker", 1.0); m_swp30s->add_route(1, "rspeaker", 1.0); + INPUT_MERGER_ANY_HIGH(config, "irq0").output_handler().set_inputline(m_maincpu, 0); I8251(config, m_sci, 10_MHz_XTAL); // uPD71051GU-10 + m_sci->rxrdy_handler().set("irq0", FUNC(input_merger_device::in_w<0>)); + m_sci->txrdy_handler().set("irq0", FUNC(input_merger_device::in_w<1>)); auto &mdin_a(MIDI_PORT(config, "mdin_a")); midiin_slot(mdin_a); @@ -171,6 +215,8 @@ void mu128_state::mu128(machine_config &config) auto &mdout(MIDI_PORT(config, "mdout")); midiout_slot(mdout); m_maincpu->write_sci_tx<0>().set(mdout, FUNC(midi_port_device::write_txd)); + + config.set_default_layout(layout_mu128); } #define ROM_LOAD32_WORD_SWAP_BIOS(bios,name,offset,length,hash) \ diff --git a/src/mame/yamaha/ymmu2000.cpp b/src/mame/yamaha/ymmu2000.cpp new file mode 100644 index 00000000000..0323e44126f --- /dev/null +++ b/src/mame/yamaha/ymmu2000.cpp @@ -0,0 +1,457 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/************************************************************************************* + + Yamaha MU-500/1000/2000: + 32/64-part, 64/128-note polyphonic/multitimbral General MIDI/XG tone module + + Driver by O. Galibert + + MU2000: SH7043, dual SWP30, sample ram, M37640 for usb, smartcard port + MU1000: sample ram and smartcard port removed + MU500: one SWP30 removed + +**************************************************************************************/ + +#include "emu.h" + +#include "bus/midi/midiinport.h" +#include "bus/midi/midioutport.h" +#include "bus/plg1x0/plg1x0.h" +#include "cpu/sh/sh7042.h" +#include "machine/input_merger.h" +#include "machine/nvram.h" +#include "machine/sci4.h" +#include "sound/swp30.h" + +#include "mulcd.h" +#include "speaker.h" + +#include "mu128.lh" +#include "mu2000.lh" + + +namespace { + +static INPUT_PORTS_START( mu500 ) + PORT_START("SWS0") + PORT_BIT(0x03, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Strings") + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Bass") + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Guitar") + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Organ") + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Chrom. Perc.") + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Piano") + + PORT_START("SWS1") + PORT_BIT(0x03, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Synth pad") + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Synth lead") + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Pipe") + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Reed") + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Brass") + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Ensemble") + + PORT_START("SWS2") + PORT_BIT(0x03, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Drum") + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Model excl.") + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("SFX") + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Percussive") + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Ethnic") + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Synth effects") + + PORT_START("SWS3") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Part +") PORT_CODE(KEYCODE_CLOSEBRACE) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Part -") PORT_CODE(KEYCODE_OPENBRACE) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Mute/Solo") PORT_CODE(KEYCODE_S) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Effect") PORT_CODE(KEYCODE_F) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Util") PORT_CODE(KEYCODE_U) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Edit") PORT_CODE(KEYCODE_E) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Play") PORT_CODE(KEYCODE_A) + + PORT_START("SWS4") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Value +") PORT_CODE(KEYCODE_EQUALS) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Value -") PORT_CODE(KEYCODE_MINUS) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Exit") PORT_CODE(KEYCODE_BACKSPACE) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Select >") PORT_CODE(KEYCODE_STOP) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Select <") PORT_CODE(KEYCODE_COMMA) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Enter") PORT_CODE(KEYCODE_ENTER) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Seq") PORT_CODE(KEYCODE_Q) + + PORT_START("SWS5") + PORT_BIT(0x1f, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Audition") PORT_CODE(KEYCODE_Z) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Select") PORT_CODE(KEYCODE_X) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Sampling/Mode") PORT_CODE(KEYCODE_M) +INPUT_PORTS_END + +class mu500_state : public driver_device +{ +public: + mu500_state(const machine_config &mconfig, device_type type, const char *tag) + : driver_device(mconfig, type, tag) + , m_maincpu(*this, "maincpu") + , m_nvram(*this, "ram") + , m_swp30m(*this, "swp30m") + , m_sci(*this, "sci") + , m_lcd(*this, "lcd") + , m_ram(*this, "ram") + , m_ext(*this, "plg%u", 1U) + , m_ioports(*this, "SWS%u", 0U) + + { } + + void mu500(machine_config &config); + +protected: + required_device m_maincpu; + required_device m_nvram; + required_device m_swp30m; + required_device m_sci; + required_device m_lcd; + required_shared_ptr m_ram; + required_device_array m_ext; + required_ioport_array<6> m_ioports; + + u16 m_pe; + u8 m_ledsw1, m_ledsw2; + + void map_500(address_map &map); + void swp30_map(address_map &map); + + virtual void machine_start() override; + virtual void machine_reset() override; + + u16 adc_ar_r(); + u16 adc_al_r(); + u16 adc_midisw_r(); + u16 adc_battery_r(); + + u16 pe_r(); + void pe_w(u16 data); + u16 pa_r(); + + void update_leds(); + u8 ledsw_r(); + void ledsw1_w(u8 data); + void ledsw2_w(u8 data); +}; + +class mu1000_state : public mu500_state +{ +public: + mu1000_state(const machine_config &mconfig, device_type type, const char *tag) + : mu500_state(mconfig, type, tag) + , m_swp30s(*this, "swp30s") + + { } + + void mu1000(machine_config &config); + +protected: + required_device m_swp30s; + void map_1000(address_map &map); +}; + +class mu2000_state : public mu1000_state +{ +public: + mu2000_state(const machine_config &mconfig, device_type type, const char *tag) + : mu1000_state(mconfig, type, tag) + { } + + void mu2000(machine_config &config); + +protected: + void map_2000(address_map &map); +}; + + + +void mu500_state::machine_start() +{ + save_item(NAME(m_pe)); + save_item(NAME(m_ledsw1)); + save_item(NAME(m_ledsw2)); + m_pe = 0; + m_ledsw1 = 0; + m_ledsw2 = 0; +} + +void mu500_state::machine_reset() +{ +} + +u16 mu500_state::pe_r() +{ + if(BIT(m_pe, 4)) { + if(BIT(m_pe, 0)) { + if(BIT(m_pe, 2)) + return m_lcd->data_read() << 8; + else + return m_lcd->control_read() << 8; + } else + return 0x0000; + } + + return 0; +} + +void mu500_state::pe_w(u16 data) +{ + if(BIT(m_pe, 4) && !BIT(data, 4)) { + if(!BIT(data, 0)) { + if(BIT(data, 2)) + m_lcd->data_write(data >> 8); + else + m_lcd->control_write(data >> 8); + } + } + + m_pe = data; +} + +u16 mu500_state::pa_r() +{ + // 21: out, selects between front and back midi a to go on rxd0 + // 20: smvprt + // 19: smvins + // 18: smbusy + // 17: rea (rotary encoder) + // 16: reb + return 0xffff; +} + +void mu500_state::update_leds() +{ + m_lcd->set_leds(util::bitswap((m_ledsw2 << 8) | m_ledsw1, 9, 8, 7, 6, 10, 11, 12, 13, 14, 15)); +} + +u8 mu500_state::ledsw_r() +{ + u8 res = 0xff; + for(u32 i=0; i != 6; i++) + if(BIT(m_ledsw1, i)) + res &= m_ioports[i]->read(); + return res; +} + +void mu500_state::ledsw1_w(u8 data) +{ + m_ledsw1 = data; + update_leds(); +} + +void mu500_state::ledsw2_w(u8 data) +{ + m_ledsw2 = data; + update_leds(); +} + +// Analog input right (also sent to the swp30m dac0) +u16 mu500_state::adc_ar_r() +{ + return 0; +} + +// Analog input left (also sent to the swp30m dac0) +u16 mu500_state::adc_al_r() +{ + return 0; +} + +// Put the host switch to pure midi +u16 mu500_state::adc_midisw_r() +{ + return 0; +} + +// Battery level +u16 mu500_state::adc_battery_r() +{ + return 0x3ff; +} + +void mu500_state::map_500(address_map &map) +{ + // 000000-3fffff: cs0 space, 32 bits, 2 wait states + map(0x000000, 0x1fffff).rom().region("maincpu", 0); + + // 400000-7fffff: cs1 space, 16 bits, 2 wait states + map(0x400000, 0x43ffff).ram().share(m_ram); + + // 800000-bfffff: cs2 space, 16 bits, cs assert extension, 3 wait states + map(0x800000, 0x801fff).m(m_swp30m, FUNC(swp30_device::map)); + // 802000 : slave swp30 + + // c00000-ffffff: cs3 space, 8 bits, cs assert extension, 2 wait states, 3 idle states + + // c00000 : smartcard + map(0xc80000, 0xc80000).rw(FUNC(mu500_state::ledsw_r), FUNC(mu500_state::ledsw1_w)); + // d00000 : smartcard + // d80000 : contrast, levels + map(0xe00000, 0xe00000).w(FUNC(mu500_state::ledsw2_w)); + // e80000 : dit2 (digital output) + map(0xf00000, 0xf0003f).m(m_sci, FUNC(sci4_device::map)); + + // f80000 : usb + + // Dedicated dram space, ras precharge = 2.5, ras-cas delay 2, cas-before-ras 2.5, dram write 3, read 3, idle 0, burst, ras down, 16bits, 9-bit address + // Automatic refresh every 420 cycles, cas-before-ras + map(0x01000000, 0x0107ffff).ram(); // dram +} + +void mu1000_state::map_1000(address_map &map) +{ + map_500(map); + map(0x802000, 0x803fff).m(m_swp30s, FUNC(swp30_device::map)); +} + +void mu2000_state::map_2000(address_map &map) +{ + map_1000(map); + map(0x000000, 0x3fffff).rom().region("maincpu", 0); +} + +void mu500_state::swp30_map(address_map &map) +{ + map(0x000000, 0x7fffff).rom().region("swp30", 0); +} + +void mu500_state::mu500(machine_config &config) +{ + SH7043A(config, m_maincpu, 7_MHz_XTAL * 4); // md=9, no on-chip rom, 32-bit space, pll 4x + m_maincpu->set_addrmap(AS_PROGRAM, &mu500_state::map_500); + m_maincpu->read_porta().set(FUNC(mu500_state::pa_r)); + m_maincpu->read_porte().set(FUNC(mu500_state::pe_r)); + m_maincpu->write_porte().set(FUNC(mu500_state::pe_w)); + m_maincpu->read_adc<0>().set(FUNC(mu500_state::adc_ar_r)); + m_maincpu->read_adc<1>().set_constant(0); + m_maincpu->read_adc<2>().set(FUNC(mu500_state::adc_al_r)); + m_maincpu->read_adc<3>().set_constant(0); + m_maincpu->read_adc<4>().set(FUNC(mu500_state::adc_midisw_r)); + m_maincpu->read_adc<5>().set_constant(0); + m_maincpu->read_adc<6>().set(FUNC(mu500_state::adc_battery_r)); + m_maincpu->read_adc<7>().set_constant(0); + + INPUT_MERGER_ANY_HIGH(config, "sciirq").output_handler().set_inputline(m_maincpu, 0); + + SCI4(config, m_sci); + m_sci->write_irq<0>().set("sciirq", FUNC(input_merger_device::in_w<0>)); + m_sci->write_irq<1>().set("sciirq", FUNC(input_merger_device::in_w<1>)); + m_sci->write_irq<3>().set_inputline(m_maincpu, 1); + + NVRAM(config, m_nvram, nvram_device::DEFAULT_NONE); + + MULCD(config, m_lcd); + + SPEAKER(config, "lspeaker").front_left(); + SPEAKER(config, "rspeaker").front_right(); + + SWP30(config, m_swp30m); + m_swp30m->set_addrmap(AS_DATA, &mu500_state::swp30_map); + m_swp30m->add_route(0, "lspeaker", 1.0); + m_swp30m->add_route(1, "rspeaker", 1.0); + + auto &mdin_a(MIDI_PORT(config, "mdin_a")); + midiin_slot(mdin_a); + mdin_a.rxd_handler().set(m_maincpu, FUNC(sh7043_device::sci_rx_w<0>)); + + auto &mdin_b(MIDI_PORT(config, "mdin_b")); + midiin_slot(mdin_b); + mdin_b.rxd_handler().set(m_maincpu, FUNC(sh7043_device::sci_rx_w<1>)); + + auto &mdout(MIDI_PORT(config, "mdout")); + midiout_slot(mdout); + m_maincpu->write_sci_tx<0>().set(mdout, FUNC(midi_port_device::write_txd)); + + PLG1X0_CONNECTOR(config, m_ext[0], plg1x0_intf, nullptr); + m_ext[0]->midi_tx().set(m_sci, FUNC(sci4_device::rx_w<30>)); + m_sci->write_tx<30>().set(m_ext[0], FUNC(plg1x0_connector::midi_rx)); + + PLG1X0_CONNECTOR(config, m_ext[1], plg1x0_intf, nullptr); + m_ext[1]->midi_tx().set(m_sci, FUNC(sci4_device::rx_w<31>)); + m_sci->write_tx<31>().set(m_ext[1], FUNC(plg1x0_connector::midi_rx)); + + PLG1X0_CONNECTOR(config, m_ext[2], plg1x0_intf, nullptr); + m_ext[2]->midi_tx().set(m_sci, FUNC(sci4_device::rx_w<32>)); + m_sci->write_tx<32>().set(m_ext[2], FUNC(plg1x0_connector::midi_rx)); + + config.set_default_layout(layout_mu128); +} + +void mu1000_state::mu1000(machine_config &config) +{ + mu500(config); + m_maincpu->set_addrmap(AS_PROGRAM, &mu1000_state::map_1000); + + SWP30(config, m_swp30s); + m_swp30s->set_addrmap(AS_DATA, &mu1000_state::swp30_map); + m_swp30s->add_route(0, "lspeaker", 1.0); + m_swp30s->add_route(1, "rspeaker", 1.0); +} + +void mu2000_state::mu2000(machine_config &config) +{ + mu1000(config); + m_maincpu->set_addrmap(AS_PROGRAM, &mu2000_state::map_2000); + + config.set_default_layout(layout_mu2000); +} + + +#define ROM_LOAD32_WORD_SWAP_BIOS(bios,name,offset,length,hash) \ + ROMX_LOAD(name, offset, length, hash, ROM_GROUPWORD | ROM_REVERSE | ROM_SKIP(2) | ROM_BIOS(bios)) + +ROM_START( mu500 ) + ROM_REGION( 0x200000, "maincpu", ROMREGION_ERASE00 ) + // Soon (tm) + + ROM_REGION32_LE( 0x2000000, "swp30", ROMREGION_ERASE00 ) + ROM_LOAD32_WORD( "xv364a0.ic49", 0x0000000, 0x800000, CRC(cda1afd6) SHA1(e7098246b33c3cf22ed8cc15ed6383f8a06d17e9) ) + ROM_LOAD32_WORD( "xv365a0.ic50", 0x0000002, 0x800000, CRC(10985ed0) SHA1(d45a2e85859e05046f3ede8317a9bb0b88898116) ) + ROM_LOAD32_WORD( "xw848a0.ic53", 0x1000000, 0x800000, CRC(34913e42) SHA1(9e8b55c2cbac3f69cc0b17aeaf02053145bfaeda) ) + ROM_LOAD32_WORD( "xw849a0.ic54", 0x1000002, 0x800000, CRC(3728f1f2) SHA1(7670d672e24d6388fa92799175f35869a140c451) ) +ROM_END + +ROM_START( mu1000 ) + ROM_REGION( 0x200000, "maincpu", 0 ) + ROM_DEFAULT_BIOS("v201") + ROM_SYSTEM_BIOS( 0, "v201", "Upgrade package (Ver2.01 02-MAY-29)" ) + ROM_LOAD32_WORD_SWAP_BIOS( 0, "mu1000-v2.01-h.bin", 0x000000, 0x100000, CRC(d0809297) SHA1(cee47062966b01ce72e8ebaf6f7fa9778b32f6ab) ) + ROM_LOAD32_WORD_SWAP_BIOS( 0, "mu1000-v2.01-l.bin", 0x000002, 0x100000, CRC(048a2750) SHA1(19f51c6304e3550d0bb8b3cca647f1fc609b0994) ) + // Version < 2.0 is very hard to find, most mu1000 have been upgraded to 2.x (aka EX) + + ROM_REGION32_LE( 0x2000000, "swp30", ROMREGION_ERASE00 ) + ROM_LOAD32_WORD( "xv364a0.ic49", 0x0000000, 0x800000, CRC(cda1afd6) SHA1(e7098246b33c3cf22ed8cc15ed6383f8a06d17e9) ) + ROM_LOAD32_WORD( "xv365a0.ic50", 0x0000002, 0x800000, CRC(10985ed0) SHA1(d45a2e85859e05046f3ede8317a9bb0b88898116) ) + ROM_LOAD32_WORD( "xw848a0.ic53", 0x1000000, 0x800000, CRC(34913e42) SHA1(9e8b55c2cbac3f69cc0b17aeaf02053145bfaeda) ) + ROM_LOAD32_WORD( "xw849a0.ic54", 0x1000002, 0x800000, CRC(3728f1f2) SHA1(7670d672e24d6388fa92799175f35869a140c451) ) +ROM_END + +ROM_START( mu2000 ) + ROM_REGION( 0x400000, "maincpu", 0 ) + ROM_DEFAULT_BIOS("v200") + ROM_SYSTEM_BIOS( 0, "v200", "Upgrade package (Ver2.01 02-MAY-29)" ) + ROM_LOAD32_WORD_SWAP_BIOS( 0, "mu2000-v2.01-h.bin", 0x000000, 0x200000, CRC(be3668f6) SHA1(00d008b6a2536a71681ce2f4fd1a5853406f82f2) ) + ROM_LOAD32_WORD_SWAP_BIOS( 0, "mu2000-v2.01-l.bin", 0x000002, 0x200000, CRC(55921a50) SHA1(fd8fe6a5cbba028d847453c004cb2dcf9ba02013) ) + ROM_SYSTEM_BIOS( 1, "v101", "20 (v1.01, 99-NOV-16)" ) + ROM_LOAD32_WORD_SWAP_BIOS( 1, "xw87020.ic25", 0x000000, 0x200000, CRC(79f6c158) SHA1(2213b9c661c6b1a79963321c37aff40be7cc1fff) ) + ROM_LOAD32_WORD_SWAP_BIOS( 1, "xw86920.ic24", 0x000002, 0x200000, CRC(afbac33c) SHA1(594b4c64aecf6a5204b058375e39e44b8fe373be) ) + + ROM_REGION32_LE( 0x2000000, "swp30", ROMREGION_ERASE00 ) + ROM_LOAD32_WORD( "xv364a0.ic49", 0x0000000, 0x800000, CRC(cda1afd6) SHA1(e7098246b33c3cf22ed8cc15ed6383f8a06d17e9) ) + ROM_LOAD32_WORD( "xv365a0.ic50", 0x0000002, 0x800000, CRC(10985ed0) SHA1(d45a2e85859e05046f3ede8317a9bb0b88898116) ) + ROM_LOAD32_WORD( "xw848a0.ic53", 0x1000000, 0x800000, CRC(34913e42) SHA1(9e8b55c2cbac3f69cc0b17aeaf02053145bfaeda) ) + ROM_LOAD32_WORD( "xw849a0.ic54", 0x1000002, 0x800000, CRC(3728f1f2) SHA1(7670d672e24d6388fa92799175f35869a140c451) ) +ROM_END + +} // anonymous namespace + + +CONS( 2000, mu500, 0, 0, mu500, mu500, mu500_state, empty_init, "Yamaha", "MU500", MACHINE_NOT_WORKING ) +CONS( 1999, mu1000, mu500, 0, mu1000, mu500, mu1000_state, empty_init, "Yamaha", "MU1000", MACHINE_NOT_WORKING ) +CONS( 1999, mu2000, mu500, 0, mu2000, mu500, mu2000_state, empty_init, "Yamaha", "MU2000", MACHINE_NOT_WORKING ) diff --git a/src/mame/yamaha/ymmu50.cpp b/src/mame/yamaha/ymmu50.cpp index 16586faaeef..8954de09ad0 100644 --- a/src/mame/yamaha/ymmu50.cpp +++ b/src/mame/yamaha/ymmu50.cpp @@ -20,13 +20,14 @@ #include "bus/midi/midiinport.h" #include "bus/midi/midioutport.h" #include "cpu/h8/h83003.h" -#include "mulcd.h" -#include "sound/swp00.h" #include "machine/nvram.h" +#include "sound/swp00.h" -#include "debugger.h" +#include "mulcd.h" #include "speaker.h" +#include "mu50.lh" + namespace { @@ -266,6 +267,8 @@ void mu50_state::mu50(machine_config &config) auto &mdout(MIDI_PORT(config, "mdout")); midiout_slot(mdout); m_mu50cpu->write_sci_tx<1>().set(mdout, FUNC(midi_port_device::write_txd)); + + config.set_default_layout(layout_mu50); } #define ROM_LOAD16_WORD_SWAP_BIOS(bios,name,offset,length,hash) \ diff --git a/src/mame/yamaha/ympsr540.cpp b/src/mame/yamaha/ympsr540.cpp index 4fff0ebd8e0..27ca98f1f70 100644 --- a/src/mame/yamaha/ympsr540.cpp +++ b/src/mame/yamaha/ympsr540.cpp @@ -6,8 +6,11 @@ #include "bus/midi/midiinport.h" #include "bus/midi/midioutport.h" #include "cpu/sh/sh7042.h" +#include "sound/swx00.h" +#include "video/hd44780.h" #include "debugger.h" +#include "screen.h" #include "speaker.h" class psr540_state : public driver_device { @@ -15,6 +18,9 @@ public: psr540_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag), m_maincpu(*this, "maincpu"), + m_swx00(*this, "swx00"), + m_lcdc(*this, "ks0066"), + m_outputs(*this, "%02d.%x.%x", 0U, 0U, 0U), m_sustain(*this, "SUSTAIN"), m_pitch_bend(*this, "PITCH_BEND") { } @@ -23,9 +29,14 @@ public: private: required_device m_maincpu; + required_device m_swx00; + required_device m_lcdc; + output_finder<80, 8, 5> m_outputs; required_ioport m_sustain; required_ioport m_pitch_bend; + u16 m_pe, m_led, m_scan; + void map(address_map &map); void machine_start() override; @@ -33,10 +44,53 @@ private: u16 adc_sustain_r(); u16 adc_midisw_r(); u16 adc_battery_r(); + + u16 pe_r(); + void pe_w(u16 data); + u8 pf_r(); + + void lcd_data_w(u8 data); + void led_data_w(offs_t, u16 data, u16 mem_mask); + void render_w(int state); }; +void psr540_state::render_w(int state) +{ + if(!state) + return; + + const u8 *render = m_lcdc->render(); + if(1) + for(int yy=0; yy != 8; yy++) + for(int x=0; x != 80; x++) { + uint8_t v = render[16*x + yy]; + for(int xx=0; xx != 5; xx++) + m_outputs[x][yy][xx] = (v >> xx) & 1; + } + + if(1) + for(int x1=0; x1 != 4; x1++) + for(int yy=0; yy != 8; yy++) { + std::string s; + for(int x=0; x != 10; x++) { + uint8_t v = render[16*(x+10*x1) + yy]; + for(int xx=0; xx != 5; xx++) + s += ((v >> (4-xx)) & 1) ? '#' : '.'; + } + logerror("XX %02d.%d %s\n", x1*10, yy, s); + } +} + void psr540_state::machine_start() { + m_outputs.resolve(); + + save_item(NAME(m_pe)); + save_item(NAME(m_led)); + save_item(NAME(m_scan)); + m_pe = 0; + m_led = 0; + m_scan = 0; } u16 psr540_state::adc_sustain_r() @@ -56,36 +110,92 @@ u16 psr540_state::adc_battery_r() void psr540_state::psr540(machine_config &config) { - SH7042(config, m_maincpu, 7_MHz_XTAL*4); // internal mask rom active, pll x4 + SH7042A(config, m_maincpu, 7_MHz_XTAL*4); // // md=a, on-chip rom, 32-bit space, pll 4x -- XW25610 6437042F14F 9M1 A m_maincpu->set_addrmap(AS_PROGRAM, &psr540_state::map); m_maincpu->read_adc<0>().set(FUNC(psr540_state::adc_midisw_r)); m_maincpu->read_adc<1>().set(FUNC(psr540_state::adc_sustain_r)); m_maincpu->read_adc<2>().set(FUNC(psr540_state::adc_battery_r)); m_maincpu->read_adc<3>().set_constant(0); m_maincpu->read_adc<4>().set_ioport(m_pitch_bend); + m_maincpu->read_porte().set(FUNC(psr540_state::pe_r)); + m_maincpu->write_porte().set(FUNC(psr540_state::pe_w)); + m_maincpu->read_portf().set(FUNC(psr540_state::pf_r)); + + SWX00_SOUND(config, m_swx00); + m_swx00->add_route(0, "lspeaker", 1.0); + m_swx00->add_route(1, "rspeaker", 1.0); + + KS0066(config, m_lcdc, 270000); // OSC = 91K resistor, TODO: actually KS0066U-10B + m_lcdc->set_default_bios_tag("f05"); + m_lcdc->set_lcd_size(2, 40); + + /* video hardware */ + auto &screen = SCREEN(config, "screen", SCREEN_TYPE_SVG); + screen.set_refresh_hz(60); + screen.set_size(1080, 360); + screen.set_visarea_full(); + screen.screen_vblank().set(FUNC(psr540_state::render_w)); SPEAKER(config, "lspeaker").front_left(); SPEAKER(config, "rspeaker").front_right(); } +u16 psr540_state::pe_r() +{ + return 0xffff; +} + +u8 psr540_state::pf_r() +{ + return 0xff; +} + +void psr540_state::pe_w(u16 data) +{ + m_pe = data; + logerror("pe lcd_rs=%x lcd_en=%x ldcic=%d fdcic=%d\n", BIT(m_pe, 11), BIT(m_pe, 9), BIT(m_pe, 4), BIT(m_pe, 3)); + m_lcdc->rs_w(BIT(m_pe, 11)); + m_lcdc->e_w(BIT(m_pe, 9)); + + if(BIT(m_pe, 4)) + m_scan = m_led & 7; +} + +void psr540_state::lcd_data_w(u8 data) +{ + m_lcdc->db_w(data); +} + +void psr540_state::led_data_w(offs_t, u16 data, u16 mem_mask) +{ + COMBINE_DATA(&m_led); + if(BIT(m_pe, 4)) + m_scan = m_led & 7; +} + void psr540_state::map(address_map &map) { - map(0x0000000, 0x001ffff).rom().region("kernel", 0).mirror(0x1e0000); + map(0x00000000, 0x0001ffff).rom().region("kernel", 0).mirror(0x1e0000); // Internal rom, single-cycle - // 200000-3fffff: cs0 space + // 200000-3fffff: cs0 space, 8bits, 1 cycle between accesses, cs assert extension, 6 wait states // 200000 fdc - map(0x0280000, 0x029ffff).ram(); // sram - // 2a0000 leds - // 2c0000 lcd + map(0x00200000, 0x00200000).lr8(NAME([]() -> u8 { return 0x80; })); + // 280000 sram (battery-backed) + map(0x00280000, 0x0029ffff).ram(); + // 2c0000 leds/scanning + map(0x002c0000, 0x002c0001).w(FUNC(psr540_state::led_data_w)); + // 300000 lcd + map(0x00300000, 0x00300000).w(FUNC(psr540_state::lcd_data_w)); - // 400000-7fffff: cs1 space - map(0x0400000, 0x07fffff).rom().region("program_rom", 0); + // 400000-7fffff: cs1 space, 16 bits, 2 wait states + map(0x00400000, 0x007fffff).rom().region("program_rom", 0); - // c00000-ffffff: cs3 space - // c00000: swx00 + // c00000-ffffff: cs3 space, 8 bits, cs assert extension, 3 wait states + map(0x00c00000, 0x00c00fff).m(m_swx00, FUNC(swx00_sound_device::map)); - // Dedicated dram space - map(0x1000000, 0x13fffff).ram(); // dram + // Dedicated dram space, ras precharge = 1.5, ras-cas delay 2, cas-before-ras 2.5, dram write 4, read 3, idle 0, burst, ras down, 16bits, 9-bit address + // Automatic refresh every 436 cycles, cas-before-ras + map(0x01000000, 0x0107ffff).ram(); // dram } static INPUT_PORTS_START( psr540 ) @@ -108,6 +218,10 @@ ROM_START( psr540 ) ROM_REGION16_LE( 0x600000, "swx00", 0) ROM_LOAD16_WORD_SWAP( "xw25410.ic210", 0, 0x400000, CRC(c7c4736d) SHA1(ff1052eb076557071ed8652e6c2fc0925144fbd5)) ROM_LOAD16_WORD_SWAP( "xw25520.ic220", 0x400000, 0x200000, CRC(9ef56c4e) SHA1(f26b588f9bcfd7bdbf1c0b38e4a1ea57e2f29f10)) + + // Warning: will change, only the grid is mapped at this point + ROM_REGION(800000, "screen", ROMREGION_ERASE00) + ROM_LOAD("psr540-lcd.svg", 0, 0x95f72, CRC(15adfc4d) SHA1(92c5bb43ef253bb33ec2b3a77c11d23db8322dc1)) ROM_END SYST( 1999, psr540, 0, 0, psr540, psr540, psr540_state, empty_init, "Yamaha", "PSR540", MACHINE_IS_SKELETON )