summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/mame/audio/taitosnd.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/mame/audio/taitosnd.c')
-rw-r--r--trunk/src/mame/audio/taitosnd.c332
1 files changed, 332 insertions, 0 deletions
diff --git a/trunk/src/mame/audio/taitosnd.c b/trunk/src/mame/audio/taitosnd.c
new file mode 100644
index 00000000000..47d9a540647
--- /dev/null
+++ b/trunk/src/mame/audio/taitosnd.c
@@ -0,0 +1,332 @@
+#include "emu.h"
+#include "cpu/z80/z80.h"
+#include "taitosnd.h"
+
+
+/**********************************************************************************************
+
+ It seems like 1 nibble commands are only for control purposes.
+ 2 nibble commands are the real messages passed from one board to the other.
+
+**********************************************************************************************/
+
+/* Some logging defines */
+#if 0
+#define REPORT_SLAVE_MODE_CHANGE
+#define REPORT_SLAVE_MODE_READ_ITSELF
+#define REPORT_MAIN_MODE_READ_SLAVE
+#define REPORT_DATA_FLOW
+#endif
+
+#define TC0140SYT_PORT01_FULL (0x01)
+#define TC0140SYT_PORT23_FULL (0x02)
+#define TC0140SYT_PORT01_FULL_MASTER (0x04)
+#define TC0140SYT_PORT23_FULL_MASTER (0x08)
+
+typedef struct _tc0140syt_state tc0140syt_state;
+struct _tc0140syt_state
+{
+ UINT8 slavedata[4]; /* Data on master->slave port (4 nibbles) */
+ UINT8 masterdata[4]; /* Data on slave->master port (4 nibbles) */
+ UINT8 mainmode; /* Access mode on master cpu side */
+ UINT8 submode; /* Access mode on slave cpu side */
+ UINT8 status; /* Status data */
+ UINT8 nmi_enabled; /* 1 if slave cpu has nmi's enabled */
+ UINT8 nmi_req; /* 1 if slave cpu has a pending nmi */
+
+ device_t *mastercpu; /* this is the maincpu */
+ device_t *slavecpu; /* this is the audiocpu */
+};
+
+/*****************************************************************************
+ INLINE FUNCTIONS
+*****************************************************************************/
+
+INLINE tc0140syt_state *get_safe_token( device_t *device )
+{
+ assert(device != NULL);
+ assert(device->type() == TC0140SYT);
+
+ return (tc0140syt_state *)downcast<legacy_device_base *>(device)->token();
+}
+
+INLINE const tc0140syt_interface *get_interface( device_t *device )
+{
+ assert(device != NULL);
+ assert((device->type() == TC0140SYT));
+ return (const tc0140syt_interface *) device->static_config();
+}
+
+/*****************************************************************************
+ DEVICE HANDLERS
+*****************************************************************************/
+
+static void interrupt_controller( device_t *device )
+{
+ tc0140syt_state *tc0140syt = get_safe_token(device);
+
+ if (tc0140syt->nmi_req && tc0140syt->nmi_enabled)
+ {
+ device_set_input_line(tc0140syt->slavecpu, INPUT_LINE_NMI, PULSE_LINE);
+ tc0140syt->nmi_req = 0;
+ }
+}
+
+WRITE8_DEVICE_HANDLER( tc0140syt_port_w )
+{
+ tc0140syt_state *tc0140syt = get_safe_token(device);
+ data &= 0x0f;
+
+ tc0140syt->mainmode = data;
+ //logerror("taitosnd: Master cpu mode [%02x]\n", data);
+ if (data > 4)
+ {
+ logerror("tc0140syt : error Master entering unknown mode[%02x]\n", data);
+ }
+}
+
+WRITE8_DEVICE_HANDLER( tc0140syt_comm_w )
+{
+ tc0140syt_state *tc0140syt = get_safe_token(device);
+
+ data &= 0x0f; /*this is important, otherwise ballbros won't work*/
+
+ switch (tc0140syt->mainmode)
+ {
+ case 0x00: // mode #0
+ tc0140syt->slavedata[tc0140syt->mainmode ++] = data;
+ //logerror("taitosnd: Master cpu written port 0, data %01x\n", data);
+ break;
+
+ case 0x01: // mode #1
+ tc0140syt->slavedata[tc0140syt->mainmode ++] = data;
+ tc0140syt->status |= TC0140SYT_PORT01_FULL;
+ tc0140syt->nmi_req = 1;
+ //logerror("taitosnd: Master cpu sends 0/1 : %01x%01x\n", tc0140syt->slavedata[1], tc0140syt->slavedata[0]);
+ break;
+
+ case 0x02: // mode #2
+ tc0140syt->slavedata[tc0140syt->mainmode ++] = data;
+ //logerror("taitosnd: Master cpu written port 2, data %01\n", data);
+ break;
+
+ case 0x03: // mode #3
+ tc0140syt->slavedata[tc0140syt->mainmode ++] = data;
+ tc0140syt->status |= TC0140SYT_PORT23_FULL;
+ tc0140syt->nmi_req = 1;
+ //logerror("taitosnd: Master cpu sends 2/3 : %01x%01x\n", tc0140syt->slavedata[3], tc0140syt->slavedata[2]);
+ break;
+
+ case 0x04: // port status
+//#ifdef REPORT_DATA_FLOW
+ //logerror("taitosnd: Master issued control value %02x (PC = %08x) \n",data, cpu_get_pc(&space->device()) );
+//#endif
+ /* this does a hi-lo transition to reset the sound cpu */
+ if (data)
+ device_set_input_line(tc0140syt->slavecpu, INPUT_LINE_RESET, ASSERT_LINE);
+ else
+ {
+ device_set_input_line(tc0140syt->slavecpu, INPUT_LINE_RESET, CLEAR_LINE);
+ device_spin(tc0140syt->mastercpu); /* otherwise no sound in driftout */
+ }
+ break;
+
+ default:
+ logerror("taitosnd: Master cpu written in mode [%02x] data[%02x]\n", tc0140syt->mainmode, data);
+ }
+
+}
+
+READ8_DEVICE_HANDLER( tc0140syt_comm_r )
+{
+ tc0140syt_state *tc0140syt = get_safe_token(device);
+
+ switch( tc0140syt->mainmode )
+ {
+ case 0x00: // mode #0
+ //logerror("taitosnd: Master cpu read portdata %01x\n", tc0140syt->masterdata[0]);
+ return tc0140syt->masterdata[tc0140syt->mainmode ++];
+
+ case 0x01: // mode #1
+ //logerror("taitosnd: Master cpu receives 0/1 : %01x%01x\n", tc0140syt->masterdata[1], tc0140syt->masterdata[0]);
+ tc0140syt->status &= ~TC0140SYT_PORT01_FULL_MASTER;
+ return tc0140syt->masterdata[tc0140syt->mainmode ++];
+
+ case 0x02: // mode #2
+ //logerror("taitosnd: Master cpu read masterdata %01x\n", tc0140syt->masterdata[2]);
+ return tc0140syt->masterdata[tc0140syt->mainmode ++];
+
+ case 0x03: // mode #3
+ //logerror("taitosnd: Master cpu receives 2/3 : %01x%01x\n", tc0140syt->masterdata[3], tc0140syt->masterdata[2]);
+ tc0140syt->status &= ~TC0140SYT_PORT23_FULL_MASTER;
+ return tc0140syt->masterdata[tc0140syt->mainmode ++];
+
+ case 0x04: // port status
+ //logerror("tc0140syt : Master cpu read status : %02x\n", tc0140syt->status);
+ return tc0140syt->status;
+
+ default:
+ logerror("tc0140syt : Master cpu read in mode [%02x]\n", tc0140syt->mainmode);
+ return 0;
+ }
+}
+
+//SLAVE SIDE
+
+WRITE8_DEVICE_HANDLER( tc0140syt_slave_port_w )
+{
+ tc0140syt_state *tc0140syt = get_safe_token(device);
+
+ data &= 0x0f;
+ tc0140syt->submode = data;
+ //logerror("taitosnd: Slave cpu mode [%02x]\n", data);
+ if (data > 6)
+ logerror("tc0140syt error : Slave cpu unknown mode[%02x]\n", data);
+}
+
+WRITE8_DEVICE_HANDLER( tc0140syt_slave_comm_w )
+{
+ tc0140syt_state *tc0140syt = get_safe_token(device);
+
+ data &= 0x0f;
+ switch (tc0140syt->submode)
+ {
+ case 0x00: // mode #0
+ tc0140syt->masterdata[tc0140syt->submode ++] = data;
+ //logerror("taitosnd: Slave cpu written port 0, data %01x\n", data);
+ break;
+
+ case 0x01: // mode #1
+ tc0140syt->masterdata[tc0140syt->submode ++] = data;
+ tc0140syt->status |= TC0140SYT_PORT01_FULL_MASTER;
+ //logerror("taitosnd: Slave cpu sends 0/1 : %01x%01x\n" , tc0140syt->masterdata[1] , tc0140syt->masterdata[0]);
+ device_spin(tc0140syt->slavecpu); /* writing should take longer than emulated, so spin */
+ break;
+
+ case 0x02: // mode #2
+ //logerror("taitosnd: Slave cpu written port 2, data %01x\n", data);
+ tc0140syt->masterdata[tc0140syt->submode ++] = data;
+ break;
+
+ case 0x03: // mode #3
+ tc0140syt->masterdata[tc0140syt->submode ++] = data;
+ tc0140syt->status |= TC0140SYT_PORT23_FULL_MASTER;
+ //logerror("taitosnd: Slave cpu sends 2/3 : %01x%01x\n" , tc0140syt->masterdata[3] , tc0140syt->masterdata[2]);
+ device_spin(tc0140syt->slavecpu); /* writing should take longer than emulated, so spin */
+ break;
+
+ case 0x04: // port status
+ //tc0140syt->status = TC0140SYT_SET_OK;
+ //logerror("tc0140syt : Slave cpu status ok.\n");
+ break;
+
+ case 0x05: // nmi disable
+ tc0140syt->nmi_enabled = 0;
+ break;
+
+ case 0x06: // nmi enable
+ tc0140syt->nmi_enabled = 1;
+ break;
+
+ default:
+ logerror("tc0140syt: Slave cpu written in mode [%02x] data[%02x]\n" , tc0140syt->submode, data & 0xff);
+ }
+
+ interrupt_controller(device);
+
+}
+
+READ8_DEVICE_HANDLER( tc0140syt_slave_comm_r )
+{
+ tc0140syt_state *tc0140syt = get_safe_token(device);
+ UINT8 res = 0;
+
+ switch ( tc0140syt->submode )
+ {
+ case 0x00: // mode #0
+ //logerror("taitosnd: Slave cpu read slavedata %01x\n", tc0140syt->slavedata[0]);
+ res = tc0140syt->slavedata[tc0140syt->submode ++];
+ break;
+
+ case 0x01: // mode #1
+ //logerror("taitosnd: Slave cpu receives 0/1 : %01x%01x PC=%4x\n", tc0140syt->slavedata[1] , tc0140syt->slavedata[0],cpu_get_pc(&space->device()));
+ tc0140syt->status &= ~TC0140SYT_PORT01_FULL;
+ res = tc0140syt->slavedata[tc0140syt->submode ++];
+ break;
+
+ case 0x02: // mode #2
+ //logerror("taitosnd: Slave cpu read slavedata %01x\n", tc0140syt->slavedata[2]);
+ res = tc0140syt->slavedata[tc0140syt->submode ++];
+ break;
+
+ case 0x03: // mode #3
+ //logerror("taitosnd: Slave cpu receives 2/3 : %01x%01x\n", tc0140syt->slavedata[3] , tc0140syt->slavedata[2]);
+ tc0140syt->status &= ~TC0140SYT_PORT23_FULL;
+ res = tc0140syt->slavedata[tc0140syt->submode ++];
+ break;
+
+ case 0x04: // port status
+ //logerror("tc0140syt : Slave cpu read status : %02x\n", tc0140syt->status);
+ res = tc0140syt->status;
+ break;
+
+ default:
+ logerror("tc0140syt : Slave cpu read in mode [%02x]\n", tc0140syt->submode);
+ res = 0;
+ }
+
+ interrupt_controller(device);
+
+ return res;
+}
+
+/*****************************************************************************
+ DEVICE INTERFACE
+*****************************************************************************/
+
+static DEVICE_START( tc0140syt )
+{
+ tc0140syt_state *tc0140syt = get_safe_token(device);
+ const tc0140syt_interface *intf = get_interface(device);
+
+ /* use the given gfx set */
+ tc0140syt->mastercpu = device->machine().device(intf->master);
+ tc0140syt->slavecpu = device->machine().device(intf->slave);
+
+ device->save_item(NAME(tc0140syt->mainmode));
+ device->save_item(NAME(tc0140syt->submode));
+ device->save_item(NAME(tc0140syt->status));
+ device->save_item(NAME(tc0140syt->nmi_enabled));
+ device->save_item(NAME(tc0140syt->nmi_req));
+ device->save_item(NAME(tc0140syt->slavedata));
+ device->save_item(NAME(tc0140syt->masterdata));
+}
+
+static DEVICE_RESET( tc0140syt )
+{
+ tc0140syt_state *tc0140syt = get_safe_token(device);
+ int i;
+
+ tc0140syt->mainmode = 0;
+ tc0140syt->submode = 0;
+ tc0140syt->status = 0;
+ tc0140syt->nmi_enabled = 0;
+ tc0140syt->nmi_req = 0;
+
+ for (i = 0; i < 4; i++)
+ {
+ tc0140syt->slavedata[i] = 0;
+ tc0140syt->masterdata[i] = 0;
+ }
+}
+
+static const char DEVTEMPLATE_SOURCE[] = __FILE__;
+
+#define DEVTEMPLATE_ID(p,s) p##tc0140syt##s
+#define DEVTEMPLATE_FEATURES DT_HAS_START | DT_HAS_RESET
+#define DEVTEMPLATE_NAME "Taito TC0140SYT"
+#define DEVTEMPLATE_FAMILY "Taito Audio Custom IC"
+#include "devtempl.h"
+
+
+DEFINE_LEGACY_DEVICE(TC0140SYT, tc0140syt);