#include "driver.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
{
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 */
} TC0140SYT;
static struct TC0140SYT tc0140syt;
static void Interrupt_Controller(void)
{
if ( tc0140syt.nmi_req && tc0140syt.nmi_enabled )
{
cpunum_set_input_line( 1, INPUT_LINE_NMI, PULSE_LINE );
tc0140syt.nmi_req = 0;
}
}
WRITE8_HANDLER( taitosound_port_w )
{
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_HANDLER( taitosound_comm_w )
{
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, activecpu_get_pc() );
//#endif
/* this does a hi-lo transition to reset the sound cpu */
if (data)
cpunum_set_input_line(1, INPUT_LINE_RESET, ASSERT_LINE);
else
{
cpunum_set_input_line(1, INPUT_LINE_RESET, CLEAR_LINE);
cpu_spin(); /* otherwise no sound in driftout */
}
break;
default:
logerror("taitosnd: Master cpu written in mode [%02x] data[%02x]\n",tc0140syt.mainmode, data);
}
}
READ8_HANDLER( taitosound_comm_r )
{
switch( tc0140syt.mainmode )
{
case 0x00: // mode #0
//logerror("taitosnd: Master cpu read portdata %01x\n", tc0140syt.masterdata[0]);
return tc0140syt.masterdata[tc0140syt.mainmode ++];
break;
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 ++];
break;
case 0x02: // mode #2
//logerror("taitosnd: Master cpu read masterdata %01x\n", tc0140syt.masterdata[2]);
return tc0140syt.masterdata[tc0140syt.mainmode ++];
break;
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 ++];
break;
case 0x04: // port status
//logerror("tc0140syt : Master cpu read status : %02x\n", tc0140syt.status);
return tc0140syt.status;
break;
default:
logerror("tc0140syt : Master cpu read in mode [%02x]\n", tc0140syt.mainmode);
return 0;
}
}
//SLAVE SIDE
WRITE8_HANDLER( taitosound_slave_port_w )
{
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_HANDLER( taitosound_slave_comm_w )
{
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]);
cpu_spin(); /* 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]);
cpu_spin(); /* 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();
}
READ8_HANDLER( taitosound_slave_comm_r )
{
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],activecpu_get_pc());
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();
return res;
}
/* wrapper functions for 16bit handlers */
WRITE16_HANDLER( taitosound_port16_lsb_w )
{
if (ACCESSING_LSB)
taitosound_port_w(0,data & 0xff);
}
WRITE16_HANDLER( taitosound_comm16_lsb_w )
{
if (ACCESSING_LSB)
taitosound_comm_w(0,data & 0xff);
}
READ16_HANDLER( taitosound_comm16_lsb_r )
{
return taitosound_comm_r(0);
}
WRITE16_HANDLER( taitosound_port16_msb_w )
{
if (ACCESSING_MSB)
taitosound_port_w(0,data >> 8);
}
WRITE16_HANDLER( taitosound_comm16_msb_w )
{
if (ACCESSING_MSB)
taitosound_comm_w(0,data >> 8);
}
READ16_HANDLER( taitosound_comm16_msb_r )
{
return taitosound_comm_r(0) << 8;
}