// license:GPL-2.0+
// copyright-holders:Jarek Burczynski
/*
**
** File: ymf262.c - software implementation of YMF262
**                  FM sound generator type OPL3
**
** Copyright Jarek Burczynski
**
** Version 0.2
**

Revision History:

03-03-2003: initial release
 - thanks to Olivier Galibert and Chris Hardy for YMF262 and YAC512 chips
 - thanks to Stiletto for the datasheets

   Features as listed in 4MF262A6 data sheet:
    1. Registers are compatible with YM3812 (OPL2) FM sound source.
    2. Up to six sounds can be used as four-operator melody sounds for variety.
    3. 18 simultaneous melody sounds, or 15 melody sounds with 5 rhythm sounds (with two operators).
    4. 6 four-operator melody sounds and 6 two-operator melody sounds, or 6 four-operator melody
       sounds, 3 two-operator melody sounds and 5 rhythm sounds (with four operators).
    5. 8 selectable waveforms.
    6. 4-channel sound output.
    7. YMF262 compabile DAC (YAC512) is available.
    8. LFO for vibrato and tremolo effedts.
    9. 2 programable timers.
   10. Shorter register access time compared with YM3812.
   11. 5V single supply silicon gate CMOS process.
   12. 24 Pin SOP Package (YMF262-M), 48 Pin SQFP Package (YMF262-S).


differences between OPL2 and OPL3 not documented in Yamaha datahasheets:
- sinus table is a little different: the negative part is off by one...

- in order to enable selection of four different waveforms on OPL2
  one must set bit 5 in register 0x01(test).
  on OPL3 this bit is ignored and 4-waveform select works *always*.
  (Don't confuse this with OPL3's 8-waveform select.)

- Envelope Generator: all 15 x rates take zero time on OPL3
  (on OPL2 15 0 and 15 1 rates take some time while 15 2 and 15 3 rates
  take zero time)

- channel calculations: output of operator 1 is in perfect sync with
  output of operator 2 on OPL3; on OPL and OPL2 output of operator 1
  is always delayed by one sample compared to output of operator 2


differences between OPL2 and OPL3 shown in datasheets:
- YMF262 does not support CSM mode


*/

//#include "stdafx.h"
#include <string.h>
#include "ymf262.h"

#define PITCH_COEF	1154
//#define PITCH_COEF	 1024

#define FREQ_SH         16  /* 16.16 fixed point (frequency calculations) */
#define EG_SH           16  /* 16.16 fixed point (EG timing)              */
#define TIMER_SH        16  /* 16.16 fixed point (timers calculations)    */

#define FREQ_MASK       ((1<<FREQ_SH)-1)

//char cpad=0;
OPL3 chip = {0xcc, 0xcd};

/* mapping of register number (offset) to slot number used by the emulator */
static const int8_t slot_array[32] = { 0, 2, 4, 1, 3, 5,-1,-1, 6, 8,10, 7, 9,11,-1,-1, 12,14,16,13,15,17,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1 }; 
static const uint8_t ksl_tab[8 * 16] = { 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,8,12,16,20,24,28,32,0,0,0,0,0,12,20,28,32,40,44,48,52,56,60,64,0,0,0,20,32,44,52,60,64,72,76,80,84,88,92,96,0,0,32,52,64,76,84,92,96,104,108,112,116,120,124,128,0,32,64,84,96,108,116,124,128,136,140,144,148,152,156,160,0,64,96,116,128,140,148,156,160,168,172,176,180,184,188,192,0,96,128,148,160,172,180,188,192,200,204,208,212,216,220,224 };
static const uint8_t ksl_shift[4] = { 31, 1, 2, 0 };
static const uint8_t sl_tab[16] = { 0, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 248 };

