summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--.gitattributes2
-rw-r--r--src/emu/sndintrf.c1
-rw-r--r--src/emu/sndintrf.h1
-rw-r--r--src/emu/sound/okim6258.c494
-rw-r--r--src/emu/sound/okim6258.h41
-rw-r--r--src/emu/sound/sound.mak5
-rw-r--r--src/mame/mame.mak3
7 files changed, 546 insertions, 1 deletions
diff --git a/.gitattributes b/.gitattributes
index 6be2931761b..79553880e34 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -834,6 +834,8 @@ src/emu/sound/nes_apu.h svneol=native#text/plain
src/emu/sound/nes_defs.h svneol=native#text/plain
src/emu/sound/nile.c svneol=native#text/plain
src/emu/sound/nile.h svneol=native#text/plain
+src/emu/sound/okim6258.c svneol=native#text/plain
+src/emu/sound/okim6258.h svneol=native#text/plain
src/emu/sound/okim6295.c svneol=native#text/plain
src/emu/sound/okim6295.h svneol=native#text/plain
src/emu/sound/pokey.c svneol=native#text/plain
diff --git a/src/emu/sndintrf.c b/src/emu/sndintrf.c
index c6671698f46..c7dccc2e52d 100644
--- a/src/emu/sndintrf.c
+++ b/src/emu/sndintrf.c
@@ -121,6 +121,7 @@ SND_GET_INFO( tms5220 );
SND_GET_INFO( vlm5030 );
SND_GET_INFO( adpcm );
SND_GET_INFO( okim6295 );
+SND_GET_INFO( okim6258 );
SND_GET_INFO( msm5205 );
SND_GET_INFO( msm5232 );
SND_GET_INFO( upd7759 );
diff --git a/src/emu/sndintrf.h b/src/emu/sndintrf.h
index 73dc9629cd2..7db71a1385e 100644
--- a/src/emu/sndintrf.h
+++ b/src/emu/sndintrf.h
@@ -84,6 +84,7 @@ enum _sound_type
SOUND_TMS5220,
SOUND_VLM5030,
SOUND_OKIM6295,
+ SOUND_OKIM6258,
SOUND_MSM5205,
SOUND_MSM5232,
SOUND_UPD7759,
diff --git a/src/emu/sound/okim6258.c b/src/emu/sound/okim6258.c
new file mode 100644
index 00000000000..d00cea5a1de
--- /dev/null
+++ b/src/emu/sound/okim6258.c
@@ -0,0 +1,494 @@
+/**********************************************************************************************
+ *
+ * OKI MSM6258 ADPCM
+ *
+ * TODO:
+ * 3-bit ADPCM support
+ * Recording?
+ *
+ **********************************************************************************************/
+
+
+#include <math.h>
+
+#include "sndintrf.h"
+#include "deprecat.h"
+#include "streams.h"
+#include "okim6258.h"
+
+#define COMMAND_STOP (1 << 0)
+#define COMMAND_PLAY (1 << 1)
+#define COMMAND_RECORD (1 << 2)
+
+#define STATUS_PLAYING (1 << 1)
+#define STATUS_RECORDING (1 << 2)
+
+static const int dividers[4] = { 1024, 768, 512, 512 };
+
+struct okim6258
+{
+ UINT8 status;
+
+ UINT32 master_clock; /* master clock frequency */
+ UINT32 divider; /* master clock divider */
+ UINT8 adpcm_type; /* 3/4 bit ADPCM select */
+ UINT8 data_in; /* ADPCM data-in register */
+ UINT8 nibble_shift; /* nibble select */
+ sound_stream *stream; /* which stream are we playing on? */
+
+ UINT8 output_bits;
+
+ INT32 signal;
+ INT32 step;
+};
+
+/* step size index shift table */
+static const int index_shift[8] = { -1, -1, -1, -1, 2, 4, 6, 8 };
+
+/* lookup table for the precomputed difference */
+static int diff_lookup[49*16];
+
+/* tables computed? */
+static int tables_computed = 0;
+
+/**********************************************************************************************
+
+ compute_tables -- compute the difference tables
+
+***********************************************************************************************/
+
+static void compute_tables(void)
+{
+ /* nibble to bit map */
+ static const int nbl2bit[16][4] =
+ {
+ { 1, 0, 0, 0}, { 1, 0, 0, 1}, { 1, 0, 1, 0}, { 1, 0, 1, 1},
+ { 1, 1, 0, 0}, { 1, 1, 0, 1}, { 1, 1, 1, 0}, { 1, 1, 1, 1},
+ {-1, 0, 0, 0}, {-1, 0, 0, 1}, {-1, 0, 1, 0}, {-1, 0, 1, 1},
+ {-1, 1, 0, 0}, {-1, 1, 0, 1}, {-1, 1, 1, 0}, {-1, 1, 1, 1}
+ };
+
+ int step, nib;
+
+ /* loop over all possible steps */
+ for (step = 0; step <= 48; step++)
+ {
+ /* compute the step value */
+ int stepval = floor(16.0 * pow(11.0 / 10.0, (double)step));
+
+ /* loop over all nibbles and compute the difference */
+ for (nib = 0; nib < 16; nib++)
+ {
+ diff_lookup[step*16 + nib] = nbl2bit[nib][0] *
+ (stepval * nbl2bit[nib][1] +
+ stepval/2 * nbl2bit[nib][2] +
+ stepval/4 * nbl2bit[nib][3] +
+ stepval/8);
+ }
+ }
+
+ tables_computed = 1;
+}
+
+
+static INT16 clock_adpcm(struct okim6258 *chip, UINT8 nibble)
+{
+ INT32 max = (1 << (chip->output_bits - 1)) - 1;
+ INT32 min = -(1 << (chip->output_bits - 1));
+
+ chip->signal += diff_lookup[chip->step * 16 + (nibble & 15)];
+
+ /* clamp to the maximum */
+ if (chip->signal > max)
+ chip->signal = max;
+ else if (chip->signal < min)
+ chip->signal = min;
+
+ /* adjust the step size and clamp */
+ chip->step += index_shift[nibble & 7];
+ if (chip->step > 48)
+ chip->step = 48;
+ else if (chip->step < 0)
+ chip->step = 0;
+
+ /* return the signal scaled up to 32767 */
+ return chip->signal << 4;
+}
+
+/**********************************************************************************************
+
+ okim6258_update -- update the sound chip so that it is in sync with CPU execution
+
+***********************************************************************************************/
+
+static void okim6258_update(void *param, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
+{
+ struct okim6258 *chip = param;
+ stream_sample_t *buffer = outputs[0];
+
+ memset(outputs[0], 0, samples * sizeof(*outputs[0]));
+
+ if (chip->status & STATUS_PLAYING)
+ {
+ int nibble_shift = chip->nibble_shift;
+
+ while (samples)
+ {
+ /* Compute the new amplitude and update the current step */
+ int nibble = (chip->data_in >> nibble_shift) & 0xf;
+
+ /* Output to the buffer */
+ INT16 sample = clock_adpcm(chip, nibble);
+
+ nibble_shift ^= 4;
+
+ *buffer++ = sample;
+ samples--;
+ }
+
+ /* Update the parameters */
+ chip->nibble_shift = nibble_shift;
+ }
+ else
+ {
+ /* Fill with 0 */
+ while (samples--)
+ *buffer++ = 0;
+ }
+}
+
+
+
+/**********************************************************************************************
+
+ state save support for MAME
+
+***********************************************************************************************/
+
+static void okim6258_state_save_register(struct okim6258 *info, const char *tag)
+{
+ state_save_register_item("OKIM6258", tag, 0, info->status);
+ state_save_register_item("OKIM6258", tag, 0, info->master_clock);
+ state_save_register_item("OKIM6258", tag, 0, info->divider);
+ state_save_register_item("OKIM6258", tag, 0, info->data_in);
+ state_save_register_item("OKIM6258", tag, 0, info->nibble_shift);
+ state_save_register_item("OKIM6258", tag, 0, info->signal);
+ state_save_register_item("OKIM6258", tag, 0, info->step);
+}
+
+
+/**********************************************************************************************
+
+ OKIM6258_start -- start emulation of an OKIM6258-compatible chip
+
+***********************************************************************************************/
+
+static SND_START( okim6258 )
+{
+ const okim6258_interface *intf = config;
+ struct okim6258 *info;
+
+ info = auto_malloc(sizeof(*info));
+ memset(info, 0, sizeof(*info));
+
+ compute_tables();
+
+ info->master_clock = clock;
+ info->adpcm_type = intf->adpcm_type;
+
+ /* D/A precision is 10-bits but 12-bit data can be output serially to an external DAC */
+ info->output_bits = intf->output_12bits ? 12 : 10;
+ info->divider = dividers[intf->divider];
+
+ info->stream = stream_create(0, 1, clock/info->divider, info, okim6258_update);
+
+ info->signal = -2;
+ info->step = 0;
+
+ okim6258_state_save_register(info, tag);
+
+ return info;
+}
+
+
+/**********************************************************************************************
+
+ OKIM6258_stop -- stop emulation of an OKIM6258-compatible chip
+
+***********************************************************************************************/
+
+static SND_RESET( okim6258 )
+{
+ struct okim6258 *info = token;
+
+ stream_update(info->stream);
+
+ info->signal = -2;
+ info->step = 0;
+ info->status = 0;
+}
+
+
+/**********************************************************************************************
+
+ okim6258_set_divider -- set the master clock divider
+
+***********************************************************************************************/
+
+void okim6258_set_divider(int which, int val)
+{
+ struct okim6258 *info = sndti_token(SOUND_OKIM6258, which);
+ int divider = dividers[val];
+
+ info->divider = dividers[val];
+ stream_set_sample_rate(info->stream, info->master_clock / divider);
+}
+
+
+/**********************************************************************************************
+
+ okim6258_set_clock -- set the master clock
+
+***********************************************************************************************/
+
+void okim6258_set_clock(int which, int val)
+{
+ struct okim6258 *info = sndti_token(SOUND_OKIM6258, which);
+
+ info->master_clock = val;
+ stream_set_sample_rate(info->stream, info->master_clock / info->divider);
+}
+
+
+/**********************************************************************************************
+
+ okim6258_get_vclk -- get the VCLK/sampling frequency
+
+***********************************************************************************************/
+
+int okim6258_get_vclk(int which)
+{
+ struct okim6258 *info = sndti_token(SOUND_OKIM6258, which);
+
+ return (info->master_clock / info->divider);
+}
+
+
+/**********************************************************************************************
+
+ okim6258_status_r -- read the status port of an OKIM6258-compatible chip
+
+***********************************************************************************************/
+
+static int okim6258_status_r(int num)
+{
+ struct okim6258 *info = sndti_token(SOUND_OKIM6258, num);
+
+ stream_update(info->stream);
+
+ return (info->status & STATUS_PLAYING) ? 0x00 : 0x80;
+}
+
+
+/**********************************************************************************************
+
+ okim6258_data_w -- write to the control port of an OKIM6258-compatible chip
+
+***********************************************************************************************/
+static void okim6258_data_w(int num, int data)
+{
+ struct okim6258 *info = sndti_token(SOUND_OKIM6258, num);
+
+ /* update the stream */
+ stream_update(info->stream);
+
+ info->data_in = data;
+ info->nibble_shift = 0;
+}
+
+
+/**********************************************************************************************
+
+ okim6258_ctrl_w -- write to the control port of an OKIM6258-compatible chip
+
+***********************************************************************************************/
+
+static void okim6258_ctrl_w(int num, int data)
+{
+ struct okim6258 *info = sndti_token(SOUND_OKIM6258, num);
+
+ stream_update(info->stream);
+
+ if (data & COMMAND_STOP)
+ {
+ info->status &= ~(STATUS_PLAYING | STATUS_RECORDING);
+ return;
+ }
+
+ if (data & COMMAND_PLAY)
+ {
+ if (!(info->status & STATUS_PLAYING))
+ {
+ info->status |= STATUS_PLAYING;
+
+ /* Also reset the ADPCM parameters */
+ info->signal = -2;
+ info->step = 0;
+ info->nibble_shift = 0;
+ }
+ }
+ else
+ {
+ info->status &= ~STATUS_PLAYING;
+ }
+
+ if (data & COMMAND_RECORD)
+ {
+ logerror("M6258: Record enabled\n");
+ info->status |= STATUS_RECORDING;
+ }
+ else
+ {
+ info->status &= ~STATUS_RECORDING;
+ }
+}
+
+
+/**********************************************************************************************
+
+ okim6258_status_0_r -- generic status read functions
+
+***********************************************************************************************/
+
+READ8_HANDLER( okim6258_status_0_r )
+{
+ return okim6258_status_r(0);
+}
+
+READ16_HANDLER( okim6258_status_0_lsb_r )
+{
+ return okim6258_status_r(0);
+}
+
+READ16_HANDLER( okim6258_status_0_msb_r )
+{
+ return okim6258_status_r(0) << 8;
+}
+
+READ8_HANDLER( okim6258_data_0_r )
+{
+ // TODO
+ return 0;
+}
+
+READ16_HANDLER( okim6258_data_0_lsb_r )
+{
+ // TODO
+ return 0;
+}
+
+READ16_HANDLER( okim6258_data_0_msb_r )
+{
+ // TODO
+ return 0;
+}
+
+/**********************************************************************************************
+
+ okim6258_data_0_w -- generic data write functions
+ okim6258_data_1_w
+
+***********************************************************************************************/
+
+WRITE8_HANDLER( okim6258_data_0_w )
+{
+ okim6258_data_w(0, data);
+}
+
+WRITE8_HANDLER( okim6258_data_1_w )
+{
+ okim6258_data_w(1, data);
+}
+
+WRITE8_HANDLER( okim6258_data_2_w )
+{
+ okim6258_data_w(2, data);
+}
+
+WRITE16_HANDLER( okim6258_data_0_lsb_w )
+{
+ if (ACCESSING_BITS_0_7)
+ okim6258_data_w(0, data & 0xff);
+}
+
+WRITE16_HANDLER( okim6258_data_1_lsb_w )
+{
+ if (ACCESSING_BITS_0_7)
+ okim6258_data_w(1, data & 0xff);
+}
+
+WRITE16_HANDLER( okim6258_data_2_lsb_w )
+{
+ if (ACCESSING_BITS_0_7)
+ okim6258_data_w(2, data & 0xff);
+}
+
+WRITE16_HANDLER( okim6258_data_0_msb_w )
+{
+ if (ACCESSING_BITS_8_15)
+ okim6258_data_w(0, data >> 8);
+}
+
+WRITE16_HANDLER( okim6258_data_1_msb_w )
+{
+ if (ACCESSING_BITS_8_15)
+ okim6258_data_w(1, data >> 8);
+}
+
+WRITE16_HANDLER( okim6258_data_2_msb_w )
+{
+ if (ACCESSING_BITS_8_15)
+ okim6258_data_w(2, data >> 8);
+}
+
+WRITE16_HANDLER( okim6258_ctrl_0_lsb_w )
+{
+ if (ACCESSING_BITS_0_7)
+ okim6258_ctrl_w(0, data & 0xff);
+}
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static SND_SET_INFO( okim6258 )
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+SND_GET_INFO( okim6258 )
+{
+ 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 = SND_SET_INFO_NAME(okim6258); break;
+ case SNDINFO_PTR_START: info->start = SND_START_NAME(okim6258); break;
+ case SNDINFO_PTR_STOP: /* nothing */ break;
+ case SNDINFO_PTR_RESET: info->reset = SND_RESET_NAME(okim6258); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "OKI6258"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "OKI ADPCM"; 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;
+ }
+}
+
diff --git a/src/emu/sound/okim6258.h b/src/emu/sound/okim6258.h
new file mode 100644
index 00000000000..c930ee14702
--- /dev/null
+++ b/src/emu/sound/okim6258.h
@@ -0,0 +1,41 @@
+#pragma once
+
+#ifndef __OKIM6258_H__
+#define __OKIM6258_H__
+
+/* an interface for the OKIM6258 and similar chips */
+
+struct _okim6258_interface
+{
+ int divider;
+ int adpcm_type;
+ int output_12bits;
+};
+
+typedef struct _okim6258_interface okim6258_interface;
+
+#define FOSC_DIV_BY_1024 0
+#define FOSC_DIV_BY_768 1
+#define FOSC_DIV_BY_512 2
+
+#define TYPE_3BITS 0
+#define TYPE_4BITS 1
+
+#define OUTPUT_10BITS 0
+#define OUTPUT_12BITS 1
+
+void okim6258_set_divider(int which, int val);
+void okim6258_set_clock(int which, int val);
+
+READ8_HANDLER( okim6258_status_0_r );
+READ16_HANDLER( okim6258_status_0_lsb_r );
+READ16_HANDLER( okim6258_status_0_msb_r );
+WRITE8_HANDLER( okim6258_data_0_w );
+READ8_HANDLER( okim6258_data_0_r );
+WRITE8_HANDLER( okim6258_ctrl_0_w );
+WRITE16_HANDLER( okim6258_data_0_lsb_w );
+WRITE16_HANDLER( okim6258_ctrl_0_lsb_w );
+READ16_HANDLER( okim6258_data_0_lsb_r );
+READ16_HANDLER( okim6258_data_0_msb_r );
+
+#endif /* __OKIM6258_H__ */
diff --git a/src/emu/sound/sound.mak b/src/emu/sound/sound.mak
index d6ec478e444..d285b5a58f5 100644
--- a/src/emu/sound/sound.mak
+++ b/src/emu/sound/sound.mak
@@ -366,6 +366,7 @@ endif
SOUNDDEFS += -DHAS_MSM5205=$(if $(filter MSM5205,$(SOUNDS)),1,0)
SOUNDDEFS += -DHAS_MSM5232=$(if $(filter MSM5232,$(SOUNDS)),1,0)
SOUNDDEFS += -DHAS_OKIM6295=$(if $(filter OKIM6295,$(SOUNDS)),1,0)
+SOUNDDEFS += -DHAS_OKIM6258=$(if $(filter OKIM6258,$(SOUNDS)),1,0)
ifneq ($(filter MSM5205,$(SOUNDS)),)
SOUNDOBJS += $(SOUNDOBJ)/msm5205.o
@@ -379,6 +380,10 @@ ifneq ($(filter OKIM6295,$(SOUNDS)),)
SOUNDOBJS += $(SOUNDOBJ)/okim6295.o
endif
+ifneq ($(filter OKIM6258,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/okim6258.o
+endif
+
#-------------------------------------------------
diff --git a/src/mame/mame.mak b/src/mame/mame.mak
index cb13ddb651c..865b17ff1b8 100644
--- a/src/mame/mame.mak
+++ b/src/mame/mame.mak
@@ -299,6 +299,7 @@ SOUNDS += VLM5030
SOUNDS += ADPCM
SOUNDS += MSM5205
SOUNDS += MSM5232
+SOUNDS += OKIM6258
SOUNDS += OKIM6295
SOUNDS += UPD7759
SOUNDS += HC55516
@@ -336,7 +337,7 @@ SOUNDS += VRENDER0
SOUNDS += ES8712
SOUNDS += CDP1869
SOUNDS += S14001A
-#SOUNDS += WAVE
+SOUNDS += WAVE
#SOUNDS += SID6581
#SOUNDS += SID8580
SOUNDS += SP0256