1565 lines
		
	
	
		
			52 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1565 lines
		
	
	
		
			52 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // license:BSD-3-Clause
 | |
| // copyright-holders:Couriersud
 | |
| /*
 | |
|  * Couriersud, July 2014:
 | |
|  *
 | |
|  * This documents recent work on the AY8910. A YM2149 is now on it's way from
 | |
|  * Hong Kong as well.
 | |
|  *
 | |
|  * TODO:
 | |
|  *
 | |
|  * - Create a true sound device nAY8910 driver.
 | |
|  * - implement approach outlined below in this driver.
 | |
|  *
 | |
|  * For years I had a AY8910 in my drawer. Arduinos were around as well.
 | |
|  * Using the approach documented in this blog post
 | |
|  *    http://www.986-studio.com/2014/05/18/another-ay-entry/#more-476
 | |
|  * I measured the output voltages using a Extech 520.
 | |
|  *
 | |
|  * Measurement Setup
 | |
|  *
 | |
|  * Laptop <--> Arduino <---> AY8910
 | |
|  *
 | |
|  * AY8910 Registers:
 | |
|  * 0x07: 3f
 | |
|  * 0x08: RV
 | |
|  * 0x09: RV
 | |
|  * 0x0A: RV
 | |
|  *
 | |
|  * Output was measured on Analog Output B with a resistor RD to
 | |
|  * ground.
 | |
|  *
 | |
|  * Measurement results:
 | |
|  *
 | |
|  * RD      983  9.830k   99.5k  1.001M    open
 | |
|  *
 | |
|  * RV        B       B       B       B       B
 | |
|  *  0   0.0000  0.0000  0.0001  0.0011  0.0616
 | |
|  *  1   0.0106  0.0998  0.6680  1.8150  2.7260
 | |
|  *  2   0.0150  0.1377  0.8320  1.9890  2.8120
 | |
|  *  3   0.0222  0.1960  1.0260  2.1740  2.9000
 | |
|  *  4   0.0320  0.2708  1.2320  2.3360  2.9760
 | |
|  *  5   0.0466  0.3719  1.4530  2.4880  3.0440
 | |
|  *  6   0.0665  0.4938  1.6680  2.6280  3.1130
 | |
|  *  7   0.1039  0.6910  1.9500  2.7900  3.1860
 | |
|  *  8   0.1237  0.7790  2.0500  2.8590  3.2340
 | |
|  *  9   0.1986  1.0660  2.3320  3.0090  3.3090
 | |
|  * 10   0.2803  1.3010  2.5050  3.0850  3.3380
 | |
|  * 11   0.3548  1.4740  2.6170  3.1340  3.3590
 | |
|  * 12   0.4702  1.6870  2.7340  3.1800  3.3730
 | |
|  * 13   0.6030  1.8870  2.8410  3.2300  3.4050
 | |
|  * 14   0.7530  2.0740  2.9280  3.2580  3.4170
 | |
|  * 15   0.9250  2.2510  3.0040  3.2940  3.4380
 | |
|  *
 | |
|  * Using an equivalent model approach with two resistors
 | |
|  *
 | |
|  *      5V
 | |
|  *       |
 | |
|  *       Z
 | |
|  *       Z Resistor Value for RV
 | |
|  *       Z
 | |
|  *       |
 | |
|  *       +---> Output signal
 | |
|  *       |
 | |
|  *       Z
 | |
|  *       Z External RD
 | |
|  *       Z
 | |
|  *       |
 | |
|  *      GND
 | |
|  *
 | |
|  * will NOT work out of the box since RV = RV(RD).
 | |
|  *
 | |
|  * The following approach will be used going forward based on die pictures
 | |
|  * of the AY8910 done by Dr. Stack van Hay:
 | |
|  *
 | |
|  *
 | |
|  *              5V
 | |
|  *             _| D
 | |
|  *          G |      NMOS
 | |
|  *     Vg ---||               Kn depends on volume selected
 | |
|  *            |_  S Vs
 | |
|  *               |
 | |
|  *               |
 | |
|  *               +---> VO Output signal
 | |
|  *               |
 | |
|  *               Z
 | |
|  *               Z External RD
 | |
|  *               Z
 | |
|  *               |
 | |
|  *              GND
 | |
|  *
 | |
|  *  Whilst conducting, the FET operates in saturation mode:
 | |
|  *
 | |
|  *  Id = Kn * (Vgs - Vth)^2
 | |
|  *
 | |
|  *  Using Id = Vs / RD
 | |
|  *
 | |
|  *  Vs = Kn * RD  * (Vg - Vs - Vth)^2
 | |
|  *
 | |
|  *  finally using Vg' = Vg - Vth
 | |
|  *
 | |
|  *  Vs = Vg' + 1 / (2 * Kn * RD) - sqrt((Vg' + 1 / (2 * Kn * RD))^2 - Vg'^2)
 | |
|  *
 | |
|  *  and finally
 | |
|  *
 | |
|  *  VO = Vs
 | |
|  *
 | |
|  *  and this can be used to re-Thenevin to 5V
 | |
|  *
 | |
|  *  RVequiv = RD * ( 5V / VO - 1)
 | |
|  *
 | |
|  *  The RV and Kn parameter are derived using least squares to match
 | |
|  *  calculation results with measurements.
 | |
|  *
 | |
|  *  FIXME:
 | |
|  *  There is voltage of 60 mV measured with the EX520 (Ri ~ 10M). This may
 | |
|  *  be induced by cutoff currents from the 15 FETs.
 | |
|  *
 | |
|  */
 | |
| 
 | |
| 
 | |
| /***************************************************************************
 | |
| 
 | |
|   ay8910.cpp
 | |
| 
 | |
|   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.
 | |
| 
 | |
|   Mostly rewritten by couriersud in 2008
 | |
| 
 | |
|   Public documentation:
 | |
| 
 | |
|   - http://privatfrickler.de/blick-auf-den-chip-soundchip-general-instruments-ay-3-8910/
 | |
|     Die pictures of the AY8910
 | |
| 
 | |
|   - US Patent 4933980
 | |
| 
 | |
|   Games using ADSR: gyruss
 | |
| 
 | |
|   A list with more games using ADSR can be found here:
 | |
|         http://mametesters.org/view.php?id=3043
 | |
| 
 | |
|   TODO:
 | |
|   * Measure volume / envelope parameters for AY8930 expanded mode
 | |
|   * YM2610 & YM2608 will need a separate flag in their config structures
 | |
|     to distinguish between legacy and discrete mode.
 | |
| 
 | |
|   The rewrite also introduces a generic model for the DAC. This model is
 | |
|   not perfect, but allows channel mixing based on a parametrized approach.
 | |
|   This model also allows to factor in different loads on individual channels.
 | |
|   If a better model is developped in the future or better measurements are
 | |
|   available, the driver should be easy to change. The model is described
 | |
|   later.
 | |
| 
 | |
|   In order to not break hundreds of existing drivers by default the flag
 | |
|   AY8910_LEGACY_OUTPUT is used by drivers not changed to take into account the
 | |
|   new model. All outputs are normalized to the old output range (i.e. 0 .. 7ffff).
 | |
|   In the case of channel mixing, output range is 0...3 * 7fff.
 | |
| 
 | |
|   The main difference between the AY-3-8910 and the YM2149 is, that the
 | |
|   AY-3-8910 datasheet mentions, that fixed volume level 0, which is set by
 | |
|   registers 8 to 10 is "channel off". The YM2149 mentions, that the generated
 | |
|   signal has a 2V DC component. This is confirmed by measurements. The approach
 | |
|   taken here is to assume the 2V DC offset for all outputs for the YM2149.
 | |
|   For the AY-3-8910, an offset is used if envelope is active for a channel.
 | |
|   This is backed by oscilloscope pictures from the datasheet. If a fixed volume
 | |
|   is set, i.e. envelope is disabled, the output voltage is set to 0V. Recordings
 | |
|   I found on the web for gyruss indicate, that the AY-3-8910 offset should
 | |
|   be around 0.2V. This will also make sound levels more compatible with
 | |
|   user observations for scramble.
 | |
| 
 | |
|   The Model:
 | |
|                      5V     5V
 | |
|                       |      |
 | |
|                       /      |
 | |
|   Volume Level x >---|       Z
 | |
|                       >      Z Pullup Resistor RU
 | |
|                        |     Z
 | |
|                        Z     |
 | |
|                     Rx Z     |
 | |
|                        Z     |
 | |
|                        |     |
 | |
|                        '-----+-------->  >---+----> Output signal
 | |
|                              |               |
 | |
|                              Z               Z
 | |
|                Pulldown RD   Z               Z Load RL
 | |
|                              Z               Z
 | |
|                              |               |
 | |
|                             GND             GND
 | |
| 
 | |
| Each Volume level x will select a different resistor Rx. Measurements from fpgaarcade.com
 | |
| where used to calibrate channel mixing for the YM2149. This was done using
 | |
| a least square approach using a fixed RL of 1K Ohm.
 | |
| 
 | |
| For the AY measurements cited in e.g. openmsx as "Hacker Kay" for a single
 | |
| channel were taken. These were normalized to 0 ... 65535 and consequently
 | |
| adapted to an offset of 0.2V and a VPP of 1.3V. These measurements are in
 | |
| line e.g. with the formula used by pcmenc for the volume: vol(i) = exp(i/2-7.5).
 | |
| 
 | |
| The following is documentation from the code moved here and amended to reflect
 | |
| the changes done:
 | |
| 
 | |
| Careful studies of the chip output prove that the chip 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. This is worthwhile noting, since the datasheets
 | |
| say, that the chip counts down.
 | |
| 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.
 | |
| 
 | |
| 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.
 | |
| 
 | |
| ****************************************************************************
 | |
| 
 | |
|     The bus control and chip selection signals of the AY PSGs and their
 | |
|     pin-compatible clones such as YM2149 are somewhat unconventional and
 | |
|     redundant, having been designed for compatibility with GI's CP1610
 | |
|     series of microprocessors. Much of the redundancy can be finessed by
 | |
|     tying BC2 to Vcc; AY-3-8913 and AY8930 do this internally.
 | |
| 
 | |
|                             /A9   A8    /CS   BDIR  BC2   BC1
 | |
|                 AY-3-8910   24    25    n/a   27    28    29
 | |
|                 AY-3-8912   n/a   17    n/a   18    19    20
 | |
|                 AY-3-8913   22    23    24    2     n/a   3
 | |
|                             ------------------------------------
 | |
|                 Inactive            NACT      0     0     0
 | |
|                 Latch address       ADAR      0     0     1
 | |
|                 Inactive            IAB       0     1     0
 | |
|                 Read from PSG       DTB       0     1     1
 | |
|                 Latch address       BAR       1     0     0
 | |
|                 Inactive            DW        1     0     1
 | |
|                 Write to PSG        DWS       1     1     0
 | |
|                 Latch address       INTAK     1     1     1
 | |
| 
 | |
| ***************************************************************************/
 | |
