mirror of
https://github.com/holub/mame
synced 2025-05-28 08:33:05 +03:00

integer value, regions are now referred to by a region class and a region tag. The class specifies the type of region (one of CPU, gfx, sound, user, disk, prom, pld) while the tag uniquely specifies the region. This change required updating all the ROM region definitions in the project to specify the class/tag instead of region number. Updated the core memory_region_* functions to accept a class/tag pair. Added new memory_region_next() function to allow for iteration over all memory regions of a given class. Added new function memory_region_class_name() to return the name for a given CPU memory region class. Changed the auto-binding behavior of CPU regions. Previously, the first CPU would auto-bind to REGION_CPU1 (that is, any ROM references would automatically assume that they lived in the corresponding region). Now, each CPU automatically binds to the RGNCLASS_CPU region with the same tag as the CPU itself. This behavior required ensuring that all previous REGION_CPU* regions were changed to RGNCLASS_CPU with the same tag as the CPU. Introduced a new auto-binding mechanism for sound cores. This works similarly to the CPU binding. Each sound core that requires a memory region now auto-binds to the RGNCLASS_SOUND with the same tag as the sound core. In almost all cases, this allowed for the removal of the explicit region item in the sound configuration, which in turn allowed for many sound configurations to removed altogether. Updated the expression engine's memory reference behavior. A recent update expanded the scope of memory references to allow for referencing data in non-active CPU spaces, in memory regions, and in EEPROMs. However, this previous update required an index, which is no longer appropriate for regions and will become increasingly less appropriate for CPUs over time. Instead, a new syntax is supported, of the form: "[tag.][space]size@addr", where 'tag' is an optional tag for the CPU or memory region you wish to access, followed by a period as a separator; 'space' is the memory address space or region class you wish to access (p/d/i for program/data/I/O spaces; o for opcode space; r for direct RAM; c/u/g/s for CPU/user/gfx/sound regions; e for EEPROMs); and 'size' is the usual b/w/d/q for byte/word/dword/qword. Cleaned up ROM definition flags and removed some ugly hacks that had existed previously. Expanded to support up to 256 BIOSes. Updated ROM_COPY to support specifying class/tag for the source region. Updated the address map AM_REGION macro to support specifying a class/tag for the region. Updated debugger windows to display the CPU and region tags where appropriate. Updated -listxml to output region class and tag for each ROM entry.
256 lines
6.9 KiB
C
256 lines
6.9 KiB
C
/***************************************************************************
|
|
|
|
Konami 051649 - SCC1 sound as used in Haunted Castle, City Bomber
|
|
|
|
This file is pieced together by Bryan McPhail from a combination of
|
|
Namco Sound, Amuse by Cab, Haunted Castle schematics and whoever first
|
|
figured out SCC!
|
|
|
|
The 051649 is a 5 channel sound generator, each channel gets it's
|
|
waveform from RAM (32 bytes per waveform, 8 bit signed data).
|
|
|
|
This sound chip is the same as the sound chip in some Konami
|
|
megaROM cartridges for the MSX. It is actually well researched
|
|
and documented:
|
|
|
|
http://www.msxnet.org/tech/scc
|
|
|
|
Thanks to Sean Young (sean@mess.org) for some bugfixes.
|
|
|
|
K052539 is equivalent to this chip except channel 5 does not share
|
|
waveforms with channel 4.
|
|
|
|
***************************************************************************/
|
|
|
|
#include "sndintrf.h"
|
|
#include "streams.h"
|
|
#include "k051649.h"
|
|
|
|
#define FREQBASEBITS 16
|
|
|
|
/* this structure defines the parameters for a channel */
|
|
typedef struct
|
|
{
|
|
unsigned long counter;
|
|
int frequency;
|
|
int volume;
|
|
int key;
|
|
signed char waveform[32]; /* 19991207.CAB */
|
|
} k051649_sound_channel;
|
|
|
|
struct k051649_info
|
|
{
|
|
k051649_sound_channel channel_list[5];
|
|
|
|
/* global sound parameters */
|
|
sound_stream * stream;
|
|
int mclock,rate;
|
|
|
|
/* mixer tables and internal buffers */
|
|
INT16 *mixer_table;
|
|
INT16 *mixer_lookup;
|
|
short *mixer_buffer;
|
|
|
|
int f[10];
|
|
};
|
|
|
|
/* build a table to divide by the number of voices */
|
|
static int make_mixer_table(struct k051649_info *info, int voices)
|
|
{
|
|
int count = voices * 256;
|
|
int i;
|
|
int gain = 8;
|
|
|
|
/* allocate memory */
|
|
info->mixer_table = auto_malloc(512 * voices * sizeof(INT16));
|
|
|
|
/* find the middle of the table */
|
|
info->mixer_lookup = info->mixer_table + (256 * voices);
|
|
|
|
/* fill in the table - 16 bit case */
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
int val = i * gain * 16 / voices;
|
|
if (val > 32767) val = 32767;
|
|
info->mixer_lookup[ i] = val;
|
|
info->mixer_lookup[-i] = -val;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* generate sound to the mix buffer */
|
|
static void K051649_update(void *param, stream_sample_t **inputs, stream_sample_t **_buffer, int length)
|
|
{
|
|
struct k051649_info *info = param;
|
|
k051649_sound_channel *voice=info->channel_list;
|
|
stream_sample_t *buffer = _buffer[0];
|
|
short *mix;
|
|
int i,v,f,j,k;
|
|
|
|
/* zap the contents of the mixer buffer */
|
|
memset(info->mixer_buffer, 0, length * sizeof(short));
|
|
|
|
for (j=0; j<5; j++) {
|
|
v=voice[j].volume;
|
|
f=voice[j].frequency;
|
|
k=voice[j].key;
|
|
/* SY 20040109: the SCC produces no sound for freq < 9 */
|
|
if (v && f > 8 && k)
|
|
{
|
|
const signed char *w = voice[j].waveform; /* 19991207.CAB */
|
|
int c=voice[j].counter;
|
|
|
|
mix = info->mixer_buffer;
|
|
|
|
/* add our contribution */
|
|
for (i = 0; i < length; i++)
|
|
{
|
|
int offs;
|
|
|
|
/* Amuse source: Cab suggests this method gives greater resolution */
|
|
/* Sean Young 20010417: the formula is really: f = clock/(16*(f+1))*/
|
|
c+=(long)((((float)info->mclock / (float)((f+1) * 16))*(float)(1<<FREQBASEBITS)) / (float)(info->rate / 32));
|
|
offs = (c >> 16) & 0x1f;
|
|
*mix++ += (w[offs] * v)>>3;
|
|
}
|
|
|
|
/* update the counter for this voice */
|
|
voice[j].counter = c;
|
|
}
|
|
}
|
|
|
|
/* mix it down */
|
|
mix = info->mixer_buffer;
|
|
for (i = 0; i < length; i++)
|
|
*buffer++ = info->mixer_lookup[*mix++];
|
|
}
|
|
|
|
static void *k051649_start(const char *tag, int sndindex, int clock, const void *config)
|
|
{
|
|
struct k051649_info *info;
|
|
|
|
info = auto_malloc(sizeof(*info));
|
|
memset(info, 0, sizeof(*info));
|
|
|
|
/* get stream channels */
|
|
info->rate = clock/16;
|
|
info->stream = stream_create(0, 1, info->rate, info, K051649_update);
|
|
info->mclock = clock;
|
|
|
|
/* allocate a buffer to mix into - 1 second's worth should be more than enough */
|
|
info->mixer_buffer = auto_malloc(2 * sizeof(short) * info->rate);
|
|
|
|
/* build the mixer table */
|
|
if (make_mixer_table(info, 5))
|
|
return NULL;
|
|
|
|
return info;
|
|
}
|
|
|
|
static void k051649_reset(void *chip)
|
|
{
|
|
struct k051649_info *info = chip;
|
|
k051649_sound_channel *voice = info->channel_list;
|
|
int i;
|
|
|
|
/* reset all the voices */
|
|
for (i=0; i>5; i++) {
|
|
voice[i].frequency = 0;
|
|
voice[i].volume = 0;
|
|
voice[i].counter = 0;
|
|
}
|
|
}
|
|
|
|
/********************************************************************************/
|
|
|
|
WRITE8_HANDLER( K051649_waveform_w )
|
|
{
|
|
struct k051649_info *info = sndti_token(SOUND_K051649, 0);
|
|
stream_update(info->stream);
|
|
info->channel_list[offset>>5].waveform[offset&0x1f]=data;
|
|
/* SY 20001114: Channel 5 shares the waveform with channel 4 */
|
|
if (offset >= 0x60)
|
|
info->channel_list[4].waveform[offset&0x1f]=data;
|
|
}
|
|
|
|
READ8_HANDLER ( K051649_waveform_r )
|
|
{
|
|
struct k051649_info *info = sndti_token(SOUND_K051649, 0);
|
|
return info->channel_list[offset>>5].waveform[offset&0x1f];
|
|
}
|
|
|
|
/* SY 20001114: Channel 5 doesn't share the waveform with channel 4 on this chip */
|
|
WRITE8_HANDLER( K052539_waveform_w )
|
|
{
|
|
struct k051649_info *info = sndti_token(SOUND_K051649, 0);
|
|
stream_update(info->stream);
|
|
info->channel_list[offset>>5].waveform[offset&0x1f]=data;
|
|
}
|
|
|
|
WRITE8_HANDLER( K051649_volume_w )
|
|
{
|
|
struct k051649_info *info = sndti_token(SOUND_K051649, 0);
|
|
stream_update(info->stream);
|
|
info->channel_list[offset&0x7].volume=data&0xf;
|
|
}
|
|
|
|
WRITE8_HANDLER( K051649_frequency_w )
|
|
{
|
|
struct k051649_info *info = sndti_token(SOUND_K051649, 0);
|
|
info->f[offset]=data;
|
|
|
|
stream_update(info->stream);
|
|
info->channel_list[offset>>1].frequency=(info->f[offset&0xe] + (info->f[offset|1]<<8))&0xfff;
|
|
}
|
|
|
|
WRITE8_HANDLER( K051649_keyonoff_w )
|
|
{
|
|
struct k051649_info *info = sndti_token(SOUND_K051649, 0);
|
|
stream_update(info->stream);
|
|
info->channel_list[0].key=data&1;
|
|
info->channel_list[1].key=data&2;
|
|
info->channel_list[2].key=data&4;
|
|
info->channel_list[3].key=data&8;
|
|
info->channel_list[4].key=data&16;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**************************************************************************
|
|
* Generic get_info
|
|
**************************************************************************/
|
|
|
|
static void k051649_set_info(void *token, UINT32 state, sndinfo *info)
|
|
{
|
|
switch (state)
|
|
{
|
|
/* no parameters to set */
|
|
}
|
|
}
|
|
|
|
|
|
void k051649_get_info(void *token, UINT32 state, sndinfo *info)
|
|
{
|
|
switch (state)
|
|
{
|
|
/* --- the following bits of info are returned as 64-bit signed integers --- */
|
|
|
|
/* --- the following bits of info are returned as pointers to data or functions --- */
|
|
case SNDINFO_PTR_SET_INFO: info->set_info = k051649_set_info; break;
|
|
case SNDINFO_PTR_START: info->start = k051649_start; break;
|
|
case SNDINFO_PTR_STOP: /* nothing */ break;
|
|
case SNDINFO_PTR_RESET: info->reset = k051649_reset; break;
|
|
|
|
/* --- the following bits of info are returned as NULL-terminated strings --- */
|
|
case SNDINFO_STR_NAME: info->s = "K051649"; break;
|
|
case SNDINFO_STR_CORE_FAMILY: info->s = "Konami custom"; break;
|
|
case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
|
|
case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
|
|
case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright Nicola Salmoria and the MAME Team"; break;
|
|
}
|
|
}
|
|
|