sh7042: Add dmac, mtu, adc, intc, sci, bsc. Separate A and non-A

psr540: Add the swx00

New machines marked as MACHINE_NOT_WORKING
------------------------------------------
Yamaha MU500 [Matt, O. Galibert]
Yamaha MU1000 [Matt, O. Galibert]
Yamaha MU2000 [Matt, O. Galibert]
This commit is contained in:
Olivier Galibert 2024-05-02 19:48:15 +02:00
parent 3b5e60b420
commit 055b4c669c
35 changed files with 3686 additions and 157 deletions

View File

@ -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",

View File

@ -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

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -11,8 +11,12 @@
#include "sh2.h"
#include "sh_intc.h"
#include "sh_adc.h"
#include "sh_bsc.h"
#include "sh_cmt.h"
#include "sh_dmac.h"
#include "sh_mtu.h"
#include "sh_port.h"
#include "sh_sci.h"
class sh7042_device : public sh2_device
{
@ -21,7 +25,13 @@ public:
template<int Port> auto read_adc() { return m_read_adc[Port].bind(); }
template<int Sci> void sci_rx_w(int state) { do_sci_w(Sci, state); }
template<int Sci> void sci_clk_w(int state) { m_sci[Sci]->do_clk_w(state); }
template<int Sci> auto write_sci_tx() { return m_sci_tx[Sci].bind(); }
template<int Sci> auto write_sci_clk() { return m_sci_clk[Sci].bind(); }
void sci_set_external_clock_period(int sci, const attotime &period) {
m_sci[sci].lookup()->do_set_external_clock_period(period);
}
auto read_porta() { return m_read_port32 [0].bind(); }
auto write_porta() { return m_write_port32[0].bind(); }
@ -46,6 +56,9 @@ public:
void set_internal_interrupt(int level, u32 vector);
void do_sci_tx(int sci, int state) { m_sci_tx[sci](state); }
void do_sci_clk(int sci, int state) { m_sci_clk[sci](state); }
protected:
const char *m_port16_names;
const char *m_port32_names;
@ -66,25 +79,43 @@ protected:
CR_BUF = 0x03
};
bool m_die_a;
sh7042_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock);
virtual void device_start() override;
virtual void device_reset() override;
virtual void device_add_mconfig(machine_config &config) override;
virtual void sh2_exception_internal(const char *message, int irqline, int vector) override;
virtual void execute_set_input(int irqline, int state) override;
private:
required_device<sh_intc_device> m_intc;
required_device<sh_adc_device> m_adc;
required_device<sh_adc_device> m_adc0;
optional_device<sh_adc_device> m_adc1;
required_device<sh_bsc_device> m_bsc;
required_device<sh_cmt_device> m_cmt;
required_device<sh_dmac_device> m_dmac;
required_device<sh_dmac_channel_device> m_dmac0;
required_device<sh_dmac_channel_device> m_dmac1;
required_device<sh_dmac_channel_device> m_dmac2;
required_device<sh_dmac_channel_device> m_dmac3;
required_device<sh_mtu_device> m_mtu;
required_device<sh_mtu_channel_device> m_mtu0;
required_device<sh_mtu_channel_device> m_mtu1;
required_device<sh_mtu_channel_device> m_mtu2;
required_device<sh_mtu_channel_device> m_mtu3;
required_device<sh_mtu_channel_device> m_mtu4;
required_device<sh_port32_device> m_porta;
required_device<sh_port16_device> m_portb;
required_device<sh_port16_device> m_portc;
required_device<sh_port32_device> m_portd;
required_device<sh_port16_device> m_porte;
required_device<sh_port16_device> m_portf;
required_device_array<sh_sci_device, 2> m_sci;
devcb_read16::array<8> m_read_adc;
devcb_write_line::array<2> m_sci_tx;
devcb_write_line::array<2> m_sci_tx, m_sci_clk;
devcb_read16::array<4> m_read_port16;
devcb_write16::array<4> m_write_port16;
devcb_read32::array<2> m_read_port32;
@ -134,14 +165,28 @@ private:
void pcf_if_w(offs_t, u16 data, u16 mem_mask);
};
class sh7042a_device : public sh7042_device
{
public:
sh7042a_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
};
class sh7043_device : public sh7042_device
{
public:
sh7043_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
};
class sh7043a_device : public sh7042_device
{
public:
sh7043a_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
};
DECLARE_DEVICE_TYPE(SH7042, sh7042_device)
DECLARE_DEVICE_TYPE(SH7043, sh7043_device)
DECLARE_DEVICE_TYPE(SH7042, sh7042_device)
DECLARE_DEVICE_TYPE(SH7042A, sh7042a_device)
DECLARE_DEVICE_TYPE(SH7043, sh7043_device)
DECLARE_DEVICE_TYPE(SH7043A, sh7043a_device)
#endif // MAME_CPU_SH_SH7042_H

