mame/src/emu/sound/namco52.c
Aaron Giles 27e2aac0fe Added internal memory maps and internal clock divider to the MB88xx
CPUs. Removed now-redundant memory maps from drivers and removed
explicitly-specified clock dividers.
2009-05-27 14:18:44 +00:00

254 lines
7.8 KiB
C

/***************************************************************************
Namco 52XX
This instance of the Fujitsu MB8843 MCU is programmed to act as a sample player.
It is used by just two games: Bosconian and Pole Position.
A0-A15 = address to read from sample ROMs
D0-D7 = data freom sample ROMs
CMD = command from CPU (sample to play, 0 = none)
OUT = sound output
+------+
EXTAL|1 42|Vcc
XTAL|2 41|CMD3
/RESET|3 40|CMD2
/IRQ|4 39|CMD1
n.c.|5 38|CMD0
[2] |6 37|A7
n.c.|7 36|A6
[1] |8 35|A5
OUT0|9 34|A4
OUT1|10 33|A3
OUT2|11 32|A2
OUT3|12 31|A1
A8|13 30|A0
A9|14 29|D7
A10|15 28|D6
A11|16 27|D5
[3]A12|17 26|D4
[3]A13|18 25|D3
[3]A14|19 24|D2
[3]A15|20 23|D1
GND|21 22|D0
+------+
[1] in polepos, GND; in bosco, 4kHz output from a 555 timer
[2] in polepos, +5V; in bosco, GND
[3] in polepos, these are true address lines, in bosco they are chip select lines
(each one select one of the four ROM chips). Behaviour related to [2]?
TODO:
- the purpose of the 555 timer in bosco is unknown; maybe modulate the output?
Jan 12, 2005. The 555 is probably an external playback frequency.
***************************************************************************/
#include "sndintrf.h"
#include "streams.h"
#include "filter.h"
#include "namco52.h"
#include "cpu/mb88xx/mb88xx.h"
typedef struct _namco_52xx namco_52xx;
struct _namco_52xx
{
const namco_52xx_interface *intf; /* pointer to our config data */
UINT8 *rom; /* pointer to sample ROM */
UINT32 rom_len;
sound_stream * stream; /* the output stream */
double n52_pb_cycle; /* playback clock time based on machine sample rate */
double n52_step; /* playback clock step based on machine sample rate */
/* n52_pb_cycle is incremented by n52_step every machine-sample.
* At every integer value of n52_pb_cycle the next 4bit value is used. */
INT32 n52_start; /* current effect start position in the ROM */
INT32 n52_end; /* current effect end position in the ROM */
INT32 n52_length; /* # of 4bit samples in current effect */
INT32 n52_pos; /* current 4bit sample of effect */
filter2_context n52_hp_filter;
filter2_context n52_lp_filter;
};
INLINE namco_52xx *get_safe_token(const device_config *device)
{
assert(device != NULL);
assert(device->token != NULL);
assert(device->type == SOUND);
assert(sound_get_type(device) == SOUND_NAMCO_52XX);
return (namco_52xx *)device->token;
}
static void namco_52xx_reset(namco_52xx *chip);
static STREAM_UPDATE( namco_52xx_stream_update_one )
{
namco_52xx *chip = (namco_52xx *)param;
int i, rom_pos, whole_pb_cycles, buf;
stream_sample_t *buffer = outputs[0];
if (chip->n52_start >= chip->n52_end)
{
memset(buffer, 0, samples * sizeof(*buffer));
return;
}
for (i = 0; i < samples; i++)
{
chip->n52_pb_cycle += chip->n52_step;
if (chip->n52_pb_cycle >= 1)
{
whole_pb_cycles = (int)chip->n52_pb_cycle;
chip->n52_pos += whole_pb_cycles;
chip->n52_pb_cycle -= whole_pb_cycles;
}
if (chip->n52_pos > chip->n52_length)
{
/* sample done */
memset(&buffer[i], 0, (samples - i) * sizeof(INT16));
i = samples;
namco_52xx_reset(chip);
}
else
{
/* filter and fill the buffer */
rom_pos = chip->n52_start + (chip->n52_pos >> 1);
/* get the 4bit sample from rom and shift to +7/-8 value */
chip->n52_hp_filter.x0 = (((chip->n52_pos & 1) ? chip->rom[rom_pos] >> 4 : chip->rom[rom_pos]) & 0x0f) - 0x08;
filter2_step(&chip->n52_hp_filter);
chip->n52_lp_filter.x0 = chip->n52_hp_filter.y0;
filter2_step(&chip->n52_lp_filter);
/* convert 4bit filtered to 16bit allowing room for filter gain */
buf = (int)(chip->n52_lp_filter.y0 * 0x0fff);
if (buf > 32767) buf = 32767;
if (buf < -32768) buf = -32768;
buffer[i] = buf;
}
}
}
static void namco_52xx_reset(namco_52xx *chip)
{
chip->n52_pb_cycle = chip->n52_start = chip->n52_end = chip->n52_length = chip->n52_pos = 0;
filter2_reset(&chip->n52_hp_filter);
filter2_reset(&chip->n52_lp_filter);
}
static DEVICE_RESET( namco_52xx )
{
namco_52xx_reset(get_safe_token(device));
}
static DEVICE_START( namco_52xx )
{
namco_52xx *chip = get_safe_token(device);
int rate = device->clock/32;
chip->intf = (const namco_52xx_interface *)device->static_config;
chip->rom = device->region;
chip->rom_len = device->regionbytes;
if (chip->intf->play_rate == 0)
{
/* If play clock is 0 (grounded) then default to internal clock */
chip->n52_step = (double)device->clock / 384 / rate;
}
else
{
chip->n52_step = chip->intf->play_rate / rate;
}
filter2_setup(device, FILTER_HIGHPASS, chip->intf->hp_filt_fc, Q_TO_DAMP(chip->intf->hp_filt_q), 1, &chip->n52_hp_filter);
filter2_setup(device, FILTER_LOWPASS, chip->intf->lp_filt_fc, Q_TO_DAMP(chip->intf->lp_filt_q), chip->intf->filt_gain, &chip->n52_lp_filter);
chip->stream = stream_create(device, 0, 1, rate, chip, namco_52xx_stream_update_one);
namco_52xx_reset(chip);
state_save_register_device_item(device, 0, chip->n52_pb_cycle);
state_save_register_device_item(device, 0, chip->n52_step);
state_save_register_device_item(device, 0, chip->n52_start);
state_save_register_device_item(device, 0, chip->n52_end);
state_save_register_device_item(device, 0, chip->n52_length);
state_save_register_device_item(device, 0, chip->n52_pos);
}
WRITE8_DEVICE_HANDLER( namco_52xx_write )
{
namco_52xx *chip = get_safe_token(device);
data &= 0x0f;
if (data != 0)
{
stream_update(chip->stream);
chip->n52_start = chip->rom[data-1] + (chip->rom[data-1+0x10] << 8);
chip->n52_end = chip->rom[data] + (chip->rom[data+0x10] << 8);
if (chip->n52_end >= chip->rom_len)
chip->n52_end = chip->rom_len;
chip->n52_length = (chip->n52_end - chip->n52_start) * 2;
chip->n52_pos = 0;
chip->n52_pb_cycle= 0;
}
}
/**************************************************************************
* Generic get_info
**************************************************************************/
ADDRESS_MAP_START( namco_52xx_map_io, ADDRESS_SPACE_IO, 8 )
// AM_RANGE(MB88_PORTK, MB88_PORTK) AM_READ(namco_52xx_K_r)
// AM_RANGE(MB88_PORTO, MB88_PORTO) AM_WRITE(namco_52xx_O_w)
// AM_RANGE(MB88_PORTR0, MB88_PORTR0) AM_READ(namco_52xx_R0_r)
// AM_RANGE(MB88_PORTR2, MB88_PORTR2) AM_READ(namco_52xx_R2_r)
ADDRESS_MAP_END
static MACHINE_DRIVER_START( namco_52xx )
MDRV_CPU_ADD("mcu", MB8843, DERIVED_CLOCK(1,1)) /* parent clock, internally divided by 6 */
MDRV_CPU_IO_MAP(namco_52xx_map_io)
MDRV_CPU_FLAGS(CPU_DISABLE) /* not implemented yet */
MACHINE_DRIVER_END
ROM_START( namco_52xx )
ROM_REGION( 0x400, "mcu", ROMREGION_LOADBYNAME )
ROM_LOAD( "52xx.bin", 0x0000, 0x0400, CRC(3257d11e) SHA1(4883b2fdbc99eb7b9906357fcc53915842c2c186) )
ROM_END
DEVICE_GET_INFO( namco_52xx )
{
switch (state)
{
/* --- the following bits of info are returned as 64-bit signed integers --- */
case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(namco_52xx); break;
/* --- the following bits of info are returned as pointers --- */
case DEVINFO_PTR_ROM_REGION: info->romregion = ROM_NAME(namco_52xx); break;
case DEVINFO_PTR_MACHINE_CONFIG: info->machine_config = MACHINE_DRIVER_NAME(namco_52xx); break;
/* --- the following bits of info are returned as pointers to data or functions --- */
case DEVINFO_FCT_START: info->start = DEVICE_START_NAME( namco_52xx ); break;
case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME( namco_52xx ); break;
/* --- the following bits of info are returned as NULL-terminated strings --- */
case DEVINFO_STR_NAME: strcpy(info->s, "Namco 52XX"); break;
case DEVINFO_STR_FAMILY: strcpy(info->s, "Namco custom"); break;
case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright Nicola Salmoria and the MAME Team"); break;
}
}