diff options
Diffstat (limited to 'trunk/src/emu/sound/segapcm.c')
-rw-r--r-- | trunk/src/emu/sound/segapcm.c | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/trunk/src/emu/sound/segapcm.c b/trunk/src/emu/sound/segapcm.c new file mode 100644 index 00000000000..7f6f7054748 --- /dev/null +++ b/trunk/src/emu/sound/segapcm.c @@ -0,0 +1,179 @@ +/*********************************************************/ +/* SEGA 16ch 8bit PCM */ +/*********************************************************/ + +#include "emu.h" +#include "segapcm.h" + +typedef struct _segapcm_state segapcm_state; +struct _segapcm_state +{ + UINT8 *ram; + UINT8 low[16]; + const UINT8 *rom; + int bankshift; + int bankmask; + int rgnmask; + sound_stream * stream; +}; + +INLINE segapcm_state *get_safe_token(device_t *device) +{ + assert(device != NULL); + assert(device->type() == SEGAPCM); + return (segapcm_state *)downcast<legacy_device_base *>(device)->token(); +} + +static STREAM_UPDATE( SEGAPCM_update ) +{ + segapcm_state *spcm = (segapcm_state *)param; + int rgnmask = spcm->rgnmask; + int ch; + + /* clear the buffers */ + memset(outputs[0], 0, samples*sizeof(*outputs[0])); + memset(outputs[1], 0, samples*sizeof(*outputs[1])); + + // reg function + // ------------------------------------------------ + // 0x00 ? + // 0x01 ? + // 0x02 volume left + // 0x03 volume right + // 0x04 loop address (08-15) + // 0x05 loop address (16-23) + // 0x06 end address + // 0x07 address delta + // 0x80 ? + // 0x81 ? + // 0x82 ? + // 0x83 ? + // 0x84 current address (08-15), 00-07 is internal? + // 0x85 current address (16-23) + // 0x86 bit 0: channel disable? + // bit 1: loop disable + // other bits: bank + // 0x87 ? + + /* loop over channels */ + for (ch = 0; ch < 16; ch++) + { + UINT8 *regs = spcm->ram+8*ch; + + /* only process active channels */ + if (!(regs[0x86]&1)) + { + const UINT8 *rom = spcm->rom + ((regs[0x86] & spcm->bankmask) << spcm->bankshift); + UINT32 addr = (regs[0x85] << 16) | (regs[0x84] << 8) | spcm->low[ch]; + UINT32 loop = (regs[0x05] << 16) | (regs[0x04] << 8); + UINT8 end = regs[6] + 1; + int i; + + /* loop over samples on this channel */ + for (i = 0; i < samples; i++) + { + INT8 v = 0; + + /* handle looping if we've hit the end */ + if ((addr >> 16) == end) + { + if (regs[0x86] & 2) + { + regs[0x86] |= 1; + break; + } + else addr = loop; + } + + /* fetch the sample */ + v = rom[(addr >> 8) & rgnmask] - 0x80; + + /* apply panning and advance */ + outputs[0][i] += v * regs[2]; + outputs[1][i] += v * regs[3]; + addr = (addr + regs[7]) & 0xffffff; + } + + /* store back the updated address */ + regs[0x84] = addr >> 8; + regs[0x85] = addr >> 16; + spcm->low[ch] = regs[0x86] & 1 ? 0 : addr; + } + } +} + +static DEVICE_START( segapcm ) +{ + const sega_pcm_interface *intf = (const sega_pcm_interface *)device->static_config(); + int mask, rom_mask, len; + segapcm_state *spcm = get_safe_token(device); + + spcm->rom = *device->region(); + spcm->ram = auto_alloc_array(device->machine(), UINT8, 0x800); + + memset(spcm->ram, 0xff, 0x800); + + spcm->bankshift = (UINT8)(intf->bank); + mask = intf->bank >> 16; + if(!mask) + mask = BANK_MASK7>>16; + + len = device->region()->bytes(); + spcm->rgnmask = len - 1; + + for(rom_mask = 1; rom_mask < len; rom_mask *= 2); + + rom_mask--; + + spcm->bankmask = mask & (rom_mask >> spcm->bankshift); + + spcm->stream = device->machine().sound().stream_alloc(*device, 0, 2, device->clock() / 128, spcm, SEGAPCM_update); + + device->save_item(NAME(spcm->low)); + device->save_pointer(NAME(spcm->ram), 0x800); +} + + +WRITE8_DEVICE_HANDLER( sega_pcm_w ) +{ + segapcm_state *spcm = get_safe_token(device); + spcm->stream->update(); + spcm->ram[offset & 0x07ff] = data; +} + +READ8_DEVICE_HANDLER( sega_pcm_r ) +{ + segapcm_state *spcm = get_safe_token(device); + spcm->stream->update(); + return spcm->ram[offset & 0x07ff]; +} + + + +/************************************************************************** + * Generic get_info + **************************************************************************/ + +DEVICE_GET_INFO( segapcm ) +{ + switch (state) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(segapcm_state); break; + + /* --- the following bits of info are returned as pointers to data or functions --- */ + case DEVINFO_FCT_START: info->start = DEVICE_START_NAME( segapcm ); break; + case DEVINFO_FCT_STOP: /* Nothing */ break; + case DEVINFO_FCT_RESET: /* Nothing */ break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case DEVINFO_STR_NAME: strcpy(info->s, "Sega PCM"); break; + case DEVINFO_STR_FAMILY: strcpy(info->s, "Sega 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; + } +} + + +DEFINE_LEGACY_SOUND_DEVICE(SEGAPCM, segapcm); |