Patchwork [v3,23/25] fm: YM2608 core forked from MAME 0.59

login
register
mail settings
Submitter 武田 =?ISO-2022-JP?B?IBskQj1TTGkbKEI=?=
Date Oct. 28, 2009, 4:50 p.m.
Message ID <200910281650.AA00166@YOUR-BD18D6DD63.m1.interq.or.jp>
Download mbox | patch
Permalink /patch/37150/
State New
Headers show

Comments


Patch

diff --git a/qemu/hw/fm.c b/qemu/hw/fm.c
new file mode 100644
index 0000000..0a78bbd
--- /dev/null
+++ b/qemu/hw/fm.c
@@ -0,0 +1,2579 @@ 
+#define YM2610B_WARNING
+
+/* YM2608 rhythm data is PCM ,not an ADPCM */
+#define YM2608_RHYTHM_PCM
+
+/*
+**
+** File: fm.c -- software implementation of Yamaha FM sound generator
+**
+** Copyright (C) 1998 Tatsuyuki Satoh , MultiArcadeMachineEmulator development
+**
+** Version 0.37f
+**
+*/
+
+/*
+** History:
+**
+** 27-10-2009 TAKEDA, toshiya
+**  - forked from MAME 0.59
+**  - remove any codes not used for YM2608
+**
+** 18-12-2001 Jarek Burczynski:
+**  - added SSG-EG support (verified on real chip)
+**
+** 12-08-2001 Jarek Burczynski:
+**  - corrected sin_tab and tl_tab data (verified on real chip)
+**  - corrected feedback calculations (verified on real chip)
+**  - corrected phase generator calculations (verified on real chip)
+**  - corrected envelope generator calculations (verified on real chip)
+**  - corrected FM volume level (YM2610 and YM2610B).
+**  - changed YMxxxUpdateOne() functions (YM2203, YM2608, YM2610, YM2610B, YM2612) :
+**    this was needed to calculate YM2610 FM channels output correctly.
+**    (Each FM channel is calculated as in other chips, but the output of the channel
+**    gets shifted right by one *before* sending to accumulator. That was impossible to do
+**    with previous implementation).
+**
+** 23-07-2001 Jarek Burczynski, Nicola Salmoria:
+**  - corrected YM2610 ADPCM type A algorithm and tables (verified on real chip)
+**
+** 11-06-2001 Jarek Burczynski:
+**  - corrected end of sample bug in OPNB_ADPCM_CALC_CHA.
+**    Real YM2610 checks for equality between current and end addresses (only 20 LSB bits).
+**
+** 08-12-98 hiro-shi:
+** rename ADPCMA -> ADPCMB, ADPCMB -> ADPCMA
+** move ROM limit check.(CALC_CH? -> 2610Write1/2)
+** test program (ADPCMB_TEST)
+** move ADPCM A/B end check.
+** ADPCMB repeat flag(no check)
+** change ADPCM volume rate (8->16) (32->48).
+**
+** 09-12-98 hiro-shi:
+** change ADPCM volume. (8->16, 48->64)
+** replace ym2610 ch0/3 (YM-2610B)
+** init cur_chip (restart bug fix)
+** change ADPCM_SHIFT (10->8) missing bank change 0x4000-0xffff.
+** add ADPCM_SHIFT_MASK
+** change ADPCMA_DECODE_MIN/MAX.
+*/
+
+
+
+/*
+	TO DO:
+!!!!!!!	CORRECT FIRST MISSING CREDIT SOUND IN GIGANDES (DELTA-T module, when DELTAN register = 0) !!!!!!
+		- use real sample rate and let mixer.c do the sample rate convertion
+
+	no check:
+		YM2608 rhythm sound
+		YM2151 CSM speech mode
+
+	no support:
+		YM2608 status mask (register :0x110)
+		YM2608 RYTHM sound
+		YM2608 PCM memory data access , DELTA-T-ADPCM with PCM port
+		YM2151 CSM speech mode with internal timer
+
+	preliminary :
+		key scale level rate (?)
+		YM2151 noise mode (CH7.OP4)
+		LFO contoller (YM2612/YM2610/YM2608/YM2151)
+
+	note:
+                        OPN                           OPM
+		fnum          fM * 2^20 / (fM/(12*n))
+		TimerOverA    ( 12*n)*(1024-NA)/fM        64*(1024-Na)/fM
+		TimerOverB    (192*n)*(256-NB)/fM       1024*(256-Nb)/fM
+		output bits   10bit<<3bit               16bit * 2ch (YM3012=10bit<<3bit)
+		sampling rate fFM / (12*prescaler)      fM / 64
+*/
+
+/************************************************************************/
+/*    comment of hiro-shi(Hiromitsu Shioya)                             */
+/*    YM2610(B) = OPN-B                                                 */
+/*    YM2610  : PSG:3ch FM:4ch ADPCM(18.5KHz):6ch DeltaT ADPCM:1ch      */
+/*    YM2610B : PSG:3ch FM:6ch ADPCM(18.5KHz):6ch DeltaT ADPCM:1ch      */
+/************************************************************************/
+
+/* This version of fm.c is a fork of the MAME 0.59 one, relicensed under the LGPL.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define INLINE static inline
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <math.h>
+
+#include "hw.h"
+#include "qemu-timer.h"
+#include "ay8910.h"
+#include "fm.h"
+/* include external DELTA-T ADPCM unit */
+#include "ymdeltat.h"		/* DELTA-T ADPCM UNIT */
+
+#define logerror(...)
+
+/* for busy flag emulation , function FM_GET_TIME_NOW() should be */
+/* return the present time in second unit with (double) value     */
+#if FM_BUSY_FLAG_SUPPORT
+#define FM_GET_TIME_NOW() ((double)qemu_get_clock(rt_clock) / 1000.0)
+#endif
+
+#ifndef PI
+#define PI 3.14159265358979323846
+#endif
+
+/* -------------------- sound quality define selection --------------------- */
+#define FREQ_SH			16  /* 16.16 fixed point (frequency calculations) */
+#define ENV_SH			16  /* 16.16 fixed point (envelope calculations)  */
+#define LFO_SH			23  /*  9.23 fixed point (LFO calculations)       */
+#define TIMER_SH		16  /* 16.16 fixed point (timers calculations)    */
+
+#define FREQ_MASK		((1<<FREQ_SH)-1)
+#define ENV_MASK		((1<<ENV_SH)-1)
+
+/* envelope output entries */
+#define ENV_BITS		10
+#define ENV_LEN			(1<<ENV_BITS)
+#define ENV_STEP		(128.0/ENV_LEN)
+#define ENV_QUIET		((int)(0x68/(ENV_STEP)))
+
+#define MAX_ATT_INDEX	((ENV_LEN<<ENV_SH)-1) /* 1023.ffff */
+#define MIN_ATT_INDEX	(      (1<<ENV_SH)-1) /*    0.ffff */
+
+/* sinwave entries */
+#define SIN_BITS		10
+#define SIN_LEN			(1<<SIN_BITS)
+#define SIN_MASK		(SIN_LEN-1)
+
+#define TL_RES_LEN		(256)	/* 8 bits addressing (real chip) */
+
+
+/* LFO table entries */
+#define LFO_ENT 512
+#define LFO_RATE 0x10000
+#define PMS_RATE 0x400
+/* LFO runtime work */
+static UINT32 lfo_amd;
+static INT32 lfo_pmd;
+static UINT32 LFOCnt,LFOIncr;	/* LFO Phase Generator */
+/* OPN LFO waveform table */
+static INT32 OPN_LFO_wave[LFO_ENT];
+
+/* -------------------- tables --------------------- */
+
+/* sustain level table (3db per step) */
+/* bit0, bit1, bit2, bit3, bit4, bit5, bit6 */
+/* 1,    2,    4,    8,    16,   32,   64   (value)*/
+/* 0.75, 1.5,  3,    6,    12,   24,   48   (dB)*/
+
+/* 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,93 (dB)*/
+#define SC(db) (UINT32) ( db * (4.0/ENV_STEP) * (1<<ENV_SH) )
+static const UINT32 SL_TABLE[16]={
+ SC( 0),SC( 1),SC( 2),SC(3 ),SC(4 ),SC(5 ),SC(6 ),SC( 7),
+ SC( 8),SC( 9),SC(10),SC(11),SC(12),SC(13),SC(14),SC(31)
+};
+#undef SC
+
+/*	TL_TAB_LEN is calculated as:
+*	13 - sinus amplitude bits     (Y axis)
+*	2  - sinus sign bit           (Y axis)
+*	TL_RES_LEN - sinus resolution (X axis)
+*/
+#define TL_TAB_LEN (13*2*TL_RES_LEN)
+static signed int tl_tab[TL_TAB_LEN];
+
+/* sin waveform table in 'decibel' scale */
+static unsigned int sin_tab[SIN_LEN];
+
+
+
+#define OPM_DTTABLE OPN_DTTABLE
+static UINT8 OPN_DTTABLE[4 * 32]={
+/* this is YM2151 and YM2612 phase increment data (in 10.10 fixed point format)*/
+/* FD=0 */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* FD=1 */
+	0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+	2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, 8, 8, 8, 8,
+/* FD=2 */
+	1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5,
+	5, 6, 6, 7, 8, 8, 9,10,11,12,13,14,16,16,16,16,
+/* FD=3 */
+	2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7,
+	8 , 8, 9,10,11,12,13,14,16,17,19,20,22,22,22,22
+};
+
+
+
+/* output final shift */
+#if (FM_SAMPLE_BITS==16)
+	#define FINAL_SH	(0)
+	#define MAXOUT		(+32767)
+	#define MINOUT		(-32768)
+#else
+	#define FINAL_SH	(8)
+	#define MAXOUT		(+127)
+	#define MINOUT		(-128)
+#endif
+
+/* -------------------- local defines , macros --------------------- */
+/* register number to channel number , slot offset */
+#define OPN_CHAN(N) (N&3)
+#define OPN_SLOT(N) ((N>>2)&3)
+#define OPM_CHAN(N) (N&7)
+#define OPM_SLOT(N) ((N>>3)&3)
+
+/* slot number */
+#define SLOT1 0
+#define SLOT2 2
+#define SLOT3 1
+#define SLOT4 3
+
+/* bit0 = Right enable , bit1 = Left enable */
+#define OUTD_RIGHT  1
+#define OUTD_LEFT   2
+#define OUTD_CENTER 3
+
+
+
+/* ---------- debug section ------------------- */
+/* save output as raw 16-bit sample */
+/* #define SAVE_SAMPLE */
+
+#ifdef SAVE_SAMPLE
+static FILE *sample[1];
+	#if 1	/*save to MONO file */
+		#define SAVE_ALL_CHANNELS \
+		{	signed int pom = lt; \
+			fputc((unsigned short)pom&0xff,sample[0]); \
+			fputc(((unsigned short)pom>>8)&0xff,sample[0]); \
+		}
+	#else	/*save to STEREO file */
+		#define SAVE_ALL_CHANNELS \
+		{	signed int pom = lt; \
+			fputc((unsigned short)pom&0xff,sample[0]); \
+			fputc(((unsigned short)pom>>8)&0xff,sample[0]); \
+			pom = rt; \
+			fputc((unsigned short)pom&0xff,sample[0]); \
+			fputc(((unsigned short)pom>>8)&0xff,sample[0]); \
+		}
+	#endif
+#endif
+
+
+/* ---------- OPN / OPM one channel  ---------- */
+typedef struct fm_slot {
+	INT32		 *DT;	/* detune          :DT_TABLE[DT]		*/
+	int			 DT2;	/* multiple,Detune2:(DT2<<4)|ML for OPM	*/
+	UINT8		 KSR;	/* key scale rate  :3-KSR				*/
+	UINT8		ARval;	/* current AR							*/
+	const UINT32 *AR;	/* attack rate     :&AR_TABLE[AR<<1]	*/
+	const UINT32 *DR;	/* decay rate      :&DR_TABLE[DR<<1]	*/
+	const UINT32 *SR;	/* sustain rate    :&DR_TABLE[SR<<1]	*/
+	const UINT32 *RR;	/* release rate    :&DR_TABLE[RR<<2+2]	*/
+	UINT8		 ksr;	/* key scale rate  :kcode>>(3-KSR)		*/
+	UINT32		 mul;	/* multiple        :ML_TABLE[ML]		*/
+
+	/* Phase Generator */
+	UINT32 Cnt;			/* phase counter						*/
+	UINT32 Incr;		/* phase step							*/
+
+	/* Envelope Generator */
+	UINT8	state;		/* phase type							*/
+	UINT32	TL;			/* total level     :TL << 3				*/
+	INT32	volume;		/* envelope counter						*/
+	UINT32	sl;			/* sustain level   :SL_TABLE[SL]		*/
+	UINT32	delta_ar;	/* envelope step for Attack				*/
+	UINT32	delta_dr;	/* envelope step for Decay				*/
+	UINT32	delta_sr;	/* envelope step for Sustain			*/
+	UINT32	delta_rr;	/* envelope step for Release			*/
+	UINT8	SEG;		/* SSG-EG waveform						*/
+    UINT8	SEGn;		/* SSG-EG negated output				*/
+
+	UINT32	key;		/* 0=last key was KEY OFF, 1=KEY ON		*/
+
+	/* LFO */
+	UINT32	amon;		/* AMS enable flag						*/
+	UINT32	ams;		/* AMS depth level of this SLOT			*/
+}FM_SLOT;
+
+typedef struct fm_chan {
+	FM_SLOT	SLOT[4];
+	UINT8 ALGO;			/* algorithm						*/
+	UINT8 FB;			/* feedback shift					*/
+	INT32 op1_out[2];	/* op1 output for feedback			*/
+	/* algorithm (connection) */
+	INT32 *connect1;	/* pointer of SLOT1 output			*/
+	INT32 *connect2;	/* pointer of SLOT2 output			*/
+	INT32 *connect3;	/* pointer of SLOT3 output			*/
+	INT32 *connect4;	/* pointer of SLOT4 output			*/
+	/* LFO */
+	INT32 pms;			/* PMS depth channel level			*/
+	UINT32 ams;			/* AMS depth channel level			*/
+	/* Phase Generator */
+	UINT32 fc;			/* fnum,blk:adjusted to sample rate	*/
+	UINT8 kcode;		/* key code:						*/
+} FM_CH;
+
+/* OPN/OPM common state */
+typedef struct fm_state {
+	UINT8 index;		/* chip index (number of chip)	*/
+	int clock;			/* master clock  (Hz)	*/
+	int rate;			/* sampling rate (Hz)	*/
+	double freqbase;	/* frequency base		*/
+	int TimerPres;		/* timer prescaler      */
+#if FM_BUSY_FLAG_SUPPORT
+	double BusyExpire;	/* ExpireTime of Busy clear */
+#endif
+	UINT8 address;		/* address register		*/
+	UINT8 irq;			/* interrupt level		*/
+	UINT8 irqmask;		/* irq mask				*/
+	UINT8 status;		/* status flag			*/
+	UINT32 mode;		/* mode  CSM / 3SLOT	*/
+	UINT8 prescaler_sel;/* prescaler selector	*/
+	UINT8 fn_h;			/* freq latch			*/
+	int TA;				/* timer a				*/
+	int TAC;			/* timer a counter		*/
+	UINT8 TB;			/* timer b				*/
+	int TBC;			/* timer b counter		*/
+	/* local time tables */
+	INT32 DT_TABLE[8][32];		/* DeTune table		*/
+	UINT32 eg_tab [32+64+32];	/* Envelope Generator rates (32 + 64 rates + 32 RKS) */
+	/* Extention Timer and IRQ handler */
+	FM_TIMERHANDLER	Timer_Handler;
+	FM_IRQHANDLER	IRQ_Handler;
+}FM_ST;
+
+
+/* -------------------- state --------------------- */
+
+/* some globals */
+#define TYPE_SSG    0x01    /* SSG support          */
+//#define	xxxxxx		0x02	/* not used */
+#define TYPE_LFOPAN 0x04    /* OPN type LFO and PAN */
+#define TYPE_6CH    0x08    /* FM 6CH / 3CH         */
+#define TYPE_DAC    0x10    /* YM2612's DAC device  */
+#define TYPE_ADPCM  0x20    /* two ADPCM units      */
+
+#define TYPE_YM2608 (TYPE_SSG |TYPE_LFOPAN |TYPE_6CH |TYPE_ADPCM)
+
+/* current chip state */
+static void *cur_chip = 0;		/* pointer of current chip struct */
+static FM_ST  *State;			/* basic status */
+static FM_CH  *cch[8];			/* pointer of FM channels */
+
+
+/* runtime work */
+static INT32 out_fm[8];			/* outputs of working channels */
+static INT32 out_adpcm[4];		/* channel output NONE,LEFT,RIGHT or CENTER for YM2608 ADPCM */
+static INT32 out_delta[4];		/* channel output NONE,LEFT,RIGHT or CENTER for YM2608 DELTAT*/
+static INT32 pg_in2,pg_in3,pg_in4;	/* PG input of SLOTs */
+
+
+/* -------------------- log output  -------------------- */
+/* log output level */
+#define LOG_ERR  3      /* ERROR       */
+#define LOG_WAR  2      /* WARNING     */
+#define LOG_INF  1      /* INFORMATION */
+#define LOG_LEVEL LOG_INF
+
+#ifndef __RAINE__
+#define LOG(n,x) if( (n)>=LOG_LEVEL ) logerror x
+#endif
+
+/* ----- limitter ----- */
+#define Limit(val, max,min) { \
+	if ( val > max )      val = max; \
+	else if ( val < min ) val = min; \
+}
+
+/* ----- buffering one of data(STEREO chip) ----- */
+#if FM_STEREO_MIX
+/* stereo mixing */
+#define FM_BUFFERING_STEREO \
+{														\
+	/* get left & right output with clipping */			\
+	out_ch[OUTD_LEFT]  += out_ch[OUTD_CENTER];				\
+	Limit( out_ch[OUTD_LEFT] , MAXOUT, MINOUT );	\
+	out_ch[OUTD_RIGHT] += out_ch[OUTD_CENTER];				\
+	Limit( out_ch[OUTD_RIGHT], MAXOUT, MINOUT );	\
+	/* buffering */										\
+	*bufL++ = out_ch[OUTD_LEFT] >>FINAL_SH;				\
+	*bufL++ = out_ch[OUTD_RIGHT]>>FINAL_SH;				\
+}
+#else
+/* stereo separate */
+#define FM_BUFFERING_STEREO \
+{														\
+	/* get left & right output with clipping */			\
+	out_ch[OUTD_LEFT]  += out_ch[OUTD_CENTER];				\
+	Limit( out_ch[OUTD_LEFT] , MAXOUT, MINOUT );	\
+	out_ch[OUTD_RIGHT] += out_ch[OUTD_CENTER];				\
+	Limit( out_ch[OUTD_RIGHT], MAXOUT, MINOUT );	\
+	/* buffering */										\
+	bufL[i] = out_ch[OUTD_LEFT] >>FINAL_SH;				\
+	bufR[i] = out_ch[OUTD_RIGHT]>>FINAL_SH;				\
+}
+#endif
+
+#if FM_INTERNAL_TIMER
+/* ----- internal timer mode , update timer */
+
+/* ---------- calculate timer A ---------- */
+	#define INTERNAL_TIMER_A(ST,CSM_CH)					\
+	{													\
+		if( ST->TAC && (ST->Timer_Handler==0) )		\
+			if( (ST->TAC -= (int)(ST->freqbase*4096)) <= 0 )	\
+			{											\
+				TimerAOver( ST );						\
+				/* CSM mode total level latch and auto key on */	\
+				if( ST->mode & 0x80 )					\
+					CSMKeyControll( CSM_CH );			\
+			}											\
+	}
+/* ---------- calculate timer B ---------- */
+	#define INTERNAL_TIMER_B(ST,step)						\
+	{														\
+		if( ST->TBC && (ST->Timer_Handler==0) )				\
+			if( (ST->TBC -= (int)(ST->freqbase*4096*step)) <= 0 )	\
+				TimerBOver( ST );							\
+	}
+#else /* FM_INTERNAL_TIMER */
+/* external timer mode */
+#define INTERNAL_TIMER_A(ST,CSM_CH)
+#define INTERNAL_TIMER_B(ST,step)
+#endif /* FM_INTERNAL_TIMER */
+
+/* --------------------- subroutines  --------------------- */
+/* status set and IRQ handling */
+INLINE void FM_STATUS_SET(FM_ST *ST,int flag)
+{
+	/* set status flag */
+	ST->status |= flag;
+	if ( !(ST->irq) && (ST->status & ST->irqmask) )
+	{
+		ST->irq = 1;
+		/* callback user interrupt handler (IRQ is OFF to ON) */
+		if(ST->IRQ_Handler) (ST->IRQ_Handler)(ST->index,1);
+	}
+}
+
+/* status reset and IRQ handling */
+INLINE void FM_STATUS_RESET(FM_ST *ST,int flag)
+{
+	/* reset status flag */
+	ST->status &=~flag;
+	if ( (ST->irq) && !(ST->status & ST->irqmask) )
+	{
+		ST->irq = 0;
+		/* callback user interrupt handler (IRQ is ON to OFF) */
+		if(ST->IRQ_Handler) (ST->IRQ_Handler)(ST->index,0);
+	}
+}
+
+/* IRQ mask set */
+INLINE void FM_IRQMASK_SET(FM_ST *ST,int flag)
+{
+	ST->irqmask = flag;
+	/* IRQ handling check */
+	FM_STATUS_SET(ST,0);
+	FM_STATUS_RESET(ST,0);
+}
+
+#if FM_BUSY_FLAG_SUPPORT
+INLINE UINT8 FM_STATUS_FLAG(FM_ST *ST)
+{
+	if( ST->BusyExpire )
+	{
+		if( (ST->BusyExpire - FM_GET_TIME_NOW()) > 0)
+			return ST->status | 0x80; /* with busy */
+		/* expire */
+		ST->BusyExpire = 0;
+	}
+	return ST->status;
+}
+INLINE void FM_BUSY_SET(FM_ST *ST,int busyclock )
+{
+	ST->BusyExpire = FM_GET_TIME_NOW() + (busyclock * ST->TimerPres / ST->clock);
+}
+#define FM_BUSY_CLEAR(ST) ((ST)->BusyExpire = 0)
+#else
+#define FM_STATUS_FLAG(ST) ((ST)->status)
+#define FM_BUSY_SET(ST,bclock) {}
+#define FM_BUSY_CLEAR(ST) {}
+#endif
+
+
+/* Envelope Generator phases */
+
+//#define EG_DEC_SSG_EG	6
+//#define EG_SUS_SSG_EG	5
+//#define EG_HLD_SSG_EG	4
+#define EG_ATT			4
+#define EG_DEC			3
+#define EG_SUS			2
+#define EG_REL			1
+#define EG_OFF			0
+
+
+
+INLINE void FM_KEYON(FM_CH *CH , int s )
+{
+	FM_SLOT *SLOT = &CH->SLOT[s];
+	if( !SLOT->key )
+	{
+		SLOT->key = 1;
+		/* restart Phase Generator */
+		SLOT->Cnt = 0;
+		/* phase -> Attack */
+		SLOT->state = EG_ATT;
+	}
+}
+
+INLINE void FM_KEYOFF(FM_CH *CH , int s )
+{
+	FM_SLOT *SLOT = &CH->SLOT[s];
+	if( SLOT->key )
+	{
+		SLOT->key = 0;
+		/* phase -> Release */
+		if (SLOT->state>EG_REL)
+			SLOT->state = EG_REL;
+	}
+}
+
+/* set algorithm connection */
+static void setup_connection( FM_CH *CH, int ch )
+{
+	INT32 *carrier = &out_fm[ch];
+
+	switch( CH->ALGO ){
+	case 0:
+		/*  PG---S1---S2---S3---S4---OUT */
+		CH->connect1 = &pg_in2;
+		CH->connect2 = &pg_in3;
+		CH->connect3 = &pg_in4;
+		break;
+	case 1:
+		/*  PG---S1-+-S3---S4---OUT */
+		/*  PG---S2-+               */
+		CH->connect1 = &pg_in3;
+		CH->connect2 = &pg_in3;
+		CH->connect3 = &pg_in4;
+		break;
+	case 2:
+		/* PG---S1------+-S4---OUT */
+		/* PG---S2---S3-+          */
+		CH->connect1 = &pg_in4;
+		CH->connect2 = &pg_in3;
+		CH->connect3 = &pg_in4;
+		break;
+	case 3:
+		/* PG---S1---S2-+-S4---OUT */
+		/* PG---S3------+          */
+		CH->connect1 = &pg_in2;
+		CH->connect2 = &pg_in4;
+		CH->connect3 = &pg_in4;
+		break;
+	case 4:
+		/* PG---S1---S2-+--OUT */
+		/* PG---S3---S4-+      */
+		CH->connect1 = &pg_in2;
+		CH->connect2 = carrier;
+		CH->connect3 = &pg_in4;
+		break;
+	case 5:
+		/*         +-S2-+     */
+		/* PG---S1-+-S3-+-OUT */
+		/*         +-S4-+     */
+		CH->connect1 = 0;	/* special case */
+		CH->connect2 = carrier;
+		CH->connect3 = carrier;
+		break;
+	case 6:
+		/* PG---S1---S2-+     */
+		/* PG--------S3-+-OUT */
+		/* PG--------S4-+     */
+		CH->connect1 = &pg_in2;
+		CH->connect2 = carrier;
+		CH->connect3 = carrier;
+		break;
+	case 7:
+		/* PG---S1-+     */
+		/* PG---S2-+-OUT */
+		/* PG---S3-+     */
+		/* PG---S4-+     */
+		CH->connect1 = carrier;
+		CH->connect2 = carrier;
+		CH->connect3 = carrier;
+	}
+	CH->connect4 = carrier;
+}
+
+/* set detune & multiple */
+INLINE void set_det_mul(FM_ST *ST,FM_CH *CH,FM_SLOT *SLOT,int v)
+{
+	SLOT->mul = (v&0x0f)? (v&0x0f)*2 : 1;
+	SLOT->DT  = ST->DT_TABLE[(v>>4)&7];
+	CH->SLOT[SLOT1].Incr=-1;
+}
+
+/* set total level */
+INLINE void set_tl(FM_CH *CH,FM_SLOT *SLOT , int v,int csmflag)
+{
+	SLOT->TL = (v&0x7f)<<(ENV_BITS-7); /* 7bit TL */
+}
+
+/* set attack rate & key scale  */
+INLINE void set_ar_ksr(FM_CH *CH,FM_SLOT *SLOT,int v,UINT32 *eg_tab)
+{
+	SLOT->KSR   = 3-(v>>6);
+	SLOT->ARval = (v&0x1f) ? 32 + ((v&0x1f)<<1) : 0;
+	SLOT->AR    = &eg_tab[ SLOT->ARval ];
+
+	if ((SLOT->ARval + SLOT->ksr) < 32+62)
+		SLOT->delta_ar = SLOT->AR[SLOT->ksr];
+	else
+		SLOT->delta_ar = MAX_ATT_INDEX+1;
+
+	CH->SLOT[SLOT1].Incr=-1;	/* Optimize: only set this, if new SLOT->KSR is different */
+}
+
+/* set decay rate */
+INLINE void set_dr(FM_SLOT *SLOT,int v,UINT32 *eg_tab)
+{
+	SLOT->DR = (v&0x1f) ? &eg_tab[32 + ((v&0x1f)<<1)] : &eg_tab[0];
+	SLOT->delta_dr = SLOT->DR[SLOT->ksr];
+}
+
+/* set sustain rate */
+INLINE void set_sr(FM_SLOT *SLOT,int v,UINT32 *eg_tab)
+{
+	SLOT->SR = (v&0x1f) ? &eg_tab[32 + ((v&0x1f)<<1)] : &eg_tab[0];
+	SLOT->delta_sr = SLOT->SR[SLOT->ksr];
+}
+
+/* set release rate */
+INLINE void set_sl_rr(FM_SLOT *SLOT,int v,UINT32 *eg_tab)
+{
+	SLOT->sl = SL_TABLE[ v>>4 ];
+	SLOT->RR  = &eg_tab[34 + ((v&0x0f)<<2)];
+	SLOT->delta_rr = SLOT->RR[SLOT->ksr];
+}
+
+
+
+INLINE signed int op_calc(UINT32 phase, unsigned int env, signed int pm)
+{
+	UINT32 p;
+
+	p = (env<<3) + sin_tab[ ( ((signed int)((phase & ~FREQ_MASK) + (pm<<15))) >> FREQ_SH ) & SIN_MASK ];
+
+	if (p >= TL_TAB_LEN)
+		return 0;
+	return tl_tab[p];
+}
+
+INLINE signed int op_calc1(UINT32 phase, unsigned int env, signed int pm)
+{
+	UINT32 p;
+	INT32  i;
+
+	i = (phase & ~FREQ_MASK) + pm;
+
+/*logerror("i=%08x (i>>16)&511=%8i phase=%i [pm=%08x] ",i, (i>>16)&511, phase>>FREQ_SH, pm);*/
+
+	p = (env<<3) + sin_tab[ (i>>FREQ_SH) & SIN_MASK];
+
+/*logerror("(p&255=%i p>>8=%i) out= %i\n", p&255,p>>8, tl_tab[p&255]>>(p>>8) );*/
+
+	if (p >= TL_TAB_LEN)
+		return 0;
+	return tl_tab[p];
+}
+
+
+
+
+
+INLINE unsigned int calc_eg(FM_SLOT *SLOT)
+{
+	unsigned int out;
+	unsigned int swap_flag = 0;
+
+
+	switch(SLOT->state)
+	{
+	case EG_ATT:		/* attack phase */
+	{
+		INT32 step = SLOT->volume;
+
+		SLOT->volume -= SLOT->delta_ar;
+		step = (step>>ENV_SH) - (((UINT32)SLOT->volume)>>ENV_SH);	/* number of levels passed since last time */
+		if (step > 0)
+		{
+			INT32 tmp_volume = SLOT->volume + (step<<ENV_SH);	/* adjust by number of levels */
+			do
+			{
+				tmp_volume = tmp_volume - (1<<ENV_SH) - ((tmp_volume>>4) & ~ENV_MASK);
+				if (tmp_volume <= MIN_ATT_INDEX)
+					break;
+				step--;
+			}while(step);
+			SLOT->volume = tmp_volume;
+		}
+
+		if (SLOT->volume <= MIN_ATT_INDEX)
+		{
+			if (SLOT->volume < 0)
+				SLOT->volume = 0;	/* this is not quite correct (checked) */
+
+			SLOT->state = EG_DEC;
+		}
+	}
+	break;
+
+
+	case EG_DEC:	/* decay phase */
+
+		if (SLOT->SEG&0x08)	/* SSG EG type envelope selected */
+		{
+				INT32 step = SLOT->volume;
+				SLOT->volume += SLOT->delta_dr;
+				step = (((UINT32)SLOT->volume)>>ENV_SH) - (step>>ENV_SH);	/* number of levels passed since last time */
+
+				if ( (SLOT->volume += ((step*3)<<ENV_SH)) >= SLOT->sl )
+				{
+					SLOT->volume = SLOT->sl;	/* this is not quite correct (checked) */
+					SLOT->state = EG_SUS;
+				}
+		}
+		else
+		{
+			if ( (SLOT->volume += SLOT->delta_dr) >= SLOT->sl )
+			{
+				SLOT->volume = SLOT->sl;	/* this is not quite correct (checked) */
+				SLOT->state = EG_SUS;
+			}
+		}
+	break;
+
+	case EG_SUS:	/* sustain phase */
+
+		if (SLOT->SEG&0x08)	/* SSG EG type envelope selected */
+		{
+			INT32 step = SLOT->volume;
+			SLOT->volume += SLOT->delta_sr;
+			step = (((UINT32)SLOT->volume)>>ENV_SH) - (step>>ENV_SH);	/* number of levels passed since last time */
+
+			if ( (SLOT->volume += ((step*3)<<ENV_SH)) > MAX_ATT_INDEX )
+			{
+				SLOT->volume = MAX_ATT_INDEX;
+
+				if (SLOT->SEG&0x01)	/* bit 0 = hold */
+				{
+					if (SLOT->SEGn&1)	/* have we swapped once ??? */
+					{
+						/* yes, so do nothing, just hold current level */
+					}
+					else
+						swap_flag = (SLOT->SEG&0x02) | 1 ; /* bit 1 = alternate */
+
+				}
+				else
+				{
+					/* same as KEY-ON operation */
+
+					/* restart of the Phase Generator should be here,
+                    	only if AR is not maximum ??? */
+					/*SLOT->Cnt = 0;*/
+
+					/* phase -> Attack */
+					SLOT->state = EG_ATT;
+
+					swap_flag = (SLOT->SEG&0x02); /* bit 1 = alternate */
+				}
+			}
+
+		}
+		else
+		{
+			if ( (SLOT->volume += SLOT->delta_sr) > MAX_ATT_INDEX )
+			{
+				SLOT->volume = MAX_ATT_INDEX;
+				/* do not change the EG phase (verified on real chip) */
+			}
+		};
+	break;
+
+	case EG_REL:	/* release phase */
+		if ( (SLOT->volume += SLOT->delta_rr) > MAX_ATT_INDEX )
+		{
+			SLOT->volume = MAX_ATT_INDEX;
+			SLOT->state = EG_OFF;
+		}
+	break;
+
+	}
+
+	out = SLOT->TL + (((unsigned int)SLOT->volume)>>ENV_SH);
+
+	if (SLOT->SEGn&2)	/* negate output (changes come from alternate bit, init comes from attack bit) */
+		out ^= 1023;
+
+	SLOT->SEGn ^= swap_flag;
+
+
+	if(SLOT->ams)
+		out += (SLOT->ams*lfo_amd/LFO_RATE);
+
+	return out;
+}
+
+
+/* ---------- calculate one channel ---------- */
+INLINE void FM_CALC_CH( FM_CH *CH )
+{
+	unsigned int eg_out1,eg_out2,eg_out3,eg_out4;  /* envelope output */
+
+	/* Phase Generator */
+	pg_in2 = pg_in3 = pg_in4 = 0;
+
+	/* Envelope Generator */
+	eg_out1 = calc_eg(&CH->SLOT[SLOT1]);
+	eg_out2 = calc_eg(&CH->SLOT[SLOT2]);
+	eg_out3 = calc_eg(&CH->SLOT[SLOT3]);
+	eg_out4 = calc_eg(&CH->SLOT[SLOT4]);
+
+	/* Connection */
+	{
+		INT32 out = CH->op1_out[0] + CH->op1_out[1];
+		CH->op1_out[0] = CH->op1_out[1];
+
+		if( !CH->connect1 ){
+			/* algorithm 5  */
+			pg_in2 = pg_in3	= pg_in4 = CH->op1_out[0];
+		}else{
+			/* other algorithms */
+			*CH->connect1 += CH->op1_out[0];
+		}
+
+		CH->op1_out[1] = 0;
+		if( eg_out1 < ENV_QUIET )	/* SLOT 1 */
+			CH->op1_out[1] = op_calc1(CH->SLOT[SLOT1].Cnt, eg_out1, (out<<CH->FB) );
+	}
+
+	if( eg_out2 < ENV_QUIET )		/* SLOT 2 */
+		*CH->connect2 += op_calc(CH->SLOT[SLOT2].Cnt, eg_out2, pg_in2);
+
+	if( eg_out3 < ENV_QUIET )		/* SLOT 3 */
+		*CH->connect3 += op_calc(CH->SLOT[SLOT3].Cnt, eg_out3, pg_in3);
+
+	if( eg_out4 < ENV_QUIET )		/* SLOT 4 */
+		*CH->connect4 += op_calc(CH->SLOT[SLOT4].Cnt, eg_out4, pg_in4);
+
+
+	/* update phase counters AFTER output calculations */
+	{
+		INT32 pms = lfo_pmd * CH->pms / LFO_RATE;
+		if(pms)
+		{
+			CH->SLOT[SLOT1].Cnt += CH->SLOT[SLOT1].Incr + (INT32)(pms * CH->SLOT[SLOT1].Incr) / PMS_RATE;
+			CH->SLOT[SLOT2].Cnt += CH->SLOT[SLOT2].Incr + (INT32)(pms * CH->SLOT[SLOT2].Incr) / PMS_RATE;
+			CH->SLOT[SLOT3].Cnt += CH->SLOT[SLOT3].Incr + (INT32)(pms * CH->SLOT[SLOT3].Incr) / PMS_RATE;
+			CH->SLOT[SLOT4].Cnt += CH->SLOT[SLOT4].Incr + (INT32)(pms * CH->SLOT[SLOT4].Incr) / PMS_RATE;
+		}
+		else
+		{
+			CH->SLOT[SLOT1].Cnt += CH->SLOT[SLOT1].Incr;
+			CH->SLOT[SLOT2].Cnt += CH->SLOT[SLOT2].Incr;
+			CH->SLOT[SLOT3].Cnt += CH->SLOT[SLOT3].Incr;
+			CH->SLOT[SLOT4].Cnt += CH->SLOT[SLOT4].Incr;
+		}
+	}
+}
+
+/* ---------- update phase increment counter of operator ---------- */
+INLINE void CALC_FCSLOT(FM_SLOT *SLOT , int fc , int kc )
+{
+	int ksr;
+
+	/* (frequency) phase increment counter */
+	SLOT->Incr = ((fc+SLOT->DT[kc])*SLOT->mul) >> 1;
+
+	ksr = kc >> SLOT->KSR;
+	if( SLOT->ksr != ksr )
+	{
+		SLOT->ksr = ksr;
+		/* calculate envelope generator rates */
+		if ((SLOT->ARval + ksr) < 32+62)
+			SLOT->delta_ar = SLOT->AR[ksr];
+		else
+			SLOT->delta_ar = MAX_ATT_INDEX+1;
+		SLOT->delta_dr = SLOT->DR[ksr];
+		SLOT->delta_sr = SLOT->SR[ksr];
+		SLOT->delta_rr = SLOT->RR[ksr];
+	}
+}
+
+/* ---------- update phase increments counters  ---------- */
+INLINE void OPN_CALC_FCOUNT(FM_CH *CH )
+{
+	if( CH->SLOT[SLOT1].Incr==-1){
+		int fc = CH->fc;
+		int kc = CH->kcode;
+		CALC_FCSLOT(&CH->SLOT[SLOT1] , fc , kc );
+		CALC_FCSLOT(&CH->SLOT[SLOT2] , fc , kc );
+		CALC_FCSLOT(&CH->SLOT[SLOT3] , fc , kc );
+		CALC_FCSLOT(&CH->SLOT[SLOT4] , fc , kc );
+	}
+}
+
+/* ----------- initialize time tables ----------- */
+static void init_timetables( FM_ST *ST , UINT8 *DTTABLE )
+{
+	int i,d;
+	double rate;
+
+#if 0
+	logerror("FM.C: samplerate=%8i chip clock=%8i  freqbase=%f  \n",
+			 ST->rate, ST->clock, ST->freqbase );
+#endif
+
+	/* DeTune table */
+	for (d = 0;d <= 3;d++){
+		for (i = 0;i <= 31;i++){
+			rate = ((double)DTTABLE[d*32 + i]) * SIN_LEN  * ST->freqbase  * (1<<FREQ_SH) / ((double)(1<<20));
+			ST->DT_TABLE[d][i]   = (INT32) rate;
+			ST->DT_TABLE[d+4][i] = (INT32)-rate;
+#if 0
+			logerror("FM.C: DT [%2i %2i] = %8x  \n", d, i, ST->DT_TABLE[d][i] );
+#endif
+		}
+	}
+
+	/* calculate Envelope Generator rate table */
+	for (i=0; i<34; i++)
+		ST->eg_tab[i] = 0;						/* infinity */
+
+	for (i=2; i<64; i++)
+	{
+		rate = ST->freqbase;					/* frequency rate */
+		if( i < 60 ) rate *= 1.0+(i&3)*0.25;	/* b0-1 : x1 , x1.25 , x1.5 , x1.75 */
+		rate *= 1<< (i>>2);						/* b2-5 : shift bit */
+		rate /= 12.0 * 1024.0;
+		rate *= (double)(1<<ENV_SH);
+		ST->eg_tab[32+i] = rate;
+#if 0
+		logerror("FM.C: Rate %2i %1i  Decay [real %11.4f ms][emul %11.4f ms][d=%08x]\n",i>>2, i&3,
+			( ((double)(ENV_LEN<<ENV_SH)) / rate )                     * (1000.0 / (double)ST->rate),
+			( ((double)(ENV_LEN<<ENV_SH)) / (double)ST->eg_tab[32+i] ) * (1000.0 / (double)ST->rate), ST->eg_tab[32+i] );
+#endif
+	}
+
+	for (i=0; i<32; i++)
+	{
+		ST->eg_tab[ 32+64+i ] = ST->eg_tab[32+63];
+	}
+}
+
+/* ---------- reset one channel  ---------- */
+static void reset_channel( FM_ST *ST , FM_CH *CH , int chan )
+{
+	int c,s;
+
+	ST->mode   = 0;	/* normal mode */
+	FM_STATUS_RESET(ST,0xff);
+	ST->TA     = 0;
+	ST->TAC    = 0;
+	ST->TB     = 0;
+	ST->TBC    = 0;
+
+	for( c = 0 ; c < chan ; c++ )
+	{
+		CH[c].fc = 0;
+		for(s = 0 ; s < 4 ; s++ )
+		{
+			CH[c].SLOT[s].SEG = 0;
+			CH[c].SLOT[s].SEGn = 0;
+			CH[c].SLOT[s].state= EG_OFF;
+			CH[c].SLOT[s].volume = MAX_ATT_INDEX;
+		}
+	}
+}
+
+/* ---------- initialize generic tables ---------- */
+
+static void init_tables(void)
+{
+	signed int i,x;
+	signed int n;
+	double o,m;
+
+	for (x=0; x<TL_RES_LEN; x++)
+	{
+		m = (1<<16) / pow(2, (x+1) * (ENV_STEP/4.0) / 8.0);
+		m = floor(m);
+
+		/* we never reach (1<<16) here due to the (x+1) */
+		/* result fits within 16 bits at maximum */
+
+		n = (int)m;		/* 16 bits here */
+		n >>= 4;		/* 12 bits here */
+		if (n&1)		/* round to nearest */
+			n = (n>>1)+1;
+		else
+			n = n>>1;
+						/* 11 bits here (rounded) */
+		n <<= 2;		/* 13 bits here (as in real chip) */
+		tl_tab[ x*2 + 0 ] = n;
+		tl_tab[ x*2 + 1 ] = -tl_tab[ x*2 + 0 ];
+
+		for (i=1; i<13; i++)
+		{
+			tl_tab[ x*2+0 + i*2*TL_RES_LEN ] =  tl_tab[ x*2+0 ]>>i;
+			tl_tab[ x*2+1 + i*2*TL_RES_LEN ] = -tl_tab[ x*2+0 + i*2*TL_RES_LEN ];
+		}
+	#if 0
+			logerror("tl %04i", x);
+			for (i=0; i<13; i++)
+				logerror(", [%02i] %4x", i*2, tl_tab[ x*2 /*+1*/ + i*2*TL_RES_LEN ]);
+			logerror("\n");
+		}
+	#endif
+	}
+	/*logerror("FM.C: TL_TAB_LEN = %i elements (%i bytes)\n",TL_TAB_LEN, (int)sizeof(tl_tab));*/
+
+
+	for (i=0; i<SIN_LEN; i++)
+	{
+		/* non-standard sinus */
+		m = sin( ((i*2)+1) * PI / SIN_LEN ); /* checked against the real chip */
+
+		/* we never reach zero here due to ((i*2)+1) */
+
+		if (m>0.0)
+			o = 8*log(1.0/m)/log(2);	/* convert to 'decibels' */
+		else
+			o = 8*log(-1.0/m)/log(2);	/* convert to 'decibels' */
+
+		o = o / (ENV_STEP/4);
+
+		n = (int)(2.0*o);
+		if (n&1)						/* round to nearest */
+			n = (n>>1)+1;
+		else
+			n = n>>1;
+
+		sin_tab[ i ] = n*2 + (m>=0.0? 0: 1 );
+		/*logerror("FM.C: sin [%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[i],tl_tab[sin_tab[i]]);*/
+	}
+
+	/*logerror("FM.C: ENV_QUIET= %08x\n",ENV_QUIET );*/
+
+#ifdef SAVE_SAMPLE
+	sample[0]=fopen("sampsum.pcm","wb");
+#endif
+}
+
+static int FMInitTable( void )
+{
+	return 1;
+}
+
+
+static void FMCloseTable( void )
+{
+#if 0
+	if( tl_tab ) free( tl_tab );
+	tl_tab = 0;
+#endif
+#ifdef SAVE_SAMPLE
+	fclose(sample[0]);
+#endif
+	return;
+}
+
+/* OPN/OPM Mode  Register Write */
+INLINE void FMSetMode( FM_ST *ST, int n, int v )
+{
+	/* b7 = CSM MODE */
+	/* b6 = 3 slot mode */
+	/* b5 = reset b */
+	/* b4 = reset a */
+	/* b3 = timer enable b */
+	/* b2 = timer enable a */
+	/* b1 = load b */
+	/* b0 = load a */
+	ST->mode = v;
+
+	/* reset Timer b flag */
+	if( v & 0x20 )
+		FM_STATUS_RESET(ST,0x02);
+	/* reset Timer a flag */
+	if( v & 0x10 )
+		FM_STATUS_RESET(ST,0x01);
+	/* load b */
+	if( v & 0x02 )
+	{
+		if( ST->TBC == 0 )
+		{
+			ST->TBC = ( 256-ST->TB)<<4;
+			/* External timer handler */
+			if (ST->Timer_Handler) (ST->Timer_Handler)(n,1,ST->TBC * ST->TimerPres,ST->clock);
+		}
+	}
+	else
+	{	/* stop timer b */
+		if( ST->TBC != 0 )
+		{
+			ST->TBC = 0;
+			if (ST->Timer_Handler) (ST->Timer_Handler)(n,1,0,ST->clock);
+		}
+	}
+	/* load a */
+	if( v & 0x01 )
+	{
+		if( ST->TAC == 0 )
+		{
+			ST->TAC = (1024-ST->TA);
+			/* External timer handler */
+			if (ST->Timer_Handler) (ST->Timer_Handler)(n,0,ST->TAC * ST->TimerPres,ST->clock);
+		}
+	}
+	else
+	{	/* stop timer a */
+		if( ST->TAC != 0 )
+		{
+			ST->TAC = 0;
+			if (ST->Timer_Handler) (ST->Timer_Handler)(n,0,0,ST->clock);
+		}
+	}
+}
+
+/* Timer A Overflow */
+INLINE void TimerAOver(FM_ST *ST)
+{
+	/* set status (if enabled) */
+	if(ST->mode & 0x04) FM_STATUS_SET(ST,0x01);
+	/* clear or reload the counter */
+	ST->TAC = (1024-ST->TA);
+	if (ST->Timer_Handler) (ST->Timer_Handler)(ST->index,0,ST->TAC * ST->TimerPres,ST->clock);
+}
+/* Timer B Overflow */
+INLINE void TimerBOver(FM_ST *ST)
+{
+	/* set status (if enabled) */
+	if(ST->mode & 0x08) FM_STATUS_SET(ST,0x02);
+	/* clear or reload the counter */
+	ST->TBC = ( 256-ST->TB)<<4;
+	if (ST->Timer_Handler) (ST->Timer_Handler)(ST->index,1,ST->TBC * ST->TimerPres,ST->clock);
+}
+/* CSM Key Controll */
+INLINE void CSMKeyControll(FM_CH *CH)
+{
+	/* all key off */
+	/* FM_KEYOFF(CH,SLOT1); */
+	/* FM_KEYOFF(CH,SLOT2); */
+	/* FM_KEYOFF(CH,SLOT3); */
+	/* FM_KEYOFF(CH,SLOT4); */
+	/* all key on */
+	FM_KEYON(CH,SLOT1);
+	FM_KEYON(CH,SLOT2);
+	FM_KEYON(CH,SLOT3);
+	FM_KEYON(CH,SLOT4);
+}
+
+static void FMsave_state_channel(QEMUFile* f,FM_CH *CH,int num_ch)
+{
+	int slot , ch;
+
+	for(ch=0;ch<num_ch;ch++,CH++)
+	{
+		/* channel */
+		qemu_put_be32s(f, &CH->op1_out[0]);
+		qemu_put_be32s(f, &CH->op1_out[1]);
+		qemu_put_be32s(f, &CH->fc);
+		/* slots */
+		for(slot=0;slot<4;slot++)
+		{
+			FM_SLOT *SLOT = &CH->SLOT[slot];
+			qemu_put_be32s(f, &SLOT->Cnt);
+			qemu_put_8s(f, &SLOT->state);
+			qemu_put_be32s(f, &SLOT->volume);
+		}
+	}
+}
+
+static int FMload_state_channel(QEMUFile* f,FM_CH *CH,int num_ch)
+{
+	int slot , ch;
+
+	for(ch=0;ch<num_ch;ch++,CH++)
+	{
+		/* channel */
+		qemu_get_be32s(f, &CH->op1_out[0]);
+		qemu_get_be32s(f, &CH->op1_out[1]);
+		qemu_get_be32s(f, &CH->fc);
+		/* slots */
+		for(slot=0;slot<4;slot++)
+		{
+			FM_SLOT *SLOT = &CH->SLOT[slot];
+			qemu_get_be32s(f, &SLOT->Cnt);
+			qemu_get_8s(f, &SLOT->state);
+			qemu_get_be32s(f, &SLOT->volume);
+		}
+	}
+
+	return 0;
+}
+
+static void FMsave_state_st(QEMUFile* f,FM_ST *ST)
+{
+#if FM_BUSY_FLAG_SUPPORT
+	uint64_t busy_expire;
+	memcpy(&busy_expire, &ST->BusyExpire, sizeof(double));
+	qemu_put_be64s(f, &busy_expire);
+#endif
+	qemu_put_8s(f, &ST->address);
+	qemu_put_8s(f, &ST->irq);
+	qemu_put_8s(f, &ST->irqmask);
+	qemu_put_8s(f, &ST->status);
+	qemu_put_be32s(f, &ST->mode);
+	qemu_put_8s(f, &ST->prescaler_sel);
+	qemu_put_8s(f, &ST->fn_h);
+	qemu_put_be32s(f, &ST->TA);
+	qemu_put_be32s(f, &ST->TAC);
+	qemu_put_8s(f, &ST->TB);
+	qemu_put_be32s(f, &ST->TBC);
+}
+
+static int FMload_state_st(QEMUFile* f,FM_ST *ST)
+{
+#if FM_BUSY_FLAG_SUPPORT
+	uint64_t busy_expire;
+	qemu_get_be64s(f, &busy_expire);
+	memcpy(&ST->BusyExpire, &busy_expire, sizeof(double));
+#endif
+	qemu_get_8s(f, &ST->address);
+	qemu_get_8s(f, &ST->irq);
+	qemu_get_8s(f, &ST->irqmask);
+	qemu_get_8s(f, &ST->status);
+	qemu_get_be32s(f, &ST->mode);
+	qemu_get_8s(f, &ST->prescaler_sel);
+	qemu_get_8s(f, &ST->fn_h);
+	qemu_get_be32s(f, &ST->TA);
+	qemu_get_be32s(f, &ST->TAC);
+	qemu_get_8s(f, &ST->TB);
+	qemu_get_be32s(f, &ST->TBC);
+
+	return 0;
+}
+
+/***********************************************************/
+/* OPN unit                                                */
+/***********************************************************/
+
+/* OPN 3slot struct */
+typedef struct opn_3slot {
+	UINT32  fc[3];			/* fnum3,blk3  : calculated		*/
+	UINT8 fn_h;				/* freq3 latch					*/
+	UINT8 kcode[3];			/* key code						*/
+}FM_3SLOT;
+
+/* OPN/A/B common state */
+typedef struct opn_f {
+	UINT8 type;				/* chip type					*/
+	FM_ST ST;				/* general state				*/
+	FM_3SLOT SL3;			/* 3 slot mode state			*/
+	FM_CH *P_CH;			/* pointer of CH				*/
+	unsigned int PAN[6*2];	/* fm channels output masks (0xffffffff = enable) */
+
+	UINT32 FN_TABLE[2048];	/* fnumber->increment counter	*/
+	/* LFO */
+	UINT32 LFOCnt;
+	UINT32 LFOIncr;
+	UINT32 LFO_FREQ[8];		/* LFO FREQ table				*/
+} FM_OPN;
+
+/* OPN key frequency number -> key code follow table */
+/* fnum higher 4bit -> keycode lower 2bit */
+static const UINT8 OPN_FKTABLE[16]={0,0,0,0,0,0,0,1,2,3,3,3,3,3,3,3};
+
+//#define LFO_ENT 512
+//#define LFO_SH (32-9)
+//#define LFO_RATE 0x10000
+//#define PMS_RATE 0x400
+
+static int OPNInitTable(void)
+{
+	int i;
+
+	/* LFO wave table */
+	for(i=0; i<LFO_ENT; i++)
+	{
+		OPN_LFO_wave[i]= i<LFO_ENT/2 ?    i*LFO_RATE/(LFO_ENT/2) :
+ 	  							(LFO_ENT-i)*LFO_RATE/(LFO_ENT/2);
+
+		/*logerror("FM.C: OPN_LFO_wave[%4i]= %8x\n",i,OPN_LFO_wave[i]);*/
+		/* 0, 0x0100, 0x0200, 0x0300 ... 0xff00, 0x10000, 0xff00..0x0100 */
+	}
+
+	init_tables();
+
+	return FMInitTable();
+}
+
+/* ---------- prescaler set(and make time tables) ---------- */
+static void OPNSetPres(FM_OPN *OPN , int pres , int TimerPres, int SSGpres)
+{
+	int i;
+
+	/* frequency base */
+#if 1
+	OPN->ST.freqbase = (OPN->ST.rate) ? ((double)OPN->ST.clock / OPN->ST.rate) / pres : 0;
+#else
+	OPN->ST.rate = (double)OPN->ST.clock / pres;
+	OPN->ST.freqbase = 1.0;
+#endif
+
+	/* Timer base time */
+	OPN->ST.TimerPres = TimerPres;
+	/* SSG part  prescaler set */
+	if( SSGpres ) SSGClk( OPN->ST.index, OPN->ST.clock * 2 / SSGpres );
+	/* make time tables */
+	init_timetables( &OPN->ST , OPN_DTTABLE );
+	/* calculate fnumber -> increment counter table */
+	for( i=0 ; i < 2048 ; i++ )
+	{
+		/* freq table for octave 7 */
+		/* opn phase increment counter = 20bit */
+		OPN->FN_TABLE[i] = (UINT32)( (double)i * 64 * OPN->ST.freqbase * (1<<(FREQ_SH-10)) ); /* -10 because chip works with 10.10 fixed point, while we use 16.16 */
+#if 0
+		logerror("FM.C: FN_TABLE[%4i] = %08x (dec=%8i)\n",
+				 i, OPN->FN_TABLE[i]>>6,OPN->FN_TABLE[i]>>6 );
+#endif
+	}
+
+	/* LFO freq. table */
+	{
+		/* 3.98Hz,5.56Hz,6.02Hz,6.37Hz,6.88Hz,9.63Hz,48.1Hz,72.2Hz @ 8MHz */
+#define FM_LF(Hz) ((double)LFO_ENT*(1<<LFO_SH)*(Hz)/(8000000.0/144))
+		static const double freq_table[8] = { FM_LF(3.98),FM_LF(5.56),FM_LF(6.02),FM_LF(6.37),FM_LF(6.88),FM_LF(9.63),FM_LF(48.1),FM_LF(72.2) };
+#undef FM_LF
+		for(i=0;i<8;i++)
+		{
+			OPN->LFO_FREQ[i] = (UINT32)(freq_table[i] * OPN->ST.freqbase);
+		}
+	}
+
+/*	LOG(LOG_INF,("OPN %d set prescaler %d\n",OPN->ST.index,pres));*/
+}
+
+/* ---------- write a OPN mode register 0x20-0x2f ---------- */
+static void OPNWriteMode(FM_OPN *OPN, int r, int v)
+{
+	UINT8 c;
+	FM_CH *CH;
+
+	switch(r){
+	case 0x21:	/* Test */
+		break;
+	case 0x22:	/* LFO FREQ (YM2608/YM2612) */
+		if( OPN->type & TYPE_LFOPAN )
+		{
+			OPN->LFOIncr = (v&0x08) ? OPN->LFO_FREQ[v&7] : 0;
+			cur_chip = NULL;
+		}
+		break;
+	case 0x24:	/* timer A High 8*/
+		OPN->ST.TA = (OPN->ST.TA & 0x03)|(((int)v)<<2);
+		break;
+	case 0x25:	/* timer A Low 2*/
+		OPN->ST.TA = (OPN->ST.TA & 0x3fc)|(v&3);
+		break;
+	case 0x26:	/* timer B */
+		OPN->ST.TB = v;
+		break;
+	case 0x27:	/* mode , timer controll */
+		FMSetMode( &(OPN->ST),OPN->ST.index,v );
+		break;
+	case 0x28:	/* key on / off */
+		c = v&0x03;
+		if( c == 3 ) break;
+		if( (v&0x04) && (OPN->type & TYPE_6CH) ) c+=3;
+		CH = OPN->P_CH;
+		CH = &CH[c];
+		/* csm mode */
+		/* if( c == 2 && (OPN->ST.mode & 0x80) ) break; */
+		if(v&0x10) FM_KEYON(CH,SLOT1); else FM_KEYOFF(CH,SLOT1);
+		if(v&0x20) FM_KEYON(CH,SLOT2); else FM_KEYOFF(CH,SLOT2);
+		if(v&0x40) FM_KEYON(CH,SLOT3); else FM_KEYOFF(CH,SLOT3);
+		if(v&0x80) FM_KEYON(CH,SLOT4); else FM_KEYOFF(CH,SLOT4);
+		break;
+	}
+}
+
+/* ---------- write a OPN register (0x30-0xff) ---------- */
+static void OPNWriteReg(FM_OPN *OPN, int r, int v)
+{
+	UINT8 c;
+	FM_CH *CH;
+	FM_SLOT *SLOT;
+
+	/* 0x30 - 0xff */
+	if( (c = OPN_CHAN(r)) == 3 ) return; /* 0xX3,0xX7,0xXB,0xXF */
+
+	if( (r >= 0x100) /* && (OPN->type & TYPE_6CH) */ ) c+=3;
+		CH = OPN->P_CH;
+		CH = &CH[c];
+
+	SLOT = &(CH->SLOT[OPN_SLOT(r)]);
+
+	switch( r & 0xf0 ) {
+	case 0x30:	/* DET , MUL */
+		set_det_mul(&OPN->ST,CH,SLOT,v);
+		break;
+
+	case 0x40:	/* TL */
+		set_tl(CH,SLOT,v,(c == 2) && (OPN->ST.mode & 0x80) );
+		break;
+
+	case 0x50:	/* KS, AR */
+		set_ar_ksr(CH,SLOT,v,OPN->ST.eg_tab);
+		break;
+
+	case 0x60:	/*     DR */
+		/* bit7 = AMS_ON ENABLE(YM2612) */
+		set_dr(SLOT,v,OPN->ST.eg_tab);
+		if( OPN->type & TYPE_LFOPAN)
+		{
+			SLOT->amon = (v&0x80) ? ~0: 0;
+			SLOT->ams = CH->ams & SLOT->amon;
+		}
+		break;
+
+	case 0x70:	/*     SR */
+		set_sr(SLOT,v,OPN->ST.eg_tab);
+		break;
+
+	case 0x80:	/* SL, RR */
+		set_sl_rr(SLOT,v,OPN->ST.eg_tab);
+		break;
+
+	case 0x90:	/* SSG-EG */
+
+		SLOT->SEG  =  v&0x0f;
+		SLOT->SEGn = (v&0x04)>>1; /* bit 1 in SEGn = attack */
+
+		/* SSG-EG envelope shapes :
+
+		E AtAlH
+		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  /___
+
+
+		E = SSG-EG enable
+
+
+		The shapes are generated using Attack, Decay and Sustain phases.
+
+		Each single character in the diagrams above represents this whole
+		sequence:
+
+		- when KEY-ON = 1, normal Attack phase is generated (*without* any
+		  difference when compared to normal mode),
+
+		- later, when envelope level reaches minimum level (max volume),
+		  the EG switches to Decay phase (which works with bigger steps
+		  when compared to normal mode - see below),
+
+		- later when envelope level passes the SL level,
+		  the EG swithes to Sustain phase (which works with bigger steps
+		  when compared to normal mode - see below),
+
+		- finally when envelope level reaches maximum level (min volume),
+		  the EG switches to Attack phase again (depends on actual waveform).
+
+		Important is that when switch to Attack phase occurs, the phase counter
+		of that operator will be zeroed-out (as in normal KEY-ON) but not always.
+		(I havent found the rule for that - perhaps only when the output level is low)
+
+		The difference (when compared to normal Envelope Generator mode) is
+		that the resolution in Decay and Sustain phases is 4 times lower;
+		this results in only 256 steps instead of normal 1024.
+		In other words:
+		when SSG-EG is disabled, the step inside of the EG is one,
+		when SSG-EG is enabled, the step is four (in Decay and Sustain phases).
+
+		Times between the level changes are the same in both modes.
+
+
+		Important:
+		Decay 1 Level (so called SL) is compared to actual SSG-EG output, so
+		it is the same in both SSG and no-SSG modes, with this exception:
+
+		when the SSG-EG is enabled and is generating raising levels
+		(when the EG output is inverted) the SL will be found at wrong level !!!
+		For example, when SL=02:
+			0 -6 = -6dB in non-inverted EG output
+			96-6 = -90dB in inverted EG output
+		Which means that EG compares its level to SL as usual, and that the
+		output is simply inverted afterall.
+
+
+		The Yamaha's manuals say that AR should be set to 0x1f (max speed).
+		That is not necessary, but then EG will be generating Attack phase.
+
+		*/
+
+
+		break;
+
+	case 0xa0:
+		switch( OPN_SLOT(r) ){
+		case 0:		/* 0xa0-0xa2 : FNUM1 */
+			{
+				UINT32 fn  = (((UINT32)( (OPN->ST.fn_h)&7))<<8) + v;
+				UINT8 blk = OPN->ST.fn_h>>3;
+				/* keyscale code */
+				CH->kcode = (blk<<2)|OPN_FKTABLE[(fn>>7)];
+				/* phase increment counter */
+				CH->fc = OPN->FN_TABLE[fn]>>(7-blk);
+				CH->SLOT[SLOT1].Incr=-1;
+			}
+			break;
+		case 1:		/* 0xa4-0xa6 : FNUM2,BLK */
+			OPN->ST.fn_h = v&0x3f;
+			break;
+		case 2:		/* 0xa8-0xaa : 3CH FNUM1 */
+			if( r < 0x100)
+			{
+				UINT32 fn  = (((UINT32)(OPN->SL3.fn_h&7))<<8) + v;
+				UINT8 blk = OPN->SL3.fn_h>>3;
+				/* keyscale code */
+				OPN->SL3.kcode[c]= (blk<<2)|OPN_FKTABLE[(fn>>7)];
+				/* phase increment counter */
+				OPN->SL3.fc[c] = OPN->FN_TABLE[fn]>>(7-blk);
+				(OPN->P_CH)[2].SLOT[SLOT1].Incr=-1;
+			}
+			break;
+		case 3:		/* 0xac-0xae : 3CH FNUM2,BLK */
+			if( r < 0x100)
+				OPN->SL3.fn_h = v&0x3f;
+			break;
+		}
+		break;
+
+	case 0xb0:
+		switch( OPN_SLOT(r) ){
+		case 0:		/* 0xb0-0xb2 : FB,ALGO */
+			{
+				int feedback = (v>>3)&7;
+				CH->ALGO = v&7;
+				CH->FB   = feedback ? feedback+6 : 0;
+				setup_connection( CH, c );
+			}
+			break;
+		case 1:		/* 0xb4-0xb6 : L , R , AMS , PMS (YM2612/YM2610B/YM2610/YM2608) */
+			if( OPN->type & TYPE_LFOPAN)
+			{
+
+				/* b0-2 PMS */
+				/* 0,3.4,6.7,10,14,20,40,80(cent) */
+				static const double pmd_table[8]={0,3.4,6.7,10,14,20,40,80};
+
+				/* b4-5 AMS */
+				/* 0, 1.4,     5.9,     11.8           (dB) */
+				/* 0, 1.40625, 5.90625, 11.90625 (or 11.8125) */
+				/* 0, 15,    , 63	  , 127      (or 126)   in internal representation */
+
+				/* bit0,    bit1,   bit2,  bit3, bit4, bit5, bit6, bit7, bit8, bit9 */
+				/* 1,       2,      4,     8,    16,   32,   64,   128,  256,  512  (internal representation value)*/
+				/* 0.09375, 0.1875, 0.375, 0.75, 1.5,  3,    6,    12,   24,   48   (dB)*/
+				static const int amd_table[4]={	(int)( ((0.0    *4)/3)/ENV_STEP),
+												(int)( ((1.40625*4)/3)/ENV_STEP),
+												(int)( ((5.90625*4)/3)/ENV_STEP),
+												(int)(((11.90625*4)/3)/ENV_STEP) };
+				/* amd_table simply becomes = { 0, 15, 63, 127 } */
+
+				CH->pms = (INT32)( (1.5/1200.0)*pmd_table[v & 7] * PMS_RATE);
+
+				CH->ams = amd_table[(v>>4) & 0x03];
+				CH->SLOT[SLOT1].ams = CH->ams & CH->SLOT[SLOT1].amon;
+				CH->SLOT[SLOT2].ams = CH->ams & CH->SLOT[SLOT2].amon;
+				CH->SLOT[SLOT3].ams = CH->ams & CH->SLOT[SLOT3].amon;
+				CH->SLOT[SLOT4].ams = CH->ams & CH->SLOT[SLOT4].amon;
+
+				/* PAN :  b7 = L, b6 = R */
+				OPN->PAN[ c*2   ] = (v & 0x80) ? ~0 : 0;
+				OPN->PAN[ c*2+1 ] = (v & 0x40) ? ~0 : 0;
+
+				/* LOG(LOG_INF,("OPN %d,%d : PAN %x %x\n",n,c,OPN->PAN[c*2],OPN->PAN[c*2+1]));*/
+			}
+			break;
+		}
+		break;
+	}
+}
+
+/*
+  prescaler circuit (best guess to verified chip behaviour)
+
+               +--------------+  +-sel2-+
+               |              +--|in20  |
+         +---+ |  +-sel1-+       |      |
+M-CLK -+-|1/2|-+--|in10  | +---+ |   out|--INT_CLOCK
+       | +---+    |   out|-|1/3|-|in21  |
+       +----------|in11  | +---+ +------+
+                  +------+
+
+reg.2d : sel2 = in21 (select sel2)
+reg.2e : sel1 = in11 (select sel1)
+reg.2f : sel1 = in10 , sel2 = in20 (clear selector)
+reset  : sel1 = in11 , sel2 = in21 (clear both)
+
+*/
+static void OPNPrescaler_w(FM_OPN *OPN , int addr, int pre_divider)
+{
+	static const int opn_pres[4] = { 2*12 , 2*12 , 6*12 , 3*12 };
+	static const int ssg_pres[4] = { 1    ,    1 ,    4 ,    2 };
+	int sel;
+
+	switch(addr)
+	{
+	case 0:		/* when reset */
+		OPN->ST.prescaler_sel = 2;
+		break;
+	case 1:		/* when postload */
+		break;
+	case 0x2d:	/* divider sel : select 1/1 for 1/3line    */
+		OPN->ST.prescaler_sel |= 0x02;
+		break;
+	case 0x2e:	/* divider sel , select 1/3line for output */
+		OPN->ST.prescaler_sel |= 0x01;
+		break;
+	case 0x2f:	/* divider sel , clear both selector to 1/2,1/2 */
+		OPN->ST.prescaler_sel = 0;
+		break;
+	}
+	sel = OPN->ST.prescaler_sel & 3;
+	/* update prescaler */
+	OPNSetPres( OPN,	opn_pres[sel]*pre_divider,
+						opn_pres[sel]*pre_divider,
+						ssg_pres[sel]*pre_divider );
+}
+
+/* adpcm type A struct */
+typedef struct adpcm_state {
+	UINT8		flag;			/* port state				*/
+	UINT8		flagMask;		/* arrived flag mask		*/
+	UINT8		now_data;		/* current ROM data			*/
+	UINT32		now_addr;		/* current ROM address		*/
+	UINT32		now_step;
+	UINT32		step;
+	UINT32		start;			/* sample data start address*/
+	UINT32		end;			/* sample data end address	*/
+	UINT8		IL;				/* Instrument Level			*/
+	INT32		adpcm_acc;		/* accumulator				*/
+	INT32		adpcm_step;		/* step						*/
+	INT32		adpcm_out;		/* (speedup) hiro-shi!!		*/
+	INT8		vol_mul;		/* volume in "0.75dB" steps	*/
+	UINT8		vol_shift;		/* volume in "-6dB" steps	*/
+	INT32		*pan;			/* &out_adpcm[OPN_xxxx] 	*/
+}ADPCM_CH;
+
+/* here's the virtual YM2608 */
+typedef struct ym2608_f {
+	UINT8		REGS[512];			/* registers			*/
+	FM_OPN		OPN;				/* OPN state			*/
+	FM_CH		CH[6];				/* channel state		*/
+	int			address1;			/* address register1	*/
+/* ADPCM-A unit */
+	UINT8		*pcmbuf;			/* pcm rom buffer		*/
+	UINT32		pcm_size;			/* size of pcm rom		*/
+	UINT8		adpcmTL;			/* adpcmA total level	*/
+	ADPCM_CH 	adpcm[6];			/* adpcm channels		*/
+	UINT32		adpcmreg[0x30];		/* registers			*/
+	UINT8		adpcm_arrivedEndAddress;
+	YM_DELTAT 	deltaT;				/* Delta-T ADPCM unit	*/
+} YM2608;
+
+/**** YM2608 ADPCM defines ****/
+#define ADPCM_SHIFT    (16)      /* frequency step rate   */
+#define ADPCMA_ADDRESS_SHIFT 8   /* adpcm A address shift */
+
+static UINT8 *pcmbufA;
+static UINT32 pcmsizeA;
+
+
+/* Algorithm and tables verified on real YM2608 */
+
+/* usual ADPCM table (16 * 1.1^N) */
+static int steps[49] =
+{
+	 16,  17,   19,   21,   23,   25,   28,
+	 31,  34,   37,   41,   45,   50,   55,
+	 60,  66,   73,   80,   88,   97,  107,
+	118, 130,  143,  157,  173,  190,  209,
+	230, 253,  279,  307,  337,  371,  408,
+	449, 494,  544,  598,  658,  724,  796,
+	876, 963, 1060, 1166, 1282, 1411, 1552
+};
+
+/* different from the usual ADPCM table */
+static int step_inc[8] = { -1*16, -1*16, -1*16, -1*16, 2*16, 5*16, 7*16, 9*16 };
+
+/* speedup purposes only */
+static int jedi_table[ 49*16 ];
+
+
+static void InitOPNB_ADPCMATable(void){
+
+	int step, nib;
+
+	for (step = 0; step < 49; step++)
+	{
+		/* loop over all nibbles and compute the difference */
+		for (nib = 0; nib < 16; nib++)
+		{
+			int value = (2*(nib & 0x07) + 1) * steps[step] / 8;
+			jedi_table[step*16 + nib] = (nib&0x08) ? -value : value;
+		}
+	}
+}
+
+/**** ADPCM A (Non control type) ****/
+INLINE void OPNB_ADPCM_CALC_CHA( YM2608 *F2608, ADPCM_CH *ch )
+{
+	UINT32 step;
+	UINT8  data;
+
+	ch->now_step += ch->step;
+	if ( ch->now_step >= (1<<ADPCM_SHIFT) )
+	{
+		step = ch->now_step >> ADPCM_SHIFT;
+		ch->now_step &= (1<<ADPCM_SHIFT)-1;
+		do{
+			/* end check */
+			/* 11-06-2001 JB: corrected comparison. Was > instead of == */
+			/* YM2608 checks lower 20 bits only, the 4 MSB bits are sample bank */
+			/* Here we use 1<<21 to compensate for nibble calculations */
+
+			if (   (ch->now_addr & ((1<<21)-1)) == ((ch->end<<1) & ((1<<21)-1))	   )
+			{
+				ch->flag = 0;
+				F2608->adpcm_arrivedEndAddress |= ch->flagMask;
+				return;
+			}
+#if 0
+			if ( ch->now_addr > (pcmsizeA<<1) ) {
+				LOG(LOG_WAR,("YM2608: Attempting to play past adpcm rom size!\n" ));
+				return;
+			}
+#endif
+			if( ch->now_addr&1 ) data = ch->now_data & 0x0f;
+			else
+			{
+				ch->now_data = *(pcmbufA+(ch->now_addr>>1));
+				data = (ch->now_data >> 4)&0x0f;
+			}
+
+			ch->now_addr++;
+
+			ch->adpcm_acc += jedi_table[ch->adpcm_step + data];
+
+			/* extend 12-bit signed int */
+			if (ch->adpcm_acc & 0x800)
+				ch->adpcm_acc |= ~0xfff;
+			else
+				ch->adpcm_acc &= 0xfff;
+
+			ch->adpcm_step += step_inc[data & 7];
+			Limit( ch->adpcm_step, 48*16, 0*16 );
+
+		}while(--step);
+
+		/**** calc pcm * volume data ****/
+		ch->adpcm_out = ((ch->adpcm_acc * ch->vol_mul) >> ch->vol_shift) & ~3;	/* multiply, shift and mask out 2 LSB bits */
+	}
+
+	/* output for work of output channels (out_adpcm[OPNxxxx])*/
+	*(ch->pan) += ch->adpcm_out;
+}
+
+/* ADPCM type A */
+static void FM_ADPCMAWrite(YM2608 *F2608,int r,int v)
+{
+	ADPCM_CH *adpcm = F2608->adpcm;
+	UINT8 c = r&0x07;
+
+	F2608->adpcmreg[r] = v&0xff; /* stock data */
+	switch( r ){
+	case 0x00: /* DM,--,C5,C4,C3,C2,C1,C0 */
+		/* F2608->port1state = v&0xff; */
+		if( !(v&0x80) ){
+			/* KEY ON */
+			for( c = 0; c < 6; c++ ){
+				if( (1<<c)&v ){
+					/**** start adpcm ****/
+					adpcm[c].step      = (UINT32)((float)(1<<ADPCM_SHIFT)*((float)F2608->OPN.ST.freqbase)/3.0);
+					adpcm[c].now_addr  = adpcm[c].start<<1;
+					adpcm[c].now_step  = 0;
+					adpcm[c].adpcm_acc = 0;
+					adpcm[c].adpcm_step= 0;
+					adpcm[c].adpcm_out = 0;
+					adpcm[c].flag      = 1;
+					if(F2608->pcmbuf==NULL){					/* Check ROM Mapped */
+						LOG(LOG_WAR,("YM2608: ADPCM-A rom not mapped\n"));
+						adpcm[c].flag = 0;
+					} else{
+						if(adpcm[c].end >= F2608->pcm_size){	/* Check End in Range */
+							LOG(LOG_WAR,("YM2608: ADPCM-A end out of range: $%08x\n",adpcm[c].end));
+							/*adpcm[c].end = F2608->pcm_size-1;*/ /* JB: DO NOT uncomment this, otherwise you will break the comparison in the ADPCM_CALC_CHA() */
+						}
+						if(adpcm[c].start >= F2608->pcm_size)	/* Check Start in Range */
+						{
+							LOG(LOG_WAR,("YM2608: ADPCM-A start out of range: $%08x\n",adpcm[c].start));
+							adpcm[c].flag = 0;
+						}
+					}
+				}	/*** (1<<c)&v ***/
+			}	/**** for loop ****/
+		} else{
+			/* KEY OFF */
+			for( c = 0; c < 6; c++ ){
+				if( (1<<c)&v )  adpcm[c].flag = 0;
+			}
+		}
+		break;
+	case 0x01:	/* B0-5 = TL */
+		F2608->adpcmTL = (v & 0x3f) ^ 0x3f;
+		for( c = 0; c < 6; c++ )
+		{
+			int volume = F2608->adpcmTL + adpcm[c].IL;
+
+			if ( volume >= 63 )	/* This is correct, 63 = quiet */
+			{
+				adpcm[c].vol_mul   = 0;
+				adpcm[c].vol_shift = 0;
+			}
+			else
+			{
+				adpcm[c].vol_mul   = 15 - (volume & 7);		/* so called 0.75 dB */
+				adpcm[c].vol_shift =  1 + (volume >> 3);	/* Yamaha engineers used the approximation: each -6 dB is close to divide by two (shift right) */
+			}
+
+			/**** calc pcm * volume data ****/
+			adpcm[c].adpcm_out = ((adpcm[c].adpcm_acc * adpcm[c].vol_mul) >> adpcm[c].vol_shift) & ~3;	/* multiply, shift and mask out low 2 bits */
+		}
+		break;
+	default:
+		c = r&0x07;
+		if( c >= 0x06 ) return;
+		switch( r&0x38 ){
+		case 0x08:	/* B7=L,B6=R, B4-0=IL */
+		{
+			int volume;
+
+			adpcm[c].IL = (v & 0x1f) ^ 0x1f;
+
+			volume = F2608->adpcmTL + adpcm[c].IL;
+
+			if ( volume >= 63 )	/* This is correct, 63 = quiet */
+			{
+				adpcm[c].vol_mul   = 0;
+				adpcm[c].vol_shift = 0;
+			}
+			else
+			{
+				adpcm[c].vol_mul   = 15 - (volume & 7);		/* so called 0.75 dB */
+				adpcm[c].vol_shift =  1 + (volume >> 3);	/* Yamaha engineers used the approximation: each -6 dB is close to divide by two (shift right) */
+			}
+
+			adpcm[c].pan    = &out_adpcm[(v>>6)&0x03];
+
+			/**** calc pcm * volume data ****/
+			adpcm[c].adpcm_out = ((adpcm[c].adpcm_acc * adpcm[c].vol_mul) >> adpcm[c].vol_shift) & ~3;	/* multiply, shift and mask out low 2 bits */
+		}
+			break;
+		case 0x10:
+		case 0x18:
+			adpcm[c].start  = ( (F2608->adpcmreg[0x18 + c]*0x0100 | F2608->adpcmreg[0x10 + c]) << ADPCMA_ADDRESS_SHIFT);
+			break;
+		case 0x20:
+		case 0x28:
+			adpcm[c].end    = ( (F2608->adpcmreg[0x28 + c]*0x0100 | F2608->adpcmreg[0x20 + c]) << ADPCMA_ADDRESS_SHIFT);
+			adpcm[c].end   += (1<<ADPCMA_ADDRESS_SHIFT) - 1;
+			break;
+		}
+	}
+}
+
+static void FMsave_state_adpcma(QEMUFile* f,ADPCM_CH *adpcm)
+{
+	int ch;
+
+	for(ch=0;ch<6;ch++,adpcm++)
+	{
+		qemu_put_8s(f, &adpcm->flag);
+		qemu_put_8s(f, &adpcm->now_data);
+		qemu_put_be32s(f, &adpcm->now_addr);
+		qemu_put_be32s(f, &adpcm->now_step);
+		qemu_put_be32s(f, &adpcm->adpcm_acc);
+		qemu_put_be32s(f, &adpcm->adpcm_step);
+		qemu_put_be32s(f, &adpcm->adpcm_out);
+	}
+}
+
+static int FMload_state_adpcma(QEMUFile* f,ADPCM_CH *adpcm)
+{
+	int ch;
+
+	for(ch=0;ch<6;ch++,adpcm++)
+	{
+		qemu_get_8s(f, &adpcm->flag);
+		qemu_get_8s(f, &adpcm->now_data);
+		qemu_get_be32s(f, &adpcm->now_addr);
+		qemu_get_be32s(f, &adpcm->now_step);
+		qemu_get_be32s(f, &adpcm->adpcm_acc);
+		qemu_get_be32s(f, &adpcm->adpcm_step);
+		qemu_get_be32s(f, &adpcm->adpcm_out);
+	}
+
+	return 0;
+}
+
+/*****************************************************************************/
+/*		YM2608 local section                                                 */
+/*****************************************************************************/
+static YM2608 *FM2608=NULL;	/* array of YM2608's */
+static int YM2608NumChips;	/* total chip */
+
+/* YM2608 Rhythm Number */
+#define RY_BD  0
+#define RY_SD  1
+#define RY_TOP 2
+#define RY_HH  3
+#define RY_TOM 4
+#define RY_RIM 5
+
+#if 0
+/* Get next pcm data */
+INLINE int YM2608ReadADPCM(int n)
+{
+	YM2608 *F2608 = &(FM2608[n]);
+	if( F2608->ADMode & 0x20 )
+	{	/* buffer memory */
+		/* F2203->OPN.ST.status |= 0x04; */
+		return 0;
+	}
+	else
+	{	/* from PCM data register */
+		FM_STATUS_SET(F2608->OPN.ST,0x08); /* BRDY = 1 */
+		return F2608->ADData;
+	}
+}
+
+/* Put decoded data */
+INLINE void YM2608WriteADPCM(int n,int v)
+{
+	YM2608 *F2608 = &(FM2608[n]);
+	if( F2608->ADMode & 0x20 )
+	{	/* for buffer */
+		return;
+	}
+	else
+	{	/* for PCM data port */
+		F2608->ADData = v;
+		FM_STATUS_SET(F2608->OPN.ST,0x08) /* BRDY = 1 */
+	}
+}
+#endif
+
+/* ---------- IRQ flag Controll Write 0x110 ---------- */
+INLINE void YM2608IRQFlagWrite(FM_ST *ST,int n,int v)
+{
+	if( v & 0x80 )
+	{	/* Reset IRQ flag */
+		FM_STATUS_RESET(ST,0xff);
+	}
+	else
+	{	/* Set IRQ mask */
+		/* !!!!!!!!!! pending !!!!!!!!!! */
+	}
+}
+
+/* ---------- compatible mode & IRQ flag Controll Write 0x29 ---------- */
+static void YM2608IRQMaskWrite(FM_OPN *OPN,int v)
+{
+	/* SCH,xx,xxx,EN_ZERO,EN_BRDY,EN_EOS,EN_TB,EN_TA */
+	/* extend 3ch. enable/disable */
+	if(v&0x80) OPN->type |= TYPE_6CH;
+	else       OPN->type &= ~TYPE_6CH;
+	/* IRQ MASK */
+	FM_IRQMASK_SET(&OPN->ST,v&0x1f);
+}
+
+#ifdef YM2608_RHYTHM_PCM
+/**** RYTHM (PCM) ****/
+INLINE void YM2608_RYTHM( YM2608 *F2608, ADPCM_CH *ch )
+
+{
+	UINT32 step;
+
+	ch->now_step += ch->step;
+	if ( ch->now_step >= (1<<ADPCM_SHIFT) )
+	{
+		step = ch->now_step >> ADPCM_SHIFT;
+		ch->now_step &= (1<<ADPCM_SHIFT)-1;
+		/* end check */
+		if ( (ch->now_addr+step) > (ch->end<<1) ) {	/*most likely this comparison is wrong */
+			ch->flag = 0;
+			F2608->adpcm_arrivedEndAddress |= ch->flagMask;
+			return;
+		}
+		do{
+			/* get a next pcm data */
+			ch->adpcm_acc = ((short *)pcmbufA)[ch->now_addr];
+			ch->now_addr++;
+		}while(--step);
+		/**** calc pcm * volume data ****/
+		ch->adpcm_out = (ch->adpcm_acc * ch->vol_mul ) >> ch->vol_shift;
+	}
+	/* output for work of output channels (out_adpcm[OPNxxxx])*/
+	*(ch->pan) += ch->adpcm_out;
+}
+#endif /* YM2608_RHYTHM_PCM */
+
+/* ---------- update one of chip ----------- */
+void YM2608UpdateOne(int num, INT16 **buffer, int length)
+{
+	YM2608 *F2608 = &(FM2608[num]);
+	FM_OPN *OPN   = &(FM2608[num].OPN);
+	YM_DELTAT *DELTAT = &(F2608[num].deltaT);
+	int i,j;
+	FMSAMPLE  *bufL,*bufR;
+
+	/* setup DELTA-T unit */
+	YM_DELTAT_DECODE_PRESET(DELTAT);
+
+	/* set bufer */
+	bufL = buffer[0];
+	bufR = buffer[1];
+
+	if( (void *)F2608 != cur_chip ){
+		cur_chip = (void *)F2608;
+
+		State = &OPN->ST;
+		cch[0]   = &F2608->CH[0];
+		cch[1]   = &F2608->CH[1];
+		cch[2]   = &F2608->CH[2];
+		cch[3]   = &F2608->CH[3];
+		cch[4]   = &F2608->CH[4];
+		cch[5]   = &F2608->CH[5];
+		/* setup adpcm rom address */
+		pcmbufA  = F2608->pcmbuf;
+		pcmsizeA = F2608->pcm_size;
+
+		LFOCnt  = OPN->LFOCnt;
+		LFOIncr = OPN->LFOIncr;
+		if( !LFOIncr ) lfo_amd = lfo_pmd = 0;
+	}
+	/* update frequency counter */
+	OPN_CALC_FCOUNT( cch[0] );
+	OPN_CALC_FCOUNT( cch[1] );
+	if( (State->mode & 0xc0) ){
+		/* 3SLOT MODE */
+		if( cch[2]->SLOT[SLOT1].Incr==-1){
+			/* 3 slot mode */
+			CALC_FCSLOT(&cch[2]->SLOT[SLOT1] , OPN->SL3.fc[1] , OPN->SL3.kcode[1] );
+			CALC_FCSLOT(&cch[2]->SLOT[SLOT2] , OPN->SL3.fc[2] , OPN->SL3.kcode[2] );
+			CALC_FCSLOT(&cch[2]->SLOT[SLOT3] , OPN->SL3.fc[0] , OPN->SL3.kcode[0] );
+			CALC_FCSLOT(&cch[2]->SLOT[SLOT4] , cch[2]->fc , cch[2]->kcode );
+		}
+	}else OPN_CALC_FCOUNT( cch[2] );
+	OPN_CALC_FCOUNT( cch[3] );
+	OPN_CALC_FCOUNT( cch[4] );
+	OPN_CALC_FCOUNT( cch[5] );
+	/* buffering */
+	for(i=0; i < length ; i++)
+	{
+		/* LFO */
+		if( LFOIncr )
+		{
+			lfo_amd = OPN_LFO_wave[(LFOCnt+=LFOIncr)>>LFO_SH];
+			lfo_pmd = lfo_amd-(LFO_RATE/2);
+		}
+
+		/* clear output acc. */
+		out_adpcm[OUTD_LEFT] = out_adpcm[OUTD_RIGHT]= out_adpcm[OUTD_CENTER] = 0;
+		out_delta[OUTD_LEFT] = out_delta[OUTD_RIGHT]= out_delta[OUTD_CENTER] = 0;
+		/* clear outputs */
+		out_fm[0] = 0;
+		out_fm[1] = 0;
+		out_fm[2] = 0;
+		out_fm[3] = 0;
+		out_fm[4] = 0;
+		out_fm[5] = 0;
+
+		/* calculate FM */
+		FM_CALC_CH( cch[0] );
+		FM_CALC_CH( cch[1] );
+		FM_CALC_CH( cch[2] );
+		FM_CALC_CH( cch[3] );
+		FM_CALC_CH( cch[4] );
+		FM_CALC_CH( cch[5] );
+
+		/**** deltaT ADPCM ****/
+		if( DELTAT->portstate )
+			YM_DELTAT_ADPCM_CALC(DELTAT);
+
+		for( j = 0; j < 6; j++ )
+		{
+			/**** ADPCM ****/
+			if( F2608->adpcm[j].flag )
+#ifdef YM2608_RHYTHM_PCM
+				YM2608_RYTHM(F2608, &F2608->adpcm[j]);
+#else
+				OPNB_ADPCM_CALC_CHA( F2608, &F2608->adpcm[j]);
+#endif
+		}
+
+		/* buffering */
+		{
+			int lt,rt;
+
+			lt =  out_adpcm[OUTD_LEFT]  + out_adpcm[OUTD_CENTER];
+			rt =  out_adpcm[OUTD_RIGHT] + out_adpcm[OUTD_CENTER];
+			lt += (out_delta[OUTD_LEFT]  + out_delta[OUTD_CENTER])>>8;
+			rt += (out_delta[OUTD_RIGHT] + out_delta[OUTD_CENTER])>>8;
+
+			lt += ((out_fm[0]>>0) & OPN->PAN[0]);	/* we need to find real level on real chip */
+			rt += ((out_fm[0]>>0) & OPN->PAN[1]);
+			lt += ((out_fm[1]>>0) & OPN->PAN[2]);
+			rt += ((out_fm[1]>>0) & OPN->PAN[3]);
+			lt += ((out_fm[2]>>0) & OPN->PAN[4]);
+			rt += ((out_fm[2]>>0) & OPN->PAN[5]);
+			lt += ((out_fm[3]>>0) & OPN->PAN[6]);
+			rt += ((out_fm[3]>>0) & OPN->PAN[7]);
+			lt += ((out_fm[4]>>0) & OPN->PAN[8]);
+			rt += ((out_fm[4]>>0) & OPN->PAN[9]);
+			lt += ((out_fm[5]>>0) & OPN->PAN[10]);
+			rt += ((out_fm[5]>>0) & OPN->PAN[11]);
+
+			lt >>= FINAL_SH;
+			rt >>= FINAL_SH;
+
+			Limit( lt, MAXOUT, MINOUT );
+			Limit( rt, MAXOUT, MINOUT );
+			/* buffering */
+			bufL[i] = lt;
+			bufR[i] = rt;
+		}
+
+		/* timer A controll */
+		INTERNAL_TIMER_A( State , cch[2] )
+	}
+	INTERNAL_TIMER_B(State,length)
+	/* check IRQ for DELTA-T arrived flag */
+ 	FM_STATUS_SET(State, 0);
+
+	OPN->LFOCnt = LFOCnt;
+
+}
+void YM2608_postload(int num)
+{
+	int r;
+
+//	for(num=0;num<YM2608NumChips;num++)
+//	{
+		YM2608 *F2608 = &(FM2608[num]);
+		/* prescaler */
+		OPNPrescaler_w(&F2608->OPN,1,2);
+		F2608->deltaT.freqbase = F2608->OPN.ST.freqbase;
+		/* IRQ mask / mode */
+		YM2608IRQMaskWrite(&F2608->OPN,F2608->REGS[0x29]);
+		/* SSG registers */
+		for(r=0;r<16;r++)
+		{
+			SSGWrite(num,0,r);
+			SSGWrite(num,1,F2608->REGS[r]);
+		}
+
+		/* OPN registers */
+		/* DT / MULTI , TL , KS / AR , AMON / DR , SR , SL / RR , SSG-EG */
+		for(r=0x30;r<0x9e;r++)
+			if((r&3) != 3)
+			{
+				OPNWriteReg(&F2608->OPN,r,F2608->REGS[r]);
+				OPNWriteReg(&F2608->OPN,r|0x100,F2608->REGS[r|0x100]);
+			}
+		/* FB / CONNECT , L / R / AMS / PMS */
+		for(r=0xb0;r<0xb6;r++)
+			if((r&3) != 3)
+			{
+				OPNWriteReg(&F2608->OPN,r,F2608->REGS[r]);
+				OPNWriteReg(&F2608->OPN,r|0x100,F2608->REGS[r|0x100]);
+			}
+		/* FM channels */
+		/*FM_channel_postload(F2608->CH,6);*/
+		/* rhythm(ADPCMA) */
+		FM_ADPCMAWrite(F2608,1,F2608->REGS[0x111]);
+		for( r=0x08 ; r<0x0c ; r++)
+			FM_ADPCMAWrite(F2608,r,F2608->REGS[r+0x110]);
+		/* Delta-T ADPCM unit */
+		YM_DELTAT_postload(&F2608->deltaT , &F2608->REGS[0x100] );
+//	}
+	cur_chip = NULL;
+}
+
+void YM2608_save_state(QEMUFile* f, int num)
+{
+	YM2608 *F2608 = &(FM2608[num]);
+
+	qemu_put_buffer(f, F2608->REGS, 512);
+	FMsave_state_st(f, &FM2608[num].OPN.ST);
+	FMsave_state_channel(f, FM2608[num].CH,6);
+	/* 3slots */
+	qemu_put_be32s(f, &F2608->OPN.SL3.fc[0]);
+	qemu_put_be32s(f, &F2608->OPN.SL3.fc[1]);
+	qemu_put_be32s(f, &F2608->OPN.SL3.fc[2]);
+	qemu_put_8s(f, &F2608->OPN.SL3.fn_h);
+	qemu_put_buffer(f, F2608->OPN.SL3.kcode, 3);
+	/* address register1 */
+	qemu_put_be32s(f, &F2608->address1);
+	/* rythm(ADPCMA) */
+	FMsave_state_adpcma(f, F2608->adpcm);
+	/* Delta-T ADPCM unit */
+	YM_DELTAT_savestate(f, &FM2608[num].deltaT);
+}
+
+int YM2608_load_state(QEMUFile* f, int num)
+{
+	YM2608 *F2608 = &(FM2608[num]);
+
+	qemu_get_buffer(f, F2608->REGS, 512);
+	FMload_state_st(f, &FM2608[num].OPN.ST);
+	FMload_state_channel(f, FM2608[num].CH,6);
+	/* 3slots */
+	qemu_get_be32s(f, &F2608->OPN.SL3.fc[0]);
+	qemu_get_be32s(f, &F2608->OPN.SL3.fc[1]);
+	qemu_get_be32s(f, &F2608->OPN.SL3.fc[2]);
+	qemu_get_8s(f, &F2608->OPN.SL3.fn_h);
+	qemu_get_buffer(f, F2608->OPN.SL3.kcode, 3);
+	/* address register1 */
+	qemu_get_be32s(f, &F2608->address1);
+	/* rythm(ADPCMA) */
+	FMload_state_adpcma(f, F2608->adpcm);
+	/* Delta-T ADPCM unit */
+	YM_DELTAT_loadstate(f, &FM2608[num].deltaT);
+
+	return 0;
+}
+
+/* -------------------------- YM2608(OPNA) ---------------------------------- */
+int YM2608Init(int num, int clock, int rate,
+               void **pcmrom,int *pcmsize,short *rhythmrom,int *rhythmpos,
+               FM_TIMERHANDLER TimerHandler,FM_IRQHANDLER IRQHandler)
+{
+	int i,j;
+
+	if (FM2608) return (-1);	/* duplicate init. */
+	cur_chip = NULL;	/* hiro-shi!! */
+
+	YM2608NumChips = num;
+
+	/* allocate extend state space */
+	if( (FM2608 = (YM2608 *)malloc(sizeof(YM2608) * YM2608NumChips))==NULL)
+		return (-1);
+	/* clear */
+	memset(FM2608,0,sizeof(YM2608) * YM2608NumChips);
+	/* allocate total level table (128kb space) */
+	if( !OPNInitTable() )
+	{
+		free( FM2608 );
+		return (-1);
+	}
+
+	for ( i = 0 ; i < YM2608NumChips; i++ ) {
+		FM2608[i].OPN.ST.index = i;
+		FM2608[i].OPN.type = TYPE_YM2608;
+		FM2608[i].OPN.P_CH = FM2608[i].CH;
+		FM2608[i].OPN.ST.clock = clock;
+		FM2608[i].OPN.ST.rate = rate;
+		/* FM2608[i].OPN.ST.irq = 0; */
+		/* FM2608[i].OPN.ST.status = 0; */
+		/* Extend handler */
+		FM2608[i].OPN.ST.Timer_Handler = TimerHandler;
+		FM2608[i].OPN.ST.IRQ_Handler   = IRQHandler;
+		/* DELTA-T */
+		FM2608[i].deltaT.memory = (UINT8 *)(pcmrom[i]);
+		FM2608[i].deltaT.memory_size = pcmsize[i];
+		FM2608[i].deltaT.arrivedFlagPtr = &FM2608[i].OPN.ST.status;
+		FM2608[i].deltaT.flagMask = 0x04; /* status flag.bit3 */
+		/* ADPCM(Rythm) */
+		FM2608[i].pcmbuf   = (UINT8 *)rhythmrom;
+#ifdef YM2608_RHYTHM_PCM
+		/* rhythm sound setup (PCM) */
+		for(j=0;j<6;j++)
+		{
+			/* rhythm sound */
+			FM2608[i].adpcm[j].start = rhythmpos[j];
+			FM2608[i].adpcm[j].end   = rhythmpos[j+1]-1;
+		}
+		FM2608[i].pcm_size = rhythmpos[6];
+#else
+		/* rhythm sound setup (ADPCM) */
+		FM2608[i].pcm_size = rhythmsize;
+#endif
+		YM2608ResetChip(i);
+	}
+	InitOPNB_ADPCMATable();
+	return 0;
+}
+
+/* ---------- shut down emulator ----------- */
+void YM2608Shutdown(void)
+{
+	if (!FM2608) return;
+
+	FMCloseTable();
+	free(FM2608);
+	FM2608 = NULL;
+}
+
+/* ---------- reset one of chips ---------- */
+void YM2608ResetChip(int num)
+{
+	int i;
+	YM2608 *F2608 = &(FM2608[num]);
+	FM_OPN *OPN   = &(FM2608[num].OPN);
+	YM_DELTAT *DELTAT = &(F2608[num].deltaT);
+
+	/* Reset Prescaler */
+	OPNPrescaler_w(OPN , 0 , 2);
+	F2608->deltaT.freqbase = OPN->ST.freqbase;
+	/* reset SSG section */
+	SSGReset(OPN->ST.index);
+	/* status clear */
+	FM_IRQMASK_SET(&OPN->ST,0x1f);
+	FM_BUSY_CLEAR(&OPN->ST);
+	OPNWriteMode(OPN,0x27,0x30); /* mode 0 , timer reset */
+
+	/* extend 3ch. disable */
+	/*OPN->type &= (~TYPE_6CH);*/
+
+	reset_channel( &OPN->ST , F2608->CH , 6 );
+	/* reset OPerator paramater */
+	for(i = 0xb6 ; i >= 0xb4 ; i-- )
+	{
+		OPNWriteReg(OPN,i      ,0xc0);
+		OPNWriteReg(OPN,i|0x100,0xc0);
+	}
+	for(i = 0xb2 ; i >= 0x30 ; i-- )
+	{
+		OPNWriteReg(OPN,i      ,0);
+		OPNWriteReg(OPN,i|0x100,0);
+	}
+	for(i = 0x26 ; i >= 0x20 ; i-- ) OPNWriteReg(OPN,i,0);
+	/* reset ADPCM unit */
+	/**** ADPCM work initial ****/
+	for( i = 0; i < 6; i++ ){		//this was i < 6+1 which must be a bug ???
+		F2608->adpcm[i].now_addr  = 0;
+		F2608->adpcm[i].now_step  = 0;
+		F2608->adpcm[i].step      = 0;
+		F2608->adpcm[i].start     = 0;
+		F2608->adpcm[i].end       = 0;
+		/* F2608->adpcm[i].delta     = 21866; */
+		F2608->adpcm[i].vol_mul   = 0;
+		F2608->adpcm[i].pan       = &out_adpcm[OUTD_CENTER]; /* default center */
+		F2608->adpcm[i].flagMask  = 0; //(i == 6) ? 0x20 : 0;
+		F2608->adpcm[i].flag      = 0;
+		F2608->adpcm[i].adpcm_acc = 0;
+		F2608->adpcm[i].adpcm_step= 0;
+		F2608->adpcm[i].adpcm_out = 0;
+	}
+	F2608->adpcmTL = 0x3f;
+	/* F2608->port1state = -1; */
+	F2608->adpcm_arrivedEndAddress = 0; /* don't used */
+
+	/* DELTA-T unit */
+	DELTAT->freqbase = OPN->ST.freqbase;
+	DELTAT->output_pointer = out_delta;
+	DELTAT->portshift = 5;		/* allways 5bits shift */ /* ASG */
+	DELTAT->output_range = 1<<23;
+	YM_DELTAT_ADPCM_Reset(DELTAT,OUTD_CENTER);
+}
+
+/* YM2608 write */
+/* n = number  */
+/* a = address */
+/* v = value   */
+int YM2608Write(int n, int a,UINT8 v)
+{
+	YM2608 *F2608 = &(FM2608[n]);
+	FM_OPN *OPN   = &(FM2608[n].OPN);
+	int addr;
+
+	switch(a&3){
+	case 0:	/* address port 0 */
+		OPN->ST.address = (v &= 0xff);
+		/* Write register to SSG emulator */
+		if( v < 16 ) SSGWrite(n,0,v);
+		/* prescaler selecter : 2d,2e,2f  */
+		if( v >= 0x2d && v <= 0x2f )
+		{
+			OPNPrescaler_w(OPN , v , 2);
+			F2608->deltaT.freqbase = OPN->ST.freqbase;
+		}
+		break;
+	case 1:	/* data port 0    */
+		addr = OPN->ST.address;
+		F2608->REGS[addr] = v;
+		switch(addr & 0xf0)
+		{
+		case 0x00:	/* SSG section */
+			/* Write data to SSG emulator */
+			SSGWrite(n,a,v);
+			break;
+		case 0x10:	/* 0x10-0x1f : Rhythm section */
+			YM2608UpdateReq(n);
+			FM_ADPCMAWrite(F2608,addr-0x10,v);
+			break;
+		case 0x20:	/* Mode Register */
+			switch(addr)
+			{
+			case 0x29: /* SCH,xirq mask */
+				YM2608IRQMaskWrite(OPN,v);
+				break;
+			default:
+				YM2608UpdateReq(n);
+				OPNWriteMode(OPN,addr,v);
+			}
+			break;
+		default:	/* OPN section */
+			YM2608UpdateReq(n);
+			OPNWriteReg(OPN,addr,v);
+		}
+		break;
+	case 2:	/* address port 1 */
+		F2608->address1 = v & 0xff;
+		break;
+	case 3:	/* data port 1    */
+		addr = F2608->address1;
+		F2608->REGS[addr+0x100] = v;
+		YM2608UpdateReq(n);
+		switch( addr & 0xf0 )
+		{
+		case 0x00:	/* DELTAT PORT */
+			switch( addr )
+			{
+			case 0x0c:	/* Limit address L */
+				/*F2608->ADLimit = (F2608->ADLimit & 0xff00) | v; */
+				/*break;*/
+			case 0x0d:	/* Limit address H */
+				/*F2608->ADLimit = (F2608->ADLimit & 0x00ff) | (v<<8);*/
+				/*break;*/
+			case 0x0e:	/* DAC data */
+				/*break;*/
+			case 0x0f:	/* PCM data port */
+				/*F2608->ADData = v;*/
+				/*FM_STATUS_RESET(F2608->OPN.ST,0x08);*/
+				break;
+			default:
+				/* 0x00-0x0b */
+				YM_DELTAT_ADPCM_Write(&F2608->deltaT,addr,v);
+			}
+			break;
+		case 0x10:	/* IRQ Flag controll */
+			if( addr == 0x10 )
+				YM2608IRQFlagWrite(&(OPN->ST),n,v);
+			break;
+		default:
+			OPNWriteReg(OPN,addr+0x100,v);
+		}
+	}
+	return OPN->ST.irq;
+}
+UINT8 YM2608Read(int n,int a)
+{
+	YM2608 *F2608 = &(FM2608[n]);
+	int addr = F2608->OPN.ST.address;
+	int ret = 0;
+
+	switch( a&3 ){
+	case 0:	/* status 0 : YM2203 compatible */
+		/* BUSY:x:x:x:x:x:FLAGB:FLAGA */
+		if(addr==0xff) ret = 0x00; /* ID code */
+		else ret = FM_STATUS_FLAG(&F2608->OPN.ST)&0x83;
+		break;
+	case 1:	/* status 0 */
+		if( addr < 16 ) ret = SSGRead(n);
+		break;
+	case 2:	/* status 1 : + ADPCM status */
+		/* BUSY:x:PCMBUSY:ZERO:BRDY:EOS:FLAGB:FLAGA */
+		if(addr==0xff) ret = 0x00; /* ID code */
+		else ret = FM_STATUS_FLAG(&F2608->OPN.ST) | (F2608->adpcm[6].flag ? 0x20 : 0);
+		break;
+	case 3:
+		ret = 0;
+		break;
+	}
+	return ret;
+}
+
+int YM2608TimerOver(int n,int c)
+{
+	YM2608 *F2608 = &(FM2608[n]);
+
+	if( c )
+	{	/* Timer B */
+		TimerBOver( &(F2608->OPN.ST) );
+	}
+	else
+	{	/* Timer A */
+		YM2608UpdateReq(n);
+		/* timer update */
+		TimerAOver( &(F2608->OPN.ST) );
+		/* CSM mode key,TL controll */
+		if( F2608->OPN.ST.mode & 0x80 )
+		{	/* CSM mode total level latch and auto key on */
+			CSMKeyControll( &(F2608->CH[2]) );
+		}
+	}
+	return FM2608->OPN.ST.irq;
+}
+
diff --git a/qemu/hw/fm.h b/qemu/hw/fm.h
new file mode 100644
index 0000000..edbe2be
--- /dev/null
+++ b/qemu/hw/fm.h
@@ -0,0 +1,96 @@ 
+/*
+  File: fm.h -- header file for software emulation for FM sound generator
+
+*/
+#ifndef _H_FM_FM_
+#define _H_FM_FM_
+
+#include "hw.h"
+#include "fm_def.h"
+
+/* --- system optimize --- */
+/* select stereo output buffer : 1=mixing / 0=separate */
+#define FM_STEREO_MIX 0
+/* select bit size of output : 8 or 16 */
+#define FM_SAMPLE_BITS 16
+/* select timer system internal or external */
+#define FM_INTERNAL_TIMER 0
+
+/* --- speedup optimize --- */
+/* busy flag emulation , The definition of FM_GET_TIME_NOW() is necessary. */
+#define FM_BUSY_FLAG_SUPPORT 0
+
+/* --- external SSG(YM2149/AY-3-8910)emulator interface port */
+/* used by YM2203,YM2608,and YM2610 */
+
+/* SSGClk   : Set SSG Clock      */
+/* int n    = chip number        */
+/* int clk  = MasterClock(Hz)    */
+/* int rate = sample rate(Hz) */
+#define SSGClk(chip,clock) AY8910_set_clock((chip)+ay8910_index_ym,clock)
+
+/* SSGWrite : Write SSG port     */
+/* int n    = chip number        */
+/* int a    = address            */
+/* int v    = data               */
+#define SSGWrite(n,a,v) AY8910Write((n)+ay8910_index_ym,a,v)
+
+/* SSGRead  : Read SSG port */
+/* int n    = chip number   */
+/* return   = Read data     */
+#define SSGRead(n) AY8910Read((n)+ay8910_index_ym)
+
+/* SSGReset : Reset SSG chip */
+/* int n    = chip number   */
+#define SSGReset(chip) AY8910_reset((chip)+ay8910_index_ym)
+
+/* --- external callback funstions for realtime update --- */
+
+/* in 2608intf.c */
+#define YM2608UpdateReq(chip) YM2608UpdateRequest(chip);
+
+#if FM_STEREO_MIX
+  #define YM2608_NUMBUF 1
+#else
+  #define YM2608_NUMBUF 2    /* FM L+R+ADPCM+RYTHM */
+#endif
+
+#if (FM_SAMPLE_BITS==16)
+typedef INT16 FMSAMPLE;
+typedef unsigned long FMSAMPLE_MIX;
+#endif
+#if (FM_SAMPLE_BITS==8)
+typedef unsigned char  FMSAMPLE;
+typedef unsigned short FMSAMPLE_MIX;
+#endif
+
+//typedef void (*FM_TIMERHANDLER)(int n,int c,int cnt,double stepTime);
+typedef void (*FM_TIMERHANDLER)(int n,int c,int cnt,int clock);
+typedef void (*FM_IRQHANDLER)(int n,int irq);
+/* FM_TIMERHANDLER : Stop or Start timer         */
+/* int n          = chip number                  */
+/* int c          = Channel 0=TimerA,1=TimerB    */
+/* int count      = timer count (0=stop)         */
+/* doube stepTime = step time of one count (sec.)*/
+
+/* FM_IRQHHANDLER : IRQ level changing sense     */
+/* int n       = chip number                     */
+/* int irq     = IRQ level 0=OFF,1=ON            */
+
+/* -------------------- YM2608(OPNA) Interface -------------------- */
+int YM2608Init(int num, int baseclock, int rate,
+               void **pcmroma,int *pcmsizea,short *rhythmrom,int *rhythmpos,
+               FM_TIMERHANDLER TimerHandler,FM_IRQHANDLER IRQHandler);
+void YM2608Shutdown(void);
+void YM2608ResetChip(int num);
+void YM2608UpdateOne(int num, INT16 **buffer, int length);
+
+void YM2608_postload(int num);
+void YM2608_save_state(QEMUFile* f, int num);
+int YM2608_load_state(QEMUFile* f, int num);
+
+int YM2608Write(int n, int a,unsigned char v);
+unsigned char YM2608Read(int n,int a);
+int YM2608TimerOver(int n, int c );
+
+#endif /* _H_FM_FM_ */