summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/emu/sound/2610intf.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/emu/sound/2610intf.c')
-rw-r--r--trunk/src/emu/sound/2610intf.c260
1 files changed, 260 insertions, 0 deletions
diff --git a/trunk/src/emu/sound/2610intf.c b/trunk/src/emu/sound/2610intf.c
new file mode 100644
index 00000000000..3c13dfda578
--- /dev/null
+++ b/trunk/src/emu/sound/2610intf.c
@@ -0,0 +1,260 @@
+/***************************************************************************
+
+ 2610intf.c
+
+ The YM2610 emulator supports up to 2 chips.
+ Each chip has the following connections:
+ - Status Read / Control Write A
+ - Port Read / Data Write A
+ - Control Write B
+ - Data Write B
+
+***************************************************************************/
+
+#include "emu.h"
+#include "ay8910.h"
+#include "2610intf.h"
+#include "fm.h"
+
+typedef struct _ym2610_state ym2610_state;
+struct _ym2610_state
+{
+ sound_stream * stream;
+ emu_timer * timer[2];
+ void * chip;
+ void * psg;
+ const ym2610_interface *intf;
+ device_t *device;
+};
+
+
+INLINE ym2610_state *get_safe_token(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == YM2610 || device->type() == YM2610B);
+ return (ym2610_state *)downcast<legacy_device_base *>(device)->token();
+}
+
+
+static void psg_set_clock(void *param, int clock)
+{
+ ym2610_state *info = (ym2610_state *)param;
+ ay8910_set_clock_ym(info->psg, clock);
+}
+
+static void psg_write(void *param, int address, int data)
+{
+ ym2610_state *info = (ym2610_state *)param;
+ ay8910_write_ym(info->psg, address, data);
+}
+
+static int psg_read(void *param)
+{
+ ym2610_state *info = (ym2610_state *)param;
+ return ay8910_read_ym(info->psg);
+}
+
+static void psg_reset(void *param)
+{
+ ym2610_state *info = (ym2610_state *)param;
+ ay8910_reset_ym(info->psg);
+}
+
+static const ssg_callbacks psgintf =
+{
+ psg_set_clock,
+ psg_write,
+ psg_read,
+ psg_reset
+};
+
+/*------------------------- TM2610 -------------------------------*/
+/* IRQ Handler */
+static void IRQHandler(void *param,int irq)
+{
+ ym2610_state *info = (ym2610_state *)param;
+ if(info->intf->handler) info->intf->handler(info->device, irq);
+}
+
+/* Timer overflow callback from timer.c */
+static TIMER_CALLBACK( timer_callback_0 )
+{
+ ym2610_state *info = (ym2610_state *)ptr;
+ ym2610_timer_over(info->chip,0);
+}
+
+static TIMER_CALLBACK( timer_callback_1 )
+{
+ ym2610_state *info = (ym2610_state *)ptr;
+ ym2610_timer_over(info->chip,1);
+}
+
+static void timer_handler(void *param,int c,int count,int clock)
+{
+ ym2610_state *info = (ym2610_state *)param;
+ if( count == 0 )
+ { /* Reset FM Timer */
+ info->timer[c]->enable(false);
+ }
+ else
+ { /* Start FM Timer */
+ attotime period = attotime::from_hz(clock) * count;
+
+ if (!info->timer[c]->enable(true))
+ info->timer[c]->adjust(period);
+ }
+}
+
+/* update request from fm.c */
+void ym2610_update_request(void *param)
+{
+ ym2610_state *info = (ym2610_state *)param;
+ info->stream->update();
+}
+
+
+static STREAM_UPDATE( ym2610_stream_update )
+{
+ ym2610_state *info = (ym2610_state *)param;
+ ym2610_update_one(info->chip, outputs, samples);
+}
+
+static STREAM_UPDATE( ym2610b_stream_update )
+{
+ ym2610_state *info = (ym2610_state *)param;
+ ym2610b_update_one(info->chip, outputs, samples);
+}
+
+
+static void ym2610_intf_postload(ym2610_state *info)
+{
+ ym2610_postload(info->chip);
+}
+
+
+static DEVICE_START( ym2610 )
+{
+ static const ym2610_interface generic_2610 = { 0 };
+ static const ay8910_interface generic_ay8910 =
+ {
+ AY8910_LEGACY_OUTPUT | AY8910_SINGLE_OUTPUT,
+ AY8910_DEFAULT_LOADS,
+ DEVCB_NULL, DEVCB_NULL, DEVCB_NULL, DEVCB_NULL
+ };
+ const ym2610_interface *intf = device->static_config() ? (const ym2610_interface *)device->static_config() : &generic_2610;
+ int rate = device->clock()/72;
+ void *pcmbufa,*pcmbufb;
+ int pcmsizea,pcmsizeb;
+ ym2610_state *info = get_safe_token(device);
+ astring name;
+ device_type type = device->type();
+
+ info->intf = intf;
+ info->device = device;
+ info->psg = ay8910_start_ym(NULL, device->type(), device, device->clock(), &generic_ay8910);
+ assert_always(info->psg != NULL, "Error creating YM2610/AY8910 chip");
+
+ /* Timer Handler set */
+ info->timer[0] = device->machine().scheduler().timer_alloc(FUNC(timer_callback_0), info);
+ info->timer[1] = device->machine().scheduler().timer_alloc(FUNC(timer_callback_1), info);
+
+ /* stream system initialize */
+ info->stream = device->machine().sound().stream_alloc(*device,0,2,rate,info,(type == YM2610) ? ym2610_stream_update : ym2610b_stream_update);
+ /* setup adpcm buffers */
+ pcmbufa = *device->region();
+ pcmsizea = device->region()->bytes();
+ name.printf("%s.deltat", device->tag());
+ pcmbufb = (void *)(device->machine().region(name)->base());
+ pcmsizeb = device->machine().region(name)->bytes();
+ if (pcmbufb == NULL || pcmsizeb == 0)
+ {
+ pcmbufb = pcmbufa;
+ pcmsizeb = pcmsizea;
+ }
+
+ /**** initialize YM2610 ****/
+ info->chip = ym2610_init(info,device,device->clock(),rate,
+ pcmbufa,pcmsizea,pcmbufb,pcmsizeb,
+ timer_handler,IRQHandler,&psgintf);
+ assert_always(info->chip != NULL, "Error creating YM2610 chip");
+
+ device->machine().save().register_postload(save_prepost_delegate(FUNC(ym2610_intf_postload), info));
+}
+
+static DEVICE_STOP( ym2610 )
+{
+ ym2610_state *info = get_safe_token(device);
+ ym2610_shutdown(info->chip);
+ ay8910_stop_ym(info->psg);
+}
+
+static DEVICE_RESET( ym2610 )
+{
+ ym2610_state *info = get_safe_token(device);
+ ym2610_reset_chip(info->chip);
+}
+
+
+READ8_DEVICE_HANDLER( ym2610_r )
+{
+ ym2610_state *info = get_safe_token(device);
+ return ym2610_read(info->chip, offset & 3);
+}
+
+WRITE8_DEVICE_HANDLER( ym2610_w )
+{
+ ym2610_state *info = get_safe_token(device);
+ ym2610_write(info->chip, offset & 3, data);
+}
+
+
+READ8_DEVICE_HANDLER( ym2610_status_port_a_r ) { return ym2610_r(device, 0); }
+READ8_DEVICE_HANDLER( ym2610_status_port_b_r ) { return ym2610_r(device, 2); }
+READ8_DEVICE_HANDLER( ym2610_read_port_r ) { return ym2610_r(device, 1); }
+
+WRITE8_DEVICE_HANDLER( ym2610_control_port_a_w ) { ym2610_w(device, 0, data); }
+WRITE8_DEVICE_HANDLER( ym2610_control_port_b_w ) { ym2610_w(device, 2, data); }
+WRITE8_DEVICE_HANDLER( ym2610_data_port_a_w ) { ym2610_w(device, 1, data); }
+WRITE8_DEVICE_HANDLER( ym2610_data_port_b_w ) { ym2610_w(device, 3, data); }
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+DEVICE_GET_INFO( ym2610 )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(ym2610_state); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME( ym2610 ); break;
+ case DEVINFO_FCT_STOP: info->stop = DEVICE_STOP_NAME( ym2610 ); break;
+ case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME( ym2610 ); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "YM2610"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "Yamaha FM"); 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;
+ }
+}
+
+DEVICE_GET_INFO( ym2610b )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "YM2610B"); break;
+
+ default: DEVICE_GET_INFO_CALL(ym2610); break;
+ }
+}
+
+
+DEFINE_LEGACY_SOUND_DEVICE(YM2610, ym2610);
+DEFINE_LEGACY_SOUND_DEVICE(YM2610B, ym2610b);