| 
 | |
| /**
 | |
| AY-3-8910(A)/8914/8916/8917/8930/YM2149 (others?):
 | |
|                         _______    _______
 | |
|                       _|       \__/       |_
 | |
|    [4] VSS (GND) --  |_|1  *            40|_|  -- VCC (+5v)
 | |
|                       _|                  |_
 | |
|              [5] NC  |_|2               39|_|  <- TEST 1 [1]
 | |
|                       _|                  |_
 | |
| ANALOG CHANNEL B <-  |_|3               38|_|  -> ANALOG CHANNEL C
 | |
|                       _|                  |_
 | |
| ANALOG CHANNEL A <-  |_|4               37|_|  <> DA0
 | |
|                       _|                  |_
 | |
|              [5] NC  |_|5               36|_|  <> DA1
 | |
|                       _|                  |_
 | |
|             IOB7 <>  |_|6               35|_|  <> DA2
 | |
|                       _|                  |_
 | |
|             IOB6 <>  |_|7               34|_|  <> DA3
 | |
|                       _|   /---\          |_
 | |
|             IOB5 <>  |_|8  \-/ |   A    33|_|  <> DA4
 | |
|                       _|   .   .   Y      |_
 | |
|             IOB4 <>  |_|9  |---|   - S  32|_|  <> DA5
 | |
|                       _|   '   '   3 O    |_
 | |
|             IOB3 <>  |_|10   8     - U  31|_|  <> DA6
 | |
|                       _|     3     8 N    |_
 | |
|             IOB2 <>  |_|11   0     9 D  30|_|  <> DA7
 | |
|                       _|     8     1      |_
 | |
|             IOB1 <>  |_|12         0    29|_|  <- BC1
 | |
|                       _|     P            |_
 | |
|             IOB0 <>  |_|13              28|_|  <- BC2
 | |
|                       _|                  |_
 | |
|             IOA7 <>  |_|14              27|_|  <- BDIR
 | |
|                       _|                  |_                     Prelim. DS:   YM2149/8930:
 | |
|             IOA6 <>  |_|15              26|_|  <- TEST 2 [2,3]   CS2           /SEL
 | |
|                       _|                  |_
 | |
|             IOA5 <>  |_|16              25|_|  <- A8 [3]         CS1
 | |
|                       _|                  |_
 | |
|             IOA4 <>  |_|17              24|_|  <- /A9 [3]        /CS0
 | |
|                       _|                  |_
 | |
|             IOA3 <>  |_|18              23|_|  <- /RESET
 | |
|                       _|                  |_
 | |
|             IOA2 <>  |_|19              22|_|  == CLOCK
 | |
|                       _|                  |_
 | |
|             IOA1 <>  |_|20              21|_|  <> IOA0
 | |
|                        |__________________|
 | |
| 
 | |
| [1] Based on the decap, TEST 1 connects to the Envelope Generator and/or the
 | |
|     frequency divider somehow. Is this an input or an output?
 | |
| [2] The TEST 2 input connects to the same selector as A8 and /A9 do on the 8910
 | |
|     and acts as just another active high enable like A8(pin 25).
 | |
|     The preliminary datasheet calls this pin CS2.
 | |
|     On the 8914, it performs the same above function but additionally ?disables?
 | |
|     the DA0-7 bus if pulled low/active. This additional function was removed
 | |
|     on the 8910.
 | |
|     This pin has an internal pullup.
 | |
|     On the AY8930 and YM2149, this pin is /SEL; if low, clock input is halved.
 | |
| [3] These 3 pins are technically enables, and have pullups/pulldowns such that
 | |
|     if the pins are left floating, the chip remains enabled.
 | |
| [4] On the AY-3-8910 the bond wire for the VSS pin goes to the substrate frame,
 | |
|     and then a separate bond wire connects it to a pad between pins 21 and 22.
 | |
| [5] These pins lack internal bond wires entirely.
 | |
| 
 | |
| 
 | |
| AY-3-8912(A):
 | |
|                         _______    _______
 | |
|                       _|       \__/       |_
 | |
| ANALOG CHANNEL C <-  |_|1  *            28|_|  <> DA0
 | |
|                       _|                  |_
 | |
|           TEST 1 ->  |_|2               27|_|  <> DA1
 | |
|                       _|                  |_
 | |
|        VCC (+5V) --  |_|3               26|_|  <> DA2
 | |
|                       _|                  |_
 | |
| ANALOG CHANNEL B <-  |_|4               25|_|  <> DA3
 | |
|                       _|    /---\         |_
 | |
| ANALOG CHANNEL A <-  |_|5   \-/ |   A   24|_|  <> DA4
 | |
|                       _|    .   .   Y     |_
 | |
|        VSS (GND) --  |_|6   |---|   - S 23|_|  <> DA5
 | |
|                       _|    '   '   3 O   |_
 | |
|             IOA7 <>  |_|7    T 8    - U 22|_|  <> DA6
 | |
|                       _|     A 3    8 N   |_
 | |
|             IOA6 <>  |_|8    I 1    9 D 21|_|  <> DA7
 | |
|                       _|     W 1    1     |_
 | |
|             IOA5 <>  |_|9    A  C   2   20|_|  <- BC1
 | |
|                       _|     N  D         |_
 | |
|             IOA4 <>  |_|10      A       19|_|  <- BC2
 | |
|                       _|                  |_
 | |
|             IOA3 <>  |_|11              18|_|  <- BDIR
 | |
|                       _|                  |_
 | |
|             IOA2 <>  |_|12              17|_|  <- A8
 | |
|                       _|                  |_
 | |
|             IOA1 <>  |_|13              16|_|  <- /RESET
 | |
|                       _|                  |_
 | |
|             IOA0 <>  |_|14              15|_|  == CLOCK
 | |
|                        |__________________|
 | |
| 
 | |
| 
 | |
| AY-3-8913:
 | |
|                         _______    _______
 | |
|                       _|       \__/       |_
 | |
|    [1] VSS (GND) --  |_|1  *            24|_|  <- /CHIP SELECT [2]
 | |
|                       _|                  |_
 | |
|             BDIR ->  |_|2               23|_|  <- A8
 | |
|                       _|                  |_
 | |
|              BC1 ->  |_|3               22|_|  <- /A9
 | |
|                       _|    /---\         |_
 | |
|              DA7 <>  |_|4   \-/ |   A   21|_|  <- /RESET
 | |
|                       _|    .   .   Y     |_
 | |
|              DA6 <>  |_|5   |---|   -   20|_|  == CLOCK
 | |
|                       _|    '   '   3     |_
 | |
|              DA5 <>  |_|6    T 8    -   19|_|  -- VSS (GND) [1]
 | |
|                       _|     A 3    8     |_
 | |
|              DA4 <>  |_|7    I 3    9   18|_|  -> ANALOG CHANNEL C
 | |
|                       _|     W 2    1     |_
 | |
|              DA3 <>  |_|8    A      3   17|_|  -> ANALOG CHANNEL A
 | |
|                       _|     N C          |_
 | |
|              DA2 <>  |_|9      -        16|_|  NC(?)
 | |
|                       _|       A          |_
 | |
|              DA1 <>  |_|10              15|_|  -> ANALOG CHANNEL B
 | |
|                       _|                  |_
 | |
|              DA0 <>  |_|11              14|_|  ?? TEST IN [3]
 | |
|                       _|                  |_
 | |
|     [4] TEST OUT ??  |_|12              13|_|  -- VCC (+5V)
 | |
|                        |__________________|
 | |
| 
 | |
| [1] Both of these are ground, they are probably connected together internally. Grounding either one should work.
 | |
| [2] This is effectively another enable, much like TEST 2 is on the AY-3-8910 and 8914, but active low
 | |
| [3] This is claimed to be equivalent to TEST 1 on the datasheet
 | |
| [4] This is claimed to be equivalent to TEST 2 on the datasheet
 | |
| 
 | |
| 
 | |
| GI AY-3-8910/A Programmable Sound Generator (PSG): 2 I/O ports
 | |
|   A7 thru A4 enable state for selecting a register can be changed with a
 | |
|     factory mask adjustment but default was 0000 for the "common" part shipped
 | |
|     (probably die "-100").
 | |
|   Pins 24, 25, and 26 are /A9, A8, and TEST2, which are an active low, high
 | |
|     and high chip enable, respectively.
 | |
|   AY-3-8910:  Unused bits in registers have unknown behavior.
 | |
|   AY-3-8910A: Unused bits in registers have unknown behavior.
 | |
|   I/O current source/sink behavior is unknown.
 | |
|   AY-3-8910 die is labeled "90-32033" with a 1979 copyright and a "-100" die
 | |
|     code.
 | |
|   AY-3-8910A die is labeled "90-32128" with a 1983 copyright.
 | |
| GI AY-3-8912/A: 1 I/O port
 | |
|   /A9 pin doesn't exist and is considered pulled low.
 | |
|   TEST2 pin doesn't exist and is considered pulled high.
 | |
|   IOB pins do not exist and have unknown behavior if driven high/low and read
 | |
|     back.
 | |
|   A7 thru A4 enable state for selecting a register can be changed with a
 | |
|     factory mask adjustment but default was 0000 for the "common" part shipped
 | |
|   AY-3-8912:  Unused bits in registers have unknown behavior.
 | |
|   AY-3-8912A: Unused bits in registers have unknown behavior.
 | |
|   I/O current source/sink behavior is unknown.
 | |
|   AY-3-8912 die is unknown.
 | |
|   AY-3-8912A or A/P die is unknown.
 | |
| AY-3-8913: 0 I/O ports
 | |
|   BC2 pin doesn't exist and is considered pulled high.
 | |
|   IOA/B pins do not exist and have unknown behavior if driven high/low and read back.
 | |
|   A7 thru A4 enable state for selecting a register can be changed with a
 | |
|     factory mask adjustment but default was 0000 for the "common" part shipped
 | |
|   AY-3-8913:  Unused bits in registers have unknown behavior.
 | |
|   AY-3-8913 die is unknown.
 | |
| GI AY-3-8914/A: 2 I/O ports
 | |
|   A7 thru A4 enable state for selecting a register can be changed with a
 | |
|     factory mask adjustment but was 0000 for the part shipped with the
 | |
|     Intellivision.
 | |
|   Pins 24, 25, and 26 are /A9, A8, and TEST2, which are an active low, high
 | |
|     and high chip enable, respectively.
 | |
|   TEST2 additionally ?disables? the data bus if pulled low.
 | |
|   The register mapping is different from the AY-3-8910, the AY-3-8914 register
 | |
|     mapping matches the "preliminary" 1978 AY-3-8910 datasheet.
 | |
|   The Envelope/Volume control register is 6 bits wide instead of 5 bits, and
 | |
|     the additional bit combines with the M bit to form a bit pair C0 and C1,
 | |
|     which shift the volume output of the Envelope generator right by 0, 1 or 2
 | |
|     bits on a given channel, or allow the low 4 bits to drive the channel
 | |
|     volume.
 | |
|   AY-3-8914:  Unused bits in registers have unknown behavior.
 | |
|   AY-3-8914A: Unused bits in registers have unknown behavior.
 | |
|   I/O current source/sink behavior is unknown.
 | |
|   AY-3-8914 die is labeled "90-32022" with a 1978 copyright.
 | |
|   AY-3-8914A die is unknown.
 | |
| GI AY-3-8916: 2 I/O ports
 | |
|   A7 thru A4 enable state for selecting a register can be changed with a
 | |
|     factory mask adjustment; its mask is unknown. This chip was shipped
 | |
|     with certain later Intellivision II systems.
 | |
|   Pins 24, 25, and 26 are /A9, /A8(!), and TEST2, which are an active low,
 | |
|     low(!) and high chip enable, respectively.
 | |
|     NOTE: the /A8 enable polarity may be mixed up with AY-3-8917 below.
 | |
|   AY-3-8916: Unused bits in registers have unknown behavior.
 | |
|   I/O current source/sink behavior is unknown.
 | |
|   AY-3-8916 die is unknown.
 | |
| GI AY-3-8917: 2 I/O ports
 | |
|   A7 thru A4 enable state for selecting a register can be changed with a
 | |
|     factory mask adjustment but was 1111 for the part shipped with the
 | |
|     Intellivision ECS module.
 | |
|   Pins 24, 25, and 26 are /A9, A8, and TEST2, which are an active low, high
 | |
|     and high chip enable, respectively.
 | |
|     NOTE: the A8 enable polarity may be mixed up with AY-3-8916 above.
 | |
|   AY-3-8917: Unused bits in registers have unknown behavior.
 | |
|   I/O current source/sink behavior is unknown.
 | |
|   AY-3-8917 die is unknown.
 | |
| Microchip AY8930 Enhanced Programmable Sound Generator (EPSG): 2 I/O ports
 | |
|   BC2 pin exists but is always considered pulled high. The pin might have no
 | |
|     bond wire at all.
 | |
|   Pins 2 and 5 might be additional test pins rather than being NC.
 | |
|   A7 thru A4 enable state for selecting a register are 0000 for all? parts
 | |
|     shipped.
 | |
|   Pins 24 and 25 are /A9, A8 which are an active low and high chip enable.
 | |
|   Pin 26 is /SELECT which if driven low divides the input clock by 2.
 | |
|   Writing 0xAn or 0xBn to register 0x0D turns on extended mode, which enables
 | |
|     an additional 16 registers (banked using 0x0D bit 0), and clears the
 | |
|     contents of all of the registers except the high 3 bits of register 0x0D
 | |
|     (according to the datasheet).
 | |
|   If the AY8930's extended mode is enabled, it gains higher resolution
 | |
|     frequency and volume control, separate volume per-channel, and the duty
 | |
|     cycle can be adjusted for the 3 channels.
 | |
|   If the mode is not enabled, it behaves almost exactly like an AY-3-8910(A?),
 | |
|     barring the BC2 and /SELECT differences.
 | |
|   AY8930: Unused bits in registers have unknown behavior, but the datasheet
 | |
|     explicitly states that unused bits always read as 0.
 | |
|   I/O current source/sink behavior is unknown.
 | |
|   AY8930 die is unknown.
 | |
| Yamaha YM2149 Software-Controlled Sound Generator (SSG): 2 I/O ports
 | |
|   A7 thru A4 enable state for selecting a register are 0000 for all? parts
 | |
|     shipped.
 | |
|   Pins 24 and 25 are /A9, A8 which are an active low and high chip enable.
 | |
|   Pin 26 is /SEL which if driven low divides the input clock by 2.
 | |
|   The YM2149 envelope register has 5 bits of resolution internally, allowing
 | |
|   for smoother volume ramping, though the register for setting its direct
 | |
|   value remains 4 bits wide.
 | |
|   YM2149: Unused bits in registers have unknown behavior.
 | |
|   I/O current source/sink behavior is unknown.
 | |
|   YM2149 die is unknown; only one die revision, 'G', has been observed
 | |
|     from Yamaha chip/datecode silkscreen surface markings.
 | |
| Yamaha YM2203: 2 I/O ports
 | |
|   The pinout of this chip is completely different from the AY-3-8910.
 | |
|   The entire way this chip is accessed is completely different from the usual
 | |
|     AY-3-8910 selection of chips, so there is a /CS and a /RD and a /WR and
 | |
|     an A0 pin; The chip status can be read back by reading the register
 | |
|     select address.
 | |
|   The chip has a 3-channel, 4-op FM synthesis sound core in it, not discussed
 | |
|     in this source file.
 | |
|   The first 16 registers are the same(?) as the YM2149.
 | |
|   YM2203: Unused bits in registers have unknown behavior.
 | |
|   I/O current source/sink behavior is unknown.
 | |
|   YM2203 die is unknown; three die revisions, 'D', 'F' and 'H', have been
 | |
|     observed from Yamaha chip/datecode silkscreen surface markings. It is
 | |
|     unknown what behavioral differences exist between these revisions.
 | |
|     The 'D' revision only appears during the first year of production, 1984, on chips marked 'YM2203B'
 | |
|     The 'F' revision exists from 1984?-1991, chips are marked 'YM2203C'
 | |
|     The 'H' revision exists from 1991 onward, chips are marked 'YM2203C'
 | |
| Yamaha YM3439: limited info: CMOS version of YM2149?
 | |
| Yamaha YMZ284: limited info: 0 I/O port, different clock divider
 | |
|   The chip selection logic is again simplified here: pin 1 is /WR, pin 2 is
 | |
|     /CS and pin 3 is A0.
 | |
|   D0-D7 are conveniently all on one side of the 16-pin package.
 | |
|   Pin 8 is /IC (initial clear), with an internal pullup.
 | |
| Yamaha YMZ294: limited info: 0 I/O port
 | |
|   Pinout is identical to YMZ284 except for two additions: pin 8 selects
 | |
|     between 4MHz (H) and 6MHz (L), while pin 10 is /TEST.
 | |
| OKI M5255, Winbond WF19054, JFC 95101, File KC89C72, Toshiba T7766A : differences to be listed
 | |
| 
 | |
| AY8930 Expanded mode registers :
 | |
|     Bank Register Bits
 | |
|     A    0        xxxx xxxx Channel A Tone period fine tune
 | |
|     A    1        xxxx xxxx Channel A Tone period coarse tune
 | |
|     A    2        xxxx xxxx Channel B Tone period fine tune
 | |
|     A    3        xxxx xxxx Channel B Tone period coarse tune
 | |
|     A    4        xxxx xxxx Channel C Tone period fine tune
 | |
|     A    5        xxxx xxxx Channel C Tone period coarse tune
 | |
|     A    6        xxxx xxxx Noise period
 | |
|     A    7        x--- ---- I/O Port B input(0) / output(1)
 | |
|                   -x-- ---- I/O Port A input(0) / output(1)
 | |
|                   --x- ---- Channel C Noise enable(0) / disable(1)
 | |
|                   ---x ---- Channel B Noise enable(0) / disable(1)
 | |
|                   ---- x--- Channel A Noise enable(0) / disable(1)
 | |
|                   ---- -x-- Channel C Tone enable(0) / disable(1)
 | |
|                   ---- --x- Channel B Tone enable(0) / disable(1)
 | |
|                   ---- ---x Channel A Tone enable(0) / disable(1)
 | |
|     A    8        --x- ---- Channel A Envelope mode
 | |
|                   ---x xxxx Channel A Tone volume
 | |
|     A    9        --x- ---- Channel B Envelope mode
 | |
|                   ---x xxxx Channel B Tone volume
 | |
|     A    A        --x- ---- Channel C Envelope mode
 | |
|                   ---x xxxx Channel C Tone volume
 | |
|     A    B        xxxx xxxx Channel A Envelope period fine tune
 | |
|     A    C        xxxx xxxx Channel A Envelope period coarse tune
 | |
|     A    D        101- ---- 101 = Expanded mode enable, other AY-3-8910A Compatiblity mode
 | |
|                   ---0 ---- 0 for Register Bank A
 | |
|                   ---- xxxx Channel A Envelope Shape/Cycle
 | |
|     A    E        xxxx xxxx 8 bit Parallel I/O on Port A
 | |
|     A    F        xxxx xxxx 8 bit Parallel I/O on Port B
 | |
| 
 | |
|     B    0        xxxx xxxx Channel B Envelope period fine tune
 | |
|     B    1        xxxx xxxx Channel B Envelope period coarse tune
 | |
|     B    2        xxxx xxxx Channel C Envelope period fine tune
 | |
|     B    3        xxxx xxxx Channel C Envelope period coarse tune
 | |
|     B    4        ---- xxxx Channel B Envelope Shape/Cycle
 | |
|     B    5        ---- xxxx Channel C Envelope Shape/Cycle
 | |
|     B    6        ---- xxxx Channel A Duty Cycle
 | |
|     B    7        ---- xxxx Channel B Duty Cycle
 | |
|     B    8        ---- xxxx Channel C Duty Cycle
 | |
|     B    9        xxxx xxxx Noise "And" Mask
 | |
|     B    A        xxxx xxxx Noise "Or" Mask
 | |
|     B    B        Reserved (Read as 0)
 | |
|     B    C        Reserved (Read as 0)
 | |
|     B    D        101- ---- 101 = Expanded mode enable, other AY-3-8910A Compatiblity mode
 | |
|                   ---1 ---- 1 for Register Bank B
 | |
|                   ---- xxxx Channel A Envelope Shape
 | |
|     B    E        Reserved (Read as 0)
 | |
|     B    F        Test (Function unknown)
 | |
| 
 | |
| Decaps:
 | |
| AY-3-8914 - http://siliconpr0n.org/map/gi/ay-3-8914/mz_mit20x/
 | |
| AY-3-8910 - http://privatfrickler.de/blick-auf-den-chip-soundchip-general-instruments-ay-3-8910/
 | |
| AY-3-8910A - https://seanriddledecap.blogspot.com/2017/01/gi-ay-3-8910-ay-3-8910a-gi-8705-cba.html (TODO: update this link when it has its own page at seanriddle.com)
 | |
| 
 | |
| Links:
 | |
| AY-3-8910 'preliminary' datasheet (which actually describes the AY-3-8914) from 1978:
 | |
|   http://spatula-city.org/~im14u2c/intv/gi_micro_programmable_tv_games/page_7_100.png
 | |
|   http://spatula-city.org/~im14u2c/intv/gi_micro_programmable_tv_games/page_7_101.png
 | |
|   http://spatula-city.org/~im14u2c/intv/gi_micro_programmable_tv_games/page_7_102.png
 | |
|   http://spatula-city.org/~im14u2c/intv/gi_micro_programmable_tv_games/page_7_103.png
 | |
|   http://spatula-city.org/~im14u2c/intv/gi_micro_programmable_tv_games/page_7_104.png
 | |
|   http://spatula-city.org/~im14u2c/intv/gi_micro_programmable_tv_games/page_7_105.png
 | |
| AY-3-8910/8912 Feb 1979 manual: https://web.archive.org/web/20140217224114/http://dev-docs.atariforge.org/files/GI_AY-3-8910_Feb-1979.pdf
 | |
| AY-3-8910/8912/8913 post-1983 manual: http://map.grauw.nl/resources/sound/generalinstrument_ay-3-8910.pdf or http://www.ym2149.com/ay8910.pdf
 | |
| AY-8930 datasheet: http://www.ym2149.com/ay8930.pdf
 | |
| YM2149 datasheet: http://www.ym2149.com/ym2149.pdf
 | |
| YM2203 English datasheet: http://www.appleii-box.de/APPLE2/JonasCard/YM2203%20datasheet.pdf
 | |
| YM2203 Japanese datasheet contents, translated: http://www.larwe.com/technical/chip_ym2203.html
 | |
| */
 | |