View File

@ -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)

View File

@ -19,17 +19,6 @@ class sh_intc_device;
class sh_adc_device : public device_t {
public:
sh_adc_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
template<typename T, typename U> sh_adc_device(const machine_config &mconfig, const char *tag, device_t *owner,
T &&cpu, U &&intc, int vect) :
sh_adc_device(mconfig, tag, owner)
{
m_cpu.set_tag(std::forward<T>(cpu));
m_intc.set_tag(std::forward<U>(intc));
m_intc_vector = vect;
}
u16 addr_r(offs_t offset);
u8 adcsr_r();
u8 adcr_r();
@ -41,9 +30,13 @@ public:
u64 internal_update(u64 current_time);
protected:
sh_adc_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock);
required_device<sh7042_device> m_cpu;
required_device<sh_intc_device> m_intc;
int m_port_base, m_port_mask, m_port_shift;
int m_intc_vector;
bool m_is_hs;
enum {
T_SOFT = 1<<0,
@ -95,6 +88,37 @@ protected:
int get_channel_index(int count);
};
DECLARE_DEVICE_TYPE(SH_ADC, sh_adc_device)
class sh_adc_ms_device : public sh_adc_device {
public:
sh_adc_ms_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
template<typename T, typename U> sh_adc_ms_device(const machine_config &mconfig, const char *tag, device_t *owner,
T &&cpu, U &&intc, int port_base, int vect) :
sh_adc_ms_device(mconfig, tag, owner)
{
m_cpu.set_tag(std::forward<T>(cpu));
m_intc.set_tag(std::forward<U>(intc));
m_is_hs = false;
m_port_base = port_base;
m_intc_vector = vect;
}
};
class sh_adc_hs_device : public sh_adc_device {
public:
sh_adc_hs_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
template<typename T, typename U> sh_adc_hs_device(const machine_config &mconfig, const char *tag, device_t *owner,
T &&cpu, U &&intc, int vect) :
sh_adc_hs_device(mconfig, tag, owner)
{
m_cpu.set_tag(std::forward<T>(cpu));
m_intc.set_tag(std::forward<U>(intc));
m_intc_vector = vect;
}
};
DECLARE_DEVICE_TYPE(SH_ADC_MS, sh_adc_ms_device)
DECLARE_DEVICE_TYPE(SH_ADC_HS, sh_adc_hs_device)
#endif // MAME_CPU_SH_SH_ADC_H

View File

@ -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);
}

View File

@ -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

View File

@ -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)));
}
}

View File

@ -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);
}

View File

