YM, DSP & DMA Sound
===========#==#=======#===============================================#=====
----------------------|YM2149/AY-3-8910 Sound Chip |-----
===========#==#=======#===============================================#=====
$FFFF8800.B|R-|PSG_SEL|Read Data | |-W| |Register Select |
$FFFF8800 PSG_SEL YM2149 register select (W) / read data (R)
Write a register number 0-15 here, then read or write the
value at $FFFF8802. The register set:
0 Channel A tone period, fine (8 bits)
1 Channel A tone period, coarse (4 bits)
2 Channel B tone period, fine
3 Channel B tone period, coarse
4 Channel C tone period, fine
5 Channel C tone period, coarse
6 Noise generator period (5 bits)
7 Mixer control and I/O port direction
8 Channel A amplitude
9 Channel B amplitude
10 Channel C amplitude
11 Envelope period, fine
12 Envelope period, coarse
13 Envelope shape (4 bits)
14 I/O Port A (floppy select, printer, RS232)
15 I/O Port B (Centronics data)
Register 7, mixer control:
Bit 7 Port B direction, 1 = output
Bit 6 Port A direction, 1 = output
Bit 5 Noise off, channel C
Bit 4 Noise off, channel B
Bit 3 Noise off, channel A
Bit 2 Tone off, channel C
Bit 1 Tone off, channel B
Bit 0 Tone off, channel A
Note the enable bits are inverted: a 0 enables that source.
Registers 8-10, amplitude:
Bits 3-0 fixed volume level 0-15
Bit 4 1 = use envelope instead of fixed volume
Register 13, envelope shape, bits 3-0:
Bit 3 CONT continue after first cycle
Bit 2 ATT attack, 1 = rising
Bit 1 ALT alternate direction each cycle
Bit 0 HOLD hold at final level
YM2149 versus AY-3-8910
The YM2149 is Yamaha's licensed version of General Instrument's
earlier AY-3-8910. The two are register compatible: same 16
registers, same layout, same writes. There are no extra
registers on either part. The differences are internal:
- The envelope counter is 5 bit on the YM2149 (32 steps)
against 4 bit on the AY (16 steps), giving smoother volume
ramps. The envelope clock is divided by 8 rather than 16
to keep the cycle time the same across twice the steps.
The volume registers stay 4 bit on both, so there is
nothing extra to write.
- The YM reads registers back exactly as written. The AY
returns 0 for unused bits regardless of what was written.
- The YM has a 2V DC offset on all outputs; the AY has 0.2V
on a channel only while an envelope is active. This is why
the AY sounds louder.
Nothing in TOS depends on any of this. AY documentation applies
to the ST unchanged as far as the register interface goes.
Register names verified against Hatari src/includes/psg.h.
Mixer and port-direction bit masks verified against EmuTOS
bios/psg.h (PSG_PORTB_OUTPUT 0x80, PSG_PORTA_OUTPUT 0x40,
PSG_NOISE_MASK 0x38, PSG_TONE_MASK 0x07).
$FFFF8802.B|rW|PSG_DAT|Write Data | | | | PSG Register 14 - Port A %RICDPBAS | | | | Reset IDE 0:no,1:reset (slow down)---+||||||| |F | | | Internal Speaker 0:on,1:off-----------+|||||| |F | | | Centronics Strobe----------------------+||||| | | | | Reset DSP 0:no,1:reset------------------+|||| |F | | | Printer Select In------------------------+||| | | | | Drive B select 0:on,1:off-----------------+|| | | | | Drive A select 0:on,1:off------------------+| | | | | Side select 0:side1,1:side0-----------------+ | | | | PSG Register 15 - Port B %xxxxxxxx | | | | Centronics Data Port-----------------++++++++ |
$FFFF8802 PSG_DAT YM2149 data register
Reads or writes the register previously selected at $FFFF8800.
PORT A, register 14, is the one that matters on the ST. It
carries the floppy drive and side select lines:
Bit 7 Reset IDE 0 = no, 1 = reset Falcon
Bit 6 Internal speaker 0 = on, 1 = off Falcon
Bit 5 Centronics strobe
Bit 4 Reset DSP 0 = no, 1 = reset Falcon
Bit 3 Printer select in
Bit 2 Drive B select 0 = selected
Bit 1 Drive A select 0 = selected
Bit 0 Side select 1 = side 0, 0 = side 1
Note the side select polarity: the bit SET selects side 0.
This is not a typo in the listing, it is how the hardware works.
Bits 3-7 carry RS232 RTS and DTR, the Centronics strobe and a
general purpose output. Always read the port, modify only the
bits you need and write it back. Writing a whole byte will
disturb the serial and printer lines.
Disable interrupts around any access to this register, or the
floppy VBL routine can deselect the drive underneath you. Set
flock at $0000043E to a non-zero value first.
Register layout verified against Hatari and EmuTOS.
===========#==#=======#===============================================#=====
----------------------|DMA, CODEC, ADC, DAC, DSP-Transmit/Receive |-----
===========#==#=======#===============================================#=====
$FFFF8900.W|RW|SND_DMA|Sound-DMA-Control %____RPRP F_EL__EL |F,STE | | | Timer A after Record/Play-------++|| | || || |F | | | MFP I/O 7 after Record/Play-------++ | || || |F | | | Frame Registers 0:play,1:record------+ || || |F | | | DMA record Enable/Loop-----------------++ || |F | | | DMA play Enable/Loop-----------------------++ |F,STE
$FFFF8900 SND_DMA Sound DMA control
Bits 1-0, DMA play:
Bit 1 loop: 0 = play once, 1 = repeat from frame start
Bit 0 enable: 0 = stop, 1 = start playback
Bits 5-4, DMA record (Falcon only), same enable/loop pair.
Bit 7 frame register select: 0 = play frame, 1 = record
Bits 11-8 and 15-12 select what happens at the end of a
record or play frame: Timer A event and MFP I/O 7 event.
On the STE only bits 1-0 exist. The record path and the event
bits are Falcon additions.
Playback reads from the frame start address at $FFFF8903-07
and continues to the frame end at $FFFF890F-13. The current
position can be read from $FFFF8909-0D while playing.
$FFFF8903.B|RW|SND_FSH|Frame Start Hi |F,STE
$FFFF8905.B|RW|SND_FSM|Frame Start Mi |F,STE
$FFFF8907.B|RW|SND_FSL|Frame Start Lo |F,STE
$FFFF8909.B|RW|SND_FCH|Frame Count Hi |F,STE
$FFFF890B.B|RW|SND_FCM|Frame Count Mi |F,STE
$FFFF890D.B|RW|SND_FCL|Frame Count Lo |F,STE
$FFFF890F.B|RW|SND_FEH|Frame End Hi |F,STE
$FFFF8911.B|RW|SND_FEM|Frame End Mi |F,STE
$FFFF8913.B|RW|SND_FEL|Frame End Lo |F,STE
$FFFF8920.W|RW|SND_SMC|Sound Mode Control %__SS__PP MB____FF |F,STE | | | DAC to track %SS--------------++ || || || |F | | | Play %PP+1 tracks-----------------++ || || |F | | | 0:Stereo,1:Mono----------------------+| || |F | | | 0:8bit,1:16bit------------------------+ || |F | | | Falcon:(unused)--STE: 6258 Hz--------------00 |F,STE | | | Falcon:12292 Hz--STE:12517 Hz--------------01 |F,STE | | | Falcon:19668 Hz--STE:25033 Hz--------------10 |F,STE | | | Falcon:49170 Hz--STE:50066 Hz--------------11 |F,STE
$FFFF8920 SND_SMC Sound mode control
This is a word register, but the two halves are separate:
$FFFF8920 is the track control byte and $FFFF8921 the mode
control byte. Hatari and EmuTOS treat them separately.
$FFFF8921, mode control:
Bit 7 0 = stereo, 1 = mono
Bit 6 0 = 8 bit, 1 = 16 bit
Bits 1-0 sample rate:
Falcon: 00 unused, 01 12292Hz, 10 19668Hz, 11 49170Hz
STE: 00 6258Hz, 01 12517Hz, 10 25033Hz, 11 50066Hz
$FFFF8920, track control (Falcon only):
Bits 5-4 which track the DAC monitors
Bits 1-0 number of tracks to play, minus one
The mono/stereo bit was previously printed on this page with
both states as 0. Corrected from EmuTOS bios/dmasound.c, which
does modectrl |= 0x80 with the comment 'Select mono', and from
Hatari src/falcon/crossbar.c, which reads isStereo as the
inverse of bit 7 and is16Bits from bit 6.
$FFFF8922.B|RW| - |Microwire Data Register |STE
$FFFF8922 Microwire Data Register (with $FFFF8924 Mask)
The STE and TT use a Microwire serial link to control an
LMC1992 audio processor, which handles master volume, left and
right balance, bass, treble, and the mix between DMA sound and
the YM2149 output. Write the command word here; $FFFF8924 is
the mask that clocks it out.
Command format: 10 CCC DDD DDD
10 chipset address, always this value
CCC command
DDD DDD data
Commands:
000 XXX XDD Mixing
00 DMA sound only
01 DMA sound + YM2149, full frequency range
10 DMA sound + YM2149 through a low pass
filter -> gives DMA sound only
11 input 3, not connected -> DMA only
001 XXD DDD Bass 0 000 = -12dB, 0 110 = 0dB,
1 100 = +12dB, 2dB steps
010 XXD DDD Treble same scale as bass
011 DDD DDD Master volume
000 000 = -80dB, 010 100 = -40dB,
101 XXX = 0dB, 2dB steps
100 XDD DDD Right channel volume
00 000 = -40dB, 01 010 = -20dB,
10 1XX = 0dB
101 XDD DDD Left channel volume, same scale as right
Any other command value is undefined.
THE STE MIXING BUG
Note the arrows on mixing modes 10 and 11 above. Mode 10 is
supposed to mix the YM2149 in through a low pass filter, which
would attenuate it relative to the DMA sound. On the STE it
does not work: input 2 is not wired, so selecting it drops the
YM output entirely and you get DMA sound only. Mode 11 selects
input 3, which is not connected at all.
The practical effect is that the STE gives you only two useful
choices, DMA alone or DMA plus YM at full volume, with no way
to balance the two in software. In games such as Xenon the
YM sound ends up considerably louder than the DMA samples.
A hardware fix for this was worked out by P. Putnik and is
documented here, along with the rest of the STE DAC work:
exxosforum.co.uk STE DAC fix, LMC section
Command set verified against Hatari src/dmaSnd.c, which
documents the same non-functional mixing modes and carries the
full LMC1992 volume tables.
$FFFF8924.B|RW| - |Microwire Mask Register |STE
===========#==#=======#===============================================#=====
----------------------|Falcon Sound Matrix and CODEC |-----
===========#==#=======#===============================================#=====
$FFFF8930.W|RW|SND_CBO|Crossbar Output Select Controller |F
$FFFF8930 SND_CBO Crossbar source (input) select
Word register, four 4-bit fields, one per source device.
Bit layout from Hatari src/falcon/crossbar.c:
Bits 15-12 A/D Converter
Bits 13-12 clock: 00 = 25.175MHz, 01 = external,
10 = 32MHz (do not use)
Bits 11-8 External Input
Bit 11 0 = DSP IN, 1 = all others
Bits 10-9 clock, as above
Bit 8 0 = handshake on, 1 = handshake off
Bits 7-4 DSP transmit
Bit 7 0 = tristate and disconnect DSP (external SSI
use only), 1 = connect DSP to multiplexer
Bits 6-5 clock, as above
Bit 4 0 = handshake on, 1 = handshake off
Bits 3-0 DMA playback
Bit 3 0 = handshaking on, destination DSP receive
1 = destination is not DSP receive
Bits 2-1 clock, as above
Bit 0 0 = handshake on, 1 = handshake off
Verified against Hatari src/falcon/crossbar.c.
$FFFF8932.W|RW|SND_CBI|Crossbar Input Select Controller |F
$FFFF8932 SND_CBI Crossbar destination (output) select
Word register, four 4-bit fields, one per destination.
Bit layout from Hatari src/falcon/crossbar.c:
In each field the two-bit source selector means:
00 = DMA output 01 = DSP output
10 = External input 11 = ADC input
Bits 15-12 D/A Converter
Bits 13-12 source, as above
Bits 11-8 External output
Bit 11 0 = DSP out, 1 = all others
Bits 10-9 source, as above
Bit 8 0 = handshake on, 1 = handshake off
Bits 7-4 DSP receive
Bit 7 0 = tristate and disconnect DSP (external SSI
use only), 1 = connect DSP to multiplexer
Bits 6-5 source, as above
Bit 4 0 = handshake on, 1 = handshake off
Bits 3-0 DMA record
Bit 3 0 = handshaking on, destination DSP transmit
1 = all
Bits 2-1 source, as above
Bit 0 0 = handshake on, 1 = handshake off
Verified against Hatari src/falcon/crossbar.c.
$FFFF8934.B|RW|SND_FDE|Frequency Divider, External Sync |F
$FFFF8935.B|RW|SND_FDI|Frequency Divider, Internal Sync |F
$FFFF8936.B|RW|SND_RTS|Record Tracks Select |F
$FFFF8937.B|RW|SND_CIS|CODEC Input Source |F
$FFFF8938.B|RW|SND_CAD|CODEC ADC Input |F
$FFFF8939.B|RW|SND_GAI|Gain settings %LLLLRRRR |F
$FFFF893A.W|RW|SND_ATT|Attenuation settings %LLLLRRRR |F
$FFFF893C.W|R-|SND_CST|CODEC Status |F
$FFFF8940.W|RW|SND_GPD|GPIO Data Direction |F
$FFFF8942.W|RW|SND_GPI|GPIO Data |F