static const uint8_t eg_rate_select[16 + 64 + 16] = { 112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,0,8,16,24,0,8,16,24,0,8,16,24,0,8,16,24,0,8,16,24,0,8,16,24,0,8,16,24,0,8,16,24,0,8,16,24,0,8,16,24,0,8,16,24,0,8,16,24,0,8,16,24,32,40,48,56,64,72,80,88,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96 };
static const uint8_t eg_rate_shift[16 + 64 + 16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,12,11,11,11,11,10,10,10,10,9,9,9,9,8,8,8,8,7,7,7,7,6,6,6,6,5,5,5,5,4,4,4,4,3,3,3,3,2,2,2,2,1,1,1,1,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 };
static const uint8_t mul_tab[16]= {	1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 20, 24, 24, 30, 30 }; /* multiple table */


static void FM_KEYON(OPL3_SLOT *SLOT, uint8_t key_set)
{
	if( !SLOT->key )
	{
		SLOT->Cnt = 0; /* restart Phase Generator */
		SLOT->state = EG_ATT; /* phase -> Attack */
	}
	SLOT->key |= key_set;
}

static void FM_KEYOFF(OPL3_SLOT *SLOT, uint8_t key_clr)
{
	if( SLOT->key )
	{
		SLOT->key &= key_clr;
		if( !SLOT->key ) 
			if (SLOT->state>EG_REL) SLOT->state = EG_REL; /* phase -> Release */
	}
}

/* update phase increment counter of operator (also update the EG rates if necessary) */
static void CALC_FCSLOT(OPL3_CH *CH, OPL3_SLOT *SLOT)
{
	uint8_t ksr;

	/* (frequency) phase increment counter */
	uint8_t shift = 7 - (CH->block_fnum >> 10);
	SLOT->Incr = ((CH->block_fnum & 0x03ff) * (uint32_t)SLOT->mul << 2) >> shift;
	ksr = CH->kcode >> SLOT->KSR;

	if( SLOT->ksr != ksr )
	{
		SLOT->ksr = ksr;
		ksr += SLOT->ar;
		/* calculate envelope generator rates */
		if (ksr < 16+60)
		{
			SLOT->eg_sh_ar  = eg_rate_shift [ksr];
			SLOT->eg_sel_ar = eg_rate_select[ksr];
		}
		else
		{
			SLOT->eg_sh_ar  = 0;
			SLOT->eg_sel_ar = 13*RATE_STEPS;
		}
		ksr = SLOT->dr + SLOT->ksr;
		SLOT->eg_sh_dr  = eg_rate_shift [ksr];
		SLOT->eg_sel_dr = eg_rate_select[ksr];
		ksr = SLOT->rr + SLOT->ksr;
		SLOT->eg_sh_rr  = eg_rate_shift [ksr];
		SLOT->eg_sel_rr = eg_rate_select[ksr];
	}
}

/* set multi,am,vib,EG-TYP,KSR,mul */
static void set_mul(uint8_t slot, uint8_t v)
{
	OPL3_CH   *CH   = &chip.P_CH[slot >> 1];
	OPL3_SLOT *SLOT = (slot & 1) ? &CH->SLOT1 : &CH->SLOT0;

	SLOT->mul     = PITCH_COEF*mul_tab[v & 0x0f];
	SLOT->KSR     = (v & 0x10) ? 0 : 2;
	SLOT->eg_type = !!(v & 0x20);
	SLOT->vib     = !!(v & 0x40);
	SLOT->AMmask_TLL = ((uint16_t)(v & 0x80) << 8) + (SLOT->AMmask_TLL & 0x7fff);

	if (chip.OPL3_mode)
	{
		int8_t chan_no = slot >> 1;

		switch(chan_no)
		{
		case 0: case 1: case 2:
		case 9: case 10: case 11:
			if (CH->extended) CALC_FCSLOT(CH,SLOT); /* normal */
			else CALC_FCSLOT(CH,SLOT); /* normal */
		break;
		case 3: case 4: case 5:
		case 12: case 13: case 14:
			if ((CH-3)->extended) CALC_FCSLOT(CH-3,SLOT); /* update this SLOT using frequency data for 1st channel of a pair */
			else CALC_FCSLOT(CH,SLOT); /* normal */
		break;
		default: 
			CALC_FCSLOT(CH,SLOT); /* normal */
			break;
		}
	}
	else CALC_FCSLOT(CH,SLOT); /* in OPL2 mode */
}