| 
 | |
| // additional modifications by tildearrow, Eulous, cam900 and Grauw for furnace (particularly AY8930 emulation)
 | |
| 
 | |
| #include "ay8910.h"
 | |
| #include <stdio.h>
 | |
| #include <math.h>
 | |
| #include <string.h>
 | |
| #include <vector>
 | |
| 
 | |
| /*************************************
 | |
|  *
 | |
|  *  constants
 | |
|  *
 | |
|  *************************************/
 | |
| 
 | |
| #define ENABLE_REGISTER_TEST        (0)     /* Enable preprogrammed registers */
 | |
| #define LOG_IGNORED_WRITES          (0)
 | |
| 
 | |
| static constexpr float MAX_OUTPUT = 1.0;
 | |
| 
 | |
| /*************************************
 | |
|  *
 | |
|  *  Type definitions
 | |
|  *
 | |
|  *************************************/
 | |
| 
 | |
| 
 | |
| /*************************************
 | |
|  *
 | |
|  *  Static
 | |
|  *
 | |
|  *************************************/
 | |
| 
 | |
| // duty cycle used for AY8930 expanded mode
 | |
| static const unsigned int duty_cycle[9] =
 | |
| {
 | |
| 	0x80000000, // 3.125 %
 | |
| 	0xc0000000, // 6.25 %
 | |
| 	0xf0000000, // 12.50 %
 | |
| 	0xff000000, // 25.00 %
 | |
| 	0xffff0000, // 50.00 %
 | |
| 	0xffffff00, // 75.00 %
 | |
| 	0xfffffff0, // 87.50 %
 | |
| 	0xfffffffc, // 93.75 %
 | |
| 	0xfffffffe  // 96.875 %
 | |
| };
 | |
