/***************************************************************************

Namco 54XX

This custom chip is a Fujitsu MB8844 MCU programmed to act as a noise
generator. It is used for explosions, the shoot sound in Bosconian, and the
tire screech sound in Pole Position.

CMD = command from main CPU
OUTn = sound outputs (3 channels)

The chip reads the command when the /IRQ is pulled down.

      +------+
 EXTAL|1   28|Vcc
  XTAL|2   27|CMD7
/RESET|3   26|CMD6
OUT0.0|4   25|CMD5
OUT0.1|5   24|CMD4
OUT0.2|6   23|/IRQ
OUT0.3|7   22|n.c. [1]
OUT1.0|8   21|n.c. [1]
OUT1.1|9   20|OUT2.3
OUT1.2|10  19|OUT2.2
OUT1.3|11  18|OUT2.1
  CMD0|12  17|OUT2.0
  CMD1|13  16|CMD3
   GND|14  15|CMD2
      +------+


[1] The RNG that drives the type A output is output on pin 21, and the one that
drives the type B output is output on pin 22, but those pins are not connected
on the board.


The command format is very simple:

0x: nop
1x: play sound type A
2x: play sound type B
3x: set parameters (type A) (followed by 4 bytes)
4x: set parameters (type B) (followed by 4 bytes)
5x: play sound type C
6x: set parameters (type C) (followed by 5 bytes)
7x: set volume for sound type C to x
8x-Fx: nop

***************************************************************************/

#include "driver.h"
#include "namco54.h"
#include "cpu/mb88xx/mb88xx.h"


static UINT8 latched_cmd;

static TIMER_CALLBACK( namco_54xx_latch_callback )
{
	latched_cmd = param;
}

static READ8_HANDLER( namco_54xx_K_r )
{
	return latched_cmd >> 4;
}

static READ8_HANDLER( namco_54xx_R0_r )
{
	return latched_cmd & 0x0f;
}


static WRITE8_HANDLER( namco_54xx_O_w )
{
	UINT8 out = (data & 0x0f);
	if (data & 0x10)
		discrete_sound_w(NAMCO_54XX_1_DATA, out);
	else
		discrete_sound_w(NAMCO_54XX_0_DATA, out);
}

static WRITE8_HANDLER( namco_54xx_R1_w )
{
	UINT8 out = (data & 0x0f);

	discrete_sound_w(NAMCO_54XX_2_DATA, out);
}



ADDRESS_MAP_START( namco_54xx_map_program, ADDRESS_SPACE_PROGRAM, 8 )
	AM_RANGE(0x000, 0x3ff) AM_ROM
ADDRESS_MAP_END

ADDRESS_MAP_START( namco_54xx_map_data, ADDRESS_SPACE_DATA, 8 )
	AM_RANGE(0x00, 0x3f) AM_RAM
ADDRESS_MAP_END

ADDRESS_MAP_START( namco_54xx_map_io, ADDRESS_SPACE_IO, 8 )
	AM_RANGE(MB88_PORTK,  MB88_PORTK)  AM_READ(namco_54xx_K_r)
	AM_RANGE(MB88_PORTO,  MB88_PORTO)  AM_WRITE(namco_54xx_O_w)
	AM_RANGE(MB88_PORTR0, MB88_PORTR0) AM_READ(namco_54xx_R0_r)
	AM_RANGE(MB88_PORTR1, MB88_PORTR1) AM_WRITE(namco_54xx_R1_w)
	AM_RANGE(MB88_PORTR2, MB88_PORTR2) AM_NOP
ADDRESS_MAP_END



static TIMER_CALLBACK( namco_54xx_irq_clear )
{
	cpunum_set_input_line(param, 0, CLEAR_LINE);
}

void namco_54xx_write(UINT8 data)
{
	int cpunum = mame_find_cpu_index(Machine, CPUTAG_54XX);

	if (cpunum == -1)
		return;

	timer_call_after_resynch(NULL, data, namco_54xx_latch_callback);

	cpunum_set_input_line(cpunum, 0, ASSERT_LINE);

	// The execution time of one instruction is ~4us, so we must make sure to
	// give the cpu time to poll the /IRQ input before we clear it.
	// The input clock to the 06XX interface chip is 64H, that is
	// 18432000/6/64 = 48kHz, so it makes sense for the irq line to be
	// asserted for one clock cycle ~= 21us.
	timer_set(ATTOTIME_IN_USEC(21), NULL, cpunum, namco_54xx_irq_clear);
}
