/*********************************************************/ /* SEGA 16ch 8bit PCM */ /*********************************************************/ #include "emu.h" #include "segapcm.h" // device type definition const device_type SEGAPCM = &device_creator; //------------------------------------------------- // segapcm_device - constructor //------------------------------------------------- segapcm_device::segapcm_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : device_t(mconfig, SEGAPCM, "Sega PCM", "segapcm", tag, owner, clock), device_sound_interface(mconfig, *this), m_ram(NULL), m_rom(NULL), m_bankshift(0), m_bankmask(0), m_rgnmask(0), m_stream(NULL) { } //------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- void segapcm_device::device_start() { int mask, rom_mask, len; const sega_pcm_interface *intf = (const sega_pcm_interface *)static_config(); m_rom = *region(); m_ram = auto_alloc_array(machine(), UINT8, 0x800); memset(m_ram, 0xff, 0x800); m_bankshift = (UINT8)(intf->bank); mask = intf->bank >> 16; if(!mask) mask = BANK_MASK7>>16; len = region()->bytes(); m_rgnmask = len - 1; for(rom_mask = 1; rom_mask < len; rom_mask *= 2); rom_mask--; m_bankmask = mask & (rom_mask >> m_bankshift); m_stream = stream_alloc(0, 2, clock() / 128); save_item(NAME(m_low)); save_pointer(NAME(m_ram), 0x800); } //------------------------------------------------- // sound_stream_update - handle a stream update //------------------------------------------------- void segapcm_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) { /* 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 (int ch = 0; ch < 16; ch++) { UINT8 *regs = m_ram+8*ch; /* only process active channels */ if (!(regs[0x86]&1)) { const UINT8 *rom = m_rom + ((regs[0x86] & m_bankmask) << m_bankshift); UINT32 addr = (regs[0x85] << 16) | (regs[0x84] << 8) | m_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) & m_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; m_low[ch] = regs[0x86] & 1 ? 0 : addr; } } } WRITE8_MEMBER( segapcm_device::sega_pcm_w ) { m_stream->update(); m_ram[offset & 0x07ff] = data; } READ8_MEMBER( segapcm_device::sega_pcm_r ) { m_stream->update(); return m_ram[offset & 0x07ff]; }