| 
 | |
| static const ay8910_device::ay_ym_param ym2149_param =
 | |
| {
 | |
| 	630, 801,
 | |
| 	16,
 | |
| 	{ 73770, 37586, 27458, 21451, 15864, 12371, 8922,  6796,
 | |
| 		4763,  3521,  2403,  1737,  1123,   762,  438,   251 },
 | |
| };
 | |
| 
 | |
| static const ay8910_device::ay_ym_param ym2149_param_env =
 | |
| {
 | |
| 	630, 801,
 | |
| 	32,
 | |
| 	{ 103350, 73770, 52657, 37586, 32125, 27458, 24269, 21451,
 | |
| 		18447, 15864, 14009, 12371, 10506,  8922,  7787,  6796,
 | |
| 		5689,  4763,  4095,  3521,  2909,  2403,  2043,  1737,
 | |
| 		1397,  1123,   925,   762,   578,   438,   332,   251 },
 | |
| };
 | |
| 
 | |
| #if 0
 | |
| /* RL = 1000, Hacker Kay normalized, 2.1V to 3.2V */
 | |
| static const ay8910_device::ay_ym_param ay8910_param =
 | |
| {
 | |
| 	664, 913,
 | |
| 	16,
 | |
| 	{ 85785, 34227, 26986, 20398, 14886, 10588,  7810,  4856,
 | |
| 		4120,  2512,  1737,  1335,  1005,   747,   586,    451 },
 | |
| };
 | |
| 
 | |
| /*
 | |
|  * RL = 3000, Hacker Kay normalized pattern, 1.5V to 2.8V
 | |
|  * These values correspond with guesses based on Gyruss schematics
 | |
|  * They work well with scramble as well.
 | |
|  */
 | |
| static const ay8910_device::ay_ym_param ay8910_param =
 | |
| {
 | |
| 	930, 454,
 | |
| 	16,
 | |
| 	{ 85066, 34179, 27027, 20603, 15046, 10724, 7922, 4935,
 | |
| 		4189,  2557,  1772,  1363,  1028,  766,   602,  464 },
 | |
| };
 | |
| 
 | |
| /*
 | |
|  * RL = 1000, Hacker Kay normalized pattern, 0.75V to 2.05V
 | |
|  * These values correspond with guesses based on Gyruss schematics
 | |
|  * They work well with scramble as well.
 | |
|  */
 | |
| static const ay8910_device::ay_ym_param ay8910_param =
 | |
| {
 | |
| 	1371, 313,
 | |
| 	16,
 | |
| 	{ 93399, 33289, 25808, 19285, 13940, 9846,  7237,  4493,
 | |
| 		3814,  2337,  1629,  1263,   962,  727,   580,   458 },
 | |
| };
 | |
| 
 | |
| /*
 | |
|  * RL = 1000, Hacker Kay normalized pattern, 0.2V to 1.5V
 | |
|  */
 | |
| static const ay8910_device::ay_ym_param ay8910_param =
 | |
| {
 | |
| 	5806, 300,
 | |
| 	16,
 | |
| 	{ 118996, 42698, 33105, 24770, 17925, 12678,  9331,  5807,
 | |
| 		4936,  3038,  2129,  1658,  1271,   969,   781,   623 }
 | |
| };
 | |
| #endif
 | |
| 
 | |