/* set ksl & tl */
static void set_ksl_tl(uint8_t slot, uint8_t v)
{
	OPL3_CH   *CH   = &chip.P_CH[slot >> 1];
	OPL3_SLOT *SLOT = (slot & 1)  ? &CH->SLOT1 : &CH->SLOT0;

	SLOT->ksl = ksl_shift[v >> 6];
	SLOT->TL  = (v & 0x3f) << (ENV_BITS-1-7); /* 7 bits TL (bit 6 = always 0) */
	SLOT->AMmask_TLL = SLOT->TL + (CH->ksl_base >> SLOT->ksl) + (SLOT->AMmask_TLL & 0x8000);

	if (chip.OPL3_mode)
	{
		uint8_t chan_no = slot >> 2;

		switch(chan_no)
		{
			case 3: case 4: case 5:
			case 12: case 13: case 14:
				if ((CH-3)->extended) SLOT->AMmask_TLL = SLOT->TL + ((CH-3)->ksl_base>>SLOT->ksl) + (SLOT->AMmask_TLL & 0x8000); /* update this SLOT using frequency data for 1st channel of a pair */
			break;
		}
	}
}

/* set attack rate & decay rate  */
static void set_ar_dr(uint8_t slot, uint8_t v)
{
	OPL3_CH   *CH   = &chip.P_CH[slot >> 1];
	OPL3_SLOT *SLOT = (slot & 1) ? &CH->SLOT1 : &CH->SLOT0;
	uint8_t ksr;
	SLOT->ar = (v & 0xf0) ? 16 + ((v & 0xf0) >> 2) : 0;

	ksr = SLOT->ar + SLOT->ksr;
	if (ksr < 16+60) /* verified on real YMF262 - all 15 x rates take "zero" time */
	{
		SLOT->eg_sh_ar  = eg_rate_shift [ksr];
		SLOT->eg_sel_ar = eg_rate_select[ksr];
	}
	else
	{
		SLOT->eg_sh_ar  = 0;
		SLOT->eg_sel_ar = 13*RATE_STEPS;
	}
	
	SLOT->dr    = (v&0x0f) ? 16 + ((v&0x0f)<<2) : 0;
	ksr = SLOT->dr + SLOT->ksr;
	SLOT->eg_sh_dr  = eg_rate_shift [ksr];
	SLOT->eg_sel_dr = eg_rate_select[ksr];
}

/* set sustain level & release rate */
static void set_sl_rr(uint8_t slot, uint8_t v)
{
	OPL3_CH   *CH   = &chip.P_CH[slot >> 1];
	OPL3_SLOT *SLOT = (slot & 1) ? &CH->SLOT1 : &CH->SLOT0;
	uint8_t ksr = SLOT->ksr;
	SLOT->sl  = (uint16_t)sl_tab[ v>>4 ] << 1;
	SLOT->rr  = (v&0x0f) ? 16 + ((v&0x0f)<<2) : 0;
	ksr += SLOT->rr;
	SLOT->eg_sh_rr  = eg_rate_shift [ksr];
	SLOT->eg_sel_rr = eg_rate_select[ksr];
}

