
                     Multiple-PSG Emulation (psg.c, psg.h) 
                     -------------------------------------
	Software implementation of AY-3-8910 Programmable sound generator.
	
Table of Contents
-----------------
	I. License
	II. Introduction
	III. Reference
	IV. Bugs, Limitations, Caveats
	V. Contacting Me
	VI. Release History
	
I. License
----------

	Based on: Sound.c, from Marat Fayzullin's fMSX distribution, 
	original source (C) Ville Hallik (ville@physic.ut.ee) 1996
       
	SCC emulation removed.  Made modular and capable of multiple PSG
	emulation.
       

	Modifications (C) 1996 Michael Cuddy, Fen's Ende Software.
	http://www.fensende.com/Users/mcuddy
       
	This source may be redistributed, without charge, as long as this
	document, and the Copyright notices remain with any distributed 
	archive.
	
	If you are using this code in an emulator, please contact me
	for the latest version.  I can be reached on the 'Net at
	mcuddy@FensEnde.com.  My web page is:
	    
	    http://www.fensende.com/Users/mcuddy/
	    
        The GYRUSS emulator web-page is:
	
	    http://www.fensende.com/Users/mcuddy/gyruss/
       
II. Introduction
----------------

	I'm working on emulator for the classic video game Gyruss.  
	Gyruss, along with many other video games of the early to 
	mid 1980's (the golden age of video games, IMHO), used 
	a programmable sound generator (PSG) chip from General 
	Instruments called the AY-3-8910.  The 8910 PSG is capable
	of generating three voices, with limited envelope control
	as well as a random "noise" channel.  The 8910 also has two
	8-bit I/O ports which could be read under program control.
	
	There were two other chips in the family, the AY-3-8911, and 
	AY-3-8912.  Both of these chips are identical to the 8910 
	from the programmers perspective, with the exception that 
	the 8911 only had 1 I/O port and the 8912 had none.
	
	The 8910 (the real one), maintains a set of 15 registers 
	internally.  Programming these registers is done through 
	two or three memory mapped or I/O mapped locations.  The first 
	location (Base+0x00) is a latch into which a register 
	number is written.  The second location (Base+0x01) can then
	be written to update the value of a register.  The third location
	(Base+0x02) can be read to fetch the value of a register.  
	
	Some hardware implementations will map the second two locations 
	onto the same address so that a read or a write to a single
	locations "does the right thing".  
	
	The actual values that should be programmed into these registers
	is beyond the scope of this document.  Datasheets are available
	from Jameco Electronics (which also still stocks this part --
	although the part is out of production: ones that I bought on 
	12/1996 were made in mid 1984 so Jameco may not have them for 
	long.  I have a copy of the datasheet, and I might put it up
	on my web site if my scanner decides to cooperate ;-)
	
	If you are writing an emulator (and you probably are, since this
	code is of limited use to anyone else), you need to study
	the schematic or ROMS of the machine that you are trying to 
	emulate to determine which memory address or I/O port the PSG(s)
	are mapped to.
	
	With that information in hand, read the next section for the
	calls available.
	
	Note that this module does _not_ provide any means for getting 
	the sound out of your computer;  that is up to you.  I have
	used both Varmint's Audio Tools ("VAT", http://www.groundup.com/),
	and the Synthetic Audio Library ("SEAL", http://www.egerter.com/)
	with good success.
	
III. Reference
--------------

	There are only a few functions and macros in the library that 
	an emulation implementor needs to know about to use the PSG
	emulation successfully.
	
	First and foremost, the header file "psg.h" must be included 
	for the macros, types and function definitions needed 
	by the library.
	
	The first function that you will call, at system initialization 
	time is AYInit():
	
	
	    int AYInit(int num, int rate, int bufsiz);
	
	    The parameters are:  
	
		'num'    -- the number of PSG's that you want emulated.  
		
		'rate'   -- the sampling rate at which you will play the 
			generated tones
		'bufsiz' -- the size of the buffer that should be 
			allocated for storage of the generated sample data
			this is usually rate / updates_per_second. Where
			update_per_second is the number  of times per
			second that you plan on calling AYUpdate() (see 
			below).
	

	When you are done using the library, you should call AYShutdown():
	
	    void AYShutdown()
	
	This function releases all storage assocated with the PSG emulation.
	
	You can reset all of the chip's registers (as if the reset pin
	on the chip was pulled low) by calling AYResetChip():
	
	    void AYResetChip(int num);
	    
	    The parameters are:
		
	        'num'    -- the number of the chip to reset. 0 is the first
			    chip and 'num-1' (where num is the number passed
			    int AYInit()) is the last one.
	
	To reset all chips, you just loop from 0 - num-1 chips.
	
       
	To write or read the registers of the PSG chip, you just call
	AYWriteReg() or AYReadReg() respectively:
	
	    void AYWriteReg(int n, int r, int v);
	    byte AYReadReg(int n, int r);
	    
	    The parameters are:
	    
	    	'n' 	-- the number of the PSG to write to / read from.
		'r'	-- the register to write / read
		'v'	-- the value to write.
		
	    AYReadReg() returns the current value of the specified register.
	    AYWriteReg() sets the specified register's value.  Some registers
	    are masked off internally by the chip (for example, the 
	    most-significant byte of the Channel Frequency (reg's 1, 3, 
	    and 5) only have 4 significant bits, if you write a number 
	    greater than 0x0F and attempt to read it back, you will get 
	    the result modulo 0xF).
	    
	The AYReadReg() and AYWriteReg() functions can optionally call 
	"AYPortHandler" functions for reads and writes of the 8910's I/O 
	port registers (numbers 14 and 15).  AYPortHandler functions
	have the following prototype:
	
	
	    byte AYPortHandler(AY8910 *chip, int port, int iswrite, byte val)
	    
	    The parameters passed in are:
	    
	        'chip'    -- A pointer to the internal chip registers; 
			     in general, it's not a good idea to write to
			     any registers except the I/O ports 
			     (chip->Regs[AY_PORTA] or chip->Regs[AY_PORTB];
			     see the psg.h header file)
		'port'	  -- one of AY_PORTA or AY_PORTB (14 or 15)
		'iswrite' -- if non-zero, a request has been made to write
		 	     to this register.
		'val'	  -- on write, this value will be the value written
			     to the port.
       
	User port handler functions are used so that your emulation does 
	not have to test for accesses to the PSG's I/O ports, it can just
	allow the PSG library to call your handler function for those
	ports.
	
 	Port handler functions are installed with the function 
	AYSetPortHandler():
	
	    void AYSetPortHandler(int n, int port, AYPortHandler func);
	
            The parameters are:
	    
	        'n'	  -- the chip number to install a port handler onto.
		'port'    -- the port to handle (AY_PORTA or AY_PORTB)
		'func'    -- A pointer to the handler function to install.
			     This function has a prototype as detailed 
			     above.
			     
			    
    	Once your emulation is configured (chips initialized, port 
	handlers installed, etc). and up and running, you should periodicly
	call AYUpdate() -- this can be done in a timer-interrupt, but it's
	better to set a flag that says an interrupt is needed).
	
	    AYUpdate(void)
	    
    	Once you have called AYUpdate, you can call AYBuffer() to get a 
	pointer to the sound buffer for a given PSG chip:
	
	    SAMPLE *AYBuffer(int n);
	    
	This returns a pointer to UNSIGNED samples. (to have them signed,
	change the definition of the macro AUDIO_CONV() in psg.h).
	
	You will need to retrieve a buffer for each PSG.  Also, the audio
	buffers are not double-buffered, you will have to arrange for 
	that yourself as well.
	