| /*
 | |
|  * RL = 2000, Based on Matthew Westcott's measurements from Dec 2001.
 | |
|  * -------------------------------------------------------------------
 | |
|  *
 | |
|  * http://groups.google.com/group/comp.sys.sinclair/browse_thread/thread/fb3091da4c4caf26/d5959a800cda0b5e?lnk=gst&q=Matthew+Westcott#d5959a800cda0b5e
 | |
|  * After what Russell mentioned a couple of weeks back about the lack of
 | |
|  * publicised measurements of AY chip volumes - I've finally got round to
 | |
|  * making these readings, and I'm placing them in the public domain - so
 | |
|  * anyone's welcome to use them in emulators or anything else.
 | |
| 
 | |
|  * To make the readings, I set up the chip to produce a constant voltage on
 | |
|  * channel C (setting bits 2 and 5 of register 6), and varied the amplitude
 | |
|  * (the low 4 bits of register 10). The voltages were measured between the
 | |
|  * channel C output (pin 1) and ground (pin 6).
 | |
|  *
 | |
|  * Level  Voltage
 | |
|  *  0     1.147
 | |
|  *  1     1.162
 | |
|  *  2     1.169
 | |
|  *  3     1.178
 | |
|  *  4     1.192
 | |
|  *  5     1.213
 | |
|  *  6     1.238
 | |
|  *  7     1.299
 | |
|  *  8     1.336
 | |
|  *  9     1.457
 | |
|  * 10     1.573
 | |
|  * 11     1.707
 | |
|  * 12     1.882
 | |
|  * 13     2.06
 | |
|  * 14     2.32
 | |
|  * 15     2.58
 | |
|  * -------------------------------------------------------------------
 | |
|  *
 | |
|  * The ZX spectrum output circuit was modelled in SwitcherCAD and
 | |
|  * the resistor values below create the voltage levels above.
 | |
|  * RD was measured on a real chip to be 8m Ohm, RU was 0.8m Ohm.
 | |
|  */
 | |
| 
 | |
| static const ay8910_device::ay_ym_param ay8910_param =
 | |
| {
 | |
| 	800000, 8000000,
 | |
| 	16,
 | |
| 	{ 15950, 15350, 15090, 14760, 14275, 13620, 12890, 11370,
 | |
| 		10600,  8590,  7190,  5985,  4820,  3945,  3017,  2345 }
 | |
| };
 | |
| 
 | |
| static const ay8910_device::mosfet_param ay8910_mosfet_param =
 | |
| {
 | |
| 	1.465385778,
 | |
| 	4.9,
 | |
| 	16,
 | |
| 	{
 | |
| 		0.00076,
 | |
| 		0.80536,
 | |
| 		1.13106,
 | |
| 		1.65952,
 | |
| 		2.42261,
 | |
| 		3.60536,
 | |
| 		5.34893,
 | |
| 		8.96871,
 | |
| 		10.97202,
 | |
| 		19.32370,
 | |
| 		29.01935,
 | |
| 		38.82026,
 | |
| 		55.50539,
 | |
| 		78.44395,
 | |
| 		109.49257,
 | |
| 		153.72985,
 | |
| 	}
 | |
| };
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| /*************************************
 | |
|  *
 | |
|  *  Inline
 | |
|  *
 | |
|  *************************************/
 | |
| 
 | |
| static inline void build_3D_table(double rl, const ay8910_device::ay_ym_param *par, const ay8910_device::ay_ym_param *par_env, int normalize, double factor, int zero_is_off, short *tab)
 | |
| {
 | |
| 	double min = 10.0,  max = 0.0;
 | |
| 
 | |
| 	std::vector<double> temp(8*32*32*32, 0);
 | |
| 
 | |
| 	for (int e = 0; e < 8; e++)
 | |
| 	{
 | |
| 		const ay8910_device::ay_ym_param *par_ch1 = (e & 0x01) ? par_env : par;
 | |
| 		const ay8910_device::ay_ym_param *par_ch2 = (e & 0x02) ? par_env : par;
 | |
| 		const ay8910_device::ay_ym_param *par_ch3 = (e & 0x04) ? par_env : par;
 | |
| 
 | |
| 		for (int j1 = 0; j1 < par_ch1->res_count; j1++)
 | |
| 			for (int j2 = 0; j2 < par_ch2->res_count; j2++)
 | |
| 				for (int j3 = 0; j3 < par_ch3->res_count; j3++)
 | |
| 				{
 | |
| 					double n;
 | |
| 					if (zero_is_off)
 | |
| 					{
 | |
| 						n  = (j1 != 0 || (e & 0x01)) ? 1 : 0;
 | |
| 						n += (j2 != 0 || (e & 0x02)) ? 1 : 0;
 | |
| 						n += (j3 != 0 || (e & 0x04)) ? 1 : 0;
 | |
| 					}
 | |
| 					else
 | |
| 						n = 3.0;
 | |
| 
 | |
| 					double rt = n / par->r_up + 3.0 / par->r_down + 1.0 / rl;
 | |
| 					double rw = n / par->r_up;
 | |
| 
 | |
| 					rw += 1.0 / par_ch1->res[j1];
 | |
| 					rt += 1.0 / par_ch1->res[j1];
 | |
| 					rw += 1.0 / par_ch2->res[j2];
 | |
| 					rt += 1.0 / par_ch2->res[j2];
 | |
| 					rw += 1.0 / par_ch3->res[j3];
 | |
| 					rt += 1.0 / par_ch3->res[j3];
 | |
| 
 | |
| 					int indx = (e << 15) | (j3 << 10) | (j2 << 5) | j1;
 | |
| 					temp[indx] = rw / rt;
 | |
| 					if (temp[indx] < min)
 | |
| 						min = temp[indx];
 | |
| 					if (temp[indx] > max)
 | |
| 						max = temp[indx];
 | |
| 				}
 | |
| 	}
 | |
| 
 | |
| 	if (normalize)
 | |
| 	{
 | |
| 		for (int j = 0; j < 32*32*32*8; j++)
 | |
| 			tab[j] = 8000 * MAX_OUTPUT * (((temp[j] - min)/(max-min))) * factor;
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		for (int j = 0; j < 32*32*32*8; j++)
 | |
| 			tab[j] = 8000 * MAX_OUTPUT * temp[j];
 | |
| 	}
 | |
| 
 | |
| 	/* for (e = 0;e<16;e++) printf("%d %d\n",e << 10, tab[e << 10]); */
 | |
| }
 | |
| 
 | |
| static inline void build_single_table(double rl, const ay8910_device::ay_ym_param *par, int normalize, short *tab, int zero_is_off)
 | |
| {
 | |
| 	double rt;
 | |
| 	double rw;
 | |
| 	double temp[32], min = 10.0, max = 0.0;
 | |
| 
 | |
| 	for (int j = 0; j < par->res_count; j++)
 | |
| 	{
 | |
| 		rt = 1.0 / par->r_down + 1.0 / rl;
 | |
| 
 | |
| 		rw = 1.0 / par->res[j];
 | |
| 		rt += 1.0 / par->res[j];
 | |
| 
 | |
| 		if (!(zero_is_off && j == 0))
 | |
| 		{
 | |
| 			rw += 1.0 / par->r_up;
 | |
| 			rt += 1.0 / par->r_up;
 | |
| 		}
 | |
| 
 | |
| 		temp[j] = rw / rt;
 | |
| 		if (temp[j] < min)
 | |
| 			min = temp[j];
 | |
| 		if (temp[j] > max)
 | |
| 			max = temp[j];
 | |
| 	}
 | |
| 	if (normalize)
 | |
| 	{
 | |
| 		for (int j = 0; j < par->res_count; j++)
 | |
| 			tab[j] = 16384 * MAX_OUTPUT * (((temp[j] - min)/(max-min)) - 0.25) * 0.5;
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		for (int j = 0; j < par->res_count; j++)
 | |
| 			tab[j] = 16384 * MAX_OUTPUT * temp[j];
 | |
| 	}
 | |
| 
 | |
| }
 | |
| 
 | |
| static inline void build_mosfet_resistor_table(const ay8910_device::mosfet_param &par, const double rd, short *tab)
 | |