void fn_a0(uint16_t r, uint8_t v, uint8_t ch_offset)
{
	OPL3_CH *CH;
	uint16_t block_fnum;

	if (r == 0xbd)          /* am depth, vibrato depth, r,bd,sd,tom,tc,hh */
	{
		if (ch_offset != 0) return; /* 0xbd register is present in set #1 only */

		chip.lfo_am_depth = !!(v & 0x80);
		chip.lfo_pm_depth_range = (v & 0x40) ? 8 : 0;
		chip.rhythm = !!(v & 0x20);

		if (chip.rhythm)
		{
			/* BD key on/off */
			if (v & 0x10)
			{
				FM_KEYON(&chip.P_CH[6].SLOT0, 2);
				FM_KEYON(&chip.P_CH[6].SLOT1, 2);
			}
			else
			{
				FM_KEYOFF(&chip.P_CH[6].SLOT0, ~2);
				FM_KEYOFF(&chip.P_CH[6].SLOT1, ~2);
			}
			/* HH key on/off */
			if (v & 0x01) FM_KEYON(&chip.P_CH[7].SLOT0, 2);
			else       FM_KEYOFF(&chip.P_CH[7].SLOT0, ~2);
			/* SD key on/off */
			if (v & 0x08) FM_KEYON(&chip.P_CH[7].SLOT1, 2);
			else       FM_KEYOFF(&chip.P_CH[7].SLOT1, ~2);
			/* TOM key on/off */
			if (v & 0x04) FM_KEYON(&chip.P_CH[8].SLOT0, 2);
			else       FM_KEYOFF(&chip.P_CH[8].SLOT0, ~2);
			/* TOP-CY key on/off */
			if (v & 0x02) FM_KEYON(&chip.P_CH[8].SLOT1, 2);
			else       FM_KEYOFF(&chip.P_CH[8].SLOT1, ~2);
		}
		else
		{
			/* BD key off */
			FM_KEYOFF(&chip.P_CH[6].SLOT0, ~2);
			FM_KEYOFF(&chip.P_CH[6].SLOT1, ~2);
			/* HH key off */
			FM_KEYOFF(&chip.P_CH[7].SLOT0, ~2);
			/* SD key off */
			FM_KEYOFF(&chip.P_CH[7].SLOT1, ~2);
			/* TOM key off */
			FM_KEYOFF(&chip.P_CH[8].SLOT0, ~2);
			/* TOP-CY off */
			FM_KEYOFF(&chip.P_CH[8].SLOT1, ~2);
		}
		return;
	}

	/* keyon,block,fnum */
	if ((r & 0x0f) > 8) return;
	CH = &chip.P_CH[(r & 0x0f) + ch_offset];

	if (!(r & 0x10)) block_fnum = (CH->block_fnum & 0x1f00) | v; /* a0-a8 */
	else
	{   /* b0-b8 */
		block_fnum = ((v & 0x1f) << 8) | (CH->block_fnum & 0xff);

		if (chip.OPL3_mode)
		{
			uint8_t chan_no = (r & 0x0f) + ch_offset;
			switch (chan_no)
			{
			case 0: case 1: case 2:
			case 9: case 10: case 11:
				if (CH->extended)
				{
					if (v & 0x20)
					{
						FM_KEYON(&CH->SLOT0, 1);
						FM_KEYON(&CH->SLOT1, 1);
						FM_KEYON(&(CH + 3)->SLOT0, 1);
						FM_KEYON(&(CH + 3)->SLOT1, 1);
					}
					else
					{
						FM_KEYOFF(&CH->SLOT0, ~1);
						FM_KEYOFF(&CH->SLOT1, ~1);
						FM_KEYOFF(&(CH + 3)->SLOT0, ~1);
						FM_KEYOFF(&(CH + 3)->SLOT1, ~1);
					}
				}
				else
				{
					if (v & 0x20)
					{
						FM_KEYON(&CH->SLOT0, 1);
						FM_KEYON(&CH->SLOT1, 1);
					}
					else
					{
						FM_KEYOFF(&CH->SLOT0, ~1);
						FM_KEYOFF(&CH->SLOT1, ~1);
					}
				}
				break;

			case 3: case 4: case 5:
			case 12: case 13: case 14:
				if ((CH - 3)->extended)
				{
					//if this is 2nd channel forming up 4-op channel just do nothing
				}
				else
				{
					if (v & 0x20)
					{
						FM_KEYON(&CH->SLOT0, 1);
						FM_KEYON(&CH->SLOT1, 1);
					}
					else
					{
						FM_KEYOFF(&CH->SLOT0, ~1);
						FM_KEYOFF(&CH->SLOT1, ~1);
					}
				}
				break;

			default:
				if (v & 0x20)
				{
					FM_KEYON(&CH->SLOT0, 1);
					FM_KEYON(&CH->SLOT1, 1);
				}
				else
				{
					FM_KEYOFF(&CH->SLOT0, ~1);
					FM_KEYOFF(&CH->SLOT1, ~1);
				}
				break;
			}
		}
		else
		{
			if (v & 0x20)
			{
				FM_KEYON(&CH->SLOT0, 1);
				FM_KEYON(&CH->SLOT1, 1);
			}
			else
			{
				FM_KEYOFF(&CH->SLOT0, ~1);
				FM_KEYOFF(&CH->SLOT1, ~1);
			}
		}
	}
	/* update */
	if (CH->block_fnum != block_fnum)
	{
		CH->block_fnum = block_fnum;
		CH->ksl_base = ksl_tab[block_fnum >> 6];

		/* BLK 2,1,0 bits -> bits 3,2,1 of kcode */
		CH->kcode = (CH->block_fnum & 0x1c00) >> 9;

		/* the info below is actually opposite to what is stated in the Manuals (verifed on real YMF262) */
		/* if notesel == 0 -> lsb of kcode is bit 10 (MSB) of fnum  */
		/* if notesel == 1 -> lsb of kcode is bit 9 (MSB-1) of fnum */
		if (chip.nts & 0x40) CH->kcode |= (CH->block_fnum >> 8) & 1; /* notesel == 1 */
		else CH->kcode |= (CH->block_fnum >> 9) & 1; /* notesel == 0 */

		if (chip.OPL3_mode)
		{
			uint8_t chan_no = (r & 0x0f) + ch_offset;
			switch (chan_no)
			{
				case 0: case 1: case 2:
				case 9: case 10: case 11:
					if (CH->extended)
					{
						/* refresh Total Level in FOUR SLOTs of this channel and channel+3 using data from THIS channel */
						(CH + 3)->SLOT0.AMmask_TLL = (CH + 3)->SLOT0.TL + (CH->ksl_base >> (CH + 3)->SLOT0.ksl) + ((CH + 3)->SLOT0.AMmask_TLL & 0x8000);
						(CH + 3)->SLOT1.AMmask_TLL = (CH + 3)->SLOT1.TL + (CH->ksl_base >> (CH + 3)->SLOT1.ksl) + ((CH + 3)->SLOT1.AMmask_TLL & 0x8000);

						/* refresh frequency counter in FOUR SLOTs of this channel and channel+3 using data from THIS channel */
						CALC_FCSLOT(CH, &(CH + 3)->SLOT0);
						CALC_FCSLOT(CH, &(CH + 3)->SLOT1);
					}
					break;

				case 3: case 4: case 5:
				case 12: case 13: case 14:
					if ((CH - 3)->extended) return;  //if this is 2nd channel forming up 4-op channel just do nothing
					break;
			}
		}
		/* in OPL2 mode */
		/* refresh Total Level in both SLOTs of this channel */
		CH->SLOT0.AMmask_TLL = CH->SLOT0.TL + (CH->ksl_base >> CH->SLOT0.ksl) + (CH->SLOT0.AMmask_TLL & 0x8000);
		CH->SLOT1.AMmask_TLL = CH->SLOT1.TL + (CH->ksl_base >> CH->SLOT1.ksl) + (CH->SLOT1.AMmask_TLL & 0x8000);

		/* refresh frequency counter in both SLOTs of this channel */
		CALC_FCSLOT(CH, &CH->SLOT0);
		CALC_FCSLOT(CH, &CH->SLOT1);
	}
}

