Patchwork [v3,22/25] ay8910: 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.AA00165@YOUR-BD18D6DD63.m1.interq.or.jp>
Download mbox | patch
Permalink /patch/37155/
State New
Headers show

Comments


Paolo Bonzini - Oct. 28, 2009, 9:55 p.m.
On 10/28/2009 09:08 PM, Stuart Brady wrote:
> On Thu, Oct 29, 2009 at 01:50:11AM +0900, TAKEDA, toshiya wrote:
>> +
>> +/* This version of ay8910.c is a fork of the MAME 0.59 one, relicensed under the LGPL.
>
> Where have you taken this from?

More exactly, how is this not violating copyright, since MAME's license 
is not compatible with anything else (more or less)?

Paolo
Roy Tam - Oct. 29, 2009, 12:35 a.m.
I did a google code search and I found this:
http://www.google.com/codesearch/p?hl=zh-TW&sa=N&cd=2&ct=rc#yVjp3hog9Qw/trunk/breemlib/apu/ay8910/ay8910.cpp&q=ay8910

//
// From mame.txt (http://www.mame.net/readme.html)
//
// VI. Reuse of Source Code
// --------------------------
//    This chapter might not apply to specific portions of MAME (e.g. CPU
//    emulators) which bear different copyright notices.
//    The source code cannot be used in a commercial product without the written
//    authorization of the authors. Use in non-commercial products is
allowed, and
//    indeed encouraged.  If you use portions of the MAME source code in your
//    program, however, you must make the full source code freely available as
//    well.
//    Usage of the _information_ contained in the source code is free
for any use.
//    However, given the amount of time and energy it took to collect this
//    information, if you find new information we would appreciate if
you made it
//    freely available as well.
//

Does it apply to this case?

P.S.: Mail resent as I click wrong button, sorry.

2009/10/29 Paolo Bonzini <bonzini@gnu.org>:
> On 10/28/2009 09:08 PM, Stuart Brady wrote:
>>
>> On Thu, Oct 29, 2009 at 01:50:11AM +0900, TAKEDA, toshiya wrote:
>>>
>>> +
>>> +/* This version of ay8910.c is a fork of the MAME 0.59 one, relicensed
>>> under the LGPL.
>>
>> Where have you taken this from?
>
> More exactly, how is this not violating copyright, since MAME's license is
> not compatible with anything else (more or less)?
>
> Paolo
>
>
>
Natalia Portillo - Oct. 29, 2009, 3:05 a.m.
This is interesting as well, first line says:
/* borrowed from AppleWin */

I suppose it means that MAME took it from the apple // emulator called  
AppleWin. and. what's the AppleWin license?

El 29/10/2009, a las 00:35, Roy Tam escribió:

