YM, DSP & DMA Sound
Jump to navigation
Jump to search
===========#==#=======#===============================================#=====
----------------------|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
The resulting waveforms (F030/CT60 listing):
00xx \____________ (falls once, silence)
01xx /|___________ (rises once, silence)
1000 \|\|\|\|\|\|\ (repeating falls)
1001 \____________ (falls once, silence)
1010 \/\/\/\/\/\/\ (falling triangle)
1011 \|----------- (falls once, holds at maximum)
1100 /|/|/|/|/|/|/ (repeating rises)
1101 /------------ (rises once, holds at maximum)
1110 /\/\/\/\/\/\/ (rising triangle)
1111 /|___________ (rises once, silence)
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.
$FFFF8804.B|RW| - |Add-on sound, not present on stock hardware |*
$FFFF8804 to $FFFF8808 Add-on sound registers
Not present on stock Atari hardware. $FFFF8800 and $FFFF8802 are
the YM2149 select and data registers; some add-on boards extend
the decoded range upward to $FFFF8808 for their own sound
hardware.
Known to be used by: SEC Booster.
IMPORTANT, FALCON: these addresses do NOT behave this way on a
Falcon. On that machine the PSG registers are fixed at $FFFF8800
and $FFFF8802 only, and every other address in the range is
masked out. Any write to the shadow registers $FFFF8804 to
$FFFF88FF will cause a BUS ERROR.
So an add-on using this range works on the ST and STE, where the
PSG address decoding is incomplete and the registers repeat
through the range, but the same code will bus error on a Falcon.
Anything writing here should check the machine type first.
Source: the Atari F030 and CT60 Hardware Register Listing, which
states the shadow registers are masked out and warns game and
demo coders specifically.
Extended bit information is not currently available for these
registers. The addresses are documented; what each bit does is
not.
$FFFF8806.B|RW| - |Add-on sound, not present on stock hardware |*
$FFFF8808.B|RW| - |Add-on sound, not present on stock hardware |*
===========#==#=======#===============================================#=====
----------------------|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.
The two halves are separate byte registers, $FFFF8900 (event
bits) and $FFFF8901 (frame select and enable/loop bits), and
the Aura and FALREG listings document them per byte. Bit 7 of
$FFFF8901 selects whether the frame address registers at
$FFFF8903-13 access the PLAY set (0) or the RECORD set (1):
they are two separate register sets appearing at the same
addresses.
Sample data interleaving in the frame buffer, per the
F030/CT60 listing:
8 bit stereo: LRLRLRLR
16 bit stereo: LLRRLLRR (one word per channel)
2 track 16 bit stereo: LLRRllrr (track 1 then track 2)
$FFFF8903.B|RW|SND_FSH|Frame Start Hi |F,STE
$FFFF8903 / $FFFF8905 / $FFFF8907 Frame Start address
Three byte registers holding a 24 bit address:
$FFFF8903 bits 23-16, high
$FFFF8905 bits 15-8, middle
$FFFF8907 bits 7-0, low
The address of the first byte of sample data. Bit 0 of the low
byte is ignored: the DMA fetches on even addresses only, so the
frame must start word aligned.
On the Falcon, bit 7 of $FFFF8900 selects whether these
registers address the play frame or the record frame.
Loaded into the DMA counter when playback starts, and reloaded
from here on each repeat if the loop bit is set.
$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
$FFFF8909 / $FFFF890B / $FFFF890D Frame Count
Three byte registers holding the current 24 bit DMA address:
$FFFF8909 bits 23-16, high
$FFFF890B bits 15-8, middle
$FFFF890D bits 7-0, low
Read these while playing to find how far through the sample the
DMA has reached. The value advances from the frame start toward
the frame end.
Reading the three bytes is not atomic, so the counter can move
between reads. Read high, middle then low and re-read if the
high byte changed, or read with interrupts disabled.
Hatari tracks this internally as frameCounterAddr, refilling
its FIFO from that address as playback advances.
$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
$FFFF890F / $FFFF8911 / $FFFF8913 Frame End address
Three byte registers holding a 24 bit address:
$FFFF890F bits 23-16, high
$FFFF8911 bits 15-8, middle
$FFFF8913 bits 7-0, low
The address one past the last byte of sample data. Playback
stops when the frame counter reaches this value.
If the loop bit in $FFFF8900 is set, the counter reloads from
the frame start registers and playback continues. If not,
playback stops and the enable bit clears.
As with the start address, bit 0 of the low byte is ignored.
$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
$FFFF8924 Microwire Mask Register
Works with the data register at $FFFF8922. The mask marks which
bits of the data word are the command; the hardware shifts both
registers out together over the Microwire serial link to the
LMC1992.
The usual value is $07FF, an 11 bit command window matching the
10 CCC DDD DDD command format described at $FFFF8922.
Behaviour during a transfer, per Hatari src/dmaSnd.c:
- The data register shifts left one bit per step.
- The mask register ROTATES left rather than shifting, so
after a complete transfer it reads back as it started.
- One shift takes 8 CPU cycles, so a full 16 step transfer
takes 128 cycles.
Because the mask rotates back to its original value, reading it
is not a reliable way to tell whether a transfer has finished.
The data register shifting to zero is the usable indicator.
Verified against Hatari src/dmaSnd.c.
===========#==#=======#===============================================#=====
----------------------|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
$FFFF8934 SND_FDE Frequency Divider, External Sync
Bits 3-0 divider for the external clock:
0000 = STe compatible mode
0001 to 1111 = divide the external clock by 256, then by
this value
(value table from the F030/CT60 listing)
Clock divider used when the crossbar is set to take an external
clock. Hatari accepts writes here but the value only matters
when an external clock source is actually connected, which on
a standard Falcon it is not.
See $FFFF8930 and $FFFF8932 for the clock and source selection
that decides whether this register is used at all.
$FFFF8935.B|RW|SND_FDI|Frequency Divider, Internal Sync |F
$FFFF8935 SND_FDI Frequency Divider, Internal Sync
Bits 3-0 clock divider, 0-15
Bits 7-4 unused
Divides the selected internal clock (25.175MHz or 32MHz, chosen
per device in $FFFF8930) down to the sample rate. Together with
the clock choice and the number of active tracks this sets the
actual playback frequency.
Sample rates with the standard 25.175MHz clock, per the
F030/CT60 listing (* = invalid for the CODEC):
0000 STe compatible mode 1000 10927Hz *
0001 49170Hz 1001 9834Hz
0010 32780Hz 1010 8940Hz *
0011 24585Hz 1011 8195Hz
0100 19668Hz 1100 7565Hz *
0101 16390Hz 1101 7024Hz *
0110 14049Hz * 1110 6556Hz *
0111 12292Hz 1111 6146Hz *
Verified against Hatari src/falcon/crossbar.c, which masks the
written value with 0x0F and recalculates the clock cycles.
$FFFF8936.B|RW|SND_RTS|Record Tracks Select |F
$FFFF8936 SND_RTS Record Tracks Select
Bits 1-0 number of tracks to record
0 = 1 track
1 = 2 tracks
2 = 3 tracks
3 = 4 tracks
Bits 7-2 unused
Verified against Hatari src/falcon/crossbar.c.
$FFFF8937.B|RW|SND_CIS|CODEC Input Source |F
$FFFF8937 SND_CIS CODEC Input Source
Bit 1 source = multiplexer (the crossbar)
Bit 0 source = A/D converter
Bits 7-2 unused
Selects what feeds the CODEC's 16 bit adder. Both bits can be
set, which sums the two sources.
Verified against Hatari src/falcon/crossbar.c.
$FFFF8938.B|RW|SND_CAD|CODEC ADC Input |F
$FFFF8938 SND_CAD CODEC ADC Input
Bit 1 Left channel 0 = microphone, 1 = PSG (YM2149)
Bit 0 Right channel 0 = microphone, 1 = PSG (YM2149)
Bits 7-2 unused
This is how the Falcon routes the YM2149 output into the ADC so
it can be mixed digitally, rather than through the analogue
path the STE uses.
Verified against Hatari src/falcon/crossbar.c.
$FFFF8939.B|RW|SND_GAI|Gain settings %LLLLRRRR |F
$FFFF8939 SND_GAI Gain settings, input amplifier
Bits 7-4 Left channel gain, 0-15
Bits 3-0 Right channel gain, 0-15
Amplification for the ADC input, in +1.5dB steps per increment.
Verified against Hatari src/falcon/crossbar.c, which indexes
its ADC volume table with (value >> 4) for left and (value & 15)
for right.
$FFFF893A.W|RW|SND_ATT|Attenuation settings %LLLLRRRR |F
$FFFF893A SND_ATT Attenuation settings, output reduction
Word register:
Bits 11-8 Left channel attenuation, 0-15
Bits 7-4 Right channel attenuation, 0-15
Bits 15-12 and 3-0 unused
Reduction for the DAC output, in -1.5dB steps per increment.
Note the field positions: this is not the same layout as the
gain register at $FFFF8939. Hatari reads left from
(value >> 8) & 0x0F and right from (value >> 4) & 0x0F.
Verified against Hatari src/falcon/crossbar.c.
$FFFF893C.W|R-|SND_CST|CODEC Status |F
$FFFF893C SND_CST CODEC Status
Bit 1 Left channel overflow
Bit 0 Right channel overflow
Bits 15-2 unused
Overflow flags set when the CODEC input clips. Read only in
practice, though Hatari accepts writes.
This register is absent from the Atari Compendium listing and
was found in Hatari and EmuTOS. EmuTOS bios/dmasound.c sets it
to $003F on reset.
FALREG.TXT additionally records bits 7-4 of the low byte
($FFFF893D) as present but of unknown function, marked "?"
even by that document's authors. The Aura FALC2.TXT listing
also notes bytes $FFFF893E/$FFFF893F reading back non zero
($81/$00) but never accessed by the XBIOS; Hatari maps
$FFFF893E as a no-bus-error filler, not a register.
Verified against Hatari src/falcon/crossbar.c.
$FFFF8940.W|RW|SND_GPD|GPIO Data Direction |F
$FFFF8940 SND_GPD GPIO Data Direction
Bits 2-0 direction for the three general purpose I/O pins
0 = input, 1 = output
Bits 15-3 unused
Three GPIO pins are brought out on the Falcon's DSP connector.
They are not used by TOS beyond initialisation and are free
for expansion hardware.
VERIFIED as a word register at the even address: Atari TOS
3.06 startup.S does move.w #7,($FFFF8940).w, with the comment
that the Sparrow GPIO pins have no pull resistors, setting
all three pins to output (%111, the default value FALREG.TXT
records). Hatari models words at $FFFF8940 and $FFFF8942.
Some listings (FALREG.TXT, the F030/CT60 page) give these
registers at the ODD addresses $FFFF8941 and $FFFF8943. That
is because the three implemented bits sit in the low byte of
each word; the registers themselves are the even words
documented here. Do not relocate them.
$FFFF8942.W|RW|SND_GPI|GPIO Data |F
$FFFF8942 SND_GPI GPIO Data
Bits 2-0 data for the three general purpose I/O pins
Bits 15-3 unused
Reads the pin state for pins set as inputs at $FFFF8940, and
drives the pin for those set as outputs.
UNVERIFIED: address confirmed by the Atari Compendium, but the
bit detail here is not corroborated by Hatari or EmuTOS.