@ -2,49 +2,78 @@
// copyright-holders:Olivier Galibert
/***************************************************************************
sh_dma.h
sh_dmac.h
SH DMA controller
***************************************************************************/
#ifndef MAME_CPU_SH_SH_DMA_H
#define MAME_CPU_SH_SH_DMA_H
#ifndef MAME_CPU_SH_SH_DMAC_H
#define MAME_CPU_SH_SH_DMAC_H
#pragma once
// To generalize eventually
class sh7042_device;
class sh_intc_device;
class sh_dma_device : public device_t {
class sh_dmac_device : public device_t {
public:
sh_dma_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
sh_dmac_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
template <typename T> sh_dma_device(const machine_config &mconfig, const char *tag, device_t *owner, T &&cpu)
: sh_dma_device(mconfig, tag, owner)
template <typename T> sh_dmac_device(const machine_config &mconfig, const char *tag, device_t *owner, T &&cpu)
: sh_dmac_device(mconfig, tag, owner)
{
set_info(cpu);
}
template<typename T> void set_info(T &&cpu) { m_cpu.set_tag(std::forward<T>(cpu)); }
u16 addr_r(offs_t offset);
u8 dmasr_r();
u8 dmar_r();
void dmasr_w(u8 data);
void dmar_w(u8 data);
u16 dmaor_r();
void dmaor_w(offs_t, u16 data, u16 mem_mask);
protected:
required_device<sh7042_device> m_cpu;
uint16_t m_addr[8];
uint8_t m_dmasr, m_dmar;
u16 m_dmaor;
virtual void device_start() override;
virtual void device_reset() override;
};
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 <typename T, typename U> sh_dmac_channel_device(const machine_config &mconfig, const char *tag, device_t *owner, T &&cpu, U &&intc)
: sh_dmac_channel_device(mconfig, tag, owner)
{
set_info(cpu, intc);
}
template<typename T, typename U> void set_info(T &&cpu, U &&intc) { m_cpu.set_tag(std::forward<T>(cpu)); m_intc.set_tag(std::forward<U>(intc)); }
u32 sar_r();
void sar_w(offs_t, u32 data, u32 mem_mask);
u32 dar_r();
void dar_w(offs_t, u32 data, u32 mem_mask);
u32 dmatcr_r();
void dmatcr_w(offs_t, u32 data, u32 mem_mask);
u32 chcr_r();
void chcr_w(offs_t, u32 data, u32 mem_mask);
protected:
required_device<sh7042_device> m_cpu;
required_device<sh_intc_device> m_intc;
u32 m_sar, m_dar, m_dmatcr, m_chcr;
virtual void device_start() override;
virtual void device_reset() override;
};
DECLARE_DEVICE_TYPE(SH_DMAC, sh_dmac_device)
DECLARE_DEVICE_TYPE(SH_DMAC_CHANNEL, sh_dmac_channel_device)
#endif

View File

@ -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()

View File

@ -24,7 +24,7 @@ public:
m_cpu.set_tag(std::forward<T>(cpu));
}
int interrupt_taken(int vector);
void interrupt_taken(int irqline, int vector);
void internal_interrupt(int vector);
void set_input(int inputnum, int state);
@ -38,14 +38,19 @@ public:
protected:
static const u8 pribit[256];
std::array<u32, 8> m_pending;
std::array<u16, 8> m_ipr;
u16 m_isr, m_icr;
u8 m_lines;
required_device<sh7042_device> m_cpu;
virtual void device_start() override;
virtual void device_reset() override;
void update_irq();
};
DECLARE_DEVICE_TYPE(SH_INTC, sh_intc_device)

View File

@ -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);
}
}

182
src/devices/cpu/sh/sh_mtu.h Normal file
View File