> I did a google code search and I found this:
> http://www.google.com/codesearch/p?hl=zh-TW&sa=N&cd=2&ct=rc#yVjp3hog9Qw/trunk/breemlib/apu/ay8910/ay8910.cpp&q=ay8910
>
> //
> // From mame.txt (http://www.mame.net/readme.html)
> //
> // VI. Reuse of Source Code
> // --------------------------
> //    This chapter might not apply to specific portions of MAME  
> (e.g. CPU
> //    emulators) which bear different copyright notices.
> //    The source code cannot be used in a commercial product without  
> the written
> //    authorization of the authors. Use in non-commercial products is
> allowed, and
> //    indeed encouraged.  If you use portions of the MAME source  
> code in your
> //    program, however, you must make the full source code freely  
> available as
> //    well.
> //    Usage of the _information_ contained in the source code is free
> for any use.
> //    However, given the amount of time and energy it took to  
> collect this
> //    information, if you find new information we would appreciate if
> you made it
> //    freely available as well.
> //
>
> Does it apply to this case?
>
> P.S.: Mail resent as I click wrong button, sorry.
>
> 2009/10/29 Paolo Bonzini <bonzini@gnu.org>:
>> On 10/28/2009 09:08 PM, Stuart Brady wrote:
>>>
>>> On Thu, Oct 29, 2009 at 01:50:11AM +0900, TAKEDA, toshiya wrote:
>>>>
>>>> +
>>>> +/* This version of ay8910.c is a fork of the MAME 0.59 one,  
>>>> relicensed
>>>> under the LGPL.
>>>
>>> Where have you taken this from?
>>
>> More exactly, how is this not violating copyright, since MAME's  
>> license is
>> not compatible with anything else (more or less)?
>>
>> Paolo
>>
>>
>>
>
>
Roy Tam - Oct. 29, 2009, 3:55 a.m.
breemlib takes this file from AppleWin, and AppleWin may take this
file from MAME.
for AppleWin, it uses GPLv2 since 2006/02/25.

2009/10/29 Natalia Portillo <claunia@claunia.com>:
> This is interesting as well, first line says:
>
> /* borrowed from AppleWin */
>
> I suppose it means that MAME took it from the apple // emulator called
> AppleWin. and. what's the AppleWin license?
> El 29/10/2009, a las 00:35, Roy Tam escribió:
>
> I did a google code search and I found this:
> http://www.google.com/codesearch/p?hl=zh-TW&sa=N&cd=2&ct=rc#yVjp3hog9Qw/trunk/breemlib/apu/ay8910/ay8910.cpp&q=ay8910
>
> //
> // From mame.txt (http://www.mame.net/readme.html)
> //
> // VI. Reuse of Source Code
> // --------------------------
> //    This chapter might not apply to specific portions of MAME (e.g. CPU
> //    emulators) which bear different copyright notices.
> //    The source code cannot be used in a commercial product without the
> written
> //    authorization of the authors. Use in non-commercial products is
> allowed, and
> //    indeed encouraged.  If you use portions of the MAME source code in
> your
> //    program, however, you must make the full source code freely available
> as
> //    well.
> //    Usage of the _information_ contained in the source code is free
> for any use.
> //    However, given the amount of time and energy it took to collect this
> //    information, if you find new information we would appreciate if
> you made it
> //    freely available as well.
> //
>
> Does it apply to this case?
>
> P.S.: Mail resent as I click wrong button, sorry.
>
> 2009/10/29 Paolo Bonzini <bonzini@gnu.org>:
>
> On 10/28/2009 09:08 PM, Stuart Brady wrote:
>
> On Thu, Oct 29, 2009 at 01:50:11AM +0900, TAKEDA, toshiya wrote:
>
> +
>
> +/* This version of ay8910.c is a fork of the MAME 0.59 one, relicensed
>
> under the LGPL.
>
> Where have you taken this from?
>
> More exactly, how is this not violating copyright, since MAME's license is
>
> not compatible with anything else (more or less)?
>
> Paolo
>
>
>
>
>
>
>
Stuart Brady - Oct. 29, 2009, 7:52 a.m.
On Wed, Oct 28, 2009 at 10:55:04PM +0100, Paolo Bonzini wrote:
> On 10/28/2009 09:08 PM, Stuart Brady wrote:
> >On Thu, Oct 29, 2009 at 01:50:11AM +0900, TAKEDA, toshiya wrote:
> >>+
> >>+/* This version of ay8910.c is a fork of the MAME 0.59 one, relicensed 
> >>under the LGPL.
> >
> >Where have you taken this from?
> 
> More exactly, how is this not violating copyright, since MAME's license 
> is not compatible with anything else (more or less)?

For that matter, fmopl.c in QEMU looks an awful lot like a copyright
violation to me:

http://www.google.com/codesearch?q=%22This+version+of+fmopl.c%22

Cheers,
Roy Tam - Oct. 29, 2009, 8:03 a.m.
Version 0.37a of fmopl.c/h is relicensed to LGPL by Tatsuyuki
Satoh(original fmopl developer).
other versions are not. Especially newer versions by Jarek Burczynski
as he refused to relicense new fmopl to LGPL.

2009/10/29 Stuart Brady <sdbrady@ntlworld.com>:
> On Wed, Oct 28, 2009 at 10:55:04PM +0100, Paolo Bonzini wrote:
>> On 10/28/2009 09:08 PM, Stuart Brady wrote:
>> >On Thu, Oct 29, 2009 at 01:50:11AM +0900, TAKEDA, toshiya wrote:
>> >>+
>> >>+/* This version of ay8910.c is a fork of the MAME 0.59 one, relicensed
>> >>under the LGPL.
>> >
>> >Where have you taken this from?
>>
>> More exactly, how is this not violating copyright, since MAME's license
>> is not compatible with anything else (more or less)?
>
> For that matter, fmopl.c in QEMU looks an awful lot like a copyright
> violation to me:
>
> http://www.google.com/codesearch?q=%22This+version+of+fmopl.c%22
>
> Cheers,
> --
> Stuart Brady
>
>
>
malc - Oct. 29, 2009, 8:14 a.m.
On Thu, 29 Oct 2009, Roy Tam wrote:

> Version 0.37a of fmopl.c/h is relicensed to LGPL by Tatsuyuki
> Satoh(original fmopl developer).
> other versions are not. Especially newer versions by Jarek Burczynski
> as he refused to relicense new fmopl to LGPL.

The first part is the case, the fmopl.c used by QEMU is the relicensed
LGPL version taken from adplug. As for refusal to relicense newer fmopl
and ymf262 all i can say that my attempts to contact Jarek was
unsuccessful so i don't know his real stance on the subject.

> 2009/10/29 Stuart Brady <sdbrady@ntlworld.com>:
> > On Wed, Oct 28, 2009 at 10:55:04PM +0100, Paolo Bonzini wrote:
> >> On 10/28/2009 09:08 PM, Stuart Brady wrote:
> >> >On Thu, Oct 29, 2009 at 01:50:11AM +0900, TAKEDA, toshiya wrote:
> >> >>+
> >> >>+/* This version of ay8910.c is a fork of the MAME 0.59 one, relicensed
> >> >>under the LGPL.
> >> >
> >> >Where have you taken this from?
> >>
> >> More exactly, how is this not violating copyright, since MAME's license
> >> is not compatible with anything else (more or less)?
> >
> > For that matter, fmopl.c in QEMU looks an awful lot like a copyright
> > violation to me:
> >
> > http://www.google.com/codesearch?q=%22This+version+of+fmopl.c%22

P.S. Please don't top post.
Paolo Bonzini - Oct. 29, 2009, 8:52 a.m.
On 10/29/2009 04:55 AM, Roy Tam wrote:
> AppleWin may take this file from MAME.
> for AppleWin, it uses GPLv2 since 2006/02/25.

Unfortunately, AppleWin is also not respecting neither the GPL nor the 
MAME license in using this file. :-(

Paolo
Laurent Desnogues - Oct. 29, 2009, 9:30 a.m.
On Thu, Oct 29, 2009 at 9:14 AM, malc <av1474@comtv.ru> wrote:
> On Thu, 29 Oct 2009, Roy Tam wrote:
>
>> Version 0.37a of fmopl.c/h is relicensed to LGPL by Tatsuyuki
>> Satoh(original fmopl developer).
>> other versions are not. Especially newer versions by Jarek Burczynski
>> as he refused to relicense new fmopl to LGPL.
>
> The first part is the case, the fmopl.c used by QEMU is the relicensed
> LGPL version taken from adplug. As for refusal to relicense newer fmopl
> and ymf262 all i can say that my attempts to contact Jarek was
> unsuccessful so i don't know his real stance on the subject.

I can ask questions on the MAME dev mailing-list.  I just need a
list of what drivers are wanted for QEMU.  I just hope the original
writers are still members of MAMEdev :-)


Laurent
malc - Oct. 29, 2009, 9:44 a.m.
On Thu, 29 Oct 2009, Laurent Desnogues wrote:

> On Thu, Oct 29, 2009 at 9:14 AM, malc <av1474@comtv.ru> wrote:
> > On Thu, 29 Oct 2009, Roy Tam wrote:
> >
> >> Version 0.37a of fmopl.c/h is relicensed to LGPL by Tatsuyuki
> >> Satoh(original fmopl developer).
> >> other versions are not. Especially newer versions by Jarek Burczynski
> >> as he refused to relicense new fmopl to LGPL.
> >
> > The first part is the case, the fmopl.c used by QEMU is the relicensed
> > LGPL version taken from adplug. As for refusal to relicense newer fmopl
> > and ymf262 all i can say that my attempts to contact Jarek was
> > unsuccessful so i don't know his real stance on the subject.
> 
> I can ask questions on the MAME dev mailing-list.  I just need a
> list of what drivers are wanted for QEMU.  I just hope the original
> writers are still members of MAMEdev :-)

That'd be very nice of you :)

For ymf262 driver the files are in need for relicensing are:

ymdeltat.h
ymf262.c
ymf262.h
Laurent Desnogues - Oct. 29, 2009, 9:45 a.m.
On Thu, Oct 29, 2009 at 10:44 AM, malc <av1474@comtv.ru> wrote:
> On Thu, 29 Oct 2009, Laurent Desnogues wrote:
>
>> On Thu, Oct 29, 2009 at 9:14 AM, malc <av1474@comtv.ru> wrote:
>> > On Thu, 29 Oct 2009, Roy Tam wrote:
>> >
>> >> Version 0.37a of fmopl.c/h is relicensed to LGPL by Tatsuyuki
>> >> Satoh(original fmopl developer).
>> >> other versions are not. Especially newer versions by Jarek Burczynski
>> >> as he refused to relicense new fmopl to LGPL.
>> >
>> > The first part is the case, the fmopl.c used by QEMU is the relicensed
>> > LGPL version taken from adplug. As for refusal to relicense newer fmopl
>> > and ymf262 all i can say that my attempts to contact Jarek was
>> > unsuccessful so i don't know his real stance on the subject.
>>
>> I can ask questions on the MAME dev mailing-list.  I just need a
>> list of what drivers are wanted for QEMU.  I just hope the original
>> writers are still members of MAMEdev :-)
>
> That'd be very nice of you :)
>
> For ymf262 driver the files are in need for relicensing are:
>
> ymdeltat.h
> ymf262.c
> ymf262.h

And not ay8910 ?


Laurent
Roy Tam - Oct. 29, 2009, 9:55 a.m.
2009/10/29 malc <av1474@comtv.ru>:
> On Thu, 29 Oct 2009, Roy Tam wrote:
>
>> Version 0.37a of fmopl.c/h is relicensed to LGPL by Tatsuyuki
>> Satoh(original fmopl developer).
>> other versions are not. Especially newer versions by Jarek Burczynski
>> as he refused to relicense new fmopl to LGPL.
>
> The first part is the case, the fmopl.c used by QEMU is the relicensed
> LGPL version taken from adplug. As for refusal to relicense newer fmopl
> and ymf262 all i can say that my attempts to contact Jarek was
> unsuccessful so i don't know his real stance on the subject.
>

Even if we don't use fmopl, we can also port dbopl(C++) and/or opl.cpp
from dosbox.

>> 2009/10/29 Stuart Brady <sdbrady@ntlworld.com>:
>> > On Wed, Oct 28, 2009 at 10:55:04PM +0100, Paolo Bonzini wrote:
>> >> On 10/28/2009 09:08 PM, Stuart Brady wrote:
>> >> >On Thu, Oct 29, 2009 at 01:50:11AM +0900, TAKEDA, toshiya wrote:
>> >> >>+
>> >> >>+/* This version of ay8910.c is a fork of the MAME 0.59 one, relicensed
>> >> >>under the LGPL.
>> >> >
>> >> >Where have you taken this from?
>> >>
>> >> More exactly, how is this not violating copyright, since MAME's license
>> >> is not compatible with anything else (more or less)?
>> >
>> > For that matter, fmopl.c in QEMU looks an awful lot like a copyright
>> > violation to me:
>> >
>> > http://www.google.com/codesearch?q=%22This+version+of+fmopl.c%22
>
> P.S. Please don't top post.
>

sorry about that.

> --
> mailto:av1474@comtv.ru
>
malc - Oct. 29, 2009, 10:05 a.m.
On Thu, 29 Oct 2009, Laurent Desnogues wrote:

> On Thu, Oct 29, 2009 at 10:44 AM, malc <av1474@comtv.ru> wrote:
> > On Thu, 29 Oct 2009, Laurent Desnogues wrote:
> >
> >> On Thu, Oct 29, 2009 at 9:14 AM, malc <av1474@comtv.ru> wrote:
> >> > On Thu, 29 Oct 2009, Roy Tam wrote:
> >> >
> >> >> Version 0.37a of fmopl.c/h is relicensed to LGPL by Tatsuyuki
> >> >> Satoh(original fmopl developer).
> >> >> other versions are not. Especially newer versions by Jarek Burczynski
> >> >> as he refused to relicense new fmopl to LGPL.
> >> >
> >> > The first part is the case, the fmopl.c used by QEMU is the relicensed
> >> > LGPL version taken from adplug. As for refusal to relicense newer fmopl
> >> > and ymf262 all i can say that my attempts to contact Jarek was
> >> > unsuccessful so i don't know his real stance on the subject.
> >>
> >> I can ask questions on the MAME dev mailing-list.  I just need a
> >> list of what drivers are wanted for QEMU.  I just hope the original
> >> writers are still members of MAMEdev :-)
> >
> > That'd be very nice of you :)
> >
> > For ymf262 driver the files are in need for relicensing are:
> >
> > ymdeltat.h
> > ymf262.c
> > ymf262.h
> 
> And not ay8910 ?

I, personally, have relatively little to do with it (and pc98 in general),
just listed my own preferences.
Dear members.

Laurent Desnogues wrote:
>On Thu, Oct 29, 2009 at 9:14 AM, malc <av1474@comtv.ru> wrote:
>> On Thu, 29 Oct 2009, Roy Tam wrote:
>>
>>> Version 0.37a of fmopl.c/h is relicensed to LGPL by Tatsuyuki
>>> Satoh(original fmopl developer).
>>> other versions are not. Especially newer versions by Jarek Burczynski
>>> as he refused to relicense new fmopl to LGPL.
>>
>> The first part is the case, the fmopl.c used by QEMU is the relicensed
>> LGPL version taken from adplug. As for refusal to relicense newer fmopl
>> and ymf262 all i can say that my attempts to contact Jarek was
>> unsuccessful so i don't know his real stance on the subject.
>
>I can ask questions on the MAME dev mailing-list.  I just need a
>list of what drivers are wanted for QEMU.  I just hope the original
>writers are still members of MAMEdev :-)

Sorry, without enough consideration, I thought there are no license problems
because fmopl is already in qemu.

Thank you very much for your offer to ask in MAME dev mailing-list.
The modules needed are:
	ay8910.c and .h,
	fm.c and .h,
	ymdeltat.c and .h,
	ym2608intf.c and .h (original module name is 2608intf)


If it is refused, it is easy to remove them in the patch.

Makefile.target:
-obj-i386-y += ay8910.o ymdeltat.o fm.o ym2608intf.o pc98sound.o

hw/pc98.c
 #ifdef HAS_AUDIO
     pcspk_audio_init(isa_irq);
-    pc98_sound_init(isa_irq);
 #endif

Thanks,
TAKEDA, toshiya

Patch

diff --git a/qemu/hw/ay8910.c b/qemu/hw/ay8910.c
new file mode 100644
index 0000000..d371023
--- /dev/null
+++ b/qemu/hw/ay8910.c
@@ -0,0 +1,733 @@ 
+/***************************************************************************
+
+  ay8910.c
+
+
+  Emulation of the AY-3-8910 / YM2149 sound chip.
+
+  Based on various code snippets by Ville Hallik, Michael Cuddy,
+  Tatsuyuki Satoh, Fabrice Frances, Nicola Salmoria.
+
+***************************************************************************/
+
+/* This version of ay8910.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/>.
+ */
+
+#include <string.h>
+#include "ay8910.h"
+
+#define MAX_OUTPUT 0x7fff
+
+#define STEP 0x8000
+
+#define logerror(...)
+
+int ay8910_index_ym;
+static int num = 0, ym_num = 0;
+
+struct AY8910
+{
+	int SampleRate;
+	mem_read_handler PortAread;
+	mem_read_handler PortBread;
+	mem_write_handler PortAwrite;
+	mem_write_handler PortBwrite;
+	int register_latch;
+	unsigned char Regs[16];
+	int lastEnable;
+	unsigned int UpdateStep;
+	int PeriodA,PeriodB,PeriodC,PeriodN,PeriodE;
+	int CountA,CountB,CountC,CountN,CountE;
+	unsigned int VolA,VolB,VolC,VolE;
+	unsigned char EnvelopeA,EnvelopeB,EnvelopeC;
+	unsigned char OutputA,OutputB,OutputC,OutputN;
+	signed char CountEnv;
+	unsigned char Hold,Alternate,Attack,Holding;
+	int RNG;
+	unsigned int VolTable[32];
+};
+
+/* register id's */
+#define AY_AFINE	(0)
+#define AY_ACOARSE	(1)
+#define AY_BFINE	(2)
+#define AY_BCOARSE	(3)
+#define AY_CFINE	(4)
+#define AY_CCOARSE	(5)
+#define AY_NOISEPER	(6)
+#define AY_ENABLE	(7)
+#define AY_AVOL		(8)
+#define AY_BVOL		(9)
+#define AY_CVOL		(10)
+#define AY_EFINE	(11)
+#define AY_ECOARSE	(12)
+#define AY_ESHAPE	(13)
+
+#define AY_PORTA	(14)
+#define AY_PORTB	(15)
+
+
+static struct AY8910 AYPSG[MAX_8910];		/* array of PSG's */
+
+
+
+static void _AYWriteReg(int n, int r, int v)
+{
+	struct AY8910 *PSG = &AYPSG[n];
+	int old;
+
+
+	PSG->Regs[r] = v;
+
+	/* A note about the period of tones, noise and envelope: for speed reasons,*/
+	/* we count down from the period to 0, but careful studies of the chip     */
+	/* output prove that it instead counts up from 0 until the counter becomes */
+	/* greater or equal to the period. This is an important difference when the*/
+	/* program is rapidly changing the period to modulate the sound.           */
+	/* To compensate for the difference, when the period is changed we adjust  */
+	/* our internal counter.                                                   */
+	/* Also, note that period = 0 is the same as period = 1. This is mentioned */
+	/* in the YM2203 data sheets. However, this does NOT apply to the Envelope */
+	/* period. In that case, period = 0 is half as period = 1. */
+	switch( r )
+	{
+	case AY_AFINE:
+	case AY_ACOARSE:
+		PSG->Regs[AY_ACOARSE] &= 0x0f;
+		old = PSG->PeriodA;
+		PSG->PeriodA = (PSG->Regs[AY_AFINE] + 256 * PSG->Regs[AY_ACOARSE]) * PSG->UpdateStep;
+		if (PSG->PeriodA == 0) PSG->PeriodA = PSG->UpdateStep;
+		PSG->CountA += PSG->PeriodA - old;
+		if (PSG->CountA <= 0) PSG->CountA = 1;
+		break;
+	case AY_BFINE:
+	case AY_BCOARSE:
+		PSG->Regs[AY_BCOARSE] &= 0x0f;
+		old = PSG->PeriodB;
+		PSG->PeriodB = (PSG->Regs[AY_BFINE] + 256 * PSG->Regs[AY_BCOARSE]) * PSG->UpdateStep;
+		if (PSG->PeriodB == 0) PSG->PeriodB = PSG->UpdateStep;
+		PSG->CountB += PSG->PeriodB - old;
+		if (PSG->CountB <= 0) PSG->CountB = 1;
+		break;
+	case AY_CFINE:
+	case AY_CCOARSE:
+		PSG->Regs[AY_CCOARSE] &= 0x0f;
+		old = PSG->PeriodC;
+		PSG->PeriodC = (PSG->Regs[AY_CFINE] + 256 * PSG->Regs[AY_CCOARSE]) * PSG->UpdateStep;
+		if (PSG->PeriodC == 0) PSG->PeriodC = PSG->UpdateStep;
+		PSG->CountC += PSG->PeriodC - old;
+		if (PSG->CountC <= 0) PSG->CountC = 1;
+		break;
+	case AY_NOISEPER:
+		PSG->Regs[AY_NOISEPER] &= 0x1f;
+		old = PSG->PeriodN;
+		PSG->PeriodN = PSG->Regs[AY_NOISEPER] * PSG->UpdateStep;
+		if (PSG->PeriodN == 0) PSG->PeriodN = PSG->UpdateStep;
+		PSG->CountN += PSG->PeriodN - old;
+		if (PSG->CountN <= 0) PSG->CountN = 1;
+		break;
+	case AY_ENABLE:
+		if ((PSG->lastEnable == -1) ||
+		    ((PSG->lastEnable & 0x40) != (PSG->Regs[AY_ENABLE] & 0x40)))
+		{
+			/* write out 0xff if port set to input */
+			if (PSG->PortAwrite)
+				(*PSG->PortAwrite)(0, (PSG->Regs[AY_ENABLE] & 0x40) ? PSG->Regs[AY_PORTA] : 0xff);
+		}
+
+		if ((PSG->lastEnable == -1) ||
+		    ((PSG->lastEnable & 0x80) != (PSG->Regs[AY_ENABLE] & 0x80)))
+		{
+			/* write out 0xff if port set to input */
+			if (PSG->PortBwrite)
+				(*PSG->PortBwrite)(0, (PSG->Regs[AY_ENABLE] & 0x80) ? PSG->Regs[AY_PORTB] : 0xff);
+		}
+
+		PSG->lastEnable = PSG->Regs[AY_ENABLE];
+		break;
+	case AY_AVOL:
+		PSG->Regs[AY_AVOL] &= 0x1f;
+		PSG->EnvelopeA = PSG->Regs[AY_AVOL] & 0x10;
+		PSG->VolA = PSG->EnvelopeA ? PSG->VolE : PSG->VolTable[PSG->Regs[AY_AVOL] ? PSG->Regs[AY_AVOL]*2+1 : 0];
+		break;
+	case AY_BVOL:
+		PSG->Regs[AY_BVOL] &= 0x1f;
+		PSG->EnvelopeB = PSG->Regs[AY_BVOL] & 0x10;
+		PSG->VolB = PSG->EnvelopeB ? PSG->VolE : PSG->VolTable[PSG->Regs[AY_BVOL] ? PSG->Regs[AY_BVOL]*2+1 : 0];
+		break;
+	case AY_CVOL:
+		PSG->Regs[AY_CVOL] &= 0x1f;
+		PSG->EnvelopeC = PSG->Regs[AY_CVOL] & 0x10;
+		PSG->VolC = PSG->EnvelopeC ? PSG->VolE : PSG->VolTable[PSG->Regs[AY_CVOL] ? PSG->Regs[AY_CVOL]*2+1 : 0];
+		break;
+	case AY_EFINE:
+	case AY_ECOARSE:
+		old = PSG->PeriodE;
+		PSG->PeriodE = ((PSG->Regs[AY_EFINE] + 256 * PSG->Regs[AY_ECOARSE])) * PSG->UpdateStep;
+		if (PSG->PeriodE == 0) PSG->PeriodE = PSG->UpdateStep / 2;
+		PSG->CountE += PSG->PeriodE - old;
+		if (PSG->CountE <= 0) PSG->CountE = 1;
+		break;
+	case AY_ESHAPE:
+		/* envelope shapes:
+		C AtAlH
+		0 0 x x  \___
+
+		0 1 x x  /___
+
+		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  /___
+
+		The envelope counter on the AY-3-8910 has 16 steps. On the YM2149 it
+		has twice the steps, happening twice as fast. Since the end result is
+		just a smoother curve, we always use the YM2149 behaviour.
+		*/
+		PSG->Regs[AY_ESHAPE] &= 0x0f;
+		PSG->Attack = (PSG->Regs[AY_ESHAPE] & 0x04) ? 0x1f : 0x00;
+		if ((PSG->Regs[AY_ESHAPE] & 0x08) == 0)
+		{
+			/* if Continue = 0, map the shape to the equivalent one which has Continue = 1 */
+			PSG->Hold = 1;
+			PSG->Alternate = PSG->Attack;
+		}
+		else
+		{
+			PSG->Hold = PSG->Regs[AY_ESHAPE] & 0x01;
+			PSG->Alternate = PSG->Regs[AY_ESHAPE] & 0x02;
+		}
+		PSG->CountE = PSG->PeriodE;
+		PSG->CountEnv = 0x1f;
+		PSG->Holding = 0;
+		PSG->VolE = PSG->VolTable[PSG->CountEnv ^ PSG->Attack];
+		if (PSG->EnvelopeA) PSG->VolA = PSG->VolE;
+		if (PSG->EnvelopeB) PSG->VolB = PSG->VolE;
+		if (PSG->EnvelopeC) PSG->VolC = PSG->VolE;
+		break;
+	case AY_PORTA:
+		if (PSG->Regs[AY_ENABLE] & 0x40)
+		{
+			if (PSG->PortAwrite)
+				(*PSG->PortAwrite)(0, PSG->Regs[AY_PORTA]);
+			else
+				logerror("PC %04x: warning - write %02x to 8910 #%d Port A\n",activecpu_get_pc(),PSG->Regs[AY_PORTA],n);
+		}
+		else
+		{
+			logerror("warning: write to 8910 #%d Port A set as input - ignored\n",n);
+		}
+		break;
+	case AY_PORTB:
+		if (PSG->Regs[AY_ENABLE] & 0x80)
+		{
+			if (PSG->PortBwrite)
+				(*PSG->PortBwrite)(0, PSG->Regs[AY_PORTB]);
+			else
+				logerror("PC %04x: warning - write %02x to 8910 #%d Port B\n",activecpu_get_pc(),PSG->Regs[AY_PORTB],n);
+		}
+		else
+		{
+			logerror("warning: write to 8910 #%d Port B set as input - ignored\n",n);
+		}
+		break;
+	}
+}
+
+
+/* write a register on AY8910 chip number 'n' */
+static void AYWriteReg(int chip, int r, int v)
+{
+	struct AY8910 *PSG = &AYPSG[chip];
+
+
+	if (r > 15) return;
+	if (r < 14)
+	{
+		if (r == AY_ESHAPE || PSG->Regs[r] != v)
+		{
+			/* update the output buffer before changing the register */
+			YM2608UpdateRequest(chip);
+		}
+	}
+
+	_AYWriteReg(chip,r,v);
+}
+
+
+
+static unsigned char AYReadReg(int n, int r)
+{
+	struct AY8910 *PSG = &AYPSG[n];
+
+
+	if (r > 15) return 0;
+
+	switch (r)
+	{
+	case AY_PORTA:
+		if ((PSG->Regs[AY_ENABLE] & 0x40) != 0)
+			logerror("warning: read from 8910 #%d Port A set as output\n",n);
+		else if (PSG->PortAread) PSG->Regs[AY_PORTA] = (*PSG->PortAread)(0);
+		else logerror("PC %04x: warning - read 8910 #%d Port A\n",activecpu_get_pc(),n);
+		break;
+	case AY_PORTB:
+		if ((PSG->Regs[AY_ENABLE] & 0x80) != 0)
+			logerror("warning: read from 8910 #%d Port B set as output\n",n);
+		else if (PSG->PortBread) PSG->Regs[AY_PORTB] = (*PSG->PortBread)(0);
+		else logerror("PC %04x: warning - read 8910 #%d Port B\n",activecpu_get_pc(),n);
+		break;
+	}
+	return PSG->Regs[r];
+}
+
+
+void AY8910Write(int chip,int a,int data)
+{
+	struct AY8910 *PSG = &AYPSG[chip];
+
+	if (a & 1)
+	{	/* Data port */
+		AYWriteReg(chip,PSG->register_latch,data);
+	}
+	else
+	{	/* Register port */
+		PSG->register_latch = data & 0x0f;
+	}
+}
+
+int AY8910Read(int chip)
+{
+	struct AY8910 *PSG = &AYPSG[chip];
+
+	return AYReadReg(chip,PSG->register_latch);
+}
+
+
+/* AY8910 interface */
+
+void AY8910Update(int chip,INT16 **buffer,int length)
+{
+	struct AY8910 *PSG = &AYPSG[chip];
+	INT16 *buf1,*buf2,*buf3;
+	int outn;
+
+	buf1 = buffer[0];
+	buf2 = buffer[1];
+	buf3 = buffer[2];
+
+
+	/* The 8910 has three outputs, each output is the mix of one of the three */
+	/* tone generators and of the (single) noise generator. The two are mixed */
+	/* BEFORE going into the DAC. The formula to mix each channel is: */
+	/* (ToneOn | ToneDisable) & (NoiseOn | NoiseDisable). */
+	/* Note that this means that if both tone and noise are disabled, the output */
+	/* is 1, not 0, and can be modulated changing the volume. */
+
+
+	/* If the channels are disabled, set their output to 1, and increase the */
+	/* counter, if necessary, so they will not be inverted during this update. */
+	/* Setting the output to 1 is necessary because a disabled channel is locked */
+	/* into the ON state (see above); and it has no effect if the volume is 0. */
+	/* If the volume is 0, increase the counter, but don't touch the output. */
+	if (PSG->Regs[AY_ENABLE] & 0x01)
+	{
+		if (PSG->CountA <= length*STEP) PSG->CountA += length*STEP;
+		PSG->OutputA = 1;
+	}
+	else if (PSG->Regs[AY_AVOL] == 0)
+	{
+		/* note that I do count += length, NOT count = length + 1. You might think */
+		/* it's the same since the volume is 0, but doing the latter could cause */
+		/* interferencies when the program is rapidly modulating the volume. */
+		if (PSG->CountA <= length*STEP) PSG->CountA += length*STEP;
+	}
+	if (PSG->Regs[AY_ENABLE] & 0x02)
+	{
+		if (PSG->CountB <= length*STEP) PSG->CountB += length*STEP;
+		PSG->OutputB = 1;
+	}
+	else if (PSG->Regs[AY_BVOL] == 0)
+	{
+		if (PSG->CountB <= length*STEP) PSG->CountB += length*STEP;
+	}
+	if (PSG->Regs[AY_ENABLE] & 0x04)
+	{
+		if (PSG->CountC <= length*STEP) PSG->CountC += length*STEP;
+		PSG->OutputC = 1;
+	}
+	else if (PSG->Regs[AY_CVOL] == 0)
+	{
+		if (PSG->CountC <= length*STEP) PSG->CountC += length*STEP;
+	}
+
+	/* for the noise channel we must not touch OutputN - it's also not necessary */
+	/* since we use outn. */
+	if ((PSG->Regs[AY_ENABLE] & 0x38) == 0x38)	/* all off */
+		if (PSG->CountN <= length*STEP) PSG->CountN += length*STEP;
+
+	outn = (PSG->OutputN | PSG->Regs[AY_ENABLE]);
+
+
+	/* buffering loop */
+	while (length)
+	{
+		int vola,volb,volc;
+		int left;
+
+
+		/* vola, volb and volc keep track of how long each square wave stays */
+		/* in the 1 position during the sample period. */
+		vola = volb = volc = 0;
+
+		left = STEP;
+		do
+		{
+			int nextevent;
+
+
+			if (PSG->CountN < left) nextevent = PSG->CountN;
+			else nextevent = left;
+
+			if (outn & 0x08)
+			{
+				if (PSG->OutputA) vola += PSG->CountA;
+				PSG->CountA -= nextevent;
+				/* PeriodA is the half period of the square wave. Here, in each */
+				/* loop I add PeriodA twice, so that at the end of the loop the */
+				/* square wave is in the same status (0 or 1) it was at the start. */
+				/* vola is also incremented by PeriodA, since the wave has been 1 */
+				/* exactly half of the time, regardless of the initial position. */
+				/* If we exit the loop in the middle, OutputA has to be inverted */
+				/* and vola incremented only if the exit status of the square */
+				/* wave is 1. */
+				while (PSG->CountA <= 0)
+				{
+					PSG->CountA += PSG->PeriodA;
+					if (PSG->CountA > 0)
+					{
+						PSG->OutputA ^= 1;
+						if (PSG->OutputA) vola += PSG->PeriodA;
+						break;
+					}
+					PSG->CountA += PSG->PeriodA;
+					vola += PSG->PeriodA;
+				}
+				if (PSG->OutputA) vola -= PSG->CountA;
+			}
+			else
+			{
+				PSG->CountA -= nextevent;
+				while (PSG->CountA <= 0)
+				{
+					PSG->CountA += PSG->PeriodA;
+					if (PSG->CountA > 0)
+					{
+						PSG->OutputA ^= 1;
+						break;
+					}
+					PSG->CountA += PSG->PeriodA;
+				}
+			}
+
+			if (outn & 0x10)
+			{
+				if (PSG->OutputB) volb += PSG->CountB;
+				PSG->CountB -= nextevent;
+				while (PSG->CountB <= 0)
+				{
+					PSG->CountB += PSG->PeriodB;
+					if (PSG->CountB > 0)
+					{
+						PSG->OutputB ^= 1;
+						if (PSG->OutputB) volb += PSG->PeriodB;
+						break;
+					}
+					PSG->CountB += PSG->PeriodB;
+					volb += PSG->PeriodB;
+				}
+				if (PSG->OutputB) volb -= PSG->CountB;
+			}
+			else
+			{
+				PSG->CountB -= nextevent;
+				while (PSG->CountB <= 0)
+				{
+					PSG->CountB += PSG->PeriodB;
+					if (PSG->CountB > 0)
+					{
+						PSG->OutputB ^= 1;
+						break;
+					}
+					PSG->CountB += PSG->PeriodB;
+				}
+			}
+
+			if (outn & 0x20)
+			{
+				if (PSG->OutputC) volc += PSG->CountC;
+				PSG->CountC -= nextevent;
+				while (PSG->CountC <= 0)
+				{
+					PSG->CountC += PSG->PeriodC;
+					if (PSG->CountC > 0)
+					{
+						PSG->OutputC ^= 1;
+						if (PSG->OutputC) volc += PSG->PeriodC;
+						break;
+					}
+					PSG->CountC += PSG->PeriodC;
+					volc += PSG->PeriodC;
+				}
+				if (PSG->OutputC) volc -= PSG->CountC;
+			}
+			else
+			{
+				PSG->CountC -= nextevent;
+				while (PSG->CountC <= 0)
+				{
+					PSG->CountC += PSG->PeriodC;
+					if (PSG->CountC > 0)
+					{
+						PSG->OutputC ^= 1;
+						break;
+					}
+					PSG->CountC += PSG->PeriodC;
+				}
+			}
+
+			PSG->CountN -= nextevent;
+			if (PSG->CountN <= 0)
+			{
+				/* Is noise output going to change? */
+				if ((PSG->RNG + 1) & 2)	/* (bit0^bit1)? */
+				{
+					PSG->OutputN = ~PSG->OutputN;
+					outn = (PSG->OutputN | PSG->Regs[AY_ENABLE]);
+				}
+
+				/* The Random Number Generator of the 8910 is a 17-bit shift */
+				/* register. The input to the shift register is bit0 XOR bit2 */
+				/* (bit0 is the output). */
+
+				/* The following is a fast way to compute bit 17 = bit0^bit2. */
+				/* Instead of doing all the logic operations, we only check */
+				/* bit 0, relying on the fact that after two shifts of the */
+				/* register, what now is bit 2 will become bit 0, and will */
+				/* invert, if necessary, bit 16, which previously was bit 18. */
+				if (PSG->RNG & 1) PSG->RNG ^= 0x28000;
+				PSG->RNG >>= 1;
+				PSG->CountN += PSG->PeriodN;
+			}
+
+			left -= nextevent;
+		} while (left > 0);
+
+		/* update envelope */
+		if (PSG->Holding == 0)
+		{
+			PSG->CountE -= STEP;
+			if (PSG->CountE <= 0)
+			{
+				do
+				{
+					PSG->CountEnv--;
+					PSG->CountE += PSG->PeriodE;
+				} while (PSG->CountE <= 0);
+
+				/* check envelope current position */
+				if (PSG->CountEnv < 0)
+				{
+					if (PSG->Hold)
+					{
+						if (PSG->Alternate)
+							PSG->Attack ^= 0x1f;
+						PSG->Holding = 1;
+						PSG->CountEnv = 0;
+					}
+					else
+					{
+						/* if CountEnv has looped an odd number of times (usually 1), */
+						/* invert the output. */
+						if (PSG->Alternate && (PSG->CountEnv & 0x20))
+ 							PSG->Attack ^= 0x1f;
+
+						PSG->CountEnv &= 0x1f;
+					}
+				}
+
+				PSG->VolE = PSG->VolTable[PSG->CountEnv ^ PSG->Attack];
+				/* reload volume */
+				if (PSG->EnvelopeA) PSG->VolA = PSG->VolE;
+				if (PSG->EnvelopeB) PSG->VolB = PSG->VolE;
+				if (PSG->EnvelopeC) PSG->VolC = PSG->VolE;
+			}
+		}
+
+		*(buf1++) = (vola * PSG->VolA) / STEP;
+		*(buf2++) = (volb * PSG->VolB) / STEP;
+		*(buf3++) = (volc * PSG->VolC) / STEP;
+
+		length--;
+	}
+}
+
+
+void AY8910_set_clock(int chip,int clock)
+{
+	struct AY8910 *PSG = &AYPSG[chip];
+
+	/* the step clock for the tone and noise generators is the chip clock    */
+	/* divided by 8; for the envelope generator of the AY-3-8910, it is half */
+	/* that much (clock/16), but the envelope of the YM2149 goes twice as    */
+	/* fast, therefore again clock/8.                                        */
+	/* Here we calculate the number of steps which happen during one sample  */
+	/* at the given sample rate. No. of events = sample rate / (clock/8).    */
+	/* STEP is a multiplier used to turn the fraction into a fixed point     */
+	/* number.                                                               */
+	PSG->UpdateStep = ((double)STEP * PSG->SampleRate * 8) / clock;
+}
+
+
+static void build_mixer_table(int chip)
+{
+	struct AY8910 *PSG = &AYPSG[chip];
+	int i;
+	double out;
+
+
+	/* calculate the volume->voltage conversion table */
+	/* The AY-3-8910 has 16 levels, in a logarithmic scale (3dB per step) */
+	/* The YM2149 still has 16 levels for the tone generators, but 32 for */
+	/* the envelope generator (1.5dB per step). */
+	out = MAX_OUTPUT;
+	for (i = 31;i > 0;i--)
+	{
+		PSG->VolTable[i] = out + 0.5;	/* round to nearest */
+
+		out /= 1.188502227;	/* = 10 ^ (1.5/20) = 1.5dB */
+	}
+	PSG->VolTable[0] = 0;
+}
+
+
+
+void AY8910_reset(int chip)
+{
+	int i;
+	struct AY8910 *PSG = &AYPSG[chip];
+
+	PSG->register_latch = 0;
+	PSG->RNG = 1;
+	PSG->OutputA = 0;
+	PSG->OutputB = 0;
+	PSG->OutputC = 0;
+	PSG->OutputN = 0xff;
+	PSG->lastEnable = -1;	/* force a write */
+	for (i = 0;i < AY_PORTA;i++)
+		_AYWriteReg(chip,i,0);	/* AYWriteReg() uses the timer system; we cannot */
+								/* call it at this time because the timer system */
+								/* has not been initialized. */
+}
+
+void AY8910_sh_reset(void)
+{
+	int i;
+
+	for (i = 0;i < num + ym_num;i++)
+		AY8910_reset(i);
+}
+
+static int AY8910_init(int chip,
+		int clock,int sample_rate,
+		mem_read_handler portAread,mem_read_handler portBread,
+		mem_write_handler portAwrite,mem_write_handler portBwrite)
+{
+	struct AY8910 *PSG = &AYPSG[chip];
+
+	memset(PSG,0,sizeof(struct AY8910));
+	PSG->SampleRate = sample_rate;
+	PSG->PortAread = portAread;
+	PSG->PortBread = portBread;
+	PSG->PortAwrite = portAwrite;
+	PSG->PortBwrite = portBwrite;
+
+	AY8910_set_clock(chip,clock);
+
+	return 0;
+}
+
+
+int AY8910_sh_start(const struct MachineSound *msound, int sample_rate)
+{
+	int chip;
+	const struct AY8910interface *intf = msound->sound_interface;
+
+	num = intf->num;
+
+	for (chip = 0;chip < num;chip++)
+	{
+		if (AY8910_init(chip+ym_num,intf->baseclock,
+				sample_rate,
+				intf->portAread[chip],intf->portBread[chip],
+				intf->portAwrite[chip],intf->portBwrite[chip]) != 0)
+			return 1;
+		build_mixer_table(chip+ym_num);
+	}
+	return 0;
+}
+
+void AY8910_sh_stop(void)
+{
+	num = 0;
+}
+
+int AY8910_sh_start_ym(const struct MachineSound *msound, int sample_rate)
+{
+	int chip;
+	const struct AY8910interface *intf = msound->sound_interface;
+
+	ym_num = intf->num;
+	ay8910_index_ym = num;
+
+	for (chip = 0;chip < ym_num;chip++)
+	{
+		if (AY8910_init(chip+num,intf->baseclock,
+				sample_rate,
+				intf->portAread[chip],intf->portBread[chip],
+				intf->portAwrite[chip],intf->portBwrite[chip]) != 0)
+			return 1;
+		build_mixer_table(chip+num);
+	}
+	return 0;
+}
+
+void AY8910_sh_stop_ym(void)
+{
+	ym_num = 0;
+}
+
diff --git a/qemu/hw/ay8910.h b/qemu/hw/ay8910.h
new file mode 100644
index 0000000..4e96b34
--- /dev/null
+++ b/qemu/hw/ay8910.h
@@ -0,0 +1,41 @@ 
+#ifndef AY8910_H
+#define AY8910_H
+
+#include "fm_def.h"
+
+#define MAX_8910 5
+#define ALL_8910_CHANNELS -1
+
+struct AY8910interface
+{
+	int num;	/* total number of 8910 in the machine */
+	int baseclock;
+	mem_read_handler portAread[MAX_8910];
+	mem_read_handler portBread[MAX_8910];
+	mem_write_handler portAwrite[MAX_8910];
+	mem_write_handler portBwrite[MAX_8910];
+	void (*handler[MAX_8910])(int irq);	/* IRQ handler for the YM2203 */
+};
+
+void AY8910_reset(int chip);
+
+void AY8910Update(int chip,INT16 **buffer,int length);
+void AY8910_set_clock(int chip,int _clock);
+
+void AY8910Write(int chip,int a,int data);
+int AY8910Read(int chip);
+
+int AY8910_sh_start(const struct MachineSound *msound, int sample_rate);
+void AY8910_sh_stop(void);
+void AY8910_sh_reset(void);
+
+/*********** An interface for SSG of YM2203 ***********/
+
+/* When both of AY8910 and YM2203 or YM2608 or YM2610 are used.      */
+/* It must be called AY8910_sh_start () before AY8910_sh_start_ym()  */
+
+extern int ay8910_index_ym;
+
+void AY8910_sh_stop_ym(void);
+int AY8910_sh_start_ym(const struct MachineSound *msound, int sample_rate);
+#endif