| {
 | |
| 	for (int j = 0; j < par.m_count; j++)
 | |
| 	{
 | |
| 		const double Vd = 5.0;
 | |
| 		const double Vg = par.m_Vg - par.m_Vth;
 | |
| 		const double kn = par.m_Kn[j] / 1.0e6;
 | |
| 		const double p2 = 1.0 / (2.0 * kn * rd) + Vg;
 | |
| 		const double Vs = p2 - sqrt(p2 * p2 - Vg * Vg);
 | |
| 
 | |
| 		const double res = rd * (Vd / Vs - 1.0);
 | |
| 
 | |
| 		tab[j] = res * 16384;
 | |
| 		//printf("%d %f %10d\n", j, rd / (res + rd) * 5.0, tab[j]);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| float ay8910_device::mix_3D()
 | |
| {
 | |
| 	int indx = 0;
 | |
| 
 | |
| 	for (int chan = 0; chan < NUM_CHANNELS; chan++)
 | |
| 	{
 | |
| 		tone_t *tone = &m_tone[chan];
 | |
| 		if (tone_envelope(tone) != 0)
 | |
| 		{
 | |
| 			envelope_t *envelope = &m_envelope[get_envelope_chan(chan)];
 | |
| 			unsigned int env_volume = envelope->volume;
 | |
| 			unsigned int env_mask = (1 << (chan + 15));
 | |
| 			if (m_feature & PSG_HAS_EXPANDED_MODE)
 | |
| 			{
 | |
| 				if (!is_expanded_mode())
 | |
| 				{
 | |
| 					env_volume >>= 1;
 | |
| 					env_mask = 0;
 | |
| 				}
 | |
| 			}
 | |
| 			if (m_feature & PSG_EXTENDED_ENVELOPE) // AY8914 Has a two bit tone_envelope field
 | |
| 			{
 | |
| 				indx |= env_mask | (m_vol_enabled[chan] ? ((env_volume >> (3-tone_envelope(tone))) << (chan*5)) : 0);
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				indx |= env_mask | (m_vol_enabled[chan] ? env_volume << (chan*5) : 0);
 | |
| 			}
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			const unsigned int tone_mask = is_expanded_mode() ? (1 << (chan + 15)) : 0;
 | |
| 			indx |= tone_mask | (m_vol_enabled[chan] ? tone_volume(tone) << (chan*5) : 0);
 | |
| 		}
 | |
| 	}
 | |
|   lastIndx=indx;
 | |
| 	return m_vol3d_table[indx];
 | |
| }
 | |
| 
 | |
| /*************************************
 | |
|  *
 | |
|  * Static functions
 | |
|  *
 | |
|  *************************************/
 | |
| 
 | |
| void ay8910_device::ay8910_write_reg(int r, int v)
 | |
| {
 | |
| 	if ((r & 0xf) == AY_EASHAPE) // shared register
 | |
| 		r &= 0xf;
 | |
| 
 | |
| 	//if (r >= 11 && r <= 13) printf("%d %x %02x\n", PSG->index, r, v);
 | |
| 	m_regs[r] = v;
 | |
| 	unsigned char coarse;
 | |
| 
 | |
| 	switch(r)
 | |
| 	{
 | |
| 		case AY_AFINE:
 | |
| 		case AY_ACOARSE:
 | |
| 			coarse = m_regs[AY_ACOARSE] & (is_expanded_mode() ? 0xff : 0xf);
 | |
| 			m_tone[0].set_period(m_regs[AY_AFINE], coarse);
 | |
| 			break;
 | |
| 		case AY_BFINE:
 | |
| 		case AY_BCOARSE:
 | |
| 			coarse = m_regs[AY_BCOARSE] & (is_expanded_mode() ? 0xff : 0xf);
 | |
| 			m_tone[1].set_period(m_regs[AY_BFINE], coarse);
 | |
| 			break;
 | |
| 		case AY_CFINE:
 | |
| 		case AY_CCOARSE:
 | |
| 			coarse = m_regs[AY_CCOARSE] & (is_expanded_mode() ? 0xff : 0xf);
 | |
| 			m_tone[2].set_period(m_regs[AY_CFINE], coarse);
 | |
| 			break;
 | |
| 		case AY_NOISEPER:
 | |
| 			/* No action required */
 | |
| 			break;
 | |
| 		case AY_AVOL:
 | |
| 			m_tone[0].set_volume(m_regs[AY_AVOL]);
 | |
| 			break;
 | |
| 		case AY_BVOL:
 | |
| 			m_tone[1].set_volume(m_regs[AY_BVOL]);
 | |
| 			break;
 | |
| 		case AY_CVOL:
 | |
| 			m_tone[2].set_volume(m_regs[AY_CVOL]);
 | |
| 			break;
 | |
| 		case AY_EACOARSE:
 | |
| 		case AY_EAFINE:
 | |
| 			m_envelope[0].set_period(m_regs[AY_EAFINE], m_regs[AY_EACOARSE]);
 | |
| 			break;
 | |
| 		case AY_ENABLE:
 | |
| 			m_last_enable = m_regs[AY_ENABLE];
 | |
| 			break;
 | |
| 		case AY_EASHAPE:
 | |
| 			if (m_feature & PSG_HAS_EXPANDED_MODE)
 | |
| 			{
 | |
| 				const unsigned char old_mode = m_mode;
 | |
| 				m_mode = (v >> 4) & 0xf;
 | |
| 				if (old_mode != m_mode)
 | |
| 				{
 | |
| 					if (((old_mode & 0xe) == 0xa) ^ ((m_mode & 0xe) == 0xa)) // AY8930 expanded mode
 | |
| 					{
 | |
| 						for (int i = 0; i < AY_EASHAPE; i++)
 | |
| 						{
 | |
| 							ay8910_write_reg(i, 0);
 | |
| 							ay8910_write_reg(i + 0x10, 0);
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 			m_envelope[0].set_shape(m_regs[AY_EASHAPE], m_env_step_mask);
 | |
| 			break;
 | |
| 		case AY_EBFINE:
 | |
| 		case AY_EBCOARSE:
 | |
| 			m_envelope[1].set_period(m_regs[AY_EBFINE], m_regs[AY_EBCOARSE]);
 | |
| 			break;
 | |
| 		case AY_ECFINE:
 | |
| 		case AY_ECCOARSE:
 | |
| 			m_envelope[2].set_period(m_regs[AY_ECFINE], m_regs[AY_ECCOARSE]);
 | |
| 			break;
 | |
| 		case AY_EBSHAPE:
 | |
| 			m_envelope[1].set_shape(m_regs[AY_EBSHAPE], m_env_step_mask);
 | |
| 			break;
 | |
| 		case AY_ECSHAPE:
 | |
| 			m_envelope[2].set_shape(m_regs[AY_ECSHAPE], m_env_step_mask);
 | |
| 			break;
 | |
| 		case AY_ADUTY:
 | |
| 			m_tone[0].set_duty(m_regs[AY_ADUTY]);
 | |
| 			break;
 | |
| 		case AY_BDUTY:
 | |
| 			m_tone[1].set_duty(m_regs[AY_BDUTY]);
 | |
| 			break;
 | |
| 		case AY_CDUTY:
 | |
| 			m_tone[2].set_duty(m_regs[AY_CDUTY]);
 | |
| 			break;
 | |
| 		case AY_NOISEAND:
 | |
| 		case AY_NOISEOR:
 | |
| 			// No action required
 | |
| 			break;
 | |
| 		default:
 | |
| 			m_regs[r] = 0; // reserved, set as 0
 | |
| 			break;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| //-------------------------------------------------
 | |
| //  sound_stream_update - handle a stream update
 | |
| //-------------------------------------------------
 | |
| 
 | |
| void ay8910_device::sound_stream_update(short** outputs, int outLen)
 | |
| {
 | |
| 	tone_t *tone;
 | |
| 	envelope_t *envelope;
 | |
| 
 | |
| 	int samples = outLen;
 | |
| 
 | |
| 	/* hack to prevent us from hanging when starting filtered outputs */
 | |
| 	if (!m_ready)
 | |
| 	{
 | |
| 		for (int chan = 0; chan < m_streams; chan++)
 | |
| 			memset(outputs[chan],0,outLen*sizeof(short));
 | |
| 	}
 | |
| 
 | |
| 	/* 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. */
 | |
| 
 | |
| 	/* buffering loop */
 | |
| 	for (int sampindex = 0; sampindex < samples; sampindex++)
 | |
| 	{
 | |
| 		for (int chan = 0; chan < NUM_CHANNELS; chan++)
 | |
| 		{
 | |
| 			tone = &m_tone[chan];
 | |
| 			const int period = std::max<int>(1, tone->period) * (m_step_mul << 1);
 | |
| 			tone->count += is_expanded_mode() ? 32 : ((m_feature & PSG_HAS_EXPANDED_MODE) ? 1 : 2);
 | |
|                         if (tone->count>=period) {
 | |
|                           tone->duty_cycle = (tone->duty_cycle - (tone->count/period)) & 0x1f;
 | |
|                           tone->output = is_expanded_mode() ? BIT(duty_cycle[tone_duty(tone)], tone->duty_cycle) : BIT(tone->duty_cycle, 0);
 | |
|                           tone->count = tone->count % period;
 | |
|                         }
 | |
| 		}
 | |
| 
 | |
| 		const int period_noise = (int)(noise_period()) * m_step_mul;
 | |
| 		if ((++m_count_noise) >= period_noise)
 | |
| 		{
 | |
| 			/* toggle the prescaler output. Noise is no different to
 | |
| 			 * channels.
 | |
| 			 */
 | |
| 			m_count_noise = 0;
 | |
| 			m_prescale_noise = (m_prescale_noise + 1) & ((m_feature & PSG_HAS_EXPANDED_MODE) ? 3 : 1);
 | |
| 
 | |
| 			if (is_expanded_mode()) // AY8930 noise generator rate is twice? compares as compatibility mode
 | |
| 			{
 | |
| 				// This is called "Noise value" on the docs, but is a counter whose period is determined by the LFSR.
 | |
| 				// Using AND/OR gates, specific periods can be "filtered" out.
 | |
| 				// A square wave can be generated through this behavior, which can be used for crude AM pulse width modulation.
 | |
| 
 | |
| 				// The period of the noise is determined by this value.
 | |
| 				// The least significant byte of the LFSR is bitwise ANDed with the AND mask, and then bitwise ORed with the OR mask.
 | |
| 				if ((++m_noise_value) >= (((unsigned char)(m_rng) & noise_and()) | noise_or())) // Clock the noise value.
 | |
| 				{
 | |
| 					m_noise_value = 0;
 | |
| 
 | |
| 					// When everything is finally said and done, a 1bit latch is flipped.
 | |
| 					// This is the final output of the noise, to be multiplied by the tone and envelope generators of the channel.
 | |
| 					m_noise_out ^= 1;
 | |
| 
 | |
| 					noise_rng_tick();
 | |
| 				}
 | |
| 			}
 | |
| 			else if (!m_prescale_noise)
 | |
| 				noise_rng_tick();
 | |
| 		}
 | |
| 
 | |
| 		for (int chan = 0; chan < NUM_CHANNELS; chan++)
 | |
| 		{
 | |
| 			tone = &m_tone[chan];
 | |
| 			m_vol_enabled[chan] = (tone->output | (unsigned char)tone_enable(chan)) & (noise_output() | (unsigned char)noise_enable(chan));
 | |
| 		}
 | |
| 
 | |
| 		/* update envelope */
 | |
| 		for (int chan = 0; chan < NUM_CHANNELS; chan++)
 | |
| 		{
 | |
| 			envelope = &m_envelope[chan];
 | |
| 			if (envelope->holding == 0)
 | |
| 			{
 | |
| 				const int period = std::max<int>(1, envelope->period) * m_env_step_mul;
 | |
| 				if ((++envelope->count) >= period)
 | |
| 				{
 | |
| 					envelope->count = 0;
 | |
| 					envelope->step--;
 | |
| 
 | |
| 					/* check envelope current position */
 | |
| 					if (envelope->step < 0)
 | |
| 					{
 | |
| 						if (envelope->hold)
 | |
| 						{
 | |
| 							if (envelope->alternate)
 | |
| 								envelope->attack ^= m_env_step_mask;
 | |
| 							envelope->holding = 1;
 | |
| 							envelope->step = 0;
 | |
| 						}
 | |
| 						else
 | |
| 						{
 | |
| 							/* if CountEnv has looped an odd number of times (usually 1), */
 | |
| 							/* invert the output. */
 | |
| 							if (envelope->alternate && (envelope->step & (m_env_step_mask + 1)))
 | |
| 								envelope->attack ^= m_env_step_mask;
 | |
| 
 | |
| 							envelope->step &= m_env_step_mask;
 | |
| 						}
 | |
| 					}
 | |
| 
 | |
| 				}
 | |
| 			}
 | |
| 			envelope->volume = (envelope->step ^ envelope->attack);
 | |
| 		}
 | |
| 
 | |
| 		if (m_streams == 3)
 | |
| 		{
 | |
| 			for (int chan = 0; chan < NUM_CHANNELS; chan++)
 | |
| 			{
 | |
| 				tone = &m_tone[chan];
 | |
| 				if (tone_envelope(tone) != 0)
 | |
| 				{
 | |
| 					envelope = &m_envelope[get_envelope_chan(chan)];
 | |
| 					unsigned int env_volume = envelope->volume;
 | |
| 					if (m_feature & PSG_HAS_EXPANDED_MODE)
 | |
| 					{
 | |
| 						if (!is_expanded_mode())
 | |
| 						{
 | |
| 							env_volume >>= 1;
 | |
| 							if (m_feature & PSG_EXTENDED_ENVELOPE) // AY8914 Has a two bit tone_envelope field
 | |
| 								outputs[chan][sampindex]=m_vol_table[chan][m_vol_enabled[chan] ? env_volume >> (3-tone_envelope(tone)) : 0];
 | |
| 							else
 | |
| 								outputs[chan][sampindex]=m_vol_table[chan][m_vol_enabled[chan] ? env_volume : 0];
 | |
| 						}
 | |
| 						else
 | |
| 						{
 | |
| 							if (m_feature & PSG_EXTENDED_ENVELOPE) // AY8914 Has a two bit tone_envelope field
 | |
| 								outputs[chan][sampindex]=m_env_table[chan][m_vol_enabled[chan] ? env_volume >> (3-tone_envelope(tone)) : 0];
 | |
| 							else
 | |
| 								outputs[chan][sampindex]=m_env_table[chan][m_vol_enabled[chan] ? env_volume : 0];
 | |
| 						}
 | |
| 					}
 | |
| 					else
 | |
| 					{
 | |
| 						if (m_feature & PSG_EXTENDED_ENVELOPE) // AY8914 Has a two bit tone_envelope field
 | |
| 							outputs[chan][sampindex]=m_env_table[chan][m_vol_enabled[chan] ? env_volume >> (3-tone_envelope(tone)) : 0];
 | |
| 						else
 | |
| 							outputs[chan][sampindex]=m_env_table[chan][m_vol_enabled[chan] ? env_volume : 0];
 | |
| 					}
 | |
| 				}
 | |
| 				else
 | |
| 				{
 | |
| 					if (is_expanded_mode())
 | |
| 						outputs[chan][sampindex]=m_env_table[chan][m_vol_enabled[chan] ? tone_volume(tone) : 0];
 | |
| 					else
 | |
| 						outputs[chan][sampindex]=m_vol_table[chan][m_vol_enabled[chan] ? tone_volume(tone) : 0];
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			outputs[0][sampindex]=mix_3D();
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void ay8910_device::build_mixer_table()
 | |
| {
 | |
| 	int normalize = 0;
 | |
| 
 | |
| 	if ((m_flags & AY8910_LEGACY_OUTPUT) != 0)
 | |
| 	{
 | |
| 		normalize = 1;
 | |
| 	}
 | |
| 
 | |
| 	if ((m_flags & AY8910_RESISTOR_OUTPUT) != 0)
 | |
| 	{
 | |
| 		for (int chan = 0; chan < NUM_CHANNELS; chan++)
 | |
| 		{
 | |
| 			build_mosfet_resistor_table(ay8910_mosfet_param, m_res_load[chan], m_vol_table[chan]);
 | |
| 			build_mosfet_resistor_table(ay8910_mosfet_param, m_res_load[chan], m_env_table[chan]);
 | |
| 		}
 | |
| 	}
 | |
| 	else if (m_streams == NUM_CHANNELS)
 | |
| 	{
 | |
| 		for (int chan = 0; chan < NUM_CHANNELS; chan++)
 | |
| 		{
 | |
| 			build_single_table(m_res_load[chan], m_par, normalize, m_vol_table[chan], m_zero_is_off);
 | |
| 			build_single_table(m_res_load[chan], m_par_env, normalize, m_env_table[chan], 0);
 | |
| 		}
 | |
| 	}
 | |
| 	/*
 | |
| 	 * The previous implementation added all three channels up instead of averaging them.
 | |
| 	 * The factor of 3 will force the same levels if normalizing is used.
 | |
| 	 */
 | |
| 	else
 | |
| 	{
 | |
| 		build_3D_table(m_res_load[0], m_par, m_par_env, normalize, 3, m_zero_is_off, m_vol3d_table);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| //-------------------------------------------------
 | |
| //  device_start - device-specific startup
 | |
| //-------------------------------------------------
 | |
| 
 | |
| void ay8910_device::device_start()
 | |
| {
 | |
| 	if ((m_flags & AY8910_SINGLE_OUTPUT) != 0)
 | |
| 	{
 | |
| 		m_streams = 1;
 | |
| 	}
 | |
| 
 | |
| 	build_mixer_table();
 | |
| }
 | |
| 
 | |
| 
 | |
| void ay8910_device::ay8910_reset_ym()
 | |
| {
 | |
| 	m_active = false;
 | |
| 	m_register_latch = 0;
 | |
| 	m_rng = (m_feature & PSG_HAS_EXPANDED_MODE) ? 0x1ffff : 1;
 | |
| 	m_mode = 0; // ay-3-8910 compatible mode
 | |
| 	m_noise_value = 0;
 | |
| 	m_noise_out = 0;
 | |
| 	for (int chan = 0; chan < NUM_CHANNELS; chan++)
 | |
| 	{
 | |
| 		m_tone[chan].reset();
 | |
| 		m_envelope[chan].reset();
 | |
| 	}
 | |
| 	m_count_noise = 0;
 | |
| 	m_prescale_noise = 0;
 | |
| 	m_last_enable = -1;  /* force a write */
 | |
| 	for (int i = 0; i < AY_PORTA; i++)
 | |
| 		ay8910_write_reg(i,0);
 | |
| 	m_ready = 1;
 | |
| #if ENABLE_REGISTER_TEST
 | |
| 	ay8910_write_reg(AY_AFINE, 0);
 | |
| 	ay8910_write_reg(AY_ACOARSE, 1);
 | |
| 	ay8910_write_reg(AY_BFINE, 0);
 | |
| 	ay8910_write_reg(AY_BCOARSE, 2);
 | |
| 	ay8910_write_reg(AY_CFINE, 0);
 | |
| 	ay8910_write_reg(AY_CCOARSE, 4);
 | |
| 	//#define AY_NOISEPER   (6)
 | |
| 	ay8910_write_reg(AY_ENABLE, ~7);
 | |
| 	ay8910_write_reg(AY_AVOL, 10);
 | |
| 	ay8910_write_reg(AY_BVOL, 10);
 | |
| 	ay8910_write_reg(AY_CVOL, 10);
 | |
| 	//#define AY_EAFINE  (11)
 | |
| 	//#define AY_EACOARSE    (12)
 | |
| 	//#define AY_EASHAPE (13)
 | |
| #endif
 | |
| }
 | |
| 
 | |
| void ay8910_device::ay8910_write_ym(int addr, unsigned char data)
 | |
| {
 | |
| 	if (addr & 1)
 | |
| 	{
 | |
| 		if (m_active)
 | |
| 		{
 | |
| 			const unsigned char register_latch = m_register_latch + get_register_bank();
 | |
| 			/* Data port */
 | |
| 			if (m_register_latch == AY_EASHAPE || m_regs[register_latch] != data)
 | |
| 			{
 | |
| 				/* update the output buffer before changing the register */
 | |
| 			}
 | |
| 
 | |
| 			ay8910_write_reg(register_latch, data);
 | |
| 		}
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		m_active = (data >> 4) == 0; // mask programmed 4-bit code
 | |
| 		if (m_active)
 | |
| 		{
 | |
| 			/* Register port */
 | |
| 			m_register_latch = data & 0x0f;
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| unsigned char ay8910_device::ay8910_read_ym()
 | |
| {
 | |
| 	unsigned char r = m_register_latch + get_register_bank();
 | |
| 
 | |
| 	if (!m_active) return 0xff; // high impedance
 | |
| 
 | |
| 	if ((r & 0xf) == AY_EASHAPE) // shared register
 | |
| 		r &= 0xf;
 | |
| 
 | |
| 	/* There are no state dependent register in the AY8910! */
 | |
| 
 | |
| 	/* Depending on chip type, unused bits in registers may or may not be accessible.
 | |
| 	Untested chips are assumed to regard them as 'ram'
 | |
| 	Tested and confirmed on hardware:
 | |
| 	- AY-3-8910: inaccessible bits (see masks below) read back as 0
 | |
| 	- AY-3-8914: same as 8910 except regs B,C,D (8,9,A below due to 8910->8914 remapping) are 0x3f
 | |
| 	- AY-3-8916/8917 (used on ECS INTV expansion): inaccessible bits mirror one of the i/o ports, needs further testing
 | |
| 	- YM2149: no anomaly
 | |
| 	*/
 | |
| 	if (chip_type == AY8910) {
 | |
| 		const unsigned char mask[0x10]={
 | |
| 			0xff,0x0f,0xff,0x0f,0xff,0x0f,0x1f,0xff,0x1f,0x1f,0x1f,0xff,0xff,0x0f,0xff,0xff
 | |
| 		};
 | |
| 		return m_regs[r] & mask[r];
 | |
| 	}
 | |
| 	else if (chip_type == AY8914) {
 | |
| 		const unsigned char mask[0x10]={
 | |
| 			0xff,0x0f,0xff,0x0f,0xff,0x0f,0x1f,0xff,0x3f,0x3f,0x3f,0xff,0xff,0x0f,0xff,0xff
 | |
| 		};
 | |
| 		return m_regs[r] & mask[r];
 | |
| 	}
 | |
| 	else return m_regs[r];
 | |
| }
 | |
| 
 | |
| /*************************************
 | |
|  *
 | |
|  * Sound Interface
 | |
|  *
 | |
|  *************************************/
 | |
| 
 | |
| 
 | |
| //-------------------------------------------------
 | |
| //  device_reset - device-specific reset
 | |
| //-------------------------------------------------
 | |
| 
 | |
| void ay8910_device::device_reset()
 | |
| {
 | |
|   lastIndx=0;
 | |
| 	ay8910_reset_ym();
 | |
| }
 | |
| 
 | |
| /*************************************
 | |
|  *
 | |
|  * Read/Write Handlers
 | |
|  *
 | |
|  *************************************/
 | |
| 
 | |
| void ay8910_device::address_w(unsigned char data)
 | |
| {
 | |
| #if ENABLE_REGISTER_TEST
 | |
| 	return;
 | |
| #else
 | |
| 	ay8910_write_ym(0, data);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| void ay8910_device::data_w(unsigned char data)
 | |
| {
 | |
| #if ENABLE_REGISTER_TEST
 | |
| 	return;
 | |
| #else
 | |
| 	ay8910_write_ym(1, data);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| // here, BC1 is hooked up to A0 on the host and BC2 is hooked up to A1
 | |
| void ay8910_device::write_bc1_bc2(int offset, unsigned char data)
 | |
| {
 | |
| 	switch (offset & 3)
 | |
| 	{
 | |
| 	case 0: // latch address
 | |
| 		address_w(data);
 | |
| 		break;
 | |
| 	case 1: // inactive
 | |
| 		break;
 | |
| 	case 2: // write to psg
 | |
| 		data_w(data);
 | |
| 		break;
 | |
| 	case 3: // latch address
 | |
| 		address_w(data);
 | |
| 		break;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static const unsigned char mapping8914to8910[16] = { 0, 2, 4, 11, 1, 3, 5, 12, 7, 6, 13, 8, 9, 10, 14, 15 };
 | |
| 
 | |
| unsigned char ay8914_device::read(int offset)
 | |
| {
 | |
| 	unsigned char rv;
 | |
| 	address_w(mapping8914to8910[offset & 0xf]);
 | |
| 	rv = data_r();
 | |
| 	return rv;
 | |
| }
 | |
| 
 | |
| void ay8914_device::write(int offset, unsigned char data)
 | |
| {
 | |
| 	address_w(mapping8914to8910[offset & 0xf]);
 | |
| 	data_w(data & 0xff);
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| ay8910_device::ay8910_device(unsigned int clock)
 | |
| 	: ay8910_device(AY8910, clock, PSG_TYPE_AY, 3, 2)
 | |
| {
 | |
| }
 | |
| 
 | |
| ay8910_device::ay8910_device(device_type type, unsigned int clock,
 | |
| 								psg_type_t psg_type, int streams, int ioports, int feature, bool clk_sel)
 | |
| 	: chip_type(type),
 | |
| 		m_type(psg_type),
 | |
| 		m_streams(streams),
 | |
| 		m_ready(0),
 | |
| 		m_active(false),
 | |
| 		m_register_latch(0),
 | |
| 		m_last_enable(0),
 | |
| 		m_prescale_noise(0),
 | |
| 		m_noise_value(0),
 | |
| 		m_count_noise(0),
 | |
| 		m_rng(0),
 | |
| 		m_noise_out(0),
 | |
| 		m_mode(0),
 | |
| 		m_env_step_mask((!(feature & PSG_HAS_EXPANDED_MODE)) && (psg_type == PSG_TYPE_AY) ? 0x0f : 0x1f),
 | |
| 		m_step_mul(    ((feature & PSG_HAS_INTERNAL_DIVIDER) || ((feature & PSG_PIN26_IS_CLKSEL) && clk_sel)) ? 2 : 1),
 | |
| 		m_env_step_mul(  ((feature & PSG_HAS_EXPANDED_MODE)  || (psg_type == PSG_TYPE_AY)) ? (m_step_mul << 1) : m_step_mul),
 | |
| 		m_zero_is_off(  (!(feature & PSG_HAS_EXPANDED_MODE)) && (psg_type == PSG_TYPE_AY) ? 1 : 0),
 | |
| 		m_par(          (!(feature & PSG_HAS_EXPANDED_MODE)) && (psg_type == PSG_TYPE_AY) ? &ay8910_param : &ym2149_param),
 | |
| 		m_par_env(      (!(feature & PSG_HAS_EXPANDED_MODE)) && (psg_type == PSG_TYPE_AY) ? &ay8910_param : &ym2149_param_env),
 | |
| 		m_flags(AY8910_LEGACY_OUTPUT | (((feature & PSG_PIN26_IS_CLKSEL) && clk_sel) ? YM2149_PIN26_LOW : 0)),
 | |
| 		m_feature(feature)
 | |
| {
 | |
| 	memset(&m_regs,0,sizeof(m_regs));
 | |
| 	memset(&m_tone,0,sizeof(m_tone));
 | |
| 	memset(&m_envelope,0,sizeof(m_envelope));
 | |
| 	memset(&m_vol_enabled,0,sizeof(m_vol_enabled));
 | |
| 	memset(&m_vol_table,0,sizeof(m_vol_table));
 | |
| 	memset(&m_env_table,0,sizeof(m_env_table));
 | |
| 	m_res_load[0] = m_res_load[1] = m_res_load[2] = 1000; //Default values for resistor loads
 | |
| 
 | |
| 	// TODO : measure ay8930 volume parameters (PSG_TYPE_YM for temporary 5 bit handling)
 | |
| 	set_type((m_feature & PSG_HAS_EXPANDED_MODE) ? PSG_TYPE_YM : psg_type, clk_sel);
 | |
| }
 | |
| 
 | |
| void ay8910_device::set_type(psg_type_t psg_type, bool clk_sel)
 | |
| {
 | |
| 	m_type = psg_type;
 | |
| 	if (psg_type == PSG_TYPE_AY)
 | |
| 	{
 | |
| 		m_env_step_mask = 0x0f;
 | |
| 		m_env_step_mul = is_clock_divided() ? 4 : 2;
 | |
| 		m_zero_is_off = 1;
 | |
| 		m_par = &ay8910_param;
 | |
| 		m_par_env = &ay8910_param;
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		m_env_step_mask = 0x1f;
 | |
| 		m_env_step_mul = is_clock_divided() ? 2 : 1;
 | |
| 		m_zero_is_off = 0;
 | |
| 		m_par = &ym2149_param;
 | |
| 		m_par_env = &ym2149_param_env;
 | |
| 	}
 | |
| 	if (m_feature & PSG_HAS_EXPANDED_MODE)
 | |
| 		m_env_step_mul <<= 1;
 | |
| 
 | |
| 	set_clock_sel(clk_sel);
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| ay8912_device::ay8912_device(unsigned int clock)
 | |
| 	: ay8910_device(AY8912, clock, PSG_TYPE_AY, 3, 1)
 | |
| {
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| ay8913_device::ay8913_device(unsigned int clock)
 | |
| 	: ay8910_device(AY8913, clock, PSG_TYPE_AY, 3, 0)
 | |
| {
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| ay8914_device::ay8914_device(unsigned int clock)
 | |
| 	: ay8910_device(AY8914, clock, PSG_TYPE_AY, 3, 2, PSG_EXTENDED_ENVELOPE)
 | |
| {
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| ay8930_device::ay8930_device(unsigned int clock, bool clk_sel)
 | |
| 	: ay8910_device(AY8930, clock, PSG_TYPE_YM, 3, 2, PSG_PIN26_IS_CLKSEL | PSG_HAS_EXPANDED_MODE, clk_sel)
 | |
| {
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| ym2149_device::ym2149_device(unsigned int clock, bool clk_sel)
 | |
| 	: ay8910_device(YM2149, clock, PSG_TYPE_YM, 3, 2, PSG_PIN26_IS_CLKSEL, clk_sel)
 | |
| {
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| ym3439_device::ym3439_device(unsigned int clock, bool clk_sel)
 | |
| 	: ay8910_device(YM3439, clock, PSG_TYPE_YM, 3, 2, PSG_PIN26_IS_CLKSEL, clk_sel)
 | |
| {
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| ymz284_device::ymz284_device(unsigned int clock)
 | |
| 	: ay8910_device(YMZ284, clock, PSG_TYPE_YM, 1, 0)
 | |
| {
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| ymz294_device::ymz294_device(unsigned int clock)
 | |
| 	: ay8910_device(YMZ294, clock, PSG_TYPE_YM, 1, 0)
 | |
| {
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| sunsoft_5b_sound_device::sunsoft_5b_sound_device(unsigned int clock)
 | |
| 	: ay8910_device(SUNSOFT_5B_SOUND, clock, PSG_TYPE_YM, 1, 0, PSG_HAS_INTERNAL_DIVIDER)
 | |
| {
 | |
| }
 | 
