From 884a2fd070f5c2f851cf9e165f967d6df8e4f83e Mon Sep 17 00:00:00 2001 From: David Haywood Date: Sun, 13 Jan 2019 16:19:06 +0000 Subject: new NOT WORKING --- Classic Arcade Pinball (JAKKS Pacific TV Game) [Sean Riddle, David Haywood] (#4502) * new NOT WORKING --- Classic Arcade Pinball (JAKKS Pacific TV Game) [Sean Riddle, David Haywood] * move to new driver instead (nw) * minor note updates (nw) * map inputs in matelcs (currently needs a hack to boot, so won't show anything yet) also removed a pointless bitswapping in a read function for some other stuff in the driver, and just correct the ports instead * fix a typo (nw) * note (nw) --- scripts/src/machine.lua | 2 ++ 1 file changed, 2 insertions(+) (limited to 'scripts/src/machine.lua') diff --git a/scripts/src/machine.lua b/scripts/src/machine.lua index 4e74fd9e6c3..14a2050c3a5 100644 --- a/scripts/src/machine.lua +++ b/scripts/src/machine.lua @@ -2622,6 +2622,8 @@ if (MACHINES["SPG2XX"]~=null) then files { MAME_DIR .. "src/devices/machine/spg2xx.cpp", MAME_DIR .. "src/devices/machine/spg2xx.h", + MAME_DIR .. "src/devices/machine/spg110.cpp", + MAME_DIR .. "src/devices/machine/spg110.h", } end -- cgit v1.2.3-70-g09d2 From 9ef08696cc5e709af1bf66d44ae472cd80449484 Mon Sep 17 00:00:00 2001 From: Olivier Galibert Date: Tue, 22 Jan 2019 22:20:54 +0100 Subject: wd33c9x: Convert the remaining drivers, kill the old driver [O. Galibert] --- scripts/src/machine.lua | 13 - scripts/target/mame/arcade.lua | 1 - scripts/target/mame/mess.lua | 1 - src/devices/bus/amiga/zorro/a590.cpp | 49 +- src/devices/bus/amiga/zorro/a590.h | 8 +- src/devices/machine/wd33c93.cpp | 984 ----------------------------------- src/devices/machine/wd33c93.h | 112 ---- src/devices/machine/wd33c9x.cpp | 8 +- src/devices/machine/wd33c9x.h | 12 +- src/mame/drivers/cps3.cpp | 2 +- src/mame/drivers/indy_indigo2.cpp | 16 +- src/mame/drivers/r9751.cpp | 40 +- src/mame/machine/hpc1.cpp | 6 +- src/mame/machine/hpc1.h | 2 +- src/mame/machine/hpc3.h | 4 +- 15 files changed, 101 insertions(+), 1157 deletions(-) delete mode 100644 src/devices/machine/wd33c93.cpp delete mode 100644 src/devices/machine/wd33c93.h (limited to 'scripts/src/machine.lua') diff --git a/scripts/src/machine.lua b/scripts/src/machine.lua index 14a2050c3a5..351c47a9232 100644 --- a/scripts/src/machine.lua +++ b/scripts/src/machine.lua @@ -2936,19 +2936,6 @@ if (MACHINES["WD2010"]~=null) then } end ---------------------------------------------------- --- ---@src/devices/machine/wd33c93.h,MACHINES["WD33C93"] = true ---------------------------------------------------- - -if (MACHINES["WD33C93"]~=null) then - MACHINES["SCSI"] = true - files { - MAME_DIR .. "src/devices/machine/wd33c93.cpp", - MAME_DIR .. "src/devices/machine/wd33c93.h", - } -end - --------------------------------------------------- -- --@src/devices/machine/wd33c9x.h,MACHINES["WD33C9X"] = true diff --git a/scripts/target/mame/arcade.lua b/scripts/target/mame/arcade.lua index f92138f11cc..71f980741b9 100644 --- a/scripts/target/mame/arcade.lua +++ b/scripts/target/mame/arcade.lua @@ -607,7 +607,6 @@ MACHINES["V3021"] = true MACHINES["WD_FDC"] = true MACHINES["WD11C00_17"] = true MACHINES["WD2010"] = true -MACHINES["WD33C93"] = true MACHINES["WD33C9X"] = true MACHINES["X2212"] = true MACHINES["X76F041"] = true diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua index 2b08275346e..700b01376ae 100644 --- a/scripts/target/mame/mess.lua +++ b/scripts/target/mame/mess.lua @@ -622,7 +622,6 @@ MACHINES["V3021"] = true MACHINES["WD_FDC"] = true MACHINES["WD11C00_17"] = true MACHINES["WD2010"] = true -MACHINES["WD33C93"] = true MACHINES["WD33C9X"] = true MACHINES["WD7600"] = true MACHINES["X2201"] = true diff --git a/src/devices/bus/amiga/zorro/a590.cpp b/src/devices/bus/amiga/zorro/a590.cpp index 32328b2f944..06231c4bd0a 100644 --- a/src/devices/bus/amiga/zorro/a590.cpp +++ b/src/devices/bus/amiga/zorro/a590.cpp @@ -10,8 +10,9 @@ #include "emu.h" #include "a590.h" -#include "bus/scsi/scsi.h" -#include "bus/scsi/scsihd.h" +#include "machine/nscsi_bus.h" +#include "machine/nscsi_cd.h" +#include "machine/nscsi_hd.h" //************************************************************************** @@ -114,6 +115,19 @@ ioport_constructor a2091_device::device_input_ports() const // device_add_mconfig - add device configuration //------------------------------------------------- +void dmac_hdc_device::scsi_devices(device_slot_interface &device) +{ + device.option_add("cdrom", NSCSI_CDROM); + device.option_add("harddisk", NSCSI_HARDDISK); +} + +void dmac_hdc_device::wd33c93(device_t *device) +{ + device->set_clock(10000000); + downcast(device)->irq_cb().set(*this, FUNC(dmac_hdc_device::scsi_irq_w)); + downcast(device)->drq_cb().set(*this, FUNC(dmac_hdc_device::scsi_drq_w)); +} + void dmac_hdc_device::device_add_mconfig(machine_config &config) { amiga_dmac_device &dmac(AMIGA_DMAC(config, "dmac", 0)); @@ -122,12 +136,16 @@ void dmac_hdc_device::device_add_mconfig(machine_config &config) dmac.int_handler().set(FUNC(dmac_hdc_device::dmac_int_w)); dmac.cfgout_handler().set(FUNC(dmac_hdc_device::dmac_cfgout_w)); - scsi_port_device &scsi(SCSI_PORT(config, "scsi")); - scsi.set_slot_device(1, "harddisk", SCSIHD, DEVICE_INPUT_DEFAULTS_NAME(SCSI_ID_1)); - - wd33c93_device &scsi_ctrl(WD33C93(config, "wd33c93")); - scsi_ctrl.set_scsi_port("scsi"); - scsi_ctrl.irq_cb().set(FUNC(dmac_hdc_device::scsi_irq_w)); + NSCSI_BUS(config, "scsi", 0); + NSCSI_CONNECTOR(config, "scsi:0", scsi_devices, nullptr, false); + NSCSI_CONNECTOR(config, "scsi:1", scsi_devices, "harddisk", false); + NSCSI_CONNECTOR(config, "scsi:3", scsi_devices, nullptr, false); + NSCSI_CONNECTOR(config, "scsi:4", scsi_devices, nullptr, false); + NSCSI_CONNECTOR(config, "scsi:5", scsi_devices, nullptr, false); + NSCSI_CONNECTOR(config, "scsi:6", scsi_devices, nullptr, false); + NSCSI_CONNECTOR(config, "scsi:7", scsi_devices, nullptr, false); + NSCSI_CONNECTOR(config, "scsi:0").option_set("wd33c93", WD33C93A) + .machine_config([this](device_t *device) { wd33c93(device); }); } @@ -205,7 +223,7 @@ dmac_hdc_device::dmac_hdc_device(const machine_config &mconfig, device_type type device_t(mconfig, type, tag, owner, clock), m_int6(false), m_dmac(*this, "dmac"), - m_wdc(*this, "wd33c93") + m_wdc(*this, "scsi:7:wd33c93") { } @@ -327,8 +345,8 @@ READ8_MEMBER( dmac_hdc_device::dmac_scsi_r ) { switch (offset) { - case 0x48: return m_wdc->read(space, 0); - case 0x49: return m_wdc->read(space, 1); + case 0x48: return m_wdc->indir_addr_r(); + case 0x49: return m_wdc->indir_reg_r(); } return 0xff; @@ -338,8 +356,8 @@ WRITE8_MEMBER( dmac_hdc_device::dmac_scsi_w ) { switch (offset) { - case 0x48: m_wdc->write(space, 0, data); break; - case 0x49: m_wdc->write(space, 1, data); break; + case 0x48: m_wdc->indir_addr_w(data); break; + case 0x49: m_wdc->indir_reg_w(data); break; } } @@ -356,3 +374,8 @@ WRITE_LINE_MEMBER( dmac_hdc_device::scsi_irq_w ) // should be or'ed with xt-ide IRQ m_dmac->intx_w(state); } + +WRITE_LINE_MEMBER( dmac_hdc_device::scsi_drq_w ) +{ + m_dmac->xdreq_w(state); +} diff --git a/src/devices/bus/amiga/zorro/a590.h b/src/devices/bus/amiga/zorro/a590.h index cf051fd30dc..62ea3bd189f 100644 --- a/src/devices/bus/amiga/zorro/a590.h +++ b/src/devices/bus/amiga/zorro/a590.h @@ -15,7 +15,7 @@ #include "zorro.h" #include "machine/dmac.h" -#include "machine/wd33c93.h" +#include "machine/wd33c9x.h" //************************************************************************** @@ -51,7 +51,7 @@ protected: // sub-devices required_device m_dmac; - required_device m_wdc; + required_device m_wdc; std::vector m_ram; @@ -61,6 +61,10 @@ private: DECLARE_WRITE_LINE_MEMBER( dmac_int_w ); DECLARE_WRITE_LINE_MEMBER( dmac_cfgout_w ) { cfgout_w(state); } DECLARE_WRITE_LINE_MEMBER( scsi_irq_w ); + DECLARE_WRITE_LINE_MEMBER( scsi_drq_w ); + + static void scsi_devices(device_slot_interface &device); + void wd33c93(device_t *device); }; // ======================> a590_device diff --git a/src/devices/machine/wd33c93.cpp b/src/devices/machine/wd33c93.cpp deleted file mode 100644 index fcbb45957af..00000000000 --- a/src/devices/machine/wd33c93.cpp +++ /dev/null @@ -1,984 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:ElSemi, R. Belmont, Ryan Holtz -/* - * wd33c93.c - * - * WD/AMD 33c93 SCSI controller, as seen in - * early PCs, some MSX add-ons, NEC PC-88, and SGI - * Indigo, Indigo2, and Indy systems. - * - * References: - * WD 33c93 manual - * NetBSD 33c93 driver - * - */ - -#include "emu.h" -#include "wd33c93.h" - -#define LOG_READS (1 << 0) -#define LOG_WRITES (1 << 1) -#define LOG_COMMANDS (1 << 2) -#define LOG_ERRORS (1 << 3) -#define LOG_MISC (1 << 4) -#define LOG_REGS (LOG_READS | LOG_WRITES) -#define LOG_ALL (LOG_REGS | LOG_COMMANDS | LOG_ERRORS | LOG_MISC) - -#define VERBOSE (0) -#include "logmacro.h" - - -/* WD commands */ -#define WD_CMD_RESET 0x00 -#define WD_CMD_ABORT 0x01 -#define WD_CMD_ASSERT_ATN 0x02 -#define WD_CMD_NEGATE_ACK 0x03 -#define WD_CMD_DISCONNECT 0x04 -#define WD_CMD_RESELECT 0x05 -#define WD_CMD_SEL_ATN 0x06 -#define WD_CMD_SEL 0x07 -#define WD_CMD_SEL_ATN_XFER 0x08 -#define WD_CMD_SEL_XFER 0x09 -#define WD_CMD_RESEL_RECEIVE 0x0a -#define WD_CMD_RESEL_SEND 0x0b -#define WD_CMD_WAIT_SEL_RECEIVE 0x0c -#define WD_CMD_SSCC 0x0d -#define WD_CMD_SND_DISC 0x0e -#define WD_CMD_SET_IDI 0x0f -#define WD_CMD_RCV_CMD 0x10 -#define WD_CMD_RCV_DATA 0x11 -#define WD_CMD_RCV_MSG_OUT 0x12 -#define WD_CMD_RCV 0x13 -#define WD_CMD_SND_STATUS 0x14 -#define WD_CMD_SND_DATA 0x15 -#define WD_CMD_SND_MSG_IN 0x16 -#define WD_CMD_SND 0x17 -#define WD_CMD_TRANS_ADDR 0x18 -#define WD_CMD_XFER_PAD 0x19 -#define WD_CMD_TRANS_INFO 0x20 -#define WD_CMD_TRANSFER_PAD 0x21 -#define WD_CMD_SBT_MODE 0x80 - -/* ASR register */ -#define ASR_INT 0x80 -#define ASR_LCI 0x40 -#define ASR_BSY 0x20 -#define ASR_CIP 0x10 -#define ASR_PE 0x02 -#define ASR_DBR 0x01 - -/* SCSI Bus Phases */ -#define PHS_DATA_OUT 0x00 -#define PHS_DATA_IN 0x01 -#define PHS_COMMAND 0x02 -#define PHS_STATUS 0x03 -#define PHS_MESS_OUT 0x06 -#define PHS_MESS_IN 0x07 - -/* Command Status Register definitions */ - - /* reset state interrupts */ -#define CSR_RESET 0x00 -#define CSR_RESET_AF 0x01 - - /* successful completion interrupts */ -#define CSR_RESELECT 0x10 -#define CSR_SELECT 0x11 -#define CSR_SEL_XFER_DONE 0x16 -#define CSR_XFER_DONE 0x18 - - /* paused or aborted interrupts */ -#define CSR_MSGIN 0x20 -#define CSR_SDP 0x21 -#define CSR_SEL_ABORT 0x22 -#define CSR_RESEL_ABORT 0x25 -#define CSR_RESEL_ABORT_AM 0x27 -#define CSR_ABORT 0x28 - - /* terminated interrupts */ -#define CSR_INVALID 0x40 -#define CSR_UNEXP_DISC 0x41 -#define CSR_TIMEOUT 0x42 -#define CSR_PARITY 0x43 -#define CSR_PARITY_ATN 0x44 -#define CSR_BAD_STATUS 0x45 -#define CSR_UNEXP 0x48 - - /* service required interrupts */ -#define CSR_RESEL 0x80 -#define CSR_RESEL_AM 0x81 -#define CSR_DISC 0x85 -#define CSR_SRV_REQ 0x88 - - /* Own ID/CDB Size register */ -#define OWNID_EAF 0x08 -#define OWNID_EHP 0x10 -#define OWNID_RAF 0x20 -#define OWNID_FS_8 0x00 -#define OWNID_FS_12 0x40 -#define OWNID_FS_16 0x80 - - /* Control register */ -#define CTRL_HSP 0x01 -#define CTRL_HA 0x02 -#define CTRL_IDI 0x04 -#define CTRL_EDI 0x08 -#define CTRL_HHP 0x10 -#define CTRL_POLLED 0x00 -#define CTRL_BURST 0x20 -#define CTRL_BUS 0x40 -#define CTRL_DMA 0x80 - - /* Synchronous Transfer Register */ -#define STR_FSS 0x80 - - /* Destination ID register */ -#define DSTID_DPD 0x40 -#define DATA_OUT_DIR 0 -#define DATA_IN_DIR 1 -#define DSTID_SCC 0x80 - - /* Source ID register */ -#define SRCID_MASK 0x07 -#define SRCID_SIV 0x08 -#define SRCID_DSP 0x20 -#define SRCID_ES 0x40 -#define SRCID_ER 0x80 - -/* convernience functions */ -uint8_t wd33c93_device::getunit() -{ - /* return the destination unit id */ - return m_regs[WD_DESTINATION_ID] & SRCID_MASK; -} - -void wd33c93_device::set_xfer_count( int count ) -{ - /* set the count */ - m_regs[WD_TRANSFER_COUNT_LSB] = count & 0xff; - m_regs[WD_TRANSFER_COUNT] = (count >> 8) & 0xff; - m_regs[WD_TRANSFER_COUNT_MSB] = (count >> 16) & 0xff; -} - -int wd33c93_device::get_xfer_count() -{ - /* get the count */ - int count = m_regs[WD_TRANSFER_COUNT_MSB]; - - count <<= 8; - count |= m_regs[WD_TRANSFER_COUNT]; - count <<= 8; - count |= m_regs[WD_TRANSFER_COUNT_LSB]; - - return count; -} - -void wd33c93_device::complete_immediate(int status) -{ - /* reset our timer */ - m_cmd_timer->reset(); - - /* set the new status */ - m_regs[WD_SCSI_STATUS] = status & 0xff; - - /* set interrupt pending */ - m_regs[WD_AUXILIARY_STATUS] |= ASR_INT; - - /* check for error conditions */ - if (get_xfer_count() > 0) - { - /* set data buffer ready */ - m_regs[WD_AUXILIARY_STATUS] |= ASR_DBR; - } - else - { - /* clear data buffer ready */ - m_regs[WD_AUXILIARY_STATUS] &= ~ASR_DBR; - } - - /* clear command in progress and bus busy */ - m_regs[WD_AUXILIARY_STATUS] &= ~(ASR_CIP | ASR_BSY); - - /* if we have a callback, call it */ - if (!m_irq_cb.isnull()) - { - m_irq_cb(1); - } -} - -void wd33c93_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr) -{ - switch (tid) - { - case 0: - complete_immediate(param); - break; - - case 1: - complete_immediate(CSR_SRV_REQ | m_busphase); - break; - - case 2: - m_regs[WD_AUXILIARY_STATUS] &= ~ASR_CIP; - break; - } -} - -void wd33c93_device::complete_cmd(uint8_t status) -{ - /* fire off a timer to complete the command */ - m_cmd_timer->adjust(attotime::from_usec(1), status); -} - -/* command handlers */ -void wd33c93_device::unimplemented_cmd() -{ - LOGMASKED(LOG_COMMANDS | LOG_ERRORS, "%s: Unimplemented SCSI controller command: %02x\n", machine().describe_context(), m_regs[WD_COMMAND]); - - /* complete the command */ - complete_cmd(CSR_INVALID); -} - -void wd33c93_device::invalid_cmd() -{ - LOGMASKED(LOG_COMMANDS | LOG_ERRORS, "%s: Invalid SCSI controller command: %02x\n", machine().describe_context(), m_regs[WD_COMMAND]); - - /* complete the command */ - complete_cmd(CSR_INVALID); -} - -void wd33c93_device::reset_cmd() -{ - int advanced = 0; - - /* see if it wants us to reset with advanced features */ - if (m_regs[WD_OWN_ID] & OWNID_EAF) - { - advanced = 1; - } - - /* clear out all registers */ - memset(m_regs, 0, sizeof(m_regs)); - - /* complete the command */ - complete_cmd(advanced ? CSR_RESET_AF : CSR_RESET); -} - -void wd33c93_device::abort_cmd() -{ - /* complete the command */ - complete_cmd(CSR_ABORT); -} - -void wd33c93_device::disconnect_cmd() -{ - /* complete the command */ - m_regs[WD_AUXILIARY_STATUS] &= ~(ASR_CIP | ASR_BSY); -} - -void wd33c93_device::select_cmd() -{ - uint8_t unit = getunit(); - uint8_t newstatus; - - /* see if we can select that device */ - if (select(unit)) - { - /* device is available - signal selection done */ - newstatus = CSR_SELECT; - - /* determine the next bus phase depending on the command */ - if ((m_regs[WD_COMMAND] & 0x7f) == WD_CMD_SEL_ATN) - { - /* /ATN asserted during select: Move to Message Out Phase to read identify */ - m_busphase = PHS_MESS_OUT; - } - else - { - /* No /ATN asserted: Move to Command Phase */ - m_busphase = PHS_COMMAND; - } - - /* queue up a service request out in the future */ - m_service_req_timer->adjust( attotime::from_usec(50) ); - } - else - { - /* device is not available */ - newstatus = CSR_TIMEOUT; - } - - /* complete the command */ - complete_cmd(newstatus); -} - -void wd33c93_device::selectxfer_cmd() -{ - uint8_t unit = getunit(); - uint8_t newstatus; - - /* see if we can select that device */ - if (select(unit)) - { - if (m_regs[WD_COMMAND_PHASE] < 0x45) - { - /* device is available */ - - /* do the request */ - send_command(&m_regs[WD_CDB_1], 12); - int phase = get_phase(); - - /* set transfer count */ - if (get_xfer_count() > TEMP_INPUT_LEN) - { - LOGMASKED(LOG_ERRORS, "WD33C93: Transfer count too big. Please increase TEMP_INPUT_LEN (size=%d)\n", get_xfer_count()); - set_xfer_count(TEMP_INPUT_LEN); - } - - switch (phase) - { - case SCSI_PHASE_DATAIN: - m_read_pending = true; - break; - } - } - - if (m_read_pending) - { - int len = TEMP_INPUT_LEN; - - if (get_xfer_count() < len) - len = get_xfer_count(); - - memset(&m_temp_input[0], 0, TEMP_INPUT_LEN); - read_data(&m_temp_input[0], len); - m_temp_input_pos = 0; - m_read_pending = false; - } - - m_regs[WD_TARGET_LUN] = 0; - m_regs[WD_CONTROL] |= CTRL_EDI; - m_regs[WD_COMMAND_PHASE] = 0x60; - - /* signal transfer ready */ - newstatus = CSR_SEL_XFER_DONE; - - /* if allowed disconnect, queue a service request */ - if (m_identify & 0x40) - { - /* queue disconnect message in */ - m_busphase = PHS_MESS_IN; - - /* queue up a service request out in the future */ - m_service_req_timer->adjust(attotime::from_usec(50)); - } - } - else - { - /* device is not available */ - newstatus = CSR_TIMEOUT; - - set_xfer_count(0); - } - - /* complete the command */ - complete_cmd(newstatus); -} - -void wd33c93_device::negate_ack() -{ - LOGMASKED(LOG_MISC, "WD33C93: ACK Negated\n"); - - /* complete the command */ - m_regs[WD_AUXILIARY_STATUS] &= ~(ASR_CIP | ASR_BSY); -} - -void wd33c93_device::xferinfo_cmd() -{ - /* make the buffer available right away */ - m_regs[WD_AUXILIARY_STATUS] |= ASR_DBR; - m_regs[WD_AUXILIARY_STATUS] |= ASR_CIP; - - /* the command will be completed once the data is transferred */ - m_deassert_cip_timer->adjust(attotime::from_msec(1)); -} - -/* Handle pending commands */ -void wd33c93_device::dispatch_command() -{ - /* get the command */ - uint8_t cmd = m_regs[WD_COMMAND] & 0x7f; - - switch (cmd) - { - case WD_CMD_RESET: - LOGMASKED(LOG_COMMANDS, "WD33C93: %s - Reset Command\n", machine().describe_context()); - reset_cmd(); - break; - - case WD_CMD_ABORT: - LOGMASKED(LOG_COMMANDS, "WD33C93: %s - Abort Command\n", machine().describe_context()); - abort_cmd(); - break; - - case WD_CMD_NEGATE_ACK: - LOGMASKED(LOG_COMMANDS, "WD33C93: %s - Negate ACK Command\n", machine().describe_context()); - negate_ack(); - break; - - case WD_CMD_DISCONNECT: - LOGMASKED(LOG_COMMANDS, "WD33C93: %s - Disconnect Command\n", machine().describe_context()); - disconnect_cmd(); - break; - - case WD_CMD_SEL_ATN: - case WD_CMD_SEL: - LOGMASKED(LOG_COMMANDS, "WD33C93: %s - Select %sCommand\n", machine().describe_context(), cmd == WD_CMD_SEL_ATN ? "w/ ATN " : ""); - select_cmd(); - break; - - case WD_CMD_SEL_ATN_XFER: - case WD_CMD_SEL_XFER: - LOGMASKED(LOG_COMMANDS, "WD33C93: %s - Select %sand Xfer Command\n", machine().describe_context(), cmd == WD_CMD_SEL_ATN ? "w/ ATN " : ""); - selectxfer_cmd(); - break; - - case WD_CMD_TRANS_INFO: - LOGMASKED(LOG_COMMANDS, "WD33C93: %s - Transfer Info Command\n", machine().describe_context()); - xferinfo_cmd(); - break; - - case WD_CMD_ASSERT_ATN: - case WD_CMD_RESELECT: - case WD_CMD_RESEL_RECEIVE: - case WD_CMD_RESEL_SEND: - case WD_CMD_WAIT_SEL_RECEIVE: - case WD_CMD_SSCC: - case WD_CMD_SND_DISC: - case WD_CMD_SET_IDI: - case WD_CMD_RCV_CMD: - case WD_CMD_RCV_DATA: - case WD_CMD_RCV_MSG_OUT: - case WD_CMD_RCV: - case WD_CMD_SND_STATUS: - case WD_CMD_SND_DATA: - case WD_CMD_SND_MSG_IN: - case WD_CMD_SND: - case WD_CMD_TRANS_ADDR: - case WD_CMD_XFER_PAD: - case WD_CMD_TRANSFER_PAD: - unimplemented_cmd(); - break; - - default: - invalid_cmd(); - break; - } -} - -WRITE8_MEMBER(wd33c93_device::write) -{ - switch (offset) - { - case 0: - { - /* update register select */ - m_sasr = data & 0x1f; - } - break; - - case 1: - { - /* update the register */ - if (m_sasr != WD_SCSI_STATUS && m_sasr <= WD_QUEUE_TAG) - { - m_regs[m_sasr] = data; - } - - switch (m_sasr) - { - case WD_OWN_ID: - LOGMASKED(LOG_WRITES, "WD33C93: %s - Write Register %02x, Own ID Register (CDB Size) = %02x\n", machine().describe_context(), m_sasr, data); - break; - case WD_CONTROL: - LOGMASKED(LOG_WRITES, "WD33C93: %s - Write Register %02x, Control Register = %02x\n", machine().describe_context(), m_sasr, data); - break; - case WD_TIMEOUT_PERIOD: - LOGMASKED(LOG_WRITES, "WD33C93: %s - Write Register %02x, Timeout Period Register = %02x\n", machine().describe_context(), m_sasr, data); - break; - case WD_CDB_1: - LOGMASKED(LOG_WRITES, "WD33C93: %s - Write Register %02x, Total Sectors Register (CDB1) = %02x\n", machine().describe_context(), m_sasr, data); - m_regs[WD_COMMAND_PHASE] = 0; - break; - case WD_CDB_2: - LOGMASKED(LOG_WRITES, "WD33C93: %s - Write Register %02x, Total Heads Register (CDB2) = %02x\n", machine().describe_context(), m_sasr, data); - break; - case WD_CDB_3: - LOGMASKED(LOG_WRITES, "WD33C93: %s - Write Register %02x, Total Cylinders Register MSB (CDB3) = %02x\n", machine().describe_context(), m_sasr, data); - break; - case WD_CDB_4: - LOGMASKED(LOG_WRITES, "WD33C93: %s - Write Register %02x, Total Cylinders Register LSB (CDB4) = %02x\n", machine().describe_context(), m_sasr, data); - break; - case WD_CDB_5: - LOGMASKED(LOG_WRITES, "WD33C93: %s - Write Register %02x, Logical Address Register MSB (CDB5) = %02x\n", machine().describe_context(), m_sasr, data); - break; - case WD_CDB_6: - LOGMASKED(LOG_WRITES, "WD33C93: %s - Write Register %02x, Logical Address Register 2nd (CDB6) = %02x\n", machine().describe_context(), m_sasr, data); - break; - case WD_CDB_7: - LOGMASKED(LOG_WRITES, "WD33C93: %s - Write Register %02x, Logical Address Register 3rd (CDB7) = %02x\n", machine().describe_context(), m_sasr, data); - break; - case WD_CDB_8: - LOGMASKED(LOG_WRITES, "WD33C93: %s - Write Register %02x, Logical Address Register LSB (CDB8) = %02x\n", machine().describe_context(), m_sasr, data); - break; - case WD_CDB_9: - LOGMASKED(LOG_WRITES, "WD33C93: %s - Write Register %02x, Sector Number Register (CDB9) = %02x\n", machine().describe_context(), m_sasr, data); - break; - case WD_CDB_10: - LOGMASKED(LOG_WRITES, "WD33C93: %s - Write Register %02x, Head Number Register (CDB10) = %02x\n", machine().describe_context(), m_sasr, data); - break; - case WD_CDB_11: - LOGMASKED(LOG_WRITES, "WD33C93: %s - Write Register %02x, Cylinder Number Register MSB (CDB11) = %02x\n", machine().describe_context(), m_sasr, data); - break; - case WD_CDB_12: - LOGMASKED(LOG_WRITES, "WD33C93: %s - Write Register %02x, Cylinder Number Register LSB (CDB12) = %02x\n", machine().describe_context(), m_sasr, data); - break; - case WD_TARGET_LUN: - LOGMASKED(LOG_WRITES, "WD33C93: %s - Write Register %02x, Target LUN Register = %02x\n", machine().describe_context(), m_sasr, data); - break; - case WD_COMMAND_PHASE: - LOGMASKED(LOG_WRITES, "WD33C93: %s - Write Register %02x, Command Phase Register = %02x\n", machine().describe_context(), m_sasr, data); - break; - case WD_SYNCHRONOUS_TRANSFER: - LOGMASKED(LOG_WRITES, "WD33C93: %s - Write Register %02x, Synchronous Transfer Register = %02x\n", machine().describe_context(), m_sasr, data); - break; - case WD_TRANSFER_COUNT_MSB: - LOGMASKED(LOG_WRITES, "WD33C93: %s - Write Register %02x, Transfer Count Register MSB = %02x\n", machine().describe_context(), m_sasr, data); - break; - case WD_TRANSFER_COUNT: - LOGMASKED(LOG_WRITES, "WD33C93: %s - Write Register %02x, Transfer Count Register 2nd = %02x\n", machine().describe_context(), m_sasr, data); - break; - case WD_TRANSFER_COUNT_LSB: - LOGMASKED(LOG_WRITES, "WD33C93: %s - Write Register %02x, Transfer Count Register LSB = %02x\n", machine().describe_context(), m_sasr, data); - break; - case WD_DESTINATION_ID: - LOGMASKED(LOG_WRITES, "WD33C93: %s - Write Register %02x, Destination ID Register = %02x\n", machine().describe_context(), m_sasr, data); - break; - case WD_SOURCE_ID: - LOGMASKED(LOG_WRITES, "WD33C93: %s - Write Register %02x, Source ID Register = %02x\n", machine().describe_context(), m_sasr, data); - break; - case WD_SCSI_STATUS: - LOGMASKED(LOG_WRITES, "WD33C93: %s - Write Register %02x, SCSI Status Register (read-only!) = %02x (ignored)\n", machine().describe_context(), m_sasr, data); - break; - case WD_COMMAND: - /* if we receive a command, schedule to process it */ - LOGMASKED(LOG_WRITES, "WD33C93: %s - Write Register %02x, Command Register = %02x - unit %d\n", machine().describe_context(), m_sasr, data, getunit()); - - /* signal we're processing it */ - m_regs[WD_AUXILIARY_STATUS] |= ASR_CIP; - - /* process the command */ - dispatch_command(); - break; - case WD_DATA: - { - LOGMASKED(LOG_WRITES, "WD33C93: %s - Write Register %02x, Data Register = %02x\n", machine().describe_context(), m_sasr, data); - - /* if data was written, and we have a count, send to device */ - int count = get_xfer_count(); - - if (m_regs[WD_COMMAND] & 0x80) - count = 1; - - if (count-- > 0) - { - /* write to FIFO */ - if (m_fifo_pos < FIFO_SIZE) - { - m_fifo[m_fifo_pos++] = data; - } - - /* update count */ - set_xfer_count(count); - - /* if we're done with the write, see where we're at */ - if (count == 0) - { - m_regs[WD_AUXILIARY_STATUS] |= ASR_INT; - m_regs[WD_AUXILIARY_STATUS] &= ~ASR_DBR; - - switch (m_busphase) - { - case PHS_MESS_OUT: - { - /* reset fifo */ - m_fifo_pos = 0; - - /* Message out phase. Data is probably SCSI Identify. Move to command phase. */ - m_busphase = PHS_COMMAND; - - m_identify = m_fifo[0]; - } - break; - - case PHS_COMMAND: - { - /* Execute the command. Depending on the command, we'll move to data in or out */ - send_command(&m_fifo[0], 12); - int xfercount = get_length(); - int phase = get_phase(); - - /* reset fifo */ - m_fifo_pos = 0; - - /* set the new count */ - set_xfer_count(xfercount); - - switch (phase) - { - case SCSI_PHASE_STATUS: - m_busphase = PHS_STATUS; - break; - - case SCSI_PHASE_DATAIN: - m_busphase = PHS_DATA_IN; - m_read_pending = true; - break; - - case SCSI_PHASE_DATAOUT: - m_busphase = PHS_DATA_OUT; - break; - } - } - break; - - case PHS_DATA_OUT: - { - /* write data out to device */ - write_data(m_fifo, m_fifo_pos); - - /* reset fifo */ - m_fifo_pos = 0; - - /* move to status phase */ - m_busphase = PHS_STATUS; - } - break; - } - - /* complete the command */ - complete_immediate(CSR_XFER_DONE | m_busphase); - } - } - else - { - LOGMASKED(LOG_MISC | LOG_ERRORS, "WD33C93: Sending data to device with transfer count = 0!. Ignoring...\n"); - } - break; - } - case WD_QUEUE_TAG: - LOGMASKED(LOG_WRITES, "WD33C93: %s - Write Register %02x, Queue Tag Register = %02x\n", machine().describe_context(), m_sasr, data); - break; - case WD_AUXILIARY_STATUS: - LOGMASKED(LOG_WRITES, "WD33C93: %s - Write Register %02x, Auxiliary Status Register (read-only!) = %02x (ignored)\n", machine().describe_context(), m_sasr, data); - break; - default: - LOGMASKED(LOG_WRITES | LOG_ERRORS, "WD33C93: %s - Write Register %02x, Unknown = %02x (ignored)\n", machine().describe_context(), m_sasr, data); - break; - } - - /* auto-increment register select if not on special registers */ - if (m_sasr != WD_COMMAND && m_sasr != WD_DATA && m_sasr != WD_AUXILIARY_STATUS) - { - m_sasr = (m_sasr + 1) & 0x1f; - } - } - break; - - default: - { - LOGMASKED(LOG_ERRORS, "WD33C93: Write to invalid offset %d (data=%02x)\n", offset, data); - } - break; - } -} - -READ8_MEMBER(wd33c93_device::read) -{ - switch (offset) - { - case 0: - /* read aux status */ - return m_regs[WD_AUXILIARY_STATUS]; - - case 1: - { - switch (m_sasr) - { - case WD_OWN_ID: - LOGMASKED(LOG_READS, "WD33C93: %s - Read Register %02x, Own ID Register (CDB Size) (%02x)\n", machine().describe_context(), m_sasr, m_regs[m_sasr]); - break; - case WD_CONTROL: - LOGMASKED(LOG_READS, "WD33C93: %s - Read Register %02x, Control Register (%02x)\n", machine().describe_context(), m_sasr, m_regs[m_sasr]); - break; - case WD_TIMEOUT_PERIOD: - LOGMASKED(LOG_READS, "WD33C93: %s - Read Register %02x, Timeout Period Register (%02x)\n", machine().describe_context(), m_sasr, m_regs[m_sasr]); - break; - case WD_CDB_1: - LOGMASKED(LOG_READS, "WD33C93: %s - Read Register %02x, Total Sectors Register (CDB1) (%02x)\n", machine().describe_context(), m_sasr, m_regs[m_sasr]); - m_regs[WD_COMMAND_PHASE] = 0; - break; - case WD_CDB_2: - LOGMASKED(LOG_READS, "WD33C93: %s - Read Register %02x, Total Heads Register (CDB2) (%02x)\n", machine().describe_context(), m_sasr, m_regs[m_sasr]); - break; - case WD_CDB_3: - LOGMASKED(LOG_READS, "WD33C93: %s - Read Register %02x, Total Cylinders Register MSB (CDB3) (%02x)\n", machine().describe_context(), m_sasr, m_regs[m_sasr]); - break; - case WD_CDB_4: - LOGMASKED(LOG_READS, "WD33C93: %s - Read Register %02x, Total Cylinders Register LSB (CDB4) (%02x)\n", machine().describe_context(), m_sasr, m_regs[m_sasr]); - break; - case WD_CDB_5: - LOGMASKED(LOG_READS, "WD33C93: %s - Read Register %02x, Logical Address Register MSB (CDB5) (%02x)\n", machine().describe_context(), m_sasr, m_regs[m_sasr]); - break; - case WD_CDB_6: - LOGMASKED(LOG_READS, "WD33C93: %s - Read Register %02x, Logical Address Register 2nd (CDB6) (%02x)\n", machine().describe_context(), m_sasr, m_regs[m_sasr]); - break; - case WD_CDB_7: - LOGMASKED(LOG_READS, "WD33C93: %s - Read Register %02x, Logical Address Register 3rd (CDB7) (%02x)\n", machine().describe_context(), m_sasr, m_regs[m_sasr]); - break; - case WD_CDB_8: - LOGMASKED(LOG_READS, "WD33C93: %s - Read Register %02x, Logical Address Register LSB (CDB8) (%02x)\n", machine().describe_context(), m_sasr, m_regs[m_sasr]); - break; - case WD_CDB_9: - LOGMASKED(LOG_READS, "WD33C93: %s - Read Register %02x, Sector Number Register (CDB9) (%02x)\n", machine().describe_context(), m_sasr, m_regs[m_sasr]); - break; - case WD_CDB_10: - LOGMASKED(LOG_READS, "WD33C93: %s - Read Register %02x, Head Number Register (CDB10) (%02x)\n", machine().describe_context(), m_sasr, m_regs[m_sasr]); - break; - case WD_CDB_11: - LOGMASKED(LOG_READS, "WD33C93: %s - Read Register %02x, Cylinder Number Register MSB (CDB11) (%02x)\n", machine().describe_context(), m_sasr, m_regs[m_sasr]); - break; - case WD_CDB_12: - LOGMASKED(LOG_READS, "WD33C93: %s - Read Register %02x, Cylinder Number Register LSB (CDB12) (%02x)\n", machine().describe_context(), m_sasr, m_regs[m_sasr]); - break; - case WD_TARGET_LUN: - LOGMASKED(LOG_READS, "WD33C93: %s - Read Register %02x, Target LUN Register (%02x)\n", machine().describe_context(), m_sasr, m_regs[m_sasr]); - break; - case WD_COMMAND_PHASE: - LOGMASKED(LOG_READS, "WD33C93: %s - Read Register %02x, Command Phase Register (%02x)\n", machine().describe_context(), m_sasr, m_regs[m_sasr]); - break; - case WD_SYNCHRONOUS_TRANSFER: - LOGMASKED(LOG_READS, "WD33C93: %s - Read Register %02x, Synchronous Transfer Register (%02x)\n", machine().describe_context(), m_sasr, m_regs[m_sasr]); - break; - case WD_TRANSFER_COUNT_MSB: - LOGMASKED(LOG_READS, "WD33C93: %s - Read Register %02x, Transfer Count Register MSB (%02x)\n", machine().describe_context(), m_sasr, m_regs[m_sasr]); - break; - case WD_TRANSFER_COUNT: - LOGMASKED(LOG_READS, "WD33C93: %s - Read Register %02x, Transfer Count Register 2nd (%02x)\n", machine().describe_context(), m_sasr, m_regs[m_sasr]); - break; - case WD_TRANSFER_COUNT_LSB: - LOGMASKED(LOG_READS, "WD33C93: %s - Read Register %02x, Transfer Count Register LSB (%02x)\n", machine().describe_context(), m_sasr, m_regs[m_sasr]); - break; - case WD_DESTINATION_ID: - LOGMASKED(LOG_READS, "WD33C93: %s - Read Register %02x, Destination ID Register (%02x)\n", machine().describe_context(), m_sasr, m_regs[m_sasr]); - break; - case WD_SOURCE_ID: - LOGMASKED(LOG_READS, "WD33C93: %s - Read Register %02x, Source ID Register (%02x)\n", machine().describe_context(), m_sasr, m_regs[m_sasr]); - break; - case WD_SCSI_STATUS: - LOGMASKED(LOG_READS, "WD33C93: %s - Read Register %02x, SCSI Status Register (%02x)\n", machine().describe_context(), m_sasr, m_regs[m_sasr]); - m_regs[WD_AUXILIARY_STATUS] &= ~ASR_INT; - - /* if reading status, clear irq flag */ - if (!m_irq_cb.isnull()) - { - m_irq_cb(0); - } - break; - case WD_COMMAND: - LOGMASKED(LOG_READS, "WD33C93: %s - Read Register %02x, Command Register (%02x)\n", machine().describe_context(), m_sasr, m_regs[m_sasr]); - break; - case WD_DATA: - { - /* we're going to be doing synchronous reads */ - - /* get the transfer count */ - int count = get_xfer_count(); - - /* initialize the return value */ - m_regs[WD_DATA] = 0; - - if (count <= 0 && m_busphase == PHS_MESS_IN) - { - /* move to disconnect */ - complete_cmd(CSR_DISC); - } - else if (count == 1 && m_busphase == PHS_STATUS) - { - /* update the count */ - set_xfer_count(0); - - /* move to message in phase */ - m_busphase = PHS_MESS_IN; - - /* complete the command */ - complete_cmd(CSR_XFER_DONE | m_busphase); - } - else if (count-- > 0) /* make sure we still have data to send */ - { - if (m_read_pending) - { - int len = TEMP_INPUT_LEN; - - if ((count + 1) < len ) - len = count + 1; - read_data(&m_temp_input[0], len); - m_temp_input_pos = 0; - m_read_pending = false; - } - - m_regs[WD_AUXILIARY_STATUS] &= ~ASR_INT; - - /* read in one byte */ - if (m_temp_input_pos < TEMP_INPUT_LEN) - m_regs[WD_DATA] = m_temp_input[m_temp_input_pos++]; - - /* update the count */ - set_xfer_count(count); - - /* transfer finished, see where we're at */ - if (count == 0) - { - if (m_regs[WD_COMMAND_PHASE] != 0x60) - { - /* move to status phase */ - m_busphase = PHS_STATUS; - - /* complete the command */ - complete_cmd(CSR_XFER_DONE | m_busphase); - } - else - { - m_regs[WD_AUXILIARY_STATUS] |= ASR_INT; - m_regs[WD_AUXILIARY_STATUS] &= ~ASR_DBR; - } - } - LOGMASKED(LOG_READS, "WD33C93: %s - Read Register %02x, Data Register (%02x)\n", machine().describe_context(), WD_DATA, m_regs[WD_DATA]); - } - break; - } - case WD_QUEUE_TAG: - LOGMASKED(LOG_READS, "WD33C93: %s - Read Register %02x, Queue Tag Register (%02x)\n", machine().describe_context(), m_sasr, m_regs[m_sasr]); - break; - case WD_AUXILIARY_STATUS: - LOGMASKED(LOG_READS, "WD33C93: %s - Read Register %02x, Auxiliary Status Register (%02x)\n", machine().describe_context(), m_sasr, m_regs[m_sasr]); - break; - default: - LOGMASKED(LOG_READS | LOG_ERRORS, "WD33C93: %s - Read Register %02x, Unknown\n", machine().describe_context(), m_sasr); - break; - } - - /* get the register value */ - uint8_t ret = 0xff; - if (m_sasr == WD_AUXILIARY_STATUS || m_sasr <= WD_QUEUE_TAG) - ret = m_regs[m_sasr]; - - /* auto-increment register select if not on special registers */ - if (m_sasr != WD_COMMAND && m_sasr != WD_DATA && m_sasr != WD_AUXILIARY_STATUS) - { - m_sasr = (m_sasr + 1) & 0x1f; - } - - return ret; - } - - default: - LOGMASKED(LOG_READS | LOG_ERRORS, "WD33C93: Read from invalid offset %d\n", offset); - break; - } - - return 0; -} - -wd33c93_device::wd33c93_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : - legacy_scsi_host_adapter(mconfig, WD33C93, tag, owner, clock), - m_irq_cb(*this) -{ -} - -void wd33c93_device::device_start() -{ - legacy_scsi_host_adapter::device_start(); - - memset(m_regs, 0, sizeof(m_regs)); - memset(m_fifo, 0, sizeof(m_fifo)); - memset(m_temp_input, 0, sizeof(m_temp_input)); - - m_sasr = 0; - m_fifo_pos = 0; - m_temp_input_pos = 0; - m_busphase = 0; - m_identify = 0; - m_read_pending = 0; - - m_irq_cb.resolve(); - - /* allocate a timer for commands */ - m_cmd_timer = timer_alloc(0); - m_service_req_timer = timer_alloc(1); - m_deassert_cip_timer = timer_alloc(2); - - save_item(NAME(m_sasr)); - save_item(NAME(m_regs)); - save_item(NAME(m_fifo)); - save_item(NAME(m_fifo_pos)); - save_item(NAME(m_temp_input)); - save_item(NAME(m_temp_input_pos)); - save_item(NAME(m_busphase)); - save_item(NAME(m_identify)); - save_item(NAME(m_read_pending)); -} - -int wd33c93_device::dma_read_data(int bytes, uint8_t *data) -{ - int len = bytes; - - if (len >= get_xfer_count()) - len = get_xfer_count(); - - if (len == 0) - return 0; - - if ((m_temp_input_pos + len) >= TEMP_INPUT_LEN) - { - LOGMASKED(LOG_ERRORS, "Reading past end of buffer, increase TEMP_INPUT_LEN size\n"); - len = TEMP_INPUT_LEN - len; - } - - assert(len); - - memcpy(data, &m_temp_input[m_temp_input_pos], len); - - m_temp_input_pos += len; - set_xfer_count(get_xfer_count() - len); - return len; -} - -void wd33c93_device::dma_write_data(int bytes, uint8_t *data) -{ - write_data(data, bytes); -} - -void wd33c93_device::clear_dma() -{ - /* indicate DMA completed by clearing the transfer count */ - set_xfer_count(0); - m_regs[WD_AUXILIARY_STATUS] &= ~ASR_DBR; -} - -int wd33c93_device::get_dma_count() -{ - return get_xfer_count(); -} - -DEFINE_DEVICE_TYPE(WD33C93, wd33c93_device, "wd33c93", "Western Digital WD33C93 SCSI") diff --git a/src/devices/machine/wd33c93.h b/src/devices/machine/wd33c93.h deleted file mode 100644 index b4a883afca4..00000000000 --- a/src/devices/machine/wd33c93.h +++ /dev/null @@ -1,112 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:ElSemi, R. Belmont, Ryan Holtz -/* - * wd33c93.h - * - */ - -#ifndef MAME_MACHINE_WD33C93_H -#define MAME_MACHINE_WD33C93_H - -#pragma once - -#include "legscsi.h" - -class wd33c93_device : public legacy_scsi_host_adapter -{ -public: - // construction/destruction - wd33c93_device(const machine_config &mconfig, const char *tag, device_t *owner) - : wd33c93_device(mconfig, tag, owner, (uint32_t)0) - { - } - - wd33c93_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - - auto irq_cb() { return m_irq_cb.bind(); } - - DECLARE_READ8_MEMBER(read); - DECLARE_WRITE8_MEMBER(write); - - int dma_read_data(int bytes, uint8_t *data); - void dma_write_data(int bytes, uint8_t *data); - void clear_dma(); - int get_dma_count(); - -protected: - // device-level overrides - virtual void device_start() override; - virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; - -private: - // wd register names - enum - { - WD_OWN_ID = 0x00, - WD_CONTROL = 0x01, - WD_TIMEOUT_PERIOD = 0x02, - WD_CDB_1 = 0x03, - WD_CDB_2 = 0x04, - WD_CDB_3 = 0x05, - WD_CDB_4 = 0x06, - WD_CDB_5 = 0x07, - WD_CDB_6 = 0x08, - WD_CDB_7 = 0x09, - WD_CDB_8 = 0x0a, - WD_CDB_9 = 0x0b, - WD_CDB_10 = 0x0c, - WD_CDB_11 = 0x0d, - WD_CDB_12 = 0x0e, - WD_TARGET_LUN = 0x0f, - WD_COMMAND_PHASE = 0x10, - WD_SYNCHRONOUS_TRANSFER = 0x11, - WD_TRANSFER_COUNT_MSB = 0x12, - WD_TRANSFER_COUNT = 0x13, - WD_TRANSFER_COUNT_LSB = 0x14, - WD_DESTINATION_ID = 0x15, - WD_SOURCE_ID = 0x16, - WD_SCSI_STATUS = 0x17, - WD_COMMAND = 0x18, - WD_DATA = 0x19, - WD_QUEUE_TAG = 0x1a, - WD_AUXILIARY_STATUS = 0x1f - }; - - static constexpr int TEMP_INPUT_LEN = 262144; - static constexpr int FIFO_SIZE = 12; - - uint8_t getunit(); - void set_xfer_count(int count); - int get_xfer_count(); - void complete_immediate(int status); - void complete_cmd(uint8_t status); - void unimplemented_cmd(); - void invalid_cmd(); - void reset_cmd(); - void abort_cmd(); - void disconnect_cmd(); - void select_cmd(); - void selectxfer_cmd(); - void negate_ack(); - void xferinfo_cmd(); - void dispatch_command(); - - uint8_t m_sasr; - uint8_t m_regs[WD_AUXILIARY_STATUS+1]; - uint8_t m_fifo[FIFO_SIZE]; - int m_fifo_pos; - uint8_t m_temp_input[TEMP_INPUT_LEN]; - int m_temp_input_pos; - uint8_t m_busphase; - uint8_t m_identify; - bool m_read_pending; - emu_timer *m_cmd_timer; - emu_timer *m_service_req_timer; - emu_timer *m_deassert_cip_timer; - devcb_write_line m_irq_cb; /* irq callback */ -}; - -// device type definition -DECLARE_DEVICE_TYPE(WD33C93, wd33c93_device) - -#endif // MAME_MACHINE_WD33C93_H diff --git a/src/devices/machine/wd33c9x.cpp b/src/devices/machine/wd33c9x.cpp index 91a80124c23..fdd0c8500e3 100644 --- a/src/devices/machine/wd33c9x.cpp +++ b/src/devices/machine/wd33c9x.cpp @@ -348,8 +348,8 @@ enum : uint16_t { // LIVE DEVICE //************************************************************************** -DEFINE_DEVICE_TYPE(WD33C92, wd33c92_device, "wd33c92", "Western Digital WD33C92 SCSI Controller") -DEFINE_DEVICE_TYPE(WD33C93N, wd33c93n_device, "wd33c93n", "Western Digital WD33C93 SCSI Controller") +DEFINE_DEVICE_TYPE(WD33C92, wd33c92_device, "wd33c92", "Western Digital WD33C92 SCSI Controller") +DEFINE_DEVICE_TYPE(WD33C93, wd33c93_device, "wd33c93", "Western Digital WD33C93 SCSI Controller") DEFINE_DEVICE_TYPE(WD33C93A, wd33c93a_device, "wd33c93a", "Western Digital WD33C93A SCSI Controller") DEFINE_DEVICE_TYPE(WD33C93B, wd33c93b_device, "wd33c93b", "Western Digital WD33C93B SCSI Controller") @@ -1715,8 +1715,8 @@ wd33c92_device::wd33c92_device(const machine_config &mconfig, const char *tag, d { } -wd33c93n_device::wd33c93n_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : wd33c9x_base_device(mconfig, WD33C93N, tag, owner, clock) +wd33c93_device::wd33c93_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : wd33c9x_base_device(mconfig, WD33C93, tag, owner, clock) { } diff --git a/src/devices/machine/wd33c9x.h b/src/devices/machine/wd33c9x.h index 9edbc772a27..65e97852e00 100644 --- a/src/devices/machine/wd33c9x.h +++ b/src/devices/machine/wd33c9x.h @@ -119,15 +119,15 @@ public: wd33c92_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); }; -class wd33c93n_device : public wd33c9x_base_device +class wd33c93_device : public wd33c9x_base_device { public: - wd33c93n_device(const machine_config &mconfig, const char *tag, device_t *owner) - : wd33c93n_device(mconfig, tag, owner, 0) + wd33c93_device(const machine_config &mconfig, const char *tag, device_t *owner) + : wd33c93_device(mconfig, tag, owner, 0) { } - wd33c93n_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + wd33c93_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); }; class wd33c93a_device : public wd33c9x_base_device @@ -153,8 +153,8 @@ public: }; -DECLARE_DEVICE_TYPE(WD33C92, wd33c92_device) -DECLARE_DEVICE_TYPE(WD33C93N, wd33c93n_device) +DECLARE_DEVICE_TYPE(WD33C92, wd33c92_device) +DECLARE_DEVICE_TYPE(WD33C93, wd33c93_device) DECLARE_DEVICE_TYPE(WD33C93A, wd33c93a_device) DECLARE_DEVICE_TYPE(WD33C93B, wd33c93b_device) diff --git a/src/mame/drivers/cps3.cpp b/src/mame/drivers/cps3.cpp index 765ffcb5534..e19859a5fbd 100644 --- a/src/mame/drivers/cps3.cpp +++ b/src/mame/drivers/cps3.cpp @@ -2190,7 +2190,7 @@ void cps3_state::cps3_map(address_map &map) map(0x05100000, 0x05100003).w(FUNC(cps3_state::cps3_irq12_ack_w)); map(0x05110000, 0x05110003).w(FUNC(cps3_state::cps3_irq10_ack_w)); - map(0x05140000, 0x05140003).rw("scsi:7:wd33c93", FUNC(wd33c93n_device::indir_r), FUNC(wd33c93n_device::indir_w)).umask32(0x00ff00ff); + map(0x05140000, 0x05140003).rw("scsi:7:wd33c93", FUNC(wd33c93_device::indir_r), FUNC(wd33c93_device::indir_w)).umask32(0x00ff00ff); map(0x06000000, 0x067fffff).rw(FUNC(cps3_state::cps3_flash1_r), FUNC(cps3_state::cps3_flash1_w)); /* Flash ROMs simm 1 */ map(0x06800000, 0x06ffffff).rw(FUNC(cps3_state::cps3_flash2_r), FUNC(cps3_state::cps3_flash2_w)); /* Flash ROMs simm 2 */ diff --git a/src/mame/drivers/indy_indigo2.cpp b/src/mame/drivers/indy_indigo2.cpp index 12d88c284fa..ef5679c7f05 100644 --- a/src/mame/drivers/indy_indigo2.cpp +++ b/src/mame/drivers/indy_indigo2.cpp @@ -110,7 +110,7 @@ protected: required_device m_maincpu; required_shared_ptr m_mainram; required_device m_mem_ctrl; - required_device m_scsi_ctrl; + required_device m_scsi_ctrl; required_device m_newport; required_device m_hpc3; }; @@ -129,7 +129,7 @@ public: private: void wd33c93_2(device_t *device); - required_device m_scsi_ctrl2; + required_device m_scsi_ctrl2; }; READ32_MEMBER(ip22_state::eisa_io_r) @@ -194,8 +194,8 @@ INPUT_PORTS_END void ip22_state::wd33c93(device_t *device) { device->set_clock(10000000); - downcast(device)->irq_cb().set(m_hpc3, FUNC(hpc3_device::scsi0_irq)); - downcast(device)->drq_cb().set(m_hpc3, FUNC(hpc3_device::scsi0_drq)); + downcast(device)->irq_cb().set(m_hpc3, FUNC(hpc3_device::scsi0_irq)); + downcast(device)->drq_cb().set(m_hpc3, FUNC(hpc3_device::scsi0_drq)); } void ip22_state::scsi_devices(device_slot_interface &device) @@ -223,7 +223,7 @@ void ip22_state::ip22_base(machine_config &config) SGI_MC(config, m_mem_ctrl, m_maincpu, ":hpc3:eeprom"); NSCSI_BUS(config, "scsibus", 0); - NSCSI_CONNECTOR(config, "scsibus:0").option_set("wd33c93", WD33C93N) + NSCSI_CONNECTOR(config, "scsibus:0").option_set("wd33c93", WD33C93) .machine_config([this](device_t *device) { wd33c93(device); }); NSCSI_CONNECTOR(config, "scsibus:1", scsi_devices, "harddisk", false); NSCSI_CONNECTOR(config, "scsibus:2", scsi_devices, nullptr, false); @@ -261,8 +261,8 @@ void ip22_state::ip224613(machine_config &config) void ip24_state::wd33c93_2(device_t *device) { device->set_clock(10000000); - downcast(device)->irq_cb().set(m_hpc3, FUNC(hpc3_device::scsi1_irq)); - downcast(device)->drq_cb().set(m_hpc3, FUNC(hpc3_device::scsi1_drq)); + downcast(device)->irq_cb().set(m_hpc3, FUNC(hpc3_device::scsi1_irq)); + downcast(device)->drq_cb().set(m_hpc3, FUNC(hpc3_device::scsi1_drq)); } void ip24_state::ip244415(machine_config &config) @@ -275,7 +275,7 @@ void ip24_state::ip244415(machine_config &config) m_maincpu->set_addrmap(AS_PROGRAM, &ip24_state::ip22_map); NSCSI_BUS(config, "scsibus2", 0); - NSCSI_CONNECTOR(config, "scsibus2:0").option_set("wd33c93", WD33C93N) + NSCSI_CONNECTOR(config, "scsibus2:0").option_set("wd33c93", WD33C93) .machine_config([this](device_t *device) { wd33c93_2(device); }); NSCSI_CONNECTOR(config, "scsibus2:1", scsi_devices, nullptr, false); NSCSI_CONNECTOR(config, "scsibus2:2", scsi_devices, nullptr, false); diff --git a/src/mame/drivers/r9751.cpp b/src/mame/drivers/r9751.cpp index 6ad473ad72d..e8b0b20ecfa 100644 --- a/src/mame/drivers/r9751.cpp +++ b/src/mame/drivers/r9751.cpp @@ -52,8 +52,11 @@ #include "cpu/m68000/m68000.h" #include "machine/terminal.h" -#include "bus/scsi/scsi.h" -#include "machine/wd33c93.h" +#include "machine/nscsi_bus.h" +#include "machine/nscsi_cd.h" +#include "machine/nscsi_hd.h" + +#include "machine/wd33c9x.h" #include "machine/pdc.h" #include "machine/smioc.h" @@ -85,7 +88,7 @@ public: m_maincpu(*this, "maincpu"), m_pdc(*this, "pdc"), m_smioc(*this, "smioc"), - m_wd33c93(*this, "wd33c93"), + m_wd33c93(*this, "scsi:7:wd33c93"), m_main_ram(*this, "main_ram") { device_trace_init(); @@ -166,6 +169,9 @@ private: void device_trace_disable(int device); void* system_trace_context; + + static void scsi_devices(device_slot_interface &device); + void wd33c93(device_t *device); }; #if ENABLE_TRACE_ALL_DEVICES @@ -957,6 +963,19 @@ INPUT_PORTS_END Machine Drivers ******************************************************************************/ +void r9751_state::scsi_devices(device_slot_interface &device) +{ + device.option_add("cdrom", NSCSI_CDROM); + device.option_add("harddisk", NSCSI_HARDDISK); +} + +void r9751_state::wd33c93(device_t *device) +{ + device->set_clock(10000000); + // downcast(device)->irq_cb().set(*this, FUNC(r9751_state::scsi_irq_w)); + // downcast(device)->drq_cb().set(*this, FUNC(r9751_state::scsi_drq_w)); +} + MACHINE_CONFIG_START(r9751_state::r9751) /* basic machine hardware */ MCFG_DEVICE_ADD("maincpu", M68030, 20000000) @@ -972,9 +991,18 @@ MACHINE_CONFIG_START(r9751_state::r9751) PDC(config, m_pdc, 0); m_pdc->m68k_r_callback().set(FUNC(r9751_state::pdc_dma_r)); m_pdc->m68k_w_callback().set(FUNC(r9751_state::pdc_dma_w)); - MCFG_DEVICE_ADD("scsi", SCSI_PORT, 0) - WD33C93(config, m_wd33c93); - m_wd33c93->set_scsi_port("scsi"); + + + NSCSI_BUS(config, "scsi", 0); + NSCSI_CONNECTOR(config, "scsi:0", scsi_devices, nullptr, false); + NSCSI_CONNECTOR(config, "scsi:1", scsi_devices, "harddisk", false); + NSCSI_CONNECTOR(config, "scsi:3", scsi_devices, nullptr, false); + NSCSI_CONNECTOR(config, "scsi:4", scsi_devices, "cdrom", false); + NSCSI_CONNECTOR(config, "scsi:5", scsi_devices, nullptr, false); + NSCSI_CONNECTOR(config, "scsi:6", scsi_devices, nullptr, false); + NSCSI_CONNECTOR(config, "scsi:7", scsi_devices, nullptr, false); + NSCSI_CONNECTOR(config, "scsi:0").option_set("wd33c93", WD33C93) + .machine_config([this](device_t *device) { wd33c93(device); }); /* software list */ MCFG_SOFTWARE_LIST_ADD("flop_list","r9751") diff --git a/src/mame/machine/hpc1.cpp b/src/mame/machine/hpc1.cpp index daf6cbbd303..bfa81052854 100644 --- a/src/mame/machine/hpc1.cpp +++ b/src/mame/machine/hpc1.cpp @@ -130,8 +130,8 @@ void hpc1_device::scsi_devices(device_slot_interface &device) void hpc1_device::wd33c93(device_t *device) { device->set_clock(10000000); - downcast(device)->irq_cb().set(*this, FUNC(hpc1_device::scsi_irq)); - downcast(device)->drq_cb().set(*this, FUNC(hpc1_device::scsi_drq)); + downcast(device)->irq_cb().set(*this, FUNC(hpc1_device::scsi_irq)); + downcast(device)->drq_cb().set(*this, FUNC(hpc1_device::scsi_drq)); } void hpc1_device::device_add_mconfig(machine_config &config) @@ -174,7 +174,7 @@ void hpc1_device::device_add_mconfig(machine_config &config) rs232b.rxd_handler().set(m_scc[1], FUNC(scc85c30_device::rxb_w)); NSCSI_BUS(config, "scsibus", 0); - NSCSI_CONNECTOR(config, "scsibus:0").option_set("wd33c93", WD33C93N) + NSCSI_CONNECTOR(config, "scsibus:0").option_set("wd33c93", WD33C93) .machine_config([this](device_t *device) { wd33c93(device); }); NSCSI_CONNECTOR(config, "scsibus:1", scsi_devices, "harddisk", false); NSCSI_CONNECTOR(config, "scsibus:2", scsi_devices, nullptr, false); diff --git a/src/mame/machine/hpc1.h b/src/mame/machine/hpc1.h index 219ae883488..2b30210be46 100644 --- a/src/mame/machine/hpc1.h +++ b/src/mame/machine/hpc1.h @@ -62,7 +62,7 @@ protected: required_device m_maincpu; required_device m_eeprom; - required_device m_wd33c93; + required_device m_wd33c93; required_device_array m_scc; required_device m_pit; required_device m_rtc; diff --git a/src/mame/machine/hpc3.h b/src/mame/machine/hpc3.h index 35c967c2769..21dc941026b 100644 --- a/src/mame/machine/hpc3.h +++ b/src/mame/machine/hpc3.h @@ -133,8 +133,8 @@ protected: }; required_device m_maincpu; - required_device m_wd33c93; - optional_device m_wd33c93_2; + required_device m_wd33c93; + optional_device m_wd33c93_2; required_device m_eeprom; required_device m_rtc; required_device m_ioc2; -- cgit v1.2.3-70-g09d2 From 76323eb770cca3655f40d400fe5f34fbaa573d6c Mon Sep 17 00:00:00 2001 From: Vas Crabb Date: Sun, 27 Jan 2019 14:22:20 +1100 Subject: srcclean and cleanup (nw) --- hash/apple2_flop_orig.xml | 6224 ++++++++++++++-------------- hash/clickstart_cart.xml | 14 +- hash/ekara_japan.xml | 60 +- hash/ekara_japan_d.xml | 6 +- hash/ekara_japan_en.xml | 12 +- hash/ekara_japan_g.xml | 36 +- hash/ekara_japan_m.xml | 4 +- hash/ekara_japan_p.xml | 8 +- hash/ekara_japan_s.xml | 6 +- hash/ekara_japan_sp.xml | 10 +- hash/ekara_us.xml | 2 +- hash/jakks_gamekey_dy.xml | 34 +- hash/jakks_gamekey_nk.xml | 10 +- hash/jakks_gamekey_sw.xml | 8 +- hash/pce_tourvision.xml | 18 +- hash/vsmile_cart.xml | 2 +- hash/vtech_storio_cart.xml | 10 +- scripts/src/machine.lua | 2 +- src/devices/bus/bbc/rom/dfs.cpp | 2 +- src/devices/bus/ekara/rom.cpp | 2 +- src/devices/bus/electron/romboxp.cpp | 4 +- src/devices/bus/nubus/nubus_specpdq.cpp | 39 +- src/devices/bus/vsmile/vsmile_slot.h | 4 +- src/devices/cpu/alpha/alpha.cpp | 4 +- src/devices/cpu/dspp/dspp.h | 18 +- src/devices/cpu/dspp/dsppdrc.cpp | 334 +- src/devices/cpu/m6502/xavix2000.cpp | 12 +- src/devices/cpu/mips/mips3.cpp | 8 +- src/devices/cpu/mips/mips3.h | 2 +- src/devices/cpu/mips/mips3drc.cpp | 10 +- src/devices/cpu/unsp/unsp.h | 12 +- src/devices/cpu/unsp/unspdefs.h | 10 +- src/devices/cpu/unsp/unspdrc.cpp | 12 +- src/devices/machine/nsc810.h | 2 +- src/devices/machine/smc91c9x.cpp | 64 +- src/devices/machine/smc91c9x.h | 6 +- src/devices/machine/spg110.cpp | 8 +- src/devices/machine/spg2xx.cpp | 30 +- src/devices/machine/wd33c9x.cpp | 8 +- src/devices/video/fixfreq.cpp | 2 +- src/emu/devfind.cpp | 2 +- src/frontend/mame/ui/icorender.cpp | 4 +- src/frontend/mame/ui/selgame.cpp | 9 +- src/lib/netlist/devices/net_lib.cpp | 2 +- src/lib/netlist/devices/nld_74107.cpp | 6 +- src/lib/netlist/devices/nld_7450.cpp | 4 +- src/lib/netlist/devices/nld_7490.cpp | 4 +- src/lib/netlist/devices/nld_7493.cpp | 2 +- src/lib/netlist/devices/nld_7497.cpp | 2 +- src/lib/netlist/devices/nld_7497.h | 4 +- src/lib/netlist/nl_base.cpp | 2 +- src/lib/netlist/nl_base.h | 10 +- src/lib/netlist/nl_errstr.h | 2 +- src/lib/netlist/nl_lists.h | 6 +- src/lib/netlist/nl_setup.h | 2 +- src/lib/netlist/plib/parray.h | 36 +- src/lib/netlist/plib/pparser.cpp | 16 +- src/lib/netlist/plib/pstring.h | 2 +- src/lib/netlist/prg/nltool.cpp | 2 +- src/lib/netlist/prg/nlwav.cpp | 12 +- src/lib/netlist/solver/nld_matrix_solver.h | 2 +- src/lib/netlist/solver/nld_ms_gmres.h | 10 +- src/mame/drivers/5clown.cpp | 12 +- src/mame/drivers/aerofgt.cpp | 2 +- src/mame/drivers/alg.cpp | 2 +- src/mame/drivers/argus.cpp | 4 +- src/mame/drivers/avt.cpp | 12 +- src/mame/drivers/battlane.cpp | 4 +- src/mame/drivers/bigevglf.cpp | 2 +- src/mame/drivers/blktiger.cpp | 4 +- src/mame/drivers/brkthru.cpp | 8 +- src/mame/drivers/chinagat.cpp | 18 +- src/mame/drivers/clickstart.cpp | 20 +- src/mame/drivers/dacholer.cpp | 2 +- src/mame/drivers/ddragon.cpp | 16 +- src/mame/drivers/deniam.cpp | 6 +- src/mame/drivers/discoboy.cpp | 2 +- src/mame/drivers/drmicro.cpp | 2 +- src/mame/drivers/dynax.cpp | 34 +- src/mame/drivers/fantland.cpp | 8 +- src/mame/drivers/fcrash.cpp | 32 +- src/mame/drivers/firetrap.cpp | 18 +- src/mame/drivers/fromance.cpp | 18 +- src/mame/drivers/fuukifg2.cpp | 4 +- src/mame/drivers/gaiden.cpp | 2 +- src/mame/drivers/galspnbl.cpp | 6 +- src/mame/drivers/gladiatr.cpp | 18 +- src/mame/drivers/goal92.cpp | 2 +- src/mame/drivers/gsword.cpp | 10 +- src/mame/drivers/hnayayoi.cpp | 2 +- src/mame/drivers/hp_ipc.cpp | 2 +- src/mame/drivers/hyperspt.cpp | 14 +- src/mame/drivers/indy_indigo2.cpp | 22 +- src/mame/drivers/karnov.cpp | 4 +- src/mame/drivers/kchamp.cpp | 12 +- src/mame/drivers/klax.cpp | 6 +- src/mame/drivers/konamim2.cpp | 2 +- src/mame/drivers/kungfur.cpp | 8 +- src/mame/drivers/kurukuru.cpp | 2 +- src/mame/drivers/lkage.cpp | 2 +- src/mame/drivers/lucky74.cpp | 16 +- src/mame/drivers/lwings.cpp | 20 +- src/mame/drivers/m90.cpp | 2 +- src/mame/drivers/matmania.cpp | 4 +- src/mame/drivers/megadriv_acbl.cpp | 2 +- src/mame/drivers/mermaid.cpp | 2 +- src/mame/drivers/metlclsh.cpp | 4 +- src/mame/drivers/mgavegas.cpp | 2 +- src/mame/drivers/miniboy7.cpp | 14 +- src/mame/drivers/mitchell.cpp | 10 +- src/mame/drivers/mjkjidai.cpp | 2 +- src/mame/drivers/namcond1.cpp | 2 +- src/mame/drivers/nmg5.cpp | 4 +- src/mame/drivers/ojankohs.cpp | 24 +- src/mame/drivers/opwolf.cpp | 16 +- src/mame/drivers/pachifev.cpp | 4 +- src/mame/drivers/palestra.cpp | 2 +- src/mame/drivers/pc9801.cpp | 2 +- src/mame/drivers/pcktgal.cpp | 2 +- src/mame/drivers/peplus.cpp | 8 +- src/mame/drivers/r9751.cpp | 4 +- src/mame/drivers/rad_eu3a14.cpp | 18 +- src/mame/drivers/rainbow.cpp | 6 +- src/mame/drivers/rastan.cpp | 8 +- src/mame/drivers/rmhaihai.cpp | 2 +- src/mame/drivers/sanremo.cpp | 24 +- src/mame/drivers/seta.cpp | 4 +- src/mame/drivers/sf.cpp | 8 +- src/mame/drivers/smc777.cpp | 18 +- src/mame/drivers/sms_bootleg.cpp | 2 +- src/mame/drivers/sothello.cpp | 4 +- src/mame/drivers/spg110.cpp | 10 +- src/mame/drivers/splash.cpp | 10 +- src/mame/drivers/srmp2.cpp | 22 +- src/mame/drivers/storio.cpp | 18 +- src/mame/drivers/suprgolf.cpp | 4 +- src/mame/drivers/system16.cpp | 2 +- src/mame/drivers/taito_l.cpp | 20 +- src/mame/drivers/taitoair.cpp | 4 +- src/mame/drivers/tbowl.cpp | 4 +- src/mame/drivers/tehkanwc.cpp | 8 +- src/mame/drivers/testpat.cpp | 8 +- src/mame/drivers/toaplan1.cpp | 8 +- src/mame/drivers/topspeed.cpp | 4 +- src/mame/drivers/trackfld.cpp | 12 +- src/mame/drivers/trkfldch.cpp | 4 +- src/mame/drivers/tubep.cpp | 18 +- src/mame/drivers/twincobr.cpp | 4 +- src/mame/drivers/vigilant.cpp | 2 +- src/mame/drivers/vii.cpp | 40 +- src/mame/drivers/wacky_gator.cpp | 10 +- src/mame/drivers/wardner.cpp | 6 +- src/mame/drivers/warriorb.cpp | 8 +- src/mame/drivers/wc90b.cpp | 4 +- src/mame/drivers/welltris.cpp | 4 +- src/mame/drivers/wgp.cpp | 6 +- src/mame/drivers/xavix.cpp | 76 +- src/mame/drivers/yunsung8.cpp | 8 +- src/mame/includes/vsmile.h | 18 +- src/mame/includes/xavix.h | 6 +- src/mame/machine/hpc1.cpp | 24 +- src/mame/machine/hpc1.h | 4 +- src/mame/machine/hpc3.cpp | 30 +- src/mame/machine/hpc3.h | 4 +- src/mame/machine/mbc55x_kbd.cpp | 6 +- src/mame/machine/nl_palestra.cpp | 14 +- src/mame/machine/nl_tp1983.cpp | 8 +- src/mame/machine/nl_tp1985.cpp | 18 +- src/mame/machine/pce_cd.cpp | 4 +- src/mame/machine/taitocchip.cpp | 8 +- src/mame/machine/xavix.cpp | 4 +- src/mame/machine/xavix2002_io.cpp | 2 +- src/mame/machine/xavix2002_io.h | 2 +- src/mame/machine/xbox_pci.cpp | 2 +- src/mame/video/arabian.cpp | 8 +- src/mame/video/funworld.cpp | 6 +- src/mame/video/tia.cpp | 192 +- src/mame/video/xavix.cpp | 2 +- 178 files changed, 4239 insertions(+), 4231 deletions(-) (limited to 'scripts/src/machine.lua') diff --git a/hash/apple2_flop_orig.xml b/hash/apple2_flop_orig.xml index 92c0f8da1ac..ce26055f178 100644 --- a/hash/apple2_flop_orig.xml +++ b/hash/apple2_flop_orig.xml @@ -3,3123 +3,3123 @@ - - Agent USA - 1984 - Scholastic - - - - - - - - - - - - - Airheart - 1986 - Broderbund Software - - - - - - - - - - - - - Alien Ambush - 1981 - Micro Distributors - - - - - - - - - - - - - Ankh - 1983 - Datamost - - - - - - - - - - - - - Apple Cider Spider - 1983 - Sierra On-Line - - - - - - - - - - - - - Apple Galaxian - 1980 - Broderbund Software - - - - - - - - - - - - - Aquatron - 1983 - Sierra On-Line - - - - - - - - - - - - - Archon: The Light and The Dark - 1984 - Electronic Arts - - - - - - - - - - - - - Ardy the Aardvark - 1983 - Datamost - - - - - - - - - - - - - Autobahn - 1981 - Sirius Software - - - - - - - - - - - - - Axis Assassin - 1982 - Electronic Arts - - - - - - - - - - - - - Aztec - 1982 - Datamost - - - - - - - - - - - - - Bad Dudes - 1988 - Data East USA - - - - - - - - - - - - - - - - - - - - Ballblazer - 1985 - Epyx - - - - - - - - - - - - - Batman: The Caped Crusader - 1985 - Data East USA - - - - - - - - - - - - - - - - - - - - BC's Quest for Tires - 1983 - Sierra On-Line - - - - - - - - - - - - - Bellhop - 1982 - Hayden Book Company - - - - - - - - - - - - - Below the Root - 1984 - Hayden Book Company - - - - - - - - - - - - - - - - - - - - The Bilestoad - 1983 - Datamost - - - - - - - - - - - - - Bug Battle - 1982 - United Software of America - - - - - - - - - - - - - Cannonball Blitz - 1982 - On-Line Systems - - - - - - - - - - - - - Caverns of Callisto - 1983 - Origin Systems - - - - - - - - - - - - - Ceiling Zero - 1981 - Turnkey Software - - - - - - - - - - - - - Centipede - 1983 - Atarisoft - - - - - - - - - - - - - Commando - 1987 - Data East USA - - - - - - - - - - - - - Congo Bongo - 1987 - SEGA Enterprises - - - - - - - - - - - - - Conquering Worlds - 1983 - Datamost - - - - - - - - - - - - - Copts and Robbers - 1981 - Sirius Software - - - - - - - - - - - - - County Fair - 1981 - Datamost - - - - - - - - - - - - - Crazy Mazey - 1982 - Datamost - - - - - - - - - - - - - Crisis Mountain - 1982 - Micro Fun - - - - - - - - - - - - - Crossfire - 1981 - On-Line Systems - - - - - - - - - - - - - Cubit - 1983 - Micromax - - - - - - - - - - - - - Cyber Strike - 1980 - Sirius Software - - - - - - - - - - - - - The Dam Busters - 1985 - Accolade - - - - - - - - - - - - - Death Sword - 1987 - Epyx - - - - - - - - - - - - - Defender II: Stargate - 1983 - Atarisoft - - - - - - - - - - - - - Destroyer - 1986 - Epyx - - - - - - - - - - - - - Dino Eggs - 1983 - Micro Fun - - - - - - - - - - - - - Dive Bomber - 1988 - Epyx - - - - - - - - - - - - - Donkey Kong - 1983 - Atarisoft - - - - - - - - - - - - - Drol - 1983 - Broderbund Software - - - - - - - - - - - - - Dung Beetles - 1982 - Datasoft - - - - - - - - - - - - - The Eidolon - 1985 - Epyx - - - - - - - - - - - - - Epoch - 1981 - Sirius Software - - - - - - - - - - - - - Falcons - 1981 - Piccadilly Software - - - - - - - - - - - - - - Fight Night - 1985 - Accolade - - - - - - - - - - - - - Flight Simulator II (v2.0) - 1985 - Accolade - - - - - - - - - - - - - Flip Out - 1982 - Sirius Software - - - - - - - - - - - - - Force 7 - 1987 - Datasoft - - - - - - - - - - - - - Formula 1 Racer - 1983 - Gentry Software - - - - - - - - - - - - - Free Fall - 1982 - Sirius Software - - - - - - - - - - - - - Frogger - 1981 - Sierra On-Line - - - - - - - - - - - - - Frogger II: Threedeep - 1984 - SEGA Enterprises - - - - - - - - - - - - - G.I. Joe - 1985 - Epyx - - - - - - - - - - - - - - - - - - - - The Games - Summer Edition - 1988 - Epyx - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - GATO - 1985 - Spectrum Holobyte - - - - - - - - - - - - - Genetic Drift - 1981 - Broderbund Software - - - - - - - - - - - - - Gobbler - 1981 - On-Line Systems - - - - - - - - - - - - - The Goonies - 1985 - Datasoft - - - - - - - - - - - - - Gumball - 1983 - Broderbund Software - - - - - - - - - - - - - The Heist - 1983 - Micro Fun - - - - - - - - - - - - - HERO - Helicopter Emergency Rescue Operation - 1983 - Activision - - - - - - - - - - - - - Hadron - 1981 - Sirius Software - - - - - - - - - - - - - Hard Hat Mack - 1983 - Electronic Arts - - - - - - - - - - - - Hardball - 1985 - Accolade - - - - - - - - - - - - - Head On - 1980 - California Pacific Computers - - - - - - - - - - - - - High Rise - 1983 - Micro Fun - - - - - - - - - - - - - Ikari Warriors - 1983 - Data East USA - - - - - - - - - - - - - - - - - - - - Ikari Warriors 2: Victory Road - 1981 - Sirius Software - - - - - - - - - - - - - - - - - + + Agent USA + 1984 + Scholastic + + + + + + + + + + + + + Airheart + 1986 + Broderbund Software + + + + + + + + + + + + + Alien Ambush + 1981 + Micro Distributors + + + + + + + + + + + + + Ankh + 1983 + Datamost + + + + + + + + + + + + + Apple Cider Spider + 1983 + Sierra On-Line + + + + + + + + + + + + + Apple Galaxian + 1980 + Broderbund Software + + + + + + + + + + + + + Aquatron + 1983 + Sierra On-Line + + + + + + + + + + + + + Archon: The Light and The Dark + 1984 + Electronic Arts + + + + + + + + + + + + + Ardy the Aardvark + 1983 + Datamost + + + + + + + + + + + + + Autobahn + 1981 + Sirius Software + + + + + + + + + + + + + Axis Assassin + 1982 + Electronic Arts + + + + + + + + + + + + + Aztec + 1982 + Datamost + + + + + + + + + + + + + Bad Dudes + 1988 + Data East USA + + + + + + + + + + + + + + + + + + + + Ballblazer + 1985 + Epyx + + + + + + + + + + + + + Batman: The Caped Crusader + 1985 + Data East USA + + + + + + + + + + + + + + + + + + + + BC's Quest for Tires + 1983 + Sierra On-Line + + + + + + + + + + + + + Bellhop + 1982 + Hayden Book Company + + + + + + + + + + + + + Below the Root + 1984 + Hayden Book Company + + + + + + + + + + + + + + + + + + + + The Bilestoad + 1983 + Datamost + + + + + + + + + + + + + Bug Battle + 1982 + United Software of America + + + + + + + + + + + + + Cannonball Blitz + 1982 + On-Line Systems + + + + + + + + + + + + + Caverns of Callisto + 1983 + Origin Systems + + + + + + + + + + + + + Ceiling Zero + 1981 + Turnkey Software + + + + + + + + + + + + + Centipede + 1983 + Atarisoft + + + + + + + + + + + + + Commando + 1987 + Data East USA + + + + + + + + + + + + + Congo Bongo + 1987 + SEGA Enterprises + + + + + + + + + + + + + Conquering Worlds + 1983 + Datamost + + + + + + + + + + + + + Copts and Robbers + 1981 + Sirius Software + + + + + + + + + + + + + County Fair + 1981 + Datamost + + + + + + + + + + + + + Crazy Mazey + 1982 + Datamost + + + + + + + + + + + + + Crisis Mountain + 1982 + Micro Fun + + + + + + + + + + + + + Crossfire + 1981 + On-Line Systems + + + + + + + + + + + + + Cubit + 1983 + Micromax + + + + + + + + + + + + + Cyber Strike + 1980 + Sirius Software + + + + + + + + + + + + + The Dam Busters + 1985 + Accolade + + + + + + + + + + + + + Death Sword + 1987 + Epyx + + + + + + + + + + + + + Defender II: Stargate + 1983 + Atarisoft + + + + + + + + + + + + + Destroyer + 1986 + Epyx + + + + + + + + + + + + + Dino Eggs + 1983 + Micro Fun + + + + + + + + + + + + + Dive Bomber + 1988 + Epyx + + + + + + + + + + + + + Donkey Kong + 1983 + Atarisoft + + + + + + + + + + + + + Drol + 1983 + Broderbund Software + + + + + + + + + + + + + Dung Beetles + 1982 + Datasoft + + + + + + + + + + + + + The Eidolon + 1985 + Epyx + + + + + + + + + + + + + Epoch + 1981 + Sirius Software + + + + + + + + + + + + + Falcons + 1981 + Piccadilly Software + + + + + + + + + + + + + + Fight Night + 1985 + Accolade + + + + + + + + + + + + + Flight Simulator II (v2.0) + 1985 + Accolade + + + + + + + + + + + + + Flip Out + 1982 + Sirius Software + + + + + + + + + + + + + Force 7 + 1987 + Datasoft + + + + + + + + + + + + + Formula 1 Racer + 1983 + Gentry Software + + + + + + + + + + + + + Free Fall + 1982 + Sirius Software + + + + + + + + + + + + + Frogger + 1981 + Sierra On-Line + + + + + + + + + + + + + Frogger II: Threedeep + 1984 + SEGA Enterprises + + + + + + + + + + + + + G.I. Joe + 1985 + Epyx + + + + + + + + + + + + + + + + + + + + The Games - Summer Edition + 1988 + Epyx + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + GATO + 1985 + Spectrum Holobyte + + + + + + + + + + + + + Genetic Drift + 1981 + Broderbund Software + + + + + + + + + + + + + Gobbler + 1981 + On-Line Systems + + + + + + + + + + + + + The Goonies + 1985 + Datasoft + + + + + + + + + + + + + Gumball + 1983 + Broderbund Software + + + + + + + + + + + + + The Heist + 1983 + Micro Fun + + + + + + + + + + + + + HERO - Helicopter Emergency Rescue Operation + 1983 + Activision + + + + + + + + + + + + + Hadron + 1981 + Sirius Software + + + + + + + + + + + + + Hard Hat Mack + 1983 + Electronic Arts + + + + + + + + + + + + Hardball + 1985 + Accolade + + + + + + + + + + + + + Head On + 1980 + California Pacific Computers + + + + + + + + + + + + + High Rise + 1983 + Micro Fun + + + + + + + + + + + + + Ikari Warriors + 1983 + Data East USA + + + + + + + + + + + + + + + + + + + + Ikari Warriors 2: Victory Road + 1981 + Sirius Software + + + + + + + + + + + + + + + + + - International Gran Prix - 1982 - MUSE Software - - - - - - - - - - - - - Jawbreaker - 1981 - On-Line Systems - - - - - - - - - - - - - Jawbreaker ][ - 1982 - Sierra On-Line - - - - - - - - - - - - - The Jet - 1986 - subLOGIC - - - - - - - - - - - - - Joust - 1983 - Atarisoft - - - - - - - - - - - - - Julius Erving and Larry Bird Go One on One - 1983 - Electronic Arts - - - - - - - - - - - - - Jungle Hunt - 1984 - Atarisoft - - - - - - - - - - - - - Karate Champ - 1985 - Data East - - - - - - - - - - - - - Karateka - 1984 - Broderbund Software - - - - - - - - - - - - - - - - - - - - Kid Niki - 1987 - Data East - - - - - - - - - - - - - - - - - - - - Kung Fu Master - 1985 - Data East - - - - - - - - - - - - - L.A. Crackdown - 1988 - Epyx - - - - - - - - - - - - - - - - - - - - Lock 'n Chase - 1982 - Mattel Electronics - - - - - - - - - - - - - Lode Runner - 1983 - Broderbund - - - - - - - - - - + International Gran Prix + 1982 + MUSE Software + + + + + + + + + + + + + Jawbreaker + 1981 + On-Line Systems + + + + + + + + + + + + + Jawbreaker ][ + 1982 + Sierra On-Line + + + + + + + + + + + + + The Jet + 1986 + subLOGIC + + + + + + + + + + + + + Joust + 1983 + Atarisoft + + + + + + + + + + + + + Julius Erving and Larry Bird Go One on One + 1983 + Electronic Arts + + + + + + + + + + + + + Jungle Hunt + 1984 + Atarisoft + + + + + + + + + + + + + Karate Champ + 1985 + Data East + + + + + + + + + + + + + Karateka + 1984 + Broderbund Software + + + + + + + + + + + + + + + + + + + + Kid Niki + 1987 + Data East + + + + + + + + + + + + + + + + + + + + Kung Fu Master + 1985 + Data East + + + + + + + + + + + + + L.A. Crackdown + 1988 + Epyx + + + + + + + + + + + + + + + + + + + + Lock 'n Chase + 1982 + Mattel Electronics + + + + + + + + + + + + + Lode Runner + 1983 + Broderbund + + + + + + + + + + - Lost Tomb - 1984 - Datasoft - - - - - - - - - - - - - Marauder - 1982 - On-Line Systems - - - - - - - - - - - - - Marble Madness - 1986 - Electronic Arts - - - - - - - - - - - - - - - - - - - - Mars Cars - 1982 - Datamost - - - - - - - - - - - - - Mating Zone - 1982 - Datamost - - - - - - - - - - - - - Megabots - 1986 - Neosoft - - - - - - - - - - - - - Might and Magic - 1986 - New World Computing - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Miner 2049er - 1982 - Micro Fun - - - - - - - - - - - - - Minit Man - 1983 - Penguin Software - - - - - - - - - - - - - Impossible Mission II - 1988 - Epyx - - - - - - - - - - - - - - - - - - - - Money Muncher - 1982 - Datamost - - - - - - - - - - - - - Monster Smash - 1983 - Datamost - - - - - - - - - - - - - Montezuma's Revenge - 1984 - Parker Brothers - - - - - - - - - - - - - Moon Patrol - 1983 - Atarisoft - - - - - - - - - - - - - The Movie Monster Game - 1986 - Epyx - - - - - - - - - - - - - - - - - - - - Mr. Robot and his Robot Factory - 1984 - Datamost - - - - - - - - - - - - - Ms. Pac-Man - 1983 - Atarisoft - - - - - - - - - - - - - Night Mission Pinball - 1982 - subLOGIC - - - - - - - - - - - - - Night Stalker - 1982 - Mattel Electronics - - - - - - - - - - - - - Orbitron - 1981 - Sirius Software - - - - - - - - - - - - - O'Riley's Mine - 1981 - Datasoft - - - - - - - - - - - - - Outpost - 1981 - Sirius Software - - - - - - - - - - - - - Paperboy - 1988 - Mindscape - - - - - - - - - - - - - Pest Patrol - 1982 - Sierra On-Line - - - - - - - - - - - - - Phantoms Five - 1980 - Sirius Software - - - - - - - - - - - - - Picnic Paranoia - 1982 - Synapse Software - - - - - - - - - - - - - Pitfall II: Lost Caverns - 1984 - Activision - - - - - - - - - - - - - Pitstop II - 1984 - Epyx - - - - - - - - - - - - - Planetfall (r10) - 1988 - Infocom - - - - - - - - - - - - - - - - - - - - Plasmania - 1983 - Sirius Software - - - - - - - - - - - - - Platoon - 1988 - Data East USA - - - - - - - - - - - - - - - - - - - - Pool 1.5 - 1981 - Innovative Design Software, Inc. - - - - - - - - - - - - - Pooyan - 1984 - Datasoft - - - - - - - - - - - - - Prince of Persia - 1989 - Broderbund - - - - - - - - - - - - - - - - - - - - Qix - 1989 - Taito America - - - - - - - - - - - - - Rad Warrior - 1987 - Epyx - - - - - - - - - - - - - Rampage - 1988 - Activision - - - - - - - - - - - - - Raster Blaster - 1981 - BudgeCo - - - - - - - - - - - - - Red Alert - 1981 - Broderbund - - - - - - - - - - - - - Repton - 1982 - Sirius Software - - - - - - - - - - - - - Rescue Raiders - 1984 - Sir-Tech - - - - - - - - - - - - - RoboCop - 1988 - Data East USA - - - - - - - - - - - - - - - - - - - - Robotron 2084 - 1983 - Atarisoft - - - - - - - - - - - - - Roundabout - 1983 - Datamost - - - - - - - - - - - - - Russki Duck - 1982 - Gebelli Software - - - - - - - - - - - - - Sabotage - 1981 - On-Line Systems - - - - - - - - - - - - - Sammy Lightfoot - 1983 - Sierra On-Line - - - - - - - - - - - - - Sargon III - 1983 - Hayden Book Company - - - - - - - - - - - - - Sea Dragon - 1982 - Adventure International - - - - - - - - - - - - - Shadowkeep - 1983 - Trillium - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Shanghai - 1986 - Activision - - - - - - - - - - + Lost Tomb + 1984 + Datasoft + + + + + + + + + + + + + Marauder + 1982 + On-Line Systems + + + + + + + + + + + + + Marble Madness + 1986 + Electronic Arts + + + + + + + + + + + + + + + + + + + + Mars Cars + 1982 + Datamost + + + + + + + + + + + + + Mating Zone + 1982 + Datamost + + + + + + + + + + + + + Megabots + 1986 + Neosoft + + + + + + + + + + + + + Might and Magic + 1986 + New World Computing + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Miner 2049er + 1982 + Micro Fun + + + + + + + + + + + + + Minit Man + 1983 + Penguin Software + + + + + + + + + + + + + Impossible Mission II + 1988 + Epyx + + + + + + + + + + + + + + + + + + + + Money Muncher + 1982 + Datamost + + + + + + + + + + + + + Monster Smash + 1983 + Datamost + + + + + + + + + + + + + Montezuma's Revenge + 1984 + Parker Brothers + + + + + + + + + + + + + Moon Patrol + 1983 + Atarisoft + + + + + + + + + + + + + The Movie Monster Game + 1986 + Epyx + + + + + + + + + + + + + + + + + + + + Mr. Robot and his Robot Factory + 1984 + Datamost + + + + + + + + + + + + + Ms. Pac-Man + 1983 + Atarisoft + + + + + + + + + + + + + Night Mission Pinball + 1982 + subLOGIC + + + + + + + + + + + + + Night Stalker + 1982 + Mattel Electronics + + + + + + + + + + + + + Orbitron + 1981 + Sirius Software + + + + + + + + + + + + + O'Riley's Mine + 1981 + Datasoft + + + + + + + + + + + + + Outpost + 1981 + Sirius Software + + + + + + + + + + + + + Paperboy + 1988 + Mindscape + + + + + + + + + + + + + Pest Patrol + 1982 + Sierra On-Line + + + + + + + + + + + + + Phantoms Five + 1980 + Sirius Software + + + + + + + + + + + + + Picnic Paranoia + 1982 + Synapse Software + + + + + + + + + + + + + Pitfall II: Lost Caverns + 1984 + Activision + + + + + + + + + + + + + Pitstop II + 1984 + Epyx + + + + + + + + + + + + + Planetfall (r10) + 1988 + Infocom + + + + + + + + + + + + + + + + + + + + Plasmania + 1983 + Sirius Software + + + + + + + + + + + + + Platoon + 1988 + Data East USA + + + + + + + + + + + + + + + + + + + + Pool 1.5 + 1981 + Innovative Design Software, Inc. + + + + + + + + + + + + + Pooyan + 1984 + Datasoft + + + + + + + + + + + + + Prince of Persia + 1989 + Broderbund + + + + + + + + + + + + + + + + + + + + Qix + 1989 + Taito America + + + + + + + + + + + + + Rad Warrior + 1987 + Epyx + + + + + + + + + + + + + Rampage + 1988 + Activision + + + + + + + + + + + + + Raster Blaster + 1981 + BudgeCo + + + + + + + + + + + + + Red Alert + 1981 + Broderbund + + + + + + + + + + + + + Repton + 1982 + Sirius Software + + + + + + + + + + + + + Rescue Raiders + 1984 + Sir-Tech + + + + + + + + + + + + + RoboCop + 1988 + Data East USA + + + + + + + + + + + + + + + + + + + + Robotron 2084 + 1983 + Atarisoft + + + + + + + + + + + + + Roundabout + 1983 + Datamost + + + + + + + + + + + + + Russki Duck + 1982 + Gebelli Software + + + + + + + + + + + + + Sabotage + 1981 + On-Line Systems + + + + + + + + + + + + + Sammy Lightfoot + 1983 + Sierra On-Line + + + + + + + + + + + + + Sargon III + 1983 + Hayden Book Company + + + + + + + + + + + + + Sea Dragon + 1982 + Adventure International + + + + + + + + + + + + + Shadowkeep + 1983 + Trillium + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Shanghai + 1986 + Activision + + + + + + + + + + - Shuffleboard - 1981 - IDSI - - - - - - - - - - - - - Skyfox - 1984 - Electronic Arts - - - - - - - - - - - - - Snack Attack - 1981 - Datamost - - - - - - - - - - - - - Snake Byte - 1981 - Sirius Software - - - - - - - - - - - - - Sneakers - 1981 - Sirius Software - - - - - - - - - - - - - - Space Eggs - 1981 - Sirius Software - - - - - - - - - - - - - Space Quarks - 1981 - Broderbund Software - - - - - - - - - - - - - Spare Change - 1983 - Broderbund Software - - - - - - - - - - - - - Spiderbot - 1988 - Epyx - - - - - - - - - - - - - Spindizzy - 1986 - Activision - - - - - - - - - - - - - Spy Hunter - 1983 - Bally Midway - - - - - - - - - - - - - The Spy Strikes Back - 1983 - Penguin Software - - - - - - - - - - - - - Spy vs Spy III: Arctic Antics - 1983 - Bally Midway - - - - - - - - - - - - - Spy's Demise - 1982 - Penguin - - - - - - - - - - - - - Star Cruiser - 1980 - Sirius Software - - - - - - - - - - - - - Star Thief - 1981 - Cavalier Computer - - - - - - - - - - - - - Stellar 7 - 1984 - Penguin Software - - - - - - - - - - - - - Street Sports Baseball - 1987 - Epyx - - - - - - - - - - - - - Street Sports Basketball - 1987 - Epyx - - - - - - - - - - - - - - - - - - - - Street Sports Football - 1988 - Epyx - - - - - - - - - - - - - - - - - - - - Street Sports Soccer - 1988 - Epyx - - - - - - - - - - - - - Sub Battle Simulator - 1986 - Epyx - - - - - - - - - - - - - - - - - - - - Suicide - 1981 - Piccadilly Software - - - - - - - - - - - - - Summer Games - 1984 - Epyx - - - - - - - - - - - - - - - - - - - - Swiss Family Robinson - 1984 - Windham Classics - - - - - - - - - - - - - Tag Team Wrestling - 1986 - Data East USA - - - - - - - - - - - - - Temple of Apshai Trilogy - 1985 - Epyx - - - - - - - - - - - - - Test Drive - 1985 - Accolade - - - - - - - - - - - - - - - - - - - - Tetris (128K) - 1987 - Spectrum HoloByte - - - - - - - - - - - - - Tharolian Tunnels - 1982 - Datamost - - - - - - - - - - - - - Thunder Bombs - 1982 - Penguin Software - - - - - - - - - - - - - Thunderchopper - 1987 - ActionSoft - - - - - - - - - - - - - Tomahawk - 1987 - Datasoft - - - - - - - - - - - - - Trick Shot - 1981 - IDSI - - - - - - - - - - - - - - - - - - - - Tubeway II - 1982 - Datamost - - - - - - - - - - - - - Twerps - 1981 - Sirius Software - - - - - - - - - - - - - Ultima IV: Quest of the Avatar - 1985 - Origin Systems - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Ultima V: Warriors of Destiny - 1988 - Origin Systems - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Up 'N Down - 1981 - Bally Midway - - - - - - - - - - - - - Vindicator - 1983 - H.A.L. Labs - - - - - - - - - - - - - Wavy Navy - 1982 - Sirius Software - - - - - - - - - - - - - Wayout - 1982 - Sirius Software - - - - - - - - - - - - - Where in the USA is Carmen Sandiego - 1986 - Broderbund - - - - - - - - - - - - - - - - - - - - Wings of Fury - 1987 - Broderbund - - - - - - - - - - - - - - - - - - - - Wishbringer (r23) - 1988 - Infocom - - - - - - - - - - - - - - - - - - - - World Karate Championship - 1986 - Epyx - - - - - - - - - - - - - The World's Greatest Baseball Game - 1984 - Epyx - - - - - - - - - - - - - The World's Greatest Football Game - 1985 - Epyx - - - - - - - - - - - - - - - - - - - - Xevious - 1984 - Mindscape - - - - - - - - - - - - - Zendar - 1982 - subLOGIC - - - - - - - - - - - - - Zorro - 1985 - Datasoft - - - - - - - - - - + Shuffleboard + 1981 + IDSI + + + + + + + + + + + + + Skyfox + 1984 + Electronic Arts + + + + + + + + + + + + + Snack Attack + 1981 + Datamost + + + + + + + + + + + + + Snake Byte + 1981 + Sirius Software + + + + + + + + + + + + + Sneakers + 1981 + Sirius Software + + + + + + + + + + + + + + Space Eggs + 1981 + Sirius Software + + + + + + + + + + + + + Space Quarks + 1981 + Broderbund Software + + + + + + + + + + + + + Spare Change + 1983 + Broderbund Software + + + + + + + + + + + + + Spiderbot + 1988 + Epyx + + + + + + + + + + + + + Spindizzy + 1986 + Activision + + + + + + + + + + + + + Spy Hunter + 1983 + Bally Midway + + + + + + + + + + + + + The Spy Strikes Back + 1983 + Penguin Software + + + + + + + + + + + + + Spy vs Spy III: Arctic Antics + 1983 + Bally Midway + + + + + + + + + + + + + Spy's Demise + 1982 + Penguin + + + + + + + + + + + + + Star Cruiser + 1980 + Sirius Software + + + + + + + + + + + + + Star Thief + 1981 + Cavalier Computer + + + + + + + + + + + + + Stellar 7 + 1984 + Penguin Software + + + + + + + + + + + + + Street Sports Baseball + 1987 + Epyx + + + + + + + + + + + + + Street Sports Basketball + 1987 + Epyx + + + + + + + + + + + + + + + + + + + + Street Sports Football + 1988 + Epyx + + + + + + + + + + + + + + + + + + + + Street Sports Soccer + 1988 + Epyx + + + + + + + + + + + + + Sub Battle Simulator + 1986 + Epyx + + + + + + + + + + + + + + + + + + + + Suicide + 1981 + Piccadilly Software + + + + + + + + + + + + + Summer Games + 1984 + Epyx + + + + + + + + + + + + + + + + + + + + Swiss Family Robinson + 1984 + Windham Classics + + + + + + + + + + + + + Tag Team Wrestling + 1986 + Data East USA + + + + + + + + + + + + + Temple of Apshai Trilogy + 1985 + Epyx + + + + + + + + + + + + + Test Drive + 1985 + Accolade + + + + + + + + + + + + + + + + + + + + Tetris (128K) + 1987 + Spectrum HoloByte + + + + + + + + + + + + + Tharolian Tunnels + 1982 + Datamost + + + + + + + + + + + + + Thunder Bombs + 1982 + Penguin Software + + + + + + + + + + + + + Thunderchopper + 1987 + ActionSoft + + + + + + + + + + + + + Tomahawk + 1987 + Datasoft + + + + + + + + + + + + + Trick Shot + 1981 + IDSI + + + + + + + + + + + + + + + + + + + + Tubeway II + 1982 + Datamost + + + + + + + + + + + + + Twerps + 1981 + Sirius Software + + + + + + + + + + + + + Ultima IV: Quest of the Avatar + 1985 + Origin Systems + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Ultima V: Warriors of Destiny + 1988 + Origin Systems + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Up 'N Down + 1981 + Bally Midway + + + + + + + + + + + + + Vindicator + 1983 + H.A.L. Labs + + + + + + + + + + + + + Wavy Navy + 1982 + Sirius Software + + + + + + + + + + + + + Wayout + 1982 + Sirius Software + + + + + + + + + + + + + Where in the USA is Carmen Sandiego + 1986 + Broderbund + + + + + + + + + + + + + + + + + + + + Wings of Fury + 1987 + Broderbund + + + + + + + + + + + + + + + + + + + + Wishbringer (r23) + 1988 + Infocom + + + + + + + + + + + + + + + + + + + + World Karate Championship + 1986 + Epyx + + + + + + + + + + + + + The World's Greatest Baseball Game + 1984 + Epyx + + + + + + + + + + + + + The World's Greatest Football Game + 1985 + Epyx + + + + + + + + + + + + + + + + + + + + Xevious + 1984 + Mindscape + + + + + + + + + + + + + Zendar + 1982 + subLOGIC + + + + + + + + + + + + + Zorro + 1985 + Datasoft + + + + + + + + + + diff --git a/hash/clickstart_cart.xml b/hash/clickstart_cart.xml index 156e3e16df2..43b1151435b 100644 --- a/hash/clickstart_cart.xml +++ b/hash/clickstart_cart.xml @@ -158,7 +158,7 @@ - + Toy Story (SP) 2007 @@ -171,8 +171,8 @@ - - + + Bob the Builder (UK) 2007 @@ -185,8 +185,8 @@ - - + + Thomas & Friends (UK) 2007 @@ -199,7 +199,7 @@ - + Dora the Explorer (UK) @@ -213,6 +213,6 @@ - + diff --git a/hash/ekara_japan.xml b/hash/ekara_japan.xml index 34691abfb53..a6e6faa2e08 100644 --- a/hash/ekara_japan.xml +++ b/hash/ekara_japan.xml @@ -7,9 +7,9 @@ Japanese e-kara carts appear to have a number of different genres split across various cart sub-series (often supporting different hw types) special releases etc. - + This file is for the base set (number on case, ECxxxx-xxx part numbers) - + The genres in the Japanese games are represented by the code after the EC/DC/MC/GC/PC etc. number JPM = J-Pop Mix ATS = Artist Selection (all songs by a single artist) @@ -27,21 +27,21 @@ ATM = unknown (used by the M series 'mini' carts) TPJ = TV Pop MIN = unknown - + Some Japanese carts have a number starting with S (S-x on case, SCxxxx-xxx part numbers) (see ekara_japan_s.xml) (for e-kara - custom presentation) M (M-x on case, MCxxxx-xxx part numbers) (see ekara_japan_m.xml) (for e-kara - custom presentation) - EN (EN-X on case, no part numbers) (see ekara_japan_en.xml) (for e-kara - custom presentation) (check other compatibility) + EN (EN-X on case, no part numbers) (see ekara_japan_en.xml) (for e-kara - custom presentation) (check other compatibility) G (G-x on case, GCxxxx-xxx part numbers) (see ekara_japan_g.xml) (for e-kara, Popira / 2) P (P-x on case, PCxxxx-xxx part numbers) (see ekara_japan_p.xml) (for e-kara, Popira / 2, DDR Family Mat) - D (D-x on case, DCxxxx-xxx part numbers) (see ekara_japan_d.xml) (for e-kara, Popira / 2, Taiko De Popira) + D (D-x on case, DCxxxx-xxx part numbers) (see ekara_japan_d.xml) (for e-kara, Popira / 2, Taiko De Popira) SP (SP-x on case, no part numbers) (see ekara_japan_sp.xml) (for e-kara, Popira / 2, Taiko de Popira, Jumping Popira) these exist but haven't got any Some Japanese carts have a number starting with JP (for Jumping Popira Only?) A (for Pichi Pichi Pitch Only?) KE (for Kids Lyric book device Only?) - KD (for e-kara?) - + KD (for e-kara?) + (there are others, need to document them) @@ -50,7 +50,7 @@ Genres can cross multiple cart types, eg. TV Pop 1,3,4,5,6 are in the 'G' series, while TV Pop 2 is in the 'P' series, and TV Pop 9 is in the 'D' series (where are 7,8?) for non-Japanese carts see ekara_us.xml and ekara_pal.xml, the PAL ones are noteworthy for using a different timing system - + *********************************************************************************** Japanese cart listing (by 'just number' code) (number on cartridge / box, EC in cart identifier code) @@ -312,7 +312,7 @@ - + Kid's Mix Volume 1 (Japan) (EC0010-KID) 2000 @@ -369,7 +369,7 @@ - + @@ -386,7 +386,7 @@ - + J-Pop Mix Volume 9 (Japan) (EC0021-JPM) 2000 @@ -604,7 +604,7 @@ - + @@ -740,11 +740,11 @@ - + - + - + J-Pop Mix Volume 33 (Japan) (EC0068-JPM) 2001 @@ -783,9 +783,9 @@ - - - + + + @@ -798,11 +798,11 @@ - + - + - + ETZ (Japan) (EC0079-ETZ) 2002 @@ -812,12 +812,12 @@ - - + + - + - + Matthew's Best Hit Selection (Japan) (EC0082-MBH) 2003 @@ -827,12 +827,12 @@ - - + + - + - + - + diff --git a/hash/ekara_japan_d.xml b/hash/ekara_japan_d.xml index 859ccb93a85..cfaa6844b09 100644 --- a/hash/ekara_japan_d.xml +++ b/hash/ekara_japan_d.xml @@ -21,12 +21,12 @@ D-3 DC0003-BHT BHT (Best Artists?) Volume 9? (most other BHT carts are in G series, or P series) D-4 DC0004- (unknown) *D-5 DC0005-TPJ TV Pop Volume 9 - D-6 DC0006- (seen) + D-6 DC0006- (seen) D-7 DC0007- (seen) D-8 DC0008- (seen) - + (more? what's the D highest number?) - + --> diff --git a/hash/ekara_japan_en.xml b/hash/ekara_japan_en.xml index 63533f411bb..f23b7117b31 100644 --- a/hash/ekara_japan_en.xml +++ b/hash/ekara_japan_en.xml @@ -5,11 +5,11 @@ - + EN-3 (Japan) 2004 @@ -27,6 +27,6 @@ - - + + diff --git a/hash/ekara_japan_g.xml b/hash/ekara_japan_g.xml index 1191b84109c..42acff7a551 100644 --- a/hash/ekara_japan_g.xml +++ b/hash/ekara_japan_g.xml @@ -32,7 +32,7 @@ (more? what's the G highest number?) --> - + BAT Volume 1 (Japan) (GC0001-BAT) 2000 @@ -65,7 +65,7 @@ - + BHT Volume 2 (Japan) (GC0004-BHT) 2000 @@ -76,7 +76,7 @@ - + BHT Volume 3 (Japan) (GC0006-BHT) 2000 @@ -87,18 +87,18 @@ - + + Unless Popira 2 is different (unlikely) it doesn't look like the SEEPROM in this cartridge can be used (unfinished design?) --> BAT Volume 4 (Japan) (GC0010-BAT) 2002 @@ -109,9 +109,9 @@ - - - + + + BAT Volume 5 (Japan) (GC0015-BAT) @@ -123,8 +123,8 @@ - - + + TV Pop Volume 5 (Japan) (GC0016-TPJ) 2002 @@ -135,6 +135,6 @@ - - + + diff --git a/hash/ekara_japan_m.xml b/hash/ekara_japan_m.xml index f068d1edd87..9f08af0b1e8 100644 --- a/hash/ekara_japan_m.xml +++ b/hash/ekara_japan_m.xml @@ -18,11 +18,11 @@ M-11 M-12 M-13 MC0013-KSM KSM Mini Volume 5 - + (more? what's the M highest number?) --> - + diff --git a/hash/ekara_japan_p.xml b/hash/ekara_japan_p.xml index a6736fff155..55f8c2fe06f 100644 --- a/hash/ekara_japan_p.xml +++ b/hash/ekara_japan_p.xml @@ -39,17 +39,17 @@ - + BHT Volume 7 (Japan) (PC0004-BHT) 2002 Takara - + - + - + diff --git a/hash/ekara_japan_s.xml b/hash/ekara_japan_s.xml index bf95c5d9826..ead455a7582 100644 --- a/hash/ekara_japan_s.xml +++ b/hash/ekara_japan_s.xml @@ -13,7 +13,7 @@ S-1 SC0001- Hello Kitty Special S-2 SC0002- (unknown) S-3 SC0003- (unknown) - S-4 *SC0004-SAI SAI (series 1) Volume 1 + S-4 *SC0004-SAI SAI (series 1) Volume 1 S-5 *SC0005-SAI SAI (series 2) Volume 1 (same series as 6,9,19,21,22) S-6 *SC0006-SAI SAI (series 2) Volume 2 (same series as 5,9,19,21,22) S-7 SC0007- (unknown) @@ -21,7 +21,7 @@ S-9 *SC0009-SAI SAI (series 2) Volume 3 (same series as 5,6,19,21,22) S-10 *SC0010-HWK HWK (untranslated) S-11 SC0011- (unknown) - S-12 *SC0012-SAI SAI (series 3) Volume 3 + S-12 *SC0012-SAI SAI (series 3) Volume 3 S-13 SC0013- (unknown) S-14 SC0014- (unknown) S-15 SC0015- (unknown) @@ -35,7 +35,7 @@ S-23 SC0023- (unknown) (more? what's the S highest number?) - + --> diff --git a/hash/ekara_japan_sp.xml b/hash/ekara_japan_sp.xml index efb6ea08554..d9e1bc16492 100644 --- a/hash/ekara_japan_sp.xml +++ b/hash/ekara_japan_sp.xml @@ -7,7 +7,7 @@ *********************************************************************************** Japanese cart listing (by SP code) * = dumped - + These don't seem to have a secondary numbering scheme (eg SPxxxx-xxx) These are for use with 5 different units @@ -16,14 +16,14 @@ 3. Popira 2 (Blue/Green) ( https://www.youtube.com/watch?v=iY1I-jfXw7U ) 4. Taiko de Popira 5. Jumping Popira (Stepping Mat type thing) ( https://www.youtube.com/watch?v=yJruMOBdLFY ) - + If you plug this into a DDR Family Mat you get the message (in Japanese) - + "please play this cartridge on e-kara series, popira, popira 2, taiko de popira or jumping popira" gives 'memory error' if plugged into Popira (needs cartridge SEEPROM emulating) gives 'eep-rom error' if plugged into Taiko de Popira (same reason) - + SP-01 (unknown) *SP-02 'Super Cartridge' SP-2 SP-03 (unknown) @@ -46,5 +46,5 @@ - + diff --git a/hash/ekara_us.xml b/hash/ekara_us.xml index e16a244b617..69af8ccac8d 100644 --- a/hash/ekara_us.xml +++ b/hash/ekara_us.xml @@ -229,5 +229,5 @@ - + diff --git a/hash/jakks_gamekey_dy.xml b/hash/jakks_gamekey_dy.xml index 1eb4a801760..00e041cea04 100644 --- a/hash/jakks_gamekey_dy.xml +++ b/hash/jakks_gamekey_dy.xml @@ -1,12 +1,12 @@ - + - + - + Sports Bowling & Goofy's Underwater Adventure 2005 @@ -14,9 +14,9 @@ - - - + + + @@ -28,13 +28,13 @@ - - - - + + + + - + Sports Tennis & Face Chase & Riches of Agrabah 2005 @@ -42,11 +42,11 @@ - - - - + + + + - - + + diff --git a/hash/jakks_gamekey_nk.xml b/hash/jakks_gamekey_nk.xml index d95389638ab..da91e1abcbf 100644 --- a/hash/jakks_gamekey_nk.xml +++ b/hash/jakks_gamekey_nk.xml @@ -1,9 +1,9 @@ - + - + Soccer Shootout & Juego De Futbol De Dora & Dora's Star Mountain Adventure 2005 @@ -11,9 +11,9 @@ - - - + + + diff --git a/hash/jakks_gamekey_sw.xml b/hash/jakks_gamekey_sw.xml index 1485cb87b70..831d5eb8df1 100644 --- a/hash/jakks_gamekey_sw.xml +++ b/hash/jakks_gamekey_sw.xml @@ -1,12 +1,12 @@ - + - + - + Turret Defense & Yoda's Escape 2005 @@ -20,5 +20,5 @@ - + diff --git a/hash/pce_tourvision.xml b/hash/pce_tourvision.xml index 510ebc7abd9..58b3f4ea510 100644 --- a/hash/pce_tourvision.xml +++ b/hash/pce_tourvision.xml @@ -898,10 +898,10 @@ Parasol Stars - + @@ -1041,7 +1041,7 @@ Parasol Stars Pro Yakyuu World Stadium '91 (TourVision PCE bootleg) 1991 bootleg (TourVision) / Namcot - + @@ -1067,7 +1067,7 @@ Parasol Stars Puzzle Boy (TourVision PCE bootleg) 1991 bootleg (TourVision) / Nihon Telenet - + @@ -1080,11 +1080,11 @@ Parasol Stars Puzznic (TourVision PCE bootleg) 1990 bootleg (TourVision) / Taito - + - + @@ -1123,7 +1123,7 @@ Parasol Stars - + diff --git a/hash/vsmile_cart.xml b/hash/vsmile_cart.xml index bb7ab418a3a..f097cf4ded7 100644 --- a/hash/vsmile_cart.xml +++ b/hash/vsmile_cart.xml @@ -1892,7 +1892,7 @@ Game cartridges - + Superman - Der Superheld (Ger) 200? diff --git a/hash/vtech_storio_cart.xml b/hash/vtech_storio_cart.xml index 32d6e17d970..1d901cf1ff0 100644 --- a/hash/vtech_storio_cart.xml +++ b/hash/vtech_storio_cart.xml @@ -1,10 +1,10 @@ - + - + Drive not ready, aborting\n"); + + set_error(ERR_AC); + end_command(); + } + else + { + m_command = data; + + start_command(); + + // all other command imply a seek + if ((m_command >> 4) != CMD_SCAN_ID) + m_status &= ~STATUS_SC; + + int amount = 0; + int target = 0; + + switch (m_command >> 4) + { + case CMD_RESTORE: + amount = m_drives[drive()].cylinder; + target = 0; + break; + + case CMD_SEEK: + case CMD_READ_SECTOR: + case CMD_WRITE_SECTOR: + case CMD_WRITE_FORMAT: + amount = abs(m_drives[drive()].cylinder - m_cylinder); + target = m_cylinder; + break; + } + + if ((m_command >> 4) != CMD_SCAN_ID) + LOGSEEK("Seeking %d cylinders to %d\n", amount, target); + + m_seek_timer->adjust(get_stepping_rate() * amount, target); + } + + break; + } +} + + +//************************************************************************** +// IMPLEMENTATION +//************************************************************************** + +void wd1010_device::cmd_restore() +{ + LOGCMD("--> RESTORE done\n"); + end_command(); +} + +void wd1010_device::cmd_read_sector() +{ + hard_disk_file *file = m_drives[drive()].drive->get_hard_disk_file(); + hard_disk_info *info = hard_disk_get_info(file); + + m_out_bcr_cb(1); + m_out_bcr_cb(0); + + // verify that we can read + if (head() > info->heads) + { + // out of range + LOG("--> Head out of range, aborting\n"); + + set_error(ERR_AC); + end_command(); + } + else + { + uint8_t buffer[512]; + + while (m_sector_count > 0) + { + LOGDATA("--> Transferring sector to buffer (lba = %08x)\n", get_lbasector()); + + hard_disk_read(file, get_lbasector(), buffer); + + for (int i = 0; i < 512; i++) + m_out_data_cb(buffer[i]); + + m_out_bcr_cb(1); + m_out_bcr_cb(0); + + // save last read head and sector number + m_drives[drive()].head = head(); + m_drives[drive()].sector = m_sector_number; + + if (BIT(m_command, 2)) + { + m_sector_number++; + m_sector_count--; + } + else + break; + } + + end_command(); + } +} + +void wd1010_device::cmd_write_sector() +{ + if (!(m_status & STATUS_DRQ)) + { + LOGDATA("Setting DATA REQUEST\n"); + m_status |= STATUS_DRQ; + m_data_timer->adjust(attotime::from_usec(35)); + return; + } + + if (m_brdy == 0) + { + m_data_timer->adjust(attotime::from_usec(35)); + return; + } + + LOGDATA("Clearing DATA REQUEST\n"); + m_status &= ~STATUS_DRQ; + + hard_disk_file *file = m_drives[drive()].drive->get_hard_disk_file(); + uint8_t buffer[512]; + + while (m_sector_count > 0) + { + if ((m_command >> 4) == CMD_WRITE_FORMAT) + { + // we ignore the format specification and fill everything with 0xe5 + std::fill(std::begin(buffer), std::end(buffer), 0xe5); + } + else + { + // get data for sector from buffer chip + for (int i = 0; i < 512; i++) + buffer[i] = m_in_data_cb(); + } + + hard_disk_write(file, get_lbasector(), buffer); + + // save last read head and sector number + m_drives[drive()].head = head(); + m_drives[drive()].sector = m_sector_number; + + if (BIT(m_command, 2)) + { + m_sector_number++; + m_sector_count--; + } + else + break; + } + + end_command(); +} + +void wd1010_device::cmd_scan_id() +{ + // update head, sector size, sector number and cylinder + m_sdh = (m_sdh & 0xf8) | (m_drives[drive()].head & 0x07); + m_sector_number = m_drives[drive()].sector; + m_cylinder = m_drives[drive()].cylinder; + + end_command(); +} + +void wd1010_device::cmd_seek() +{ + LOGCMD("--> SEEK done\n"); + end_command(); +} diff --git a/src/devices/machine/wd1010.h b/src/devices/machine/wd1010.h new file mode 100644 index 00000000000..b5db9975693 --- /dev/null +++ b/src/devices/machine/wd1010.h @@ -0,0 +1,143 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + Western Digital WD1010-05 Winchester Disk Controller + +***************************************************************************/ + +#ifndef MAME_MACHINE_WD1010_H +#define MAME_MACHINE_WD1010_H + +#pragma once + +#include "imagedev/harddriv.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> wd1010_device + +class wd1010_device : public device_t +{ +public: + // construction/destruction + wd1010_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + auto out_intrq_callback() { return m_out_intrq_cb.bind(); } + auto out_bcr_callback() { return m_out_bcr_cb.bind(); } + auto in_data_callback() { return m_in_data_cb.bind(); } + auto out_data_callback() { return m_out_data_cb.bind(); } + + DECLARE_READ8_MEMBER(read); + DECLARE_WRITE8_MEMBER(write); + + DECLARE_WRITE_LINE_MEMBER(drdy_w); + DECLARE_WRITE_LINE_MEMBER(brdy_w); + +protected: + // device-level overrides + virtual void device_start() override; + virtual void device_reset() override; + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; + +private: + enum + { + STATUS_ERR = 0x01, // error + STATUS_CIP = 0x02, // command in progress + STATUS_RSV = 0x04, // reserved + STATUS_DRQ = 0x08, // data request + STATUS_SC = 0x10, // seek complete + STATUS_WF = 0x20, // write fault + STATUS_RDY = 0x40, // drive ready + STATUS_BSY = 0x80 // controller busy + }; + + enum + { + ERR_DM = 0x01, // data address mark not found + ERR_TK = 0x02, // track zero error + ERR_AC = 0x04, // aborted command + ERR_RSV1 = 0x08, // reserved, forced to 0 + ERR_ID = 0x10, // id not found + ERR_RSV2 = 0x20, // reserved, forced to 0 + ERR_CRC = 0x40, // crc error + ERR_BB = 0x80 // bad block + }; + + enum + { + CMD_RESTORE = 1, + CMD_READ_SECTOR = 2, + CMD_WRITE_SECTOR = 3, + CMD_SCAN_ID = 4, + CMD_WRITE_FORMAT = 5, + CMD_SEEK = 7 + }; + + enum + { + TIMER_SEEK, + TIMER_DATA + }; + + void set_error(int error); + void set_intrq(int state); + attotime get_stepping_rate(); + void start_command(); + void end_command(); + int get_lbasector(); + + // extract values from sdh + int head() { return (m_sdh >> 0) & 0x07; } + int drive() { return (m_sdh >> 3) & 0x03; } + int sector_size() + { + const int S[4] = { 256, 512, 1024, 128 }; + return S[(m_sdh >> 5) & 0x03]; + } + + void cmd_restore(); + void cmd_read_sector(); + void cmd_write_sector(); + void cmd_scan_id(); + void cmd_seek(); + + devcb_write_line m_out_intrq_cb; + devcb_write_line m_out_bcr_cb; + devcb_read8 m_in_data_cb; + devcb_write8 m_out_data_cb; + + struct + { + harddisk_image_device *drive; + uint8_t head; + uint16_t cylinder; + uint8_t sector; + } m_drives[4]; + + emu_timer *m_seek_timer; + emu_timer *m_data_timer; + + int m_intrq; + int m_brdy; + uint8_t m_stepping_rate; + uint8_t m_command; + + // task file registers + uint8_t m_error; + uint8_t m_precomp; + uint8_t m_sector_count; + uint8_t m_sector_number; + uint16_t m_cylinder; + uint8_t m_sdh; + uint8_t m_status; +}; + +// device type definition +DECLARE_DEVICE_TYPE(WD1010, wd1010_device) + +#endif // MAME_MACHINE_WD1010_H -- cgit v1.2.3-70-g09d2 From cb60e245dcf3830669c44b240e40f60580625cc6 Mon Sep 17 00:00:00 2001 From: David Haywood Date: Thu, 14 Mar 2019 11:35:19 +0000 Subject: SPG2XX - Make audio emulation a subdevice (#4757) * SPG2XX - Make audio emulation a subdevice (I need to reuse some of it for SPG110) * these will end up in different places on spg110 so split the handler (nw) * refactor a little for cleaner use later (nw) * realign logging with function names (nw) * (nw) * (nw) * recent change in audio_beat_tick appears to break "icanpian jjs" seems unintentional? (MG please verify) also documented an existing suspicious use of 'channel' in code. * use channel_bit here instead, seems more logical (nw) * reorganize code here a bit too (nw) --- scripts/src/machine.lua | 2 + src/devices/machine/spg2xx.cpp | 1216 +------------------------------- src/devices/machine/spg2xx.h | 320 +-------- src/devices/machine/spg2xx_audio.cpp | 1270 ++++++++++++++++++++++++++++++++++ src/devices/machine/spg2xx_audio.h | 372 ++++++++++ 5 files changed, 1681 insertions(+), 1499 deletions(-) create mode 100644 src/devices/machine/spg2xx_audio.cpp create mode 100644 src/devices/machine/spg2xx_audio.h (limited to 'scripts/src/machine.lua') diff --git a/scripts/src/machine.lua b/scripts/src/machine.lua index edf745c67d3..54810e56038 100644 --- a/scripts/src/machine.lua +++ b/scripts/src/machine.lua @@ -2622,6 +2622,8 @@ if (MACHINES["SPG2XX"]~=null) then files { MAME_DIR .. "src/devices/machine/spg2xx.cpp", MAME_DIR .. "src/devices/machine/spg2xx.h", + MAME_DIR .. "src/devices/machine/spg2xx_audio.cpp", + MAME_DIR .. "src/devices/machine/spg2xx_audio.h", MAME_DIR .. "src/devices/machine/spg110.cpp", MAME_DIR .. "src/devices/machine/spg110.h", } diff --git a/src/devices/machine/spg2xx.cpp b/src/devices/machine/spg2xx.cpp index 3c26f92cf7f..5345f12b639 100644 --- a/src/devices/machine/spg2xx.cpp +++ b/src/devices/machine/spg2xx.cpp @@ -56,7 +56,6 @@ DEFINE_DEVICE_TYPE(SPG28X, spg28x_device, "spg28x", "SPG280-series System-on-a-C #include "logmacro.h" #define SPG_DEBUG_VIDEO (0) -#define SPG_DEBUG_AUDIO (0) #define IO_IRQ_ENABLE m_io_regs[0x21] #define IO_IRQ_STATUS m_io_regs[0x22] @@ -65,7 +64,8 @@ DEFINE_DEVICE_TYPE(SPG28X, spg28x_device, "spg28x", "SPG280-series System-on-a-C spg2xx_device::spg2xx_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, type, tag, owner, clock) - , device_sound_interface(mconfig, *this) + , device_mixer_interface(mconfig, *this, 2) + , m_spg_audio(*this, "spgaudio") , m_rowscrolloffset(15) , m_porta_out(*this) , m_portb_out(*this) @@ -103,7 +103,9 @@ void spg2xx_device::map(address_map &map) map(0x002900, 0x002aff).ram().share("scrollram"); map(0x002b00, 0x002bff).ram().share("paletteram"); map(0x002c00, 0x002fff).ram().share("spriteram"); - map(0x003000, 0x0037ff).rw(FUNC(spg2xx_device::audio_r), FUNC(spg2xx_device::audio_w)); + map(0x003000, 0x0031ff).rw(m_spg_audio, FUNC(spg2xx_audio_device::audio_r), FUNC(spg2xx_audio_device::audio_w)); + map(0x003200, 0x0033ff).rw(m_spg_audio, FUNC(spg2xx_audio_device::audio_phase_r), FUNC(spg2xx_audio_device::audio_phase_w)); + map(0x003400, 0x0037ff).rw(m_spg_audio, FUNC(spg2xx_audio_device::audio_ctrl_r), FUNC(spg2xx_audio_device::audio_ctrl_w)); map(0x003d00, 0x003eff).rw(FUNC(spg2xx_device::io_r), FUNC(spg2xx_device::io_w)); } @@ -140,9 +142,6 @@ void spg2xx_device::device_start() m_screenpos_timer = timer_alloc(TIMER_SCREENPOS); m_screenpos_timer->adjust(attotime::never); - m_audio_beat = timer_alloc(TIMER_BEAT); - m_audio_beat->adjust(attotime::never); - m_uart_tx_timer = timer_alloc(TIMER_UART_TX); m_uart_tx_timer->adjust(attotime::never); @@ -158,10 +157,6 @@ void spg2xx_device::device_start() m_timer_src_c = timer_alloc(TIMER_SRC_C); m_timer_src_c->adjust(attotime::never); - m_stream = stream_alloc(0, 2, 281250/4); - - m_channel_debug = -1; - save_item(NAME(m_timer_a_preload)); save_item(NAME(m_timer_b_preload)); save_item(NAME(m_timer_b_divisor)); @@ -175,21 +170,6 @@ void spg2xx_device::device_start() save_item(NAME(m_debug_palette)); save_item(NAME(m_sprite_index_to_debug)); - save_item(NAME(m_debug_samples)); - save_item(NAME(m_debug_rates)); - - save_item(NAME(m_audio_regs)); - save_item(NAME(m_sample_shift)); - save_item(NAME(m_sample_count)); - save_item(NAME(m_sample_addr)); - save_item(NAME(m_channel_rate)); - save_item(NAME(m_channel_rate_accum)); - save_item(NAME(m_rampdown_frame)); - save_item(NAME(m_envclk_frame)); - save_item(NAME(m_envelope_addr)); - save_item(NAME(m_channel_debug)); - save_item(NAME(m_audio_curr_beat_base_count)); - save_item(NAME(m_io_regs)); save_item(NAME(m_uart_rx_fifo)); save_item(NAME(m_uart_rx_fifo_start)); @@ -210,25 +190,10 @@ void spg2xx_device::device_start() save_item(NAME(m_4hz_divider)); save_item(NAME(m_uart_baud_rate)); - for (int i = 0; i < 16; i++) - { - save_item(NAME(m_adpcm[i].m_signal), i); - save_item(NAME(m_adpcm[i].m_step), i); - } } void spg2xx_device::device_reset() { - memset(m_audio_regs, 0, 0x800 * sizeof(uint16_t)); - memset(m_sample_shift, 0, 16); - memset(m_sample_count, 0, sizeof(uint32_t) * 16); - memset(m_sample_addr, 0, sizeof(uint32_t) * 16); - memset(m_channel_rate, 0, sizeof(double) * 16); - memset(m_channel_rate_accum, 0, sizeof(double) * 16); - memset(m_rampdown_frame, 0, sizeof(uint32_t) * 16); - memset(m_envclk_frame, 4, sizeof(uint32_t) * 16); - memset(m_envelope_addr, 0, sizeof(uint32_t) * 16); - memset(m_video_regs, 0, 0x100 * sizeof(uint16_t)); memset(m_io_regs, 0, 0x200 * sizeof(uint16_t)); @@ -264,15 +229,6 @@ void spg2xx_device::device_reset() m_debug_palette = false; m_sprite_index_to_debug = 0; - m_debug_samples = false; - m_debug_rates = false; - m_audio_curr_beat_base_count = 0; - - m_audio_regs[AUDIO_CHANNEL_REPEAT] = 0x3f; - m_audio_regs[AUDIO_CHANNEL_ENV_MODE] = 0x3f; - - m_audio_beat->adjust(attotime::from_ticks(4, 281250), 0, attotime::from_ticks(4, 281250)); - m_4khz_timer->adjust(attotime::from_hz(4096), 0, attotime::from_hz(4096)); m_2khz_divider = 0; @@ -280,6 +236,23 @@ void spg2xx_device::device_reset() m_4hz_divider = 0; } +WRITE_LINE_MEMBER(spg2xx_device::audioirq_w) +{ + if (state == ASSERT_LINE) + { + m_cpu->set_state_unsynced(UNSP_IRQ4_LINE, ASSERT_LINE); + } + else + { + m_cpu->set_state_unsynced(UNSP_IRQ4_LINE, CLEAR_LINE); + } +} + +READ16_MEMBER(spg2xx_device::space_r) +{ + address_space &cpuspace = m_cpu->space(AS_PROGRAM); + return cpuspace.read_word(offset); +} /************************* * Video Hardware * @@ -976,25 +949,6 @@ WRITE_LINE_MEMBER(spg2xx_device::vblank) m_debug_palette = !m_debug_palette; #endif -#if SPG_DEBUG_AUDIO - if (machine().input().code_pressed_once(KEYCODE_3)) - m_debug_samples = !m_debug_samples; - if (machine().input().code_pressed_once(KEYCODE_4)) - m_debug_rates = !m_debug_rates; - if (machine().input().code_pressed_once(KEYCODE_1)) - { - m_channel_debug--; - if (m_channel_debug < -1) - m_channel_debug = 15; - } - if (machine().input().code_pressed_once(KEYCODE_2)) - { - m_channel_debug++; - if (m_channel_debug == 16) - m_channel_debug = -1; - } -#endif - if (VIDEO_IRQ_ENABLE & 1) { VIDEO_IRQ_STATUS |= 1; @@ -1941,10 +1895,6 @@ void spg2xx_device::device_timer(emu_timer &timer, device_timer_id id, int param break; } - case TIMER_BEAT: - audio_beat_tick(); - break; - case TIMER_UART_TX: uart_transmit_tick(); break; @@ -2082,20 +2032,6 @@ void spg2xx_device::check_irqs(const uint16_t changed) m_cpu->set_state_unsynced(UNSP_IRQ3_LINE, (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x2100) ? ASSERT_LINE : CLEAR_LINE); } - if (changed & (AUDIO_BIS_MASK | AUDIO_BIE_MASK)) // Beat IRQ - { - if ((m_audio_regs[AUDIO_BEAT_COUNT] & (AUDIO_BIS_MASK | AUDIO_BIE_MASK)) == (AUDIO_BIS_MASK | AUDIO_BIE_MASK)) - { - LOGMASKED(LOG_BEAT, "Asserting beat IRQ\n"); - m_cpu->set_state_unsynced(UNSP_IRQ4_LINE, ASSERT_LINE); - } - else - { - LOGMASKED(LOG_BEAT, "Clearing beat IRQ\n"); - m_cpu->set_state_unsynced(UNSP_IRQ4_LINE, CLEAR_LINE); - } - } - if (changed & 0x1200) // External IRQ { LOGMASKED(LOG_UART, "%ssserting IRQ5 (%04x, %04x)\n", (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x1200) ? "A" : "Dea", (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x1200), changed); @@ -2214,1108 +2150,12 @@ void spg2xx_device::do_cpu_dma(uint32_t len) m_io_regs[0x103] = (dst + len) & 0x3fff; } -/*********************** -* Audio Hardware * -***********************/ - -READ16_MEMBER(spg2xx_device::audio_r) -{ - const uint16_t channel = (offset & 0x00f0) >> 4; - uint16_t data = m_audio_regs[offset]; - - if (offset >= 0x400) - { - switch (offset) - { - case AUDIO_CHANNEL_ENABLE: - LOGMASKED(LOG_SPU_READS, "audio_r: Channel Enable: %04x\n", data); - break; - - case AUDIO_MAIN_VOLUME: - LOGMASKED(LOG_SPU_READS, "audio_r: Main Volume: %04x\n", data); - break; - - case AUDIO_CHANNEL_FIQ_ENABLE: - LOGMASKED(LOG_SPU_READS | LOG_IRQS, "audio_r: Channel FIQ Enable: %04x\n", data); - break; - - case AUDIO_CHANNEL_FIQ_STATUS: - LOGMASKED(LOG_SPU_READS | LOG_IRQS, "audio_r: Channel FIQ Acknowledge: %04x\n", data); - break; - - case AUDIO_BEAT_BASE_COUNT: - LOGMASKED(LOG_SPU_READS | LOG_BEAT, "audio_r: Beat Base Count: %04x\n", data); - break; - - case AUDIO_BEAT_COUNT: - LOGMASKED(LOG_SPU_READS | LOG_BEAT, "audio_r: Beat Count: %04x\n", data); - break; - - case AUDIO_ENVCLK0: - case AUDIO_ENVCLK1: - LOGMASKED(LOG_SPU_READS | LOG_ENVELOPES, "audio_r: Envelope Interval %d (lo): %04x\n", offset == AUDIO_ENVCLK0 ? 0 : 1, data); - break; - - case AUDIO_ENVCLK0_HIGH: - case AUDIO_ENVCLK1_HIGH: - LOGMASKED(LOG_SPU_READS | LOG_ENVELOPES, "audio_r: Envelope Interval %d (hi): %04x\n", offset == AUDIO_ENVCLK0_HIGH ? 0 : 1, data); - break; - - case AUDIO_ENV_RAMP_DOWN: - LOGMASKED(LOG_SPU_READS | LOG_RAMPDOWN, "audio_r: Envelope Fast Ramp Down: %04x\n", data); - break; - - case AUDIO_CHANNEL_STOP: - LOGMASKED(LOG_SPU_READS, "audio_r: Channel Stop Status: %04x\n", data); - break; - - case AUDIO_CHANNEL_ZERO_CROSS: - LOGMASKED(LOG_SPU_READS, "audio_r: Channel Zero-Cross Enable: %04x\n", data); - break; - - case AUDIO_CONTROL: - LOGMASKED(LOG_SPU_READS, "audio_r: Control: %04x\n", data); - break; - - case AUDIO_COMPRESS_CTRL: - LOGMASKED(LOG_SPU_READS, "audio_r: Compressor Control: %04x\n", data); - break; - - case AUDIO_CHANNEL_STATUS: - LOGMASKED(LOG_SPU_READS, "audio_r: Channel Status: %04x\n", data); - break; - - case AUDIO_WAVE_IN_L: - LOGMASKED(LOG_SPU_READS, "audio_r: Wave In (L) / FIFO Write Data: %04x\n", data); - break; - - case AUDIO_WAVE_IN_R: - LOGMASKED(LOG_SPU_READS, "audio_r: Wave In (R) / Software Channel FIFO IRQ Control: %04x\n", data); - break; - - case AUDIO_WAVE_OUT_L: - LOGMASKED(LOG_SPU_READS, "audio_r: Wave Out (L): %04x\n", data); - break; - - case AUDIO_WAVE_OUT_R: - LOGMASKED(LOG_SPU_READS, "audio_r: Wave Out (R): %04x\n", data); - break; - - case AUDIO_CHANNEL_REPEAT: - LOGMASKED(LOG_SPU_READS, "audio_r: Channel Repeat Enable: %04x\n", data); - break; - - case AUDIO_CHANNEL_ENV_MODE: - LOGMASKED(LOG_SPU_READS | LOG_ENVELOPES, "audio_r: Channel Envelope Enable: %04x\n", data); - break; - - case AUDIO_CHANNEL_TONE_RELEASE: - LOGMASKED(LOG_SPU_READS, "audio_r: Channel Tone Release Enable: %04x\n", data); - break; - - case AUDIO_CHANNEL_ENV_IRQ: - LOGMASKED(LOG_SPU_READS | LOG_IRQS, "audio_r: Channel Envelope IRQ Status: %04x\n", data); - break; - - case AUDIO_CHANNEL_PITCH_BEND: - LOGMASKED(LOG_SPU_READS, "audio_r: Channel Pitch Bend Enable: %04x\n", data); - break; - - case AUDIO_SOFT_PHASE: - LOGMASKED(LOG_SPU_READS, "audio_r: Software Channel Phase: %04x\n", data); - break; - - case AUDIO_ATTACK_RELEASE: - LOGMASKED(LOG_SPU_READS, "audio_r: Attack/Release Time Control: %04x\n", data); - break; - - case AUDIO_EQ_CUTOFF10: - LOGMASKED(LOG_SPU_READS, "audio_r: EQ Cutoff Frequency 0/1: %04x\n", data); - break; - - case AUDIO_EQ_CUTOFF32: - LOGMASKED(LOG_SPU_READS, "audio_r: EQ Cutoff Frequency 2/3: %04x\n", data); - break; - - case AUDIO_EQ_GAIN10: - LOGMASKED(LOG_SPU_READS, "audio_r: EQ Cutoff Gain 0/1: %04x\n", data); - break; - - case AUDIO_EQ_GAIN32: - LOGMASKED(LOG_SPU_READS, "audio_r: EQ Cutoff Gain 2/3: %04x\n", data); - break; - - default: - LOGMASKED(LOG_UNKNOWN_SPU, "audio_r: Unknown register %04x = %04x\n", 0x3000 + offset, data); - break; - } - } - else if (channel < 16) - { - switch (offset & AUDIO_CHAN_OFFSET_MASK) - { - case AUDIO_WAVE_ADDR: - LOGMASKED(LOG_CHANNEL_READS, "audio_r: Channel %d: Wave Addr (lo): %04x\n", channel, data); - break; - - case AUDIO_MODE: - LOGMASKED(LOG_CHANNEL_READS, "audio_r: Channel %d: Mode: %04x (ADPCM:%d, 16M:%d, TONE:%d, LADDR_HI:%04x, WADDR_HI:%04x)\n", channel, data, - get_adpcm_bit(channel), get_16bit_bit(channel), get_tone_mode(channel), get_loop_addr_high(channel), get_wave_addr_high(channel)); - break; - - case AUDIO_LOOP_ADDR: - LOGMASKED(LOG_CHANNEL_READS, "audio_r: Channel %d: Loop Addr: %04x\n", channel, data); - break; - - case AUDIO_PAN_VOL: - LOGMASKED(LOG_CHANNEL_READS, "audio_r: Channel %d: Pan/Vol: %04x (PAN:%02x, VOL:%02x)\n", channel, data, - get_pan(channel), get_volume(channel)); - break; - - case AUDIO_ENVELOPE0: - LOGMASKED(LOG_CHANNEL_READS | LOG_ENVELOPES, "audio_r: Channel %d: Envelope0: %04x (RPTPER:%d, TARGET:%02x, SIGN:%d, INC:%02x)\n", channel, data, - get_repeat_period_bit(channel), get_envelope_target(channel), get_envelope_sign_bit(channel), get_envelope_inc(channel)); - break; - - case AUDIO_ENVELOPE_DATA: - LOGMASKED(LOG_CHANNEL_READS | LOG_ENVELOPES, "audio_r: Channel %d: Envelope Data: %04x (CNT:%d, EDD:%02x)\n", channel, data, - get_envelope_count(channel), get_edd(channel)); - break; - - case AUDIO_ENVELOPE1: - LOGMASKED(LOG_CHANNEL_READS | LOG_ENVELOPES, "audio_r: Channel %d: Envelope1 Data: %04x (RPTCNT:%02x, RPT:%d, LOAD:%02x)\n", channel, data, - get_envelope_repeat_count(channel), get_envelope_repeat_bit(channel), get_envelope_load(channel)); - break; - - case AUDIO_ENVELOPE_ADDR_HIGH: - LOGMASKED(LOG_CHANNEL_READS | LOG_ENVELOPES, "audio_r: Channel %d: Envelope Addr (hi): %04x (IRQADDR:%03x, IRQEN:%d, EADDR_HI:%02x)\n", channel, data, - get_audio_irq_addr(channel), get_audio_irq_enable_bit(channel), get_envelope_addr_high(channel)); - break; - - case AUDIO_ENVELOPE_ADDR: - LOGMASKED(LOG_CHANNEL_READS | LOG_ENVELOPES, "audio_r: Channel %d: Envelope Addr (lo): %04x \n", channel, data); - break; - - case AUDIO_WAVE_DATA_PREV: - LOGMASKED(LOG_CHANNEL_READS, "audio_r: Channel %d: Wave Data Prev: %04x \n", channel, data); - break; - - case AUDIO_ENVELOPE_LOOP_CTRL: - LOGMASKED(LOG_CHANNEL_READS | LOG_ENVELOPES, "audio_r: Channel %d: Envelope Loop Ctrl: %04x (RDOFFS:%02x, EAOFFS:%03x)\n", channel, data, - get_rampdown_offset(channel), get_envelope_eaoffset(channel)); - break; - - case AUDIO_WAVE_DATA: - LOGMASKED(LOG_CHANNEL_READS, "audio_r: Channel %d: Wave Data: %04x\n", channel, data); - break; - - case AUDIO_ADPCM_SEL: - LOGMASKED(LOG_CHANNEL_READS, "audio_r: Channel %d: ADPCM Sel: %04x (ADPCM36:%d, POINTNUM:%02x\n", channel, data, - get_adpcm36_bit(channel), get_point_number(channel)); - break; - - case AUDIO_PHASE_HIGH: - LOGMASKED(LOG_CHANNEL_READS, "audio_r: Channel %d: Phase High: %04x\n", channel, data); - break; - - case AUDIO_PHASE_ACCUM_HIGH: - LOGMASKED(LOG_CHANNEL_READS, "audio_r: Channel %d: Phase Accum High: %04x\n", channel, data); - break; - - case AUDIO_TARGET_PHASE_HIGH: - LOGMASKED(LOG_CHANNEL_READS, "audio_r: Channel %d: Target Phase High: %04x\n", channel, data); - break; - - case AUDIO_RAMP_DOWN_CLOCK: - LOGMASKED(LOG_CHANNEL_READS | LOG_RAMPDOWN, "audio_r: Channel %d: Rampdown Clock: %04x\n", channel, data); - break; - - case AUDIO_PHASE: - LOGMASKED(LOG_CHANNEL_READS, "audio_r: Channel %d: Phase: %04x\n", channel, data); - break; - - case AUDIO_PHASE_ACCUM: - LOGMASKED(LOG_CHANNEL_READS, "audio_r: Channel %d: Phase Accum: %04x\n", channel, data); - break; - - case AUDIO_TARGET_PHASE: - LOGMASKED(LOG_CHANNEL_READS, "audio_r: Channel %d: Target Phase: %04x\n", channel, data); - break; - - case AUDIO_PHASE_CTRL: - LOGMASKED(LOG_CHANNEL_READS, "audio_r: Channel %d: Phase Ctrl: %04x (TIMESTEP:%d, SIGN:%d, OFFSET:%03x\n", channel, data, - get_phase_time_step(channel), get_phase_sign_bit(channel), get_phase_offset(channel)); - break; - - default: - LOGMASKED(LOG_UNKNOWN_SPU, "audio_r: Unknown register %04x\n", 0x3000 + offset); - break; - } - } - else if (channel >= 16) - { - LOGMASKED(LOG_UNKNOWN_SPU, "audio_r: Trying to read from channel %d\n", channel); - } - return data; -} - -WRITE16_MEMBER(spg2xx_device::audio_w) +void spg2xx_device::device_add_mconfig(machine_config &config) { - const uint16_t channel = (offset & 0x00f0) >> 4; - - if (offset >= 0x400) - { - switch (offset) - { - case AUDIO_CHANNEL_ENABLE: - { - LOGMASKED(LOG_SPU_WRITES, "audio_w: Channel Enable: %04x\n", data); - const uint16_t changed = m_audio_regs[AUDIO_CHANNEL_ENABLE] ^ data; - for (uint32_t channel_bit = 0; channel_bit < 16; channel_bit++) - { - const uint16_t mask = 1 << channel_bit; - if (!(changed & mask)) - continue; - - if (data & mask) - { - if (!(m_audio_regs[AUDIO_CHANNEL_STATUS] & mask)) - { - LOGMASKED(LOG_SPU_WRITES, "Enabling channel %d\n", channel_bit); - m_audio_regs[offset] |= mask; - if (!(m_audio_regs[AUDIO_CHANNEL_STOP] & mask)) - { - LOGMASKED(LOG_SPU_WRITES, "Stop not set, starting playback on channel %d, mask %04x\n", channel_bit, mask); - m_audio_regs[AUDIO_CHANNEL_STATUS] |= mask; - m_sample_addr[channel_bit] = get_wave_addr(channel_bit); - m_envelope_addr[channel_bit] = get_envelope_addr(channel_bit); - set_envelope_count(channel, get_envelope_load(channel)); - } - m_adpcm[channel_bit].reset(); - m_sample_shift[channel_bit] = 0; - m_sample_count[channel_bit] = 0; - } - } - else - { - stop_channel(channel_bit); - //m_audio_regs[offset] &= ~mask; - //m_audio_regs[AUDIO_CHANNEL_STATUS] &= ~mask; - //m_audio_regs[AUDIO_CHANNEL_STOP] |= mask; - //m_audio_regs[AUDIO_CHANNEL_TONE_RELEASE] &= ~mask; - } - } - break; - } - - case AUDIO_MAIN_VOLUME: - LOGMASKED(LOG_SPU_WRITES, "audio_w: Main Volume: %04x\n", data); - m_audio_regs[offset] = data & AUDIO_MAIN_VOLUME_MASK; - break; - - case AUDIO_CHANNEL_FIQ_ENABLE: - LOGMASKED(LOG_SPU_WRITES | LOG_IRQS, "audio_w: Channel FIQ Enable: %04x\n", data); - m_audio_regs[offset] = data & AUDIO_CHANNEL_FIQ_ENABLE_MASK; - break; - - case AUDIO_CHANNEL_FIQ_STATUS: - LOGMASKED(LOG_SPU_WRITES | LOG_IRQS, "audio_w: Channel FIQ Acknowledge: %04x\n", data); - m_audio_regs[offset] &= ~(data & AUDIO_CHANNEL_FIQ_STATUS_MASK); - break; - - case AUDIO_BEAT_BASE_COUNT: - LOGMASKED(LOG_SPU_WRITES | LOG_BEAT, "audio_w: Beat Base Count: %04x\n", data); - m_audio_regs[offset] = data & AUDIO_BEAT_BASE_COUNT_MASK; - m_audio_curr_beat_base_count = m_audio_regs[offset]; - break; - - case AUDIO_BEAT_COUNT: - { - LOGMASKED(LOG_SPU_WRITES | LOG_BEAT, "audio_w: Beat Count: %04x\n", data); - const uint16_t old = m_audio_regs[offset]; - m_audio_regs[offset] &= ~(data & AUDIO_BIS_MASK); - m_audio_regs[offset] &= AUDIO_BIS_MASK; - m_audio_regs[offset] |= data & ~AUDIO_BIS_MASK; - const uint16_t changed = old ^ m_audio_regs[offset]; - if (changed & (AUDIO_BIS_MASK | AUDIO_BIE_MASK)) - { - LOGMASKED(LOG_BEAT, "BIS mask changed, updating IRQ\n"); - check_irqs(changed & (AUDIO_BIS_MASK | AUDIO_BIE_MASK)); - } - break; - } - - case AUDIO_ENVCLK0: - case AUDIO_ENVCLK1: - { - LOGMASKED(LOG_SPU_WRITES | LOG_ENVELOPES, "audio_w: Envelope Interval %d (lo): %04x\n", offset == AUDIO_ENVCLK0 ? 0 : 1, data); - const uint16_t old = m_audio_regs[offset]; - m_audio_regs[offset] = data; - const uint16_t changed = old ^ m_audio_regs[offset]; - - if (!changed) - break; - - const uint8_t channel_offset = offset == AUDIO_ENVCLK0 ? 0 : 8; - for (uint8_t channel_bit = 0; channel_bit < 4; channel_bit++) - { - const uint8_t shift = channel_bit << 2; - const uint16_t mask = 0x0f << shift; - if (changed & mask) - { - m_envclk_frame[channel_bit + channel_offset] = get_envclk_frame_count(channel_bit + channel_offset); - } - } - break; - } - - case AUDIO_ENVCLK0_HIGH: - case AUDIO_ENVCLK1_HIGH: - { - LOGMASKED(LOG_SPU_WRITES | LOG_ENVELOPES, "audio_w: Envelope Interval %d (hi): %04x\n", offset == AUDIO_ENVCLK0_HIGH ? 0 : 1, data); - const uint16_t old = m_audio_regs[offset]; - m_audio_regs[offset] = data; - const uint16_t changed = old ^ m_audio_regs[offset]; - if (!changed) - break; - - const uint8_t channel_offset = offset == AUDIO_ENVCLK0_HIGH ? 0 : 8; - for (uint8_t channel_bit = 0; channel_bit < 4; channel_bit++) - { - const uint8_t shift = channel_bit << 2; - const uint16_t mask = 0x0f << shift; - if (changed & mask) - { - m_envclk_frame[channel_bit + channel_offset + 4] = get_envclk_frame_count(channel_bit + channel_offset); - } - } - break; - } - - case AUDIO_ENV_RAMP_DOWN: - { - LOGMASKED(LOG_SPU_WRITES | LOG_RAMPDOWN, "audio_w: Envelope Fast Ramp Down: %04x\n", data); - const uint16_t old = m_audio_regs[offset]; - m_audio_regs[offset] = (data & AUDIO_ENV_RAMP_DOWN_MASK) & m_audio_regs[AUDIO_CHANNEL_STATUS]; - const uint16_t changed = old ^ m_audio_regs[offset]; - if (!changed) - break; - - for (uint32_t channel_bit = 0; channel_bit < 16; channel_bit++) - { - const uint16_t mask = 1 << channel_bit; - if ((changed & mask) && (data & mask)) - { - m_rampdown_frame[channel_bit] = get_rampdown_frame_count(channel_bit); - LOGMASKED(LOG_RAMPDOWN, "Preparing to ramp down channel %d in %d ticks\n", channel_bit, m_rampdown_frame[channel_bit] / 13); - } - } - break; - } - - case AUDIO_CHANNEL_STOP: - LOGMASKED(LOG_SPU_WRITES, "audio_w: Channel Stop Status: %04x\n", data); - m_audio_regs[offset] &= ~data; - break; - - case AUDIO_CHANNEL_ZERO_CROSS: - LOGMASKED(LOG_SPU_WRITES, "audio_w: Channel Zero-Cross Enable: %04x\n", data); - m_audio_regs[offset] = data & AUDIO_CHANNEL_ZERO_CROSS_MASK; - break; - - case AUDIO_CONTROL: - LOGMASKED(LOG_SPU_WRITES, "audio_w: Control: %04x (SOFTCH:%d, COMPEN:%d, NOHIGH:%d, NOINT:%d, EQEN:%d, VOLSEL:%d)\n", data - , (data & AUDIO_CONTROL_SOFTCH_MASK) ? 1 : 0 - , (data & AUDIO_CONTROL_COMPEN_MASK) ? 1 : 0 - , (data & AUDIO_CONTROL_NOHIGH_MASK) ? 1 : 0 - , (data & AUDIO_CONTROL_NOINT_MASK) ? 1 : 0 - , (data & AUDIO_CONTROL_EQEN_MASK) ? 1 : 0 - , (data & AUDIO_CONTROL_VOLSEL_MASK) >> AUDIO_CONTROL_VOLSEL_SHIFT); - m_audio_regs[offset] = data & AUDIO_CONTROL_MASK; - break; + SPG2XX_AUDIO(config, m_spg_audio, DERIVED_CLOCK(1, 1)); + m_spg_audio->write_irq_callback().set(FUNC(spg2xx_device::audioirq_w)); + m_spg_audio->space_read_callback().set(FUNC(spg2xx_device::space_r)); - case AUDIO_COMPRESS_CTRL: - LOGMASKED(LOG_SPU_WRITES, "audio_w: Compressor Control: %04x\n", data); - m_audio_regs[offset] = data; - break; - - case AUDIO_CHANNEL_STATUS: - LOGMASKED(LOG_SPU_WRITES, "audio_w: Channel Status (read-only): %04x\n", data); - break; - - case AUDIO_WAVE_IN_L: - LOGMASKED(LOG_SPU_WRITES, "audio_w: Wave In (L) / FIFO Write Data: %04x\n", data); - m_audio_regs[offset] = data; - break; - - case AUDIO_WAVE_IN_R: - LOGMASKED(LOG_SPU_WRITES, "audio_w: Wave In (R) / Software Channel FIFO IRQ Control: %04x\n", data); - m_audio_regs[offset] = data; - break; - - case AUDIO_WAVE_OUT_L: - LOGMASKED(LOG_SPU_WRITES, "audio_w: Wave Out (L): %04x\n", data); - m_audio_regs[offset] = data; - break; - - case AUDIO_WAVE_OUT_R: - LOGMASKED(LOG_SPU_WRITES, "audio_w: Wave Out (R): %04x\n", data); - m_audio_regs[offset] = data; - break; - - case AUDIO_CHANNEL_REPEAT: - LOGMASKED(LOG_SPU_WRITES, "audio_w: Channel Repeat Enable: %04x\n", data); - m_audio_regs[offset] = data & AUDIO_CHANNEL_REPEAT_MASK; - break; - - case AUDIO_CHANNEL_ENV_MODE: - LOGMASKED(LOG_SPU_WRITES | LOG_ENVELOPES, "audio_w: Channel Envelope Enable: %04x\n", data); - m_audio_regs[offset] = data & AUDIO_CHANNEL_ENV_MODE_MASK; - break; - - case AUDIO_CHANNEL_TONE_RELEASE: - LOGMASKED(LOG_SPU_WRITES, "audio_w: Channel Tone Release Enable: %04x\n", data); - m_audio_regs[offset] = data & AUDIO_CHANNEL_TONE_RELEASE_MASK; - break; - - case AUDIO_CHANNEL_ENV_IRQ: - LOGMASKED(LOG_SPU_WRITES | LOG_ENVELOPES | LOG_IRQS, "audio_w: Channel Envelope IRQ Acknowledge: %04x\n", data); - m_audio_regs[offset] &= ~data & AUDIO_CHANNEL_ENV_IRQ_MASK; - break; - - case AUDIO_CHANNEL_PITCH_BEND: - LOGMASKED(LOG_SPU_WRITES, "audio_w: Channel Pitch Bend Enable: %04x\n", data); - m_audio_regs[offset] = data & AUDIO_CHANNEL_PITCH_BEND_MASK; - break; - - case AUDIO_SOFT_PHASE: - LOGMASKED(LOG_SPU_WRITES, "audio_w: Software Channel Phase: %04x\n", data); - m_audio_regs[offset] = data; - break; - - case AUDIO_ATTACK_RELEASE: - LOGMASKED(LOG_SPU_WRITES, "audio_w: Attack/Release Time Control: %04x\n", data); - m_audio_regs[offset] = data; - break; - - case AUDIO_EQ_CUTOFF10: - LOGMASKED(LOG_SPU_WRITES, "audio_w: EQ Cutoff Frequency 0/1: %04x\n", data); - m_audio_regs[offset] = data & AUDIO_EQ_CUTOFF10_MASK; - break; - - case AUDIO_EQ_CUTOFF32: - LOGMASKED(LOG_SPU_WRITES, "audio_w: EQ Cutoff Frequency 2/3: %04x\n", data); - m_audio_regs[offset] = data & AUDIO_EQ_CUTOFF32_MASK; - break; - - case AUDIO_EQ_GAIN10: - LOGMASKED(LOG_SPU_WRITES, "audio_w: EQ Cutoff Gain 0/1: %04x\n", data); - m_audio_regs[offset] = data & AUDIO_EQ_GAIN10_MASK; - break; - - case AUDIO_EQ_GAIN32: - LOGMASKED(LOG_SPU_WRITES, "audio_w: EQ Cutoff Gain 2/3: %04x\n", data); - m_audio_regs[offset] = data & AUDIO_EQ_GAIN32_MASK; - break; - - default: - m_audio_regs[offset] = data; - LOGMASKED(LOG_UNKNOWN_SPU, "audio_w: Unknown register %04x = %04x\n", 0x3000 + offset, data); - break; - } - } - else if (channel < 16) - { - switch (offset & AUDIO_CHAN_OFFSET_MASK) - { - case AUDIO_WAVE_ADDR: - m_audio_regs[offset] = data; - LOGMASKED(LOG_CHANNEL_WRITES, "audio_w: Channel %d: Wave Addr (lo): %04x\n", channel, data); - break; - - case AUDIO_MODE: - m_audio_regs[offset] = data; - LOGMASKED(LOG_CHANNEL_WRITES, "audio_w: Channel %d: Mode: %04x (ADPCM:%d, 16M:%d, TONE:%d, LADDR_HI:%04x, WADDR_HI:%04x)\n", channel, data, - get_adpcm_bit(channel), get_16bit_bit(channel), get_tone_mode(channel), get_loop_addr_high(channel), get_wave_addr_high(channel)); - break; - - case AUDIO_LOOP_ADDR: - m_audio_regs[offset] = data; - LOGMASKED(LOG_CHANNEL_WRITES, "audio_w: Channel %d: Loop Addr: %04x\n", channel, data); - break; - - case AUDIO_PAN_VOL: - m_audio_regs[offset] = data & AUDIO_PAN_VOL_MASK; - LOGMASKED(LOG_CHANNEL_WRITES, "audio_w: Channel %d: Pan/Vol: %04x (PAN:%02x, VOL:%02x)\n", channel, data, - get_pan(channel), get_volume(channel)); - break; - - case AUDIO_ENVELOPE0: - m_audio_regs[offset] = data; - LOGMASKED(LOG_CHANNEL_WRITES | LOG_ENVELOPES, "audio_w: Channel %d: Envelope0: %04x (RPTPER:%d, TARGET:%02x, SIGN:%d, INC:%02x)\n", channel, data, - get_repeat_period_bit(channel), get_envelope_target(channel), get_envelope_sign_bit(channel), get_envelope_inc(channel)); - break; - - case AUDIO_ENVELOPE_DATA: - m_audio_regs[offset] = data & AUDIO_ENVELOPE_DATA_MASK; - LOGMASKED(LOG_CHANNEL_WRITES | LOG_ENVELOPES, "audio_w: Channel %d: Envelope Data: %04x (CNT:%d, EDD:%02x)\n", channel, data, - get_envelope_count(channel), get_edd(channel)); - break; - - case AUDIO_ENVELOPE1: - m_audio_regs[offset] = data; - LOGMASKED(LOG_CHANNEL_WRITES | LOG_ENVELOPES, "audio_w: Channel %d: Envelope1 Data: %04x (RPTCNT:%02x, RPT:%d, LOAD:%02x)\n", channel, data, - get_envelope_repeat_count(channel), get_envelope_repeat_bit(channel), get_envelope_load(channel)); - break; - - case AUDIO_ENVELOPE_ADDR_HIGH: - m_audio_regs[offset] = data; - LOGMASKED(LOG_CHANNEL_WRITES | LOG_ENVELOPES, "audio_w: Channel %d: Envelope Addr (hi): %04x (IRQADDR:%03x, IRQEN:%d, EADDR_HI:%02x)\n", channel, data, - get_audio_irq_addr(channel), get_audio_irq_enable_bit(channel), get_envelope_addr_high(channel)); - break; - - case AUDIO_ENVELOPE_ADDR: - m_audio_regs[offset] = data; - LOGMASKED(LOG_CHANNEL_WRITES | LOG_ENVELOPES, "audio_w: Channel %d: Envelope Addr (lo): %04x\n", channel, data); - break; - - case AUDIO_WAVE_DATA_PREV: - m_audio_regs[offset] = data; - LOGMASKED(LOG_CHANNEL_WRITES, "audio_w: Channel %d: Wave Data Prev: %04x \n", channel, data); - break; - - case AUDIO_ENVELOPE_LOOP_CTRL: - m_audio_regs[offset] = data; - LOGMASKED(LOG_CHANNEL_WRITES | LOG_ENVELOPES, "audio_w: Channel %d: Envelope Loop Ctrl: %04x (RDOFFS:%02x, EAOFFS:%03x)\n", channel, data, - get_rampdown_offset(channel), get_envelope_eaoffset(channel)); - break; - - case AUDIO_WAVE_DATA: - m_audio_regs[offset] = data; - LOGMASKED(LOG_CHANNEL_WRITES, "audio_w: Channel %d: Wave Data: %04x\n", channel, data); - break; - - case AUDIO_ADPCM_SEL: - m_audio_regs[offset] = data & AUDIO_ADPCM_SEL_MASK; - LOGMASKED(LOG_CHANNEL_WRITES, "audio_w: Channel %d: ADPCM Sel: %04x (ADPCM36:%d, POINTNUM:%02x\n", channel, data, - get_adpcm36_bit(channel), get_point_number(channel)); - break; - - case AUDIO_PHASE_HIGH: - m_audio_regs[offset] = data & AUDIO_PHASE_HIGH_MASK; - m_channel_rate[channel] = ((double)get_phase(channel) * 140625.0 * 2.0) / (double)(1 << 19); - m_channel_rate_accum[channel] = 0.0; - LOGMASKED(LOG_CHANNEL_WRITES, "audio_w: Channel %d: Phase High: %04x (rate: %f)\n", channel, data, m_channel_rate[channel]); - break; - - case AUDIO_PHASE_ACCUM_HIGH: - m_audio_regs[offset] = data & AUDIO_PHASE_ACCUM_HIGH_MASK; - LOGMASKED(LOG_CHANNEL_WRITES, "audio_w: Channel %d: Phase Accum High: %04x\n", channel, data); - break; - - case AUDIO_TARGET_PHASE_HIGH: - m_audio_regs[offset] = data & AUDIO_TARGET_PHASE_HIGH_MASK; - LOGMASKED(LOG_CHANNEL_WRITES, "audio_w: Channel %d: Target Phase High: %04x\n", channel, data); - break; - - case AUDIO_RAMP_DOWN_CLOCK: - m_audio_regs[offset] = data & AUDIO_RAMP_DOWN_CLOCK_MASK; - LOGMASKED(LOG_CHANNEL_WRITES | LOG_RAMPDOWN, "audio_w: Channel %d: Rampdown Clock: %04x\n", channel, data); - break; - - case AUDIO_PHASE: - m_audio_regs[offset] = data; - m_channel_rate[channel] = ((double)get_phase(channel) * 140625.0 * 2.0) / (double)(1 << 19); - m_channel_rate_accum[channel] = 0.0; - LOGMASKED(LOG_CHANNEL_WRITES, "audio_w: Channel %d: Phase: %04x (rate: %f)\n", channel, data, m_channel_rate[channel]); - break; - - case AUDIO_PHASE_ACCUM: - m_audio_regs[offset] = data; - LOGMASKED(LOG_CHANNEL_WRITES, "audio_w: Channel %d: Phase Accum: %04x\n", channel, data); - break; - - case AUDIO_TARGET_PHASE: - m_audio_regs[offset] = data; - LOGMASKED(LOG_CHANNEL_WRITES, "audio_w: Channel %d: Target Phase: %04x\n", channel, data); - break; - - case AUDIO_PHASE_CTRL: - m_audio_regs[offset] = data; - LOGMASKED(LOG_CHANNEL_WRITES, "audio_w: Channel %d: Phase Ctrl: %04x (TIMESTEP:%d, SIGN:%d, OFFSET:%03x\n", channel, data, - get_phase_time_step(channel), get_phase_sign_bit(channel), get_phase_offset(channel)); - break; - - default: - m_audio_regs[offset] = data; - LOGMASKED(LOG_UNKNOWN_SPU, "audio_w: Unknown register %04x = %04x\n", 0x3000 + offset, data); - break; - } - } - else if (channel >= 16) - { - LOGMASKED(LOG_UNKNOWN_SPU, "audio_w: Trying to write to channel %d: %04x = %04x\n", channel, 0x3000 + offset, data); - } - else - { - m_audio_regs[offset] = data; - } -} - -void spg2xx_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) -{ - stream_sample_t *out_l = outputs[0]; - stream_sample_t *out_r = outputs[1]; - address_space &space = m_cpu->space(AS_PROGRAM); - - for (int i = 0; i < samples; i++) - { - int32_t left_total = 0; - int32_t right_total = 0; - - for (uint32_t channel = 0; channel < 16; channel++) - { - if (!get_channel_status(channel)) - { - continue; - } - - if (SPG_DEBUG_AUDIO && m_debug_rates) - printf("%f:%f ", m_channel_rate[channel], m_channel_rate_accum[channel]); - bool playing = advance_channel(space, channel); - if (playing) - { - int32_t sample = (int16_t)(m_audio_regs[(channel << 4) | AUDIO_WAVE_DATA] ^ 0x8000); - if (!(m_audio_regs[AUDIO_CONTROL] & AUDIO_CONTROL_NOINT_MASK)) - { - int32_t prev_sample = (int16_t)(m_audio_regs[(channel << 4) | AUDIO_WAVE_DATA_PREV] ^ 0x8000); - int16_t lerp_factor = (int16_t)((m_channel_rate_accum[channel] / 70312.5) * 256.0); - prev_sample = (prev_sample * (0x100 - lerp_factor)) >> 8; - sample = (sample * lerp_factor) >> 8; - sample += prev_sample; - } - - sample = (sample * (int32_t)get_edd(channel)) >> 7; - - int32_t vol = get_volume(channel); - int32_t pan = get_pan(channel); - - int32_t pan_left, pan_right; - if (pan < 0x40) - { - pan_left = 0x7f * vol; - pan_right = pan * 2 * vol; - } - else - { - pan_left = (0x7f - pan) * 2 * vol; - pan_right = 0x7f * vol; - } - - left_total += ((int16_t)sample * (int16_t)pan_left) >> 14; - right_total += ((int16_t)sample * (int16_t)pan_right) >> 14; - - const uint16_t mask = (1 << channel); - if (m_audio_regs[AUDIO_ENV_RAMP_DOWN] & mask) - { - if (m_rampdown_frame[channel] == 0) - { - LOGMASKED(LOG_RAMPDOWN, "Ticking rampdown for channel %d\n", channel); - audio_rampdown_tick(channel); - } - m_rampdown_frame[channel]--; - } - else if (!(m_audio_regs[AUDIO_CHANNEL_ENV_MODE] & mask)) - { - if (m_envclk_frame[channel] == 0) - { - LOGMASKED(LOG_ENVELOPES, "Ticking envelope for channel %d\n", channel); - audio_envelope_tick(space, channel); - m_envclk_frame[channel] = get_envclk_frame_count(channel); - } - m_envclk_frame[channel]--; - } - } - } - - switch (get_vol_sel()) - { - case 0: // 1/16 - left_total >>= 4; - right_total >>= 4; - break; - case 1: // 1/4 - case 2: // 1 - case 3: // 2 // Both x1 and x2 clip like mad even with only 6 voices. Hack it for now. - left_total >>= 2; - right_total >>= 2; - break; - } - *out_l++ = (left_total * (int16_t)m_audio_regs[AUDIO_MAIN_VOLUME]) >> 7; - *out_r++ = (right_total * (int16_t)m_audio_regs[AUDIO_MAIN_VOLUME]) >> 7; - } -} - -inline void spg2xx_device::stop_channel(const uint32_t channel) -{ - // TODO: IRQs - m_audio_regs[AUDIO_CHANNEL_ENABLE] &= ~(1 << channel); - m_audio_regs[AUDIO_CHANNEL_STATUS] &= ~(1 << channel); - m_audio_regs[(channel << 4) | AUDIO_MODE] &= ~AUDIO_ADPCM_MASK; - m_audio_regs[AUDIO_CHANNEL_TONE_RELEASE] &= ~(1 << channel); - m_audio_regs[AUDIO_ENV_RAMP_DOWN] &= ~(1 << channel); -} - -bool spg2xx_device::advance_channel(address_space &space, const uint32_t channel) -{ - m_channel_rate_accum[channel] += m_channel_rate[channel]; - uint32_t samples_to_advance = 0; - while (m_channel_rate_accum[channel] >= 70312.5) - { - m_channel_rate_accum[channel] -= 70312.5; - samples_to_advance++; - } - - if (!samples_to_advance) - return true; - - bool playing = true; - - if (get_adpcm_bit(channel)) - { - // ADPCM mode - for (uint32_t sample = 0; sample < samples_to_advance && playing; sample++) - { - playing = fetch_sample(space, channel); - if (playing) - { - m_sample_shift[channel] += 4; - if (m_sample_shift[channel] == 16) - { - m_sample_shift[channel] = 0; - m_sample_addr[channel]++; - } - } - } - } - else if (get_16bit_bit(channel)) - { - // 16-bit mode - for (uint32_t sample = 0; sample < samples_to_advance && playing; sample++) - { - playing = fetch_sample(space, channel); - if (playing) - m_sample_addr[channel]++; - } - } - else - { - // 8-bit mode - for (uint32_t sample = 0; sample < samples_to_advance && playing; sample++) - { - playing = fetch_sample(space, channel); - if (playing) - { - m_sample_shift[channel] += 8; - if (m_sample_shift[channel] == 16) - { - m_sample_shift[channel] = 0; - m_sample_addr[channel]++; - } - } - } - } - - return playing; -} - -bool spg2xx_device::fetch_sample(address_space &space, const uint32_t channel) -{ - const uint32_t channel_mask = channel << 4; - m_audio_regs[channel_mask | AUDIO_WAVE_DATA_PREV] = m_audio_regs[channel_mask | AUDIO_WAVE_DATA]; - - const uint32_t wave_data_reg = channel_mask | AUDIO_WAVE_DATA; - const uint16_t tone_mode = get_tone_mode(channel); - uint16_t raw_sample = tone_mode ? space.read_word(m_sample_addr[channel]) : m_audio_regs[wave_data_reg]; - - LOGMASKED(LOG_SAMPLES, "Channel %d: Raw sample %04x\n", channel, raw_sample); - - if (get_adpcm_bit(channel)) - { - // ADPCM mode - if (tone_mode != 0 && raw_sample == 0xffff) - { - if (tone_mode == AUDIO_TONE_MODE_HW_ONESHOT) - { - LOGMASKED(LOG_SAMPLES, "ADPCM stopped after %d samples\n", m_sample_count[channel]); - m_sample_count[channel] = 0; - stop_channel(channel); - return false; - } - else - { - LOGMASKED(LOG_SAMPLES, "ADPCM looping after %d samples\n", m_sample_count[channel]); - m_sample_count[channel] = 0; - loop_channel(channel); - m_audio_regs[(channel << 4) | AUDIO_MODE] &= ~AUDIO_ADPCM_MASK; - } - } - else - { - m_audio_regs[wave_data_reg] = raw_sample; - m_audio_regs[wave_data_reg] >>= m_sample_shift[channel]; - const uint8_t adpcm_sample = (uint8_t)(m_audio_regs[wave_data_reg] & 0x000f); - m_audio_regs[wave_data_reg] = (uint16_t)(m_adpcm[channel].clock(adpcm_sample) << 4) ^ 0x8000; - } - m_sample_count[channel]++; - } - else if (get_16bit_bit(channel)) - { - // 16-bit mode - if (tone_mode != 0 && raw_sample == 0xffff) - { - if (tone_mode == AUDIO_TONE_MODE_HW_ONESHOT) - { - LOGMASKED(LOG_SAMPLES, "16-bit PCM stopped after %d samples\n", m_sample_count[channel]); - m_sample_count[channel] = 0; - stop_channel(channel); - return false; - } - else - { - LOGMASKED(LOG_SAMPLES, "16-bit PCM looping after %d samples\n", m_sample_count[channel]); - m_sample_count[channel] = 0; - loop_channel(channel); - } - } - else - { - m_audio_regs[wave_data_reg] = raw_sample; - } - m_sample_count[channel]++; - } - else - { - // 8-bit mode - if (tone_mode != 0) - { - if (m_sample_shift[channel]) - raw_sample &= 0xff00; - else - raw_sample <<= 8; - raw_sample |= raw_sample >> 8; - - if (raw_sample == 0xffff) - { - if (tone_mode == AUDIO_TONE_MODE_HW_ONESHOT) - { - LOGMASKED(LOG_SAMPLES, "Channel %d: 8-bit PCM stopped after %d samples\n", channel, m_sample_count[channel]); - m_sample_count[channel] = 0; - stop_channel(channel); - return false; - } - else - { - LOGMASKED(LOG_SAMPLES, "Channel %d: 8-bit PCM looping after %d samples\n", channel, m_sample_count[channel]); - m_sample_count[channel] = 0; - loop_channel(channel); - } - } - else - { - m_audio_regs[wave_data_reg] = raw_sample; - } - } - m_sample_count[channel]++; - } - - return true; -} - -inline void spg2xx_device::loop_channel(const uint32_t channel) -{ - m_sample_addr[channel] = get_loop_addr(channel); - m_sample_shift[channel] = 0; - LOGMASKED(LOG_SAMPLES, "Channel %d: Looping to address %08x\n", channel, m_sample_addr[channel]); -} - -void spg2xx_device::audio_beat_tick() -{ - if (m_audio_curr_beat_base_count == 0) - { - LOGMASKED(LOG_BEAT, "Beat base count elapsed, reloading with %d\n", m_audio_regs[AUDIO_BEAT_BASE_COUNT]); - m_audio_curr_beat_base_count = m_audio_regs[AUDIO_BEAT_BASE_COUNT]; - - uint16_t beat_count = m_audio_regs[AUDIO_BEAT_COUNT] & AUDIO_BEAT_COUNT_MASK; - if (beat_count == 0) - { - if (m_audio_regs[AUDIO_BEAT_COUNT] & AUDIO_BIE_MASK) - { - LOGMASKED(LOG_BEAT, "Beat count elapsed, setting Status bit and checking IRQs\n"); - m_audio_regs[AUDIO_BEAT_COUNT] |= AUDIO_BIS_MASK; - check_irqs(AUDIO_BIS_MASK); - } - else - { - LOGMASKED(LOG_BEAT, "Beat count elapsed but IRQ not enabled\n"); - } - } - - beat_count--; - m_audio_regs[AUDIO_BEAT_COUNT] = (m_audio_regs[AUDIO_BEAT_COUNT] & ~AUDIO_BEAT_COUNT_MASK) | beat_count; - } - m_audio_curr_beat_base_count--; -} - -void spg2xx_device::audio_rampdown_tick(const uint32_t channel) -{ - const uint8_t old_edd = get_edd(channel); - uint8_t new_edd = old_edd - get_rampdown_offset(channel); - if (new_edd > old_edd) - new_edd = 0; - - if (new_edd) - { - LOGMASKED(LOG_RAMPDOWN, "Channel %d preparing for next rampdown step (%02x)\n", channel, new_edd); - const uint16_t channel_mask = channel << 4; - m_audio_regs[channel_mask | AUDIO_ENVELOPE_DATA] &= ~AUDIO_EDD_MASK; - m_audio_regs[channel_mask | AUDIO_ENVELOPE_DATA] |= new_edd & AUDIO_EDD_MASK; - m_rampdown_frame[channel] = get_rampdown_frame_count(channel); - } - else - { - LOGMASKED(LOG_RAMPDOWN, "Stopping channel %d due to rampdown\n", channel); - const uint16_t channel_mask = 1 << channel; - m_audio_regs[AUDIO_CHANNEL_ENABLE] &= ~channel_mask; - m_audio_regs[AUDIO_CHANNEL_STATUS] &= ~channel_mask; - m_audio_regs[AUDIO_CHANNEL_STOP] |= channel_mask; - m_audio_regs[AUDIO_ENV_RAMP_DOWN] &= ~channel_mask; - m_audio_regs[AUDIO_CHANNEL_TONE_RELEASE] &= ~channel_mask; - } -} - -const uint32_t spg2xx_device::s_rampdown_frame_counts[8] = -{ - 13*4, 13*16, 13*64, 13*256, 13*1024, 13*4096, 13*8192, 13*8192 -}; - -uint32_t spg2xx_device::get_rampdown_frame_count(const uint32_t channel) -{ - return s_rampdown_frame_counts[get_rampdown_clock(channel)]; -} - -const uint32_t spg2xx_device::s_envclk_frame_counts[16] = -{ - 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 8192, 8192, 8192, 8192 -}; - -uint32_t spg2xx_device::get_envclk_frame_count(const uint32_t channel) -{ - return s_envclk_frame_counts[get_envelope_clock(channel)]; -} - -uint32_t spg2xx_device::get_envelope_clock(const offs_t channel) const -{ - if (channel < 4) - return (m_audio_regs[AUDIO_ENVCLK0] >> (channel << 2)) & 0x000f; - else if (channel < 8) - return (m_audio_regs[AUDIO_ENVCLK0_HIGH] >> ((channel - 4) << 2)) & 0x000f; - else if (channel < 12) - return (m_audio_regs[AUDIO_ENVCLK1] >> ((channel - 8) << 2)) & 0x000f; - else - return (m_audio_regs[AUDIO_ENVCLK1_HIGH] >> ((channel - 12) << 2)) & 0x000f; -} - -bool spg2xx_device::audio_envelope_tick(address_space &space, const uint32_t channel) -{ - const uint16_t channel_mask = channel << 4; - uint16_t new_count = get_envelope_count(channel); - const uint16_t curr_edd = get_edd(channel); - LOGMASKED(LOG_ENVELOPES, "envelope %d tick, count is %04x, curr edd is %04x\n", channel, new_count, curr_edd); - bool edd_changed = false; - if (new_count == 0) - { - const uint16_t target = get_envelope_target(channel); - uint16_t new_edd = curr_edd; - const uint16_t inc = get_envelope_inc(channel); - - if (new_edd != target) - { - if (get_envelope_sign_bit(channel)) - { - new_edd -= inc; - LOGMASKED(LOG_ENVELOPES, "Envelope %d new EDD-: %04x (%04x), dec %04x\n", channel, new_edd, target, inc); - if (new_edd > curr_edd) - new_edd = 0; - else if (new_edd < target) - new_edd = target; - - if (new_edd == 0) - { - LOGMASKED(LOG_ENVELOPES, "Envelope %d at 0, stopping channel\n", channel); - stop_channel(channel); - return true; - } - } - else - { - new_edd += inc; - LOGMASKED(LOG_ENVELOPES, "Envelope %d new EDD+: %04x (%04x), inc %04x\n", channel, new_edd, target, inc); - if (new_edd >= target) - new_edd = target; - } - } - - if (new_edd == target) - { - LOGMASKED(LOG_ENVELOPES, "Envelope %d at target %04x\n", channel, target); - new_edd = target; - - if (get_envelope_repeat_bit(channel)) - { - const uint16_t repeat_count = get_envelope_repeat_count(channel) - 1; - LOGMASKED(LOG_ENVELOPES, "Repeating envelope, new repeat count %d\n", repeat_count); - if (repeat_count == 0) - { - m_audio_regs[channel_mask | AUDIO_ENVELOPE0] = space.read_word(m_envelope_addr[channel]); - m_audio_regs[channel_mask | AUDIO_ENVELOPE1] = space.read_word(m_envelope_addr[channel] + 1); - m_audio_regs[channel_mask | AUDIO_ENVELOPE_LOOP_CTRL] = space.read_word(m_envelope_addr[channel] + 2); - m_envelope_addr[channel] = get_envelope_addr(channel) + get_envelope_eaoffset(channel); - LOGMASKED(LOG_ENVELOPES, "Envelope data after repeat: %04x %04x %04x (%08x)\n", m_audio_regs[channel_mask | AUDIO_ENVELOPE0], m_audio_regs[channel_mask | AUDIO_ENVELOPE1], m_audio_regs[channel_mask | AUDIO_ENVELOPE_LOOP_CTRL], m_envelope_addr[channel]); - } - else - { - set_envelope_repeat_count(channel, repeat_count); - } - } - else - { - LOGMASKED(LOG_ENVELOPES, "Fetching envelope for channel %d from %08x\n", channel, m_envelope_addr[channel]); - m_audio_regs[channel_mask | AUDIO_ENVELOPE0] = space.read_word(m_envelope_addr[channel]); - m_audio_regs[channel_mask | AUDIO_ENVELOPE1] = space.read_word(m_envelope_addr[channel] + 1); - LOGMASKED(LOG_ENVELOPES, "Fetched envelopes %04x %04x\n", m_audio_regs[channel_mask | AUDIO_ENVELOPE0], m_audio_regs[channel_mask | AUDIO_ENVELOPE1]); - m_envelope_addr[channel] += 2; - } - new_count = get_envelope_load(channel); - set_envelope_count(channel, new_count); - } - else - { - LOGMASKED(LOG_ENVELOPES, "Envelope %d not yet at target %04x (%04x)\n", channel, target, new_edd); - new_count = get_envelope_load(channel); - set_envelope_count(channel, new_count); - } - LOGMASKED(LOG_ENVELOPES, "Envelope %d new count %04x\n", channel, new_count); - - set_edd(channel, new_edd); - edd_changed = true; - LOGMASKED(LOG_ENVELOPES, "Setting channel %d edd to %04x, register is %04x\n", channel, new_edd, m_audio_regs[(channel << 4) | AUDIO_ENVELOPE_DATA]); - } - else - { - new_count--; - set_envelope_count(channel, new_count); - } - LOGMASKED(LOG_ENVELOPES, "envelope %d post-tick, count is now %04x, register is %04x\n", channel, new_count, m_audio_regs[(channel << 4) | AUDIO_ENVELOPE_DATA]); - return edd_changed; + 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); } diff --git a/src/devices/machine/spg2xx.h b/src/devices/machine/spg2xx.h index 51ec4769b94..b35559d0dd3 100644 --- a/src/devices/machine/spg2xx.h +++ b/src/devices/machine/spg2xx.h @@ -35,10 +35,10 @@ #pragma once #include "cpu/unsp/unsp.h" -#include "sound/okiadpcm.h" +#include "spg2xx_audio.h" #include "screen.h" -class spg2xx_device : public device_t, public device_sound_interface +class spg2xx_device : public device_t, public device_mixer_interface { public: spg2xx_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); @@ -71,6 +71,8 @@ public: uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); DECLARE_WRITE_LINE_MEMBER(vblank); + required_device m_spg_audio; + protected: spg2xx_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, const uint32_t sprite_limit) : spg2xx_device(mconfig, type, tag, owner, clock) @@ -78,8 +80,7 @@ protected: m_sprite_limit = sprite_limit; } - // sound stream update overrides - virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) override; + virtual void device_add_mconfig(machine_config &config) override; enum { @@ -99,292 +100,15 @@ protected: TILE_Y_FLIP = 0x0008 }; - void audio_beat_tick(); - void audio_rampdown_tick(const uint32_t channel); - bool audio_envelope_tick(address_space &space, const uint32_t channel); - inline uint32_t get_rampdown_frame_count(const uint32_t channel); - inline uint32_t get_envclk_frame_count(const uint32_t channel); - - // Audio getters - bool get_channel_enable(const offs_t channel) const { return m_audio_regs[AUDIO_CHANNEL_ENABLE] & (1 << channel); } - bool get_channel_status(const offs_t channel) const { return m_audio_regs[AUDIO_CHANNEL_STATUS] & (1 << channel); } - bool get_manual_envelope_enable(const offs_t channel) const { return m_audio_regs[AUDIO_CHANNEL_ENV_MODE] & (1 << channel); } - bool get_auto_envelope_enable(const offs_t channel) const { return !get_manual_envelope_enable(channel); } - uint32_t get_envelope_clock(const offs_t channel) const; - uint16_t get_vol_sel() const { return (m_audio_regs[AUDIO_CONTROL] & AUDIO_CONTROL_VOLSEL_MASK) >> AUDIO_CONTROL_VOLSEL_SHIFT; } - - // Audio Mode getters - uint16_t get_wave_addr_high(const offs_t channel) const { return m_audio_regs[(channel << 4) | AUDIO_MODE] & AUDIO_WADDR_HIGH_MASK; } - uint16_t get_loop_addr_high(const offs_t channel) const { return (m_audio_regs[(channel << 4) | AUDIO_MODE] & AUDIO_LADDR_HIGH_MASK) >> AUDIO_LADDR_HIGH_SHIFT; } - uint16_t get_tone_mode(const offs_t channel) const { return (m_audio_regs[(channel << 4) | AUDIO_MODE] & AUDIO_TONE_MODE_MASK) >> AUDIO_TONE_MODE_SHIFT; } - uint16_t get_16bit_bit(const offs_t channel) const { return (m_audio_regs[(channel << 4) | AUDIO_MODE] & AUDIO_16M_MASK) ? 1 : 0; } - uint16_t get_adpcm_bit(const offs_t channel) const { return (m_audio_regs[(channel << 4) | AUDIO_MODE] & AUDIO_ADPCM_MASK) ? 1 : 0; } - - // Audio Pan getters - uint16_t get_volume(const offs_t channel) const { return m_audio_regs[(channel << 4) | AUDIO_PAN_VOL] & AUDIO_VOLUME_MASK; } - uint16_t get_pan(const offs_t channel) const { return (m_audio_regs[(channel << 4) | AUDIO_PAN_VOL] & AUDIO_PAN_MASK) >> AUDIO_PAN_SHIFT; } - - // Audio Envelope0 Data getters - uint16_t get_envelope_inc(const offs_t channel) const { return m_audio_regs[(channel << 4) | AUDIO_ENVELOPE0] & AUDIO_ENVELOPE_INC_MASK; } - uint16_t get_envelope_sign_bit(const offs_t channel) const { return (m_audio_regs[(channel << 4) | AUDIO_ENVELOPE0] & AUDIO_ENVELOPE_SIGN_MASK) ? 1 : 0; } - uint16_t get_envelope_target(const offs_t channel) const { return (m_audio_regs[(channel << 4) | AUDIO_ENVELOPE0] & AUDIO_ENVELOPE_TARGET_MASK) >> AUDIO_ENVELOPE_TARGET_SHIFT; } - uint16_t get_repeat_period_bit(const offs_t channel) const { return (m_audio_regs[(channel << 4) | AUDIO_ENVELOPE0] & AUDIO_ENVELOPE_REPEAT_PERIOD_MASK) ? 1 : 0; } - - // Audio Envelope Data getters - uint16_t get_edd(const offs_t channel) const { return m_audio_regs[(channel << 4) | AUDIO_ENVELOPE_DATA] & AUDIO_EDD_MASK; } - uint16_t get_envelope_count(const offs_t channel) const { return (m_audio_regs[(channel << 4) | AUDIO_ENVELOPE_DATA] & AUDIO_ENVELOPE_COUNT_MASK) >> AUDIO_ENVELOPE_COUNT_SHIFT; } - void set_edd(const offs_t channel, uint8_t edd) { m_audio_regs[(channel << 4) | AUDIO_ENVELOPE_DATA] = (m_audio_regs[(channel << 4) | AUDIO_ENVELOPE_DATA] & ~AUDIO_EDD_MASK) | edd; } - void set_envelope_count(const offs_t channel, uint16_t count) { m_audio_regs[(channel << 4) | AUDIO_ENVELOPE_DATA] = get_edd(channel) | (count << AUDIO_ENVELOPE_COUNT_SHIFT); } - - // Audio Envelope1 Data getters - uint16_t get_envelope_load(const offs_t channel) const { return m_audio_regs[(channel << 4) | AUDIO_ENVELOPE1] & AUDIO_ENVELOPE_LOAD_MASK; } - uint16_t get_envelope_repeat_bit(const offs_t channel) const { return (m_audio_regs[(channel << 4) | AUDIO_ENVELOPE1] & AUDIO_ENVELOPE_RPT_MASK) ? 1 : 0; } - uint16_t get_envelope_repeat_count(const offs_t channel) const { return (m_audio_regs[(channel << 4) | AUDIO_ENVELOPE1] & AUDIO_ENVELOPE_RPCNT_MASK) >> AUDIO_ENVELOPE_RPCNT_SHIFT; } - inline void set_envelope_repeat_count(const offs_t channel, const uint16_t count) { m_audio_regs[(channel << 4) | AUDIO_ENVELOPE1] = (m_audio_regs[(channel << 4) | AUDIO_ENVELOPE1] & ~AUDIO_ENVELOPE_RPCNT_MASK) | ((count << AUDIO_ENVELOPE_RPCNT_SHIFT) & AUDIO_ENVELOPE_RPCNT_MASK); } - - // Audio Envelope Address getters - uint16_t get_envelope_addr_high(const offs_t channel) const { return m_audio_regs[(channel << 4) | AUDIO_ENVELOPE_ADDR_HIGH] & AUDIO_EADDR_HIGH_MASK; } - uint16_t get_audio_irq_enable_bit(const offs_t channel) const { return (m_audio_regs[(channel << 4) | AUDIO_ENVELOPE_ADDR_HIGH] & AUDIO_IRQ_EN_MASK) ? 1 : 0; } - uint16_t get_audio_irq_addr(const offs_t channel) const { return (m_audio_regs[(channel << 4) | AUDIO_ENVELOPE_ADDR_HIGH] & AUDIO_IRQ_ADDR_MASK) >> AUDIO_IRQ_ADDR_SHIFT; } - - // Audio Envelope Loop getters - uint16_t get_envelope_eaoffset(const offs_t channel) const { return m_audio_regs[(channel << 4) | AUDIO_ENVELOPE_LOOP_CTRL] & AUDIO_EAOFFSET_MASK; } - uint16_t get_rampdown_offset(const offs_t channel) const { return (m_audio_regs[(channel << 4) | AUDIO_ENVELOPE_LOOP_CTRL] & AUDIO_RAMPDOWN_OFFSET_MASK) >> AUDIO_RAMPDOWN_OFFSET_SHIFT; } - void set_envelope_eaoffset(const offs_t channel, uint16_t eaoffset) { m_audio_regs[(channel << 4) | AUDIO_ENVELOPE_LOOP_CTRL] = (m_audio_regs[(channel << 4) | AUDIO_ENVELOPE_LOOP_CTRL] & ~AUDIO_RAMPDOWN_OFFSET_MASK) | (eaoffset & AUDIO_EAOFFSET_MASK); } - - // Audio ADPCM getters - uint16_t get_point_number(const offs_t channel) const { return (m_audio_regs[(channel << 4) | AUDIO_ADPCM_SEL] & AUDIO_POINT_NUMBER_MASK) >> AUDIO_POINT_NUMBER_SHIFT; } - uint16_t get_adpcm36_bit(const offs_t channel) const { return (m_audio_regs[(channel << 4) | AUDIO_ADPCM_SEL] & AUDIO_ADPCM36_MASK) ? 1 : 0; } - - // Audio high-word getters - uint16_t get_phase_high(const offs_t channel) const { return m_audio_regs[(channel << 4) | AUDIO_PHASE_HIGH] & AUDIO_PHASE_HIGH_MASK; } - uint16_t get_phase_accum_high(const offs_t channel) const { return m_audio_regs[(channel << 4) | AUDIO_PHASE_ACCUM_HIGH] & AUDIO_PHASE_ACCUM_HIGH_MASK; } - uint16_t get_target_phase_high(const offs_t channel) const { return m_audio_regs[(channel << 4) | AUDIO_TARGET_PHASE_HIGH] & AUDIO_TARGET_PHASE_HIGH_MASK; } - uint16_t get_rampdown_clock(const offs_t channel) const { return m_audio_regs[(channel << 4) | AUDIO_RAMP_DOWN_CLOCK] & AUDIO_RAMP_DOWN_CLOCK_MASK; } - - // Audio ADPCM getters - uint16_t get_phase_offset(const offs_t channel) const { return m_audio_regs[(channel << 4) | AUDIO_PHASE_CTRL] & AUDIO_PHASE_OFFSET_MASK; } - uint16_t get_phase_sign_bit(const offs_t channel) const { return (m_audio_regs[(channel << 4) | AUDIO_PHASE_CTRL] & AUDIO_PHASE_SIGN_MASK) >> AUDIO_PHASE_SIGN_SHIFT; } - uint16_t get_phase_time_step(const offs_t channel) const { return (m_audio_regs[(channel << 4) | AUDIO_PHASE_CTRL] & AUDIO_PHASE_TIME_STEP_MASK) >> AUDIO_PHASE_TIME_STEP_SHIFT; } - - // Audio combined getters - uint32_t get_phase(const offs_t channel) const { return ((uint32_t)get_phase_high(channel) << 16) | m_audio_regs[(channel << 4) | AUDIO_PHASE]; } - uint32_t get_phase_accum(const offs_t channel) const { return ((uint32_t)get_phase_accum_high(channel) << 16) | m_audio_regs[(channel << 4) | AUDIO_PHASE_ACCUM]; } - uint32_t get_target_phase(const offs_t channel) const { return ((uint32_t)get_target_phase_high(channel) << 16) | m_audio_regs[(channel << 4) | AUDIO_TARGET_PHASE]; } - uint32_t get_wave_addr(const offs_t channel) const { return ((uint32_t)get_wave_addr_high(channel) << 16) | m_audio_regs[(channel << 4) | AUDIO_WAVE_ADDR]; } - uint32_t get_loop_addr(const offs_t channel) const { return ((uint32_t)get_loop_addr_high(channel) << 16) | m_audio_regs[(channel << 4) | AUDIO_LOOP_ADDR]; } - uint32_t get_envelope_addr(const offs_t channel) const { return ((uint32_t)get_envelope_addr_high(channel) << 16) | m_audio_regs[(channel << 4) | AUDIO_ENVELOPE_ADDR]; } - - enum - { - AUDIO_WAVE_ADDR = 0x000, - - AUDIO_MODE = 0x001, - AUDIO_WADDR_HIGH_MASK = 0x003f, - AUDIO_LADDR_HIGH_MASK = 0x0fc0, - AUDIO_LADDR_HIGH_SHIFT = 6, - AUDIO_TONE_MODE_MASK = 0x3000, - AUDIO_TONE_MODE_SHIFT = 12, - AUDIO_TONE_MODE_SW = 0, - AUDIO_TONE_MODE_HW_ONESHOT = 1, - AUDIO_TONE_MODE_HW_LOOP = 2, - AUDIO_16M_MASK = 0x4000, - AUDIO_ADPCM_MASK = 0x8000, - - AUDIO_LOOP_ADDR = 0x002, - - AUDIO_PAN_VOL = 0x003, - AUDIO_PAN_VOL_MASK = 0x7f7f, - AUDIO_VOLUME_MASK = 0x007f, - AUDIO_PAN_MASK = 0x7f00, - AUDIO_PAN_SHIFT = 8, - - AUDIO_ENVELOPE0 = 0x004, - AUDIO_ENVELOPE_INC_MASK = 0x007f, - AUDIO_ENVELOPE_SIGN_MASK = 0x0080, - AUDIO_ENVELOPE_TARGET_MASK = 0x7f00, - AUDIO_ENVELOPE_TARGET_SHIFT = 8, - AUDIO_ENVELOPE_REPEAT_PERIOD_MASK = 0x8000, - - AUDIO_ENVELOPE_DATA = 0x005, - AUDIO_ENVELOPE_DATA_MASK = 0xff7f, - AUDIO_EDD_MASK = 0x007f, - AUDIO_ENVELOPE_COUNT_MASK = 0xff00, - AUDIO_ENVELOPE_COUNT_SHIFT = 8, - - AUDIO_ENVELOPE1 = 0x006, - AUDIO_ENVELOPE_LOAD_MASK = 0x00ff, - AUDIO_ENVELOPE_RPT_MASK = 0x0100, - AUDIO_ENVELOPE_RPCNT_MASK = 0xfe00, - AUDIO_ENVELOPE_RPCNT_SHIFT = 9, - - AUDIO_ENVELOPE_ADDR_HIGH = 0x007, - AUDIO_EADDR_HIGH_MASK = 0x003f, - AUDIO_IRQ_EN_MASK = 0x0040, - AUDIO_IRQ_ADDR_MASK = 0xff80, - AUDIO_IRQ_ADDR_SHIFT = 7, - - AUDIO_ENVELOPE_ADDR = 0x008, - AUDIO_WAVE_DATA_PREV = 0x009, - - AUDIO_ENVELOPE_LOOP_CTRL = 0x00a, - AUDIO_EAOFFSET_MASK = 0x01ff, - AUDIO_RAMPDOWN_OFFSET_MASK = 0xfe00, - AUDIO_RAMPDOWN_OFFSET_SHIFT = 9, - - AUDIO_WAVE_DATA = 0x00b, - - AUDIO_ADPCM_SEL = 0x00d, - AUDIO_ADPCM_SEL_MASK = 0xfe00, - AUDIO_POINT_NUMBER_MASK = 0x7e00, - AUDIO_POINT_NUMBER_SHIFT = 9, - AUDIO_ADPCM36_MASK = 0x8000, - - AUDIO_PHASE_HIGH = 0x200, - AUDIO_PHASE_HIGH_MASK = 0x0007, - - AUDIO_PHASE_ACCUM_HIGH = 0x201, - AUDIO_PHASE_ACCUM_HIGH_MASK = 0x0007, - - AUDIO_TARGET_PHASE_HIGH = 0x202, - AUDIO_TARGET_PHASE_HIGH_MASK= 0x0007, - - AUDIO_RAMP_DOWN_CLOCK = 0x203, - AUDIO_RAMP_DOWN_CLOCK_MASK = 0x0007, - - AUDIO_PHASE = 0x204, - AUDIO_PHASE_ACCUM = 0x205, - AUDIO_TARGET_PHASE = 0x206, - - AUDIO_PHASE_CTRL = 0x207, - AUDIO_PHASE_OFFSET_MASK = 0x0fff, - AUDIO_PHASE_SIGN_MASK = 0x1000, - AUDIO_PHASE_SIGN_SHIFT = 12, - AUDIO_PHASE_TIME_STEP_MASK = 0xe000, - AUDIO_PHASE_TIME_STEP_SHIFT = 13, - - AUDIO_CHAN_OFFSET_MASK = 0xf0f, - - AUDIO_CHANNEL_ENABLE = 0x400, - AUDIO_CHANNEL_ENABLE_MASK = 0xffff, - - AUDIO_MAIN_VOLUME = 0x401, - AUDIO_MAIN_VOLUME_MASK = 0x007f, - - AUDIO_CHANNEL_FIQ_ENABLE = 0x402, - AUDIO_CHANNEL_FIQ_ENABLE_MASK = 0xffff, - - AUDIO_CHANNEL_FIQ_STATUS = 0x403, - AUDIO_CHANNEL_FIQ_STATUS_MASK = 0xffff, - - AUDIO_BEAT_BASE_COUNT = 0x404, - AUDIO_BEAT_BASE_COUNT_MASK = 0x07ff, - - AUDIO_BEAT_COUNT = 0x405, - AUDIO_BEAT_COUNT_MASK = 0x3fff, - AUDIO_BIS_MASK = 0x4000, - AUDIO_BIE_MASK = 0x8000, - - AUDIO_ENVCLK0 = 0x406, - - AUDIO_ENVCLK0_HIGH = 0x407, - AUDIO_ENVCLK0_HIGH_MASK = 0xffff, - - AUDIO_ENVCLK1 = 0x408, - - AUDIO_ENVCLK1_HIGH = 0x409, - AUDIO_ENVCLK1_HIGH_MASK = 0xffff, - - AUDIO_ENV_RAMP_DOWN = 0x40a, - AUDIO_ENV_RAMP_DOWN_MASK = 0xffff, - - AUDIO_CHANNEL_STOP = 0x40b, - AUDIO_CHANNEL_STOP_MASK = 0xffff, - - AUDIO_CHANNEL_ZERO_CROSS = 0x40c, - AUDIO_CHANNEL_ZERO_CROSS_MASK = 0xffff, - - AUDIO_CONTROL = 0x40d, - AUDIO_CONTROL_MASK = 0x9fe8, - AUDIO_CONTROL_SATURATE_MASK = 0x8000, - AUDIO_CONTROL_SOFTCH_MASK = 0x1000, - AUDIO_CONTROL_COMPEN_MASK = 0x0800, - AUDIO_CONTROL_NOHIGH_MASK = 0x0400, - AUDIO_CONTROL_NOINT_MASK = 0x0200, - AUDIO_CONTROL_EQEN_MASK = 0x0100, - AUDIO_CONTROL_VOLSEL_MASK = 0x00c0, - AUDIO_CONTROL_VOLSEL_SHIFT = 6, - AUDIO_CONTROL_FOF_MASK = 0x0020, - AUDIO_CONTROL_INIT_MASK = 0x0008, - - AUDIO_COMPRESS_CTRL = 0x40e, - AUDIO_COMPRESS_CTRL_PEAK_MASK = 0x8000, - AUDIO_COMPRESS_CTRL_THRESHOLD_MASK = 0x7f00, - AUDIO_COMPRESS_CTRL_THRESHOLD_SHIFT = 8, - AUDIO_COMPRESS_CTRL_ATTSCALE_MASK = 0x00c0, - AUDIO_COMPRESS_CTRL_ATTSCALE_SHIFT = 6, - AUDIO_COMPRESS_CTRL_RELSCALE_MASK = 0x0030, - AUDIO_COMPRESS_CTRL_RELSCALE_SHIFT = 4, - AUDIO_COMPRESS_CTRL_DISZC_MASK = 0x0008, - AUDIO_COMPRESS_CTRL_RATIO_MASK = 0x0007, - - AUDIO_CHANNEL_STATUS = 0x40f, - AUDIO_CHANNEL_STATUS_MASK = 0xffff, - - AUDIO_WAVE_IN_L = 0x410, - - AUDIO_WAVE_IN_R = 0x411, - AUDIO_SOFTIRQ_MASK = 0x8000, - AUDIO_SOFTIRQ_EN_MASK = 0x4000, - AUDIO_SOFT_PHASE_HIGH_MASK = 0x0070, - AUDIO_SOFT_PHASE_HIGH_SHIFT = 4, - AUDIO_FIFO_IRQ_THRESHOLD_MASK = 0x000f, - - AUDIO_WAVE_OUT_L = 0x412, - AUDIO_WAVE_OUT_R = 0x413, - - AUDIO_CHANNEL_REPEAT = 0x414, - AUDIO_CHANNEL_REPEAT_MASK = 0xffff, - - AUDIO_CHANNEL_ENV_MODE = 0x415, - AUDIO_CHANNEL_ENV_MODE_MASK = 0xffff, - - AUDIO_CHANNEL_TONE_RELEASE = 0x416, - AUDIO_CHANNEL_TONE_RELEASE_MASK = 0xffff, - - AUDIO_CHANNEL_ENV_IRQ = 0x417, - AUDIO_CHANNEL_ENV_IRQ_MASK = 0xffff, - - AUDIO_CHANNEL_PITCH_BEND = 0x418, - AUDIO_CHANNEL_PITCH_BEND_MASK = 0xffff, - - AUDIO_SOFT_PHASE = 0x419, - - AUDIO_ATTACK_RELEASE = 0x41a, - AUDIO_RELEASE_TIME_MASK = 0x00ff, - AUDIO_ATTACK_TIME_MASK = 0xff00, - AUDIO_ATTACK_TIME_SHIFT = 8, - - AUDIO_EQ_CUTOFF10 = 0x41b, - AUDIO_EQ_CUTOFF10_MASK = 0x7f7f, - - AUDIO_EQ_CUTOFF32 = 0x41c, - AUDIO_EQ_CUTOFF32_MASK = 0x7f7f, - - AUDIO_EQ_GAIN10 = 0x41d, - AUDIO_EQ_GAIN10_MASK = 0x7f7f, - - AUDIO_EQ_GAIN32 = 0x41e, - AUDIO_EQ_GAIN32_MASK = 0x7f7f - }; - DECLARE_READ16_MEMBER(video_r); DECLARE_WRITE16_MEMBER(video_w); - DECLARE_READ16_MEMBER(audio_r); - DECLARE_WRITE16_MEMBER(audio_w); + virtual DECLARE_READ16_MEMBER(io_r); virtual DECLARE_WRITE16_MEMBER(io_w); + DECLARE_WRITE_LINE_MEMBER(audioirq_w); + DECLARE_READ16_MEMBER(space_r); + void check_extint_irq(int channel); void check_irqs(const uint16_t changed); inline void check_video_irq(); @@ -454,11 +178,6 @@ protected: uint8_t mix_channel(uint8_t a, uint8_t b); - void stop_channel(const uint32_t channel); - bool advance_channel(address_space &space, const uint32_t channel); - bool fetch_sample(address_space &space, const uint32_t channel); - void loop_channel(const uint32_t channel); - uint32_t m_screenbuf[320 * 240]; uint8_t m_rgb5_to_rgb8[32]; uint32_t m_rgb555_to_rgb888[0x8000]; @@ -471,20 +190,6 @@ protected: bool m_debug_palette; uint8_t m_sprite_index_to_debug; - bool m_debug_samples; - bool m_debug_rates; - - uint16_t m_audio_regs[0x800]; - uint8_t m_sample_shift[16]; - uint32_t m_sample_count[16]; - uint32_t m_sample_addr[16]; - double m_channel_rate[16]; - double m_channel_rate_accum[16]; - uint32_t m_rampdown_frame[16]; - uint32_t m_envclk_frame[16]; - uint32_t m_envelope_addr[16]; - int m_channel_debug; - uint16_t m_audio_curr_beat_base_count; uint16_t m_io_regs[0x200]; uint8_t m_uart_rx_fifo[8]; @@ -528,7 +233,6 @@ protected: emu_timer *m_timer_src_ab; emu_timer *m_timer_src_c; emu_timer *m_screenpos_timer; - emu_timer *m_audio_beat; emu_timer *m_4khz_timer; uint32_t m_2khz_divider; @@ -539,17 +243,11 @@ protected: emu_timer *m_uart_tx_timer; emu_timer *m_uart_rx_timer; - sound_stream *m_stream; - oki_adpcm_state m_adpcm[16]; - required_device m_cpu; required_device m_screen; required_shared_ptr m_scrollram; required_shared_ptr m_paletteram; required_shared_ptr m_spriteram; - - static const uint32_t s_rampdown_frame_counts[8]; - static const uint32_t s_envclk_frame_counts[16]; }; class spg24x_device : public spg2xx_device diff --git a/src/devices/machine/spg2xx_audio.cpp b/src/devices/machine/spg2xx_audio.cpp new file mode 100644 index 00000000000..64a9742eebc --- /dev/null +++ b/src/devices/machine/spg2xx_audio.cpp @@ -0,0 +1,1270 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +/***************************************************************************** + + SunPlus SPG2xx-series SoC peripheral emulation (Audio) + +**********************************************************************/ + +#include "emu.h" +#include "spg2xx_audio.h" + +DEFINE_DEVICE_TYPE(SPG2XX_AUDIO, spg2xx_audio_device, "spg2xx", "SPG2xx-series System-on-a-Chip Audio") + +#define LOG_SPU_READS (1U << 13) +#define LOG_SPU_WRITES (1U << 14) +#define LOG_UNKNOWN_SPU (1U << 15) +#define LOG_CHANNEL_READS (1U << 16) +#define LOG_CHANNEL_WRITES (1U << 17) +#define LOG_ENVELOPES (1U << 18) +#define LOG_SAMPLES (1U << 19) +#define LOG_RAMPDOWN (1U << 20) +#define LOG_BEAT (1U << 21) + +#define LOG_SPU (LOG_SPU_READS | LOG_SPU_WRITES | LOG_UNKNOWN_SPU | LOG_CHANNEL_READS | LOG_CHANNEL_WRITES \ + | LOG_ENVELOPES | LOG_SAMPLES | LOG_RAMPDOWN | LOG_BEAT) +#define LOG_ALL (LOG_SPU) + +#define VERBOSE (0) +#include "logmacro.h" + +#define SPG_DEBUG_AUDIO (0) + + +spg2xx_audio_device::spg2xx_audio_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, type, tag, owner, clock) + , device_sound_interface(mconfig, *this) + , m_space_read_cb(*this) + , m_irq_cb(*this) +{ +} + +spg2xx_audio_device::spg2xx_audio_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : spg2xx_audio_device(mconfig, SPG2XX_AUDIO, tag, owner, clock) +{ +} + + +void spg2xx_audio_device::device_start() +{ + m_audio_beat = timer_alloc(TIMER_BEAT); + m_audio_beat->adjust(attotime::never); + + m_stream = stream_alloc(0, 2, 281250/4); + + m_channel_debug = -1; + + save_item(NAME(m_debug_samples)); + save_item(NAME(m_debug_rates)); + + save_item(NAME(m_audio_regs)); + save_item(NAME(m_audio_phase_regs)); + save_item(NAME(m_audio_ctrl_regs)); + + save_item(NAME(m_sample_shift)); + save_item(NAME(m_sample_count)); + save_item(NAME(m_sample_addr)); + save_item(NAME(m_channel_rate)); + save_item(NAME(m_channel_rate_accum)); + save_item(NAME(m_rampdown_frame)); + save_item(NAME(m_envclk_frame)); + save_item(NAME(m_envelope_addr)); + save_item(NAME(m_channel_debug)); + save_item(NAME(m_audio_curr_beat_base_count)); + + + for (int i = 0; i < 16; i++) + { + save_item(NAME(m_adpcm[i].m_signal), i); + save_item(NAME(m_adpcm[i].m_step), i); + } + + m_space_read_cb.resolve_safe(0); + m_irq_cb.resolve(); +} + +void spg2xx_audio_device::device_reset() +{ + memset(m_audio_regs, 0, 0x200 * sizeof(uint16_t)); + memset(m_audio_phase_regs, 0, 0x200 * sizeof(uint16_t)); + memset(m_audio_ctrl_regs, 0, 0x400 * sizeof(uint16_t)); + + memset(m_sample_shift, 0, 16); + memset(m_sample_count, 0, sizeof(uint32_t) * 16); + memset(m_sample_addr, 0, sizeof(uint32_t) * 16); + memset(m_channel_rate, 0, sizeof(double) * 16); + memset(m_channel_rate_accum, 0, sizeof(double) * 16); + memset(m_rampdown_frame, 0, sizeof(uint32_t) * 16); + memset(m_envclk_frame, 4, sizeof(uint32_t) * 16); + memset(m_envelope_addr, 0, sizeof(uint32_t) * 16); + + m_debug_samples = false; + m_debug_rates = false; + m_audio_curr_beat_base_count = 0; + + m_audio_ctrl_regs[AUDIO_CHANNEL_REPEAT] = 0x3f; + m_audio_ctrl_regs[AUDIO_CHANNEL_ENV_MODE] = 0x3f; + + m_audio_beat->adjust(attotime::from_ticks(4, 281250), 0, attotime::from_ticks(4, 281250)); +} + + +void spg2xx_audio_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_BEAT: + audio_beat_tick(); + break; + } +} + +/*********************** +* Audio Hardware * +***********************/ +void spg2xx_audio_device::check_irqs(const uint16_t changed) +{ + if (changed & (AUDIO_BIS_MASK | AUDIO_BIE_MASK)) // Beat IRQ + { + if ((m_audio_ctrl_regs[AUDIO_BEAT_COUNT] & (AUDIO_BIS_MASK | AUDIO_BIE_MASK)) == (AUDIO_BIS_MASK | AUDIO_BIE_MASK)) + { + LOGMASKED(LOG_BEAT, "Asserting beat IRQ\n"); + m_irq_cb(true); + } + else + { + LOGMASKED(LOG_BEAT, "Clearing beat IRQ\n"); + m_irq_cb(false); + } + } +} + +READ16_MEMBER(spg2xx_audio_device::audio_ctrl_r) +{ + uint16_t data = m_audio_ctrl_regs[offset]; + + switch (offset) + { + case AUDIO_CHANNEL_ENABLE: + LOGMASKED(LOG_SPU_READS, "audio_ctrl_r: Channel Enable: %04x\n", data); + break; + + case AUDIO_MAIN_VOLUME: + LOGMASKED(LOG_SPU_READS, "audio_ctrl_r: Main Volume: %04x\n", data); + break; + + case AUDIO_CHANNEL_FIQ_ENABLE: + LOGMASKED(LOG_SPU_READS, "audio_ctrl_r: Channel FIQ Enable: %04x\n", data); + break; + + case AUDIO_CHANNEL_FIQ_STATUS: + LOGMASKED(LOG_SPU_READS, "audio_ctrl_r: Channel FIQ Acknowledge: %04x\n", data); + break; + + case AUDIO_BEAT_BASE_COUNT: + LOGMASKED(LOG_SPU_READS | LOG_BEAT, "audio_ctrl_r: Beat Base Count: %04x\n", data); + break; + + case AUDIO_BEAT_COUNT: + LOGMASKED(LOG_SPU_READS | LOG_BEAT, "audio_ctrl_r: Beat Count: %04x\n", data); + break; + + case AUDIO_ENVCLK0: + case AUDIO_ENVCLK1: + LOGMASKED(LOG_SPU_READS | LOG_ENVELOPES, "audio_ctrl_r: Envelope Interval %d (lo): %04x\n", offset == AUDIO_ENVCLK0 ? 0 : 1, data); + break; + + case AUDIO_ENVCLK0_HIGH: + case AUDIO_ENVCLK1_HIGH: + LOGMASKED(LOG_SPU_READS | LOG_ENVELOPES, "audio_ctrl_r: Envelope Interval %d (hi): %04x\n", offset == AUDIO_ENVCLK0_HIGH ? 0 : 1, data); + break; + + case AUDIO_ENV_RAMP_DOWN: + LOGMASKED(LOG_SPU_READS | LOG_RAMPDOWN, "audio_ctrl_r: Envelope Fast Ramp Down: %04x\n", data); + break; + + case AUDIO_CHANNEL_STOP: + LOGMASKED(LOG_SPU_READS, "audio_ctrl_r: Channel Stop Status: %04x\n", data); + break; + + case AUDIO_CHANNEL_ZERO_CROSS: + LOGMASKED(LOG_SPU_READS, "audio_ctrl_r: Channel Zero-Cross Enable: %04x\n", data); + break; + + case AUDIO_CONTROL: + LOGMASKED(LOG_SPU_READS, "audio_ctrl_r: Control: %04x\n", data); + break; + + case AUDIO_COMPRESS_CTRL: + LOGMASKED(LOG_SPU_READS, "audio_ctrl_r: Compressor Control: %04x\n", data); + break; + + case AUDIO_CHANNEL_STATUS: + LOGMASKED(LOG_SPU_READS, "audio_ctrl_r: Channel Status: %04x\n", data); + break; + + case AUDIO_WAVE_IN_L: + LOGMASKED(LOG_SPU_READS, "audio_ctrl_r: Wave In (L) / FIFO Write Data: %04x\n", data); + break; + + case AUDIO_WAVE_IN_R: + LOGMASKED(LOG_SPU_READS, "audio_ctrl_r: Wave In (R) / Software Channel FIFO IRQ Control: %04x\n", data); + break; + + case AUDIO_WAVE_OUT_L: + LOGMASKED(LOG_SPU_READS, "audio_ctrl_r: Wave Out (L): %04x\n", data); + break; + + case AUDIO_WAVE_OUT_R: + LOGMASKED(LOG_SPU_READS, "audio_ctrl_r: Wave Out (R): %04x\n", data); + break; + + case AUDIO_CHANNEL_REPEAT: + LOGMASKED(LOG_SPU_READS, "audio_ctrl_r: Channel Repeat Enable: %04x\n", data); + break; + + case AUDIO_CHANNEL_ENV_MODE: + LOGMASKED(LOG_SPU_READS | LOG_ENVELOPES, "audio_ctrl_r: Channel Envelope Enable: %04x\n", data); + break; + + case AUDIO_CHANNEL_TONE_RELEASE: + LOGMASKED(LOG_SPU_READS, "audio_ctrl_r: Channel Tone Release Enable: %04x\n", data); + break; + + case AUDIO_CHANNEL_ENV_IRQ: + LOGMASKED(LOG_SPU_READS, "audio_ctrl_r: Channel Envelope IRQ Status: %04x\n", data); + break; + + case AUDIO_CHANNEL_PITCH_BEND: + LOGMASKED(LOG_SPU_READS, "audio_ctrl_r: Channel Pitch Bend Enable: %04x\n", data); + break; + + case AUDIO_SOFT_PHASE: + LOGMASKED(LOG_SPU_READS, "audio_ctrl_r: Software Channel Phase: %04x\n", data); + break; + + case AUDIO_ATTACK_RELEASE: + LOGMASKED(LOG_SPU_READS, "audio_ctrl_r: Attack/Release Time Control: %04x\n", data); + break; + + case AUDIO_EQ_CUTOFF10: + LOGMASKED(LOG_SPU_READS, "audio_ctrl_r: EQ Cutoff Frequency 0/1: %04x\n", data); + break; + + case AUDIO_EQ_CUTOFF32: + LOGMASKED(LOG_SPU_READS, "audio_ctrl_r: EQ Cutoff Frequency 2/3: %04x\n", data); + break; + + case AUDIO_EQ_GAIN10: + LOGMASKED(LOG_SPU_READS, "audio_ctrl_r: EQ Cutoff Gain 0/1: %04x\n", data); + break; + + case AUDIO_EQ_GAIN32: + LOGMASKED(LOG_SPU_READS, "audio_ctrl_r: EQ Cutoff Gain 2/3: %04x\n", data); + break; + + default: + LOGMASKED(LOG_UNKNOWN_SPU, "audio_ctrl_r: Unknown register %04x = %04x\n", 0x3000 + offset, data); + break; + } + + return data; +} + +READ16_MEMBER(spg2xx_audio_device::audio_r) +{ + const uint16_t channel = (offset & 0x00f0) >> 4; + uint16_t data = m_audio_regs[offset]; + + + switch (offset & AUDIO_CHAN_OFFSET_MASK) + { + case AUDIO_WAVE_ADDR: + LOGMASKED(LOG_CHANNEL_READS, "audio_r: Channel %d: Wave Addr (lo): %04x\n", channel, data); + break; + + case AUDIO_MODE: + LOGMASKED(LOG_CHANNEL_READS, "audio_r: Channel %d: Mode: %04x (ADPCM:%d, 16M:%d, TONE:%d, LADDR_HI:%04x, WADDR_HI:%04x)\n", channel, data, + get_adpcm_bit(channel), get_16bit_bit(channel), get_tone_mode(channel), get_loop_addr_high(channel), get_wave_addr_high(channel)); + break; + + case AUDIO_LOOP_ADDR: + LOGMASKED(LOG_CHANNEL_READS, "audio_r: Channel %d: Loop Addr: %04x\n", channel, data); + break; + + case AUDIO_PAN_VOL: + LOGMASKED(LOG_CHANNEL_READS, "audio_r: Channel %d: Pan/Vol: %04x (PAN:%02x, VOL:%02x)\n", channel, data, + get_pan(channel), get_volume(channel)); + break; + + case AUDIO_ENVELOPE0: + LOGMASKED(LOG_CHANNEL_READS | LOG_ENVELOPES, "audio_r: Channel %d: Envelope0: %04x (RPTPER:%d, TARGET:%02x, SIGN:%d, INC:%02x)\n", channel, data, + get_repeat_period_bit(channel), get_envelope_target(channel), get_envelope_sign_bit(channel), get_envelope_inc(channel)); + break; + + case AUDIO_ENVELOPE_DATA: + LOGMASKED(LOG_CHANNEL_READS | LOG_ENVELOPES, "audio_r: Channel %d: Envelope Data: %04x (CNT:%d, EDD:%02x)\n", channel, data, + get_envelope_count(channel), get_edd(channel)); + break; + + case AUDIO_ENVELOPE1: + LOGMASKED(LOG_CHANNEL_READS | LOG_ENVELOPES, "audio_r: Channel %d: Envelope1 Data: %04x (RPTCNT:%02x, RPT:%d, LOAD:%02x)\n", channel, data, + get_envelope_repeat_count(channel), get_envelope_repeat_bit(channel), get_envelope_load(channel)); + break; + + case AUDIO_ENVELOPE_ADDR_HIGH: + LOGMASKED(LOG_CHANNEL_READS | LOG_ENVELOPES, "audio_r: Channel %d: Envelope Addr (hi): %04x (IRQADDR:%03x, IRQEN:%d, EADDR_HI:%02x)\n", channel, data, + get_audio_irq_addr(channel), get_audio_irq_enable_bit(channel), get_envelope_addr_high(channel)); + break; + + case AUDIO_ENVELOPE_ADDR: + LOGMASKED(LOG_CHANNEL_READS | LOG_ENVELOPES, "audio_r: Channel %d: Envelope Addr (lo): %04x \n", channel, data); + break; + + case AUDIO_WAVE_DATA_PREV: + LOGMASKED(LOG_CHANNEL_READS, "audio_r: Channel %d: Wave Data Prev: %04x \n", channel, data); + break; + + case AUDIO_ENVELOPE_LOOP_CTRL: + LOGMASKED(LOG_CHANNEL_READS | LOG_ENVELOPES, "audio_r: Channel %d: Envelope Loop Ctrl: %04x (RDOFFS:%02x, EAOFFS:%03x)\n", channel, data, + get_rampdown_offset(channel), get_envelope_eaoffset(channel)); + break; + + case AUDIO_WAVE_DATA: + LOGMASKED(LOG_CHANNEL_READS, "audio_r: Channel %d: Wave Data: %04x\n", channel, data); + break; + + case AUDIO_ADPCM_SEL: + LOGMASKED(LOG_CHANNEL_READS, "audio_r: Channel %d: ADPCM Sel: %04x (ADPCM36:%d, POINTNUM:%02x\n", channel, data, + get_adpcm36_bit(channel), get_point_number(channel)); + break; + + default: + LOGMASKED(LOG_UNKNOWN_SPU, "audio_r: Unknown register %04x\n", 0x3000 + offset); + break; + + } + + return data; +} + + +READ16_MEMBER(spg2xx_audio_device::audio_phase_r) +{ + const uint16_t channel = (offset & 0x00f0) >> 4; + uint16_t data = m_audio_phase_regs[offset]; + + switch (offset & AUDIO_CHAN_OFFSET_MASK) + { + case AUDIO_PHASE_HIGH: + LOGMASKED(LOG_CHANNEL_READS, "audio_phase_r: Channel %d: Phase High: %04x\n", channel, data); + break; + + case AUDIO_PHASE_ACCUM_HIGH: + LOGMASKED(LOG_CHANNEL_READS, "audio_phase_r: Channel %d: Phase Accum High: %04x\n", channel, data); + break; + + case AUDIO_TARGET_PHASE_HIGH: + LOGMASKED(LOG_CHANNEL_READS, "audio_phase_r: Channel %d: Target Phase High: %04x\n", channel, data); + break; + + case AUDIO_RAMP_DOWN_CLOCK: + LOGMASKED(LOG_CHANNEL_READS | LOG_RAMPDOWN, "audio_phase_r: Channel %d: Rampdown Clock: %04x\n", channel, data); + break; + + case AUDIO_PHASE: + LOGMASKED(LOG_CHANNEL_READS, "audio_phase_r: Channel %d: Phase: %04x\n", channel, data); + break; + + case AUDIO_PHASE_ACCUM: + LOGMASKED(LOG_CHANNEL_READS, "audio_phase_r: Channel %d: Phase Accum: %04x\n", channel, data); + break; + + case AUDIO_TARGET_PHASE: + LOGMASKED(LOG_CHANNEL_READS, "audio_phase_r: Channel %d: Target Phase: %04x\n", channel, data); + break; + + case AUDIO_PHASE_CTRL: + LOGMASKED(LOG_CHANNEL_READS, "audio_phase_r: Channel %d: Phase Ctrl: %04x (TIMESTEP:%d, SIGN:%d, OFFSET:%03x\n", channel, data, + get_phase_time_step(channel), get_phase_sign_bit(channel), get_phase_offset(channel)); + break; + + default: + LOGMASKED(LOG_UNKNOWN_SPU, "audio_phase_r: Unknown register %04x\n", 0x3000 + offset); + break; + } + + return data; +} + +WRITE16_MEMBER(spg2xx_audio_device::audio_ctrl_w) +{ + switch (offset) + { + case AUDIO_CHANNEL_ENABLE: + { + LOGMASKED(LOG_SPU_WRITES, "audio_ctrl_w: Channel Enable: %04x\n", data); + const uint16_t changed = m_audio_ctrl_regs[AUDIO_CHANNEL_ENABLE] ^ data; + for (uint32_t channel_bit = 0; channel_bit < 16; channel_bit++) + { + const uint16_t mask = 1 << channel_bit; + if (!(changed & mask)) + continue; + + if (data & mask) + { + if (!(m_audio_ctrl_regs[AUDIO_CHANNEL_STATUS] & mask)) + { + LOGMASKED(LOG_SPU_WRITES, "Enabling channel %d\n", channel_bit); + m_audio_ctrl_regs[offset] |= mask; + if (!(m_audio_ctrl_regs[AUDIO_CHANNEL_STOP] & mask)) + { + LOGMASKED(LOG_SPU_WRITES, "Stop not set, starting playback on channel %d, mask %04x\n", channel_bit, mask); + m_audio_ctrl_regs[AUDIO_CHANNEL_STATUS] |= mask; + m_sample_addr[channel_bit] = get_wave_addr(channel_bit); + m_envelope_addr[channel_bit] = get_envelope_addr(channel_bit); + set_envelope_count(channel_bit, get_envelope_load(channel_bit)); + } + m_adpcm[channel_bit].reset(); + m_sample_shift[channel_bit] = 0; + m_sample_count[channel_bit] = 0; + } + } + else + { + stop_channel(channel_bit); + //m_audio_ctrl_regs[offset] &= ~mask; + //m_audio_ctrl_regs[AUDIO_CHANNEL_STATUS] &= ~mask; + //m_audio_ctrl_regs[AUDIO_CHANNEL_STOP] |= mask; + //m_audio_ctrl_regs[AUDIO_CHANNEL_TONE_RELEASE] &= ~mask; + } + } + break; + } + + case AUDIO_MAIN_VOLUME: + LOGMASKED(LOG_SPU_WRITES, "audio_ctrl_w: Main Volume: %04x\n", data); + m_audio_ctrl_regs[offset] = data & AUDIO_MAIN_VOLUME_MASK; + break; + + case AUDIO_CHANNEL_FIQ_ENABLE: + LOGMASKED(LOG_SPU_WRITES, "audio_ctrl_w: Channel FIQ Enable: %04x\n", data); + m_audio_ctrl_regs[offset] = data & AUDIO_CHANNEL_FIQ_ENABLE_MASK; + break; + + case AUDIO_CHANNEL_FIQ_STATUS: + LOGMASKED(LOG_SPU_WRITES, "audio_ctrl_w: Channel FIQ Acknowledge: %04x\n", data); + m_audio_ctrl_regs[offset] &= ~(data & AUDIO_CHANNEL_FIQ_STATUS_MASK); + break; + + case AUDIO_BEAT_BASE_COUNT: + LOGMASKED(LOG_SPU_WRITES | LOG_BEAT, "audio_ctrl_w: Beat Base Count: %04x\n", data); + m_audio_ctrl_regs[offset] = data & AUDIO_BEAT_BASE_COUNT_MASK; + m_audio_curr_beat_base_count = m_audio_ctrl_regs[offset]; + break; + + case AUDIO_BEAT_COUNT: + { + LOGMASKED(LOG_SPU_WRITES | LOG_BEAT, "audio_ctrl_w: Beat Count: %04x\n", data); + const uint16_t old = m_audio_ctrl_regs[offset]; + m_audio_ctrl_regs[offset] &= ~(data & AUDIO_BIS_MASK); + m_audio_ctrl_regs[offset] &= AUDIO_BIS_MASK; + m_audio_ctrl_regs[offset] |= data & ~AUDIO_BIS_MASK; + const uint16_t changed = old ^ m_audio_ctrl_regs[offset]; + if (changed & (AUDIO_BIS_MASK | AUDIO_BIE_MASK)) + { + LOGMASKED(LOG_BEAT, "BIS mask changed, updating IRQ\n"); + check_irqs(changed & (AUDIO_BIS_MASK | AUDIO_BIE_MASK)); + } + break; + } + + case AUDIO_ENVCLK0: + case AUDIO_ENVCLK1: + { + LOGMASKED(LOG_SPU_WRITES | LOG_ENVELOPES, "audio_ctrl_w: Envelope Interval %d (lo): %04x\n", offset == AUDIO_ENVCLK0 ? 0 : 1, data); + const uint16_t old = m_audio_ctrl_regs[offset]; + m_audio_ctrl_regs[offset] = data; + const uint16_t changed = old ^ m_audio_ctrl_regs[offset]; + + if (!changed) + break; + + const uint8_t channel_offset = offset == AUDIO_ENVCLK0 ? 0 : 8; + for (uint8_t channel_bit = 0; channel_bit < 4; channel_bit++) + { + const uint8_t shift = channel_bit << 2; + const uint16_t mask = 0x0f << shift; + if (changed & mask) + { + m_envclk_frame[channel_bit + channel_offset] = get_envclk_frame_count(channel_bit + channel_offset); + } + } + break; + } + + case AUDIO_ENVCLK0_HIGH: + case AUDIO_ENVCLK1_HIGH: + { + LOGMASKED(LOG_SPU_WRITES | LOG_ENVELOPES, "audio_ctrl_w: Envelope Interval %d (hi): %04x\n", offset == AUDIO_ENVCLK0_HIGH ? 0 : 1, data); + const uint16_t old = m_audio_ctrl_regs[offset]; + m_audio_ctrl_regs[offset] = data; + const uint16_t changed = old ^ m_audio_ctrl_regs[offset]; + if (!changed) + break; + + const uint8_t channel_offset = offset == AUDIO_ENVCLK0_HIGH ? 0 : 8; + for (uint8_t channel_bit = 0; channel_bit < 4; channel_bit++) + { + const uint8_t shift = channel_bit << 2; + const uint16_t mask = 0x0f << shift; + if (changed & mask) + { + m_envclk_frame[channel_bit + channel_offset + 4] = get_envclk_frame_count(channel_bit + channel_offset); + } + } + break; + } + + case AUDIO_ENV_RAMP_DOWN: + { + LOGMASKED(LOG_SPU_WRITES | LOG_RAMPDOWN, "audio_ctrl_w: Envelope Fast Ramp Down: %04x\n", data); + const uint16_t old = m_audio_ctrl_regs[offset]; + m_audio_ctrl_regs[offset] = (data & AUDIO_ENV_RAMP_DOWN_MASK) & m_audio_ctrl_regs[AUDIO_CHANNEL_STATUS]; + const uint16_t changed = old ^ m_audio_ctrl_regs[offset]; + if (!changed) + break; + + for (uint32_t channel_bit = 0; channel_bit < 16; channel_bit++) + { + const uint16_t mask = 1 << channel_bit; + if ((changed & mask) && (data & mask)) + { + m_rampdown_frame[channel_bit] = get_rampdown_frame_count(channel_bit); + LOGMASKED(LOG_RAMPDOWN, "Preparing to ramp down channel %d in %d ticks\n", channel_bit, m_rampdown_frame[channel_bit] / 13); + } + } + break; + } + + case AUDIO_CHANNEL_STOP: + LOGMASKED(LOG_SPU_WRITES, "audio_ctrl_w: Channel Stop Status: %04x\n", data); + m_audio_ctrl_regs[offset] &= ~data; + break; + + case AUDIO_CHANNEL_ZERO_CROSS: + LOGMASKED(LOG_SPU_WRITES, "audio_ctrl_w: Channel Zero-Cross Enable: %04x\n", data); + m_audio_ctrl_regs[offset] = data & AUDIO_CHANNEL_ZERO_CROSS_MASK; + break; + + case AUDIO_CONTROL: + LOGMASKED(LOG_SPU_WRITES, "audio_ctrl_w: Control: %04x (SOFTCH:%d, COMPEN:%d, NOHIGH:%d, NOINT:%d, EQEN:%d, VOLSEL:%d)\n", data + , (data & AUDIO_CONTROL_SOFTCH_MASK) ? 1 : 0 + , (data & AUDIO_CONTROL_COMPEN_MASK) ? 1 : 0 + , (data & AUDIO_CONTROL_NOHIGH_MASK) ? 1 : 0 + , (data & AUDIO_CONTROL_NOINT_MASK) ? 1 : 0 + , (data & AUDIO_CONTROL_EQEN_MASK) ? 1 : 0 + , (data & AUDIO_CONTROL_VOLSEL_MASK) >> AUDIO_CONTROL_VOLSEL_SHIFT); + m_audio_ctrl_regs[offset] = data & AUDIO_CONTROL_MASK; + break; + + case AUDIO_COMPRESS_CTRL: + LOGMASKED(LOG_SPU_WRITES, "audio_ctrl_w: Compressor Control: %04x\n", data); + m_audio_ctrl_regs[offset] = data; + break; + + case AUDIO_CHANNEL_STATUS: + LOGMASKED(LOG_SPU_WRITES, "audio_ctrl_w: Channel Status (read-only): %04x\n", data); + break; + + case AUDIO_WAVE_IN_L: + LOGMASKED(LOG_SPU_WRITES, "audio_ctrl_w: Wave In (L) / FIFO Write Data: %04x\n", data); + m_audio_ctrl_regs[offset] = data; + break; + + case AUDIO_WAVE_IN_R: + LOGMASKED(LOG_SPU_WRITES, "audio_ctrl_w: Wave In (R) / Software Channel FIFO IRQ Control: %04x\n", data); + m_audio_ctrl_regs[offset] = data; + break; + + case AUDIO_WAVE_OUT_L: + LOGMASKED(LOG_SPU_WRITES, "audio_ctrl_w: Wave Out (L): %04x\n", data); + m_audio_ctrl_regs[offset] = data; + break; + + case AUDIO_WAVE_OUT_R: + LOGMASKED(LOG_SPU_WRITES, "audio_ctrl_w: Wave Out (R): %04x\n", data); + m_audio_ctrl_regs[offset] = data; + break; + + case AUDIO_CHANNEL_REPEAT: + LOGMASKED(LOG_SPU_WRITES, "audio_ctrl_w: Channel Repeat Enable: %04x\n", data); + m_audio_ctrl_regs[offset] = data & AUDIO_CHANNEL_REPEAT_MASK; + break; + + case AUDIO_CHANNEL_ENV_MODE: + LOGMASKED(LOG_SPU_WRITES | LOG_ENVELOPES, "audio_ctrl_w: Channel Envelope Enable: %04x\n", data); + m_audio_ctrl_regs[offset] = data & AUDIO_CHANNEL_ENV_MODE_MASK; + break; + + case AUDIO_CHANNEL_TONE_RELEASE: + LOGMASKED(LOG_SPU_WRITES, "audio_ctrl_w: Channel Tone Release Enable: %04x\n", data); + m_audio_ctrl_regs[offset] = data & AUDIO_CHANNEL_TONE_RELEASE_MASK; + break; + + case AUDIO_CHANNEL_ENV_IRQ: + LOGMASKED(LOG_SPU_WRITES | LOG_ENVELOPES, "audio_ctrl_w: Channel Envelope IRQ Acknowledge: %04x\n", data); + m_audio_ctrl_regs[offset] &= ~data & AUDIO_CHANNEL_ENV_IRQ_MASK; + break; + + case AUDIO_CHANNEL_PITCH_BEND: + LOGMASKED(LOG_SPU_WRITES, "audio_ctrl_w: Channel Pitch Bend Enable: %04x\n", data); + m_audio_ctrl_regs[offset] = data & AUDIO_CHANNEL_PITCH_BEND_MASK; + break; + + case AUDIO_SOFT_PHASE: + LOGMASKED(LOG_SPU_WRITES, "audio_ctrl_w: Software Channel Phase: %04x\n", data); + m_audio_ctrl_regs[offset] = data; + break; + + case AUDIO_ATTACK_RELEASE: + LOGMASKED(LOG_SPU_WRITES, "audio_ctrl_w: Attack/Release Time Control: %04x\n", data); + m_audio_ctrl_regs[offset] = data; + break; + + case AUDIO_EQ_CUTOFF10: + LOGMASKED(LOG_SPU_WRITES, "audio_ctrl_w: EQ Cutoff Frequency 0/1: %04x\n", data); + m_audio_ctrl_regs[offset] = data & AUDIO_EQ_CUTOFF10_MASK; + break; + + case AUDIO_EQ_CUTOFF32: + LOGMASKED(LOG_SPU_WRITES, "audio_ctrl_w: EQ Cutoff Frequency 2/3: %04x\n", data); + m_audio_ctrl_regs[offset] = data & AUDIO_EQ_CUTOFF32_MASK; + break; + + case AUDIO_EQ_GAIN10: + LOGMASKED(LOG_SPU_WRITES, "audio_ctrl_w: EQ Cutoff Gain 0/1: %04x\n", data); + m_audio_ctrl_regs[offset] = data & AUDIO_EQ_GAIN10_MASK; + break; + + case AUDIO_EQ_GAIN32: + LOGMASKED(LOG_SPU_WRITES, "audio_ctrl_w: EQ Cutoff Gain 2/3: %04x\n", data); + m_audio_ctrl_regs[offset] = data & AUDIO_EQ_GAIN32_MASK; + break; + + default: + m_audio_ctrl_regs[offset] = data; + LOGMASKED(LOG_UNKNOWN_SPU, "audio_ctrl_w: Unknown register %04x = %04x\n", 0x3000 + offset, data); + break; + } +} + +WRITE16_MEMBER(spg2xx_audio_device::audio_phase_w) +{ + const uint16_t channel = (offset & 0x00f0) >> 4; + + switch (offset & AUDIO_CHAN_OFFSET_MASK) + { + case AUDIO_PHASE_HIGH: + m_audio_phase_regs[offset] = data & AUDIO_PHASE_HIGH_MASK; + m_channel_rate[channel] = ((double)get_phase(channel) * 140625.0 * 2.0) / (double)(1 << 19); + m_channel_rate_accum[channel] = 0.0; + LOGMASKED(LOG_CHANNEL_WRITES, "audio_phase_w: Channel %d: Phase High: %04x (rate: %f)\n", channel, data, m_channel_rate[channel]); + break; + + case AUDIO_PHASE_ACCUM_HIGH: + m_audio_phase_regs[offset] = data & AUDIO_PHASE_ACCUM_HIGH_MASK; + LOGMASKED(LOG_CHANNEL_WRITES, "audio_phase_w: Channel %d: Phase Accum High: %04x\n", channel, data); + break; + + case AUDIO_TARGET_PHASE_HIGH: + m_audio_phase_regs[offset] = data & AUDIO_TARGET_PHASE_HIGH_MASK; + LOGMASKED(LOG_CHANNEL_WRITES, "audio_phase_w: Channel %d: Target Phase High: %04x\n", channel, data); + break; + + case AUDIO_RAMP_DOWN_CLOCK: + m_audio_phase_regs[offset] = data & AUDIO_RAMP_DOWN_CLOCK_MASK; + LOGMASKED(LOG_CHANNEL_WRITES | LOG_RAMPDOWN, "audio_phase_w: Channel %d: Rampdown Clock: %04x\n", channel, data); + break; + + case AUDIO_PHASE: + m_audio_phase_regs[offset] = data; + m_channel_rate[channel] = ((double)get_phase(channel) * 140625.0 * 2.0) / (double)(1 << 19); + m_channel_rate_accum[channel] = 0.0; + LOGMASKED(LOG_CHANNEL_WRITES, "audio_phase_w: Channel %d: Phase: %04x (rate: %f)\n", channel, data, m_channel_rate[channel]); + break; + + case AUDIO_PHASE_ACCUM: + m_audio_phase_regs[offset] = data; + LOGMASKED(LOG_CHANNEL_WRITES, "audio_phase_w: Channel %d: Phase Accum: %04x\n", channel, data); + break; + + case AUDIO_TARGET_PHASE: + m_audio_phase_regs[offset] = data; + LOGMASKED(LOG_CHANNEL_WRITES, "audio_phase_w: Channel %d: Target Phase: %04x\n", channel, data); + break; + + case AUDIO_PHASE_CTRL: + m_audio_phase_regs[offset] = data; + LOGMASKED(LOG_CHANNEL_WRITES, "audio_phase_w: Channel %d: Phase Ctrl: %04x (TIMESTEP:%d, SIGN:%d, OFFSET:%03x\n", channel, data, + get_phase_time_step(channel), get_phase_sign_bit(channel), get_phase_offset(channel)); + break; + + default: + m_audio_phase_regs[offset] = data; + LOGMASKED(LOG_UNKNOWN_SPU, "audio_phase_w: Unknown register %04x = %04x\n", 0x3000 + offset, data); + break; + } +} + + +WRITE16_MEMBER(spg2xx_audio_device::audio_w) +{ + const uint16_t channel = (offset & 0x00f0) >> 4; + + switch (offset & AUDIO_CHAN_OFFSET_MASK) + { + case AUDIO_WAVE_ADDR: + m_audio_regs[offset] = data; + LOGMASKED(LOG_CHANNEL_WRITES, "audio_w: Channel %d: Wave Addr (lo): %04x\n", channel, data); + break; + + case AUDIO_MODE: + m_audio_regs[offset] = data; + LOGMASKED(LOG_CHANNEL_WRITES, "audio_w: Channel %d: Mode: %04x (ADPCM:%d, 16M:%d, TONE:%d, LADDR_HI:%04x, WADDR_HI:%04x)\n", channel, data, + get_adpcm_bit(channel), get_16bit_bit(channel), get_tone_mode(channel), get_loop_addr_high(channel), get_wave_addr_high(channel)); + break; + + case AUDIO_LOOP_ADDR: + m_audio_regs[offset] = data; + LOGMASKED(LOG_CHANNEL_WRITES, "audio_w: Channel %d: Loop Addr: %04x\n", channel, data); + break; + + case AUDIO_PAN_VOL: + m_audio_regs[offset] = data & AUDIO_PAN_VOL_MASK; + LOGMASKED(LOG_CHANNEL_WRITES, "audio_w: Channel %d: Pan/Vol: %04x (PAN:%02x, VOL:%02x)\n", channel, data, + get_pan(channel), get_volume(channel)); + break; + + case AUDIO_ENVELOPE0: + m_audio_regs[offset] = data; + LOGMASKED(LOG_CHANNEL_WRITES | LOG_ENVELOPES, "audio_w: Channel %d: Envelope0: %04x (RPTPER:%d, TARGET:%02x, SIGN:%d, INC:%02x)\n", channel, data, + get_repeat_period_bit(channel), get_envelope_target(channel), get_envelope_sign_bit(channel), get_envelope_inc(channel)); + break; + + case AUDIO_ENVELOPE_DATA: + m_audio_regs[offset] = data & AUDIO_ENVELOPE_DATA_MASK; + LOGMASKED(LOG_CHANNEL_WRITES | LOG_ENVELOPES, "audio_w: Channel %d: Envelope Data: %04x (CNT:%d, EDD:%02x)\n", channel, data, + get_envelope_count(channel), get_edd(channel)); + break; + + case AUDIO_ENVELOPE1: + m_audio_regs[offset] = data; + LOGMASKED(LOG_CHANNEL_WRITES | LOG_ENVELOPES, "audio_w: Channel %d: Envelope1 Data: %04x (RPTCNT:%02x, RPT:%d, LOAD:%02x)\n", channel, data, + get_envelope_repeat_count(channel), get_envelope_repeat_bit(channel), get_envelope_load(channel)); + break; + + case AUDIO_ENVELOPE_ADDR_HIGH: + m_audio_regs[offset] = data; + LOGMASKED(LOG_CHANNEL_WRITES | LOG_ENVELOPES, "audio_w: Channel %d: Envelope Addr (hi): %04x (IRQADDR:%03x, IRQEN:%d, EADDR_HI:%02x)\n", channel, data, + get_audio_irq_addr(channel), get_audio_irq_enable_bit(channel), get_envelope_addr_high(channel)); + break; + + case AUDIO_ENVELOPE_ADDR: + m_audio_regs[offset] = data; + LOGMASKED(LOG_CHANNEL_WRITES | LOG_ENVELOPES, "audio_w: Channel %d: Envelope Addr (lo): %04x\n", channel, data); + break; + + case AUDIO_WAVE_DATA_PREV: + m_audio_regs[offset] = data; + LOGMASKED(LOG_CHANNEL_WRITES, "audio_w: Channel %d: Wave Data Prev: %04x \n", channel, data); + break; + + case AUDIO_ENVELOPE_LOOP_CTRL: + m_audio_regs[offset] = data; + LOGMASKED(LOG_CHANNEL_WRITES | LOG_ENVELOPES, "audio_w: Channel %d: Envelope Loop Ctrl: %04x (RDOFFS:%02x, EAOFFS:%03x)\n", channel, data, + get_rampdown_offset(channel), get_envelope_eaoffset(channel)); + break; + + case AUDIO_WAVE_DATA: + m_audio_regs[offset] = data; + LOGMASKED(LOG_CHANNEL_WRITES, "audio_w: Channel %d: Wave Data: %04x\n", channel, data); + break; + + case AUDIO_ADPCM_SEL: + m_audio_regs[offset] = data & AUDIO_ADPCM_SEL_MASK; + LOGMASKED(LOG_CHANNEL_WRITES, "audio_w: Channel %d: ADPCM Sel: %04x (ADPCM36:%d, POINTNUM:%02x\n", channel, data, + get_adpcm36_bit(channel), get_point_number(channel)); + break; + + default: + m_audio_regs[offset] = data; + LOGMASKED(LOG_UNKNOWN_SPU, "audio_w: Unknown register %04x = %04x\n", 0x3000 + offset, data); + break; + + } +} + +void spg2xx_audio_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + stream_sample_t *out_l = outputs[0]; + stream_sample_t *out_r = outputs[1]; + + for (int i = 0; i < samples; i++) + { + int32_t left_total = 0; + int32_t right_total = 0; + + for (uint32_t channel = 0; channel < 16; channel++) + { + if (!get_channel_status(channel)) + { + continue; + } + + if (SPG_DEBUG_AUDIO && m_debug_rates) + printf("%f:%f ", m_channel_rate[channel], m_channel_rate_accum[channel]); + bool playing = advance_channel(channel); + if (playing) + { + int32_t sample = (int16_t)(m_audio_regs[(channel << 4) | AUDIO_WAVE_DATA] ^ 0x8000); + if (!(m_audio_ctrl_regs[AUDIO_CONTROL] & AUDIO_CONTROL_NOINT_MASK)) + { + int32_t prev_sample = (int16_t)(m_audio_regs[(channel << 4) | AUDIO_WAVE_DATA_PREV] ^ 0x8000); + int16_t lerp_factor = (int16_t)((m_channel_rate_accum[channel] / 70312.5) * 256.0); + prev_sample = (prev_sample * (0x100 - lerp_factor)) >> 8; + sample = (sample * lerp_factor) >> 8; + sample += prev_sample; + } + + sample = (sample * (int32_t)get_edd(channel)) >> 7; + + int32_t vol = get_volume(channel); + int32_t pan = get_pan(channel); + + int32_t pan_left, pan_right; + if (pan < 0x40) + { + pan_left = 0x7f * vol; + pan_right = pan * 2 * vol; + } + else + { + pan_left = (0x7f - pan) * 2 * vol; + pan_right = 0x7f * vol; + } + + left_total += ((int16_t)sample * (int16_t)pan_left) >> 14; + right_total += ((int16_t)sample * (int16_t)pan_right) >> 14; + + const uint16_t mask = (1 << channel); + if (m_audio_ctrl_regs[AUDIO_ENV_RAMP_DOWN] & mask) + { + if (m_rampdown_frame[channel] == 0) + { + LOGMASKED(LOG_RAMPDOWN, "Ticking rampdown for channel %d\n", channel); + audio_rampdown_tick(channel); + } + m_rampdown_frame[channel]--; + } + else if (!(m_audio_ctrl_regs[AUDIO_CHANNEL_ENV_MODE] & mask)) + { + if (m_envclk_frame[channel] == 0) + { + LOGMASKED(LOG_ENVELOPES, "Ticking envelope for channel %d\n", channel); + audio_envelope_tick(channel); + m_envclk_frame[channel] = get_envclk_frame_count(channel); + } + m_envclk_frame[channel]--; + } + } + } + + switch (get_vol_sel()) + { + case 0: // 1/16 + left_total >>= 4; + right_total >>= 4; + break; + case 1: // 1/4 + case 2: // 1 + case 3: // 2 // Both x1 and x2 clip like mad even with only 6 voices. Hack it for now. + left_total >>= 2; + right_total >>= 2; + break; + } + *out_l++ = (left_total * (int16_t)m_audio_ctrl_regs[AUDIO_MAIN_VOLUME]) >> 7; + *out_r++ = (right_total * (int16_t)m_audio_ctrl_regs[AUDIO_MAIN_VOLUME]) >> 7; + } +} + +inline void spg2xx_audio_device::stop_channel(const uint32_t channel) +{ + // TODO: IRQs + m_audio_ctrl_regs[AUDIO_CHANNEL_ENABLE] &= ~(1 << channel); + m_audio_ctrl_regs[AUDIO_CHANNEL_STATUS] &= ~(1 << channel); + m_audio_regs[(channel << 4) | AUDIO_MODE] &= ~AUDIO_ADPCM_MASK; + m_audio_ctrl_regs[AUDIO_CHANNEL_TONE_RELEASE] &= ~(1 << channel); + m_audio_ctrl_regs[AUDIO_ENV_RAMP_DOWN] &= ~(1 << channel); +} + +bool spg2xx_audio_device::advance_channel(const uint32_t channel) +{ + m_channel_rate_accum[channel] += m_channel_rate[channel]; + uint32_t samples_to_advance = 0; + while (m_channel_rate_accum[channel] >= 70312.5) + { + m_channel_rate_accum[channel] -= 70312.5; + samples_to_advance++; + } + + if (!samples_to_advance) + return true; + + bool playing = true; + + if (get_adpcm_bit(channel)) + { + // ADPCM mode + for (uint32_t sample = 0; sample < samples_to_advance && playing; sample++) + { + playing = fetch_sample(channel); + if (playing) + { + m_sample_shift[channel] += 4; + if (m_sample_shift[channel] == 16) + { + m_sample_shift[channel] = 0; + m_sample_addr[channel]++; + } + } + } + } + else if (get_16bit_bit(channel)) + { + // 16-bit mode + for (uint32_t sample = 0; sample < samples_to_advance && playing; sample++) + { + playing = fetch_sample(channel); + if (playing) + m_sample_addr[channel]++; + } + } + else + { + // 8-bit mode + for (uint32_t sample = 0; sample < samples_to_advance && playing; sample++) + { + playing = fetch_sample(channel); + if (playing) + { + m_sample_shift[channel] += 8; + if (m_sample_shift[channel] == 16) + { + m_sample_shift[channel] = 0; + m_sample_addr[channel]++; + } + } + } + } + + return playing; +} + +uint16_t spg2xx_audio_device::read_space(offs_t offset) +{ + return m_space_read_cb(offset); +} + +bool spg2xx_audio_device::fetch_sample(const uint32_t channel) +{ + const uint32_t channel_mask = channel << 4; + m_audio_regs[channel_mask | AUDIO_WAVE_DATA_PREV] = m_audio_regs[channel_mask | AUDIO_WAVE_DATA]; + + const uint32_t wave_data_reg = channel_mask | AUDIO_WAVE_DATA; + const uint16_t tone_mode = get_tone_mode(channel); + uint16_t raw_sample = tone_mode ? read_space(m_sample_addr[channel]) : m_audio_regs[wave_data_reg]; + + LOGMASKED(LOG_SAMPLES, "Channel %d: Raw sample %04x\n", channel, raw_sample); + + if (get_adpcm_bit(channel)) + { + // ADPCM mode + if (tone_mode != 0 && raw_sample == 0xffff) + { + if (tone_mode == AUDIO_TONE_MODE_HW_ONESHOT) + { + LOGMASKED(LOG_SAMPLES, "ADPCM stopped after %d samples\n", m_sample_count[channel]); + m_sample_count[channel] = 0; + stop_channel(channel); + return false; + } + else + { + LOGMASKED(LOG_SAMPLES, "ADPCM looping after %d samples\n", m_sample_count[channel]); + m_sample_count[channel] = 0; + loop_channel(channel); + m_audio_regs[(channel << 4) | AUDIO_MODE] &= ~AUDIO_ADPCM_MASK; + } + } + else + { + m_audio_regs[wave_data_reg] = raw_sample; + m_audio_regs[wave_data_reg] >>= m_sample_shift[channel]; + const uint8_t adpcm_sample = (uint8_t)(m_audio_regs[wave_data_reg] & 0x000f); + m_audio_regs[wave_data_reg] = (uint16_t)(m_adpcm[channel].clock(adpcm_sample) << 4) ^ 0x8000; + } + m_sample_count[channel]++; + } + else if (get_16bit_bit(channel)) + { + // 16-bit mode + if (tone_mode != 0 && raw_sample == 0xffff) + { + if (tone_mode == AUDIO_TONE_MODE_HW_ONESHOT) + { + LOGMASKED(LOG_SAMPLES, "16-bit PCM stopped after %d samples\n", m_sample_count[channel]); + m_sample_count[channel] = 0; + stop_channel(channel); + return false; + } + else + { + LOGMASKED(LOG_SAMPLES, "16-bit PCM looping after %d samples\n", m_sample_count[channel]); + m_sample_count[channel] = 0; + loop_channel(channel); + } + } + else + { + m_audio_regs[wave_data_reg] = raw_sample; + } + m_sample_count[channel]++; + } + else + { + // 8-bit mode + if (tone_mode != 0) + { + if (m_sample_shift[channel]) + raw_sample &= 0xff00; + else + raw_sample <<= 8; + raw_sample |= raw_sample >> 8; + + if (raw_sample == 0xffff) + { + if (tone_mode == AUDIO_TONE_MODE_HW_ONESHOT) + { + LOGMASKED(LOG_SAMPLES, "Channel %d: 8-bit PCM stopped after %d samples\n", channel, m_sample_count[channel]); + m_sample_count[channel] = 0; + stop_channel(channel); + return false; + } + else + { + LOGMASKED(LOG_SAMPLES, "Channel %d: 8-bit PCM looping after %d samples\n", channel, m_sample_count[channel]); + m_sample_count[channel] = 0; + loop_channel(channel); + } + } + else + { + m_audio_regs[wave_data_reg] = raw_sample; + } + } + m_sample_count[channel]++; + } + + return true; +} + +inline void spg2xx_audio_device::loop_channel(const uint32_t channel) +{ + m_sample_addr[channel] = get_loop_addr(channel); + m_sample_shift[channel] = 0; + LOGMASKED(LOG_SAMPLES, "Channel %d: Looping to address %08x\n", channel, m_sample_addr[channel]); +} + +void spg2xx_audio_device::audio_beat_tick() +{ + if (m_audio_curr_beat_base_count == 0) + { + LOGMASKED(LOG_BEAT, "Beat base count elapsed, reloading with %d\n", m_audio_ctrl_regs[AUDIO_BEAT_BASE_COUNT]); + m_audio_curr_beat_base_count = m_audio_ctrl_regs[AUDIO_BEAT_BASE_COUNT]; + + uint16_t beat_count = m_audio_ctrl_regs[AUDIO_BEAT_COUNT] & AUDIO_BEAT_COUNT_MASK; + if (beat_count == 0) + { + if (m_audio_ctrl_regs[AUDIO_BEAT_COUNT] & AUDIO_BIE_MASK) + { + LOGMASKED(LOG_BEAT, "Beat count elapsed, setting Status bit and checking IRQs\n"); + m_audio_ctrl_regs[AUDIO_BEAT_COUNT] |= AUDIO_BIS_MASK; + check_irqs(AUDIO_BIS_MASK); + } + else + { + LOGMASKED(LOG_BEAT, "Beat count elapsed but IRQ not enabled\n"); + } + } + else + { + beat_count--; + m_audio_ctrl_regs[AUDIO_BEAT_COUNT] = (m_audio_ctrl_regs[AUDIO_BEAT_COUNT] & ~AUDIO_BEAT_COUNT_MASK) | beat_count; + } + } + m_audio_curr_beat_base_count--; +} + +void spg2xx_audio_device::audio_rampdown_tick(const uint32_t channel) +{ + const uint8_t old_edd = get_edd(channel); + uint8_t new_edd = old_edd - get_rampdown_offset(channel); + if (new_edd > old_edd) + new_edd = 0; + + if (new_edd) + { + LOGMASKED(LOG_RAMPDOWN, "Channel %d preparing for next rampdown step (%02x)\n", channel, new_edd); + const uint16_t channel_mask = channel << 4; + m_audio_regs[channel_mask | AUDIO_ENVELOPE_DATA] &= ~AUDIO_EDD_MASK; + m_audio_regs[channel_mask | AUDIO_ENVELOPE_DATA] |= new_edd & AUDIO_EDD_MASK; + m_rampdown_frame[channel] = get_rampdown_frame_count(channel); + } + else + { + LOGMASKED(LOG_RAMPDOWN, "Stopping channel %d due to rampdown\n", channel); + const uint16_t channel_mask = 1 << channel; + m_audio_ctrl_regs[AUDIO_CHANNEL_ENABLE] &= ~channel_mask; + m_audio_ctrl_regs[AUDIO_CHANNEL_STATUS] &= ~channel_mask; + m_audio_ctrl_regs[AUDIO_CHANNEL_STOP] |= channel_mask; + m_audio_ctrl_regs[AUDIO_ENV_RAMP_DOWN] &= ~channel_mask; + m_audio_ctrl_regs[AUDIO_CHANNEL_TONE_RELEASE] &= ~channel_mask; + } +} + +const uint32_t spg2xx_audio_device::s_rampdown_frame_counts[8] = +{ + 13*4, 13*16, 13*64, 13*256, 13*1024, 13*4096, 13*8192, 13*8192 +}; + +uint32_t spg2xx_audio_device::get_rampdown_frame_count(const uint32_t channel) +{ + return s_rampdown_frame_counts[get_rampdown_clock(channel)]; +} + +const uint32_t spg2xx_audio_device::s_envclk_frame_counts[16] = +{ + 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 8192, 8192, 8192, 8192 +}; + +uint32_t spg2xx_audio_device::get_envclk_frame_count(const uint32_t channel) +{ + return s_envclk_frame_counts[get_envelope_clock(channel)]; +} + +uint32_t spg2xx_audio_device::get_envelope_clock(const offs_t channel) const +{ + if (channel < 4) + return (m_audio_ctrl_regs[AUDIO_ENVCLK0] >> (channel << 2)) & 0x000f; + else if (channel < 8) + return (m_audio_ctrl_regs[AUDIO_ENVCLK0_HIGH] >> ((channel - 4) << 2)) & 0x000f; + else if (channel < 12) + return (m_audio_ctrl_regs[AUDIO_ENVCLK1] >> ((channel - 8) << 2)) & 0x000f; + else + return (m_audio_ctrl_regs[AUDIO_ENVCLK1_HIGH] >> ((channel - 12) << 2)) & 0x000f; +} + +bool spg2xx_audio_device::audio_envelope_tick(const uint32_t channel) +{ + const uint16_t channel_mask = channel << 4; + uint16_t new_count = get_envelope_count(channel); + const uint16_t curr_edd = get_edd(channel); + LOGMASKED(LOG_ENVELOPES, "envelope %d tick, count is %04x, curr edd is %04x\n", channel, new_count, curr_edd); + bool edd_changed = false; + if (new_count == 0) + { + const uint16_t target = get_envelope_target(channel); + uint16_t new_edd = curr_edd; + const uint16_t inc = get_envelope_inc(channel); + + if (new_edd != target) + { + if (get_envelope_sign_bit(channel)) + { + new_edd -= inc; + LOGMASKED(LOG_ENVELOPES, "Envelope %d new EDD-: %04x (%04x), dec %04x\n", channel, new_edd, target, inc); + if (new_edd > curr_edd) + new_edd = 0; + else if (new_edd < target) + new_edd = target; + + if (new_edd == 0) + { + LOGMASKED(LOG_ENVELOPES, "Envelope %d at 0, stopping channel\n", channel); + stop_channel(channel); + return true; + } + } + else + { + new_edd += inc; + LOGMASKED(LOG_ENVELOPES, "Envelope %d new EDD+: %04x (%04x), inc %04x\n", channel, new_edd, target, inc); + if (new_edd >= target) + new_edd = target; + } + } + + if (new_edd == target) + { + LOGMASKED(LOG_ENVELOPES, "Envelope %d at target %04x\n", channel, target); + new_edd = target; + + if (get_envelope_repeat_bit(channel)) + { + const uint16_t repeat_count = get_envelope_repeat_count(channel) - 1; + LOGMASKED(LOG_ENVELOPES, "Repeating envelope, new repeat count %d\n", repeat_count); + if (repeat_count == 0) + { + m_audio_regs[channel_mask | AUDIO_ENVELOPE0] = read_space(m_envelope_addr[channel]); + m_audio_regs[channel_mask | AUDIO_ENVELOPE1] = read_space(m_envelope_addr[channel] + 1); + m_audio_regs[channel_mask | AUDIO_ENVELOPE_LOOP_CTRL] = read_space(m_envelope_addr[channel] + 2); + m_envelope_addr[channel] = get_envelope_addr(channel) + get_envelope_eaoffset(channel); + LOGMASKED(LOG_ENVELOPES, "Envelope data after repeat: %04x %04x %04x (%08x)\n", m_audio_regs[channel_mask | AUDIO_ENVELOPE0], m_audio_regs[channel_mask | AUDIO_ENVELOPE1], m_audio_regs[channel_mask | AUDIO_ENVELOPE_LOOP_CTRL], m_envelope_addr[channel]); + } + else + { + set_envelope_repeat_count(channel, repeat_count); + } + } + else + { + LOGMASKED(LOG_ENVELOPES, "Fetching envelope for channel %d from %08x\n", channel, m_envelope_addr[channel]); + m_audio_regs[channel_mask | AUDIO_ENVELOPE0] = read_space(m_envelope_addr[channel]); + m_audio_regs[channel_mask | AUDIO_ENVELOPE1] = read_space(m_envelope_addr[channel] + 1); + LOGMASKED(LOG_ENVELOPES, "Fetched envelopes %04x %04x\n", m_audio_regs[channel_mask | AUDIO_ENVELOPE0], m_audio_regs[channel_mask | AUDIO_ENVELOPE1]); + m_envelope_addr[channel] += 2; + } + new_count = get_envelope_load(channel); + set_envelope_count(channel, new_count); + } + else + { + LOGMASKED(LOG_ENVELOPES, "Envelope %d not yet at target %04x (%04x)\n", channel, target, new_edd); + new_count = get_envelope_load(channel); + set_envelope_count(channel, new_count); + } + LOGMASKED(LOG_ENVELOPES, "Envelope %d new count %04x\n", channel, new_count); + + set_edd(channel, new_edd); + edd_changed = true; + LOGMASKED(LOG_ENVELOPES, "Setting channel %d edd to %04x, register is %04x\n", channel, new_edd, m_audio_regs[(channel << 4) | AUDIO_ENVELOPE_DATA]); + } + else + { + new_count--; + set_envelope_count(channel, new_count); + } + LOGMASKED(LOG_ENVELOPES, "envelope %d post-tick, count is now %04x, register is %04x\n", channel, new_count, m_audio_regs[(channel << 4) | AUDIO_ENVELOPE_DATA]); + return edd_changed; +} diff --git a/src/devices/machine/spg2xx_audio.h b/src/devices/machine/spg2xx_audio.h new file mode 100644 index 00000000000..2ea8b26651a --- /dev/null +++ b/src/devices/machine/spg2xx_audio.h @@ -0,0 +1,372 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +/***************************************************************************** + + SunPlus SPG2xx-series SoC peripheral emulation (Audio) + +**********************************************************************/ + +#ifndef MAME_MACHINE_SPG2XX_AUDIO_H +#define MAME_MACHINE_SPG2XX_AUDIO_H + +#pragma once + +#include "sound/okiadpcm.h" +#include "cpu/unsp/unsp.h" + +class spg2xx_audio_device : public device_t, public device_sound_interface +{ +public: + spg2xx_audio_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + spg2xx_audio_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + auto space_read_callback() { return m_space_read_cb.bind(); } + auto write_irq_callback() { return m_irq_cb.bind(); } + + DECLARE_READ16_MEMBER(audio_r); + DECLARE_WRITE16_MEMBER(audio_w); + DECLARE_READ16_MEMBER(audio_ctrl_r); + DECLARE_WRITE16_MEMBER(audio_ctrl_w); + DECLARE_READ16_MEMBER(audio_phase_r); + DECLARE_WRITE16_MEMBER(audio_phase_w); + +protected: + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) override; + + void audio_beat_tick(); + void audio_rampdown_tick(const uint32_t channel); + bool audio_envelope_tick(const uint32_t channel); + inline uint32_t get_rampdown_frame_count(const uint32_t channel); + inline uint32_t get_envclk_frame_count(const uint32_t channel); + + // Audio getters + bool get_channel_enable(const offs_t channel) const { return m_audio_ctrl_regs[AUDIO_CHANNEL_ENABLE] & (1 << channel); } + bool get_channel_status(const offs_t channel) const { return m_audio_ctrl_regs[AUDIO_CHANNEL_STATUS] & (1 << channel); } + bool get_manual_envelope_enable(const offs_t channel) const { return m_audio_ctrl_regs[AUDIO_CHANNEL_ENV_MODE] & (1 << channel); } + bool get_auto_envelope_enable(const offs_t channel) const { return !get_manual_envelope_enable(channel); } + uint32_t get_envelope_clock(const offs_t channel) const; + uint16_t get_vol_sel() const { return (m_audio_ctrl_regs[AUDIO_CONTROL] & AUDIO_CONTROL_VOLSEL_MASK) >> AUDIO_CONTROL_VOLSEL_SHIFT; } + + // Audio Mode getters + uint16_t get_wave_addr_high(const offs_t channel) const { return m_audio_regs[(channel << 4) | AUDIO_MODE] & AUDIO_WADDR_HIGH_MASK; } + uint16_t get_loop_addr_high(const offs_t channel) const { return (m_audio_regs[(channel << 4) | AUDIO_MODE] & AUDIO_LADDR_HIGH_MASK) >> AUDIO_LADDR_HIGH_SHIFT; } + uint16_t get_tone_mode(const offs_t channel) const { return (m_audio_regs[(channel << 4) | AUDIO_MODE] & AUDIO_TONE_MODE_MASK) >> AUDIO_TONE_MODE_SHIFT; } + uint16_t get_16bit_bit(const offs_t channel) const { return (m_audio_regs[(channel << 4) | AUDIO_MODE] & AUDIO_16M_MASK) ? 1 : 0; } + uint16_t get_adpcm_bit(const offs_t channel) const { return (m_audio_regs[(channel << 4) | AUDIO_MODE] & AUDIO_ADPCM_MASK) ? 1 : 0; } + + // Audio Pan getters + uint16_t get_volume(const offs_t channel) const { return m_audio_regs[(channel << 4) | AUDIO_PAN_VOL] & AUDIO_VOLUME_MASK; } + uint16_t get_pan(const offs_t channel) const { return (m_audio_regs[(channel << 4) | AUDIO_PAN_VOL] & AUDIO_PAN_MASK) >> AUDIO_PAN_SHIFT; } + + // Audio Envelope0 Data getters + uint16_t get_envelope_inc(const offs_t channel) const { return m_audio_regs[(channel << 4) | AUDIO_ENVELOPE0] & AUDIO_ENVELOPE_INC_MASK; } + uint16_t get_envelope_sign_bit(const offs_t channel) const { return (m_audio_regs[(channel << 4) | AUDIO_ENVELOPE0] & AUDIO_ENVELOPE_SIGN_MASK) ? 1 : 0; } + uint16_t get_envelope_target(const offs_t channel) const { return (m_audio_regs[(channel << 4) | AUDIO_ENVELOPE0] & AUDIO_ENVELOPE_TARGET_MASK) >> AUDIO_ENVELOPE_TARGET_SHIFT; } + uint16_t get_repeat_period_bit(const offs_t channel) const { return (m_audio_regs[(channel << 4) | AUDIO_ENVELOPE0] & AUDIO_ENVELOPE_REPEAT_PERIOD_MASK) ? 1 : 0; } + + // Audio Envelope Data getters + uint16_t get_edd(const offs_t channel) const { return m_audio_regs[(channel << 4) | AUDIO_ENVELOPE_DATA] & AUDIO_EDD_MASK; } + uint16_t get_envelope_count(const offs_t channel) const { return (m_audio_regs[(channel << 4) | AUDIO_ENVELOPE_DATA] & AUDIO_ENVELOPE_COUNT_MASK) >> AUDIO_ENVELOPE_COUNT_SHIFT; } + void set_edd(const offs_t channel, uint8_t edd) { m_audio_regs[(channel << 4) | AUDIO_ENVELOPE_DATA] = (m_audio_regs[(channel << 4) | AUDIO_ENVELOPE_DATA] & ~AUDIO_EDD_MASK) | edd; } + void set_envelope_count(const offs_t channel, uint16_t count) { m_audio_regs[(channel << 4) | AUDIO_ENVELOPE_DATA] = get_edd(channel) | (count << AUDIO_ENVELOPE_COUNT_SHIFT); } + + // Audio Envelope1 Data getters + uint16_t get_envelope_load(const offs_t channel) const { return m_audio_regs[(channel << 4) | AUDIO_ENVELOPE1] & AUDIO_ENVELOPE_LOAD_MASK; } + uint16_t get_envelope_repeat_bit(const offs_t channel) const { return (m_audio_regs[(channel << 4) | AUDIO_ENVELOPE1] & AUDIO_ENVELOPE_RPT_MASK) ? 1 : 0; } + uint16_t get_envelope_repeat_count(const offs_t channel) const { return (m_audio_regs[(channel << 4) | AUDIO_ENVELOPE1] & AUDIO_ENVELOPE_RPCNT_MASK) >> AUDIO_ENVELOPE_RPCNT_SHIFT; } + inline void set_envelope_repeat_count(const offs_t channel, const uint16_t count) { m_audio_regs[(channel << 4) | AUDIO_ENVELOPE1] = (m_audio_regs[(channel << 4) | AUDIO_ENVELOPE1] & ~AUDIO_ENVELOPE_RPCNT_MASK) | ((count << AUDIO_ENVELOPE_RPCNT_SHIFT) & AUDIO_ENVELOPE_RPCNT_MASK); } + + // Audio Envelope Address getters + uint16_t get_envelope_addr_high(const offs_t channel) const { return m_audio_regs[(channel << 4) | AUDIO_ENVELOPE_ADDR_HIGH] & AUDIO_EADDR_HIGH_MASK; } + uint16_t get_audio_irq_enable_bit(const offs_t channel) const { return (m_audio_regs[(channel << 4) | AUDIO_ENVELOPE_ADDR_HIGH] & AUDIO_IRQ_EN_MASK) ? 1 : 0; } + uint16_t get_audio_irq_addr(const offs_t channel) const { return (m_audio_regs[(channel << 4) | AUDIO_ENVELOPE_ADDR_HIGH] & AUDIO_IRQ_ADDR_MASK) >> AUDIO_IRQ_ADDR_SHIFT; } + + // Audio Envelope Loop getters + uint16_t get_envelope_eaoffset(const offs_t channel) const { return m_audio_regs[(channel << 4) | AUDIO_ENVELOPE_LOOP_CTRL] & AUDIO_EAOFFSET_MASK; } + uint16_t get_rampdown_offset(const offs_t channel) const { return (m_audio_regs[(channel << 4) | AUDIO_ENVELOPE_LOOP_CTRL] & AUDIO_RAMPDOWN_OFFSET_MASK) >> AUDIO_RAMPDOWN_OFFSET_SHIFT; } + void set_envelope_eaoffset(const offs_t channel, uint16_t eaoffset) { m_audio_regs[(channel << 4) | AUDIO_ENVELOPE_LOOP_CTRL] = (m_audio_regs[(channel << 4) | AUDIO_ENVELOPE_LOOP_CTRL] & ~AUDIO_RAMPDOWN_OFFSET_MASK) | (eaoffset & AUDIO_EAOFFSET_MASK); } + + // Audio ADPCM getters + uint16_t get_point_number(const offs_t channel) const { return (m_audio_regs[(channel << 4) | AUDIO_ADPCM_SEL] & AUDIO_POINT_NUMBER_MASK) >> AUDIO_POINT_NUMBER_SHIFT; } + uint16_t get_adpcm36_bit(const offs_t channel) const { return (m_audio_regs[(channel << 4) | AUDIO_ADPCM_SEL] & AUDIO_ADPCM36_MASK) ? 1 : 0; } + + // Audio high-word getters + uint16_t get_phase_high(const offs_t channel) const { return m_audio_phase_regs[(channel << 4) | AUDIO_PHASE_HIGH] & AUDIO_PHASE_HIGH_MASK; } + uint16_t get_phase_accum_high(const offs_t channel) const { return m_audio_phase_regs[(channel << 4) | AUDIO_PHASE_ACCUM_HIGH] & AUDIO_PHASE_ACCUM_HIGH_MASK; } + uint16_t get_target_phase_high(const offs_t channel) const { return m_audio_phase_regs[(channel << 4) | AUDIO_TARGET_PHASE_HIGH] & AUDIO_TARGET_PHASE_HIGH_MASK; } + uint16_t get_rampdown_clock(const offs_t channel) const { return m_audio_phase_regs[(channel << 4) | AUDIO_RAMP_DOWN_CLOCK] & AUDIO_RAMP_DOWN_CLOCK_MASK; } + + // Audio ADPCM getters + uint16_t get_phase_offset(const offs_t channel) const { return m_audio_phase_regs[(channel << 4) | AUDIO_PHASE_CTRL] & AUDIO_PHASE_OFFSET_MASK; } + uint16_t get_phase_sign_bit(const offs_t channel) const { return (m_audio_phase_regs[(channel << 4) | AUDIO_PHASE_CTRL] & AUDIO_PHASE_SIGN_MASK) >> AUDIO_PHASE_SIGN_SHIFT; } + uint16_t get_phase_time_step(const offs_t channel) const { return (m_audio_phase_regs[(channel << 4) | AUDIO_PHASE_CTRL] & AUDIO_PHASE_TIME_STEP_MASK) >> AUDIO_PHASE_TIME_STEP_SHIFT; } + + // Audio combined getters + uint32_t get_phase(const offs_t channel) const { return ((uint32_t)get_phase_high(channel) << 16) | m_audio_phase_regs[(channel << 4) | AUDIO_PHASE]; } + uint32_t get_phase_accum(const offs_t channel) const { return ((uint32_t)get_phase_accum_high(channel) << 16) | m_audio_phase_regs[(channel << 4) | AUDIO_PHASE_ACCUM]; } + uint32_t get_target_phase(const offs_t channel) const { return ((uint32_t)get_target_phase_high(channel) << 16) | m_audio_phase_regs[(channel << 4) | AUDIO_TARGET_PHASE]; } + + uint32_t get_wave_addr(const offs_t channel) const { return ((uint32_t)get_wave_addr_high(channel) << 16) | m_audio_regs[(channel << 4) | AUDIO_WAVE_ADDR]; } + uint32_t get_loop_addr(const offs_t channel) const { return ((uint32_t)get_loop_addr_high(channel) << 16) | m_audio_regs[(channel << 4) | AUDIO_LOOP_ADDR]; } + uint32_t get_envelope_addr(const offs_t channel) const { return ((uint32_t)get_envelope_addr_high(channel) << 16) | m_audio_regs[(channel << 4) | AUDIO_ENVELOPE_ADDR]; } + + enum // at audio write offset 0x000 in spg2xx + { + AUDIO_WAVE_ADDR = 0x000, + + AUDIO_MODE = 0x001, + AUDIO_WADDR_HIGH_MASK = 0x003f, + AUDIO_LADDR_HIGH_MASK = 0x0fc0, + AUDIO_LADDR_HIGH_SHIFT = 6, + AUDIO_TONE_MODE_MASK = 0x3000, + AUDIO_TONE_MODE_SHIFT = 12, + AUDIO_TONE_MODE_SW = 0, + AUDIO_TONE_MODE_HW_ONESHOT = 1, + AUDIO_TONE_MODE_HW_LOOP = 2, + AUDIO_16M_MASK = 0x4000, + AUDIO_ADPCM_MASK = 0x8000, + + AUDIO_LOOP_ADDR = 0x002, + + AUDIO_PAN_VOL = 0x003, + AUDIO_PAN_VOL_MASK = 0x7f7f, + AUDIO_VOLUME_MASK = 0x007f, + AUDIO_PAN_MASK = 0x7f00, + AUDIO_PAN_SHIFT = 8, + + AUDIO_ENVELOPE0 = 0x004, + AUDIO_ENVELOPE_INC_MASK = 0x007f, + AUDIO_ENVELOPE_SIGN_MASK = 0x0080, + AUDIO_ENVELOPE_TARGET_MASK = 0x7f00, + AUDIO_ENVELOPE_TARGET_SHIFT = 8, + AUDIO_ENVELOPE_REPEAT_PERIOD_MASK = 0x8000, + + AUDIO_ENVELOPE_DATA = 0x005, + AUDIO_ENVELOPE_DATA_MASK = 0xff7f, + AUDIO_EDD_MASK = 0x007f, + AUDIO_ENVELOPE_COUNT_MASK = 0xff00, + AUDIO_ENVELOPE_COUNT_SHIFT = 8, + + AUDIO_ENVELOPE1 = 0x006, + AUDIO_ENVELOPE_LOAD_MASK = 0x00ff, + AUDIO_ENVELOPE_RPT_MASK = 0x0100, + AUDIO_ENVELOPE_RPCNT_MASK = 0xfe00, + AUDIO_ENVELOPE_RPCNT_SHIFT = 9, + + AUDIO_ENVELOPE_ADDR_HIGH = 0x007, + AUDIO_EADDR_HIGH_MASK = 0x003f, + AUDIO_IRQ_EN_MASK = 0x0040, + AUDIO_IRQ_ADDR_MASK = 0xff80, + AUDIO_IRQ_ADDR_SHIFT = 7, + + AUDIO_ENVELOPE_ADDR = 0x008, + AUDIO_WAVE_DATA_PREV = 0x009, + + AUDIO_ENVELOPE_LOOP_CTRL = 0x00a, + AUDIO_EAOFFSET_MASK = 0x01ff, + AUDIO_RAMPDOWN_OFFSET_MASK = 0xfe00, + AUDIO_RAMPDOWN_OFFSET_SHIFT = 9, + + AUDIO_WAVE_DATA = 0x00b, + + AUDIO_ADPCM_SEL = 0x00d, + AUDIO_ADPCM_SEL_MASK = 0xfe00, + AUDIO_POINT_NUMBER_MASK = 0x7e00, + AUDIO_POINT_NUMBER_SHIFT = 9, + AUDIO_ADPCM36_MASK = 0x8000, + }; + + enum // at audio write offset 0x200 in spg2xx + { + AUDIO_PHASE_HIGH = 0x000, + AUDIO_PHASE_HIGH_MASK = 0x0007, + + AUDIO_PHASE_ACCUM_HIGH = 0x001, + AUDIO_PHASE_ACCUM_HIGH_MASK = 0x0007, + + AUDIO_TARGET_PHASE_HIGH = 0x002, + AUDIO_TARGET_PHASE_HIGH_MASK= 0x0007, + + AUDIO_RAMP_DOWN_CLOCK = 0x003, + AUDIO_RAMP_DOWN_CLOCK_MASK = 0x0007, + + AUDIO_PHASE = 0x004, + AUDIO_PHASE_ACCUM = 0x005, + AUDIO_TARGET_PHASE = 0x006, + + AUDIO_PHASE_CTRL = 0x007, + AUDIO_PHASE_OFFSET_MASK = 0x0fff, + AUDIO_PHASE_SIGN_MASK = 0x1000, + AUDIO_PHASE_SIGN_SHIFT = 12, + AUDIO_PHASE_TIME_STEP_MASK = 0xe000, + AUDIO_PHASE_TIME_STEP_SHIFT = 13, + + AUDIO_CHAN_OFFSET_MASK = 0xf0f, + }; + + enum // at audio write offset 0x400 in spg2xx + { + + AUDIO_CHANNEL_ENABLE = 0x000, + AUDIO_CHANNEL_ENABLE_MASK = 0xffff, + + AUDIO_MAIN_VOLUME = 0x001, + AUDIO_MAIN_VOLUME_MASK = 0x007f, + + AUDIO_CHANNEL_FIQ_ENABLE = 0x002, + AUDIO_CHANNEL_FIQ_ENABLE_MASK = 0xffff, + + AUDIO_CHANNEL_FIQ_STATUS = 0x003, + AUDIO_CHANNEL_FIQ_STATUS_MASK = 0xffff, + + AUDIO_BEAT_BASE_COUNT = 0x004, + AUDIO_BEAT_BASE_COUNT_MASK = 0x07ff, + + AUDIO_BEAT_COUNT = 0x005, + AUDIO_BEAT_COUNT_MASK = 0x3fff, + AUDIO_BIS_MASK = 0x4000, + AUDIO_BIE_MASK = 0x8000, + + AUDIO_ENVCLK0 = 0x006, + + AUDIO_ENVCLK0_HIGH = 0x007, + AUDIO_ENVCLK0_HIGH_MASK = 0xffff, + + AUDIO_ENVCLK1 = 0x008, + + AUDIO_ENVCLK1_HIGH = 0x009, + AUDIO_ENVCLK1_HIGH_MASK = 0xffff, + + AUDIO_ENV_RAMP_DOWN = 0x00a, + AUDIO_ENV_RAMP_DOWN_MASK = 0xffff, + + AUDIO_CHANNEL_STOP = 0x00b, + AUDIO_CHANNEL_STOP_MASK = 0xffff, + + AUDIO_CHANNEL_ZERO_CROSS = 0x00c, + AUDIO_CHANNEL_ZERO_CROSS_MASK = 0xffff, + + AUDIO_CONTROL = 0x00d, + AUDIO_CONTROL_MASK = 0x9fe8, + AUDIO_CONTROL_SATURATE_MASK = 0x8000, + AUDIO_CONTROL_SOFTCH_MASK = 0x1000, + AUDIO_CONTROL_COMPEN_MASK = 0x0800, + AUDIO_CONTROL_NOHIGH_MASK = 0x0400, + AUDIO_CONTROL_NOINT_MASK = 0x0200, + AUDIO_CONTROL_EQEN_MASK = 0x0100, + AUDIO_CONTROL_VOLSEL_MASK = 0x00c0, + AUDIO_CONTROL_VOLSEL_SHIFT = 6, + AUDIO_CONTROL_FOF_MASK = 0x0020, + AUDIO_CONTROL_INIT_MASK = 0x0008, + + AUDIO_COMPRESS_CTRL = 0x00e, + AUDIO_COMPRESS_CTRL_PEAK_MASK = 0x8000, + AUDIO_COMPRESS_CTRL_THRESHOLD_MASK = 0x7f00, + AUDIO_COMPRESS_CTRL_THRESHOLD_SHIFT = 8, + AUDIO_COMPRESS_CTRL_ATTSCALE_MASK = 0x00c0, + AUDIO_COMPRESS_CTRL_ATTSCALE_SHIFT = 6, + AUDIO_COMPRESS_CTRL_RELSCALE_MASK = 0x0030, + AUDIO_COMPRESS_CTRL_RELSCALE_SHIFT = 4, + AUDIO_COMPRESS_CTRL_DISZC_MASK = 0x0008, + AUDIO_COMPRESS_CTRL_RATIO_MASK = 0x0007, + + AUDIO_CHANNEL_STATUS = 0x00f, + AUDIO_CHANNEL_STATUS_MASK = 0xffff, + + AUDIO_WAVE_IN_L = 0x010, + + AUDIO_WAVE_IN_R = 0x011, + AUDIO_SOFTIRQ_MASK = 0x8000, + AUDIO_SOFTIRQ_EN_MASK = 0x4000, + AUDIO_SOFT_PHASE_HIGH_MASK = 0x0070, + AUDIO_SOFT_PHASE_HIGH_SHIFT = 4, + AUDIO_FIFO_IRQ_THRESHOLD_MASK = 0x000f, + + AUDIO_WAVE_OUT_L = 0x012, + AUDIO_WAVE_OUT_R = 0x013, + + AUDIO_CHANNEL_REPEAT = 0x014, + AUDIO_CHANNEL_REPEAT_MASK = 0xffff, + + AUDIO_CHANNEL_ENV_MODE = 0x015, + AUDIO_CHANNEL_ENV_MODE_MASK = 0xffff, + + AUDIO_CHANNEL_TONE_RELEASE = 0x016, + AUDIO_CHANNEL_TONE_RELEASE_MASK = 0xffff, + + AUDIO_CHANNEL_ENV_IRQ = 0x017, + AUDIO_CHANNEL_ENV_IRQ_MASK = 0xffff, + + AUDIO_CHANNEL_PITCH_BEND = 0x018, + AUDIO_CHANNEL_PITCH_BEND_MASK = 0xffff, + + AUDIO_SOFT_PHASE = 0x019, + + AUDIO_ATTACK_RELEASE = 0x01a, + AUDIO_RELEASE_TIME_MASK = 0x00ff, + AUDIO_ATTACK_TIME_MASK = 0xff00, + AUDIO_ATTACK_TIME_SHIFT = 8, + + AUDIO_EQ_CUTOFF10 = 0x01b, + AUDIO_EQ_CUTOFF10_MASK = 0x7f7f, + + AUDIO_EQ_CUTOFF32 = 0x01c, + AUDIO_EQ_CUTOFF32_MASK = 0x7f7f, + + AUDIO_EQ_GAIN10 = 0x01d, + AUDIO_EQ_GAIN10_MASK = 0x7f7f, + + AUDIO_EQ_GAIN32 = 0x01e, + AUDIO_EQ_GAIN32_MASK = 0x7f7f + }; + + static const device_timer_id TIMER_BEAT = 3; + void check_irqs(const uint16_t changed); + + virtual void device_start() override; + virtual void device_reset() override; + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; + + uint16_t read_space(offs_t offset); + + void stop_channel(const uint32_t channel); + bool advance_channel(const uint32_t channel); + bool fetch_sample(const uint32_t channel); + void loop_channel(const uint32_t channel); + + + bool m_debug_samples; + bool m_debug_rates; + + uint16_t m_audio_regs[0x200]; + uint16_t m_audio_phase_regs[0x200]; + uint16_t m_audio_ctrl_regs[0x400]; + uint8_t m_sample_shift[16]; + uint32_t m_sample_count[16]; + uint32_t m_sample_addr[16]; + double m_channel_rate[16]; + double m_channel_rate_accum[16]; + uint32_t m_rampdown_frame[16]; + uint32_t m_envclk_frame[16]; + uint32_t m_envelope_addr[16]; + int m_channel_debug; + uint16_t m_audio_curr_beat_base_count; + + emu_timer *m_audio_beat; + + sound_stream *m_stream; + oki_adpcm_state m_adpcm[16]; + + static const uint32_t s_rampdown_frame_counts[8]; + static const uint32_t s_envclk_frame_counts[16]; + +private: + devcb_read16 m_space_read_cb; + devcb_write_line m_irq_cb; + +}; + +DECLARE_DEVICE_TYPE(SPG2XX_AUDIO, spg2xx_audio_device) + +#endif // MAME_MACHINE_SPG2XX_AUDIO_H -- cgit v1.2.3-70-g09d2 From a500ebecb161d8be140f40f895ac375172204e09 Mon Sep 17 00:00:00 2001 From: DavidHaywood <28625134+DavidHaywood@users.noreply.github.com> Date: Mon, 25 Mar 2019 16:31:10 +0000 Subject: refactoring checkpoint (nw) --- scripts/src/machine.lua | 2 + src/devices/machine/spg2xx.cpp | 1172 ++-------------------------------- src/devices/machine/spg2xx.h | 98 +-- src/devices/machine/spg2xx_io.cpp | 1270 +++++++++++++++++++++++++++++++++++++ src/devices/machine/spg2xx_io.h | 169 +++++ 5 files changed, 1534 insertions(+), 1177 deletions(-) create mode 100644 src/devices/machine/spg2xx_io.cpp create mode 100644 src/devices/machine/spg2xx_io.h (limited to 'scripts/src/machine.lua') diff --git a/scripts/src/machine.lua b/scripts/src/machine.lua index 54810e56038..fa451ae5dc6 100644 --- a/scripts/src/machine.lua +++ b/scripts/src/machine.lua @@ -2624,6 +2624,8 @@ if (MACHINES["SPG2XX"]~=null) then MAME_DIR .. "src/devices/machine/spg2xx.h", MAME_DIR .. "src/devices/machine/spg2xx_audio.cpp", MAME_DIR .. "src/devices/machine/spg2xx_audio.h", + MAME_DIR .. "src/devices/machine/spg2xx_io.cpp", + MAME_DIR .. "src/devices/machine/spg2xx_io.h", MAME_DIR .. "src/devices/machine/spg110.cpp", MAME_DIR .. "src/devices/machine/spg110.h", } diff --git a/src/devices/machine/spg2xx.cpp b/src/devices/machine/spg2xx.cpp index 1e8d32fbc0e..ff96082e958 100644 --- a/src/devices/machine/spg2xx.cpp +++ b/src/devices/machine/spg2xx.cpp @@ -57,8 +57,8 @@ DEFINE_DEVICE_TYPE(SPG28X, spg28x_device, "spg28x", "SPG280-series System-on-a-C #define SPG_DEBUG_VIDEO (0) -#define IO_IRQ_ENABLE m_io_regs[0x21] -#define IO_IRQ_STATUS m_io_regs[0x22] +//#define IO_IRQ_ENABLE m_io_regs[0x21] +//#define IO_IRQ_STATUS m_io_regs[0x22] #define VIDEO_IRQ_ENABLE m_video_regs[0x62] #define VIDEO_IRQ_STATUS m_video_regs[0x63] @@ -66,6 +66,7 @@ spg2xx_device::spg2xx_device(const machine_config &mconfig, device_type type, co : device_t(mconfig, type, tag, owner, clock) , device_mixer_interface(mconfig, *this, 2) , m_spg_audio(*this, "spgaudio") + , m_spg_io(*this, "spgio") , m_rowscrolloffset(15) , m_porta_out(*this) , m_portb_out(*this) @@ -106,7 +107,7 @@ void spg2xx_device::map(address_map &map) map(0x003000, 0x0031ff).rw(m_spg_audio, FUNC(spg2xx_audio_device::audio_r), FUNC(spg2xx_audio_device::audio_w)); map(0x003200, 0x0033ff).rw(m_spg_audio, FUNC(spg2xx_audio_device::audio_phase_r), FUNC(spg2xx_audio_device::audio_phase_w)); map(0x003400, 0x0037ff).rw(m_spg_audio, FUNC(spg2xx_audio_device::audio_ctrl_r), FUNC(spg2xx_audio_device::audio_ctrl_w)); - map(0x003d00, 0x003dff).rw(FUNC(spg2xx_device::io_r), FUNC(spg2xx_device::io_w)); + map(0x003d00, 0x003dff).rw(m_spg_io, FUNC(spg2xx_io_device::io_r), FUNC(spg2xx_io_device::io_w)); map(0x003e00, 0x003e03).rw(FUNC(spg2xx_device::dma_r), FUNC(spg2xx_device::dma_w)); } @@ -135,34 +136,9 @@ void spg2xx_device::device_start() m_uart_tx.resolve_safe(); m_chip_sel.resolve_safe(); - m_tmb1 = timer_alloc(TIMER_TMB1); - m_tmb2 = timer_alloc(TIMER_TMB2); - m_tmb1->adjust(attotime::never); - m_tmb2->adjust(attotime::never); - m_screenpos_timer = timer_alloc(TIMER_SCREENPOS); m_screenpos_timer->adjust(attotime::never); - m_uart_tx_timer = timer_alloc(TIMER_UART_TX); - m_uart_tx_timer->adjust(attotime::never); - - m_uart_rx_timer = timer_alloc(TIMER_UART_RX); - m_uart_rx_timer->adjust(attotime::never); - - m_4khz_timer = timer_alloc(TIMER_4KHZ); - m_4khz_timer->adjust(attotime::never); - - m_timer_src_ab = timer_alloc(TIMER_SRC_AB); - m_timer_src_ab->adjust(attotime::never); - - m_timer_src_c = timer_alloc(TIMER_SRC_C); - m_timer_src_c->adjust(attotime::never); - - save_item(NAME(m_timer_a_preload)); - save_item(NAME(m_timer_b_preload)); - save_item(NAME(m_timer_b_divisor)); - save_item(NAME(m_timer_b_tick_rate)); - save_item(NAME(m_hide_page0)); save_item(NAME(m_hide_page1)); save_item(NAME(m_hide_sprites)); @@ -171,54 +147,43 @@ void spg2xx_device::device_start() save_item(NAME(m_debug_palette)); save_item(NAME(m_sprite_index_to_debug)); - save_item(NAME(m_io_regs)); save_item(NAME(m_dma_regs)); - save_item(NAME(m_uart_rx_fifo)); - save_item(NAME(m_uart_rx_fifo_start)); - save_item(NAME(m_uart_rx_fifo_end)); - save_item(NAME(m_uart_rx_fifo_count)); - save_item(NAME(m_uart_rx_available)); - save_item(NAME(m_uart_rx_irq)); - save_item(NAME(m_uart_tx_irq)); - - save_item(NAME(m_extint)); - save_item(NAME(m_video_regs)); save_item(NAME(m_sprite_limit)); save_item(NAME(m_pal_flag)); - save_item(NAME(m_2khz_divider)); - save_item(NAME(m_1khz_divider)); - save_item(NAME(m_4hz_divider)); +// save_item(NAME(m_2khz_divider)); +// save_item(NAME(m_1khz_divider)); +// save_item(NAME(m_4hz_divider)); - save_item(NAME(m_uart_baud_rate)); +// save_item(NAME(m_uart_baud_rate)); } void spg2xx_device::device_reset() { memset(m_video_regs, 0, 0x100 * sizeof(uint16_t)); - memset(m_io_regs, 0, 0x100 * sizeof(uint16_t)); +// memset(m_io_regs, 0, 0x100 * sizeof(uint16_t)); memset(m_dma_regs, 0, 0x4 * sizeof(uint16_t)); - m_timer_a_preload = 0; - m_timer_b_preload = 0; - m_timer_b_divisor = 0; - m_timer_b_tick_rate = 0; +// m_timer_a_preload = 0; +// m_timer_b_preload = 0; +// m_timer_b_divisor = 0; +// m_timer_b_tick_rate = 0; - m_io_regs[0x23] = 0x0028; - m_io_regs[0x2c] = 0x1418; - m_io_regs[0x2d] = 0x1658; +// m_io_regs[0x23] = 0x0028; +// m_io_regs[0x2c] = 0x1418; +// m_io_regs[0x2d] = 0x1658; - m_uart_rx_available = false; - memset(m_uart_rx_fifo, 0, ARRAY_LENGTH(m_uart_rx_fifo)); - m_uart_rx_fifo_start = 0; - m_uart_rx_fifo_end = 0; - m_uart_rx_fifo_count = 0; - m_uart_tx_irq = false; - m_uart_rx_irq = false; +// m_uart_rx_available = false; +// memset(m_uart_rx_fifo, 0, ARRAY_LENGTH(m_uart_rx_fifo)); +// m_uart_rx_fifo_start = 0; +// m_uart_rx_fifo_end = 0; +// m_uart_rx_fifo_count = 0; +// m_uart_tx_irq = false; +// m_uart_rx_irq = false; - memset(m_extint, 0, sizeof(bool) * 2); +// memset(m_extint, 0, sizeof(bool) * 2); m_video_regs[0x36] = 0xffff; m_video_regs[0x37] = 0xffff; @@ -233,11 +198,21 @@ void spg2xx_device::device_reset() m_debug_palette = false; m_sprite_index_to_debug = 0; - m_4khz_timer->adjust(attotime::from_hz(4096), 0, attotime::from_hz(4096)); +// m_4khz_timer->adjust(attotime::from_hz(4096), 0, attotime::from_hz(4096)); - m_2khz_divider = 0; - m_1khz_divider = 0; - m_4hz_divider = 0; +// m_2khz_divider = 0; +// m_1khz_divider = 0; +// m_4hz_divider = 0; +} + +void spg2xx_device::uart_rx(uint8_t data) +{ + // TODO trampoline +} + +void spg2xx_device::extint_w(int channel, bool state) +{ + // TODO trampoline } WRITE_LINE_MEMBER(spg2xx_device::audioirq_w) @@ -972,186 +947,6 @@ void spg2xx_device::check_video_irq() * Machine Hardware * *************************/ -void spg2xx_device::uart_rx(uint8_t data) -{ - LOGMASKED(LOG_UART, "uart_rx: Pulling %02x into receive FIFO\n", data); - if (BIT(m_io_regs[0x30], 6)) - { - m_uart_rx_fifo[m_uart_rx_fifo_end] = data; - m_uart_rx_fifo_end = (m_uart_rx_fifo_end + 1) % ARRAY_LENGTH(m_uart_rx_fifo); - m_uart_rx_fifo_count++; - if (m_uart_rx_timer->remaining() == attotime::never) - m_uart_rx_timer->adjust(attotime::from_ticks(BIT(m_io_regs[0x30], 5) ? 11 : 10, m_uart_baud_rate)); - } -} - -READ16_MEMBER(spg2xx_device::io_r) -{ - static const char *const gpioregs[] = { "GPIO Data Port", "GPIO Buffer Port", "GPIO Direction Port", "GPIO Attribute Port", "GPIO IRQ/Latch Port" }; - static const char gpioports[] = { 'A', 'B', 'C' }; - - uint16_t val = m_io_regs[offset]; - - switch (offset) - { - case 0x01: case 0x06: case 0x0b: // GPIO Data Port A/B/C - do_gpio(offset, false); - LOGMASKED(LOG_GPIO, "%s: io_r: %s %c = %04x\n", machine().describe_context(), gpioregs[(offset - 1) % 5], gpioports[(offset - 1) / 5], m_io_regs[offset]); - val = m_io_regs[offset]; - break; - - case 0x02: case 0x03: case 0x04: case 0x05: - case 0x07: case 0x08: case 0x09: case 0x0a: - case 0x0c: case 0x0d: case 0x0e: case 0x0f: // Other GPIO regs - LOGMASKED(LOG_GPIO, "%s: io_r: %s %c = %04x\n", machine().describe_context(), gpioregs[(offset - 1) % 5], gpioports[(offset - 1) / 5], m_io_regs[offset]); - break; - - case 0x10: // Timebase Control - LOGMASKED(LOG_IO_READS, "io_r: Timebase Control = %04x\n", val); - break; - - case 0x12: // Timer A Data - LOGMASKED(LOG_IO_WRITES, "io_r: Timer A Data = %04x\n", val); - break; - - case 0x1c: // Video line counter - val = m_screen->vpos(); - LOGMASKED(LOG_VLINES, "io_r: Video Line = %04x\n", val); - break; - - case 0x20: // System Control - LOGMASKED(LOG_IO_READS, "io_r: System Control = %04x\n", val); - break; - - case 0x21: // IRQ Control - LOGMASKED(LOG_IRQS, "%s: io_r: I/O IRQ Control = %04x\n", machine().describe_context(), val); - break; - - case 0x22: // IRQ Status - LOGMASKED(LOG_IRQS, "%s: io_r: I/O IRQ Status = %04x\n", machine().describe_context(), val); - break; - - case 0x23: // External Memory Control - LOGMASKED(LOG_IO_READS, "%s: io_r: Ext. Memory Control = %04x\n", machine().describe_context(), val); - break; - - case 0x25: // ADC Control - LOGMASKED(LOG_IO_READS, "io_r: ADC Control = %04x\n", val); - break; - - case 0x27: // ADC Data - { - m_io_regs[0x27] = 0; - const uint16_t old = IO_IRQ_STATUS; - IO_IRQ_STATUS &= ~0x2000; - const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE); - if (changed) - check_irqs(changed); - LOGMASKED(LOG_IO_READS, "%s: io_r: ADC Data = %04x\n", machine().describe_context(), val); - break; - } - - case 0x29: // Wakeup Source - LOGMASKED(LOG_IO_READS, "io_r: Wakeup Source = %04x\n", val); - break; - - case 0x2b: - LOGMASKED(LOG_IO_READS, "io_r: NTSC/PAL = %04x\n", m_pal_flag); - return m_pal_flag; - - case 0x2c: // PRNG 0 - { - const uint16_t value = m_io_regs[0x2c]; - m_io_regs[0x2c] = ((value << 1) | (BIT(value, 14) ^ BIT(value, 13))) & 0x7fff; - return value; - } - - case 0x2d: // PRNG 1 - { - const uint16_t value = m_io_regs[0x2d]; - m_io_regs[0x2d] = ((value << 1) | (BIT(value, 14) ^ BIT(value, 13))) & 0x7fff; - return value; - } - - case 0x2e: // FIQ Source Select - LOGMASKED(LOG_FIQ, "io_r: FIQ Source Select = %04x\n", val); - break; - - case 0x2f: // Data Segment - val = m_cpu->get_ds(); - LOGMASKED(LOG_SEGMENT, "io_r: Data Segment = %04x\n", val); - break; - - case 0x30: // UART Control - LOGMASKED(LOG_UART, "%s: io_r: UART Control = %04x\n", machine().describe_context(), val); - break; - - case 0x31: // UART Status - //LOGMASKED(LOG_UART, "%s: io_r: UART Status = %04x\n", machine().describe_context(), val); - break; - - case 0x36: // UART RX Data - if (m_uart_rx_available) - { - m_io_regs[0x31] &= ~0x0081; - LOGMASKED(LOG_UART, "UART Rx data is available, clearing bits\n"); - if (m_uart_rx_fifo_count) - { - LOGMASKED(LOG_UART, "Remaining count %d, value %02x\n", m_uart_rx_fifo_count, m_uart_rx_fifo[m_uart_rx_fifo_start]); - m_io_regs[0x36] = m_uart_rx_fifo[m_uart_rx_fifo_start]; - val = m_io_regs[0x36]; - m_uart_rx_fifo_start = (m_uart_rx_fifo_start + 1) % ARRAY_LENGTH(m_uart_rx_fifo); - m_uart_rx_fifo_count--; - - if (m_uart_rx_fifo_count == 0) - { - m_uart_rx_available = false; - } - else - { - LOGMASKED(LOG_UART, "Remaining count %d, setting up timer\n", m_uart_rx_fifo_count); - //uart_receive_tick(); - if (m_uart_rx_timer->remaining() == attotime::never) - m_uart_rx_timer->adjust(attotime::from_ticks(BIT(m_io_regs[0x30], 5) ? 11 : 10, m_uart_baud_rate)); - } - } - else - { - m_uart_rx_available = false; - } - } - else - { - m_io_regs[0x37] |= 0x2000; - } - LOGMASKED(LOG_UART, "%s: io_r: UART Rx Data = %04x\n", machine().describe_context(), val); - break; - - case 0x37: // UART Rx FIFO Control - val &= ~0x0070; - val |= (m_uart_rx_available ? 7 : 0) << 4; - LOGMASKED(LOG_UART, "io_r: UART Rx FIFO Control = %04x\n", machine().describe_context(), val); - break; - - case 0x51: // unknown, polled by ClickStart cartridges ( clikstrt ) - return 0x8000; - - case 0x59: // I2C Status - LOGMASKED(LOG_I2C, "io_r: I2C Status = %04x\n", val); - break; - - case 0x5e: // I2C Data In - LOGMASKED(LOG_I2C, "io_r: I2C Data In = %04x\n", val); - break; - - default: - LOGMASKED(LOG_UNKNOWN_IO, "io_r: Unknown register %04x\n", 0x3d00 + offset); - break; - } - - return val; -} - READ16_MEMBER(spg2xx_device::dma_r) { uint16_t val = m_dma_regs[offset]; @@ -1184,674 +979,6 @@ READ16_MEMBER(spg2xx_device::dma_r) } -void spg2xx_device::update_porta_special_modes() -{ - static const char* const s_pa_special[4][16] = - { - // Input, Special 0 - // Input, Special 1 - // Output, Special 0 - // Output, Special 1 - - { "LP", "ExtClk2", "ExtClk1", "-", "SDA", "SlvRDY", "-", "-", "SPICLK", "-", "RxD", "SPISSB", "-", "-", "-", "-" }, - { "-", "-", "-", "SCK", "-", "SWS", "-", "-", "-", "-", "-", "-", "IRQ2B", "-", "-", "IRQ1B" }, - { "-", "-", "-", "SCK", "SDA", "SWS", "-", "-", "SPICLK", "TxD", "-", "SPISSB", "TAPWM", "TM1", "TBPWM", "TM2" }, - { "CSB3", "CSB2", "CSB1", "SCK", "SDA", "VSYNC", "HSYNC", "SYSCLK3", "SPICLK", "TxD", "SWS", "SPISSB", "-", "VSYNC", "HSYNC", "CSYNC" }, - }; - for (int bit = 15; bit >= 0; bit--) - { - if (!BIT(m_io_regs[0x05], bit)) - continue; - uint8_t type = (BIT(m_io_regs[0x03], bit) << 1) | BIT(m_io_regs[0x00], 0); - LOGMASKED(LOG_GPIO, " Bit %2d: %s\n", bit, s_pa_special[type][bit]); - } -} - -void spg2xx_device::update_portb_special_modes() -{ - static const char* const s_pb_special[4][8] = - { - // Input, Special 0 - // Input, Special 1 - // Output, Special 0 - // Output, Special 1 - - { "-", "-", "-", "-", "-", "-", "SDA", "SlvRDY" }, - { "-", "-", "-", "-", "-", "-", "SDA", "SlvRDY" }, - { "VSYNC", "HSYNC", "CSYNC", "-", "-", "SCK", "SDA", "SWS" }, - { "CSB3", "CSB2", "CSB1", "TBPWM", "TM2", "-", "-", "SYSCLK2" }, - }; - for (int bit = 7; bit >= 0; bit--) - { - if (!BIT(m_io_regs[0x0a], bit)) - continue; - uint8_t type = (BIT(m_io_regs[0x08], bit) << 1) | BIT(m_io_regs[0x00], 1); - LOGMASKED(LOG_GPIO, " Bit %2d: %s\n", bit, s_pb_special[type][bit]); - } -} - -void spg2xx_device::update_timer_b_rate() -{ - switch (m_io_regs[0x17] & 7) - { - case 0: - case 1: - case 5: - case 6: - case 7: - m_timer_src_c->adjust(attotime::never); - break; - case 2: - m_timer_src_c->adjust(attotime::from_hz(32768), 0, attotime::from_hz(32768)); - break; - case 3: - m_timer_src_c->adjust(attotime::from_hz(8192), 0, attotime::from_hz(8192)); - break; - case 4: - m_timer_src_c->adjust(attotime::from_hz(4096), 0, attotime::from_hz(4096)); - break; - } -} - -void spg2xx_device::update_timer_ab_src() -{ - if (m_timer_b_tick_rate == 0) - return; - - m_timer_b_divisor++; - if (m_timer_b_divisor >= m_timer_b_tick_rate) - { - m_timer_b_divisor = 0; - increment_timer_a(); - } -} - -void spg2xx_device::increment_timer_a() -{ - m_io_regs[0x12]++; - if (m_io_regs[0x12] == 0) - { - m_io_regs[0x12] = m_timer_a_preload; - const uint16_t old = IO_IRQ_STATUS; - IO_IRQ_STATUS |= 0x0800; - const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE); - if (changed) - { - //printf("Timer A overflow\n"); - check_irqs(0x0800); - } - } -} - -void spg2xx_device::update_timer_c_src() -{ - m_io_regs[0x16]++; - if (m_io_regs[0x16] == 0) - { - m_io_regs[0x16] = m_timer_b_preload; - const uint16_t old = IO_IRQ_STATUS; - IO_IRQ_STATUS |= 0x0400; - const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE); - if (changed) - { - printf("Timer B overflow\n"); - check_irqs(0x0400); - } - } -} - - -WRITE16_MEMBER(spg28x_device::io_w) -{ - if (offset == 0x33) - { - m_io_regs[offset] = data; - m_uart_baud_rate = 27000000 / (0x10000 - m_io_regs[0x33]); - LOGMASKED(LOG_UART, "%s: io_w: UART Baud Rate scaler = %04x (%d baud)\n", machine().describe_context(), data, m_uart_baud_rate); - } - else - { - spg2xx_device::io_w(space, offset, data, mem_mask); - } -} - -WRITE16_MEMBER(spg2xx_device::io_w) -{ - static const char *const gpioregs[] = { "GPIO Data Port", "GPIO Buffer Port", "GPIO Direction Port", "GPIO Attribute Port", "GPIO IRQ/Latch Port" }; - static const char gpioports[3] = { 'A', 'B', 'C' }; - - switch (offset) - { - case 0x00: // GPIO special function select - { - LOGMASKED(LOG_GPIO, "%s: io_w: GPIO Configuration = %04x (IOBWake:%d, IOAWake:%d, IOBSpecSel:%d, IOASpecSel:%d)\n", machine().describe_context(), data - , BIT(data, 4), BIT(data, 3), BIT(data, 1), BIT(data, 0)); - const uint16_t old = m_io_regs[offset]; - m_io_regs[offset] = data; - const uint16_t changed = old ^ data; - if (BIT(changed, 0)) - update_porta_special_modes(); - if (BIT(changed, 1)) - update_portb_special_modes(); - break; - } - - case 0x01: case 0x06: case 0x0b: // GPIO data, port A/B/C - offset++; - // Intentional fallthrough - we redirect data register writes to the buffer register. - - case 0x02: case 0x04: // Port A - case 0x07: case 0x09: // Port B - case 0x0c: case 0x0d: case 0x0e: case 0x0f: // Port C - LOGMASKED(LOG_GPIO, "%s: io_w: %s %c = %04x\n", machine().describe_context(), gpioregs[(offset - 1) % 5], gpioports[(offset - 1) / 5], data); - m_io_regs[offset] = data; - do_gpio(offset, true); - break; - - case 0x03: // Port A Direction - LOGMASKED(LOG_GPIO, "%s: io_w: GPIO Direction Port A = %04x\n", machine().describe_context(), data); - m_io_regs[offset] = data; - update_porta_special_modes(); - do_gpio(offset, true); - break; - - case 0x08: // Port B Direction - LOGMASKED(LOG_GPIO, "%s: io_w: GPIO Direction Port B = %04x\n", machine().describe_context(), data); - m_io_regs[offset] = data; - update_portb_special_modes(); - do_gpio(offset, true); - break; - - case 0x05: // Port A Special - LOGMASKED(LOG_GPIO, "%s: io_w: Port A Special Function Select: %04x\n", machine().describe_context(), data); - m_io_regs[offset] = data; - update_porta_special_modes(); - break; - - case 0x0a: // Port B Special - LOGMASKED(LOG_GPIO, "%s: io_w: Port B Special Function Select: %04x\n", machine().describe_context(), data); - m_io_regs[offset] = data; - update_portb_special_modes(); - break; - - case 0x10: // Timebase Control - { - static const char* const s_tmb1_sel[2][4] = - { - { "8Hz", "16Hz", "32Hz", "64Hz" }, - { "12kHz", "24kHz", "40kHz", "40kHz" } - }; - static const char* const s_tmb2_sel[2][4] = - { - { "128Hz", "256Hz", "512Hz", "1024Hz" }, - { "105kHz", "210kHz", "420kHz", "840kHz" } - }; - static const uint32_t s_tmb1_freq[2][4] = - { - { 8, 16, 32, 64 }, - { 12000, 24000, 40000, 40000 } - }; - static const uint32_t s_tmb2_freq[2][4] = - { - { 128, 256, 512, 1024 }, - { 105000, 210000, 420000, 840000 } - }; - LOGMASKED(LOG_TIMERS, "io_w: Timebase Control = %04x (Source:%s, TMB2:%s, TMB1:%s)\n", data, - BIT(data, 4) ? "27MHz" : "32768Hz", s_tmb2_sel[BIT(data, 4)][(data >> 2) & 3], s_tmb1_sel[BIT(data, 4)][data & 3]); - m_io_regs[offset] = data; - const uint8_t hifreq = BIT(data, 4); - const uint32_t tmb1freq = s_tmb1_freq[hifreq][data & 3]; - m_tmb1->adjust(attotime::from_hz(tmb1freq), 0, attotime::from_hz(tmb1freq)); - const uint32_t tmb2freq = s_tmb2_freq[hifreq][(data >> 2) & 3]; - m_tmb2->adjust(attotime::from_hz(tmb2freq), 0, attotime::from_hz(tmb2freq)); - break; - } - - case 0x11: // Timebase Clear - LOGMASKED(LOG_TIMERS, "io_w: Timebase Clear = %04x\n", data); - break; - - case 0x12: // Timer A Data - LOGMASKED(LOG_TIMERS, "io_w: Timer A Data = %04x\n", data); - m_io_regs[offset] = data; - m_timer_a_preload = data; - break; - - case 0x13: // Timer A Control - { - static const char* const s_source_a[8] = { "0", "0", "32768Hz", "8192Hz", "4096Hz", "1", "0", "ExtClk1" }; - static const char* const s_source_b[8] = { "2048Hz", "1024Hz", "256Hz", "TMB1", "4Hz", "2Hz", "1", "ExtClk2" }; - LOGMASKED(LOG_TIMERS, "io_w: Timer A Control = %04x (Source A:%s, Source B:%s)\n", data, - s_source_a[data & 7], s_source_b[(data >> 3) & 7]); - m_io_regs[offset] = data; - int timer_a_rate = 0; - switch (data & 7) - { - case 0: - case 1: - case 5: - case 6: - case 7: - m_timer_src_ab->adjust(attotime::never); - break; - case 2: - m_timer_src_ab->adjust(attotime::from_hz(32768), 0, attotime::from_hz(32768)); - timer_a_rate = 32768; - break; - case 3: - m_timer_src_ab->adjust(attotime::from_hz(8192), 0, attotime::from_hz(8192)); - timer_a_rate = 8192; - break; - case 4: - m_timer_src_ab->adjust(attotime::from_hz(4096), 0, attotime::from_hz(4096)); - timer_a_rate = 4096; - break; - } - switch ((data >> 3) & 7) - { - case 0: - m_timer_b_tick_rate = timer_a_rate / 2048; - break; - case 1: - m_timer_b_tick_rate = timer_a_rate / 1024; - break; - case 2: - m_timer_b_tick_rate = timer_a_rate / 256; - break; - case 3: - m_timer_b_tick_rate = 0; - break; - case 4: - m_timer_b_tick_rate = timer_a_rate / 4; - break; - case 5: - m_timer_b_tick_rate = timer_a_rate / 2; - break; - case 6: - m_timer_b_tick_rate = 1; - break; - case 7: - m_timer_b_tick_rate = 0; - break; - } - break; - } - - case 0x15: // Timer A IRQ Clear - { - LOGMASKED(LOG_TIMERS, "io_w: Timer A IRQ Clear\n"); - const uint16_t old = IO_IRQ_STATUS; - IO_IRQ_STATUS &= ~0x0800; - const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE); - if (changed) - check_irqs(0x0800); - break; - } - - case 0x16: // Timer B Data - LOGMASKED(LOG_TIMERS, "io_w: Timer B Data = %04x\n", data); - m_io_regs[offset] = data; - m_timer_b_preload = data; - break; - - case 0x17: // Timer B Control - { - static const char* const s_source_c[8] = { "0", "0", "32768Hz", "8192Hz", "4096Hz", "1", "0", "ExtClk1" }; - LOGMASKED(LOG_TIMERS, "io_w: Timer B Control = %04x (Source C:%s)\n", data, s_source_c[data & 7]); - m_io_regs[offset] = data; - if (m_io_regs[0x18] == 1) - { - update_timer_b_rate(); - } - break; - } - - case 0x18: // Timer B Enable - { - LOGMASKED(LOG_TIMERS, "io_w: Timer B Enable = %04x\n", data); - m_io_regs[offset] = data & 1; - if (data & 1) - { - update_timer_b_rate(); - } - else - { - m_timer_src_c->adjust(attotime::never); - } - break; - } - - case 0x19: // Timer B IRQ Clear - { - LOGMASKED(LOG_TIMERS, "io_w: Timer B IRQ Clear\n"); - const uint16_t old = IO_IRQ_STATUS; - IO_IRQ_STATUS &= ~0x0400; - const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE); - if (changed) - check_irqs(0x0400); - break; - } - - case 0x20: // System Control - { - static const char* const s_sysclk[4] = { "13.5MHz", "27MHz", "27MHz NoICE", "54MHz" }; - static const char* const s_lvd_voltage[4] = { "2.7V", "2.9V", "3.1V", "3.3V" }; - static const char* const s_weak_strong[2] = { "Weak", "Strong" }; - LOGMASKED(LOG_IO_WRITES, "io_w: System Control = %04x (Watchdog:%d, Sleep:%d, SysClk:%s, SysClkInv:%d, LVROutEn:%d, LVREn:%d\n" - , data, BIT(data, 15), BIT(data, 14), s_sysclk[(data >> 12) & 3], BIT(data, 11), BIT(data, 9), BIT(data, 8)); - LOGMASKED(LOG_IO_WRITES, " LVDEn:%d, LVDVoltSel:%s, 32kHzDisable:%d, StrWkMode:%s, VDACDisable:%d, ADACDisable:%d, ADACOutDisable:%d)\n" - , BIT(data, 7), s_lvd_voltage[(data >> 5) & 3], BIT(data, 4), s_weak_strong[BIT(data, 3)], BIT(data, 2), BIT(data, 1), BIT(data, 0)); - m_io_regs[offset] = data; - break; - } - - case 0x21: // IRQ Enable - { - LOGMASKED(LOG_IRQS, "io_w: IRQ Enable = %04x\n", data); - const uint16_t old = IO_IRQ_ENABLE; - m_io_regs[offset] = data; - const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE); - if (changed) - check_irqs(changed); - break; - } - - case 0x22: // IRQ Acknowledge - { - LOGMASKED(LOG_IRQS, "io_w: IRQ Acknowledge = %04x\n", data); - const uint16_t old = IO_IRQ_STATUS; - IO_IRQ_STATUS &= ~data; - const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE); - if (m_uart_rx_irq || m_uart_tx_irq) - { - LOGMASKED(LOG_IRQS | LOG_UART, "Re-setting UART IRQ due to still-unacknowledged Rx or Tx.\n"); - IO_IRQ_STATUS |= 0x0100; - } - if (changed) - check_irqs(changed); - break; - } - - case 0x23: // External Memory Control - { - static const char* const s_bus_arb[8] = - { - "Forbidden", "Forbidden", "Forbidden", "Forbidden", "Forbidden", "1:SPU/2:PPU/3:CPU", "Forbidden", "1:PPU/2:SPU/3:CPU" - }; - static const char* const s_addr_decode[4] = - { - "ROMCSB: 4000-3fffff, CSB1: ---, CSB2: ---, CSB3: ---", - "ROMCSB: 4000-1fffff, CSB1: 200000-3fffff, CSB2: ---, CSB3: ---", - "ROMCSB: 4000-0fffff, CSB1: 100000-1fffff, CSB2: 200000-2fffff, CSB3: 300000-3fffff", - "ROMCSB: 4000-0fffff, CSB1: 100000-1fffff, CSB2: 200000-2fffff, CSB3: 300000-3fffff" - }; - static const char* const s_ram_decode[16] = - { - "None", "None", "None", "None", "None", "None", "None", "None", - "4KW, 3ff000-3fffff\n", - "8KW, 3fe000-3fffff\n", - "16KW, 3fc000-3fffff\n", - "32KW, 3f8000-3fffff\n", - "64KW, 3f0000-3fffff\n", - "128KW, 3e0000-3fffff\n", - "256KW, 3c0000-3fffff\n", - "512KW, 380000-3fffff\n" - }; - LOGMASKED(LOG_EXT_MEM, "io_w: Ext. Memory Control (not yet implemented) = %04x:\n", data); - LOGMASKED(LOG_EXT_MEM, " WaitStates:%d, BusArbPrio:%s\n", (data >> 1) & 3, s_bus_arb[(data >> 3) & 7]); - LOGMASKED(LOG_EXT_MEM, " ROMAddrDecode:%s\n", s_addr_decode[(data >> 6) & 3]); - LOGMASKED(LOG_EXT_MEM, " RAMAddrDecode:%s\n", s_ram_decode[(data >> 8) & 15]); - m_chip_sel((data >> 6) & 3); - m_io_regs[offset] = data; - break; - } - - case 0x24: // Watchdog - LOGMASKED(LOG_WATCHDOG, "io_w: Watchdog Pet = %04x\n", data); - break; - - case 0x25: // ADC Control - { - LOGMASKED(LOG_IO_WRITES, "%s: io_w: ADC Control = %04x\n", machine().describe_context(), data); - m_io_regs[offset] = data & ~0x1000; - if (BIT(data, 0)) - { - m_io_regs[0x27] = 0x8000 | (m_adc_in[BIT(data, 5)]() & 0x7fff); - m_io_regs[0x25] |= 0x2000; - } - if (BIT(data, 12) && !BIT(m_io_regs[offset], 1)) - { - const uint16_t old = IO_IRQ_STATUS; - IO_IRQ_STATUS |= 0x2000; - const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE); - if (changed) - { - check_irqs(changed); - } - } - break; - } - - case 0x28: // Sleep Mode - LOGMASKED(LOG_IO_WRITES, "io_w: Sleep Mode (%s enter value) = %04x\n", data == 0xaa55 ? "valid" : "invalid", data); - m_io_regs[offset] = data; - break; - - case 0x29: // Wakeup Source - { - m_io_regs[offset] = data; - static const char* const s_sources[8] = - { - "TMB1", "TMB2", "2Hz", "4Hz", "1024Hz", "2048Hz", "4096Hz", "Key" - }; - - LOGMASKED(LOG_IO_WRITES, "io_w: Wakeup Source = %04x:\n", data); - bool comma = false; - char buf[1024]; - int char_idx = 0; - for (int i = 7; i >= 0; i--) - { - if (BIT(data, i)) - { - char_idx += sprintf(&buf[char_idx], "%s%s", comma ? ", " : "", s_sources[i]); - comma = true; - } - } - buf[char_idx] = 0; - LOGMASKED(LOG_IO_WRITES, " %s\n", buf); - break; - } - - case 0x2c: // PRNG 0 seed - LOGMASKED(LOG_IO_WRITES, "io_w: PRNG 0 seed = %04x\n", data & 0x7fff); - m_io_regs[offset] = data & 0x7fff; - break; - - case 0x2d: // PRNG 1 seed - LOGMASKED(LOG_IO_WRITES, "io_w: PRNG 1 seed = %04x\n", data & 0x7fff); - m_io_regs[offset] = data & 0x7fff; - break; - - case 0x2e: // FIQ Source Select - { - static const char* const s_fiq_select[8] = - { - "PPU", "SPU Channel", "Timer A", "Timer B", "UART/SPI", "External", "Reserved", "None" - }; - LOGMASKED(LOG_FIQ, "io_w: FIQ Source Select (not yet implemented) = %04x, %s\n", data, s_fiq_select[data & 7]); - m_io_regs[offset] = data; - break; - } - - case 0x2f: // Data Segment - m_cpu->set_ds(data & 0x3f); - LOGMASKED(LOG_SEGMENT, "io_w: Data Segment = %04x\n", data); - break; - - case 0x30: // UART Control - { - static const char* const s_9th_bit[4] = { "0", "1", "Odd", "Even" }; - LOGMASKED(LOG_UART, "%s: io_w: UART Control = %04x (TxEn:%d, RxEn:%d, Bits:%d, MultiProc:%d, 9thBit:%s, TxIntEn:%d, RxIntEn:%d\n", - machine().describe_context(), data, BIT(data, 7), BIT(data, 6), BIT(data, 5) ? 9 : 8, BIT(data, 4), s_9th_bit[(data >> 2) & 3], - BIT(data, 1), BIT(data, 0)); - const uint16_t changed = m_io_regs[offset] ^ data; - m_io_regs[offset] = data; - if (!BIT(data, 6)) - { - m_uart_rx_available = false; - m_io_regs[0x36] = 0; - } - if (BIT(changed, 7)) - { - if (BIT(data, 7)) - { - m_io_regs[0x31] |= 0x0002; - } - else - { - m_io_regs[0x31] &= ~0x0042; - m_uart_tx_timer->adjust(attotime::never); - } - } - break; - } - - case 0x31: // UART Status - LOGMASKED(LOG_UART, "%s: io_w: UART Status = %04x\n", machine().describe_context(), data); - if (BIT(data, 0)) - { - m_io_regs[0x31] &= ~1; - m_uart_rx_irq = false; - } - if (BIT(data, 1)) - { - m_io_regs[0x31] &= ~2; - m_uart_tx_irq = false; - } - if (!m_uart_rx_irq && !m_uart_tx_irq) - { - const uint16_t old = IO_IRQ_STATUS; - IO_IRQ_STATUS &= ~0x0100; - const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE); - if (changed) - check_irqs(0x0100); - } - break; - - case 0x33: // UART Baud Rate (low byte) - case 0x34: // UART Baud Rate (high byte) - { - m_io_regs[offset] = data; - const uint32_t divisor = 16 * (0x10000 - ((m_io_regs[0x34] << 8) | m_io_regs[0x33])); - LOGMASKED(LOG_UART, "%s: io_w: UART Baud Rate (%s byte): Baud rate = %d\n", offset == 0x33 ? "low" : "high", machine().describe_context(), 27000000 / divisor); - m_uart_baud_rate = 27000000 / divisor; - break; - } - - case 0x35: // UART TX Data - LOGMASKED(LOG_UART, "%s: io_w: UART Tx Data = %02x\n", machine().describe_context(), data & 0x00ff); - m_io_regs[offset] = data; - if (BIT(m_io_regs[0x30], 7)) - { - LOGMASKED(LOG_UART, "io_w: UART Tx: Clearing ready bit, setting busy bit, setting up timer\n"); - m_uart_tx_timer->adjust(attotime::from_ticks(BIT(m_io_regs[0x30], 5) ? 11 : 10, m_uart_baud_rate)); - m_io_regs[0x31] &= ~0x0002; - m_io_regs[0x31] |= 0x0040; - } - break; - - case 0x36: // UART RX Data - LOGMASKED(LOG_UART, "%s: io_w: UART Rx Data (read-only) = %04x\n", machine().describe_context(), data); - break; - - case 0x37: // UART Rx FIFO Control - LOGMASKED(LOG_UART, "%s: io_w: UART Rx FIFO Control = %04x (Reset:%d, Overrun:%d, Underrun:%d, Count:%d, Threshold:%d)\n", - machine().describe_context(), data, BIT(data, 15), BIT(data, 14), BIT(data, 13), (data >> 4) & 7, data & 7); - if (data & 0x8000) - { - m_uart_rx_available = false; - m_io_regs[0x36] = 0; - } - m_io_regs[offset] &= ~data & 0x6000; - m_io_regs[offset] &= ~0x0007; - m_io_regs[offset] |= data & 0x0007; - break; - - case 0x50: // SIO Setup - { - static const char* const s_addr_mode[4] = { "16-bit", "None", "8-bit", "24-bit" }; - static const char* const s_baud_rate[4] = { "/16", "/4", "/8", "/32" }; - LOGMASKED(LOG_SIO, "io_w: SIO Setup (not implemented) = %04x (DS301Ready:%d, Start:%d, Auto:%d, IRQEn:%d, Width:%d, Related:%d\n", data - , BIT(data, 11), BIT(data, 10), BIT(data, 9), BIT(data, 8), BIT(data, 7) ? 16 : 8, BIT(data, 6)); - LOGMASKED(LOG_SIO, " (Mode:%s, RWProtocol:%d, Rate:sysclk%s, AddrMode:%s)\n" - , BIT(data, 5), BIT(data, 4), s_baud_rate[(data >> 2) & 3], s_addr_mode[data & 3]); - break; - } - - case 0x52: // SIO Start Address (low) - LOGMASKED(LOG_SIO, "io_w: SIO Stat Address (low) (not implemented) = %04x\n", data); - break; - - case 0x53: // SIO Start Address (hi) - LOGMASKED(LOG_SIO, "io_w: SIO Stat Address (hi) (not implemented) = %04x\n", data); - break; - - case 0x54: // SIO Data - LOGMASKED(LOG_SIO, "io_w: SIO Data (not implemented) = %04x\n", data); - break; - - case 0x55: // SIO Automatic Transmit Count - LOGMASKED(LOG_SIO, "io_w: SIO Auto Transmit Count (not implemented) = %04x\n", data); - break; - - case 0x58: // I2C Command - LOGMASKED(LOG_I2C, "io_w: I2C Command = %04x\n", data); - m_io_regs[offset] = data; - do_i2c(); - break; - - case 0x59: // I2C Status / Acknowledge - LOGMASKED(LOG_I2C, "io_w: I2C Acknowledge = %04x\n", data); - m_io_regs[offset] &= ~data; - break; - - case 0x5a: // I2C Access Mode - LOGMASKED(LOG_I2C, "io_w: I2C Access Mode = %04x\n", data); - m_io_regs[offset] = data; - break; - - case 0x5b: // I2C Device Address - LOGMASKED(LOG_I2C, "io_w: I2C Device Address = %04x\n", data); - m_io_regs[offset] = data; - break; - - case 0x5c: // I2C Sub-Address - LOGMASKED(LOG_I2C, "io_w: I2C Sub-Address = %04x\n", data); - m_io_regs[offset] = data; - break; - - case 0x5d: // I2C Data Out - LOGMASKED(LOG_I2C, "io_w: I2C Data Out = %04x\n", data); - m_io_regs[offset] = data; - break; - - case 0x5e: // I2C Data In - LOGMASKED(LOG_I2C, "io_w: I2C Data In = %04x\n", data); - m_io_regs[offset] = data; - break; - - case 0x5f: // I2C Controller Mode - LOGMASKED(LOG_I2C, "io_w: I2C Controller Mode = %04x\n", data); - m_io_regs[offset] = data; - break; - - default: - LOGMASKED(LOG_UNKNOWN_IO, "io_w: Unknown register %04x = %04x\n", 0x3d00 + offset, data); - m_io_regs[offset] = data; - break; - } -} - WRITE16_MEMBER(spg2xx_device::dma_w) { switch (offset) @@ -1888,28 +1015,6 @@ void spg2xx_device::device_timer(emu_timer &timer, device_timer_id id, int param { switch (id) { - case TIMER_TMB1: - { - LOGMASKED(LOG_TIMERS, "TMB1 elapsed, setting IRQ Status bit 0 (old:%04x, new:%04x, enable:%04x)\n", IO_IRQ_STATUS, IO_IRQ_STATUS | 1, IO_IRQ_ENABLE); - const uint16_t old = IO_IRQ_STATUS; - IO_IRQ_STATUS |= 1; - const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE); - if (changed) - check_irqs(0x0001); - break; - } - - case TIMER_TMB2: - { - LOGMASKED(LOG_TIMERS, "TMB2 elapsed, setting IRQ Status bit 1 (old:%04x, new:%04x, enable:%04x)\n", IO_IRQ_STATUS, IO_IRQ_STATUS | 2, IO_IRQ_ENABLE); - const uint16_t old = IO_IRQ_STATUS; - IO_IRQ_STATUS |= 2; - const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE); - if (changed) - check_irqs(0x0002); - break; - } - case TIMER_SCREENPOS: { if (VIDEO_IRQ_ENABLE & 2) @@ -1923,125 +1028,9 @@ void spg2xx_device::device_timer(emu_timer &timer, device_timer_id id, int param m_screenpos_timer->adjust(m_screen->time_until_pos(m_video_regs[0x36], m_video_regs[0x37] << 1)); break; } - - case TIMER_UART_TX: - uart_transmit_tick(); - break; - - case TIMER_UART_RX: - uart_receive_tick(); - break; - - case TIMER_4KHZ: - system_timer_tick(); - break; - - case TIMER_SRC_AB: - update_timer_ab_src(); - break; - - case TIMER_SRC_C: - update_timer_c_src(); - break; - } -} - -void spg2xx_device::system_timer_tick() -{ - const uint16_t old = IO_IRQ_STATUS; - uint16_t check_mask = 0x0040; - IO_IRQ_STATUS |= 0x0040; - - m_2khz_divider++; - if (m_2khz_divider == 2) - { - m_2khz_divider = 0; - IO_IRQ_STATUS |= 0x0020; - check_mask |= 0x0020; - - m_1khz_divider++; - if (m_1khz_divider == 2) - { - m_1khz_divider = 0; - IO_IRQ_STATUS |= 0x0010; - check_mask |= 0x0010; - - m_4hz_divider++; - if (m_4hz_divider == 256) - { - m_4hz_divider = 0; - IO_IRQ_STATUS |= 0x0008; - check_mask |= 0x0008; - } - } - } - - const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE); - if (changed) - check_irqs(check_mask); -} - -void spg2xx_device::uart_transmit_tick() -{ - LOGMASKED(LOG_UART, "uart_transmit_tick: Transmitting %02x, setting TxReady, clearing TxBusy\n", (uint8_t)m_io_regs[0x35]); - m_uart_tx((uint8_t)m_io_regs[0x35]); - m_io_regs[0x31] |= 0x0002; - m_io_regs[0x31] &= ~0x0040; - if (BIT(m_io_regs[0x30], 1)) - { - const uint16_t old = IO_IRQ_STATUS; - IO_IRQ_STATUS |= 0x0100; - m_uart_tx_irq = true; - LOGMASKED(LOG_UART, "uart_transmit_tick: Setting UART IRQ bit\n"); - if (IO_IRQ_STATUS != old) - { - LOGMASKED(LOG_UART, "uart_transmit_tick: Bit newly set, checking IRQs\n"); - check_irqs(0x0100); - } } } -void spg2xx_device::uart_receive_tick() -{ - LOGMASKED(LOG_UART, "uart_receive_tick: Setting RBF and RxRDY\n"); - m_io_regs[0x31] |= 0x81; - m_uart_rx_available = true; - if (BIT(m_io_regs[0x30], 0)) - { - LOGMASKED(LOG_UART, "uart_receive_tick: RxIntEn is set, setting rx_irq to true and setting UART IRQ\n"); - m_uart_rx_irq = true; - IO_IRQ_STATUS |= 0x0100; - check_irqs(0x0100); - } -} - -void spg2xx_device::extint_w(int channel, bool state) -{ - LOGMASKED(LOG_EXTINT, "Setting extint channel %d to %s\n", channel, state ? "true" : "false"); - bool old = m_extint[channel]; - m_extint[channel] = state; - if (old != state) - { - check_extint_irq(channel); - } -} - -void spg2xx_device::check_extint_irq(int channel) -{ - LOGMASKED(LOG_EXTINT, "%sing extint %d interrupt\n", m_extint[channel] ? "rais" : "lower", channel + 1); - const uint16_t mask = (channel == 0) ? 0x0200 : 0x1000; - const uint16_t old_irq = IO_IRQ_STATUS; - if (m_extint[channel]) - IO_IRQ_STATUS |= mask; - else - IO_IRQ_STATUS &= ~mask; - - if (old_irq != IO_IRQ_STATUS) - { - LOGMASKED(LOG_EXTINT, "extint IRQ changed, so checking interrupts\n"); - check_irqs(mask); - } -} void spg2xx_device::check_irqs(const uint16_t changed) { @@ -2049,6 +1038,7 @@ void spg2xx_device::check_irqs(const uint16_t changed) // m_cpu->set_state_unsynced(UNSP_IRQ1_LINE, ASSERT_LINE); // } +#if 0 if (changed & 0x0c00) // Timer A, Timer B IRQ { LOGMASKED(LOG_TIMERS, "%ssserting IRQ2 (%04x, %04x)\n", (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x0c00) ? "A" : "Dea", (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x0c00), changed); @@ -2078,86 +1068,7 @@ void spg2xx_device::check_irqs(const uint16_t changed) LOGMASKED(LOG_IRQS, "%ssserting IRQ7 (%04x, %04x)\n", (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x008b) ? "A" : "Dea", (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x008b), changed); m_cpu->set_state_unsynced(UNSP_IRQ7_LINE, (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x008b) ? ASSERT_LINE : CLEAR_LINE); } -} - -uint16_t spg2xx_device::do_special_gpio(uint32_t index, uint16_t mask) -{ - uint16_t data = 0; - switch (index) - { - case 0: // Port A - if (mask & 0xe000) - { - const uint8_t csel = m_cpu->get_csb() & 0x0e; - data = (csel << 12) & mask; - } - break; - case 1: // Port B - // To do - break; - case 2: // Port C - // To do - break; - default: - // Can't happen - break; - } - return data; -} - -void spg2xx_device::do_gpio(uint32_t offset, bool write) -{ - uint32_t index = (offset - 1) / 5; - uint16_t buffer = m_io_regs[5 * index + 2]; - uint16_t dir = m_io_regs[5 * index + 3]; - uint16_t attr = m_io_regs[5 * index + 4]; - uint16_t special = m_io_regs[5 * index + 5]; - - uint16_t push = dir; - uint16_t pull = ~dir; - uint16_t what = (buffer & (push | pull)); - what ^= (dir & ~attr); - what &= ~special; - - switch (index) - { - case 0: - if (write) - m_porta_out(0, what, push &~ special); - what = (what & ~pull); - if (!write) - what |= m_porta_in(0, pull &~ special) & pull; - break; - case 1: - if (write) - m_portb_out(0, what, push &~ special); - what = (what & ~pull); - if (!write) - what |= m_portb_in(0, pull &~ special) & pull; - break; - case 2: - if (write) - m_portc_out(0, what, push &~ special); - what = (what & ~pull); - if (!write) - what |= m_portc_in(0, pull &~ special) & pull; - break; - } - - what |= do_special_gpio(index, special); - m_io_regs[5 * index + 1] = what; -} - -void spg2xx_device::do_i2c() -{ - const uint16_t addr = ((m_io_regs[0x5b] & 0x06) << 7) | (uint8_t)m_io_regs[0x5c]; - - if (m_io_regs[0x58] & 0x40) // Serial EEPROM read - m_io_regs[0x5e] = m_eeprom_r(addr); - else - m_eeprom_w(addr, m_io_regs[0x5d]); - - m_io_regs[0x59] |= 1; +#endif } void spg2xx_device::do_cpu_dma(uint32_t len) @@ -2187,4 +1098,7 @@ void spg2xx_device::device_add_mconfig(machine_config &config) 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); + + SPG24X_IO(config, m_spg_io, DERIVED_CLOCK(1, 1), m_cpu, m_screen); + } diff --git a/src/devices/machine/spg2xx.h b/src/devices/machine/spg2xx.h index 714ff11958d..8d97cd30135 100644 --- a/src/devices/machine/spg2xx.h +++ b/src/devices/machine/spg2xx.h @@ -36,6 +36,7 @@ #include "cpu/unsp/unsp.h" #include "spg2xx_audio.h" +#include "spg2xx_io.h" #include "screen.h" class spg2xx_device : public device_t, public device_mixer_interface @@ -72,6 +73,7 @@ public: DECLARE_WRITE_LINE_MEMBER(vblank); required_device m_spg_audio; + required_device m_spg_io; protected: spg2xx_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, const uint32_t sprite_limit) @@ -103,8 +105,8 @@ protected: DECLARE_READ16_MEMBER(video_r); DECLARE_WRITE16_MEMBER(video_w); - virtual DECLARE_READ16_MEMBER(io_r); - virtual DECLARE_WRITE16_MEMBER(io_w); +// virtual DECLARE_READ16_MEMBER(io_r); +// virtual DECLARE_WRITE16_MEMBER(io_w); DECLARE_READ16_MEMBER(dma_r); DECLARE_WRITE16_MEMBER(dma_w); @@ -112,42 +114,42 @@ protected: DECLARE_WRITE_LINE_MEMBER(audioirq_w); DECLARE_READ16_MEMBER(space_r); - void check_extint_irq(int channel); +// void check_extint_irq(int channel); void check_irqs(const uint16_t changed); inline void check_video_irq(); void spg2xx_map(address_map &map); - static const device_timer_id TIMER_TMB1 = 0; - static const device_timer_id TIMER_TMB2 = 1; +// static const device_timer_id TIMER_TMB1 = 0; +// static const device_timer_id TIMER_TMB2 = 1; static const device_timer_id TIMER_SCREENPOS = 2; - static const device_timer_id TIMER_BEAT = 3; - static const device_timer_id TIMER_UART_TX = 4; - static const device_timer_id TIMER_UART_RX = 5; - static const device_timer_id TIMER_4KHZ = 6; - static const device_timer_id TIMER_SRC_AB = 7; - static const device_timer_id TIMER_SRC_C = 8; +// static const device_timer_id TIMER_BEAT = 3; +// static const device_timer_id TIMER_UART_TX = 4; +// static const device_timer_id TIMER_UART_RX = 5; +// static const device_timer_id TIMER_4KHZ = 6; +// static const device_timer_id TIMER_SRC_AB = 7; +// static const device_timer_id TIMER_SRC_C = 8; virtual void device_start() override; virtual void device_reset() override; virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; - void update_porta_special_modes(); - void update_portb_special_modes(); - void do_gpio(uint32_t offset, bool write); - uint16_t do_special_gpio(uint32_t index, uint16_t mask); +// void update_porta_special_modes(); +// void update_portb_special_modes(); +// void do_gpio(uint32_t offset, bool write); +// uint16_t do_special_gpio(uint32_t index, uint16_t mask); - void update_timer_b_rate(); - void update_timer_ab_src(); - void update_timer_c_src(); - void increment_timer_a(); +// void update_timer_b_rate(); +// void update_timer_ab_src(); +// void update_timer_c_src(); +// void increment_timer_a(); - void uart_transmit_tick(); - void uart_receive_tick(); +// void uart_transmit_tick(); +// void uart_receive_tick(); - void system_timer_tick(); +// void system_timer_tick(); - void do_i2c(); +// void do_i2c(); void do_cpu_dma(uint32_t len); void do_sprite_dma(uint32_t len); @@ -194,17 +196,17 @@ protected: uint8_t m_sprite_index_to_debug; - uint16_t m_io_regs[0x100]; +// uint16_t m_io_regs[0x100]; uint16_t m_dma_regs[0x4]; - uint8_t m_uart_rx_fifo[8]; - uint8_t m_uart_rx_fifo_start; - uint8_t m_uart_rx_fifo_end; - uint8_t m_uart_rx_fifo_count; - bool m_uart_rx_available; - bool m_uart_rx_irq; - bool m_uart_tx_irq; +// uint8_t m_uart_rx_fifo[8]; +// uint8_t m_uart_rx_fifo_start; +// uint8_t m_uart_rx_fifo_end; +// uint8_t m_uart_rx_fifo_count; +// bool m_uart_rx_available; +// bool m_uart_rx_irq; +// bool m_uart_tx_irq; - bool m_extint[2]; +// bool m_extint[2]; uint16_t m_video_regs[0x100]; uint32_t m_sprite_limit; @@ -227,25 +229,25 @@ protected: devcb_write8 m_chip_sel; - uint16_t m_timer_a_preload; - uint16_t m_timer_b_preload; - uint16_t m_timer_b_divisor; - uint16_t m_timer_b_tick_rate; +// uint16_t m_timer_a_preload; +// uint16_t m_timer_b_preload; +// uint16_t m_timer_b_divisor; +// uint16_t m_timer_b_tick_rate; - emu_timer *m_tmb1; - emu_timer *m_tmb2; - emu_timer *m_timer_src_ab; - emu_timer *m_timer_src_c; +// emu_timer *m_tmb1; +// emu_timer *m_tmb2; +// emu_timer *m_timer_src_ab; +// emu_timer *m_timer_src_c; emu_timer *m_screenpos_timer; - emu_timer *m_4khz_timer; - uint32_t m_2khz_divider; - uint32_t m_1khz_divider; - uint32_t m_4hz_divider; +// emu_timer *m_4khz_timer; +// uint32_t m_2khz_divider; +// uint32_t m_1khz_divider; +// uint32_t m_4hz_divider; - uint32_t m_uart_baud_rate; - emu_timer *m_uart_tx_timer; - emu_timer *m_uart_rx_timer; +// uint32_t m_uart_baud_rate; +// emu_timer *m_uart_tx_timer; +// emu_timer *m_uart_rx_timer; required_device m_cpu; required_device m_screen; @@ -281,7 +283,7 @@ public: spg28x_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - virtual DECLARE_WRITE16_MEMBER(io_w) override; + //virtual DECLARE_WRITE16_MEMBER(io_w) override; }; DECLARE_DEVICE_TYPE(SPG24X, spg24x_device) diff --git a/src/devices/machine/spg2xx_io.cpp b/src/devices/machine/spg2xx_io.cpp new file mode 100644 index 00000000000..e0c777c80cb --- /dev/null +++ b/src/devices/machine/spg2xx_io.cpp @@ -0,0 +1,1270 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz + +#include "emu.h" +#include "spg2xx_io.h" + +DEFINE_DEVICE_TYPE(SPG24X_IO, spg24x_io_device, "spg24x_io", "SPG240-series System-on-a-Chip I/O") +DEFINE_DEVICE_TYPE(SPG28X_IO, spg28x_io_device, "spg28x_io", "SPG280-series System-on-a-Chip I/O") + +#define LOG_IO_READS (1U << 1) +#define LOG_IO_WRITES (1U << 2) +#define LOG_UNKNOWN_IO (1U << 3) +#define LOG_IRQS (1U << 4) +#define LOG_VLINES (1U << 5) +#define LOG_GPIO (1U << 6) +#define LOG_UART (1U << 7) +#define LOG_I2C (1U << 8) +#define LOG_DMA (1U << 9) +#define LOG_SEGMENT (1U << 10) +#define LOG_WATCHDOG (1U << 11) +#define LOG_TIMERS (1U << 12) +#define LOG_SPU_READS (1U << 13) +#define LOG_SPU_WRITES (1U << 14) +#define LOG_UNKNOWN_SPU (1U << 15) +#define LOG_CHANNEL_READS (1U << 16) +#define LOG_CHANNEL_WRITES (1U << 17) +#define LOG_ENVELOPES (1U << 18) +#define LOG_SAMPLES (1U << 19) +#define LOG_RAMPDOWN (1U << 20) +#define LOG_BEAT (1U << 21) +#define LOG_PPU_READS (1U << 22) +#define LOG_PPU_WRITES (1U << 23) +#define LOG_UNKNOWN_PPU (1U << 24) +#define LOG_FIQ (1U << 25) +#define LOG_SIO (1U << 26) +#define LOG_EXT_MEM (1U << 27) +#define LOG_EXTINT (1U << 28) +#define LOG_IO (LOG_IO_READS | LOG_IO_WRITES | LOG_IRQS | LOG_GPIO | LOG_UART | LOG_I2C | LOG_DMA | LOG_TIMERS | LOG_EXTINT | LOG_UNKNOWN_IO) +#define LOG_CHANNELS (LOG_CHANNEL_READS | LOG_CHANNEL_WRITES) +#define LOG_SPU (LOG_SPU_READS | LOG_SPU_WRITES | LOG_UNKNOWN_SPU | LOG_CHANNEL_READS | LOG_CHANNEL_WRITES \ + | LOG_ENVELOPES | LOG_SAMPLES | LOG_RAMPDOWN | LOG_BEAT) +#define LOG_PPU (LOG_PPU_READS | LOG_PPU_WRITES | LOG_UNKNOWN_PPU) +#define LOG_ALL (LOG_IO | LOG_SPU | LOG_PPU | LOG_VLINES | LOG_SEGMENT | LOG_FIQ) + +#define VERBOSE (0) +#include "logmacro.h" + + +#define IO_IRQ_ENABLE m_io_regs[0x21] +#define IO_IRQ_STATUS m_io_regs[0x22] + +spg2xx_io_device::spg2xx_io_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, type, tag, owner, clock) + , m_porta_out(*this) + , m_portb_out(*this) + , m_portc_out(*this) + , m_porta_in(*this) + , m_portb_in(*this) + , m_portc_in(*this) + , m_adc_in{{*this}, {*this}} + , m_eeprom_w(*this) + , m_eeprom_r(*this) + , m_uart_tx(*this) + , m_chip_sel(*this) + , m_cpu(*this, finder_base::DUMMY_TAG) + , m_screen(*this, finder_base::DUMMY_TAG) +{ +} + +spg24x_io_device::spg24x_io_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : spg2xx_io_device(mconfig, SPG24X_IO, tag, owner, clock, 256) +{ +} + +spg28x_io_device::spg28x_io_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : spg2xx_io_device(mconfig, SPG28X_IO, tag, owner, clock, 64) +{ +} + + +void spg2xx_io_device::device_start() +{ + m_porta_out.resolve_safe(); + m_portb_out.resolve_safe(); + m_portc_out.resolve_safe(); + m_porta_in.resolve_safe(0); + m_portb_in.resolve_safe(0); + m_portc_in.resolve_safe(0); + m_adc_in[0].resolve_safe(0x0fff); + m_adc_in[1].resolve_safe(0x0fff); + m_eeprom_w.resolve_safe(); + m_eeprom_r.resolve_safe(0); + m_uart_tx.resolve_safe(); + m_chip_sel.resolve_safe(); + + m_tmb1 = timer_alloc(TIMER_TMB1); + m_tmb2 = timer_alloc(TIMER_TMB2); + m_tmb1->adjust(attotime::never); + m_tmb2->adjust(attotime::never); + + m_uart_tx_timer = timer_alloc(TIMER_UART_TX); + m_uart_tx_timer->adjust(attotime::never); + + m_uart_rx_timer = timer_alloc(TIMER_UART_RX); + m_uart_rx_timer->adjust(attotime::never); + + m_4khz_timer = timer_alloc(TIMER_4KHZ); + m_4khz_timer->adjust(attotime::never); + + m_timer_src_ab = timer_alloc(TIMER_SRC_AB); + m_timer_src_ab->adjust(attotime::never); + + m_timer_src_c = timer_alloc(TIMER_SRC_C); + m_timer_src_c->adjust(attotime::never); + + save_item(NAME(m_timer_a_preload)); + save_item(NAME(m_timer_b_preload)); + save_item(NAME(m_timer_b_divisor)); + save_item(NAME(m_timer_b_tick_rate)); + + save_item(NAME(m_io_regs)); + + save_item(NAME(m_extint)); + + save_item(NAME(m_2khz_divider)); + save_item(NAME(m_1khz_divider)); + save_item(NAME(m_4hz_divider)); + + save_item(NAME(m_uart_baud_rate)); +} + +void spg2xx_io_device::device_reset() +{ + memset(m_io_regs, 0, 0x100 * sizeof(uint16_t)); + + m_timer_a_preload = 0; + m_timer_b_preload = 0; + m_timer_b_divisor = 0; + m_timer_b_tick_rate = 0; + + m_io_regs[0x23] = 0x0028; + m_io_regs[0x2c] = 0x1418; + m_io_regs[0x2d] = 0x1658; + + m_uart_rx_available = false; + memset(m_uart_rx_fifo, 0, ARRAY_LENGTH(m_uart_rx_fifo)); + m_uart_rx_fifo_start = 0; + m_uart_rx_fifo_end = 0; + m_uart_rx_fifo_count = 0; + m_uart_tx_irq = false; + m_uart_rx_irq = false; + + memset(m_extint, 0, sizeof(bool) * 2); + + m_4khz_timer->adjust(attotime::from_hz(4096), 0, attotime::from_hz(4096)); + + m_2khz_divider = 0; + m_1khz_divider = 0; + m_4hz_divider = 0; +} + +/************************* +* Machine Hardware * +*************************/ + +void spg2xx_io_device::uart_rx(uint8_t data) +{ + LOGMASKED(LOG_UART, "uart_rx: Pulling %02x into receive FIFO\n", data); + if (BIT(m_io_regs[0x30], 6)) + { + m_uart_rx_fifo[m_uart_rx_fifo_end] = data; + m_uart_rx_fifo_end = (m_uart_rx_fifo_end + 1) % ARRAY_LENGTH(m_uart_rx_fifo); + m_uart_rx_fifo_count++; + if (m_uart_rx_timer->remaining() == attotime::never) + m_uart_rx_timer->adjust(attotime::from_ticks(BIT(m_io_regs[0x30], 5) ? 11 : 10, m_uart_baud_rate)); + } +} + +READ16_MEMBER(spg2xx_io_device::io_r) +{ + static const char *const gpioregs[] = { "GPIO Data Port", "GPIO Buffer Port", "GPIO Direction Port", "GPIO Attribute Port", "GPIO IRQ/Latch Port" }; + static const char gpioports[] = { 'A', 'B', 'C' }; + + uint16_t val = m_io_regs[offset]; + + switch (offset) + { + case 0x01: case 0x06: case 0x0b: // GPIO Data Port A/B/C + do_gpio(offset, false); + LOGMASKED(LOG_GPIO, "%s: io_r: %s %c = %04x\n", machine().describe_context(), gpioregs[(offset - 1) % 5], gpioports[(offset - 1) / 5], m_io_regs[offset]); + val = m_io_regs[offset]; + break; + + case 0x02: case 0x03: case 0x04: case 0x05: + case 0x07: case 0x08: case 0x09: case 0x0a: + case 0x0c: case 0x0d: case 0x0e: case 0x0f: // Other GPIO regs + LOGMASKED(LOG_GPIO, "%s: io_r: %s %c = %04x\n", machine().describe_context(), gpioregs[(offset - 1) % 5], gpioports[(offset - 1) / 5], m_io_regs[offset]); + break; + + case 0x10: // Timebase Control + LOGMASKED(LOG_IO_READS, "io_r: Timebase Control = %04x\n", val); + break; + + case 0x12: // Timer A Data + LOGMASKED(LOG_IO_WRITES, "io_r: Timer A Data = %04x\n", val); + break; + + case 0x1c: // Video line counter + val = m_screen->vpos(); + LOGMASKED(LOG_VLINES, "io_r: Video Line = %04x\n", val); + break; + + case 0x20: // System Control + LOGMASKED(LOG_IO_READS, "io_r: System Control = %04x\n", val); + break; + + case 0x21: // IRQ Control + LOGMASKED(LOG_IRQS, "%s: io_r: I/O IRQ Control = %04x\n", machine().describe_context(), val); + break; + + case 0x22: // IRQ Status + LOGMASKED(LOG_IRQS, "%s: io_r: I/O IRQ Status = %04x\n", machine().describe_context(), val); + break; + + case 0x23: // External Memory Control + LOGMASKED(LOG_IO_READS, "%s: io_r: Ext. Memory Control = %04x\n", machine().describe_context(), val); + break; + + case 0x25: // ADC Control + LOGMASKED(LOG_IO_READS, "io_r: ADC Control = %04x\n", val); + break; + + case 0x27: // ADC Data + { + m_io_regs[0x27] = 0; + const uint16_t old = IO_IRQ_STATUS; + IO_IRQ_STATUS &= ~0x2000; + const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE); + if (changed) + check_irqs(changed); + LOGMASKED(LOG_IO_READS, "%s: io_r: ADC Data = %04x\n", machine().describe_context(), val); + break; + } + + case 0x29: // Wakeup Source + LOGMASKED(LOG_IO_READS, "io_r: Wakeup Source = %04x\n", val); + break; + + case 0x2b: + LOGMASKED(LOG_IO_READS, "io_r: NTSC/PAL = %04x\n", m_pal_flag); + return m_pal_flag; + + case 0x2c: // PRNG 0 + { + const uint16_t value = m_io_regs[0x2c]; + m_io_regs[0x2c] = ((value << 1) | (BIT(value, 14) ^ BIT(value, 13))) & 0x7fff; + return value; + } + + case 0x2d: // PRNG 1 + { + const uint16_t value = m_io_regs[0x2d]; + m_io_regs[0x2d] = ((value << 1) | (BIT(value, 14) ^ BIT(value, 13))) & 0x7fff; + return value; + } + + case 0x2e: // FIQ Source Select + LOGMASKED(LOG_FIQ, "io_r: FIQ Source Select = %04x\n", val); + break; + + case 0x2f: // Data Segment + val = m_cpu->get_ds(); + LOGMASKED(LOG_SEGMENT, "io_r: Data Segment = %04x\n", val); + break; + + case 0x30: // UART Control + LOGMASKED(LOG_UART, "%s: io_r: UART Control = %04x\n", machine().describe_context(), val); + break; + + case 0x31: // UART Status + //LOGMASKED(LOG_UART, "%s: io_r: UART Status = %04x\n", machine().describe_context(), val); + break; + + case 0x36: // UART RX Data + if (m_uart_rx_available) + { + m_io_regs[0x31] &= ~0x0081; + LOGMASKED(LOG_UART, "UART Rx data is available, clearing bits\n"); + if (m_uart_rx_fifo_count) + { + LOGMASKED(LOG_UART, "Remaining count %d, value %02x\n", m_uart_rx_fifo_count, m_uart_rx_fifo[m_uart_rx_fifo_start]); + m_io_regs[0x36] = m_uart_rx_fifo[m_uart_rx_fifo_start]; + val = m_io_regs[0x36]; + m_uart_rx_fifo_start = (m_uart_rx_fifo_start + 1) % ARRAY_LENGTH(m_uart_rx_fifo); + m_uart_rx_fifo_count--; + + if (m_uart_rx_fifo_count == 0) + { + m_uart_rx_available = false; + } + else + { + LOGMASKED(LOG_UART, "Remaining count %d, setting up timer\n", m_uart_rx_fifo_count); + //uart_receive_tick(); + if (m_uart_rx_timer->remaining() == attotime::never) + m_uart_rx_timer->adjust(attotime::from_ticks(BIT(m_io_regs[0x30], 5) ? 11 : 10, m_uart_baud_rate)); + } + } + else + { + m_uart_rx_available = false; + } + } + else + { + m_io_regs[0x37] |= 0x2000; + } + LOGMASKED(LOG_UART, "%s: io_r: UART Rx Data = %04x\n", machine().describe_context(), val); + break; + + case 0x37: // UART Rx FIFO Control + val &= ~0x0070; + val |= (m_uart_rx_available ? 7 : 0) << 4; + LOGMASKED(LOG_UART, "io_r: UART Rx FIFO Control = %04x\n", machine().describe_context(), val); + break; + + case 0x51: // unknown, polled by ClickStart cartridges ( clikstrt ) + return 0x8000; + + case 0x59: // I2C Status + LOGMASKED(LOG_I2C, "io_r: I2C Status = %04x\n", val); + break; + + case 0x5e: // I2C Data In + LOGMASKED(LOG_I2C, "io_r: I2C Data In = %04x\n", val); + break; + + default: + LOGMASKED(LOG_UNKNOWN_IO, "io_r: Unknown register %04x\n", 0x3d00 + offset); + break; + } + + return val; +} + +void spg2xx_io_device::update_porta_special_modes() +{ + static const char* const s_pa_special[4][16] = + { + // Input, Special 0 + // Input, Special 1 + // Output, Special 0 + // Output, Special 1 + + { "LP", "ExtClk2", "ExtClk1", "-", "SDA", "SlvRDY", "-", "-", "SPICLK", "-", "RxD", "SPISSB", "-", "-", "-", "-" }, + { "-", "-", "-", "SCK", "-", "SWS", "-", "-", "-", "-", "-", "-", "IRQ2B", "-", "-", "IRQ1B" }, + { "-", "-", "-", "SCK", "SDA", "SWS", "-", "-", "SPICLK", "TxD", "-", "SPISSB", "TAPWM", "TM1", "TBPWM", "TM2" }, + { "CSB3", "CSB2", "CSB1", "SCK", "SDA", "VSYNC", "HSYNC", "SYSCLK3", "SPICLK", "TxD", "SWS", "SPISSB", "-", "VSYNC", "HSYNC", "CSYNC" }, + }; + for (int bit = 15; bit >= 0; bit--) + { + if (!BIT(m_io_regs[0x05], bit)) + continue; + uint8_t type = (BIT(m_io_regs[0x03], bit) << 1) | BIT(m_io_regs[0x00], 0); + LOGMASKED(LOG_GPIO, " Bit %2d: %s\n", bit, s_pa_special[type][bit]); + } +} + +void spg2xx_io_device::update_portb_special_modes() +{ + static const char* const s_pb_special[4][8] = + { + // Input, Special 0 + // Input, Special 1 + // Output, Special 0 + // Output, Special 1 + + { "-", "-", "-", "-", "-", "-", "SDA", "SlvRDY" }, + { "-", "-", "-", "-", "-", "-", "SDA", "SlvRDY" }, + { "VSYNC", "HSYNC", "CSYNC", "-", "-", "SCK", "SDA", "SWS" }, + { "CSB3", "CSB2", "CSB1", "TBPWM", "TM2", "-", "-", "SYSCLK2" }, + }; + for (int bit = 7; bit >= 0; bit--) + { + if (!BIT(m_io_regs[0x0a], bit)) + continue; + uint8_t type = (BIT(m_io_regs[0x08], bit) << 1) | BIT(m_io_regs[0x00], 1); + LOGMASKED(LOG_GPIO, " Bit %2d: %s\n", bit, s_pb_special[type][bit]); + } +} + +void spg2xx_io_device::update_timer_b_rate() +{ + switch (m_io_regs[0x17] & 7) + { + case 0: + case 1: + case 5: + case 6: + case 7: + m_timer_src_c->adjust(attotime::never); + break; + case 2: + m_timer_src_c->adjust(attotime::from_hz(32768), 0, attotime::from_hz(32768)); + break; + case 3: + m_timer_src_c->adjust(attotime::from_hz(8192), 0, attotime::from_hz(8192)); + break; + case 4: + m_timer_src_c->adjust(attotime::from_hz(4096), 0, attotime::from_hz(4096)); + break; + } +} + +void spg2xx_io_device::update_timer_ab_src() +{ + if (m_timer_b_tick_rate == 0) + return; + + m_timer_b_divisor++; + if (m_timer_b_divisor >= m_timer_b_tick_rate) + { + m_timer_b_divisor = 0; + increment_timer_a(); + } +} + +void spg2xx_io_device::increment_timer_a() +{ + m_io_regs[0x12]++; + if (m_io_regs[0x12] == 0) + { + m_io_regs[0x12] = m_timer_a_preload; + const uint16_t old = IO_IRQ_STATUS; + IO_IRQ_STATUS |= 0x0800; + const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE); + if (changed) + { + //printf("Timer A overflow\n"); + check_irqs(0x0800); + } + } +} + +void spg2xx_io_device::update_timer_c_src() +{ + m_io_regs[0x16]++; + if (m_io_regs[0x16] == 0) + { + m_io_regs[0x16] = m_timer_b_preload; + const uint16_t old = IO_IRQ_STATUS; + IO_IRQ_STATUS |= 0x0400; + const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE); + if (changed) + { + printf("Timer B overflow\n"); + check_irqs(0x0400); + } + } +} + + +WRITE16_MEMBER(spg28x_io_device::io_w) +{ + if (offset == 0x33) + { + m_io_regs[offset] = data; + m_uart_baud_rate = 27000000 / (0x10000 - m_io_regs[0x33]); + LOGMASKED(LOG_UART, "%s: io_w: UART Baud Rate scaler = %04x (%d baud)\n", machine().describe_context(), data, m_uart_baud_rate); + } + else + { + spg2xx_io_device::io_w(space, offset, data, mem_mask); + } +} + +WRITE16_MEMBER(spg2xx_io_device::io_w) +{ + static const char *const gpioregs[] = { "GPIO Data Port", "GPIO Buffer Port", "GPIO Direction Port", "GPIO Attribute Port", "GPIO IRQ/Latch Port" }; + static const char gpioports[3] = { 'A', 'B', 'C' }; + + switch (offset) + { + case 0x00: // GPIO special function select + { + LOGMASKED(LOG_GPIO, "%s: io_w: GPIO Configuration = %04x (IOBWake:%d, IOAWake:%d, IOBSpecSel:%d, IOASpecSel:%d)\n", machine().describe_context(), data + , BIT(data, 4), BIT(data, 3), BIT(data, 1), BIT(data, 0)); + const uint16_t old = m_io_regs[offset]; + m_io_regs[offset] = data; + const uint16_t changed = old ^ data; + if (BIT(changed, 0)) + update_porta_special_modes(); + if (BIT(changed, 1)) + update_portb_special_modes(); + break; + } + + case 0x01: case 0x06: case 0x0b: // GPIO data, port A/B/C + offset++; + // Intentional fallthrough - we redirect data register writes to the buffer register. + + case 0x02: case 0x04: // Port A + case 0x07: case 0x09: // Port B + case 0x0c: case 0x0d: case 0x0e: case 0x0f: // Port C + LOGMASKED(LOG_GPIO, "%s: io_w: %s %c = %04x\n", machine().describe_context(), gpioregs[(offset - 1) % 5], gpioports[(offset - 1) / 5], data); + m_io_regs[offset] = data; + do_gpio(offset, true); + break; + + case 0x03: // Port A Direction + LOGMASKED(LOG_GPIO, "%s: io_w: GPIO Direction Port A = %04x\n", machine().describe_context(), data); + m_io_regs[offset] = data; + update_porta_special_modes(); + do_gpio(offset, true); + break; + + case 0x08: // Port B Direction + LOGMASKED(LOG_GPIO, "%s: io_w: GPIO Direction Port B = %04x\n", machine().describe_context(), data); + m_io_regs[offset] = data; + update_portb_special_modes(); + do_gpio(offset, true); + break; + + case 0x05: // Port A Special + LOGMASKED(LOG_GPIO, "%s: io_w: Port A Special Function Select: %04x\n", machine().describe_context(), data); + m_io_regs[offset] = data; + update_porta_special_modes(); + break; + + case 0x0a: // Port B Special + LOGMASKED(LOG_GPIO, "%s: io_w: Port B Special Function Select: %04x\n", machine().describe_context(), data); + m_io_regs[offset] = data; + update_portb_special_modes(); + break; + + case 0x10: // Timebase Control + { + static const char* const s_tmb1_sel[2][4] = + { + { "8Hz", "16Hz", "32Hz", "64Hz" }, + { "12kHz", "24kHz", "40kHz", "40kHz" } + }; + static const char* const s_tmb2_sel[2][4] = + { + { "128Hz", "256Hz", "512Hz", "1024Hz" }, + { "105kHz", "210kHz", "420kHz", "840kHz" } + }; + static const uint32_t s_tmb1_freq[2][4] = + { + { 8, 16, 32, 64 }, + { 12000, 24000, 40000, 40000 } + }; + static const uint32_t s_tmb2_freq[2][4] = + { + { 128, 256, 512, 1024 }, + { 105000, 210000, 420000, 840000 } + }; + LOGMASKED(LOG_TIMERS, "io_w: Timebase Control = %04x (Source:%s, TMB2:%s, TMB1:%s)\n", data, + BIT(data, 4) ? "27MHz" : "32768Hz", s_tmb2_sel[BIT(data, 4)][(data >> 2) & 3], s_tmb1_sel[BIT(data, 4)][data & 3]); + m_io_regs[offset] = data; + const uint8_t hifreq = BIT(data, 4); + const uint32_t tmb1freq = s_tmb1_freq[hifreq][data & 3]; + m_tmb1->adjust(attotime::from_hz(tmb1freq), 0, attotime::from_hz(tmb1freq)); + const uint32_t tmb2freq = s_tmb2_freq[hifreq][(data >> 2) & 3]; + m_tmb2->adjust(attotime::from_hz(tmb2freq), 0, attotime::from_hz(tmb2freq)); + break; + } + + case 0x11: // Timebase Clear + LOGMASKED(LOG_TIMERS, "io_w: Timebase Clear = %04x\n", data); + break; + + case 0x12: // Timer A Data + LOGMASKED(LOG_TIMERS, "io_w: Timer A Data = %04x\n", data); + m_io_regs[offset] = data; + m_timer_a_preload = data; + break; + + case 0x13: // Timer A Control + { + static const char* const s_source_a[8] = { "0", "0", "32768Hz", "8192Hz", "4096Hz", "1", "0", "ExtClk1" }; + static const char* const s_source_b[8] = { "2048Hz", "1024Hz", "256Hz", "TMB1", "4Hz", "2Hz", "1", "ExtClk2" }; + LOGMASKED(LOG_TIMERS, "io_w: Timer A Control = %04x (Source A:%s, Source B:%s)\n", data, + s_source_a[data & 7], s_source_b[(data >> 3) & 7]); + m_io_regs[offset] = data; + int timer_a_rate = 0; + switch (data & 7) + { + case 0: + case 1: + case 5: + case 6: + case 7: + m_timer_src_ab->adjust(attotime::never); + break; + case 2: + m_timer_src_ab->adjust(attotime::from_hz(32768), 0, attotime::from_hz(32768)); + timer_a_rate = 32768; + break; + case 3: + m_timer_src_ab->adjust(attotime::from_hz(8192), 0, attotime::from_hz(8192)); + timer_a_rate = 8192; + break; + case 4: + m_timer_src_ab->adjust(attotime::from_hz(4096), 0, attotime::from_hz(4096)); + timer_a_rate = 4096; + break; + } + switch ((data >> 3) & 7) + { + case 0: + m_timer_b_tick_rate = timer_a_rate / 2048; + break; + case 1: + m_timer_b_tick_rate = timer_a_rate / 1024; + break; + case 2: + m_timer_b_tick_rate = timer_a_rate / 256; + break; + case 3: + m_timer_b_tick_rate = 0; + break; + case 4: + m_timer_b_tick_rate = timer_a_rate / 4; + break; + case 5: + m_timer_b_tick_rate = timer_a_rate / 2; + break; + case 6: + m_timer_b_tick_rate = 1; + break; + case 7: + m_timer_b_tick_rate = 0; + break; + } + break; + } + + case 0x15: // Timer A IRQ Clear + { + LOGMASKED(LOG_TIMERS, "io_w: Timer A IRQ Clear\n"); + const uint16_t old = IO_IRQ_STATUS; + IO_IRQ_STATUS &= ~0x0800; + const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE); + if (changed) + check_irqs(0x0800); + break; + } + + case 0x16: // Timer B Data + LOGMASKED(LOG_TIMERS, "io_w: Timer B Data = %04x\n", data); + m_io_regs[offset] = data; + m_timer_b_preload = data; + break; + + case 0x17: // Timer B Control + { + static const char* const s_source_c[8] = { "0", "0", "32768Hz", "8192Hz", "4096Hz", "1", "0", "ExtClk1" }; + LOGMASKED(LOG_TIMERS, "io_w: Timer B Control = %04x (Source C:%s)\n", data, s_source_c[data & 7]); + m_io_regs[offset] = data; + if (m_io_regs[0x18] == 1) + { + update_timer_b_rate(); + } + break; + } + + case 0x18: // Timer B Enable + { + LOGMASKED(LOG_TIMERS, "io_w: Timer B Enable = %04x\n", data); + m_io_regs[offset] = data & 1; + if (data & 1) + { + update_timer_b_rate(); + } + else + { + m_timer_src_c->adjust(attotime::never); + } + break; + } + + case 0x19: // Timer B IRQ Clear + { + LOGMASKED(LOG_TIMERS, "io_w: Timer B IRQ Clear\n"); + const uint16_t old = IO_IRQ_STATUS; + IO_IRQ_STATUS &= ~0x0400; + const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE); + if (changed) + check_irqs(0x0400); + break; + } + + case 0x20: // System Control + { + static const char* const s_sysclk[4] = { "13.5MHz", "27MHz", "27MHz NoICE", "54MHz" }; + static const char* const s_lvd_voltage[4] = { "2.7V", "2.9V", "3.1V", "3.3V" }; + static const char* const s_weak_strong[2] = { "Weak", "Strong" }; + LOGMASKED(LOG_IO_WRITES, "io_w: System Control = %04x (Watchdog:%d, Sleep:%d, SysClk:%s, SysClkInv:%d, LVROutEn:%d, LVREn:%d\n" + , data, BIT(data, 15), BIT(data, 14), s_sysclk[(data >> 12) & 3], BIT(data, 11), BIT(data, 9), BIT(data, 8)); + LOGMASKED(LOG_IO_WRITES, " LVDEn:%d, LVDVoltSel:%s, 32kHzDisable:%d, StrWkMode:%s, VDACDisable:%d, ADACDisable:%d, ADACOutDisable:%d)\n" + , BIT(data, 7), s_lvd_voltage[(data >> 5) & 3], BIT(data, 4), s_weak_strong[BIT(data, 3)], BIT(data, 2), BIT(data, 1), BIT(data, 0)); + m_io_regs[offset] = data; + break; + } + + case 0x21: // IRQ Enable + { + LOGMASKED(LOG_IRQS, "io_w: IRQ Enable = %04x\n", data); + const uint16_t old = IO_IRQ_ENABLE; + m_io_regs[offset] = data; + const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE); + if (changed) + check_irqs(changed); + break; + } + + case 0x22: // IRQ Acknowledge + { + LOGMASKED(LOG_IRQS, "io_w: IRQ Acknowledge = %04x\n", data); + const uint16_t old = IO_IRQ_STATUS; + IO_IRQ_STATUS &= ~data; + const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE); + if (m_uart_rx_irq || m_uart_tx_irq) + { + LOGMASKED(LOG_IRQS | LOG_UART, "Re-setting UART IRQ due to still-unacknowledged Rx or Tx.\n"); + IO_IRQ_STATUS |= 0x0100; + } + if (changed) + check_irqs(changed); + break; + } + + case 0x23: // External Memory Control + { + static const char* const s_bus_arb[8] = + { + "Forbidden", "Forbidden", "Forbidden", "Forbidden", "Forbidden", "1:SPU/2:PPU/3:CPU", "Forbidden", "1:PPU/2:SPU/3:CPU" + }; + static const char* const s_addr_decode[4] = + { + "ROMCSB: 4000-3fffff, CSB1: ---, CSB2: ---, CSB3: ---", + "ROMCSB: 4000-1fffff, CSB1: 200000-3fffff, CSB2: ---, CSB3: ---", + "ROMCSB: 4000-0fffff, CSB1: 100000-1fffff, CSB2: 200000-2fffff, CSB3: 300000-3fffff", + "ROMCSB: 4000-0fffff, CSB1: 100000-1fffff, CSB2: 200000-2fffff, CSB3: 300000-3fffff" + }; + static const char* const s_ram_decode[16] = + { + "None", "None", "None", "None", "None", "None", "None", "None", + "4KW, 3ff000-3fffff\n", + "8KW, 3fe000-3fffff\n", + "16KW, 3fc000-3fffff\n", + "32KW, 3f8000-3fffff\n", + "64KW, 3f0000-3fffff\n", + "128KW, 3e0000-3fffff\n", + "256KW, 3c0000-3fffff\n", + "512KW, 380000-3fffff\n" + }; + LOGMASKED(LOG_EXT_MEM, "io_w: Ext. Memory Control (not yet implemented) = %04x:\n", data); + LOGMASKED(LOG_EXT_MEM, " WaitStates:%d, BusArbPrio:%s\n", (data >> 1) & 3, s_bus_arb[(data >> 3) & 7]); + LOGMASKED(LOG_EXT_MEM, " ROMAddrDecode:%s\n", s_addr_decode[(data >> 6) & 3]); + LOGMASKED(LOG_EXT_MEM, " RAMAddrDecode:%s\n", s_ram_decode[(data >> 8) & 15]); + m_chip_sel((data >> 6) & 3); + m_io_regs[offset] = data; + break; + } + + case 0x24: // Watchdog + LOGMASKED(LOG_WATCHDOG, "io_w: Watchdog Pet = %04x\n", data); + break; + + case 0x25: // ADC Control + { + LOGMASKED(LOG_IO_WRITES, "%s: io_w: ADC Control = %04x\n", machine().describe_context(), data); + m_io_regs[offset] = data & ~0x1000; + if (BIT(data, 0)) + { + m_io_regs[0x27] = 0x8000 | (m_adc_in[BIT(data, 5)]() & 0x7fff); + m_io_regs[0x25] |= 0x2000; + } + if (BIT(data, 12) && !BIT(m_io_regs[offset], 1)) + { + const uint16_t old = IO_IRQ_STATUS; + IO_IRQ_STATUS |= 0x2000; + const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE); + if (changed) + { + check_irqs(changed); + } + } + break; + } + + case 0x28: // Sleep Mode + LOGMASKED(LOG_IO_WRITES, "io_w: Sleep Mode (%s enter value) = %04x\n", data == 0xaa55 ? "valid" : "invalid", data); + m_io_regs[offset] = data; + break; + + case 0x29: // Wakeup Source + { + m_io_regs[offset] = data; + static const char* const s_sources[8] = + { + "TMB1", "TMB2", "2Hz", "4Hz", "1024Hz", "2048Hz", "4096Hz", "Key" + }; + + LOGMASKED(LOG_IO_WRITES, "io_w: Wakeup Source = %04x:\n", data); + bool comma = false; + char buf[1024]; + int char_idx = 0; + for (int i = 7; i >= 0; i--) + { + if (BIT(data, i)) + { + char_idx += sprintf(&buf[char_idx], "%s%s", comma ? ", " : "", s_sources[i]); + comma = true; + } + } + buf[char_idx] = 0; + LOGMASKED(LOG_IO_WRITES, " %s\n", buf); + break; + } + + case 0x2c: // PRNG 0 seed + LOGMASKED(LOG_IO_WRITES, "io_w: PRNG 0 seed = %04x\n", data & 0x7fff); + m_io_regs[offset] = data & 0x7fff; + break; + + case 0x2d: // PRNG 1 seed + LOGMASKED(LOG_IO_WRITES, "io_w: PRNG 1 seed = %04x\n", data & 0x7fff); + m_io_regs[offset] = data & 0x7fff; + break; + + case 0x2e: // FIQ Source Select + { + static const char* const s_fiq_select[8] = + { + "PPU", "SPU Channel", "Timer A", "Timer B", "UART/SPI", "External", "Reserved", "None" + }; + LOGMASKED(LOG_FIQ, "io_w: FIQ Source Select (not yet implemented) = %04x, %s\n", data, s_fiq_select[data & 7]); + m_io_regs[offset] = data; + break; + } + + case 0x2f: // Data Segment + m_cpu->set_ds(data & 0x3f); + LOGMASKED(LOG_SEGMENT, "io_w: Data Segment = %04x\n", data); + break; + + case 0x30: // UART Control + { + static const char* const s_9th_bit[4] = { "0", "1", "Odd", "Even" }; + LOGMASKED(LOG_UART, "%s: io_w: UART Control = %04x (TxEn:%d, RxEn:%d, Bits:%d, MultiProc:%d, 9thBit:%s, TxIntEn:%d, RxIntEn:%d\n", + machine().describe_context(), data, BIT(data, 7), BIT(data, 6), BIT(data, 5) ? 9 : 8, BIT(data, 4), s_9th_bit[(data >> 2) & 3], + BIT(data, 1), BIT(data, 0)); + const uint16_t changed = m_io_regs[offset] ^ data; + m_io_regs[offset] = data; + if (!BIT(data, 6)) + { + m_uart_rx_available = false; + m_io_regs[0x36] = 0; + } + if (BIT(changed, 7)) + { + if (BIT(data, 7)) + { + m_io_regs[0x31] |= 0x0002; + } + else + { + m_io_regs[0x31] &= ~0x0042; + m_uart_tx_timer->adjust(attotime::never); + } + } + break; + } + + case 0x31: // UART Status + LOGMASKED(LOG_UART, "%s: io_w: UART Status = %04x\n", machine().describe_context(), data); + if (BIT(data, 0)) + { + m_io_regs[0x31] &= ~1; + m_uart_rx_irq = false; + } + if (BIT(data, 1)) + { + m_io_regs[0x31] &= ~2; + m_uart_tx_irq = false; + } + if (!m_uart_rx_irq && !m_uart_tx_irq) + { + const uint16_t old = IO_IRQ_STATUS; + IO_IRQ_STATUS &= ~0x0100; + const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE); + if (changed) + check_irqs(0x0100); + } + break; + + case 0x33: // UART Baud Rate (low byte) + case 0x34: // UART Baud Rate (high byte) + { + m_io_regs[offset] = data; + const uint32_t divisor = 16 * (0x10000 - ((m_io_regs[0x34] << 8) | m_io_regs[0x33])); + LOGMASKED(LOG_UART, "%s: io_w: UART Baud Rate (%s byte): Baud rate = %d\n", offset == 0x33 ? "low" : "high", machine().describe_context(), 27000000 / divisor); + m_uart_baud_rate = 27000000 / divisor; + break; + } + + case 0x35: // UART TX Data + LOGMASKED(LOG_UART, "%s: io_w: UART Tx Data = %02x\n", machine().describe_context(), data & 0x00ff); + m_io_regs[offset] = data; + if (BIT(m_io_regs[0x30], 7)) + { + LOGMASKED(LOG_UART, "io_w: UART Tx: Clearing ready bit, setting busy bit, setting up timer\n"); + m_uart_tx_timer->adjust(attotime::from_ticks(BIT(m_io_regs[0x30], 5) ? 11 : 10, m_uart_baud_rate)); + m_io_regs[0x31] &= ~0x0002; + m_io_regs[0x31] |= 0x0040; + } + break; + + case 0x36: // UART RX Data + LOGMASKED(LOG_UART, "%s: io_w: UART Rx Data (read-only) = %04x\n", machine().describe_context(), data); + break; + + case 0x37: // UART Rx FIFO Control + LOGMASKED(LOG_UART, "%s: io_w: UART Rx FIFO Control = %04x (Reset:%d, Overrun:%d, Underrun:%d, Count:%d, Threshold:%d)\n", + machine().describe_context(), data, BIT(data, 15), BIT(data, 14), BIT(data, 13), (data >> 4) & 7, data & 7); + if (data & 0x8000) + { + m_uart_rx_available = false; + m_io_regs[0x36] = 0; + } + m_io_regs[offset] &= ~data & 0x6000; + m_io_regs[offset] &= ~0x0007; + m_io_regs[offset] |= data & 0x0007; + break; + + case 0x50: // SIO Setup + { + static const char* const s_addr_mode[4] = { "16-bit", "None", "8-bit", "24-bit" }; + static const char* const s_baud_rate[4] = { "/16", "/4", "/8", "/32" }; + LOGMASKED(LOG_SIO, "io_w: SIO Setup (not implemented) = %04x (DS301Ready:%d, Start:%d, Auto:%d, IRQEn:%d, Width:%d, Related:%d\n", data + , BIT(data, 11), BIT(data, 10), BIT(data, 9), BIT(data, 8), BIT(data, 7) ? 16 : 8, BIT(data, 6)); + LOGMASKED(LOG_SIO, " (Mode:%s, RWProtocol:%d, Rate:sysclk%s, AddrMode:%s)\n" + , BIT(data, 5), BIT(data, 4), s_baud_rate[(data >> 2) & 3], s_addr_mode[data & 3]); + break; + } + + case 0x52: // SIO Start Address (low) + LOGMASKED(LOG_SIO, "io_w: SIO Stat Address (low) (not implemented) = %04x\n", data); + break; + + case 0x53: // SIO Start Address (hi) + LOGMASKED(LOG_SIO, "io_w: SIO Stat Address (hi) (not implemented) = %04x\n", data); + break; + + case 0x54: // SIO Data + LOGMASKED(LOG_SIO, "io_w: SIO Data (not implemented) = %04x\n", data); + break; + + case 0x55: // SIO Automatic Transmit Count + LOGMASKED(LOG_SIO, "io_w: SIO Auto Transmit Count (not implemented) = %04x\n", data); + break; + + case 0x58: // I2C Command + LOGMASKED(LOG_I2C, "io_w: I2C Command = %04x\n", data); + m_io_regs[offset] = data; + do_i2c(); + break; + + case 0x59: // I2C Status / Acknowledge + LOGMASKED(LOG_I2C, "io_w: I2C Acknowledge = %04x\n", data); + m_io_regs[offset] &= ~data; + break; + + case 0x5a: // I2C Access Mode + LOGMASKED(LOG_I2C, "io_w: I2C Access Mode = %04x\n", data); + m_io_regs[offset] = data; + break; + + case 0x5b: // I2C Device Address + LOGMASKED(LOG_I2C, "io_w: I2C Device Address = %04x\n", data); + m_io_regs[offset] = data; + break; + + case 0x5c: // I2C Sub-Address + LOGMASKED(LOG_I2C, "io_w: I2C Sub-Address = %04x\n", data); + m_io_regs[offset] = data; + break; + + case 0x5d: // I2C Data Out + LOGMASKED(LOG_I2C, "io_w: I2C Data Out = %04x\n", data); + m_io_regs[offset] = data; + break; + + case 0x5e: // I2C Data In + LOGMASKED(LOG_I2C, "io_w: I2C Data In = %04x\n", data); + m_io_regs[offset] = data; + break; + + case 0x5f: // I2C Controller Mode + LOGMASKED(LOG_I2C, "io_w: I2C Controller Mode = %04x\n", data); + m_io_regs[offset] = data; + break; + + default: + LOGMASKED(LOG_UNKNOWN_IO, "io_w: Unknown register %04x = %04x\n", 0x3d00 + offset, data); + m_io_regs[offset] = data; + break; + } +} + +void spg2xx_io_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_TMB1: + { + LOGMASKED(LOG_TIMERS, "TMB1 elapsed, setting IRQ Status bit 0 (old:%04x, new:%04x, enable:%04x)\n", IO_IRQ_STATUS, IO_IRQ_STATUS | 1, IO_IRQ_ENABLE); + const uint16_t old = IO_IRQ_STATUS; + IO_IRQ_STATUS |= 1; + const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE); + if (changed) + check_irqs(0x0001); + break; + } + + case TIMER_TMB2: + { + LOGMASKED(LOG_TIMERS, "TMB2 elapsed, setting IRQ Status bit 1 (old:%04x, new:%04x, enable:%04x)\n", IO_IRQ_STATUS, IO_IRQ_STATUS | 2, IO_IRQ_ENABLE); + const uint16_t old = IO_IRQ_STATUS; + IO_IRQ_STATUS |= 2; + const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE); + if (changed) + check_irqs(0x0002); + break; + } + + case TIMER_UART_TX: + uart_transmit_tick(); + break; + + case TIMER_UART_RX: + uart_receive_tick(); + break; + + case TIMER_4KHZ: + system_timer_tick(); + break; + + case TIMER_SRC_AB: + update_timer_ab_src(); + break; + + case TIMER_SRC_C: + update_timer_c_src(); + break; + } +} + +void spg2xx_io_device::system_timer_tick() +{ + const uint16_t old = IO_IRQ_STATUS; + uint16_t check_mask = 0x0040; + IO_IRQ_STATUS |= 0x0040; + + m_2khz_divider++; + if (m_2khz_divider == 2) + { + m_2khz_divider = 0; + IO_IRQ_STATUS |= 0x0020; + check_mask |= 0x0020; + + m_1khz_divider++; + if (m_1khz_divider == 2) + { + m_1khz_divider = 0; + IO_IRQ_STATUS |= 0x0010; + check_mask |= 0x0010; + + m_4hz_divider++; + if (m_4hz_divider == 256) + { + m_4hz_divider = 0; + IO_IRQ_STATUS |= 0x0008; + check_mask |= 0x0008; + } + } + } + + const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE); + if (changed) + check_irqs(check_mask); +} + +void spg2xx_io_device::uart_transmit_tick() +{ + LOGMASKED(LOG_UART, "uart_transmit_tick: Transmitting %02x, setting TxReady, clearing TxBusy\n", (uint8_t)m_io_regs[0x35]); + m_uart_tx((uint8_t)m_io_regs[0x35]); + m_io_regs[0x31] |= 0x0002; + m_io_regs[0x31] &= ~0x0040; + if (BIT(m_io_regs[0x30], 1)) + { + const uint16_t old = IO_IRQ_STATUS; + IO_IRQ_STATUS |= 0x0100; + m_uart_tx_irq = true; + LOGMASKED(LOG_UART, "uart_transmit_tick: Setting UART IRQ bit\n"); + if (IO_IRQ_STATUS != old) + { + LOGMASKED(LOG_UART, "uart_transmit_tick: Bit newly set, checking IRQs\n"); + check_irqs(0x0100); + } + } +} + +void spg2xx_io_device::uart_receive_tick() +{ + LOGMASKED(LOG_UART, "uart_receive_tick: Setting RBF and RxRDY\n"); + m_io_regs[0x31] |= 0x81; + m_uart_rx_available = true; + if (BIT(m_io_regs[0x30], 0)) + { + LOGMASKED(LOG_UART, "uart_receive_tick: RxIntEn is set, setting rx_irq to true and setting UART IRQ\n"); + m_uart_rx_irq = true; + IO_IRQ_STATUS |= 0x0100; + check_irqs(0x0100); + } +} + +void spg2xx_io_device::extint_w(int channel, bool state) +{ + LOGMASKED(LOG_EXTINT, "Setting extint channel %d to %s\n", channel, state ? "true" : "false"); + bool old = m_extint[channel]; + m_extint[channel] = state; + if (old != state) + { + check_extint_irq(channel); + } +} + +void spg2xx_io_device::check_extint_irq(int channel) +{ + LOGMASKED(LOG_EXTINT, "%sing extint %d interrupt\n", m_extint[channel] ? "rais" : "lower", channel + 1); + const uint16_t mask = (channel == 0) ? 0x0200 : 0x1000; + const uint16_t old_irq = IO_IRQ_STATUS; + if (m_extint[channel]) + IO_IRQ_STATUS |= mask; + else + IO_IRQ_STATUS &= ~mask; + + if (old_irq != IO_IRQ_STATUS) + { + LOGMASKED(LOG_EXTINT, "extint IRQ changed, so checking interrupts\n"); + check_irqs(mask); + } +} + +void spg2xx_io_device::check_irqs(const uint16_t changed) +{ + if (changed & 0x0c00) // Timer A, Timer B IRQ + { + LOGMASKED(LOG_TIMERS, "%ssserting IRQ2 (%04x, %04x)\n", (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x0c00) ? "A" : "Dea", (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x0c00), changed); + m_cpu->set_state_unsynced(UNSP_IRQ2_LINE, (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x0c00) ? ASSERT_LINE : CLEAR_LINE); + } + + if (changed & 0x2100) // UART, ADC IRQ + { + LOGMASKED(LOG_UART, "%ssserting IRQ3 (%04x, %04x)\n", (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x2100) ? "A" : "Dea", (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x2100), changed); + m_cpu->set_state_unsynced(UNSP_IRQ3_LINE, (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x2100) ? ASSERT_LINE : CLEAR_LINE); + } + + if (changed & 0x1200) // External IRQ + { + LOGMASKED(LOG_UART, "%ssserting IRQ5 (%04x, %04x)\n", (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x1200) ? "A" : "Dea", (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x1200), changed); + m_cpu->set_state_unsynced(UNSP_IRQ5_LINE, (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x1200) ? ASSERT_LINE : CLEAR_LINE); + } + + if (changed & 0x0070) // 1024Hz, 2048Hz, 4096Hz IRQ + { + LOGMASKED(LOG_TIMERS, "%ssserting IRQ6 (%04x, %04x)\n", (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x0070) ? "A" : "Dea", (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x0070), changed); + m_cpu->set_state_unsynced(UNSP_IRQ6_LINE, (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x0070) ? ASSERT_LINE : CLEAR_LINE); + } + + if (changed & 0x008b) // TMB1, TMB2, 4Hz, key change IRQ + { + LOGMASKED(LOG_IRQS, "%ssserting IRQ7 (%04x, %04x)\n", (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x008b) ? "A" : "Dea", (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x008b), changed); + m_cpu->set_state_unsynced(UNSP_IRQ7_LINE, (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x008b) ? ASSERT_LINE : CLEAR_LINE); + } +} + +uint16_t spg2xx_io_device::do_special_gpio(uint32_t index, uint16_t mask) +{ + uint16_t data = 0; + switch (index) + { + case 0: // Port A + if (mask & 0xe000) + { + const uint8_t csel = m_cpu->get_csb() & 0x0e; + data = (csel << 12) & mask; + } + break; + case 1: // Port B + // To do + break; + case 2: // Port C + // To do + break; + default: + // Can't happen + break; + } + return data; +} + +void spg2xx_io_device::do_gpio(uint32_t offset, bool write) +{ + uint32_t index = (offset - 1) / 5; + uint16_t buffer = m_io_regs[5 * index + 2]; + uint16_t dir = m_io_regs[5 * index + 3]; + uint16_t attr = m_io_regs[5 * index + 4]; + uint16_t special = m_io_regs[5 * index + 5]; + + uint16_t push = dir; + uint16_t pull = ~dir; + uint16_t what = (buffer & (push | pull)); + what ^= (dir & ~attr); + what &= ~special; + + switch (index) + { + case 0: + if (write) + m_porta_out(0, what, push &~ special); + what = (what & ~pull); + if (!write) + what |= m_porta_in(0, pull &~ special) & pull; + break; + case 1: + if (write) + m_portb_out(0, what, push &~ special); + what = (what & ~pull); + if (!write) + what |= m_portb_in(0, pull &~ special) & pull; + break; + case 2: + if (write) + m_portc_out(0, what, push &~ special); + what = (what & ~pull); + if (!write) + what |= m_portc_in(0, pull &~ special) & pull; + break; + } + + what |= do_special_gpio(index, special); + m_io_regs[5 * index + 1] = what; +} + +void spg2xx_io_device::do_i2c() +{ + const uint16_t addr = ((m_io_regs[0x5b] & 0x06) << 7) | (uint8_t)m_io_regs[0x5c]; + + if (m_io_regs[0x58] & 0x40) // Serial EEPROM read + m_io_regs[0x5e] = m_eeprom_r(addr); + else + m_eeprom_w(addr, m_io_regs[0x5d]); + + m_io_regs[0x59] |= 1; +} diff --git a/src/devices/machine/spg2xx_io.h b/src/devices/machine/spg2xx_io.h new file mode 100644 index 00000000000..16710fc8044 --- /dev/null +++ b/src/devices/machine/spg2xx_io.h @@ -0,0 +1,169 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz + +#ifndef MAME_MACHINE_SPG2XX_IO_H +#define MAME_MACHINE_SPG2XX_IO_H + +#pragma once + +#include "cpu/unsp/unsp.h" +#include "screen.h" + +class spg2xx_io_device : public device_t +{ +public: + spg2xx_io_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + + auto porta_out() { return m_porta_out.bind(); } + auto portb_out() { return m_portb_out.bind(); } + auto portc_out() { return m_portc_out.bind(); } + auto porta_in() { return m_porta_in.bind(); } + auto portb_in() { return m_portb_in.bind(); } + auto portc_in() { return m_portc_in.bind(); } + + template auto adc_in() { return m_adc_in[Line].bind(); } + + auto eeprom_w() { return m_eeprom_w.bind(); } + auto eeprom_r() { return m_eeprom_r.bind(); } + + auto uart_tx() { return m_uart_tx.bind(); } + + auto chip_select() { return m_chip_sel.bind(); } + + void uart_rx(uint8_t data); + + void extint_w(int channel, bool state); + + virtual DECLARE_READ16_MEMBER(io_r); + virtual DECLARE_WRITE16_MEMBER(io_w); + +protected: + spg2xx_io_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, const uint32_t sprite_limit) + : spg2xx_io_device(mconfig, type, tag, owner, clock) + { + } + + + DECLARE_WRITE_LINE_MEMBER(audioirq_w); + DECLARE_READ16_MEMBER(space_r); + + void check_extint_irq(int channel); + void check_irqs(const uint16_t changed); + + static const device_timer_id TIMER_TMB1 = 0; + static const device_timer_id TIMER_TMB2 = 1; + + static const device_timer_id TIMER_UART_TX = 4; + static const device_timer_id TIMER_UART_RX = 5; + static const device_timer_id TIMER_4KHZ = 6; + static const device_timer_id TIMER_SRC_AB = 7; + static const device_timer_id TIMER_SRC_C = 8; + + virtual void device_start() override; + virtual void device_reset() override; + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; + + void update_porta_special_modes(); + void update_portb_special_modes(); + void do_gpio(uint32_t offset, bool write); + uint16_t do_special_gpio(uint32_t index, uint16_t mask); + + void update_timer_b_rate(); + void update_timer_ab_src(); + void update_timer_c_src(); + void increment_timer_a(); + + void uart_transmit_tick(); + void uart_receive_tick(); + + void system_timer_tick(); + + void do_i2c(); + + uint16_t m_io_regs[0x100]; + + uint8_t m_uart_rx_fifo[8]; + uint8_t m_uart_rx_fifo_start; + uint8_t m_uart_rx_fifo_end; + uint8_t m_uart_rx_fifo_count; + bool m_uart_rx_available; + bool m_uart_rx_irq; + bool m_uart_tx_irq; + + bool m_extint[2]; + + devcb_write16 m_porta_out; + devcb_write16 m_portb_out; + devcb_write16 m_portc_out; + devcb_read16 m_porta_in; + devcb_read16 m_portb_in; + devcb_read16 m_portc_in; + + devcb_read16 m_adc_in[2]; + + devcb_write8 m_eeprom_w; + devcb_read8 m_eeprom_r; + + devcb_write8 m_uart_tx; + + devcb_write8 m_chip_sel; + + uint16_t m_timer_a_preload; + uint16_t m_timer_b_preload; + uint16_t m_timer_b_divisor; + uint16_t m_timer_b_tick_rate; + + emu_timer *m_tmb1; + emu_timer *m_tmb2; + emu_timer *m_timer_src_ab; + emu_timer *m_timer_src_c; + + emu_timer *m_4khz_timer; + uint32_t m_2khz_divider; + uint32_t m_1khz_divider; + uint32_t m_4hz_divider; + + uint32_t m_uart_baud_rate; + emu_timer *m_uart_tx_timer; + emu_timer *m_uart_rx_timer; + + required_device m_cpu; + required_device m_screen; + + uint16_t m_pal_flag; +}; + +class spg24x_io_device : public spg2xx_io_device +{ +public: + template + spg24x_io_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&cpu_tag, U &&screen_tag) + : spg24x_io_device(mconfig, tag, owner, clock) + { + m_cpu.set_tag(std::forward(cpu_tag)); + m_screen.set_tag(std::forward(screen_tag)); + } + + spg24x_io_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); +}; + +class spg28x_io_device : public spg2xx_io_device +{ +public: + template + spg28x_io_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&cpu_tag, U &&screen_tag) + : spg28x_io_device(mconfig, tag, owner, clock) + { + m_cpu.set_tag(std::forward(cpu_tag)); + m_screen.set_tag(std::forward(screen_tag)); + } + + spg28x_io_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual DECLARE_WRITE16_MEMBER(io_w) override; +}; + +DECLARE_DEVICE_TYPE(SPG24X_IO, spg24x_io_device) +DECLARE_DEVICE_TYPE(SPG28X_IO, spg28x_io_device) + +#endif // MAME_MACHINE_SPG2XX_IO_H -- cgit v1.2.3-70-g09d2