summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/nec/v5x.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/nec/v5x.cpp')
-rw-r--r--src/devices/cpu/nec/v5x.cpp813
1 files changed, 600 insertions, 213 deletions
diff --git a/src/devices/cpu/nec/v5x.cpp b/src/devices/cpu/nec/v5x.cpp
index aecc62128c8..50b2bd7da79 100644
--- a/src/devices/cpu/nec/v5x.cpp
+++ b/src/devices/cpu/nec/v5x.cpp
@@ -6,11 +6,12 @@
* CPU cores within each device are as follows:
*
* Device CPU
+ * V40 (µPD70208) V20 (µPD70108)
* V50 (µPD70216) V30 (µPD70116)
* V53 (µPD70236) V33 (µPD70136)
* V53A (µPD70236A) V33A (µPD70136A)
*
- * The peripherals are nearly identical between all three devices:
+ * The peripherals are nearly identical between all four devices:
*
* Name Description Device
* TCU Timer/Counter Unit µPD71054/i8254 subset
@@ -29,93 +30,131 @@
#include "emu.h"
#include "v5x.h"
-#include "necpriv.h"
+#include "necpriv.ipp"
#define VERBOSE 0
#include "logmacro.h"
+DEFINE_DEVICE_TYPE(V40, v40_device, "v40", "NEC V40")
DEFINE_DEVICE_TYPE(V50, v50_device, "v50", "NEC V50")
DEFINE_DEVICE_TYPE(V53, v53_device, "v53", "NEC V53")
DEFINE_DEVICE_TYPE(V53A, v53a_device, "v53a", "NEC V53A")
-WRITE8_MEMBER(v5x_base_device::SULA_w)
+u8 device_v5x_interface::SULA_r()
{
- LOG("SULA_w %02x\n", data);
+ return m_SULA;
+}
+
+void device_v5x_interface::SULA_w(u8 data)
+{
+ if (VERBOSE)
+ device().logerror("SULA_w %02x\n", data);
m_SULA = data;
install_peripheral_io();
}
-WRITE8_MEMBER(v5x_base_device::TULA_w)
+u8 device_v5x_interface::TULA_r()
+{
+ return m_TULA;
+}
+
+void device_v5x_interface::TULA_w(u8 data)
{
- LOG("TULA_w %02x\n", data);
+ if (VERBOSE)
+ device().logerror("TULA_w %02x\n", data);
m_TULA = data;
install_peripheral_io();
}
-WRITE8_MEMBER(v5x_base_device::IULA_w)
+u8 device_v5x_interface::IULA_r()
{
- LOG("IULA_w %02x\n", data);
+ return m_IULA;
+}
+
+void device_v5x_interface::IULA_w(u8 data)
+{
+ if (VERBOSE)
+ device().logerror("IULA_w %02x\n", data);
m_IULA = data;
install_peripheral_io();
}
-WRITE8_MEMBER(v5x_base_device::DULA_w)
+u8 device_v5x_interface::DULA_r()
+{
+ return m_DULA;
+}
+
+void device_v5x_interface::DULA_w(u8 data)
{
- LOG("DULA_w %02x\n", data);
+ if (VERBOSE)
+ device().logerror("DULA_w %02x\n", data);
m_DULA = data;
install_peripheral_io();
}
-WRITE8_MEMBER(v5x_base_device::OPHA_w)
+u8 device_v5x_interface::OPHA_r()
+{
+ return m_OPHA;
+}
+
+void device_v5x_interface::OPHA_w(u8 data)
{
- LOG("OPHA_w %02x\n", data);
+ if (VERBOSE)
+ {
+ device().logerror("OPHA_w %02x\n", data);
+ if (data == 0xff)
+ device().logerror("OPHA is mapped in system IO area!\n", data);
+ }
m_OPHA = data;
- install_peripheral_io();
}
-WRITE8_MEMBER(v5x_base_device::OPSEL_w)
+u8 device_v5x_interface::OPSEL_r()
{
- LOG("OPSEL_w %02x\n", data);
- m_OPSEL = data;
+ return m_OPSEL;
+}
+
+void device_v5x_interface::OPSEL_w(u8 data)
+{
+ if (VERBOSE)
+ device().logerror("OPSEL_w %02x\n", data);
+ m_OPSEL = data & 0x0f;
install_peripheral_io();
}
-WRITE8_MEMBER(v53_device::SCTL_w)
+u8 device_v5x_interface::TCKS_r()
{
- // bit 7: unused
- // bit 6: unused
- // bit 5: unused
- // bit 4: SCU input clock source
- // bit 3: uPD71037 DMA mode - Carry A20
- // bit 2: uPD71037 DMA mode - Carry A16
- // bit 1: uPD71037 DMA mode enable (otherwise in uPD71071 mode)
- // bit 0: Onboard pripheral I/O maps to 8-bit boundaries? (otherwise 16-bit)
+ return m_TCKS;
+}
- LOG("SCTL_w %02x\n", data);
- m_SCTL = data;
- install_peripheral_io();
+void device_v5x_interface::TCKS_w(u8 data)
+{
+ m_TCKS = data;
+ tcu_clock_update();
}
-WRITE8_MEMBER(v50_device::OPCN_w)
+void device_v5x_interface::interface_clock_changed(bool sync_on_new_clock_domain)
{
- // bit 7: unused
- // bit 6: unused
- // bit 5: unused
- // bit 4: unused
- // bit 3: IRSW
- // bit 2: IRSW
- // bit 1: PF
- // bit 0: PF
+ tcu_clock_update();
+}
- LOG("OPCN_w %02x\n", data);
- m_OPCN = data;
- install_peripheral_io();
+void device_v5x_interface::tcu_clock_update()
+{
+ for (int i = 0; i < 3; i++)
+ m_tcu->set_clockin(i, BIT(m_TCKS, i + 2) ? m_tclk : device().clock() / double(4 << (m_TCKS & 3)));
}
-void v5x_base_device::device_reset()
+void device_v5x_interface::tclk_w(int state)
{
- v33_base_device::device_reset();
+ if (BIT(m_TCKS, 2))
+ m_tcu->write_clk0(state);
+ if (BIT(m_TCKS, 3))
+ m_tcu->write_clk1(state);
+ if (BIT(m_TCKS, 4))
+ m_tcu->write_clk2(state);
+}
+void device_v5x_interface::interface_pre_reset()
+{
m_OPSEL= 0x00;
// peripheral addresses
@@ -124,195 +163,587 @@ void v5x_base_device::device_reset()
m_IULA = 0x00;
m_DULA = 0x00;
m_OPHA = 0x00;
+
+ m_TCKS = 0x00;
+ tcu_clock_update();
}
-void v50_device::device_reset()
+void device_v5x_interface::interface_post_start()
{
- v5x_base_device::device_reset();
+ device().save_item(NAME(m_OPSEL));
+ device().save_item(NAME(m_SULA));
+ device().save_item(NAME(m_TULA));
+ device().save_item(NAME(m_IULA));
+ device().save_item(NAME(m_DULA));
+ device().save_item(NAME(m_OPHA));
+ device().save_item(NAME(m_TCKS));
+}
- m_OPCN = 0;
+void device_v5x_interface::interface_post_load()
+{
+ install_peripheral_io();
}
-void v53_device::device_reset()
+// the external interface provides no external access to the usual IRQ line of the V33, everything goes through the interrupt controller
+void device_v5x_interface::v5x_set_input(int irqline, int state)
{
- v5x_base_device::device_reset();
+ switch (irqline)
+ {
+ case INPUT_LINE_IRQ0: m_icu->ir0_w(state); break;
+ case INPUT_LINE_IRQ1: m_icu->ir1_w(state); break;
+ case INPUT_LINE_IRQ2: m_icu->ir2_w(state); break;
+ case INPUT_LINE_IRQ3: m_icu->ir3_w(state); break;
+ case INPUT_LINE_IRQ4: m_icu->ir4_w(state); break;
+ case INPUT_LINE_IRQ5: m_icu->ir5_w(state); break;
+ case INPUT_LINE_IRQ6: m_icu->ir6_w(state); break;
+ case INPUT_LINE_IRQ7: m_icu->ir7_w(state); break;
- m_SCTL = 0x00;
+ case INPUT_LINE_NMI: downcast<nec_common_device &>(device()).set_nmi_line(state); break;
+ case NEC_INPUT_LINE_POLL: downcast<nec_common_device &>(device()).set_poll_line(state); break;
+ }
}
-void v5x_base_device::device_start()
+// for hooking the interrupt controller output up to the core
+void device_v5x_interface::internal_irq_w(int state)
{
- v33_base_device::device_start();
+ downcast<nec_common_device &>(device()).set_int_line(state);
+}
- set_irq_acknowledge_callback(device_irq_acknowledge_delegate(FUNC(v5x_icu_device::inta_cb), m_icu.target()));
+void device_v5x_interface::v5x_add_mconfig(machine_config &config)
+{
+ PIT8254(config, m_tcu);
+
+ V5X_DMAU(config, m_dmau, 4000000);
+
+ V5X_ICU(config, m_icu, 0);
+ m_icu->out_int_callback().set(FUNC(device_v5x_interface::internal_irq_w));
+ m_icu->in_sp_callback().set_constant(1);
+ m_icu->read_slave_ack_callback().set(FUNC(device_v5x_interface::get_pic_ack));
- save_item(NAME(m_OPSEL));
- save_item(NAME(m_SULA));
- save_item(NAME(m_TULA));
- save_item(NAME(m_IULA));
- save_item(NAME(m_DULA));
- save_item(NAME(m_OPHA));
+ V5X_SCU(config, m_scu, 0);
}
-void v50_device::device_start()
+void device_v5x_interface::remappable_io_map(address_map &map)
{
- v5x_base_device::device_start();
+ map(0, INTERNAL_IO_ADDR_MASK).rw(FUNC(device_v5x_interface::temp_io_byte_r), FUNC(device_v5x_interface::temp_io_byte_w));
+}
- save_item(NAME(m_OPCN));
+device_v5x_interface::device_v5x_interface(const machine_config &mconfig, nec_common_device &device, bool is_16bit)
+ : device_interface(device, "v5x")
+ , m_tcu(device, "tcu")
+ , m_dmau(device, "dmau")
+ , m_icu(device, "icu")
+ , m_scu(device, "scu")
+ , m_internal_io_config("internal_io", ENDIANNESS_LITTLE, is_16bit ? 16 : 8, INTERNAL_IO_ADDR_WIDTH, 0, address_map_constructor(FUNC(device_v5x_interface::remappable_io_map), this))
+ , m_tclk(0.0)
+ , m_OPSEL(0)
+ , m_SULA(0)
+ , m_TULA(0)
+ , m_IULA(0)
+ , m_DULA(0)
+ , m_OPHA(0)
+ , m_TCKS(0)
+{
}
-void v53_device::device_start()
+
+u8 v50_base_device::io_read_byte(offs_t a)
{
- v5x_base_device::device_start();
+ if (check_OPHA(a))
+ return device_v5x_interface::internal_io_read_byte(a);
+ else
+ return nec_common_device::io_read_byte(a);
+}
- save_item(NAME(m_SCTL));
+u16 v50_base_device::io_read_word(offs_t a)
+{
+ if (check_OPHA(a))
+ {
+ if ((a & INTERNAL_IO_ADDR_MASK) == INTERNAL_IO_ADDR_MASK)
+ {
+ return (device_v5x_interface::internal_io_read_byte(a) & 0x00ff)
+ | ((nec_common_device::io_read_byte(a + 1) << 8) & 0xff00);
+ }
+ else
+ return device_v5x_interface::internal_io_read_word(a);
+ }
+ else
+ return nec_common_device::io_read_word(a);
}
-void v5x_base_device::device_post_load()
+void v50_base_device::io_write_byte(offs_t a, u8 v)
{
- install_peripheral_io();
+ if (check_OPHA(a))
+ {
+ device_v5x_interface::internal_io_write_byte(a, v);
+ }
+ else
+ nec_common_device::io_write_byte(a, v);
}
-void v53_device::install_peripheral_io()
+void v50_base_device::io_write_word(offs_t a, u16 v)
+{
+ if (check_OPHA(a))
+ {
+ if ((a & INTERNAL_IO_ADDR_MASK) == INTERNAL_IO_ADDR_MASK)
+ {
+ device_v5x_interface::internal_io_write_byte(a, v & 0xff);
+ nec_common_device::io_write_byte(a + 1, (v >> 8) & 0xff);
+ }
+ else
+ {
+ device_v5x_interface::internal_io_write_word(a, v);
+ }
+ }
+ else
+ nec_common_device::io_write_word(a, v);
+}
+
+
+u8 v50_base_device::OPCN_r()
+{
+ return m_OPCN;
+}
+
+void v50_base_device::OPCN_w(u8 data)
+{
+ // bit 7: unused
+ // bit 6: unused
+ // bit 5: unused
+ // bit 4: unused
+ // bit 3: IRSW (INT2 source select)
+ // bit 2: IRSW (INT1 source select)
+ // bit 1: PF (DMA3/SCU I/O select)
+ // bit 0: PF (INTAK/SRDY/TOUT1 output select)
+
+ LOG("OPCN_w %02x\n", data);
+ m_OPCN = data & 0x0f;
+
+ m_tout1_callback((data & 0x03) == 0x03 ? m_tout1 : 1);
+ m_icu->ir1_w(BIT(data, 2) ? m_sint : m_intp1);
+ m_icu->ir2_w(BIT(data, 3) ? m_tout1 : m_intp2);
+}
+
+void v50_base_device::tout1_w(int state)
+{
+ m_tout1 = state;
+ if ((m_OPCN & 0x03) == 0x01)
+ m_tout1_callback(state);
+ if (BIT(m_OPCN, 3))
+ m_icu->ir2_w(state);
+}
+
+void v50_base_device::sint_w(int state)
+{
+ m_sint = state;
+ if (BIT(m_OPCN, 2))
+ m_icu->ir1_w(state);
+}
+
+void v50_base_device::device_reset()
+{
+ nec_common_device::device_reset();
+
+ m_OPCN = 0;
+ m_tout1_callback(1);
+}
+
+void v50_base_device::device_start()
+{
+ nec_common_device::device_start();
+ m_internal_io = &space(AS_INTERNAL_IO);
+
+ set_irq_acknowledge_callback(*m_icu, FUNC(v5x_icu_device::inta_cb));
+
+ m_scu->write_cts(0);
+
+ save_item(NAME(m_OPCN));
+ save_item(NAME(m_tout1));
+ save_item(NAME(m_sint));
+ save_item(NAME(m_intp1));
+ save_item(NAME(m_intp2));
+}
+
+void v40_device::install_peripheral_io()
{
// unmap everything in I/O space up to the fixed position registers (we avoid overwriting them, it isn't a valid config)
- space(AS_IO).unmap_readwrite(0x1000, 0xfeff);
+ space(AS_INTERNAL_IO).unmap_readwrite(0, INTERNAL_IO_ADDR_MASK);
+ space(AS_INTERNAL_IO).install_readwrite_handler(0, INTERNAL_IO_ADDR_MASK,
+ read8sm_delegate(*this, FUNC(v40_device::temp_io_byte_r)),
+ write8sm_delegate(*this, FUNC(v40_device::temp_io_byte_w)));
- // IOAG determines if the handlers used 8-bit or 16-bit access
- // the hng64.c games first set everything up in 8-bit mode, then
- // do the procedure again in 16-bit mode before using them?!
+ if (m_OPSEL & OPSEL_DS)
+ {
+ u16 const base = m_DULA & INTERNAL_IO_ADDR_MASK;
+
+ space(AS_INTERNAL_IO).unmap_readwrite(base & ~0x0f, base | 0x0f);
+ space(AS_INTERNAL_IO).install_readwrite_handler(base & ~0x0f, base | 0x0f,
+ read8sm_delegate(*m_dmau, FUNC(v5x_dmau_device::read)),
+ write8sm_delegate(*m_dmau, FUNC(v5x_dmau_device::write)));
+ }
+
+ if (m_OPSEL & OPSEL_IS)
+ {
+ u16 const base = m_IULA & INTERNAL_IO_ADDR_MASK;
- int const IOAG = m_SCTL & 1;
+ space(AS_INTERNAL_IO).unmap_readwrite(base & ~0x01, base | 0x01);
+ space(AS_INTERNAL_IO).install_readwrite_handler(base & ~0x01, base | 0x01,
+ read8sm_delegate(*m_icu, FUNC(v5x_icu_device::read)),
+ write8sm_delegate(*m_icu, FUNC(v5x_icu_device::write)));
+ }
+
+ if (m_OPSEL & OPSEL_TS)
+ {
+ u16 const base = m_TULA & INTERNAL_IO_ADDR_MASK;
+
+ space(AS_INTERNAL_IO).unmap_readwrite(base & ~0x03, base | 0x03);
+ space(AS_INTERNAL_IO).install_readwrite_handler(base & ~0x03, base | 0x03,
+ read8sm_delegate(*m_tcu, FUNC(pit8253_device::read)),
+ write8sm_delegate(*m_tcu, FUNC(pit8253_device::write)));
+ }
+
+ if (m_OPSEL & OPSEL_SS)
+ {
+ u16 const base = m_SULA & INTERNAL_IO_ADDR_MASK;
+
+ space(AS_INTERNAL_IO).unmap_readwrite(base & ~0x03, base | 0x03);
+ space(AS_INTERNAL_IO).install_readwrite_handler(base & ~0x03, base | 0x03,
+ read8sm_delegate(*m_scu, FUNC(v5x_scu_device::read)),
+ write8sm_delegate(*m_scu, FUNC(v5x_scu_device::write)));
+ }
+}
+
+void v50_device::install_peripheral_io()
+{
+ // unmap everything in I/O space up to the fixed position registers (we avoid overwriting them, it isn't a valid config)
+ space(AS_INTERNAL_IO).unmap_readwrite(0, INTERNAL_IO_ADDR_MASK);
+ space(AS_INTERNAL_IO).install_readwrite_handler(0, INTERNAL_IO_ADDR_MASK,
+ read8sm_delegate(*this, FUNC(v50_device::temp_io_byte_r)),
+ write8sm_delegate(*this, FUNC(v50_device::temp_io_byte_w)));
if (m_OPSEL & OPSEL_DS)
{
- u16 const base = ((m_OPHA << 8) | m_DULA) & 0xfffe;
+ u16 const base = m_DULA & INTERNAL_IO_ADDR_MASK;
- if (m_SCTL & 0x02) // uPD71037 mode
- {
- if (IOAG) // 8-bit
- {
- }
- else
- {
- }
- }
- else // uPD71071 mode
- space(AS_IO).install_readwrite_handler(base + 0x00, base + 0x0f,
- read8sm_delegate(FUNC(v5x_dmau_device::read), m_dmau.target()),
- write8sm_delegate(FUNC(v5x_dmau_device::write), m_dmau.target()), 0xffff);
+ space(AS_INTERNAL_IO).unmap_readwrite(base & ~0x0f, base | 0x0f);
+ space(AS_INTERNAL_IO).install_readwrite_handler(base & ~0x0f, base | 0x0f,
+ read8sm_delegate(*m_dmau, FUNC(v5x_dmau_device::read)),
+ write8sm_delegate(*m_dmau, FUNC(v5x_dmau_device::write)), 0xffff);
}
if (m_OPSEL & OPSEL_IS)
{
- u16 const base = ((m_OPHA << 8) | m_IULA) & 0xfffe;
+ u16 const base = m_IULA & INTERNAL_IO_ADDR_MASK;
- if (IOAG) // 8-bit
- space(AS_IO).install_readwrite_handler(base + 0x00, base + 0x01,
- read8sm_delegate(FUNC(v5x_icu_device::read), m_icu.target()),
- write8sm_delegate(FUNC(v5x_icu_device::write), m_icu.target()), 0xffff);
- else
- space(AS_IO).install_readwrite_handler(base + 0x00, base + 0x03,
- read8sm_delegate(FUNC(v5x_icu_device::read), m_icu.target()),
- write8sm_delegate(FUNC(v5x_icu_device::write), m_icu.target()), 0x00ff);
+ space(AS_INTERNAL_IO).unmap_readwrite(base & ~0x03, base | 0x03);
+ space(AS_INTERNAL_IO).install_readwrite_handler(base & ~0x03, base | 0x03,
+ read8sm_delegate(*m_icu, FUNC(v5x_icu_device::read)),
+ write8sm_delegate(*m_icu, FUNC(v5x_icu_device::write)), io_mask(base));
}
if (m_OPSEL & OPSEL_TS)
{
- u16 const base = ((m_OPHA << 8) | m_TULA) & 0xfffe;
+ u16 const base = m_TULA & INTERNAL_IO_ADDR_MASK;
- if (IOAG) // 8-bit
- space(AS_IO).install_readwrite_handler(base + 0x00, base + 0x03,
- read8sm_delegate(FUNC(pit8253_device::read), m_tcu.target()),
- write8sm_delegate(FUNC(pit8253_device::write), m_tcu.target()), 0xffff);
- else
- space(AS_IO).install_readwrite_handler(base + 0x00, base + 0x07,
- read8sm_delegate(FUNC(pit8253_device::read), m_tcu.target()),
- write8sm_delegate(FUNC(pit8253_device::write), m_tcu.target()), 0x00ff);
+ space(AS_INTERNAL_IO).unmap_readwrite(base & ~0x07, base | 0x07);
+ space(AS_INTERNAL_IO).install_readwrite_handler(base & ~0x07, base | 0x07,
+ read8sm_delegate(*m_tcu, FUNC(pit8253_device::read)),
+ write8sm_delegate(*m_tcu, FUNC(pit8253_device::write)), io_mask(base));
}
if (m_OPSEL & OPSEL_SS)
{
- u16 const base = ((m_OPHA << 8) | m_SULA) & 0xfffe;
+ u16 const base = m_SULA & INTERNAL_IO_ADDR_MASK;
- if (IOAG) // 8-bit
- space(AS_IO).install_readwrite_handler(base + 0x00, base + 0x03,
- read8sm_delegate(FUNC(v5x_scu_device::read), m_scu.target()),
- write8sm_delegate(FUNC(v5x_scu_device::write), m_scu.target()), 0xffff);
+ space(AS_INTERNAL_IO).unmap_readwrite(base & ~0x07, base | 0x07);
+ space(AS_INTERNAL_IO).install_readwrite_handler(base & ~0x07, base | 0x07,
+ read8sm_delegate(*m_scu, FUNC(v5x_scu_device::read)),
+ write8sm_delegate(*m_scu, FUNC(v5x_scu_device::write)), io_mask(base));
+ }
+}
+
+void v50_base_device::internal_port_map(address_map &map)
+{
+ map(0xfff0, 0xfff0).rw(FUNC(v50_base_device::TCKS_r), FUNC(v50_base_device::TCKS_w));
+
+ map(0xfff2, 0xfff2).w(FUNC(v50_base_device::RFC_w));
+
+ map(0xfff4, 0xfff4).w(FUNC(v50_base_device::WMB0_w)); // actually WMB on V50
+ map(0xfff5, 0xfff5).w(FUNC(v50_base_device::WCY1_w));
+ map(0xfff6, 0xfff6).w(FUNC(v50_base_device::WCY2_w));
+
+ map(0xfff8, 0xfff8).rw(FUNC(v50_base_device::SULA_r), FUNC(v50_base_device::SULA_w));
+ map(0xfff9, 0xfff9).rw(FUNC(v50_base_device::TULA_r), FUNC(v50_base_device::TULA_w));
+ map(0xfffa, 0xfffa).rw(FUNC(v50_base_device::IULA_r), FUNC(v50_base_device::IULA_w));
+ map(0xfffb, 0xfffb).rw(FUNC(v50_base_device::DULA_r), FUNC(v50_base_device::DULA_w));
+ map(0xfffc, 0xfffc).rw(FUNC(v50_base_device::OPHA_r), FUNC(v50_base_device::OPHA_w));
+ map(0xfffd, 0xfffd).rw(FUNC(v50_base_device::OPSEL_r), FUNC(v50_base_device::OPSEL_w));
+ map(0xfffe, 0xfffe).rw(FUNC(v50_base_device::OPCN_r), FUNC(v50_base_device::OPCN_w));
+}
+
+void v50_base_device::execute_set_input(int irqline, int state)
+{
+ switch (irqline)
+ {
+ case INPUT_LINE_IRQ1:
+ m_intp1 = state;
+ if (BIT(m_OPCN, 2))
+ return;
+ break;
+
+ case INPUT_LINE_IRQ2:
+ m_intp2 = state;
+ if (BIT(m_OPCN, 3))
+ return;
+ break;
+ }
+
+ v5x_set_input(irqline, state);
+}
+
+void v50_base_device::device_add_mconfig(machine_config &config)
+{
+ v5x_add_mconfig(config);
+
+ // Timer 0 is internally connected to INT0
+ m_tcu->out_handler<0>().set(m_icu, FUNC(pic8259_device::ir0_w));
+
+ // Timer 1 is internally connected to RxC/TxC
+ m_tcu->out_handler<1>().set(m_scu, FUNC(v5x_scu_device::write_rxc));
+ m_tcu->out_handler<1>().append(m_scu, FUNC(v5x_scu_device::write_txc));
+ m_tcu->out_handler<1>().append(FUNC(v50_base_device::tout1_w));
+
+ m_scu->sint_handler().set(FUNC(v50_base_device::sint_w));
+}
+
+device_memory_interface::space_config_vector v50_base_device::memory_space_config() const
+{
+ space_config_vector spaces = {
+ std::make_pair(AS_PROGRAM, &m_program_config),
+ std::make_pair(AS_IO, &m_io_config),
+ std::make_pair(AS_INTERNAL_IO, &m_internal_io_config)
+ };
+ return spaces;
+}
+
+v50_base_device::v50_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, bool is_16bit, u8 prefetch_size, u8 prefetch_cycles, u32 chip_type)
+ : nec_common_device(mconfig, type, tag, owner, clock, is_16bit, prefetch_size, prefetch_cycles, chip_type, address_map_constructor(FUNC(v50_base_device::internal_port_map), this))
+ , device_v5x_interface(mconfig, *this, is_16bit)
+ , m_tout1_callback(*this)
+ , m_icu_slave_ack(*this, 0)
+ , m_OPCN(0)
+ , m_tout1(false)
+ , m_intp1(false)
+ , m_intp2(false)
+{
+}
+
+v40_device::v40_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : v50_base_device(mconfig, V40, tag, owner, clock, false, 4, 4, V20_TYPE)
+{
+}
+
+v50_device::v50_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : v50_base_device(mconfig, V50, tag, owner, clock, true, 6, 2, V30_TYPE)
+{
+}
+
+u8 v53_device::io_read_byte(offs_t a)
+{
+ if (check_OPHA(a))
+ return device_v5x_interface::internal_io_read_byte(a);
+ else
+ return nec_common_device::io_read_byte(a);
+}
+
+u16 v53_device::io_read_word(offs_t a)
+{
+ if (check_OPHA(a))
+ {
+ if ((a & INTERNAL_IO_ADDR_MASK) == INTERNAL_IO_ADDR_MASK)
+ {
+ return (device_v5x_interface::internal_io_read_byte(a) & 0x00ff)
+ | ((nec_common_device::io_read_byte(a + 1) << 8) & 0xff00);
+ }
else
- space(AS_IO).install_readwrite_handler(base + 0x00, base + 0x07,
- read8sm_delegate(FUNC(v5x_scu_device::read), m_scu.target()),
- write8sm_delegate(FUNC(v5x_scu_device::write), m_scu.target()), 0x00ff);
+ return device_v5x_interface::internal_io_read_word(a);
}
+ else
+ return nec_common_device::io_read_word(a);
}
-WRITE_LINE_MEMBER(v53_device::hack_w)
+void v53_device::io_write_byte(offs_t a, u8 v)
{
- if (!(m_SCTL & 0x02))
- m_dmau->hack_w(state);
+ if (check_OPHA(a))
+ {
+ device_v5x_interface::internal_io_write_byte(a, v);
+ }
else
- LOG("hack_w not in 71071mode\n");
+ nec_common_device::io_write_byte(a, v);
}
-void v50_device::install_peripheral_io()
+void v53_device::io_write_word(offs_t a, u16 v)
+{
+ if (check_OPHA(a))
+ {
+ if ((a & INTERNAL_IO_ADDR_MASK) == INTERNAL_IO_ADDR_MASK)
+ {
+ device_v5x_interface::internal_io_write_byte(a, v & 0xff);
+ nec_common_device::io_write_byte(a + 1, (v >> 8) & 0xff);
+ }
+ else
+ {
+ device_v5x_interface::internal_io_write_word(a, v);
+ }
+ }
+ else
+ nec_common_device::io_write_word(a, v);
+}
+
+
+u8 v53_device::SCTL_r()
+{
+ return m_SCTL;
+}
+
+void v53_device::SCTL_w(u8 data)
+{
+ // bit 7: unused
+ // bit 6: unused
+ // bit 5: unused
+ // bit 4: SCU input clock source
+ // bit 3: uPD71037 DMA mode - Carry A20
+ // bit 2: uPD71037 DMA mode - Carry A16
+ // bit 1: uPD71037 DMA mode enable (otherwise in uPD71071 mode)
+ // bit 0: Onboard pripheral I/O maps to 8-bit boundaries? (otherwise 16-bit)
+
+ LOG("SCTL_w %02x\n", data);
+ m_SCTL = data & 0x1f;
+ install_peripheral_io();
+}
+
+void v53_device::device_reset()
+{
+ v33_base_device::device_reset();
+
+ m_SCTL = 0x00;
+}
+
+void v53_device::device_start()
+{
+ v33_base_device::device_start();
+ m_internal_io = &space(AS_INTERNAL_IO);
+
+ set_irq_acknowledge_callback(*m_icu, FUNC(v5x_icu_device::inta_cb));
+
+ save_item(NAME(m_SCTL));
+}
+
+void v53_device::install_peripheral_io()
{
// unmap everything in I/O space up to the fixed position registers (we avoid overwriting them, it isn't a valid config)
- space(AS_IO).unmap_readwrite(0x1000, 0xfeff);
+ space(AS_INTERNAL_IO).unmap_readwrite(0, INTERNAL_IO_ADDR_MASK);
+ space(AS_INTERNAL_IO).install_readwrite_handler(0, INTERNAL_IO_ADDR_MASK,
+ read8sm_delegate(*this, FUNC(v53_device::temp_io_byte_r)),
+ write8sm_delegate(*this, FUNC(v53_device::temp_io_byte_w)));
+
+ // IOAG determines if the handlers used 8-bit or 16-bit access
+ // the hng64.cpp games first set everything up in 8-bit mode, then
+ // do the procedure again in 16-bit mode before using them?!
+
+ bool const IOAG = m_SCTL & 1;
if (m_OPSEL & OPSEL_DS)
{
- u16 const base = ((m_OPHA << 8) | m_DULA) & 0xfffe;
+ u16 const base = m_DULA & INTERNAL_IO_ADDR_MASK;
- space(AS_IO).install_readwrite_handler(base + 0x00, base + 0x0f,
- read8sm_delegate(FUNC(v5x_dmau_device::read), m_dmau.target()),
- write8sm_delegate(FUNC(v5x_dmau_device::write), m_dmau.target()), 0xffff);
+ if (m_SCTL & 0x02) // uPD71037 mode
+ {
+ if (IOAG) // 8-bit
+ {
+ space(AS_INTERNAL_IO).unmap_readwrite(base & ~0x0f, base | 0x0f);
+ }
+ else
+ {
+ space(AS_INTERNAL_IO).unmap_readwrite(base & ~0x1f, base | 0x1f);
+ }
+ }
+ else // uPD71071 mode
+ {
+ space(AS_INTERNAL_IO).unmap_readwrite(base & ~0x0f, base | 0x0f);
+ space(AS_INTERNAL_IO).install_readwrite_handler(base & ~0x0f, base | 0x0f,
+ read8sm_delegate(*m_dmau, FUNC(v5x_dmau_device::read)),
+ write8sm_delegate(*m_dmau, FUNC(v5x_dmau_device::write)), 0xffff);
+ }
}
if (m_OPSEL & OPSEL_IS)
{
- u16 const base = ((m_OPHA << 8) | m_IULA) & 0xfffe;
+ u16 const base = m_IULA & INTERNAL_IO_ADDR_MASK;
- space(AS_IO).install_readwrite_handler(base + 0x00, base + 0x03,
- read8sm_delegate(FUNC(v5x_icu_device::read), m_icu.target()),
- write8sm_delegate(FUNC(v5x_icu_device::write), m_icu.target()), 0x00ff);
+ if (IOAG) // 8-bit
+ {
+ space(AS_INTERNAL_IO).unmap_readwrite(base & ~0x01, base | 0x01);
+ space(AS_INTERNAL_IO).install_readwrite_handler(base & ~0x01, base | 0x01,
+ read8sm_delegate(*m_icu, FUNC(v5x_icu_device::read)),
+ write8sm_delegate(*m_icu, FUNC(v5x_icu_device::write)), 0xffff);
+ }
+ else
+ {
+ space(AS_INTERNAL_IO).unmap_readwrite(base & ~0x03, base | 0x03);
+ space(AS_INTERNAL_IO).install_readwrite_handler(base & ~0x03, base | 0x03,
+ read8sm_delegate(*m_icu, FUNC(v5x_icu_device::read)),
+ write8sm_delegate(*m_icu, FUNC(v5x_icu_device::write)), io_mask(base));
+ }
}
if (m_OPSEL & OPSEL_TS)
{
- u16 const base = ((m_OPHA << 8) | m_TULA) & 0xfffe;
+ u16 const base = m_TULA & INTERNAL_IO_ADDR_MASK;
- space(AS_IO).install_readwrite_handler(base + 0x00, base + 0x07,
- read8sm_delegate(FUNC(pit8253_device::read), m_tcu.target()),
- write8sm_delegate(FUNC(pit8253_device::write), m_tcu.target()), 0x00ff);
+ if (IOAG) // 8-bit
+ {
+ space(AS_INTERNAL_IO).unmap_readwrite(base & ~0x03, base | 0x03);
+ space(AS_INTERNAL_IO).install_readwrite_handler(base & ~0x03, base | 0x03,
+ read8sm_delegate(*m_tcu, FUNC(pit8253_device::read)),
+ write8sm_delegate(*m_tcu, FUNC(pit8253_device::write)), 0xffff);
+ }
+ else
+ {
+ space(AS_INTERNAL_IO).unmap_readwrite(base & ~0x07, base | 0x07);
+ space(AS_INTERNAL_IO).install_readwrite_handler(base & ~0x07, base | 0x07,
+ read8sm_delegate(*m_tcu, FUNC(pit8253_device::read)),
+ write8sm_delegate(*m_tcu, FUNC(pit8253_device::write)), io_mask(base));
+ }
}
if (m_OPSEL & OPSEL_SS)
{
- u16 const base = ((m_OPHA << 8) | m_SULA) & 0xfffe;
+ u16 const base = m_SULA & INTERNAL_IO_ADDR_MASK;
- space(AS_IO).install_readwrite_handler(base + 0x00, base + 0x07,
- read8sm_delegate(FUNC(v5x_scu_device::read), m_scu.target()),
- write8sm_delegate(FUNC(v5x_scu_device::write), m_scu.target()), 0x00ff);
+ if (IOAG) // 8-bit
+ {
+ space(AS_INTERNAL_IO).unmap_readwrite(base & ~0x03, base | 0x03);
+ space(AS_INTERNAL_IO).install_readwrite_handler(base & ~0x03, base | 0x03,
+ read8sm_delegate(*m_scu, FUNC(v5x_scu_device::read)),
+ write8sm_delegate(*m_scu, FUNC(v5x_scu_device::write)), 0xffff);
+ }
+ else
+ {
+ space(AS_INTERNAL_IO).unmap_readwrite(base & ~0x07, base | 0x07);
+ space(AS_INTERNAL_IO).install_readwrite_handler(base & ~0x07, base | 0x07,
+ read8sm_delegate(*m_scu, FUNC(v5x_scu_device::read)),
+ write8sm_delegate(*m_scu, FUNC(v5x_scu_device::write)), io_mask(base));
+ }
}
}
-void v50_device::internal_port_map(address_map &map)
+void v53_device::hack_w(int state)
{
- map(0xfff0, 0xfff0).w(FUNC(v50_device::TCKS_w));
-
- map(0xfff2, 0xfff2).w(FUNC(v50_device::RFC_w));
-
- map(0xfff4, 0xfff4).w(FUNC(v50_device::WMB0_w)); // actually WMB on V50
- map(0xfff5, 0xfff5).w(FUNC(v50_device::WCY1_w));
- map(0xfff6, 0xfff6).w(FUNC(v50_device::WCY2_w));
-
- map(0xfff8, 0xfff8).w(FUNC(v50_device::SULA_w));
- map(0xfff9, 0xfff9).w(FUNC(v50_device::TULA_w));
- map(0xfffa, 0xfffa).w(FUNC(v50_device::IULA_w));
- map(0xfffb, 0xfffb).w(FUNC(v50_device::DULA_w));
- map(0xfffc, 0xfffc).w(FUNC(v50_device::OPHA_w));
- map(0xfffd, 0xfffd).w(FUNC(v50_device::OPSEL_w));
- map(0xfffe, 0xfffe).w(FUNC(v50_device::OPCN_w));
+ if (!(m_SCTL & 0x02))
+ m_dmau->hack_w(state);
+ else
+ LOG("hack_w not in 71071mode\n");
}
void v53_device::internal_port_map(address_map &map)
@@ -328,7 +759,7 @@ void v53_device::internal_port_map(address_map &map)
map(0xffec, 0xffec).w(FUNC(v53_device::WCY0_w)); // waitstate control
map(0xffed, 0xffed).w(FUNC(v53_device::WAC_w)); // waitstate control
// 0xffee-0xffef reserved
- map(0xfff0, 0xfff0).w(FUNC(v53_device::TCKS_w)); // timer clocks
+ map(0xfff0, 0xfff0).rw(FUNC(v53_device::TCKS_r), FUNC(v53_device::TCKS_w)); // timer clocks
map(0xfff1, 0xfff1).w(FUNC(v53_device::SBCR_w)); // internal clock divider, halt behavior etc.
map(0xfff2, 0xfff2).w(FUNC(v53_device::RFC_w)); // ram refresh control
map(0xfff3, 0xfff3).w(FUNC(v53_device::WMB1_w)); // waitstate control
@@ -336,82 +767,38 @@ void v53_device::internal_port_map(address_map &map)
map(0xfff5, 0xfff5).w(FUNC(v53_device::WCY3_w)); // waitstate control
map(0xfff6, 0xfff6).w(FUNC(v53_device::WCY4_w)); // waitstate control
// 0xfff6 reserved
- map(0xfff8, 0xfff8).w(FUNC(v53_device::SULA_w)); // scu mapping
- map(0xfff9, 0xfff9).w(FUNC(v53_device::TULA_w)); // tcu mapping
- map(0xfffa, 0xfffa).w(FUNC(v53_device::IULA_w)); // icu mapping
- map(0xfffb, 0xfffb).w(FUNC(v53_device::DULA_w)); // dmau mapping
- map(0xfffc, 0xfffc).w(FUNC(v53_device::OPHA_w)); // peripheral mapping (upper bits, common)
- map(0xfffd, 0xfffd).w(FUNC(v53_device::OPSEL_w)); // peripheral enabling
- map(0xfffe, 0xfffe).w(FUNC(v53_device::SCTL_w)); // peripheral configuration (& byte / word mapping)
+ map(0xfff8, 0xfff8).rw(FUNC(v53_device::SULA_r), FUNC(v53_device::SULA_w)); // scu mapping
+ map(0xfff9, 0xfff9).rw(FUNC(v53_device::TULA_r), FUNC(v53_device::TULA_w)); // tcu mapping
+ map(0xfffa, 0xfffa).rw(FUNC(v53_device::IULA_r), FUNC(v53_device::IULA_w)); // icu mapping
+ map(0xfffb, 0xfffb).rw(FUNC(v53_device::DULA_r), FUNC(v53_device::DULA_w)); // dmau mapping
+ map(0xfffc, 0xfffc).rw(FUNC(v53_device::OPHA_r), FUNC(v53_device::OPHA_w)); // peripheral mapping (upper bits, common)
+ map(0xfffd, 0xfffd).rw(FUNC(v53_device::OPSEL_r), FUNC(v53_device::OPSEL_w)); // peripheral enabling
+ map(0xfffe, 0xfffe).rw(FUNC(v53_device::SCTL_r), FUNC(v53_device::SCTL_w)); // peripheral configuration (& byte / word mapping)
// 0xffff reserved
}
-// the external interface provides no external access to the usual IRQ line of the V33, everything goes through the interrupt controller
-void v5x_base_device::execute_set_input(int irqline, int state)
+void v53_device::execute_set_input(int irqline, int state)
{
- switch (irqline)
- {
- case INPUT_LINE_IRQ0: m_icu->ir0_w(state); break;
- case INPUT_LINE_IRQ1: m_icu->ir1_w(state); break;
- case INPUT_LINE_IRQ2: m_icu->ir2_w(state); break;
- case INPUT_LINE_IRQ3: m_icu->ir3_w(state); break;
- case INPUT_LINE_IRQ4: m_icu->ir4_w(state); break;
- case INPUT_LINE_IRQ5: m_icu->ir5_w(state); break;
- case INPUT_LINE_IRQ6: m_icu->ir6_w(state); break;
- case INPUT_LINE_IRQ7: m_icu->ir7_w(state); break;
-
- case INPUT_LINE_NMI: nec_common_device::execute_set_input(irqline, state); break;
- case NEC_INPUT_LINE_POLL: nec_common_device::execute_set_input(irqline, state); break;
- }
+ v5x_set_input(irqline, state);
}
-// for hooking the interrupt controller output up to the core
-WRITE_LINE_MEMBER(v5x_base_device::internal_irq_w)
+void v53_device::device_add_mconfig(machine_config &config)
{
- nec_common_device::execute_set_input(0, state);
+ v5x_add_mconfig(config);
}
-void v5x_base_device::device_add_mconfig(machine_config &config)
-{
- PIT8254(config, m_tcu, 0);
- m_tcu->set_clk<0>(clock());
- m_tcu->set_clk<1>(clock());
- m_tcu->set_clk<2>(clock());
-
- V5X_DMAU(config, m_dmau, 4000000);
-
- V5X_ICU(config, m_icu, 0);
- m_icu->out_int_callback().set(FUNC(v5x_base_device::internal_irq_w));
- m_icu->in_sp_callback().set_constant(1);
- m_icu->read_slave_ack_callback().set(FUNC(v5x_base_device::get_pic_ack));
-
- V5X_SCU(config, m_scu, 0);
-}
-
-void v50_device::device_add_mconfig(machine_config &config)
-{
- v5x_base_device::device_add_mconfig(config);
-
- // V50 timer 0 is internally connected to INT0
- m_tcu->out_handler<0>().set(m_icu, FUNC(pic8259_device::ir0_w));
-}
-
-v5x_base_device::v5x_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, address_map_constructor port_map)
- : v33_base_device(mconfig, type, tag, owner, clock, port_map)
- , m_tcu(*this, "tcu")
- , m_dmau(*this, "dmau")
- , m_icu(*this, "icu")
- , m_scu(*this, "scu")
-{
-}
-
-v50_device::v50_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
- : v5x_base_device(mconfig, V50, tag, owner, clock, address_map_constructor(FUNC(v50_device::internal_port_map), this))
+device_memory_interface::space_config_vector v53_device::memory_space_config() const
{
+ return space_config_vector {
+ std::make_pair(AS_PROGRAM, &m_program_config),
+ std::make_pair(AS_IO, &m_io_config),
+ std::make_pair(AS_INTERNAL_IO, &m_internal_io_config)
+ };
}
v53_device::v53_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock)
- : v5x_base_device(mconfig, type, tag, owner, clock, address_map_constructor(FUNC(v53_device::internal_port_map), this))
+ : v33_base_device(mconfig, type, tag, owner, clock, address_map_constructor(FUNC(v53_device::internal_port_map), this))
+ , device_v5x_interface(mconfig, *this, true)
{
}