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
25 #include "hw/audio/audio.h"
26 #include "audio/audio.h"
27 #include "hw/isa/isa.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
{
64 uint32_t regs
[CS_REGS
];
65 uint8_t dregs
[CS_DREGS
];
78 #define MODE2 (1 << 6)
99 Left_ADC_Input_Control
,
100 Right_ADC_Input_Control
,
101 Left_AUX1_Input_Control
,
102 Right_AUX1_Input_Control
,
103 Left_AUX2_Input_Control
,
104 Right_AUX2_Input_Control
,
105 Left_DAC_Output_Control
,
106 Right_DAC_Output_Control
,
107 FS_And_Playback_Data_Format
,
108 Interface_Configuration
,
110 Error_Status_And_Initialization
,
113 Playback_Upper_Base_Count
,
114 Playback_Lower_Base_Count
,
115 Alternate_Feature_Enable_I
,
116 Alternate_Feature_Enable_II
,
117 Left_Line_Input_Control
,
118 Right_Line_Input_Control
,
122 Alternate_Feature_Enable_III
,
123 Alternate_Feature_Status
,
125 Mono_Input_And_Output_Control
,
129 Capture_Upper_Base_Count
,
130 Capture_Lower_Base_Count
133 static int freqs
[2][8] = {
134 { 8000, 16000, 27420, 32000, -1, -1, 48000, 9000 },
135 { 5510, 11025, 18900, 22050, 37800, 44100, 33075, 6620 }
138 /* Tables courtesy http://hazelware.luggle.com/tutorials/mulawcompression.html */
139 static int16_t MuLawDecompressTable
[256] =
141 -32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956,
142 -23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764,
143 -15996,-15484,-14972,-14460,-13948,-13436,-12924,-12412,
144 -11900,-11388,-10876,-10364, -9852, -9340, -8828, -8316,
145 -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
146 -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
147 -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
148 -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
149 -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
150 -1372, -1308, -1244, -1180, -1116, -1052, -988, -924,
151 -876, -844, -812, -780, -748, -716, -684, -652,
152 -620, -588, -556, -524, -492, -460, -428, -396,
153 -372, -356, -340, -324, -308, -292, -276, -260,
154 -244, -228, -212, -196, -180, -164, -148, -132,
155 -120, -112, -104, -96, -88, -80, -72, -64,
156 -56, -48, -40, -32, -24, -16, -8, 0,
157 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
158 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
159 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
160 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316,
161 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140,
162 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092,
163 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004,
164 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980,
165 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436,
166 1372, 1308, 1244, 1180, 1116, 1052, 988, 924,
167 876, 844, 812, 780, 748, 716, 684, 652,
168 620, 588, 556, 524, 492, 460, 428, 396,
169 372, 356, 340, 324, 308, 292, 276, 260,
170 244, 228, 212, 196, 180, 164, 148, 132,
171 120, 112, 104, 96, 88, 80, 72, 64,
172 56, 48, 40, 32, 24, 16, 8, 0
175 static int16_t ALawDecompressTable
[256] =
177 -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
178 -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
179 -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368,
180 -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392,
181 -22016,-20992,-24064,-23040,-17920,-16896,-19968,-18944,
182 -30208,-29184,-32256,-31232,-26112,-25088,-28160,-27136,
183 -11008,-10496,-12032,-11520,-8960, -8448, -9984, -9472,
184 -15104,-14592,-16128,-15616,-13056,-12544,-14080,-13568,
185 -344, -328, -376, -360, -280, -264, -312, -296,
186 -472, -456, -504, -488, -408, -392, -440, -424,
187 -88, -72, -120, -104, -24, -8, -56, -40,
188 -216, -200, -248, -232, -152, -136, -184, -168,
189 -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184,
190 -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696,
191 -688, -656, -752, -720, -560, -528, -624, -592,
192 -944, -912, -1008, -976, -816, -784, -880, -848,
193 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736,
194 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784,
195 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368,
196 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392,
197 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944,
198 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136,
199 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472,
200 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568,
201 344, 328, 376, 360, 280, 264, 312, 296,
202 472, 456, 504, 488, 408, 392, 440, 424,
203 88, 72, 120, 104, 24, 8, 56, 40,
204 216, 200, 248, 232, 152, 136, 184, 168,
205 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184,
206 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696,
207 688, 656, 752, 720, 560, 528, 624, 592,
208 944, 912, 1008, 976, 816, 784, 880, 848
211 static void cs_reset (void *opaque
)
215 s
->regs
[Index_Address
] = 0x40;
216 s
->regs
[Index_Data
] = 0x00;
217 s
->regs
[Status
] = 0x00;
218 s
->regs
[PIO_Data
] = 0x00;
220 s
->dregs
[Left_ADC_Input_Control
] = 0x00;
221 s
->dregs
[Right_ADC_Input_Control
] = 0x00;
222 s
->dregs
[Left_AUX1_Input_Control
] = 0x88;
223 s
->dregs
[Right_AUX1_Input_Control
] = 0x88;
224 s
->dregs
[Left_AUX2_Input_Control
] = 0x88;
225 s
->dregs
[Right_AUX2_Input_Control
] = 0x88;
226 s
->dregs
[Left_DAC_Output_Control
] = 0x80;
227 s
->dregs
[Right_DAC_Output_Control
] = 0x80;
228 s
->dregs
[FS_And_Playback_Data_Format
] = 0x00;
229 s
->dregs
[Interface_Configuration
] = 0x08;
230 s
->dregs
[Pin_Control
] = 0x00;
231 s
->dregs
[Error_Status_And_Initialization
] = 0x00;
232 s
->dregs
[MODE_And_ID
] = 0x8a;
233 s
->dregs
[Loopback_Control
] = 0x00;
234 s
->dregs
[Playback_Upper_Base_Count
] = 0x00;
235 s
->dregs
[Playback_Lower_Base_Count
] = 0x00;
236 s
->dregs
[Alternate_Feature_Enable_I
] = 0x00;
237 s
->dregs
[Alternate_Feature_Enable_II
] = 0x00;
238 s
->dregs
[Left_Line_Input_Control
] = 0x88;
239 s
->dregs
[Right_Line_Input_Control
] = 0x88;
240 s
->dregs
[Timer_Low_Base
] = 0x00;
241 s
->dregs
[Timer_High_Base
] = 0x00;
242 s
->dregs
[RESERVED
] = 0x00;
243 s
->dregs
[Alternate_Feature_Enable_III
] = 0x00;
244 s
->dregs
[Alternate_Feature_Status
] = 0x00;
245 s
->dregs
[Version_Chip_ID
] = 0xa0;
246 s
->dregs
[Mono_Input_And_Output_Control
] = 0xa0;
247 s
->dregs
[RESERVED_2
] = 0x00;
248 s
->dregs
[Capture_Data_Format
] = 0x00;
249 s
->dregs
[RESERVED_3
] = 0x00;
250 s
->dregs
[Capture_Upper_Base_Count
] = 0x00;
251 s
->dregs
[Capture_Lower_Base_Count
] = 0x00;
254 static void cs_audio_callback (void *opaque
, int free
)
257 s
->audio_free
= free
;
260 static void cs_reset_voices (CSState
*s
, uint32_t val
)
263 struct audsettings as
;
266 if (val
== 0 || val
== 32)
267 val
= (1 << 4) | (1 << 5);
271 as
.freq
= freqs
[xtal
][(val
>> 1) & 7];
274 lerr ("unsupported frequency (val=%#x)\n", val
);
278 as
.nchannels
= (val
& (1 << 4)) ? 2 : 1;
282 switch ((val
>> 5) & ((s
->dregs
[MODE_And_ID
] & MODE2
) ? 7 : 3)) {
285 s
->shift
= as
.nchannels
== 2;
289 s
->tab
= MuLawDecompressTable
;
292 s
->tab
= ALawDecompressTable
;
294 as
.fmt
= AUD_FMT_S16
;
295 as
.endianness
= AUDIO_HOST_ENDIANNESS
;
296 s
->shift
= as
.nchannels
== 2;
302 as
.fmt
= AUD_FMT_S16
;
303 s
->shift
= as
.nchannels
;
308 lerr ("attempt to use reserved format value (%#x)\n", val
);
312 lerr ("ADPCM 4 bit IMA compatible format is not supported\n");
316 s
->voice
= AUD_open_out (
325 if (s
->dregs
[Interface_Configuration
] & PEN
) {
326 if (!s
->dma_running
) {
327 DMA_hold_DREQ (s
->dma
);
328 AUD_set_active_out (s
->voice
, 1);
334 if (s
->dma_running
) {
335 DMA_release_DREQ (s
->dma
);
336 AUD_set_active_out (s
->voice
, 0);
343 if (s
->dma_running
) {
344 DMA_release_DREQ (s
->dma
);
345 AUD_set_active_out (s
->voice
, 0);
349 static uint64_t cs_read (void *opaque
, hwaddr addr
, unsigned size
)
352 uint32_t saddr
, iaddr
, ret
;
359 ret
= s
->regs
[saddr
] & ~0x80;
363 if (!(s
->dregs
[MODE_And_ID
] & MODE2
))
364 iaddr
= s
->regs
[Index_Address
] & 0x0f;
366 iaddr
= s
->regs
[Index_Address
] & 0x1f;
368 ret
= s
->dregs
[iaddr
];
369 if (iaddr
== Error_Status_And_Initialization
) {
370 /* keep SEAL happy */
371 if (s
->aci_counter
) {
379 ret
= s
->regs
[saddr
];
382 dolog ("read %d:%d -> %d\n", saddr
, iaddr
, ret
);
386 static void cs_write (void *opaque
, hwaddr addr
,
387 uint64_t val64
, unsigned size
)
390 uint32_t saddr
, iaddr
, val
;
397 if (!(s
->regs
[Index_Address
] & MCE
) && (val
& MCE
)
398 && (s
->dregs
[Interface_Configuration
] & (3 << 3)))
399 s
->aci_counter
= conf
.aci_counter
;
401 s
->regs
[Index_Address
] = val
& ~(1 << 7);
405 if (!(s
->dregs
[MODE_And_ID
] & MODE2
))
406 iaddr
= s
->regs
[Index_Address
] & 0x0f;
408 iaddr
= s
->regs
[Index_Address
] & 0x1f;
414 lwarn ("attempt to write %#x to reserved indirect register %d\n",
418 case FS_And_Playback_Data_Format
:
419 if (s
->regs
[Index_Address
] & MCE
) {
420 cs_reset_voices (s
, val
);
423 if (s
->dregs
[Alternate_Feature_Status
] & PMCE
) {
424 val
= (val
& ~0x0f) | (s
->dregs
[iaddr
] & 0x0f);
425 cs_reset_voices (s
, val
);
428 lwarn ("[P]MCE(%#x, %#x) is not set, val=%#x\n",
429 s
->regs
[Index_Address
],
430 s
->dregs
[Alternate_Feature_Status
],
435 s
->dregs
[iaddr
] = val
;
438 case Interface_Configuration
:
439 val
&= ~(1 << 5); /* D5 is reserved */
440 s
->dregs
[iaddr
] = val
;
442 lwarn ("PIO is not supported (%#x)\n", val
);
446 if (!s
->dma_running
) {
447 cs_reset_voices (s
, s
->dregs
[FS_And_Playback_Data_Format
]);
451 if (s
->dma_running
) {
452 DMA_release_DREQ (s
->dma
);
453 AUD_set_active_out (s
->voice
, 0);
459 case Error_Status_And_Initialization
:
460 lwarn ("attempt to write to read only register %d\n", iaddr
);
464 dolog ("val=%#x\n", val
);
466 s
->dregs
[iaddr
] |= MODE2
;
468 s
->dregs
[iaddr
] &= ~MODE2
;
471 case Alternate_Feature_Enable_I
:
473 lerr ("timer is not yet supported\n");
474 s
->dregs
[iaddr
] = val
;
477 case Alternate_Feature_Status
:
478 if ((s
->dregs
[iaddr
] & PI
) && !(val
& PI
)) {
480 qemu_irq_lower (s
->pic
);
481 s
->regs
[Status
] &= ~INT
;
483 s
->dregs
[iaddr
] = val
;
486 case Version_Chip_ID
:
487 lwarn ("write to Version_Chip_ID register %#x\n", val
);
488 s
->dregs
[iaddr
] = val
;
492 s
->dregs
[iaddr
] = val
;
495 dolog ("written value %#x to indirect register %d\n", val
, iaddr
);
499 if (s
->regs
[Status
] & INT
) {
500 qemu_irq_lower (s
->pic
);
502 s
->regs
[Status
] &= ~INT
;
503 s
->dregs
[Alternate_Feature_Status
] &= ~(PI
| CI
| TI
);
507 lwarn ("attempt to write value %#x to PIO register\n", val
);
512 static int cs_write_audio (CSState
*s
, int nchan
, int dma_pos
,
513 int dma_len
, int len
)
516 uint8_t tmpbuf
[4096];
522 int left
= dma_len
- dma_pos
;
526 to_copy
= audio_MIN (temp
, left
);
527 if (to_copy
> sizeof (tmpbuf
)) {
528 to_copy
= sizeof (tmpbuf
);
531 copied
= DMA_read_memory (nchan
, tmpbuf
, dma_pos
, to_copy
);
534 int16_t linbuf
[4096];
536 for (i
= 0; i
< copied
; ++i
)
537 linbuf
[i
] = s
->tab
[tmpbuf
[i
]];
538 copied
= AUD_write (s
->voice
, linbuf
, copied
<< 1);
542 copied
= AUD_write (s
->voice
, tmpbuf
, copied
);
546 dma_pos
= (dma_pos
+ copied
) % dma_len
;
557 static int cs_dma_read (void *opaque
, int nchan
, int dma_pos
, int dma_len
)
563 copy
= s
->voice
? (s
->audio_free
>> (s
->tab
!= NULL
)) : dma_len
;
565 if (s
->dregs
[Pin_Control
] & IEN
) {
566 till
= (s
->dregs
[Playback_Lower_Base_Count
]
567 | (s
->dregs
[Playback_Upper_Base_Count
] << 8)) << s
->shift
;
568 till
-= s
->transferred
;
569 copy
= audio_MIN (till
, copy
);
572 if ((copy
<= 0) || (dma_len
<= 0)) {
576 written
= cs_write_audio (s
, nchan
, dma_pos
, dma_len
, copy
);
578 dma_pos
= (dma_pos
+ written
) % dma_len
;
579 s
->audio_free
-= (written
<< (s
->tab
!= NULL
));
581 if (written
== till
) {
582 s
->regs
[Status
] |= INT
;
583 s
->dregs
[Alternate_Feature_Status
] |= PI
;
585 qemu_irq_raise (s
->pic
);
588 s
->transferred
+= written
;
594 static int cs4231a_pre_load (void *opaque
)
598 if (s
->dma_running
) {
599 DMA_release_DREQ (s
->dma
);
600 AUD_set_active_out (s
->voice
, 0);
606 static int cs4231a_post_load (void *opaque
, int version_id
)
610 if (s
->dma_running
&& (s
->dregs
[Interface_Configuration
] & PEN
)) {
612 cs_reset_voices (s
, s
->dregs
[FS_And_Playback_Data_Format
]);
617 static const VMStateDescription vmstate_cs4231a
= {
620 .minimum_version_id
= 1,
621 .minimum_version_id_old
= 1,
622 .pre_load
= cs4231a_pre_load
,
623 .post_load
= cs4231a_post_load
,
624 .fields
= (VMStateField
[]) {
625 VMSTATE_UINT32_ARRAY (regs
, CSState
, CS_REGS
),
626 VMSTATE_BUFFER (dregs
, CSState
),
627 VMSTATE_INT32 (dma_running
, CSState
),
628 VMSTATE_INT32 (audio_free
, CSState
),
629 VMSTATE_INT32 (transferred
, CSState
),
630 VMSTATE_INT32 (aci_counter
, CSState
),
631 VMSTATE_END_OF_LIST ()
635 static const MemoryRegionOps cs_ioport_ops
= {
639 .min_access_size
= 1,
640 .max_access_size
= 1,
644 static int cs4231a_initfn (ISADevice
*dev
)
646 CSState
*s
= DO_UPCAST (CSState
, dev
, dev
);
648 isa_init_irq (dev
, &s
->pic
, s
->irq
);
650 memory_region_init_io (&s
->ioports
, &cs_ioport_ops
, s
, "cs4231a", 4);
651 isa_register_ioport (dev
, &s
->ioports
, s
->port
);
653 DMA_register_channel (s
->dma
, cs_dma_read
, s
);
655 qemu_register_reset (cs_reset
, s
);
658 AUD_register_card ("cs4231a", &s
->card
);
662 static int cs4231a_init (ISABus
*bus
)
664 isa_create_simple (bus
, "cs4231a");
668 static Property cs4231a_properties
[] = {
669 DEFINE_PROP_HEX32 ("iobase", CSState
, port
, 0x534),
670 DEFINE_PROP_UINT32 ("irq", CSState
, irq
, 9),
671 DEFINE_PROP_UINT32 ("dma", CSState
, dma
, 3),
672 DEFINE_PROP_END_OF_LIST (),
675 static void cs4231a_class_initfn (ObjectClass
*klass
, void *data
)
677 DeviceClass
*dc
= DEVICE_CLASS (klass
);
678 ISADeviceClass
*ic
= ISA_DEVICE_CLASS (klass
);
679 ic
->init
= cs4231a_initfn
;
680 dc
->desc
= "Crystal Semiconductor CS4231A";
681 dc
->vmsd
= &vmstate_cs4231a
;
682 dc
->props
= cs4231a_properties
;
685 static const TypeInfo cs4231a_info
= {
687 .parent
= TYPE_ISA_DEVICE
,
688 .instance_size
= sizeof (CSState
),
689 .class_init
= cs4231a_class_initfn
,
692 static void cs4231a_register_types (void)
694 type_register_static (&cs4231a_info
);
695 isa_register_soundhw("cs4231a", "CS4231A", cs4231a_init
);
698 type_init (cs4231a_register_types
)