summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/generalplus_gpl16250soc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/machine/generalplus_gpl16250soc.cpp')
-rw-r--r--src/devices/machine/generalplus_gpl16250soc.cpp1856
1 files changed, 1856 insertions, 0 deletions
diff --git a/src/devices/machine/generalplus_gpl16250soc.cpp b/src/devices/machine/generalplus_gpl16250soc.cpp
new file mode 100644
index 00000000000..dc4505ce9ff
--- /dev/null
+++ b/src/devices/machine/generalplus_gpl16250soc.cpp
@@ -0,0 +1,1856 @@
+// license:BSD-3-Clause
+// copyright-holders:David Haywood
+/*****************************************************************************
+
+ SunPlus "GCM394" (based on die pictures)
+
+ Note, these are all the same chip but in different configurations so
+ should be tidied up and made to use callbacks
+
+**********************************************************************/
+
+#include "emu.h"
+#include "generalplus_gpl16250soc.h"
+
+
+#define LOG_GCM394_SPI (1U << 5)
+#define LOG_GCM394_IO (1U << 4)
+#define LOG_GCM394_SYSDMA (1U << 3)
+#define LOG_GCM394 (1U << 2)
+#define LOG_GCM394_UNMAPPED (1U << 1)
+
+#define VERBOSE (LOG_GCM394 | LOG_GCM394_IO | LOG_GCM394_UNMAPPED | LOG_GCM394_SYSDMA)
+#include "logmacro.h"
+
+
+DEFINE_DEVICE_TYPE(GCM394, sunplus_gcm394_device, "gcm394", "GeneralPlus GPL16250 System-on-a-Chip")
+
+sunplus_gcm394_base_device::sunplus_gcm394_base_device(const machine_config& mconfig, device_type type, const char* tag, device_t* owner, uint32_t clock, address_map_constructor internal) :
+ unsp_20_device(mconfig, type, tag, owner, clock, internal),
+ device_mixer_interface(mconfig, *this, 2),
+ m_screen(*this, finder_base::DUMMY_TAG),
+ m_spg_video(*this, "spgvideo"),
+ m_spg_audio(*this, "spgaudio"),
+ m_internalrom(*this, "internal"),
+ m_mainram(*this, "mainram"),
+ m_porta_in(*this, 0),
+ m_portb_in(*this, 0),
+ m_portc_in(*this, 0),
+ m_portd_in(*this, 0),
+ m_porta_out(*this),
+ m_portb_out(*this),
+ m_portc_out(*this),
+ m_portd_out(*this),
+ m_nand_read_cb(*this, 0),
+ m_csbase(0x20000),
+ m_cs_space(nullptr),
+ m_romtype(0),
+ m_space_read_cb(*this, 0),
+ m_space_write_cb(*this),
+ m_boot_mode(0),
+ m_cs_callback(*this, DEVICE_SELF, FUNC(sunplus_gcm394_base_device::default_cs_callback))
+{
+}
+
+sunplus_gcm394_device::sunplus_gcm394_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ sunplus_gcm394_base_device(mconfig, GCM394, tag, owner, clock)
+{
+}
+
+DEFINE_DEVICE_TYPE(GPAC800, generalplus_gpac800_device, "gpac800", "GeneralPlus GPL16250 System-on-a-Chip (with NAND handling)")
+
+generalplus_gpac800_device::generalplus_gpac800_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ sunplus_gcm394_base_device(mconfig, GPAC800, tag, owner, clock, address_map_constructor(FUNC(generalplus_gpac800_device::gpac800_internal_map), this))
+{
+}
+
+
+DEFINE_DEVICE_TYPE(GP_SPISPI, generalplus_gpspispi_device, "gpac800spi", "GeneralPlus GPL16250 (with SPI handling)")
+
+generalplus_gpspispi_device::generalplus_gpspispi_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ sunplus_gcm394_base_device(mconfig, GP_SPISPI, tag, owner, clock, address_map_constructor(FUNC(generalplus_gpspispi_device::gpspispi_internal_map), this))
+{
+}
+
+
+void generalplus_gpspi_direct_device::ramwrite_w(offs_t offset, uint16_t data)
+{
+ // TODO: Gross hack, it puts some self-check code in RAM at startup, this replaces those calls with retf.
+ if (offset == 0x100 && data == 0xf14c) data = 0x9a90;
+ if (offset == 0x00 && data == 0x9311) data = 0x9a90;
+
+ m_mainram[offset] = data;
+}
+
+uint16_t generalplus_gpspi_direct_device::ramread_r(offs_t offset)
+{
+ return m_mainram[offset];
+}
+
+uint16_t generalplus_gpspi_direct_device::spi_direct_7b40_r()
+{
+ return 0xffff; // doesn't care for now
+}
+
+uint16_t generalplus_gpspi_direct_device::spi_direct_79f5_r()
+{
+ return 0xffff; // hangs if returning 0
+}
+
+uint16_t generalplus_gpspi_direct_device::spi_direct_7b46_r()
+{
+ int i = machine().rand();
+
+ if (i & 1) return 0x01;
+ else return 0x02;
+}
+
+uint16_t generalplus_gpspi_direct_device::spi_direct_79f4_r()
+{
+ // status bits?
+ return machine().rand();
+}
+
+
+uint16_t generalplus_gpspi_direct_device::spi_direct_7af0_r()
+{
+ return m_7af0;
+}
+
+void generalplus_gpspi_direct_device::spi_direct_7af0_w(uint16_t data)
+{
+ // words read from ROM are written here during the checksum routine in RAM, and must
+ // be shifted for the checksum to pass.
+ m_7af0 = data >> 8;
+}
+
+
+uint16_t generalplus_gpspi_direct_device::spi_direct_78e8_r()
+{
+ return machine().rand();
+}
+
+void generalplus_gpspi_direct_device::device_start()
+{
+ sunplus_gcm394_base_device::device_start();
+ save_item(NAME(m_7af0));
+}
+
+void generalplus_gpspi_direct_device::device_reset()
+{
+ sunplus_gcm394_base_device::device_reset();
+ m_7af0 = 0;
+}
+
+void generalplus_gpspi_direct_device::spi_direct_78e8_w(uint16_t data)
+{
+ logerror("%s: spi_direct_78e8_w %04x\n", machine().describe_context(), data);
+}
+
+void generalplus_gpspi_direct_device::gpspi_direct_internal_map(address_map& map)
+{
+ sunplus_gcm394_base_device::base_internal_map(map);
+
+ map(0x000000, 0x0027ff).rw(FUNC(generalplus_gpspi_direct_device::ramread_r), FUNC(generalplus_gpspi_direct_device::ramwrite_w));
+ // TODO: RAM is only 0x2800 on this, like earlier SPG2xx models? unmap the extra from the base_internal_map?
+
+ map(0x00780b, 0x00780b).nopw();
+
+ map(0x0078e8, 0x0078e8).rw(FUNC(generalplus_gpspi_direct_device::spi_direct_78e8_r), FUNC(generalplus_gpspi_direct_device::spi_direct_78e8_w));
+
+ map(0x0079f4, 0x0079f4).r(FUNC(generalplus_gpspi_direct_device::spi_direct_79f4_r));
+ map(0x0079f5, 0x0079f5).r(FUNC(generalplus_gpspi_direct_device::spi_direct_79f5_r));
+
+ map(0x007af0, 0x007af0).rw(FUNC(generalplus_gpspi_direct_device::spi_direct_7af0_r), FUNC(generalplus_gpspi_direct_device::spi_direct_7af0_w));
+
+ map(0x007b40, 0x007b40).r(FUNC(generalplus_gpspi_direct_device::spi_direct_7b40_r));
+// map(0x007b46, 0x007b46).r(FUNC(generalplus_gpspi_direct_device::spi_direct_7b46_r));
+ map(0x007b40, 0x007b40).nopw();
+ map(0x007b41, 0x007b41).nopw();
+ map(0x007b42, 0x007b42).nopw();
+
+ map(0x007b46, 0x007b46).ram(); // values must be written and read from here, but is there any transformation?
+ map(0x007b47, 0x007b47).nopw();
+ map(0x007b48, 0x007b48).nopw();
+
+ map(0x007b49, 0x007b49).ram();
+
+ map(0x009000, 0x3fffff).rom().region("spidirect", 0);
+}
+
+
+DEFINE_DEVICE_TYPE(GP_SPI_DIRECT, generalplus_gpspi_direct_device, "gpac800spi_direct", "GeneralPlus GPL16250 (with direct SPI handling)")
+
+generalplus_gpspi_direct_device::generalplus_gpspi_direct_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ sunplus_gcm394_base_device(mconfig, GP_SPI_DIRECT, tag, owner, clock, address_map_constructor(FUNC(generalplus_gpspi_direct_device::gpspi_direct_internal_map), this))
+{
+}
+
+
+
+
+void sunplus_gcm394_base_device::default_cs_callback(uint16_t cs0, uint16_t cs1, uint16_t cs2, uint16_t cs3, uint16_t cs4)
+{
+ logerror("callback not hooked\n");
+}
+
+
+// **************************************** SYSTEM DMA device *************************************************
+
+uint16_t sunplus_gcm394_base_device::read_dma_params(int channel, int offset)
+{
+ uint16_t retdata = m_dma_params[offset][channel];
+ LOGMASKED(LOG_GCM394_SYSDMA, "%s:sunplus_gcm394_base_device::read_dma_params (channel %01x) %01x returning %04x\n", machine().describe_context(), channel, offset, retdata);
+ return retdata;
+}
+
+void sunplus_gcm394_base_device::write_dma_params(int channel, int offset, uint16_t data)
+{
+ LOGMASKED(LOG_GCM394_SYSDMA, "%s:sunplus_gcm394_base_device::write_dma_params (channel %01x) %01x %04x\n", machine().describe_context(), channel, offset, data);
+
+ m_dma_params[offset][channel] = data;
+
+ // TODO: very likely DMA happens whenever the length is not 0, as long as it's been enabled previously
+ // jak_prft doesn't rewrite the offset 0 register between requests, and instead writes the length
+ // as the final thing for each new request. other games do not write the length last, but turn off
+ // register 0 before writing params, and enable it again afterwards
+ // if that's the case, this code can be refactored to work on 'length' instead of the m_dma_latched
+
+ if (offset == 3)
+ {
+ m_dma_latched[channel] = true;
+
+ if (m_dma_params[0][channel] & 1)
+ trigger_systemm_dma(channel);
+ }
+
+ if (offset == 0 && (data & 1))
+ {
+ if (m_dma_latched[channel])
+ trigger_systemm_dma(channel);
+ }
+
+}
+
+
+uint16_t sunplus_gcm394_base_device::system_dma_params_channel0_r(offs_t offset)
+{
+ return read_dma_params(0, offset);
+}
+
+
+void sunplus_gcm394_base_device::system_dma_params_channel0_w(offs_t offset, uint16_t data)
+{
+ write_dma_params(0, offset, data);
+}
+
+uint16_t sunplus_gcm394_base_device::system_dma_params_channel1_r(offs_t offset)
+{
+ return read_dma_params(1, offset);
+}
+
+void sunplus_gcm394_base_device::system_dma_params_channel1_w(offs_t offset, uint16_t data)
+{
+ write_dma_params(1, offset, data);
+}
+
+uint16_t sunplus_gcm394_base_device::system_dma_params_channel2_r(offs_t offset)
+{
+ return read_dma_params(2, offset);
+}
+
+void sunplus_gcm394_base_device::system_dma_params_channel2_w(offs_t offset, uint16_t data)
+{
+ write_dma_params(2, offset, data);
+}
+
+uint16_t sunplus_gcm394_base_device::system_dma_params_channel3_r(offs_t offset)
+{
+ return read_dma_params(3, offset);
+}
+
+void sunplus_gcm394_base_device::system_dma_params_channel3_w(offs_t offset, uint16_t data)
+{
+ write_dma_params(3, offset, data);
+}
+
+
+
+
+uint16_t sunplus_gcm394_base_device::system_dma_status_r()
+{
+ LOGMASKED(LOG_GCM394_SYSDMA, "%s:sunplus_gcm394_base_device::system_dma_status_r (7abf)\n", machine().describe_context());
+
+ // bit 0 = channel 0 ready
+ // bit 1 = channel 1 ready
+
+ return 0x00ff;
+}
+
+void sunplus_gcm394_base_device::trigger_systemm_dma(int channel)
+{
+ uint16_t mode = m_dma_params[0][channel];
+ uint32_t source = m_dma_params[1][channel] | (m_dma_params[4][channel] << 16);
+ uint32_t dest = m_dma_params[2][channel] | (m_dma_params[5][channel] << 16) ;
+ uint32_t length = m_dma_params[3][channel] | (m_dma_params[6][channel] << 16);
+ int sourcedelta = 0;
+ int destdelta = 0;
+
+ if ((mode & 0xa0) == 0x00)
+ sourcedelta = 1;
+ else if ((mode & 0xa0) == 0x20)
+ sourcedelta = -1;
+
+ if ((mode & 0x50) == 0x00)
+ destdelta = 1;
+ else if ((mode & 0x50) == 0x10)
+ destdelta = -1;
+
+ LOGMASKED(LOG_GCM394_SYSDMA, "%s:possible DMA operation with params mode:%04x source:%08x (word offset) dest:%08x (word offset) length:%08x (words) while csbank is %02x\n", machine().describe_context(), mode, source, dest, length, m_membankswitch_7810 );
+
+ // wrlshunt transfers ROM to RAM, all RAM write addresses have 0x800000 in the destination set
+
+ source &= 0x0fffffff;
+ length &= 0x0fffffff; // gormiti
+
+ for (int i = 0; i < length; i++)
+ {
+ uint16_t val;
+ if (mode & 0x1000)
+ {
+ val = (read_space(source) & 0xFF) | (read_space(source) << 8);
+ i++;
+ }
+ else
+ {
+ val = read_space(source);
+ }
+
+ source += sourcedelta;
+
+ if (mode & 0x2000)
+ {
+ write_space(dest, val & 0xFF);
+ dest += destdelta;
+ write_space(dest, val >> 8);
+ }
+ else
+ {
+ write_space(dest, val);
+ }
+
+ dest += destdelta;
+ }
+
+ // HACKS to get into service mode for debugging
+
+ // note, these patch the code copied to SRAM so the 'PROGRAM ROM' check fails (it passes otherwise)
+
+ address_space& mem = this->space(AS_PROGRAM);
+
+ //if (mem.read_word(0x4368c) == 0x4846)
+ // mem.write_word(0x4368c, 0x4840); // cars 2 force service mode
+
+ //if (mem.read_word(0x34410) == 0x4846)
+ // mem.write_word(0x34410, 0x4840); // golden tee force service mode
+
+ // what is it waiting for when we need these? (needed on some service mode screens)
+ //if (mem.read_word(0x3f368) == 0x4840)
+ // mem.write_word(0x3f368, 0x4841); // cars 2 IRQ? wait hack
+
+ //if (mem.read_word(0x4d8d4) == 0x4840)
+ // mem.write_word(0x4d8d4, 0x4841); // golden tee IRQ? wait hack
+
+ //if (mem.read_word(0x3510f) == 0x4845)
+ // mem.write_word(0x3510f, 0x4840); // camp rock force service mode
+
+ if (mem.read_word(0x4abe7) == 0x4840)
+ mem.write_word(0x4abe7, 0x4841); // camp rock IRQ? wait hack
+
+ //if (mem.read_word(0x37244) == 0x4845)
+ // mem.write_word(0x37244, 0x4840); // hannah montana guitar force service mode
+
+
+
+
+ // clear params after operation
+ m_dma_params[0][channel] = m_dma_params[0][channel] & 0x00f7;
+
+ m_dma_params[1][channel] = m_dma_params[2][channel] = m_dma_params[3][channel] = m_dma_params[4][channel] = m_dma_params[5][channel] = m_dma_params[6][channel] = 0x0000;
+ m_dma_latched[channel] = false;
+
+ //machine().debug_break();
+
+}
+
+void sunplus_gcm394_base_device::system_dma_7abf_unk_w(uint16_t data)
+{
+ // if this isn't trigger, is it enable? (which could maybe used as similar if DMA only starts to happen if unmasked?)
+
+ LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::system_dma_7abf_unk_w %04x\n", machine().describe_context(), data);
+}
+
+uint16_t sunplus_gcm394_base_device::system_dma_memtype_r()
+{
+ LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::system_dma_memtype_r\n", machine().describe_context());
+ return m_system_dma_memtype;
+}
+
+void sunplus_gcm394_base_device::system_dma_memtype_w(uint16_t data)
+{
+ static char const* const types[16] =
+ {
+ "Unused / USB",
+ "DAC CHA",
+ "UART TX",
+ "UART RX",
+ "SD/MMC",
+ "NAND Flash",
+ "Serial Interface",
+ "DAC CHB",
+ "ADC Audo Sample Full",
+ "SPI TX",
+ "SPI RX",
+ "RESERVED (c)",
+ "RESERVED (d)",
+ "RESERVED (e)",
+ "RESERVED (f)"
+ };
+
+ m_system_dma_memtype = data;
+
+ LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::system_dma_memtype_w %04x (CH3: %s | CH2: %s | CH1: %s | CH0: %s )\n", machine().describe_context(), data,
+ types[((m_system_dma_memtype>>12)&0xf)],
+ types[((m_system_dma_memtype>>8)&0xf)],
+ types[((m_system_dma_memtype>>4)&0xf)],
+ types[((m_system_dma_memtype)&0xf)]);
+
+}
+
+uint16_t sunplus_gcm394_base_device::system_7a35_r()
+{
+ LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::system_7a35_r\n", machine().describe_context());
+ return machine().rand();
+}
+
+uint16_t sunplus_gcm394_base_device::system_7a37_r()
+{
+ LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::system_7a37_r\n", machine().describe_context());
+ return machine().rand();
+}
+
+uint16_t sunplus_gcm394_base_device::system_7a39_r()
+{
+ LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::system_7a39_r\n", machine().describe_context());
+ return machine().rand();
+}
+
+
+uint16_t sunplus_gcm394_base_device::system_7a3a_r()
+{
+ LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::system_7a3a_r\n", machine().describe_context());
+ return machine().rand();
+}
+
+uint16_t sunplus_gcm394_base_device::system_7a46_r()
+{
+ LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::system_7a46_r\n", machine().describe_context());
+ return machine().rand();
+}
+
+uint16_t sunplus_gcm394_base_device::system_7a54_r()
+{
+ LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::system_7a54_r\n", machine().describe_context());
+ return machine().rand();
+}
+
+// **************************************** 78xx region with some handling *************************************************
+
+uint16_t sunplus_gcm394_base_device::unkarea_780f_status_r()
+{
+ LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::unkarea_780f_status_r\n", machine().describe_context());
+ return 0x0002;
+}
+
+uint16_t sunplus_gcm394_base_device::unkarea_78fb_status_r()
+{
+ LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::unkarea_78fb_status_r\n", machine().describe_context());
+ m_78fb ^= 0x0100; // status flag for something?
+ return m_78fb;
+}
+
+// sets bit 0x0002 then expects it to have cleared
+uint16_t sunplus_gcm394_base_device::unkarea_7819_r() { LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::unkarea_7819_r\n", machine().describe_context()); return m_7819 & ~ 0x0002; }
+void sunplus_gcm394_base_device::unkarea_7819_w(uint16_t data) { LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::unkarea_7819_w %04x\n", machine().describe_context(), data); m_7819 = data; }
+
+// **************************************** 78xx region stubs *************************************************
+
+uint16_t sunplus_gcm394_base_device::unkarea_782d_r() { LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::unkarea_782d_r\n", machine().describe_context()); return m_782d; }
+void sunplus_gcm394_base_device::unkarea_782d_w(uint16_t data) { LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::unkarea_782d_w %04x\n", machine().describe_context(), data); m_782d = data; }
+
+uint16_t sunplus_gcm394_base_device::unkarea_7803_r() { LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::unkarea_7803_r\n", machine().describe_context()); return m_7803; }
+void sunplus_gcm394_base_device::unkarea_7803_w(uint16_t data) { LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::unkarea_7803_w %04x\n", machine().describe_context(), data); m_7803 = data; }
+
+void sunplus_gcm394_base_device::unkarea_7807_w(uint16_t data) { LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::unkarea_7807_w %04x\n", machine().describe_context(), data); m_7807 = data; }
+
+void sunplus_gcm394_base_device::waitmode_enter_780c_w(uint16_t data)
+{
+ // LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::waitmode_enter_780c_w %04x\n", machine().describe_context(), data);
+ // must be followed by 6 nops to ensure wait mode is entered
+}
+
+// this gets stored / modified / restored before certain memory accesses (
+// used extensively during SDRAM checks in jak_gtg and jak_car2
+
+uint16_t sunplus_gcm394_base_device::membankswitch_7810_r()
+{
+// LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::membankswitch_7810_r\n", machine().describe_context());
+ return m_membankswitch_7810;
+}
+
+void sunplus_gcm394_base_device::membankswitch_7810_w(uint16_t data)
+{
+// if (m_membankswitch_7810 != data)
+// LOGMASKED(LOG_GCM394,"%s:sunplus_gcm394_base_device::membankswitch_7810_w %04x\n", machine().describe_context(), data);
+
+// if (m_membankswitch_7810 != data)
+// popmessage("bankswitch %04x -> %04x", m_membankswitch_7810, data);
+
+ m_membankswitch_7810 = data;
+}
+
+
+void sunplus_gcm394_base_device::unkarea_7816_w(uint16_t data)
+{
+ LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::unkarea_7816_w %04x\n", machine().describe_context(), data);
+ m_7816 = data;
+}
+
+void sunplus_gcm394_base_device::unkarea_7817_w(uint16_t data)
+{
+ LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::unkarea_7817_w %04x\n", machine().describe_context(), data);
+ m_7817 = data;
+}
+
+void sunplus_gcm394_base_device::chipselect_csx_memory_device_control_w(offs_t offset, uint16_t data)
+{
+ LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::chipselect_csx_memory_device_control_w %04x (782x registers offset %d)\n", machine().describe_context(), data, offset);
+ m_782x[offset] = data;
+
+
+ static const char* const md[] =
+ {
+ "(00) ROM / SRAM",
+ "(01) ROM / SRAM",
+ "(10) NOR FLASH",
+ "(11) NAND FLASH",
+ };
+
+ uint8_t cs_wait = data & 0x000f;
+ uint8_t cs_warat = (data & 0x0030)>>4;
+ uint8_t cs_md = (data & 0x00c0)>>6;
+ int cs_size = (data & 0xff00)>>8;
+
+ logerror("CS%d set to size: %02x (%08x words) md: %01x %s warat: %01x wait: %01x\n", offset, cs_size, (cs_size+1)*0x10000, cs_md, md[cs_md], cs_warat, cs_wait);
+
+ m_cs_callback(m_782x[0], m_782x[1], m_782x[2], m_782x[3], m_782x[4]);
+
+}
+
+void sunplus_gcm394_base_device::device_post_load()
+{
+ m_cs_callback(m_782x[0], m_782x[1], m_782x[2], m_782x[3], m_782x[4]);
+}
+
+void sunplus_gcm394_base_device::unkarea_7835_w(uint16_t data) { LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::unkarea_7835_w %04x\n", machine().describe_context(), data); m_7835 = data; }
+
+// IO here?
+
+// Port A
+
+uint16_t sunplus_gcm394_base_device::ioarea_7860_porta_r()
+{
+ LOGMASKED(LOG_GCM394_IO, "%s:sunplus_gcm394_base_device::ioarea_7860_porta_r\n", machine().describe_context());
+ return m_porta_in();
+}
+
+void sunplus_gcm394_base_device::ioarea_7860_porta_w(uint16_t data)
+{
+ LOGMASKED(LOG_GCM394_IO, "%s:sunplus_gcm394_base_device::ioarea_7860_porta_w %04x\n", machine().describe_context(), data);
+ m_porta_out(data);
+}
+
+uint16_t sunplus_gcm394_base_device::ioarea_7861_porta_buffer_r()
+{
+ LOGMASKED(LOG_GCM394_IO, "%s:sunplus_gcm394_base_device::ioarea_7861_porta_buffer_r\n", machine().describe_context());
+ return 0x0000;// 0xffff;// m_7861;
+}
+
+void sunplus_gcm394_base_device::ioarea_7861_porta_buffer_w(uint16_t data)
+{
+ LOGMASKED(LOG_GCM394_IO, "%s:sunplus_gcm394_base_device::ioarea_7861_porta_buffer_w %04x\n", machine().describe_context(), data);
+}
+
+uint16_t sunplus_gcm394_base_device::ioarea_7862_porta_direction_r()
+{
+ LOGMASKED(LOG_GCM394_IO, "%s:sunplus_gcm394_base_device::ioarea_7862_porta_direction_r\n", machine().describe_context());
+ return m_7862_porta_direction;
+}
+
+void sunplus_gcm394_base_device::ioarea_7862_porta_direction_w(uint16_t data)
+{
+ LOGMASKED(LOG_GCM394_IO, "%s:sunplus_gcm394_base_device::ioarea_7862_porta_direction_w %04x\n", machine().describe_context(), data);
+ m_7862_porta_direction = data;
+}
+
+uint16_t sunplus_gcm394_base_device::ioarea_7863_porta_attribute_r()
+{
+ LOGMASKED(LOG_GCM394_IO, "%s:sunplus_gcm394_base_device::ioarea_7863_porta_attribute_r\n", machine().describe_context());
+ return m_7863_porta_attribute;
+}
+
+void sunplus_gcm394_base_device::ioarea_7863_porta_attribute_w(uint16_t data)
+{
+ LOGMASKED(LOG_GCM394_IO, "%s:sunplus_gcm394_base_device::ioarea_7863_porta_attribute_w %04x\n", machine().describe_context(), data);
+ m_7863_porta_attribute = data;
+}
+
+// Port B
+
+uint16_t sunplus_gcm394_base_device::ioarea_7868_portb_r()
+{
+ LOGMASKED(LOG_GCM394_IO, "%s:sunplus_gcm394_base_device::ioarea_7868_portb_r\n", machine().describe_context());
+ return m_portb_in();
+}
+
+uint16_t sunplus_gcm394_base_device::ioarea_7869_portb_buffer_r()
+{
+ LOGMASKED(LOG_GCM394_IO, "%s:sunplus_gcm394_base_device::ioarea_7869_portb_buffer_r\n", machine().describe_context());
+ return machine().rand();
+}
+
+void sunplus_gcm394_base_device::ioarea_7869_portb_buffer_w(uint16_t data)
+{
+ LOGMASKED(LOG_GCM394_IO, "%s:sunplus_gcm394_base_device::ioarea_7869_portb_buffer_w %04x\n", machine().describe_context(), data);
+ m_portb_out(data); // buffer writes must update output state too, beijuehh requires it for banking
+}
+
+void sunplus_gcm394_base_device::ioarea_7868_portb_w(uint16_t data)
+{
+ LOGMASKED(LOG_GCM394_IO, "%s:sunplus_gcm394_base_device::ioarea_7868_portb_w %04x\n", machine().describe_context(), data);
+ m_portb_out(data);
+}
+
+uint16_t sunplus_gcm394_base_device::ioarea_786a_portb_direction_r()
+{
+ LOGMASKED(LOG_GCM394_IO, "%s:sunplus_gcm394_base_device::ioarea_786a_portb_direction_r\n", machine().describe_context());
+ return m_786a_portb_direction;
+}
+
+void sunplus_gcm394_base_device::ioarea_786a_portb_direction_w(uint16_t data)
+{
+ LOGMASKED(LOG_GCM394_IO, "%s:sunplus_gcm394_base_device::ioarea_786a_portb_direction_w %04x\n", machine().describe_context(), data);
+ m_786a_portb_direction = data;
+}
+
+uint16_t sunplus_gcm394_base_device::ioarea_786b_portb_attribute_r()
+{
+ LOGMASKED(LOG_GCM394_IO, "%s:sunplus_gcm394_base_device::ioarea_786b_portb_attribute_r\n", machine().describe_context());
+ return m_786b_portb_attribute;
+}
+
+void sunplus_gcm394_base_device::ioarea_786b_portb_attribute_w(uint16_t data)
+{
+ LOGMASKED(LOG_GCM394_IO, "%s:sunplus_gcm394_base_device::ioarea_786b_portb_attribute_w %04x\n", machine().describe_context(), data);
+ m_786b_portb_attribute = data;
+}
+
+// Port C
+
+uint16_t sunplus_gcm394_base_device::ioarea_7870_portc_r()
+{
+ LOGMASKED(LOG_GCM394_IO, "%s:sunplus_gcm394_base_device::ioarea_7870_portc_r\n", machine().describe_context());
+ return m_portc_in();
+}
+
+void sunplus_gcm394_base_device::ioarea_7870_portc_w(uint16_t data)
+{
+ LOGMASKED(LOG_GCM394_IO, "%s:sunplus_gcm394_base_device::ioarea_7870_portc_w %04x\n", machine().describe_context(), data);
+ m_7870 = data;
+ m_portc_out(data);
+}
+
+uint16_t sunplus_gcm394_base_device::ioarea_7871_portc_buffer_r()
+{
+ LOGMASKED(LOG_GCM394_IO, "%s:sunplus_gcm394_base_device::ioarea_7871_portc_buffer_r\n", machine().describe_context());
+ return 0xffff;// m_7871;
+}
+
+void sunplus_gcm394_base_device::ioarea_7871_portc_buffer_w(uint16_t data)
+{
+ LOGMASKED(LOG_GCM394_IO, "%s:sunplus_gcm394_base_device::ioarea_7871_portc_buffer_w %04x\n", machine().describe_context(), data);
+}
+
+
+uint16_t sunplus_gcm394_base_device::ioarea_7872_portc_direction_r()
+{
+ LOGMASKED(LOG_GCM394_IO, "%s:sunplus_gcm394_base_device::ioarea_7872_portc_direction_r\n", machine().describe_context());
+ return m_7872_portc_direction;
+}
+
+void sunplus_gcm394_base_device::ioarea_7872_portc_direction_w(uint16_t data)
+{
+ LOGMASKED(LOG_GCM394_IO, "%s:sunplus_gcm394_base_device::ioarea_7872_portc_direction_w %04x\n", machine().describe_context(), data);
+ m_7872_portc_direction = data;
+}
+
+uint16_t sunplus_gcm394_base_device::ioarea_7873_portc_attribute_r()
+{
+ LOGMASKED(LOG_GCM394_IO, "%s:sunplus_gcm394_base_device::ioarea_7873_portc_attribute_r\n", machine().describe_context());
+ return m_7873_portc_attribute;
+}
+
+void sunplus_gcm394_base_device::ioarea_7873_portc_attribute_w(uint16_t data)
+{
+ LOGMASKED(LOG_GCM394_IO, "%s:sunplus_gcm394_base_device::ioarea_7873_portc_attribute_w %04x\n", machine().describe_context(), data);
+ m_7873_portc_attribute = data;
+}
+
+// Port D
+
+uint16_t sunplus_gcm394_base_device::ioarea_7878_portd_r()
+{
+ LOGMASKED(LOG_GCM394_IO, "%s:sunplus_gcm394_base_device::ioarea_7878_portd_r\n", machine().describe_context());
+ return m_portd_in();
+}
+
+void sunplus_gcm394_base_device::ioarea_7878_portd_w(uint16_t data)
+{
+ LOGMASKED(LOG_GCM394_IO, "%s:sunplus_gcm394_base_device::ioarea_7878_portd_w %04x\n", machine().describe_context(), data);
+ //m_7878 = data;
+ m_portd_out(data);
+}
+
+uint16_t sunplus_gcm394_base_device::ioarea_7879_portd_buffer_r()
+{
+ LOGMASKED(LOG_GCM394_IO, "%s:sunplus_gcm394_base_device::ioarea_7879_portd_buffer_r\n", machine().describe_context());
+ return 0xffff;// m_7871;
+}
+
+void sunplus_gcm394_base_device::ioarea_7879_portd_buffer_w(uint16_t data)
+{
+ LOGMASKED(LOG_GCM394_IO, "%s:sunplus_gcm394_base_device::ioarea_7879_portd_buffer_w %04x\n", machine().describe_context(), data);
+ m_portd_out(data); // buffer writes must update output state too, beijuehh requires it for banking
+}
+
+
+uint16_t sunplus_gcm394_base_device::ioarea_787a_portd_direction_r()
+{
+ LOGMASKED(LOG_GCM394_IO, "%s:sunplus_gcm394_base_device::ioarea_787a_portd_direction_r\n", machine().describe_context());
+ return m_787a_portd_direction;
+}
+
+void sunplus_gcm394_base_device::ioarea_787a_portd_direction_w(uint16_t data)
+{
+ LOGMASKED(LOG_GCM394_IO, "%s:sunplus_gcm394_base_device::ioarea_787a_portd_direction_w %04x\n", machine().describe_context(), data);
+ m_787a_portd_direction = data;
+}
+
+uint16_t sunplus_gcm394_base_device::ioarea_787b_portd_attribute_r()
+{
+ LOGMASKED(LOG_GCM394_IO, "%s:sunplus_gcm394_base_device::ioarea_787b_portd_attribute_r\n", machine().describe_context());
+ return m_787b_portd_attribute;
+}
+
+void sunplus_gcm394_base_device::ioarea_787b_portd_attribute_w(uint16_t data)
+{
+ LOGMASKED(LOG_GCM394_IO, "%s:sunplus_gcm394_base_device::ioarea_787b_portd_attribute_w %04x\n", machine().describe_context(), data);
+ m_787b_portd_attribute = data;
+}
+
+uint16_t sunplus_gcm394_base_device::unkarea_7882_r() { LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::unkarea_7882_r\n", machine().describe_context()); return 0xffff;// m_7882;
+}
+void sunplus_gcm394_base_device::unkarea_7882_w(uint16_t data) { LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::unkarea_7882_w %04x\n", machine().describe_context(), data); m_7882 = data; }
+uint16_t sunplus_gcm394_base_device::unkarea_7883_r() { LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::unkarea_7883_r\n", machine().describe_context()); return 0xffff;// m_7883;
+}
+void sunplus_gcm394_base_device::unkarea_7883_w(uint16_t data) { LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::unkarea_7883_w %04x\n", machine().describe_context(), data); m_7883 = data; }
+
+void sunplus_gcm394_base_device::unkarea_78a0_w(uint16_t data) { LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::unkarea_78a0_w %04x\n", machine().describe_context(), data); m_78a0 = data; }
+
+uint16_t sunplus_gcm394_base_device::unkarea_78a0_r()
+{
+ LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::unkarea_78a0_r\n", machine().describe_context());
+ return 0x0000;// machine().rand();
+}
+
+uint16_t sunplus_gcm394_base_device::unkarea_78a1_r()
+{
+ LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::unkarea_78a1_r\n", machine().describe_context());
+ return 0xffff;// machine().rand();
+}
+
+void sunplus_gcm394_base_device::unkarea_78a4_w(uint16_t data) { LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::unkarea_78a4_w %04x\n", machine().describe_context(), data); m_78a4 = data; }
+void sunplus_gcm394_base_device::unkarea_78a5_w(uint16_t data) { LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::unkarea_78a5_w %04x\n", machine().describe_context(), data); m_78a5 = data; }
+void sunplus_gcm394_base_device::unkarea_78a6_w(uint16_t data) { LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::unkarea_78a6_w %04x\n", machine().describe_context(), data); m_78a6 = data; }
+
+void sunplus_gcm394_base_device::unkarea_78a8_w(uint16_t data) { LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::unkarea_78a8_w %04x\n", machine().describe_context(), data); m_78a8 = data; }
+
+
+void sunplus_gcm394_base_device::unkarea_78b0_w(uint16_t data) { LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::unkarea_78b0_w %04x\n", machine().describe_context(), data); m_78b0 = data; }
+void sunplus_gcm394_base_device::unkarea_78b1_w(uint16_t data) { LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::unkarea_78b1_w %04x\n", machine().describe_context(), data); m_78b1 = data; }
+
+uint16_t sunplus_gcm394_base_device::unkarea_78b2_r()
+{
+ LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::unkarea_78b2_r\n", machine().describe_context());
+ return 0xffff;// m_78b2;
+}
+
+void sunplus_gcm394_base_device::unkarea_78b2_w(uint16_t data) { LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::unkarea_78b2_w %04x\n", machine().describe_context(), data); m_78b2 = data; }
+
+void sunplus_gcm394_base_device::unkarea_78b8_w(uint16_t data) { LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::unkarea_78b8_w %04x\n", machine().describe_context(), data); m_78b8 = data; }
+void sunplus_gcm394_base_device::unkarea_78f0_w(uint16_t data) { LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::unkarea_78f0_w %04x\n", machine().describe_context(), data); m_78f0 = data; }
+
+uint16_t sunplus_gcm394_base_device::unkarea_78c0_r()
+{
+ LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::unkarea_78c0_r\n", machine().describe_context());
+ return machine().rand();
+}
+
+uint16_t sunplus_gcm394_base_device::unkarea_78d0_r()
+{
+ LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::unkarea_78d0_r\n", machine().describe_context());
+ return machine().rand();
+}
+
+uint16_t sunplus_gcm394_base_device::unkarea_78d8_r()
+{
+ LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::unkarea_78d8_r\n", machine().describe_context());
+ return machine().rand();
+}
+
+// **************************************** 793x uknown region stubs *************************************************
+
+uint16_t sunplus_gcm394_base_device::unkarea_7904_r()
+{
+ LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::unkarea_7904_r\n", machine().describe_context());
+ return machine().rand(); // lazertag waits on a bit, status flag for something?
+
+}
+
+uint16_t sunplus_gcm394_base_device::unkarea_7934_r()
+{
+ // does this return data written, or is it a status flag?
+ LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::unkarea_7934_r\n", machine().describe_context());
+ return m_7934;
+}
+
+void sunplus_gcm394_base_device::unkarea_7934_w(uint16_t data)
+{
+ LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::unkarea_7934_w %04x\n", machine().describe_context(), data);
+ m_7934 = data;
+}
+
+// value of 7935 is read then written in irq6, nothing happens unless bit 0x0100 was set, which could be some kind of irq source being acked?
+uint16_t sunplus_gcm394_base_device::unkarea_7935_r()
+{
+ LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::unkarea_7935_r\n", machine().describe_context());
+ return m_7935;
+}
+
+void sunplus_gcm394_base_device::unkarea_7935_w(uint16_t data)
+{
+ LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::unkarea_7935_w %04x\n", machine().describe_context(), data);
+ m_7935 &= ~data;
+ //checkirq6();
+}
+
+uint16_t sunplus_gcm394_base_device::unkarea_7936_r() { LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::unkarea_7936_r\n", machine().describe_context()); return 0x0000; }
+void sunplus_gcm394_base_device::unkarea_7936_w(uint16_t data) { LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::unkarea_7936_w %04x\n", machine().describe_context(), data); m_7936 = data; }
+
+// **************************************** 794x SPI *************************************************
+
+// these are related to the accelerometer values on jak_g500 (8-bit signed) and also the SPI reads for bkrankp
+uint16_t sunplus_gcm394_base_device::spi_7944_rxdata_r()
+{
+ LOGMASKED(LOG_GCM394_SPI, "%s:sunplus_gcm394_base_device::spi_7944_rxdata_r\n", machine().describe_context());
+ return machine().rand();
+}
+
+uint16_t sunplus_gcm394_base_device::spi_7945_misc_control_reg_r()
+{
+ LOGMASKED(LOG_GCM394_SPI, "%s:sunplus_gcm394_base_device::spi_7945_misc_control_reg_r\n", machine().describe_context());
+ return machine().rand();// &0x0007;
+}
+
+void sunplus_gcm394_base_device::spi_7942_txdata_w(uint16_t data)
+{
+ LOGMASKED(LOG_GCM394_SPI, "%s:sunplus_gcm394_base_device::spi_7942_txdata_w %04x\n", machine().describe_context(), data);
+}
+
+// **************************************** 796x unknown *************************************************
+
+void sunplus_gcm394_base_device::unkarea_7960_w(uint16_t data) { LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::unkarea_7960_w %04x\n", machine().describe_context(), data); m_7960 = data; }
+
+uint16_t sunplus_gcm394_base_device::unkarea_7961_r() { LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::unkarea_7961_r\n", machine().describe_context()); return m_7961; }
+void sunplus_gcm394_base_device::unkarea_7961_w(uint16_t data) { LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::unkarea_7961_w %04x\n", machine().describe_context(), data); m_7961 = data; }
+
+
+// **************************************** fallthrough logger etc. *************************************************
+
+uint16_t sunplus_gcm394_base_device::unk_r(offs_t offset)
+{
+ switch (offset)
+ {
+ default:
+ LOGMASKED(LOG_GCM394_UNMAPPED, "%s:sunplus_gcm394_base_device::unk_r @ 0x%04x\n", machine().describe_context(), offset + 0x7000);
+ return 0x0000;
+ }
+
+ return 0x0000;
+}
+
+void sunplus_gcm394_base_device::unk_w(offs_t offset, uint16_t data)
+{
+
+ switch (offset)
+ {
+ default:
+ LOGMASKED(LOG_GCM394_UNMAPPED, "%s:sunplus_gcm394_base_device::unk_w @ 0x%04x (data 0x%04x)\n", machine().describe_context(), offset + 0x7000, data);
+ break;
+ }
+}
+
+void sunplus_gcm394_base_device::base_internal_map(address_map &map)
+{
+ map(0x000000, 0x006fff).ram().share("mainram");
+ map(0x007000, 0x007fff).rw(FUNC(sunplus_gcm394_base_device::unk_r), FUNC(sunplus_gcm394_base_device::unk_w)); // catch unhandled
+
+ // ######################################################################################################################################################################################
+ // 70xx region = video hardware
+ // ######################################################################################################################################################################################
+
+ // note, tilemaps are at the same address offsets in video device as spg2xx (but unknown devices are extra)
+
+ map(0x007000, 0x007007).rw(m_spg_video, FUNC(gcm394_base_video_device::tmap2_regs_r), FUNC(gcm394_base_video_device::tmap2_regs_w)); // written with other unknown_video_device1 LSB/MSB regs below (roz layer or line layer?)
+ map(0x007008, 0x00700f).rw(m_spg_video, FUNC(gcm394_base_video_device::tmap3_regs_r), FUNC(gcm394_base_video_device::tmap3_regs_w)); // written with other unknown_video_device2 LSB/MSB regs below (roz layer or line layer?)
+
+ map(0x007010, 0x007015).rw(m_spg_video, FUNC(gcm394_base_video_device::tmap0_regs_r), FUNC(gcm394_base_video_device::tmap0_regs_w));
+ map(0x007016, 0x00701b).rw(m_spg_video, FUNC(gcm394_base_video_device::tmap1_regs_r), FUNC(gcm394_base_video_device::tmap1_regs_w));
+
+ map(0x00701c, 0x00701c).w(m_spg_video, FUNC(gcm394_base_video_device::video_701c_w)); // these 3 are written together in paccon
+ map(0x00701d, 0x00701d).w(m_spg_video, FUNC(gcm394_base_video_device::video_701d_w));
+ map(0x00701e, 0x00701e).w(m_spg_video, FUNC(gcm394_base_video_device::video_701e_w));
+
+ // tilebase LSBs
+ map(0x007020, 0x007020).rw(m_spg_video, FUNC(gcm394_base_video_device::tmap0_tilebase_lsb_r), FUNC(gcm394_base_video_device::tmap0_tilebase_lsb_w)); // tilebase, written with other tmap0 regs
+ map(0x007021, 0x007021).rw(m_spg_video, FUNC(gcm394_base_video_device::tmap1_tilebase_lsb_r), FUNC(gcm394_base_video_device::tmap1_tilebase_lsb_w)); // tilebase, written with other tmap1 regs
+ map(0x007022, 0x007022).rw(m_spg_video, FUNC(gcm394_base_video_device::sprite_7022_gfxbase_lsb_r), FUNC(gcm394_base_video_device::sprite_7022_gfxbase_lsb_w)); // sprite tilebase written as 7022, 702d and 7042 group
+ map(0x007023, 0x007023).rw(m_spg_video, FUNC(gcm394_base_video_device::tmap2_tilebase_lsb_r), FUNC(gcm394_base_video_device::tmap2_tilebase_lsb_w)); // written with other tmap2 regs (roz layer or line layer?)
+ map(0x007024, 0x007024).rw(m_spg_video, FUNC(gcm394_base_video_device::tmap3_tilebase_lsb_r), FUNC(gcm394_base_video_device::tmap3_tilebase_lsb_w)); // written with other tmap3 regs (roz layer or line layer?)
+
+ map(0x00702a, 0x00702a).w(m_spg_video, FUNC(gcm394_base_video_device::video_702a_w)); // blend level control
+
+ // tilebase MSBs
+ map(0x00702b, 0x00702b).rw(m_spg_video, FUNC(gcm394_base_video_device::tmap0_tilebase_msb_r), FUNC(gcm394_base_video_device::tmap0_tilebase_msb_w)); // written with other tmap0 regs
+ map(0x00702c, 0x00702c).rw(m_spg_video, FUNC(gcm394_base_video_device::tmap1_tilebase_msb_r), FUNC(gcm394_base_video_device::tmap1_tilebase_msb_w)); // written with other tmap1 regs
+ map(0x00702d, 0x00702d).rw(m_spg_video, FUNC(gcm394_base_video_device::sprite_702d_gfxbase_msb_r), FUNC(gcm394_base_video_device::sprite_702d_gfxbase_msb_w)); // sprites, written as 7022, 702d and 7042 group
+ map(0x00702e, 0x00702e).rw(m_spg_video, FUNC(gcm394_base_video_device::tmap2_tilebase_msb_r), FUNC(gcm394_base_video_device::tmap2_tilebase_msb_w)); // written with other tmap2 regs (roz layer or line layer?)
+ map(0x00702f, 0x00702f).rw(m_spg_video, FUNC(gcm394_base_video_device::tmap3_tilebase_msb_r), FUNC(gcm394_base_video_device::tmap3_tilebase_msb_w)); // written with other tmap3 regs (roz layer or line layer?)
+
+ map(0x007036, 0x007036).w(m_spg_video, FUNC(gcm394_base_video_device::split_irq_xpos_w));
+ map(0x007037, 0x007037).w(m_spg_video, FUNC(gcm394_base_video_device::split_irq_ypos_w));
+
+
+ map(0x007030, 0x007030).rw(m_spg_video, FUNC(gcm394_base_video_device::video_7030_brightness_r), FUNC(gcm394_base_video_device::video_7030_brightness_w));
+ map(0x007038, 0x007038).r(m_spg_video, FUNC(gcm394_base_video_device::video_curline_r));
+ map(0x00703a, 0x00703a).rw(m_spg_video, FUNC(gcm394_base_video_device::video_703a_palettebank_r), FUNC(gcm394_base_video_device::video_703a_palettebank_w));
+ map(0x00703c, 0x00703c).rw(m_spg_video, FUNC(gcm394_base_video_device::video_703c_tvcontrol1_r), FUNC(gcm394_base_video_device::video_703c_tvcontrol1_w)); // TV Control 1
+
+ map(0x007042, 0x007042).rw(m_spg_video, FUNC(gcm394_base_video_device::sprite_7042_extra_r), FUNC(gcm394_base_video_device::sprite_7042_extra_w)); // maybe sprites, written as 7022, 702d and 7042 group
+
+ map(0x007051, 0x007051).r(m_spg_video, FUNC(gcm394_base_video_device::video_7051_r)); // wrlshunt checks this (doesn't exist on older SPG?)
+
+ map(0x007062, 0x007062).rw(m_spg_video, FUNC(gcm394_base_video_device::videoirq_source_enable_r), FUNC(gcm394_base_video_device::videoirq_source_enable_w));
+ map(0x007063, 0x007063).rw(m_spg_video, FUNC(gcm394_base_video_device::video_7063_videoirq_source_r), FUNC(gcm394_base_video_device::video_7063_videoirq_source_ack_w));
+
+ // note, 70 / 71 / 72 are the same offsets used for DMA as in spg2xx video device
+ map(0x007070, 0x007070).w(m_spg_video, FUNC(gcm394_base_video_device::video_dma_source_w)); // video dma, not system dma? (sets pointers to ram buffers)
+ map(0x007071, 0x007071).w(m_spg_video, FUNC(gcm394_base_video_device::video_dma_dest_w)); // sets pointers to 7300, 7400 ram areas below
+ map(0x007072, 0x007072).rw(m_spg_video, FUNC(gcm394_base_video_device::video_dma_size_busy_r), FUNC(gcm394_base_video_device::video_dma_size_trigger_w)); //
+
+ // these don't exist on older SPG
+ map(0x00707c, 0x00707c).r(m_spg_video, FUNC(gcm394_base_video_device::video_707c_r)); // wrlshunt polls this waiting for 0x8000, is this some kind of manual port-based data upload?
+
+ map(0x00707e, 0x00707e).w(m_spg_video, FUNC(gcm394_base_video_device::video_707e_spritebank_w)); // written around same time as DMA, seems to select alt sprite bank
+ map(0x00707f, 0x00707f).rw(m_spg_video, FUNC(gcm394_base_video_device::video_707f_r), FUNC(gcm394_base_video_device::video_707f_w));
+
+ // another set of registers for something?
+ map(0x007080, 0x007080).w(m_spg_video, FUNC(gcm394_base_video_device::video_7080_w));
+ map(0x007081, 0x007081).w(m_spg_video, FUNC(gcm394_base_video_device::video_7081_w));
+ map(0x007082, 0x007082).w(m_spg_video, FUNC(gcm394_base_video_device::video_7082_w));
+ map(0x007083, 0x007083).rw(m_spg_video, FUNC(gcm394_base_video_device::video_7083_r), FUNC(gcm394_base_video_device::video_7083_w));
+ map(0x007084, 0x007084).w(m_spg_video, FUNC(gcm394_base_video_device::video_7084_w));
+ map(0x007085, 0x007085).w(m_spg_video, FUNC(gcm394_base_video_device::video_7085_w));
+ map(0x007086, 0x007086).w(m_spg_video, FUNC(gcm394_base_video_device::video_7086_w));
+ map(0x007087, 0x007087).w(m_spg_video, FUNC(gcm394_base_video_device::video_7087_w));
+ map(0x007088, 0x007088).w(m_spg_video, FUNC(gcm394_base_video_device::video_7088_w));
+
+ map(0x0070e0, 0x0070e0).r(m_spg_video, FUNC(gcm394_base_video_device::video_70e0_prng_r)); // gormiti checks this
+
+ // ######################################################################################################################################################################################
+ // 73xx-77xx = video ram
+ // ######################################################################################################################################################################################
+
+ map(0x007100, 0x0071ff).ram().share("rowscroll"); // based on jak_s500
+ map(0x007200, 0x0072ff).ram().share("rowzoom"); // ^^
+
+ map(0x007300, 0x0073ff).rw(m_spg_video, FUNC(gcm394_base_video_device::palette_r), FUNC(gcm394_base_video_device::palette_w));
+
+ map(0x007400, 0x0077ff).rw(m_spg_video, FUNC(gcm394_base_video_device::spriteram_r), FUNC(gcm394_base_video_device::spriteram_w));
+
+ // ######################################################################################################################################################################################
+ // 78xx region = system regs?
+ // ######################################################################################################################################################################################
+
+ map(0x007803, 0x007803).rw(FUNC(sunplus_gcm394_base_device::unkarea_7803_r), FUNC(sunplus_gcm394_base_device::unkarea_7803_w));
+
+ map(0x007807, 0x007807).w(FUNC(sunplus_gcm394_base_device::unkarea_7807_w));
+ // 7808
+
+ // 780a
+
+ map(0x00780c, 0x00780c).w(FUNC(sunplus_gcm394_base_device::waitmode_enter_780c_w));
+
+ map(0x00780f, 0x00780f).r(FUNC(sunplus_gcm394_base_device::unkarea_780f_status_r));
+
+ map(0x007810, 0x007810).rw(FUNC(sunplus_gcm394_base_device::membankswitch_7810_r), FUNC(sunplus_gcm394_base_device::membankswitch_7810_w)); // 7810 Bank Switch Control Register (P_BankSwitch_Ctrl) (maybe)
+
+ map(0x007819, 0x007819).rw(FUNC(sunplus_gcm394_base_device::unkarea_7819_r), FUNC(sunplus_gcm394_base_device::unkarea_7819_w));
+
+ map(0x007816, 0x007816).w(FUNC(sunplus_gcm394_base_device::unkarea_7816_w));
+ map(0x007817, 0x007817).w(FUNC(sunplus_gcm394_base_device::unkarea_7817_w));
+
+ // ######################################################################################################################################################################################
+ // 782x region = memory config / control
+ // ######################################################################################################################################################################################
+ // wrlshunt | smartfp
+ map(0x007820, 0x007824).w(FUNC(sunplus_gcm394_base_device::chipselect_csx_memory_device_control_w)); // 7f8a (7f8a before DMA from ROM to RAM, 008a after DMA from ROM to RAM) | 3f04 7820 Chip Select (CS0) Memory Device Control (P_MC50_Ctrl)
+ // 7f47 | 0044 7821 Chip Select (CS1) Memory Device Control (P_MC51_Ctrl)
+ // 0047 | 1f44 7822 Chip Select (CS2) Memory Device Control (P_MC52_Ctrl)
+ // 0047 | 0044 7823 Chip Select (CS3) Memory Device Control (P_MC53_Ctrl)
+ // 0047 | 0044 7824 Chip Select (CS4) Memory Device Control (P_MC54_Ctrl)
+
+ map(0x00782d, 0x00782d).rw(FUNC(sunplus_gcm394_base_device::unkarea_782d_r), FUNC(sunplus_gcm394_base_device::unkarea_782d_w)); // on startup
+ // 782f
+
+ map(0x007835, 0x007835).w(FUNC(sunplus_gcm394_base_device::unkarea_7835_w));
+
+ // 783a
+ // 783b
+ // 783c
+ // 783d
+ // 783e
+
+ // 7840 - accessed by code in RAM when changing bank in tkmag220
+ // 7841 - ^^
+
+ // ######################################################################################################################################################################################
+ // 786x - 787x - IO related?
+ // ######################################################################################################################################################################################
+
+ map(0x007860, 0x007860).rw(FUNC(sunplus_gcm394_base_device::ioarea_7860_porta_r), FUNC(sunplus_gcm394_base_device::ioarea_7860_porta_w)); // 7860 I/O PortA Data Register
+ map(0x007861, 0x007861).rw(FUNC(sunplus_gcm394_base_device::ioarea_7861_porta_buffer_r), FUNC(sunplus_gcm394_base_device::ioarea_7861_porta_buffer_w)); // 7861 I/O PortA Buffer Register
+ map(0x007862, 0x007862).rw(FUNC(sunplus_gcm394_base_device::ioarea_7862_porta_direction_r), FUNC(sunplus_gcm394_base_device::ioarea_7862_porta_direction_w)); // 7862 I/O PortA Direction Register
+ map(0x007863, 0x007863).rw(FUNC(sunplus_gcm394_base_device::ioarea_7863_porta_attribute_r), FUNC(sunplus_gcm394_base_device::ioarea_7863_porta_attribute_w)); // 7863 I/O PortA Attribute Register
+
+ map(0x007868, 0x007868).rw(FUNC(sunplus_gcm394_base_device::ioarea_7868_portb_r), FUNC(sunplus_gcm394_base_device::ioarea_7868_portb_w)); // on startup // 7868 I/O PortB Data Register
+ map(0x007869, 0x007869).rw(FUNC(sunplus_gcm394_base_device::ioarea_7869_portb_buffer_r), FUNC(sunplus_gcm394_base_device::ioarea_7869_portb_buffer_w)); // 7869 I/O PortB Buffer Register // jak_s500
+ map(0x00786a, 0x00786a).rw(FUNC(sunplus_gcm394_base_device::ioarea_786a_portb_direction_r), FUNC(sunplus_gcm394_base_device::ioarea_786a_portb_direction_w)); // 786a I/O PortB Direction Register
+ map(0x00786b, 0x00786b).rw(FUNC(sunplus_gcm394_base_device::ioarea_786b_portb_attribute_r), FUNC(sunplus_gcm394_base_device::ioarea_786b_portb_attribute_w)); // 786b I/O PortB Attribute Register
+ // 786c I/O PortB Latch / Wakeup
+
+ map(0x007870, 0x007870).rw(FUNC(sunplus_gcm394_base_device::ioarea_7870_portc_r) ,FUNC(sunplus_gcm394_base_device::ioarea_7870_portc_w)); // 7870 I/O PortC Data Register
+ map(0x007871, 0x007871).rw(FUNC(sunplus_gcm394_base_device::ioarea_7871_portc_buffer_r), FUNC(sunplus_gcm394_base_device::ioarea_7871_portc_buffer_w)); // 7871 I/O PortC Buffer Register
+ map(0x007872, 0x007872).rw(FUNC(sunplus_gcm394_base_device::ioarea_7872_portc_direction_r), FUNC(sunplus_gcm394_base_device::ioarea_7872_portc_direction_w)); // 7872 I/O PortC Direction Register
+ map(0x007873, 0x007873).rw(FUNC(sunplus_gcm394_base_device::ioarea_7873_portc_attribute_r), FUNC(sunplus_gcm394_base_device::ioarea_7873_portc_attribute_w)); // 7873 I/O PortC Attribute Register
+
+ // 7874 (data 0x1249) (bkrankp data 0x36db)
+
+ map(0x007878, 0x007878).rw(FUNC(sunplus_gcm394_base_device::ioarea_7878_portd_r) ,FUNC(sunplus_gcm394_base_device::ioarea_7878_portd_w)); // 7878 I/O PortD Data Register
+ map(0x007879, 0x007879).rw(FUNC(sunplus_gcm394_base_device::ioarea_7879_portd_buffer_r), FUNC(sunplus_gcm394_base_device::ioarea_7879_portd_buffer_w)); // 7879 I/O PortD Buffer Register
+ map(0x00787a, 0x00787a).rw(FUNC(sunplus_gcm394_base_device::ioarea_787a_portd_direction_r), FUNC(sunplus_gcm394_base_device::ioarea_787a_portd_direction_w)); // 787a I/O PortD Direction Register
+ map(0x00787b, 0x00787b).rw(FUNC(sunplus_gcm394_base_device::ioarea_787b_portd_attribute_r), FUNC(sunplus_gcm394_base_device::ioarea_787b_portd_attribute_w)); // 787b I/O PortD Attribute Register
+
+ // 787c (data 0x1249) (bkrankp data 0x36db)
+ // 787e (data 0x1249) (bkrankp data 0x36db)
+
+ // 7880
+
+ map(0x007882, 0x007882).rw(FUNC(sunplus_gcm394_base_device::unkarea_7882_r), FUNC(sunplus_gcm394_base_device::unkarea_7882_w));
+ map(0x007883, 0x007883).rw(FUNC(sunplus_gcm394_base_device::unkarea_7883_r), FUNC(sunplus_gcm394_base_device::unkarea_7883_w));
+
+ // 0x7888 (data 0x1249) (bkrankp data 0x36db), written with 7874 / 787c / 787e above
+
+ // ######################################################################################################################################################################################
+ // 78ax - interrupt controller?
+ // ######################################################################################################################################################################################
+
+ map(0x0078a0, 0x0078a0).rw(FUNC(sunplus_gcm394_base_device::unkarea_78a0_r), FUNC(sunplus_gcm394_base_device::unkarea_78a0_w));
+ map(0x0078a1, 0x0078a1).r(FUNC(sunplus_gcm394_base_device::unkarea_78a1_r));
+
+ map(0x0078a4, 0x0078a4).w(FUNC(sunplus_gcm394_base_device::unkarea_78a4_w));
+ map(0x0078a5, 0x0078a5).w(FUNC(sunplus_gcm394_base_device::unkarea_78a5_w));
+ map(0x0078a6, 0x0078a6).w(FUNC(sunplus_gcm394_base_device::unkarea_78a6_w));
+
+ map(0x0078a8, 0x0078a8).w(FUNC(sunplus_gcm394_base_device::unkarea_78a8_w));
+
+ // ######################################################################################################################################################################################
+ // 78bx - timer control?
+ // ######################################################################################################################################################################################
+
+ map(0x0078b0, 0x0078b0).w(FUNC(sunplus_gcm394_base_device::unkarea_78b0_w)); // 78b0 TimeBase A Control Register (P_TimeBaseA_Ctrl)
+ map(0x0078b1, 0x0078b1).w(FUNC(sunplus_gcm394_base_device::unkarea_78b1_w)); // 78b1 TimeBase B Control Register (P_TimeBaseB_Ctrl)
+ map(0x0078b2, 0x0078b2).rw(FUNC(sunplus_gcm394_base_device::unkarea_78b2_r), FUNC(sunplus_gcm394_base_device::unkarea_78b2_w)); // 78b2 TimeBase C Control Register (P_TimeBaseC_Ctrl)
+
+ map(0x0078b8, 0x0078b8).w(FUNC(sunplus_gcm394_base_device::unkarea_78b8_w)); // 78b8 TimeBase Counter Reset Register (P_TimeBase_Reset)
+
+ map(0x0078c0, 0x0078c0).r(FUNC(sunplus_gcm394_base_device::unkarea_78c0_r)); // beijuehh
+
+ map(0x0078d0, 0x0078d0).r(FUNC(sunplus_gcm394_base_device::unkarea_78d0_r)); // jak_s500
+ map(0x0078d8, 0x0078d8).r(FUNC(sunplus_gcm394_base_device::unkarea_78d8_r)); // jak_tsh
+
+
+ // ######################################################################################################################################################################################
+ // 78fx - unknown
+ // ######################################################################################################################################################################################
+
+ map(0x0078f0, 0x0078f0).w(FUNC(sunplus_gcm394_base_device::unkarea_78f0_w));
+
+ map(0x0078fb, 0x0078fb).r(FUNC(sunplus_gcm394_base_device::unkarea_78fb_status_r));
+
+ // ######################################################################################################################################################################################
+ // 793x - misc?
+ // ######################################################################################################################################################################################
+
+ map(0x007904, 0x007904).r(FUNC(sunplus_gcm394_base_device::unkarea_7904_r)); // lazertag after a while
+
+ // possible rtc?
+ map(0x007934, 0x007934).rw(FUNC(sunplus_gcm394_base_device::unkarea_7934_r), FUNC(sunplus_gcm394_base_device::unkarea_7934_w));
+ map(0x007935, 0x007935).rw(FUNC(sunplus_gcm394_base_device::unkarea_7935_r), FUNC(sunplus_gcm394_base_device::unkarea_7935_w));
+ map(0x007936, 0x007936).rw(FUNC(sunplus_gcm394_base_device::unkarea_7936_r), FUNC(sunplus_gcm394_base_device::unkarea_7936_w));
+
+ // ######################################################################################################################################################################################
+ // 794x - SPI
+ // ######################################################################################################################################################################################
+
+ //7940 P_SPI_Ctrl - SPI Control Register
+ //7941 P_SPI_TXStatus - SPI Transmit Status Register
+ map(0x007942, 0x007942).w(FUNC(sunplus_gcm394_base_device::spi_7942_txdata_w)); //7942 P_SPI_TXData - SPI Transmit FIFO Register
+ //7943 P_SPI_RXStatus - SPI Receive Status Register
+ map(0x007944, 0x007944).r(FUNC(sunplus_gcm394_base_device::spi_7944_rxdata_r)); // 7944 P_SPI_RXData - SPI Receive FIFO Register (jak_s500 accelerometer) (also the SPI ROM DMA input port for bkrankp?)
+ map(0x007945, 0x007945).r(FUNC(sunplus_gcm394_base_device::spi_7945_misc_control_reg_r)); // 7945 P_SPI_Misc - SPI Misc Control Register (jak_s500 accelerometer)
+
+ // ######################################################################################################################################################################################
+ // 796x - unknown
+ // ######################################################################################################################################################################################
+
+ // possible adc?
+ map(0x007960, 0x007960).w(FUNC(sunplus_gcm394_base_device::unkarea_7960_w));
+ map(0x007961, 0x007961).rw(FUNC(sunplus_gcm394_base_device::unkarea_7961_r), FUNC(sunplus_gcm394_base_device::unkarea_7961_w));
+
+ // ######################################################################################################################################################################################
+ // 7axx region = system (including dma)
+ // ######################################################################################################################################################################################
+
+ map(0x007a35, 0x007a35).r(FUNC(sunplus_gcm394_base_device::system_7a35_r)); // wlsair60
+ map(0x007a37, 0x007a37).r(FUNC(sunplus_gcm394_base_device::system_7a37_r)); // wlsair60
+ map(0x007a39, 0x007a39).r(FUNC(sunplus_gcm394_base_device::system_7a39_r)); // wlsair60
+ map(0x007a3a, 0x007a3a).r(FUNC(sunplus_gcm394_base_device::system_7a3a_r)); // ?
+ map(0x007a46, 0x007a46).r(FUNC(sunplus_gcm394_base_device::system_7a46_r)); // wlsair60
+ map(0x007a54, 0x007a54).r(FUNC(sunplus_gcm394_base_device::system_7a54_r)); // wlsair60
+
+ map(0x007a80, 0x007a87).rw(FUNC(sunplus_gcm394_base_device::system_dma_params_channel0_r), FUNC(sunplus_gcm394_base_device::system_dma_params_channel0_w));
+ map(0x007a88, 0x007a8f).rw(FUNC(sunplus_gcm394_base_device::system_dma_params_channel1_r), FUNC(sunplus_gcm394_base_device::system_dma_params_channel1_w)); // jak_tsm writes here
+ map(0x007a90, 0x007a97).rw(FUNC(sunplus_gcm394_base_device::system_dma_params_channel2_r), FUNC(sunplus_gcm394_base_device::system_dma_params_channel2_w)); // bkrankp writes here (is this on all types or just SPI?)
+ map(0x007a98, 0x007a9f).rw(FUNC(sunplus_gcm394_base_device::system_dma_params_channel3_r), FUNC(sunplus_gcm394_base_device::system_dma_params_channel3_w)); // not seen, but probably
+
+ map(0x007abe, 0x007abe).rw(FUNC(sunplus_gcm394_base_device::system_dma_memtype_r), FUNC(sunplus_gcm394_base_device::system_dma_memtype_w)); // 7abe - written with DMA stuff (source type for each channel so that device handles timings properly?)
+ map(0x007abf, 0x007abf).rw(FUNC(sunplus_gcm394_base_device::system_dma_status_r), FUNC(sunplus_gcm394_base_device::system_dma_7abf_unk_w));
+
+ // ######################################################################################################################################################################################
+ // 7bxx-7fxx = audio
+ // ######################################################################################################################################################################################
+
+ map(0x007b80, 0x007bbf).rw(m_spg_audio, FUNC(sunplus_gcm394_audio_device::control_r), FUNC(sunplus_gcm394_audio_device::control_w));
+ map(0x007c00, 0x007dff).rw(m_spg_audio, FUNC(sunplus_gcm394_audio_device::audio_r), FUNC(sunplus_gcm394_audio_device::audio_w));
+ map(0x007e00, 0x007fff).rw(m_spg_audio, FUNC(sunplus_gcm394_audio_device::audio_phase_r), FUNC(sunplus_gcm394_audio_device::audio_phase_w));
+
+}
+
+void sunplus_gcm394_base_device::gcm394_internal_map(address_map& map)
+{
+ sunplus_gcm394_base_device::base_internal_map(map);
+
+ // no internal ROM on this model?
+
+ map(0x08000, 0x0ffff).r(FUNC(sunplus_gcm394_base_device::internalrom_lower32_r)).nopw();
+
+ map(0x10000, 0x01ffff).nopr();
+
+ map(0x020000, 0x1fffff).rw(FUNC(sunplus_gcm394_base_device::cs_space_r), FUNC(sunplus_gcm394_base_device::cs_space_w));
+ map(0x200000, 0x3fffff).rw(FUNC(sunplus_gcm394_base_device::cs_bank_space_r), FUNC(sunplus_gcm394_base_device::cs_bank_space_w));
+}
+
+uint16_t sunplus_gcm394_base_device::cs_space_r(offs_t offset)
+{
+ return m_cs_space->read_word(offset);
+}
+
+void sunplus_gcm394_base_device::cs_space_w(offs_t offset, uint16_t data)
+{
+ m_cs_space->write_word(offset, data);
+}
+uint16_t sunplus_gcm394_base_device::cs_bank_space_r(offs_t offset)
+{
+ int bank = m_membankswitch_7810 & 0x3f;
+ int realoffset = offset + (bank * 0x200000) - m_csbase;
+
+ if (realoffset < 0)
+ {
+ logerror("read real offset < 0\n");
+ return 0;
+ }
+
+ return m_cs_space->read_word(realoffset);
+}
+
+void sunplus_gcm394_base_device::cs_bank_space_w(offs_t offset, uint16_t data)
+{
+ int bank = m_membankswitch_7810 & 0x3f;
+ int realoffset = offset + (bank * 0x200000) - m_csbase;
+
+ if (realoffset < 0)
+ {
+ logerror("write real offset < 0\n");
+ return;
+ }
+
+ m_cs_space->write_word(realoffset, data);
+}
+
+
+
+uint16_t sunplus_gcm394_base_device::internalrom_lower32_r(offs_t offset)
+{
+ if (m_boot_mode == 0)
+ {
+ uint16_t* introm = (uint16_t*)m_internalrom->base();
+ return introm[offset];
+ }
+ else
+ {
+ if (!m_cs_space)
+ return 0x0000;
+
+ uint16_t val = m_cs_space->read_word(offset+0x8000);
+ return val;
+ }
+}
+
+
+// GPR27P512A = C2 76
+// HY27UF081G2A = AD F1 80 1D
+// H27U518S2C = AD 76
+
+uint16_t generalplus_gpac800_device::nand_7854_r()
+{
+ // TODO: use actual NAND / Smart Media devices once this is better understood.
+ // The games have extensive checks on startup to determine the flash types, but then it appears that
+ // certain games (eg jak_tsm) will only function correctly with specific ones, even if the code
+ // continues regardless. Others will bail early if they don't get what they want.
+
+ // I think some unSP core maths bugs are causing severe issues after the initial load for jak_tsm
+ // at the moment, possibly the same ones that are causing rendering issues in the jak_gtg bitmap
+ // test and seemingly incorrect road data for jak_car2, either that or the hookup here is very
+ // non-standard outside of the ident codes
+
+ // real TSM code starts at 4c000
+
+
+ //logerror("%s:sunplus_gcm394_base_device::nand_7854_r\n", machine().describe_context());
+
+ if (m_nandcommand == 0x90) // read ident
+ {
+ logerror("%s:sunplus_gcm394_base_device::nand_7854_r READ IDENT byte %d\n", machine().describe_context(), m_curblockaddr);
+
+ uint8_t data = 0x00;
+
+ if (m_romtype == 0)
+ {
+ if (m_curblockaddr == 0)
+ data = 0xc2;
+ else
+ data = 0x76;
+ }
+ else if (m_romtype == 1)
+ {
+ if (m_curblockaddr == 0)
+ data = 0xad;
+ else if (m_curblockaddr == 1)
+ data = 0x76;
+ }
+ else
+ {
+ if (m_curblockaddr == 0)
+ data = 0xad;
+ else if (m_curblockaddr == 1)
+ data = 0xf1;
+ else if (m_curblockaddr == 2)
+ data = 0x80;
+ else if (m_curblockaddr == 3)
+ data = 0x1d;
+ }
+
+ m_curblockaddr++;
+
+ return data;
+ }
+ else if (m_nandcommand == 0x00 || m_nandcommand == 0x01 || m_nandcommand == 0x50)
+ {
+ //logerror("%s:sunplus_gcm394_base_device::nand_7854_r READ DATA byte %d\n", machine().describe_context(), m_curblockaddr);
+
+ uint8_t data = m_nand_read_cb(m_effectiveaddress + m_curblockaddr);
+
+ m_curblockaddr++;
+
+ return data;
+ }
+ else if (m_nandcommand == 0x70) // read status
+ {
+ logerror("%s:sunplus_gcm394_base_device::nand_7854_r READ STATUS byte %d\n", machine().describe_context(), m_curblockaddr);
+
+ return 0xffff;
+ }
+ else
+ {
+ logerror("%s:sunplus_gcm394_base_device::nand_7854_r READ UNKNOWN byte %d\n", machine().describe_context(), m_curblockaddr);
+ return 0xffff;
+ }
+
+ return 0x0000;
+}
+
+// 7998
+
+void generalplus_gpac800_device::nand_command_w(uint16_t data)
+{
+ logerror("%s:sunplus_gcm394_base_device::nand_command_w %04x\n", machine().describe_context(), data);
+ m_nandcommand = data;
+}
+
+void generalplus_gpac800_device::nand_addr_low_w(uint16_t data)
+{
+ logerror("%s:sunplus_gcm394_base_device::nand_addr_low_w %04x\n", machine().describe_context(), data);
+ m_nand_addr_low = data;
+ m_curblockaddr = 0;
+}
+
+void generalplus_gpac800_device::recalculate_calculate_effective_nand_address()
+{
+ uint8_t type = m_nand_7856 & 0xf;
+ uint8_t shift = 0;
+ uint32_t page_offset = 0;
+
+ if (type == 7)
+ shift = 4;
+ else if (type == 11)
+ shift = 5;
+
+ if (m_nandcommand == 0x01)
+ page_offset = 256;
+ else if (m_nandcommand == 0x50)
+ page_offset = 512;
+
+ uint32_t nandaddress = (m_nand_addr_high << 16) | m_nand_addr_low;
+
+ if (m_nand_7850 & 0x4000)
+ nandaddress *= 2;
+
+ uint32_t page = type ? nandaddress : /*(m_nand_7850 & 0x4000) ?*/ nandaddress >> 8 /*: nandaddress >> 9*/;
+ m_effectiveaddress = (page * 528 + page_offset) << shift;
+
+ logerror("%s: Requested address is %08x, translating to %08x\n", machine().describe_context(), nandaddress, m_effectiveaddress);
+}
+
+void generalplus_gpac800_device::nand_addr_high_w(uint16_t data)
+{
+ logerror("%s:sunplus_gcm394_base_device::nand_addr_high_w %04x\n", machine().describe_context(), data);
+ m_nand_addr_high = data;
+
+ recalculate_calculate_effective_nand_address();
+
+ m_curblockaddr = 0;
+}
+
+void generalplus_gpac800_device::nand_dma_ctrl_w(uint16_t data)
+{
+ logerror("%s:sunplus_gcm394_base_device::nand_dma_ctrl_w(?) %04x\n", machine().describe_context(), data);
+ m_nand_dma_ctrl = data;
+}
+
+uint16_t generalplus_gpac800_device::nand_7850_status_r()
+{
+ // 0x8000 = ready
+ return m_nand_7850 | 0x8000;
+}
+
+void generalplus_gpac800_device::nand_7850_w(uint16_t data)
+{
+ logerror("%s:sunplus_gcm394_base_device::nand_7850_w %04x\n", machine().describe_context(), data);
+ m_nand_7850 = data;
+}
+
+void generalplus_gpac800_device::nand_7856_type_w(uint16_t data)
+{
+ logerror("%s:sunplus_gcm394_base_device::nand_7856_type_w %04x\n", machine().describe_context(), data);
+ m_nand_7856 = data;
+
+ recalculate_calculate_effective_nand_address();
+
+ m_curblockaddr = 0;
+}
+
+void generalplus_gpac800_device::nand_7857_w(uint16_t data)
+{
+ logerror("%s:sunplus_gcm394_base_device::nand_7857_w %04x\n", machine().describe_context(), data);
+ m_nand_7857 = data;
+}
+
+void generalplus_gpac800_device::nand_785b_w(uint16_t data)
+{
+ logerror("%s:sunplus_gcm394_base_device::nand_785b_w %04x\n", machine().describe_context(), data);
+ m_nand_785b = data;
+}
+
+void generalplus_gpac800_device::nand_785c_w(uint16_t data)
+{
+ logerror("%s:sunplus_gcm394_base_device::nand_785c_w %04x\n", machine().describe_context(), data);
+ m_nand_785c = data;
+}
+
+void generalplus_gpac800_device::nand_785d_w(uint16_t data)
+{
+ logerror("%s:sunplus_gcm394_base_device::nand_785d_w %04x\n", machine().describe_context(), data);
+ m_nand_785d = data;
+}
+
+// [:maincpu] ':maincpu' (00146D) jak_tsm
+uint16_t generalplus_gpac800_device::nand_785e_r()
+{
+ return 0x0000;
+}
+
+//[:maincpu] ':maincpu' (001490) jak_tsm
+uint16_t generalplus_gpac800_device::nand_ecc_low_byte_error_flag_1_r()
+{
+ return 0x0000;
+}
+
+/*
+UNMAPPED reads writes
+
+jak_tsm uses these (all iniitalized near start)
+unclear if these are specific to the GPAC800 type, or present in the older types
+
+[:maincpu] ':maincpu' (00043F):sunplus_gcm394_base_device::unk_w @ 0x780a (data 0x0000)
+[:maincpu] ':maincpu' (000442):sunplus_gcm394_base_device::unk_w @ 0x7808 (data 0x0000)
+[:maincpu] ':maincpu' (000445):sunplus_gcm394_base_device::unk_w @ 0x782f (data 0x0002)
+[:maincpu] ':maincpu' (000449):sunplus_gcm394_base_device::unk_w @ 0x783d (data 0x05d9)
+[:maincpu] ':maincpu' (00044D):sunplus_gcm394_base_device::unk_w @ 0x783c (data 0x0a57)
+[:maincpu] ':maincpu' (000451):sunplus_gcm394_base_device::unk_w @ 0x783b (data 0x2400)
+[:maincpu] ':maincpu' (000454):sunplus_gcm394_base_device::unk_w @ 0x783e (data 0x0002)
+[:maincpu] ':maincpu' (000458):sunplus_gcm394_base_device::unk_w @ 0x783a (data 0x3011)
+[:maincpu] ':maincpu' (00045B):sunplus_gcm394_base_device::unk_w @ 0x7874 (data 0x0000)
+[:maincpu] ':maincpu' (00045D):sunplus_gcm394_base_device::unk_w @ 0x787c (data 0x0000)
+[:maincpu] ':maincpu' (00045F):sunplus_gcm394_base_device::unk_w @ 0x7888 (data 0x0000)
+[:maincpu] ':maincpu' (000461):sunplus_gcm394_base_device::unk_w @ 0x787e (data 0x0000)
+
+jak_car2 uses these
+
+[:maincpu] ':maincpu' (004056):sunplus_gcm394_base_device::unk_w @ 0x782f (data 0x0002)
+[:maincpu] ':maincpu' (004059):sunplus_gcm394_base_device::unk_w @ 0x783d (data 0x05d9)
+[:maincpu] ':maincpu' (00405C):sunplus_gcm394_base_device::unk_w @ 0x783c (data 0x0a57)
+[:maincpu] ':maincpu' (00405F):sunplus_gcm394_base_device::unk_w @ 0x783b (data 0x2400)
+[:maincpu] ':maincpu' (004062):sunplus_gcm394_base_device::unk_w @ 0x783e (data 0x0002)
+[:maincpu] ':maincpu' (004065):sunplus_gcm394_base_device::unk_w @ 0x783a (data 0x3011)
+[:maincpu] ':maincpu' (004069):sunplus_gcm394_base_device::unk_r @ 0x7880
+[:maincpu] ':maincpu' (00406F):sunplus_gcm394_base_device::unk_w @ 0x7874 (data 0x1249)
+[:maincpu] ':maincpu' (004071):sunplus_gcm394_base_device::unk_w @ 0x787c (data 0x1249)
+[:maincpu] ':maincpu' (004073):sunplus_gcm394_base_device::unk_w @ 0x7888 (data 0x1249)
+[:maincpu] ':maincpu' (004075):sunplus_gcm394_base_device::unk_w @ 0x787e (data 0x1249)
+[:maincpu] ':maincpu' (004088):sunplus_gcm394_base_device::unk_w @ 0x7841 (data 0x000f)
+[:maincpu] ':maincpu' (00408F):sunplus_gcm394_base_device::unk_w @ 0x780a (data 0x0000)
+[:maincpu] ':maincpu' (004092):sunplus_gcm394_base_device::unk_w @ 0x7808 (data 0x0002)
+
+[:maincpu] ':maincpu' (03000A):sunplus_gcm394_base_device::unk_w @ 0x7874 (data 0x36db)
+[:maincpu] ':maincpu' (03000C):sunplus_gcm394_base_device::unk_w @ 0x787c (data 0x36db)
+[:maincpu] ':maincpu' (03000E):sunplus_gcm394_base_device::unk_w @ 0x7888 (data 0x36db)
+[:maincpu] ':maincpu' (030010):sunplus_gcm394_base_device::unk_w @ 0x787e (data 0x36db)
+[:maincpu] ':maincpu' (030013):sunplus_gcm394_base_device::unk_w @ 0x787f (data 0x0010)
+[:maincpu] ':maincpu' (03001D):sunplus_gcm394_base_device::unk_w @ 0x7804 (data 0x1c7f)
+[:maincpu] ':maincpu' (030023):sunplus_gcm394_base_device::unk_w @ 0x7805 (data 0xcdf0)
+[:maincpu] ':maincpu' (03E645):sunplus_gcm394_base_device::unk_w @ 0x7861 (data 0x1f66)
+[:maincpu] ':maincpu' (03E64C):sunplus_gcm394_base_device::unk_w @ 0x786b (data 0x0000)
+[:maincpu] ':maincpu' (03E64F):sunplus_gcm394_base_device::unk_w @ 0x7869 (data 0x0000)
+[:maincpu] ':maincpu' (03E652):sunplus_gcm394_base_device::unk_w @ 0x786a (data 0x0000)
+[:maincpu] ':maincpu' (03E65B):sunplus_gcm394_base_device::unk_w @ 0x7966 (data 0x0001)
+[:maincpu] ':maincpu' (03CBD0):sunplus_gcm394_base_device::unk_w @ 0x7871 (data 0x0000)
+
+-- this one seems like a common alt type of DMA, used in both hw types as it polls 707c status before doing it
+[:maincpu] ':maincpu' (03B4C7):sunplus_gcm394_base_device::unk_w @ 0x707c (data 0x0001)
+-- also video / alt dma?
+[:maincpu] ':maincpu' (068C15):sunplus_gcm394_base_device::unk_r @ 0x707e
+
+beambox sets things up with different values (ultimately stalls on some check, maybe seeprom?)
+
+[:maincpu] ':maincpu' (00043F):sunplus_gcm394_base_device::unk_w @ 0x780a (data 0x0000)
+[:maincpu] ':maincpu' (000442):sunplus_gcm394_base_device::unk_w @ 0x7808 (data 0x0000)
+[:maincpu] ':maincpu' (000445):sunplus_gcm394_base_device::unk_w @ 0x782f (data 0x0002)
+[:maincpu] ':maincpu' (000449):sunplus_gcm394_base_device::unk_w @ 0x783d (data 0x05d9)
+[:maincpu] ':maincpu' (00044D):sunplus_gcm394_base_device::unk_w @ 0x783c (data 0x0f58)
+[:maincpu] ':maincpu' (000451):sunplus_gcm394_base_device::unk_w @ 0x783b (data 0x2400)
+[:maincpu] ':maincpu' (000454):sunplus_gcm394_base_device::unk_w @ 0x783e (data 0x0002)
+[:maincpu] ':maincpu' (000458):sunplus_gcm394_base_device::unk_w @ 0x783a (data 0x4011)
+[:maincpu] ':maincpu' (00045C):sunplus_gcm394_base_device::unk_w @ 0x7874 (data 0x2492) -- note pair of 4, but different values to above games
+[:maincpu] ':maincpu' (00045E):sunplus_gcm394_base_device::unk_w @ 0x787c (data 0x2492)
+[:maincpu] ':maincpu' (000460):sunplus_gcm394_base_device::unk_w @ 0x7888 (data 0x2492)
+[:maincpu] ':maincpu' (000462):sunplus_gcm394_base_device::unk_w @ 0x787e (data 0x2492)
+
+vbaby code is very differet, attempts to load NAND block manually, not with DMA
+
+*/
+
+
+// all tilemap registers etc. appear to be in the same place as the above system, including the 'extra' ones not on the earlier models
+// so it's likely this is built on top of that just with NAND support
+void generalplus_gpac800_device::gpac800_internal_map(address_map& map)
+{
+ sunplus_gcm394_base_device::base_internal_map(map);
+
+ // 785x = NAND device
+ map(0x007850, 0x007850).rw(FUNC(generalplus_gpac800_device::nand_7850_status_r), FUNC(generalplus_gpac800_device::nand_7850_w)); // NAND Control Reg
+ map(0x007851, 0x007851).w(FUNC(generalplus_gpac800_device::nand_command_w)); // NAND Command Reg
+ map(0x007852, 0x007852).w(FUNC(generalplus_gpac800_device::nand_addr_low_w)); // NAND Low Address Reg
+ map(0x007853, 0x007853).w(FUNC(generalplus_gpac800_device::nand_addr_high_w)); // NAND High Address Reg
+ map(0x007854, 0x007854).r(FUNC(generalplus_gpac800_device::nand_7854_r)); // NAND Data Reg
+ map(0x007855, 0x007855).w(FUNC(generalplus_gpac800_device::nand_dma_ctrl_w)); // NAND DMA / INT Control
+ map(0x007856, 0x007856).w(FUNC(generalplus_gpac800_device::nand_7856_type_w)); // usually 0x0021?
+ map(0x007857, 0x007857).w(FUNC(generalplus_gpac800_device::nand_7857_w));
+
+ // most of these are likely ECC stuff for testing the ROM?
+ map(0x00785b, 0x00785b).w(FUNC(generalplus_gpac800_device::nand_785b_w));
+ map(0x00785c, 0x00785c).w(FUNC(generalplus_gpac800_device::nand_785c_w));
+ map(0x00785d, 0x00785d).w(FUNC(generalplus_gpac800_device::nand_785d_w));
+ map(0x00785e, 0x00785e).r(FUNC(generalplus_gpac800_device::nand_785e_r)); // also ECC status related?
+ map(0x00785f, 0x00785f).r(FUNC(generalplus_gpac800_device::nand_ecc_low_byte_error_flag_1_r)); // ECC Low Byte Error Flag 1 (maybe)
+
+ // 128kwords internal ROM
+ //map(0x08000, 0x0ffff).rom().region("internal", 0); // lower 32kwords of internal ROM is visible / shadowed depending on boot pins and register
+ map(0x08000, 0x0ffff).r(FUNC(generalplus_gpac800_device::internalrom_lower32_r)).nopw();
+ map(0x10000, 0x27fff).rom().region("internal", 0x10000); // upper 96kwords of internal ROM is always visible
+ map(0x28000, 0x2ffff).noprw(); // reserved
+ // 0x30000+ is CS access
+
+ map(0x030000, 0x1fffff).rw(FUNC(generalplus_gpac800_device::cs_space_r), FUNC(generalplus_gpac800_device::cs_space_w));
+ map(0x200000, 0x3fffff).rw(FUNC(generalplus_gpac800_device::cs_bank_space_r), FUNC(generalplus_gpac800_device::cs_bank_space_w));
+}
+
+
+uint16_t generalplus_gpspispi_device::spi_unk_7943_r()
+{
+ return 0x0007;
+}
+
+void generalplus_gpspispi_device::gpspispi_internal_map(address_map& map)
+{
+ sunplus_gcm394_base_device::base_internal_map(map);
+
+ map(0x007943, 0x007943).r(FUNC(generalplus_gpspispi_device::spi_unk_7943_r));
+
+ map(0x008000, 0x00ffff).rom().region("internal", 0);
+}
+
+
+void sunplus_gcm394_base_device::device_start()
+{
+ unsp_20_device::device_start();
+
+ m_cs_callback.resolve();
+
+ m_unk_timer = timer_alloc(FUNC(sunplus_gcm394_base_device::unknown_tick), this);
+ m_unk_timer->adjust(attotime::never);
+
+ save_item(NAME(m_dma_params));
+ save_item(NAME(m_7803));
+ save_item(NAME(m_7807));
+ save_item(NAME(m_membankswitch_7810));
+ save_item(NAME(m_7816));
+ save_item(NAME(m_7817));
+ save_item(NAME(m_7819));
+ save_item(NAME(m_782x));
+ save_item(NAME(m_782d));
+ save_item(NAME(m_7835));
+ save_item(NAME(m_7860));
+ save_item(NAME(m_7861));
+ save_item(NAME(m_7862_porta_direction));
+ save_item(NAME(m_7863_porta_attribute));
+
+ save_item(NAME(m_786a_portb_direction));
+ save_item(NAME(m_786b_portb_attribute));
+
+ save_item(NAME(m_7870));
+ //save_item(NAME(m_7871));
+ save_item(NAME(m_7872_portc_direction));
+ save_item(NAME(m_7873_portc_attribute));
+ save_item(NAME(m_7882));
+ save_item(NAME(m_7883));
+ save_item(NAME(m_78a0));
+ save_item(NAME(m_78a4));
+ save_item(NAME(m_78a5));
+ save_item(NAME(m_78a6));
+ save_item(NAME(m_78a8));
+ save_item(NAME(m_78b0));
+ save_item(NAME(m_78b1));
+ save_item(NAME(m_78b2));
+ save_item(NAME(m_78b8));
+ save_item(NAME(m_78f0));
+ save_item(NAME(m_78fb));
+ save_item(NAME(m_7934));
+ save_item(NAME(m_7935));
+ save_item(NAME(m_7936));
+ save_item(NAME(m_7960));
+ save_item(NAME(m_7961));
+ save_item(NAME(m_system_dma_memtype));
+ save_item(NAME(m_csbase));
+ save_item(NAME(m_romtype));
+}
+
+void sunplus_gcm394_base_device::device_reset()
+{
+ unsp_20_device::device_reset();
+
+ for (int j = 0; j < 3; j++)
+ {
+ for (int i = 0; i < 7; i++)
+ {
+ m_dma_params[i][j] = 0x0000;
+ }
+ m_dma_latched[j] = false;
+ }
+
+ // 78xx unknown
+
+ m_78fb = 0x0000;
+ m_782d = 0x0000;
+
+ m_7807 = 0x0000;
+
+ m_membankswitch_7810 = 0x0001;
+
+ m_7816 = 0x0000;
+ m_7817 = 0x0000;
+
+ m_7819 = 0x0000;
+
+ m_782x[0] = 0x0000;
+ m_782x[1] = 0x0000;
+ m_782x[2] = 0x0000;
+ m_782x[3] = 0x0000;
+ m_782x[4] = 0x0000;
+
+ m_7835 = 0x0000;
+
+ m_7860 = 0x0000;
+
+ m_7861 = 0x0000;
+
+ m_7862_porta_direction = 0x0000;
+ m_7863_porta_attribute = 0x0000;
+
+ m_786a_portb_direction = 0x0000;
+ m_786b_portb_attribute = 0x0000;
+
+ m_7870 = 0x0000;
+
+ //m_7871 = 0x0000;
+
+ m_7872_portc_direction = 0x0000;
+ m_7873_portc_attribute = 0x0000;
+
+ m_7882 = 0x0000;
+ m_7883 = 0x0000;
+
+ m_78a0 = 0x0000;
+
+ m_78a4 = 0x0000;
+ m_78a5 = 0x0000;
+ m_78a6 = 0x0000;
+
+ m_78a8 = 0x0000;
+
+ m_78b0 = 0x0000;
+ m_78b1 = 0x0000;
+ m_78b2 = 0x0000;
+
+ m_78b8 = 0x0000;
+ m_78f0 = 0x0000;
+
+ // 79xx unknown
+
+ m_7934 = 0x0000;
+ m_7935 = 0x0000;
+ m_7936 = 0x0000;
+
+ m_7960 = 0x0000;
+ m_7961 = 0x0000;
+
+ m_system_dma_memtype = 0x0000;
+
+ m_unk_timer->adjust(attotime::from_hz(60), 0, attotime::from_hz(60));
+
+ m_spg_video->set_video_spaces(this->space(AS_PROGRAM), *m_cs_space, m_csbase);
+ m_spg_video->reset();
+}
+
+void generalplus_gpac800_device::device_reset()
+{
+ sunplus_gcm394_base_device::device_reset();
+
+ m_nand_addr_low = 0x0000;
+ m_nand_addr_high = 0x0000;
+ m_nand_dma_ctrl = 0x0000;
+ m_nand_7850 = 0x0000;
+ m_nand_785d = 0x0000;
+ m_nand_785c = 0x0000;
+ m_nand_785b = 0x0000;
+ m_nand_7856 = 0x0000;
+ m_nand_7857 = 0x0000;
+}
+
+IRQ_CALLBACK_MEMBER(sunplus_gcm394_base_device::irq_vector_cb)
+{
+ //logerror("irq_vector_cb %d\n", irqline);
+
+ if (irqline == UNSP_IRQ6_LINE)
+ set_state_unsynced(UNSP_IRQ6_LINE, CLEAR_LINE);
+
+ if (irqline == UNSP_IRQ4_LINE)
+ set_state_unsynced(UNSP_IRQ4_LINE, CLEAR_LINE);
+
+ return 0;
+}
+
+
+void sunplus_gcm394_base_device::checkirq6()
+{
+/*
+ if (m_7935 & 0x0100)
+ set_state_unsynced(UNSP_IRQ6_LINE, ASSERT_LINE);
+ else
+ set_state_unsynced(UNSP_IRQ6_LINE, CLEAR_LINE);
+*/
+}
+
+/* the IRQ6 interrupt on Wrlshunt
+ reads 78a1, checks bit 0400
+ if it IS set, just increases value in RAM at 1a2e (no ack)
+ if it ISN'T set, then read/write 78b2 (ack something?) then increase value in RAM at 1a2e
+ (smartfp doesn't touch these addresses? but instead reads/writes 7935, alt ack?)
+
+ wrlshunt also has an IRQ4
+ it always reads/writes 78c0 before executing payload (ack?)
+ payload is a lot of manipulation of values in RAM, no registers touched
+
+ wrlshunt also has FIQ
+ no ack mechanism, for sound timer maybe (as it appears to be on spg110)
+
+
+ ----
+
+ IRQ5 is video IRQ
+ in both games writing 0x0001 to 7063 seems to be an ack mechanism
+ wrlshunt also checks bit 0x0040 of 7863 and will ack that too with alt code paths
+
+ 7863 is therefore some kind of 'video irq source' ?
+
+*/
+
+
+TIMER_CALLBACK_MEMBER(sunplus_gcm394_base_device::unknown_tick)
+{
+ m_7935 |= 0x0100;
+ set_state_unsynced(UNSP_IRQ6_LINE, ASSERT_LINE);
+ //set_state_unsynced(UNSP_IRQ4_LINE, ASSERT_LINE);
+
+ // checkirq6();
+}
+
+
+void sunplus_gcm394_base_device::audioirq_w(int state)
+{
+ //set_state_unsynced(UNSP_IRQ5_LINE, state);
+}
+
+void sunplus_gcm394_base_device::videoirq_w(int state)
+{
+ set_state_unsynced(UNSP_IRQ5_LINE, state);
+}
+
+uint16_t sunplus_gcm394_base_device::read_space(uint32_t offset)
+{
+ address_space& space = this->space(AS_PROGRAM);
+ uint16_t val;
+ if (offset < m_csbase)
+ {
+ val = space.read_word(offset);
+ }
+ else
+ {
+ val = m_cs_space->read_word(offset-m_csbase);
+ }
+
+ return val;
+}
+
+
+
+void sunplus_gcm394_base_device::write_space(uint32_t offset, uint16_t data)
+{
+ address_space& space = this->space(AS_PROGRAM);
+ if (offset < m_csbase)
+ {
+ space.write_word(offset, data);
+ }
+ else
+ {
+ m_cs_space->write_word(offset-m_csbase, data);
+ }
+}
+
+
+
+void sunplus_gcm394_base_device::device_add_mconfig(machine_config &config)
+{
+ SUNPLUS_GCM394_AUDIO(config, m_spg_audio, DERIVED_CLOCK(1, 1));
+ m_spg_audio->write_irq_callback().set(FUNC(sunplus_gcm394_base_device::audioirq_w));
+ m_spg_audio->space_read_callback().set(FUNC(sunplus_gcm394_base_device::read_space));
+
+ m_spg_audio->add_route(0, *this, 1.0, AUTO_ALLOC_INPUT, 0);
+ m_spg_audio->add_route(1, *this, 1.0, AUTO_ALLOC_INPUT, 1);
+
+ GCM394_VIDEO(config, m_spg_video, DERIVED_CLOCK(1, 1), DEVICE_SELF, m_screen);
+ m_spg_video->write_video_irq_callback().set(FUNC(sunplus_gcm394_base_device::videoirq_w));
+ m_spg_video->space_read_callback().set(FUNC(sunplus_gcm394_base_device::read_space));
+}
+
+