YM, DSP & DMA Sound

From Atari Wiki
Revision as of 08:44, 27 July 2026 by Exxos (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
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.





Back to Memory Map for Atari ST,STE,TT and Falcon