uint16_t packptr16(void *ptr)
{
	uint16_t v;
	uint16_t i = (uint8_t*)ptr - (uint8_t*)&chip;
	uint8_t j;
	for (j = 0; i >= 96; i -= 96, j++);
	v = (uint16_t)j << 7;
	j = i & 0xff;
	if (j >= 48) j -= 48, v |= 64;
	return v | j;
}

/* write a value v to register r on OPL chip */
static void OPL3WriteReg(uint16_t r, uint8_t v)
{
	OPL3_CH *CH;
	uint8_t ch_offset = 0, base;
	int8_t slot;
	uint32_t mask;

	if(r & 0x100)
	{
		switch(r)
		{
		case 0x101: return; /* test register */

		case 0x104: /* 6 channels enable */
			{
				CH = &chip.P_CH[0];    /* channel 0 */
				CH->extended = v & 1;
				CH++;                   /* channel 1 */
				CH->extended = (v>>=1) & 1;
				CH++;                   /* channel 2 */
				CH->extended = (v>>=1) & 1;
				CH = &chip.P_CH[9];    /* channel 9 */
				CH->extended = (v>>=1) & 1;
				CH++;                   /* channel 10 */
				CH->extended = (v>>=1) & 1;
				CH++;                   /* channel 11 */
				CH->extended = (v>>1) & 1;
			}
			return;

		case 0x105: /* OPL3 extensions enable register */
			chip.OPL3_mode = v & 0x01;   /* OPL3 mode when bit0=1 otherwise it is OPL2 mode */
			return;
		}
		ch_offset = 9;  /* register page #2 starts from channel 9 (counting from 0) */
	}

	r &= 0xff; /* adjust bus to 8 bits */

	switch(r & 0xe0)
	{
	case 0x00:  /* 00-1f:control */
		switch(r & 0x1f)
		{
		case 0x01:  /* test register */
		break;
		case 0x02:  /* Timer 1 */
		break;
		case 0x03:  /* Timer 2 */
		break;
		case 0x04:  /* IRQ clear / mask and Timer enable */
		break;
		case 0x08:  /* x,NTS,x,x, x,x,x,x */
			chip.nts = v;
			break;
		}
		break;
	case 0x20:  /* am ON, vib ON, ksr, eg_type, mul */
		slot = slot_array[r & 0x1f];
		if(slot < 0) return;
		set_mul(slot + ch_offset*2, v);
	break;
	case 0x40:
		slot = slot_array[r & 0x1f];
		if(slot < 0) return;
		set_ksl_tl(slot + ch_offset*2, v);
	break;
	case 0x60:
		slot = slot_array[r&0x1f];
		if(slot < 0) return;
		set_ar_dr(slot + ch_offset*2, v);
	break;
	case 0x80:
		slot = slot_array[r&0x1f];
		if(slot < 0) return;
		set_sl_rr(slot + ch_offset*2, v);
	break;
	case 0xa0:
		fn_a0(r, v, ch_offset);
		break;

	case 0xc0:
		/* CH.D, CH.C, CH.B, CH.A, FB(3bits), C */
		if( (r & 0xf) > 8) return;
		CH = &chip.P_CH[(r & 0xf) + ch_offset];
		base = (r & 0xf) + ch_offset;
		mask = 1l << base;

		if (chip.OPL3_mode) /* OPL3 mode */
		{
			chip.panA = (chip.panA & ~mask) | ((uint32_t)((v & 0x10) >> 4) << base);
			chip.panB = (chip.panB & ~mask) | ((uint32_t)((v & 0x20) >> 5) << base);
//			chip.pan[ base    ] = (v & 0x10) != 0; /* ch.A */
//			chip.pan[ base +1 ] = (v & 0x20) != 0; /* ch.B */
//			chip.pan[ base +2 ] = (v & 0x40) != 0; /* ch.C */
//			chip.pan[ base +3 ] = (v & 0x80) != 0; /* ch.D */
		}
		else /* OPL2 mode - always enabled */
		{
			chip.panA |= mask;
			chip.panB |= mask;
//			chip.pan[ base    ] = 1;      /* ch.A */
//			chip.pan[ base +1 ] = 1;      /* ch.B */
//			chip.pan[ base +2 ] = 1;      /* ch.C */
//			chip.pan[ base +3 ] = 1;      /* ch.D */
		}
		CH->SLOT0.FB  = (v & 0xe) ? 9 - ((v & 0xe) >> 1) : 0;
		CH->SLOT0.CON = v & 1;

		if( chip.OPL3_mode )
		{
			uint8_t chan_no = (r & 0x0f) + ch_offset;

			switch(chan_no)
			{
			case 0: case 1: case 2:
			case 9: case 10: case 11:
				if (CH->extended)
				{
					uint8_t conn = (CH->SLOT0.CON << 1) | (CH+3)->SLOT0.CON;
					switch(conn)
					{
					case 0:
						/* 1 -> 2 -> 3 -> 4 - out */
						CH->SLOT0.connect = packptr16(&chip.phase_modulation);
						CH->SLOT1.connect = packptr16(&chip.phase_modulation2);
						(CH+3)->SLOT0.connect = packptr16(&chip.phase_modulation);
						(CH + 3)->SLOT1.connect = packptr16(&chip.P_CH[chan_no + 3].chanout);// chanout[chan_no + 3];
					break;
					case 1:
						/* 1 -> 2 -\
						   3 -> 4 -+- out */
						CH->SLOT0.connect = packptr16(&chip.phase_modulation);
						CH->SLOT1.connect = packptr16(&chip.P_CH[chan_no].chanout); // chanout[chan_no];
						(CH+3)->SLOT0.connect = packptr16(&chip.phase_modulation);
						(CH+3)->SLOT1.connect = packptr16(&chip.P_CH[chan_no + 3].chanout);
					break;
					case 2:
						/* 1 -----------\
						   2 -> 3 -> 4 -+- out */
						CH->SLOT0.connect = packptr16(&chip.P_CH[chan_no].chanout);
						CH->SLOT1.connect = packptr16(&chip.phase_modulation2);
						(CH+3)->SLOT0.connect = packptr16(&chip.phase_modulation);
						(CH+3)->SLOT1.connect = packptr16(&chip.P_CH[chan_no + 3].chanout);
					break;
					case 3:
						/* 1 ------\
						   2 -> 3 -+- out
						   4 ------/     */
						CH->SLOT0.connect = packptr16(&chip.P_CH[chan_no].chanout);
						CH->SLOT1.connect = packptr16(&chip.phase_modulation2);
						(CH+3)->SLOT0.connect = packptr16(&chip.P_CH[chan_no + 3].chanout);
						(CH+3)->SLOT1.connect = packptr16(&chip.P_CH[chan_no + 3].chanout);
					break;
					}
				}
				else
				{
					/* 2 operators mode */
					CH->SLOT0.connect = packptr16(CH->SLOT0.CON ? &chip.P_CH[(r & 0xf) + ch_offset].chanout : &chip.phase_modulation);
					CH->SLOT1.connect = packptr16(&chip.P_CH[(r & 0xf) + ch_offset].chanout);
				}
			break;

			case 3: case 4: case 5:
			case 12: case 13: case 14:
				if ((CH-3)->extended)
				{
					uint8_t conn = ((CH-3)->SLOT0.CON << 1) | CH->SLOT0.CON;
					switch(conn)
					{
					case 0:
						/* 1 -> 2 -> 3 -> 4 - out */
						(CH-3)->SLOT0.connect = packptr16(&chip.phase_modulation);
						(CH-3)->SLOT1.connect = packptr16(&chip.phase_modulation2);
						CH->SLOT0.connect = packptr16(&chip.phase_modulation);
						CH->SLOT1.connect = packptr16(&chip.P_CH[ chan_no ].chanout);
					break;
					case 1:
						/* 1 -> 2 -\
						   3 -> 4 -+- out */
						(CH-3)->SLOT0.connect = packptr16(&chip.phase_modulation);
						(CH-3)->SLOT1.connect = packptr16(&chip.P_CH[ chan_no - 3 ].chanout);
						CH->SLOT0.connect = packptr16(&chip.phase_modulation);
						CH->SLOT1.connect = packptr16(&chip.P_CH[ chan_no ].chanout);
					break;
					case 2:
						/* 1 -----------\
						   2 -> 3 -> 4 -+- out */
						(CH-3)->SLOT0.connect = packptr16(&chip.P_CH[ chan_no - 3 ].chanout);
						(CH-3)->SLOT1.connect = packptr16(&chip.phase_modulation2);
						CH->SLOT0.connect = packptr16(&chip.phase_modulation);
						CH->SLOT1.connect = packptr16(&chip.P_CH[ chan_no ].chanout);
					break;
					case 3:
						/* 1 ------\
						   2 -> 3 -+- out
						   4 ------/     */
						(CH-3)->SLOT0.connect = packptr16(&chip.P_CH[ chan_no - 3 ].chanout);
						(CH-3)->SLOT1.connect = packptr16(&chip.phase_modulation2);
						CH->SLOT0.connect = packptr16(&chip.P_CH[ chan_no ].chanout);
						CH->SLOT1.connect = packptr16(&chip.P_CH[ chan_no ].chanout);
					break;
					}
				}
				else
				{
					/* 2 operators mode */
					CH->SLOT0.connect = packptr16(CH->SLOT0.CON ? &chip.P_CH[(r & 0xf) + ch_offset].chanout : &chip.phase_modulation);
					CH->SLOT1.connect = packptr16(&chip.P_CH[(r & 0xf)+ch_offset].chanout);
				}
			break;

			default:
					/* 2 operators mode */
					CH->SLOT0.connect = packptr16(CH->SLOT0.CON ? &chip.P_CH[(r & 0xf) + ch_offset].chanout : &chip.phase_modulation);
					CH->SLOT1.connect = packptr16(&chip.P_CH[(r & 0xf) + ch_offset].chanout);
			break;
			}
		}
		else
		{
			/* OPL2 mode - always 2 operators mode */
			CH->SLOT0.connect = packptr16(CH->SLOT0.CON ? &chip.P_CH[(r&0xf)+ch_offset].chanout : &chip.phase_modulation);
			CH->SLOT1.connect = packptr16(&chip.P_CH[(r&0xf)+ch_offset].chanout);
		}
	break;

	case 0xe0: /* waveform select */
		slot = slot_array[r&0x1f];
		if(slot < 0) return;

		slot += ch_offset*2;
		CH = &chip.P_CH[slot >> 1];

		/* store 3-bit value written regardless of current OPL2 or OPL3 mode... (verified on real YMF262) */
		v &= 7;
		if(slot & 1) CH->SLOT1.waveform_number = v;
		else CH->SLOT0.waveform_number = v;

		/* ... but select only waveforms 0-3 in OPL2 mode */
		if( !chip.OPL3_mode ) v &= 3; /* we're in OPL2 mode */
		if(slot & 1) CH->SLOT1.wavetable = v;
		else CH->SLOT0.wavetable = v;
	break;
	}
}