@ -0,0 +1,182 @@
// license:BSD-3-Clause
// copyright-holders:Olivier Galibert
/***************************************************************************
sh_mtu.h
SH Multifunction timer pulse unit
***************************************************************************/
#ifndef MAME_CPU_SH_SH_MTU_H
#define MAME_CPU_SH_SH_MTU_H
#pragma once
// To generalize eventually
class sh7042_device;
class sh_intc_device;
class sh_mtu_channel_device : public device_t {
public:
enum {
CHAIN,
INPUT_A,
INPUT_B,
INPUT_C,
INPUT_D,
DIV_1,
DIV_2,
DIV_4,
DIV_8,
DIV_16,
DIV_32,
DIV_64,
DIV_128,
DIV_256,
DIV_512,
DIV_1024,
DIV_2048,
DIV_4096
};
enum {
TGR_CLEAR_NONE = -1,
TGR_CLEAR_EXT = -2
};
enum {
IRQ_A = 0x01,
IRQ_B = 0x02,
IRQ_C = 0x04,
IRQ_D = 0x08,
IRQ_V = 0x10,
IRQ_U = 0x20,
IRQ_E = 0x80
};
sh_mtu_channel_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
template <typename T, typename U> sh_mtu_channel_device(const machine_config &mconfig, const char *tag, device_t *owner, T &&cpu, int tgr_count, int tier_mask, U &&intc, int irq_base,
int t0, int t1, int t2, int t3, int t4, int t5, int t6, int t7)
: sh_mtu_channel_device(mconfig, tag, owner)
{
set_info(cpu, intc);
m_tgr_count = tgr_count;
m_tbr_count = 0;
m_tier_mask = tier_mask;
m_interrupt[0] = irq_base;
m_interrupt[1] = irq_base + 1;
m_interrupt[2] = tier_mask & 0x04 ? -1 : irq_base + 2;
m_interrupt[3] = tier_mask & 0x08 ? -1 : irq_base + 3;
m_interrupt[4] = irq_base + 4;
m_interrupt[5] = tier_mask & 0x20 ? -1 : irq_base + 5;
m_count_types[0] = t0;
m_count_types[1] = t1;
m_count_types[2] = t2;
m_count_types[3] = t3;
m_count_types[4] = t4;
m_count_types[5] = t5;
m_count_types[6] = t6;
m_count_types[7] = t7;
}
template<typename T, typename U> void set_info(T &&cpu, U &&intc) { m_cpu.set_tag(std::forward<T>(cpu)); m_intc.set_tag(std::forward<U>(intc)); }
template<typename T> void set_chain(T &&chain) { m_chained_timer.set_tag(std::forward<T>(chain)); }
u8 tcr_r();
void tcr_w(u8 data);
u8 tmdr_r();
void tmdr_w(u8 data);
u8 tior_r();
void tior_w(u8 data);
u8 tier_r();
void tier_w(u8 data);
u8 tsr_r();
void tsr_w(u8 data);
u16 tcnt_r();
void tcnt_w(offs_t, u16 data, u16 mem_mask);
u16 tgr_r(offs_t reg);
void tgr_w(offs_t reg, u16 data, u16 mem_mask);
u16 tgrc_r(offs_t reg);
void tgrc_w(offs_t reg, u16 data, u16 mem_mask);
void set_enable(bool enable);
u64 internal_update(u64 current_time);
protected:
required_device<sh7042_device> m_cpu;
required_device<sh_intc_device> m_intc;
optional_device<sh_mtu_channel_device> m_chained_timer;
int m_interrupt[6];
u8 m_tier_mask;
int m_tgr_count, m_tbr_count;
int m_tgr_clearing;
u8 m_tcr, m_tmdr, m_tior, m_tier, m_tsr;
int m_clock_type, m_clock_divider;
u16 m_tcnt;
std::array<u16, 4> m_tgr;
u64 m_last_clock_update, m_event_time;
u32 m_phase, m_counter_cycle;
bool m_counter_incrementing;
bool m_channel_active;
std::array<int, 8> m_count_types;
virtual void device_start() override;
virtual void device_reset() override;
void update_counter(u64 cur_time = 0);
void recalc_event(u64 cur_time = 0);
};
class sh_mtu_device : public device_t {
public:
sh_mtu_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
template <typename T> sh_mtu_device(const machine_config &mconfig, const char *tag, device_t *owner, T &&cpu, int timer_count)
: sh_mtu_device(mconfig, tag, owner)
{
set_info(cpu);
m_timer_count = timer_count;
}
template<typename T> void set_info(T &&cpu) { m_cpu.set_tag(std::forward<T>(cpu)); }
u8 tstr_r();
void tstr_w(u8 data);
u8 tsyr_r();
void tsyr_w(u8 data);
u8 toer_r();
void toer_w(u8 data);
u8 tocr_r();
void tocr_w(u8 data);
u8 tgcr_r();
void tgcr_w(u8 data);
u16 tcdr_r();
void tcdr_w(offs_t, u16 data, u16 mem_mask);
u16 tddr_r();
void tddr_w(offs_t, u16 data, u16 mem_mask);
u16 tcnts_r();
void tcnts_w(offs_t, u16 data, u16 mem_mask);
u16 tcbr_r();
void tcbr_w(offs_t, u16 data, u16 mem_mask);
protected:
required_device<sh7042_device> m_cpu;
required_device_array<sh_mtu_channel_device, 5> m_timer_channel;
int m_timer_count;
u8 m_tstr, m_tsyr, m_toer, m_tocr, m_tgcr;
u16 m_tcdr, m_tddr, m_tcnts, m_tcbr;
virtual void device_start() override;
virtual void device_reset() override;
};
DECLARE_DEVICE_TYPE(SH_MTU, sh_mtu_device)
DECLARE_DEVICE_TYPE(SH_MTU_CHANNEL, sh_mtu_channel_device)
#endif

