2 * QEMU Crystal CS4231 audio chip emulation
4 * Copyright (c) 2006 Fabrice Bellard
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 #include "audio/audio.h"
29 #include "qemu-timer.h"
41 /* #define DEBUG_XLAW */
48 #define dolog(...) AUD_log ("cs4231a", __VA_ARGS__)
53 #define lwarn(...) AUD_log ("cs4231a", "warning: " __VA_ARGS__)
54 #define lerr(...) AUD_log ("cs4231a", "error: " __VA_ARGS__)
59 typedef struct CSState
{
63 uint32_t regs
[CS_REGS
];
64 uint8_t dregs
[CS_DREGS
];
77 #define IO_READ_PROTO(name) \
78 static uint32_t name (void *opaque, uint32_t addr)
80 #define IO_WRITE_PROTO(name) \
81 static void name (void *opaque, uint32_t addr, uint32_t val)
83 #define GET_SADDR(addr) (addr & 3)
85 #define MODE2 (1 << 6)
106 Left_ADC_Input_Control
,
107 Right_ADC_Input_Control
,
108 Left_AUX1_Input_Control
,
109 Right_AUX1_Input_Control
,
110 Left_AUX2_Input_Control
,
111 Right_AUX2_Input_Control
,
112 Left_DAC_Output_Control
,
113 Right_DAC_Output_Control
,
114 FS_And_Playback_Data_Format
,
115 Interface_Configuration
,
117 Error_Status_And_Initialization
,
120 Playback_Upper_Base_Count
,
121 Playback_Lower_Base_Count
,
122 Alternate_Feature_Enable_I
,
123 Alternate_Feature_Enable_II
,
124 Left_Line_Input_Control
,
125 Right_Line_Input_Control
,
129 Alternate_Feature_Enable_III
,
130 Alternate_Feature_Status
,
132 Mono_Input_And_Output_Control
,
136 Capture_Upper_Base_Count
,
137 Capture_Lower_Base_Count
140 static int freqs
[2][8] = {
141 { 8000, 16000, 27420, 32000, -1, -1, 48000, 9000 },
142 { 5510, 11025, 18900, 22050, 37800, 44100, 33075, 6620 }
145 /* Tables courtesy http://hazelware.luggle.com/tutorials/mulawcompression.html */
146 static int16_t MuLawDecompressTable
[256] =
148 -32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956,
149 -23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764,
150 -15996,-15484,-14972,-14460,-13948,-13436,-12924,-12412,
151 -11900,-11388,-10876,-10364, -9852, -9340, -8828, -8316,
152 -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
153 -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
154 -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
155 -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
156 -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
157 -1372, -1308, -1244, -1180, -1116, -1052, -988, -924,
158 -876, -844, -812, -780, -748, -716, -684, -652,
159 -620, -588, -556, -524, -492, -460, -428, -396,
160 -372, -356, -340, -324, -308, -292, -276, -260,
161 -244, -228, -212, -196, -180, -164, -148, -132,
162 -120, -112, -104, -96, -88, -80, -72, -64,
163 -56, -48, -40, -32, -24, -16, -8, 0,
164 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
165 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
166 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
167 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316,
168 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140,
169 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092,
170 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004,
171 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980,
172 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436,
173 1372, 1308, 1244, 1180, 1116, 1052, 988, 924,
174 876, 844, 812, 780, 748, 716, 684, 652,
175 620, 588, 556, 524, 492, 460, 428, 396,
176 372, 356, 340, 324, 308, 292, 276, 260,
177 244, 228, 212, 196, 180, 164, 148, 132,
178 120, 112, 104, 96, 88, 80, 72, 64,
179 56, 48, 40, 32, 24, 16, 8, 0
182 static int16_t ALawDecompressTable
[256] =
184 -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
185 -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
186 -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368,
187 -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392,
188 -22016,-20992,-24064,-23040,-17920,-16896,-19968,-18944,
189 -30208,-29184,-32256,-31232,-26112,-25088,-28160,-27136,
190 -11008,-10496,-12032,-11520,-8960, -8448, -9984, -9472,
191 -15104,-14592,-16128,-15616,-13056,-12544,-14080,-13568,
192 -344, -328, -376, -360, -280, -264, -312, -296,
193 -472, -456, -504, -488, -408, -392, -440, -424,
194 -88, -72, -120, -104, -24, -8, -56, -40,
195 -216, -200, -248, -232, -152, -136, -184, -168,
196 -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184,
197 -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696,
198 -688, -656, -752, -720, -560, -528, -624, -592,
199 -944, -912, -1008, -976, -816, -784, -880, -848,
200 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736,
201 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784,
202 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368,
203 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392,
204 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944,
205 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136,
206 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472,
207 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568,
208 344, 328, 376, 360, 280, 264, 312, 296,
209 472, 456, 504, 488, 408, 392, 440, 424,
210 88, 72, 120, 104, 24, 8, 56, 40,
211 216, 200, 248, 232, 152, 136, 184, 168,
212 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184,
213 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696,
214 688, 656, 752, 720, 560, 528, 624, 592,
215 944, 912, 1008, 976, 816, 784, 880, 848
218 static void cs_reset (void *opaque
)
222 s
->regs
[Index_Address
] = 0x40;
223 s
->regs
[Index_Data
] = 0x00;
224 s
->regs
[Status
] = 0x00;
225 s
->regs
[PIO_Data
] = 0x00;
227 s
->dregs
[Left_ADC_Input_Control
] = 0x00;
228 s
->dregs
[Right_ADC_Input_Control
] = 0x00;
229 s
->dregs
[Left_AUX1_Input_Control
] = 0x88;
230 s
->dregs
[Right_AUX1_Input_Control
] = 0x88;
231 s
->dregs
[Left_AUX2_Input_Control
] = 0x88;
232 s
->dregs
[Right_AUX2_Input_Control
] = 0x88;
233 s
->dregs
[Left_DAC_Output_Control
] = 0x80;
234 s
->dregs
[Right_DAC_Output_Control
] = 0x80;
235 s
->dregs
[FS_And_Playback_Data_Format
] = 0x00;
236 s
->dregs
[Interface_Configuration
] = 0x08;
237 s
->dregs
[Pin_Control
] = 0x00;
238 s
->dregs
[Error_Status_And_Initialization
] = 0x00;
239 s
->dregs
[MODE_And_ID
] = 0x8a;
240 s
->dregs
[Loopback_Control
] = 0x00;
241 s
->dregs
[Playback_Upper_Base_Count
] = 0x00;
242 s
->dregs
[Playback_Lower_Base_Count
] = 0x00;
243 s
->dregs
[Alternate_Feature_Enable_I
] = 0x00;
244 s
->dregs
[Alternate_Feature_Enable_II
] = 0x00;
245 s
->dregs
[Left_Line_Input_Control
] = 0x88;
246 s
->dregs
[Right_Line_Input_Control
] = 0x88;
247 s
->dregs
[Timer_Low_Base
] = 0x00;
248 s
->dregs
[Timer_High_Base
] = 0x00;
249 s
->dregs
[RESERVED
] = 0x00;
250 s
->dregs
[Alternate_Feature_Enable_III
] = 0x00;
251 s
->dregs
[Alternate_Feature_Status
] = 0x00;
252 s
->dregs
[Version_Chip_ID
] = 0xa0;
253 s
->dregs
[Mono_Input_And_Output_Control
] = 0xa0;
254 s
->dregs
[RESERVED_2
] = 0x00;
255 s
->dregs
[Capture_Data_Format
] = 0x00;
256 s
->dregs
[RESERVED_3
] = 0x00;
257 s
->dregs
[Capture_Upper_Base_Count
] = 0x00;
258 s
->dregs
[Capture_Lower_Base_Count
] = 0x00;
261 static void cs_audio_callback (void *opaque
, int free
)
264 s
->audio_free
= free
;
267 static void cs_reset_voices (CSState
*s
, uint32_t val
)
270 struct audsettings as
;
273 if (val
== 0 || val
== 32)
274 val
= (1 << 4) | (1 << 5);
278 as
.freq
= freqs
[xtal
][(val
>> 1) & 7];
281 lerr ("unsupported frequency (val=%#x)\n", val
);
285 as
.nchannels
= (val
& (1 << 4)) ? 2 : 1;
289 switch ((val
>> 5) & ((s
->dregs
[MODE_And_ID
] & MODE2
) ? 7 : 3)) {
292 s
->shift
= as
.nchannels
== 2;
296 s
->tab
= MuLawDecompressTable
;
299 s
->tab
= ALawDecompressTable
;
301 as
.fmt
= AUD_FMT_S16
;
302 as
.endianness
= AUDIO_HOST_ENDIANNESS
;
303 s
->shift
= as
.nchannels
== 2;
309 as
.fmt
= AUD_FMT_S16
;
310 s
->shift
= as
.nchannels
;
315 lerr ("attempt to use reserved format value (%#x)\n", val
);
319 lerr ("ADPCM 4 bit IMA compatible format is not supported\n");
323 s
->voice
= AUD_open_out (
332 if (s
->dregs
[Interface_Configuration
] & PEN
) {
333 if (!s
->dma_running
) {
334 DMA_hold_DREQ (s
->dma
);
335 AUD_set_active_out (s
->voice
, 1);
341 if (s
->dma_running
) {
342 DMA_release_DREQ (s
->dma
);
343 AUD_set_active_out (s
->voice
, 0);
350 if (s
->dma_running
) {
351 DMA_release_DREQ (s
->dma
);
352 AUD_set_active_out (s
->voice
, 0);
356 IO_READ_PROTO (cs_read
)
359 uint32_t saddr
, iaddr
, ret
;
361 saddr
= GET_SADDR (addr
);
366 ret
= s
->regs
[saddr
] & ~0x80;
370 if (!(s
->dregs
[MODE_And_ID
] & MODE2
))
371 iaddr
= s
->regs
[Index_Address
] & 0x0f;
373 iaddr
= s
->regs
[Index_Address
] & 0x1f;
375 ret
= s
->dregs
[iaddr
];
376 if (iaddr
== Error_Status_And_Initialization
) {
377 /* keep SEAL happy */
378 if (s
->aci_counter
) {
386 ret
= s
->regs
[saddr
];
389 dolog ("read %d:%d -> %d\n", saddr
, iaddr
, ret
);
393 IO_WRITE_PROTO (cs_write
)
396 uint32_t saddr
, iaddr
;
398 saddr
= GET_SADDR (addr
);
402 if (!(s
->regs
[Index_Address
] & MCE
) && (val
& MCE
)
403 && (s
->dregs
[Interface_Configuration
] & (3 << 3)))
404 s
->aci_counter
= conf
.aci_counter
;
406 s
->regs
[Index_Address
] = val
& ~(1 << 7);
410 if (!(s
->dregs
[MODE_And_ID
] & MODE2
))
411 iaddr
= s
->regs
[Index_Address
] & 0x0f;
413 iaddr
= s
->regs
[Index_Address
] & 0x1f;
419 lwarn ("attempt to write %#x to reserved indirect register %d\n",
423 case FS_And_Playback_Data_Format
:
424 if (s
->regs
[Index_Address
] & MCE
) {
425 cs_reset_voices (s
, val
);
428 if (s
->dregs
[Alternate_Feature_Status
] & PMCE
) {
429 val
= (val
& ~0x0f) | (s
->dregs
[iaddr
] & 0x0f);
430 cs_reset_voices (s
, val
);
433 lwarn ("[P]MCE(%#x, %#x) is not set, val=%#x\n",
434 s
->regs
[Index_Address
],
435 s
->dregs
[Alternate_Feature_Status
],
440 s
->dregs
[iaddr
] = val
;
443 case Interface_Configuration
:
444 val
&= ~(1 << 5); /* D5 is reserved */
445 s
->dregs
[iaddr
] = val
;
447 lwarn ("PIO is not supported (%#x)\n", val
);
451 if (!s
->dma_running
) {
452 cs_reset_voices (s
, s
->dregs
[FS_And_Playback_Data_Format
]);
456 if (s
->dma_running
) {
457 DMA_release_DREQ (s
->dma
);
458 AUD_set_active_out (s
->voice
, 0);
464 case Error_Status_And_Initialization
:
465 lwarn ("attempt to write to read only register %d\n", iaddr
);
469 dolog ("val=%#x\n", val
);
471 s
->dregs
[iaddr
] |= MODE2
;
473 s
->dregs
[iaddr
] &= ~MODE2
;
476 case Alternate_Feature_Enable_I
:
478 lerr ("timer is not yet supported\n");
479 s
->dregs
[iaddr
] = val
;
482 case Alternate_Feature_Status
:
483 if ((s
->dregs
[iaddr
] & PI
) && !(val
& PI
)) {
485 qemu_irq_lower (s
->pic
);
486 s
->regs
[Status
] &= ~INT
;
488 s
->dregs
[iaddr
] = val
;
491 case Version_Chip_ID
:
492 lwarn ("write to Version_Chip_ID register %#x\n", val
);
493 s
->dregs
[iaddr
] = val
;
497 s
->dregs
[iaddr
] = val
;
500 dolog ("written value %#x to indirect register %d\n", val
, iaddr
);
504 if (s
->regs
[Status
] & INT
) {
505 qemu_irq_lower (s
->pic
);
507 s
->regs
[Status
] &= ~INT
;
508 s
->dregs
[Alternate_Feature_Status
] &= ~(PI
| CI
| TI
);
512 lwarn ("attempt to write value %#x to PIO register\n", val
);
517 static int cs_write_audio (CSState
*s
, int nchan
, int dma_pos
,
518 int dma_len
, int len
)
521 uint8_t tmpbuf
[4096];
527 int left
= dma_len
- dma_pos
;
531 to_copy
= audio_MIN (temp
, left
);
532 if (to_copy
> sizeof (tmpbuf
)) {
533 to_copy
= sizeof (tmpbuf
);
536 copied
= DMA_read_memory (nchan
, tmpbuf
, dma_pos
, to_copy
);
539 int16_t linbuf
[4096];
541 for (i
= 0; i
< copied
; ++i
)
542 linbuf
[i
] = s
->tab
[tmpbuf
[i
]];
543 copied
= AUD_write (s
->voice
, linbuf
, copied
<< 1);
547 copied
= AUD_write (s
->voice
, tmpbuf
, copied
);
551 dma_pos
= (dma_pos
+ copied
) % dma_len
;
562 static int cs_dma_read (void *opaque
, int nchan
, int dma_pos
, int dma_len
)
568 copy
= s
->voice
? (s
->audio_free
>> (s
->tab
!= NULL
)) : dma_len
;
570 if (s
->dregs
[Pin_Control
] & IEN
) {
571 till
= (s
->dregs
[Playback_Lower_Base_Count
]
572 | (s
->dregs
[Playback_Upper_Base_Count
] << 8)) << s
->shift
;
573 till
-= s
->transferred
;
574 copy
= audio_MIN (till
, copy
);
577 if ((copy
<= 0) || (dma_len
<= 0)) {
581 written
= cs_write_audio (s
, nchan
, dma_pos
, dma_len
, copy
);
583 dma_pos
= (dma_pos
+ written
) % dma_len
;
584 s
->audio_free
-= (written
<< (s
->tab
!= NULL
));
586 if (written
== till
) {
587 s
->regs
[Status
] |= INT
;
588 s
->dregs
[Alternate_Feature_Status
] |= PI
;
590 qemu_irq_raise (s
->pic
);
593 s
->transferred
+= written
;
599 static void cs_save (QEMUFile
*f
, void *opaque
)
605 for (i
= 0; i
< CS_REGS
; i
++)
606 qemu_put_be32s (f
, &s
->regs
[i
]);
608 qemu_put_buffer (f
, s
->dregs
, CS_DREGS
);
609 val
= s
->dma_running
; qemu_put_be32s (f
, &val
);
610 val
= s
->audio_free
; qemu_put_be32s (f
, &val
);
611 val
= s
->transferred
; qemu_put_be32s (f
, &val
);
612 val
= s
->aci_counter
; qemu_put_be32s (f
, &val
);
615 static int cs_load (QEMUFile
*f
, void *opaque
, int version_id
)
619 uint32_t val
, dma_running
;
624 for (i
= 0; i
< CS_REGS
; i
++)
625 qemu_get_be32s (f
, &s
->regs
[i
]);
627 qemu_get_buffer (f
, s
->dregs
, CS_DREGS
);
629 qemu_get_be32s (f
, &dma_running
);
630 qemu_get_be32s (f
, &val
); s
->audio_free
= val
;
631 qemu_get_be32s (f
, &val
); s
->transferred
= val
;
632 qemu_get_be32s (f
, &val
); s
->aci_counter
= val
;
633 if (dma_running
&& (s
->dregs
[Interface_Configuration
] & PEN
))
634 cs_reset_voices (s
, s
->dregs
[FS_And_Playback_Data_Format
]);
638 static int cs4231a_initfn (ISADevice
*dev
)
640 CSState
*s
= DO_UPCAST (CSState
, dev
, dev
);
643 isa_init_irq (dev
, &s
->pic
, s
->irq
);
645 for (i
= 0; i
< 4; i
++) {
646 register_ioport_write (s
->port
+ i
, 1, 1, cs_write
, s
);
647 register_ioport_read (s
->port
+ i
, 1, 1, cs_read
, s
);
650 DMA_register_channel (s
->dma
, cs_dma_read
, s
);
652 register_savevm ("cs4231a", 0, 1, cs_save
, cs_load
, s
);
653 qemu_register_reset (cs_reset
, s
);
656 AUD_register_card ("cs4231a", &s
->card
);
660 int cs4231a_init (qemu_irq
*pic
)
662 isa_create_simple ("cs4231a");
666 static ISADeviceInfo cs4231a_info
= {
667 .qdev
.name
= "cs4231a",
668 .qdev
.desc
= "Crystal Semiconductor CS4231A",
669 .qdev
.size
= sizeof (CSState
),
670 .init
= cs4231a_initfn
,
671 .qdev
.props
= (Property
[]) {
672 DEFINE_PROP_HEX32 ("iobase", CSState
, port
, 0x534),
673 DEFINE_PROP_UINT32 ("irq", CSState
, irq
, 9),
674 DEFINE_PROP_UINT32 ("dma", CSState
, dma
, 3),
675 DEFINE_PROP_END_OF_LIST (),
679 static void cs4231a_register (void)
681 isa_qdev_register (&cs4231a_info
);
683 device_init (cs4231a_register
)