diff options
Diffstat (limited to 'trunk/src/mame/audio/taitosnd.c')
-rw-r--r-- | trunk/src/mame/audio/taitosnd.c | 332 |
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); |