View File

@ -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();
}

151
src/devices/cpu/sh/sh_sci.h Normal file
View File

@ -0,0 +1,151 @@
// license:BSD-3-Clause
// copyright-holders:Olivier Galibert
/***************************************************************************
sh_sci.h
SH Serial Communications Interface
***************************************************************************/
#ifndef MAME_CPU_SH_SH_SCI_H
#define MAME_CPU_SH_SH_SCI_H
#pragma once
class sh7042_device;
class sh_intc_device;
class sh_sci_device : public device_t {
public:
sh_sci_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
template<typename T, typename U> sh_sci_device(const machine_config &mconfig, const char *tag, device_t *owner, int id, T &&cpu, U &&intc, int eri, int rxi, int txi, int tei)
: sh_sci_device(mconfig, tag, owner, 0)
{
m_cpu.set_tag(std::forward<T>(cpu));
m_intc.set_tag(std::forward<U>(intc));
m_id = id;
m_eri_int = eri;
m_rxi_int = rxi;
m_txi_int = txi;
m_tei_int = tei;
}
void do_set_external_clock_period(const attotime &_period);
void smr_w(u8 data);
u8 smr_r();
void brr_w(u8 data);
u8 brr_r();
void scr_w(u8 data);
u8 scr_r();
void tdr_w(u8 data);
u8 tdr_r();
void ssr_w(u8 data);
u8 ssr_r();
u8 rdr_r();
void scmr_w(u8 data);
u8 scmr_r();
void do_rx_w(int state);
void do_clk_w(int state);
u64 internal_update(u64 current_time);
protected:
enum {
ST_IDLE, ST_START, ST_BIT, ST_PARITY, ST_STOP, ST_LAST_TICK
};
static const char *const state_names[];
enum {
CLK_TX = 1,
CLK_RX = 2
};
enum {
INTERNAL_ASYNC,
INTERNAL_ASYNC_OUT,
EXTERNAL_ASYNC,
EXTERNAL_RATE_ASYNC,
INTERNAL_SYNC_OUT,
EXTERNAL_SYNC,
EXTERNAL_RATE_SYNC
};
enum {
SMR_CA = 0x80,
SMR_CHR = 0x40,
SMR_PE = 0x20,
SMR_OE = 0x10,
SMR_STOP = 0x08,
SMR_MP = 0x04,
SMR_CKS = 0x03,
SCR_TIE = 0x80,
SCR_RIE = 0x40,
SCR_TE = 0x20,
SCR_RE = 0x10,
SCR_MPIE = 0x08,
SCR_TEIE = 0x04,
SCR_CKE = 0x03,
SCR_CKE1 = 0x02,
SCR_CKE0 = 0x01,
SSR_TDRE = 0x80,
SSR_RDRF = 0x40,
SSR_ORER = 0x20,
SSR_FER = 0x10,
SSR_PER = 0x08,
SSR_TEND = 0x04,
SSR_MPB = 0x02,
SSR_MPBT = 0x01
};
required_device<sh7042_device> m_cpu;
required_device<sh_intc_device> m_intc;
attotime m_external_clock_period;
double m_external_to_internal_ratio, m_internal_to_external_ratio;
int m_id, m_eri_int, m_rxi_int, m_txi_int, m_tei_int;
int m_tx_state, m_rx_state, m_tx_bit, m_rx_bit, m_clock_state, m_tx_parity, m_rx_parity, m_tx_clock_counter, m_rx_clock_counter;
u32 m_clock_mode;
bool m_ext_clock_value, m_rx_value;
u8 m_rdr, m_tdr, m_smr, m_scr, m_ssr, m_brr, m_rsr, m_tsr;
u64 m_clock_event, m_clock_step, m_divider;
std::string m_last_clock_message;
void device_start() override;
void device_reset() override;
TIMER_CALLBACK_MEMBER(sync_tick);
void clock_start(int mode);
void clock_stop(int mode);
void clock_update();
void tx_start();
void tx_async_tick();
void tx_async_step();
void tx_sync_tick();
void tx_sync_step();
void rx_start();
void rx_done();
void rx_async_tick();
void rx_async_step();
void rx_sync_tick();
void rx_sync_step();
bool is_sync_start() const;
bool has_recv_error() const;
};
DECLARE_DEVICE_TYPE(SH_SCI, sh_sci_device)
#endif // MAME_CPU_SH_SH_SCI_H