void OPL3ResetChip()
{
	uint16_t c;

//	eg_cnt   = 0;
//	noise_rng = 1;    /* noise shift register */
	memset(&chip, 0, sizeof(chip));
	for(c = 0xff ; c >= 0x20 ; c-- ) OPL3WriteReg(c, 0);
	for(c = 0x1ff ; c >= 0x120 ; c-- ) OPL3WriteReg(c, 0);

	/* reset operator parameters */
	for( c = 0 ; c < 9*2 ; c++ )
	{
		OPL3_CH *CH = &chip.P_CH[c];
		CH->SLOT0.state   = EG_OFF;
		CH->SLOT0.volume  = MAX_ATT_INDEX;
		CH->SLOT1.state	= EG_OFF;
		CH->SLOT1.volume	= MAX_ATT_INDEX;
	}
}

/* YMF262 I/O interface */
void OPL3Write(uint8_t a, uint8_t v)
{
	switch(a&3)
	{
	case 0: /* address port 0 (register set #1) */
		chip.address = v;
		break;

	case 1: /* data port - ignore A1 */
	case 3: /* data port - ignore A1 */
//		if(chip->UpdateHandler) chip->UpdateHandler(chip->UpdateParam,0);
		OPL3WriteReg(chip.address, v);
	break;

	case 2: /* address port 1 (register set #2) */
		if( chip.OPL3_mode ) chip.address = v | 0x100; /* OPL3 mode */
		else
		{
			if( v==5 ) chip.address = v | 0x100; /* in OPL2 mode the only accessible in set #2 is register 0x05 */
			else chip.address = v;  /* verified range: 0x01, 0x04, 0x20-0xef(set #2 becomes set #1 in opl2 mode) */
		}
		break;
	}
}