IV. Bugs, Limitations, Caveats
------------------------------

	Low-Frequencies are not handled correctly.  I don't really know 
	why.  When I get some more time, I'll look into it.
	
	Most PSG's were clocked at 1.832 MHz.  If yours was not, change
	the #define of A8910_CLOCK in psg.h 
	
	I need to allow user-specified buffers to be passed in; this will
	avoid a memcpy() from the PSG's buffers into the sample buffers.
	
	Some sound libraries want signed samples, some want unsigned. By
	default, the PSG code generates unsigned samples.  You will 
	have to change the definition of AUDIO_CONV() in psg.h if your 
	audio library wants different.
	
	It might be nice to generate 16-bit samples. but the PSG generates
	such crappy waveforms (yes, the real chip generated crappy 
	waveforms, too) it might not make a difference.
	
V. Contacting Me
----------------

	First of all, I would like to stress that I did not write the 
	engine of this code.  It was stolen, lock, stock, and barrel
	from Marat Fayzullin's fMSX emulation.  The code was originally
	written for that emulator by Ville Hallik (ville@physic.ut.ee).
	
	The code, when I got it, was quick, and portable, but did not 
	directly support the I/O ports on the chip, and also did not
	support multiple chips. I needed FIVE 8910's for my Gyruss
	emulator, so I ripped up the code into the state that you see
	here.
	
	If you are using this code in an emulator, please contact me
	for the latest version.  I can be reached on the 'Net at
	mcuddy@FensEnde.com.  My web page is:
	    
	    http://www.fensende.com/Users/mcuddy/
	    
        The GYRUSS emulator web-page is:
	
	    http://www.fensende.com/Users/mcuddy/gyruss/
	    
        Enjoy.
	
VI. Release History
-------------------

	12/15/1996 -- V1.0 -- First public release
	
	Restructured original code from fMSX.  Made more modular, and 
	capable of supporting multiple-PSGs.
	
-EOF-