View File

@ -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<<i)))
m_tx[i+3](1);
}
void sci4_device::tx_set(int chan, int state)
{
if(chan < 3)
m_tx[chan](state);
else
for(u32 i=0; i != 4; i++)
if((m_targets & (1<<i)))
m_tx[i+3](state);
}
void sci4_device::fifo_w(int chan, u8 data)
{
if(m_tdr_full[chan] && (m_enable[chan] & 4)) {
m_status[chan] = 6;
m_irq[chan](1);
} else {
m_tdr[chan] = data;
m_tdr_full[chan] = 1;
if(m_status[chan] == 2) {
m_status[chan] = 0;
m_irq[chan](0);
}
if(!m_tx_active[chan] && (m_enable[chan] & 2))
tx_start(chan);
}
}
u8 sci4_device::fifo_r(int chan)
{
m_rdr_full[chan] = 0;
if(m_status[chan] == 4) {
m_status[chan] = 0;
m_irq[chan](0);
}
return m_rdr[chan];
}
void sci4_device::rx_changed(int chan)
{
if(!m_rx_active[chan] && !m_cur_rx[chan] && (m_enable[chan] & 1)) {
m_rx_active[chan] = 1;
m_rx_step[chan] = 0;
m_rsr[chan] = 0;
wait(1, 0, chan);
} else if(m_rx_active[chan]) {
if(m_rx_step[chan] == 0) {
// Start bit gone before half-time
m_rx_active[chan] = 0;
m_rx_timer[chan]->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")

View File

@ -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<int Sci> void rx_w(int state) { do_rx_w(Sci, state); }
template<int Sci> 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<int irq> 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<u8, 7> m_rx;
std::array<u8, 4> m_enable, m_status, m_datamode, m_div, m_cur_rx;
std::array<u8, 4> m_tdr, m_tsr, m_tdr_full, m_tx_step, m_tx_active;
std::array<u8, 4> 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

View File

@ -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;

View File

@ -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;

View File

@ -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;

54
src/mame/layout/mu128.lay Normal file
View File

@ -0,0 +1,54 @@
<?xml version="1.0"?>
<!--
license:CC0-1.0
authors:hap
-->
<mamelayout version="2">
<!-- define elements -->
<element name="led" defstate="0">
<disk state="0"><color red="0.07" green="0.1" blue="0.02" /></disk>
<disk state="1"><color red="0.7" green="1.0" blue="0.2" /></disk>
</element>
<element name="ledr" defstate="0">
<rect state="0"><color red="0.07" green="0.1" blue="0.02" /></rect>
<rect state="1"><color red="0.7" green="1.0" blue="0.2" /></rect>
</element>
<element name="lcda" defstate="0">
<rect>
<color state="0" red="0" green="0" blue="0" />
<color state="7" red="0.95" green="0.95" blue="0.95" />
</rect>
</element>
<element name="lcdm"><rect><color red="0.7" green="1.0" blue="0.2" /></rect></element>
<!-- build screen -->
<view name="Internal Layout">
<bounds x="0" y="0" width="121" height="30.21" />
<screen index="0"><bounds x="0" y="0" width="100" height="30.21" /></screen>
<element name="contrast" ref="lcda" blend="add"><bounds x="0" y="0" width="100" height="30.21" /></element>
<element ref="lcdm" blend="multiply"><bounds x="0" y="0" width="100" height="30.21" /></element>
<element name="LED0" ref="led"><bounds x="104" y="2" width="4" height="4" /></element>
<element name="LED1" ref="led"><bounds x="113" y="2" width="4" height="4" /></element>
<element name="LED2" ref="led"><bounds x="104" y="10" width="4" height="4" /></element>
<element name="LED3" ref="led"><bounds x="113" y="10" width="4" height="4" /></element>
<element name="LED4" ref="led"><bounds x="104" y="18" width="4" height="4" /></element>
<element name="LED5" ref="led"><bounds x="113" y="18" width="4" height="4" /></element>
// mu-plg1-plg2-plg3
<element name="LED6" ref="ledr"><bounds x="103" y="26" width="3" height="1" /></element>
<element name="LED7" ref="ledr"><bounds x="107" y="26" width="3" height="1" /></element>
<element name="LED8" ref="ledr"><bounds x="111" y="26" width="3" height="1" /></element>
<element name="LED9" ref="ledr"><bounds x="115" y="26" width="3" height="1" /></element>
</view>
</mamelayout>

View File

@ -0,0 +1,58 @@
<?xml version="1.0"?>
<!--
license:CC0-1.0
authors:hap
-->
<mamelayout version="2">
<!-- define elements -->
<element name="led" defstate="0">
<disk state="0"><color red="0.07" green="0.1" blue="0.02" /></disk>
<disk state="1"><color red="0.7" green="1.0" blue="0.2" /></disk>
</element>
<element name="ledred" defstate="0">
<disk state="0"><color red="0.1" green="0" blue="0.02" /></disk>
<disk state="1"><color red="1.0" green="0" blue="0.2" /></disk>
</element>
<element name="ledr" defstate="0">
<rect state="0"><color red="0.07" green="0.1" blue="0.02" /></rect>
<rect state="1"><color red="0.7" green="1.0" blue="0.2" /></rect>
</element>
<element name="lcda" defstate="0">
<rect>
<color state="0" red="0" green="0" blue="0" />
<color state="7" red="0.95" green="0.95" blue="0.95" />
</rect>
</element>
<element name="lcdm"><rect><color red="0.7" green="1.0" blue="0.2" /></rect></element>
<!-- build screen -->
<view name="Internal Layout">
<bounds x="0" y="0" width="121" height="30.21" />
<screen index="0"><bounds x="0" y="0" width="100" height="30.21" /></screen>
<element name="contrast" ref="lcda" blend="add"><bounds x="0" y="0" width="100" height="30.21" /></element>
<element ref="lcdm" blend="multiply"><bounds x="0" y="0" width="100" height="30.21" /></element>
<element name="LED0" ref="led"><bounds x="104" y="2" width="4" height="4" /></element>
<element name="LED1" ref="led"><bounds x="113" y="2" width="4" height="4" /></element>
<element name="LED2" ref="led"><bounds x="104" y="10" width="4" height="4" /></element>
<element name="LED3" ref="led"><bounds x="113" y="10" width="4" height="4" /></element>
<element name="LED4" ref="ledred"><bounds x="104" y="18" width="4" height="4" /></element>
<element name="LED5" ref="led"><bounds x="113" y="18" width="4" height="4" /></element>
<element name="LED6" ref="ledr"><bounds x="103" y="26" width="3" height="1" /></element>
<element name="LED7" ref="ledr"><bounds x="107" y="26" width="3" height="1" /></element>
<element name="LED8" ref="ledr"><bounds x="111" y="26" width="3" height="1" /></element>
<element name="LED9" ref="ledr"><bounds x="115" y="26" width="3" height="1" /></element>
</view>
</mamelayout>

42
src/mame/layout/mu50.lay Normal file
View File

@ -0,0 +1,42 @@
<?xml version="1.0"?>
<!--
license:CC0-1.0
authors:hap
-->
<mamelayout version="2">
<!-- define elements -->
<element name="led" defstate="0">
<disk state="0"><color red="0.07" green="0.1" blue="0.02" /></disk>
<disk state="1"><color red="0.7" green="1.0" blue="0.2" /></disk>
</element>
<element name="lcda" defstate="0">
<rect>
<color state="0" red="0" green="0" blue="0" />
<color state="7" red="0.95" green="0.95" blue="0.95" />
</rect>
</element>
<element name="lcdm"><rect><color red="0.7" green="1.0" blue="0.2" /></rect></element>
<!-- build screen -->
<view name="Internal Layout">
<bounds x="0" y="0" width="121" height="30.21" />
<screen index="0"><bounds x="0" y="0" width="100" height="30.21" /></screen>
<element name="contrast" ref="lcda" blend="add"><bounds x="0" y="0" width="100" height="30.21" /></element>
<element ref="lcdm" blend="multiply"><bounds x="0" y="0" width="100" height="30.21" /></element>
<element name="LED0" ref="led"><bounds x="104" y="2" width="4" height="4" /></element>
<element name="LED1" ref="led"><bounds x="113" y="2" width="4" height="4" /></element>
<element name="LED2" ref="led"><bounds x="104" y="13" width="4" height="4" /></element>
<element name="LED3" ref="led"><bounds x="113" y="13" width="4" height="4" /></element>
<element name="LED4" ref="led"><bounds x="104" y="24" width="4" height="4" /></element>
</view>
</mamelayout>

View File

@ -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

View File

@ -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;
}

View File

@ -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<hd44780_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);
};

View File

@ -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<h8s2655_device> m_maincpu;
required_device<swp30_device> m_swp30;
required_device<mulcd_device> m_lcd;
optional_device<mulcd_device> m_lcd;
required_device<plg1x0_connector> m_ext1;
optional_device<plg1x0_connector> 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 )

View File

@ -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<i8251_device> m_sci;
required_shared_ptr<u32> 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) \

View File

@ -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<sh7043a_device> m_maincpu;
required_device<nvram_device> m_nvram;
required_device<swp30_device> m_swp30m;
required_device<sci4_device> m_sci;
required_device<mulcd_device> m_lcd;
required_shared_ptr<u32> m_ram;
required_device_array<plg1x0_connector, 3> 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<swp30_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 )

View File

@ -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) \

View File

@ -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<sh7042_device> m_maincpu;
required_device<swx00_sound_device> m_swx00;
required_device<hd44780_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 )