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 #define TYPE_CS4231A "cs4231a"
60 #define CS4231A(obj) OBJECT_CHECK (CSState, (obj), TYPE_CS4231A)
62 typedef struct CSState
{
67 uint32_t regs
[CS_REGS
];
68 uint8_t dregs
[CS_DREGS
];
81 #define MODE2 (1 << 6)
102 Left_ADC_Input_Control
,
103 Right_ADC_Input_Control
,
104 Left_AUX1_Input_Control
,
105 Right_AUX1_Input_Control
,
106 Left_AUX2_Input_Control
,
107 Right_AUX2_Input_Control
,
108 Left_DAC_Output_Control
,
109 Right_DAC_Output_Control
,
110 FS_And_Playback_Data_Format
,
111 Interface_Configuration
,
113 Error_Status_And_Initialization
,
116 Playback_Upper_Base_Count
,
117 Playback_Lower_Base_Count
,
118 Alternate_Feature_Enable_I
,
119 Alternate_Feature_Enable_II
,
120 Left_Line_Input_Control
,
121 Right_Line_Input_Control
,
125 Alternate_Feature_Enable_III
,
126 Alternate_Feature_Status
,
128 Mono_Input_And_Output_Control
,
132 Capture_Upper_Base_Count
,
133 Capture_Lower_Base_Count
136 static int freqs
[2][8] = {
137 { 8000, 16000, 27420, 32000, -1, -1, 48000, 9000 },
138 { 5510, 11025, 18900, 22050, 37800, 44100, 33075, 6620 }
141 /* Tables courtesy http://hazelware.luggle.com/tutorials/mulawcompression.html */
142 static int16_t MuLawDecompressTable
[256] =
144 -32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956,
145 -23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764,
146 -15996,-15484,-14972,-14460,-13948,-13436,-12924,-12412,
147 -11900,-11388,-10876,-10364, -9852, -9340, -8828, -8316,
148 -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
149 -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
150 -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
151 -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
152 -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
153 -1372, -1308, -1244, -1180, -1116, -1052, -988, -924,
154 -876, -844, -812, -780, -748, -716, -684, -652,
155 -620, -588, -556, -524, -492, -460, -428, -396,
156 -372, -356, -340, -324, -308, -292, -276, -260,
157 -244, -228, -212, -196, -180, -164, -148, -132,
158 -120, -112, -104, -96, -88, -80, -72, -64,
159 -56, -48, -40, -32, -24, -16, -8, 0,
160 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
161 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
162 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
163 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316,
164 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140,
165 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092,
166 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004,
167 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980,
168 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436,
169 1372, 1308, 1244, 1180, 1116, 1052, 988, 924,
170 876, 844, 812, 780, 748, 716, 684, 652,
171 620, 588, 556, 524, 492, 460, 428, 396,
172 372, 356, 340, 324, 308, 292, 276, 260,
173 244, 228, 212, 196, 180, 164, 148, 132,
174 120, 112, 104, 96, 88, 80, 72, 64,
175 56, 48, 40, 32, 24, 16, 8, 0
178 static int16_t ALawDecompressTable
[256] =
180 -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
181 -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
182 -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368,
183 -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392,
184 -22016,-20992,-24064,-23040,-17920,-16896,-19968,-18944,
185 -30208,-29184,-32256,-31232,-26112,-25088,-28160,-27136,
186 -11008,-10496,-12032,-11520,-8960, -8448, -9984, -9472,
187 -15104,-14592,-16128,-15616,-13056,-12544,-14080,-13568,
188 -344, -328, -376, -360, -280, -264, -312, -296,
189 -472, -456, -504, -488, -408, -392, -440, -424,
190 -88, -72, -120, -104, -24, -8, -56, -40,
191 -216, -200, -248, -232, -152, -136, -184, -168,
192 -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184,
193 -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696,
194 -688, -656, -752, -720, -560, -528, -624, -592,
195 -944, -912, -1008, -976, -816, -784, -880, -848,
196 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736,
197 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784,
198 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368,
199 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392,
200 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944,
201 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136,
202 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472,
203 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568,
204 344, 328, 376, 360, 280, 264, 312, 296,
205 472, 456, 504, 488, 408, 392, 440, 424,
206 88, 72, 120, 104, 24, 8, 56, 40,
207 216, 200, 248, 232, 152, 136, 184, 168,
208 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184,
209 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696,
210 688, 656, 752, 720, 560, 528, 624, 592,
211 944, 912, 1008, 976, 816, 784, 880, 848
214 static void cs4231a_reset (DeviceState
*dev
)
216 CSState
*s
= CS4231A (dev
);
218 s
->regs
[Index_Address
] = 0x40;
219 s
->regs
[Index_Data
] = 0x00;
220 s
->regs
[Status
] = 0x00;
221 s
->regs
[PIO_Data
] = 0x00;
223 s
->dregs
[Left_ADC_Input_Control
] = 0x00;
224 s
->dregs
[Right_ADC_Input_Control
] = 0x00;
225 s
->dregs
[Left_AUX1_Input_Control
] = 0x88;
226 s
->dregs
[Right_AUX1_Input_Control
] = 0x88;
227 s
->dregs
[Left_AUX2_Input_Control
] = 0x88;
228 s
->dregs
[Right_AUX2_Input_Control
] = 0x88;
229 s
->dregs
[Left_DAC_Output_Control
] = 0x80;
230 s
->dregs
[Right_DAC_Output_Control
] = 0x80;
231 s
->dregs
[FS_And_Playback_Data_Format
] = 0x00;
232 s
->dregs
[Interface_Configuration
] = 0x08;
233 s
->dregs
[Pin_Control
] = 0x00;
234 s
->dregs
[Error_Status_And_Initialization
] = 0x00;
235 s
->dregs
[MODE_And_ID
] = 0x8a;
236 s
->dregs
[Loopback_Control
] = 0x00;
237 s
->dregs
[Playback_Upper_Base_Count
] = 0x00;
238 s
->dregs
[Playback_Lower_Base_Count
] = 0x00;
239 s
->dregs
[Alternate_Feature_Enable_I
] = 0x00;
240 s
->dregs
[Alternate_Feature_Enable_II
] = 0x00;
241 s
->dregs
[Left_Line_Input_Control
] = 0x88;
242 s
->dregs
[Right_Line_Input_Control
] = 0x88;
243 s
->dregs
[Timer_Low_Base
] = 0x00;
244 s
->dregs
[Timer_High_Base
] = 0x00;
245 s
->dregs
[RESERVED
] = 0x00;
246 s
->dregs
[Alternate_Feature_Enable_III
] = 0x00;
247 s
->dregs
[Alternate_Feature_Status
] = 0x00;
248 s
->dregs
[Version_Chip_ID
] = 0xa0;
249 s
->dregs
[Mono_Input_And_Output_Control
] = 0xa0;
250 s
->dregs
[RESERVED_2
] = 0x00;
251 s
->dregs
[Capture_Data_Format
] = 0x00;
252 s
->dregs
[RESERVED_3
] = 0x00;
253 s
->dregs
[Capture_Upper_Base_Count
] = 0x00;
254 s
->dregs
[Capture_Lower_Base_Count
] = 0x00;
257 static void cs_audio_callback (void *opaque
, int free
)
260 s
->audio_free
= free
;
263 static void cs_reset_voices (CSState
*s
, uint32_t val
)
266 struct audsettings as
;
269 if (val
== 0 || val
== 32)
270 val
= (1 << 4) | (1 << 5);
274 as
.freq
= freqs
[xtal
][(val
>> 1) & 7];
277 lerr ("unsupported frequency (val=%#x)\n", val
);
281 as
.nchannels
= (val
& (1 << 4)) ? 2 : 1;
285 switch ((val
>> 5) & ((s
->dregs
[MODE_And_ID
] & MODE2
) ? 7 : 3)) {
288 s
->shift
= as
.nchannels
== 2;
292 s
->tab
= MuLawDecompressTable
;
295 s
->tab
= ALawDecompressTable
;
297 as
.fmt
= AUD_FMT_S16
;
298 as
.endianness
= AUDIO_HOST_ENDIANNESS
;
299 s
->shift
= as
.nchannels
== 2;
305 as
.fmt
= AUD_FMT_S16
;
306 s
->shift
= as
.nchannels
;
311 lerr ("attempt to use reserved format value (%#x)\n", val
);
315 lerr ("ADPCM 4 bit IMA compatible format is not supported\n");
319 s
->voice
= AUD_open_out (
328 if (s
->dregs
[Interface_Configuration
] & PEN
) {
329 if (!s
->dma_running
) {
330 DMA_hold_DREQ (s
->dma
);
331 AUD_set_active_out (s
->voice
, 1);
337 if (s
->dma_running
) {
338 DMA_release_DREQ (s
->dma
);
339 AUD_set_active_out (s
->voice
, 0);
346 if (s
->dma_running
) {
347 DMA_release_DREQ (s
->dma
);
348 AUD_set_active_out (s
->voice
, 0);
352 static uint64_t cs_read (void *opaque
, hwaddr addr
, unsigned size
)
355 uint32_t saddr
, iaddr
, ret
;
362 ret
= s
->regs
[saddr
] & ~0x80;
366 if (!(s
->dregs
[MODE_And_ID
] & MODE2
))
367 iaddr
= s
->regs
[Index_Address
] & 0x0f;
369 iaddr
= s
->regs
[Index_Address
] & 0x1f;
371 ret
= s
->dregs
[iaddr
];
372 if (iaddr
== Error_Status_And_Initialization
) {
373 /* keep SEAL happy */
374 if (s
->aci_counter
) {
382 ret
= s
->regs
[saddr
];
385 dolog ("read %d:%d -> %d\n", saddr
, iaddr
, ret
);
389 static void cs_write (void *opaque
, hwaddr addr
,
390 uint64_t val64
, unsigned size
)
393 uint32_t saddr
, iaddr
, val
;
400 if (!(s
->regs
[Index_Address
] & MCE
) && (val
& MCE
)
401 && (s
->dregs
[Interface_Configuration
] & (3 << 3)))
402 s
->aci_counter
= conf
.aci_counter
;
404 s
->regs
[Index_Address
] = val
& ~(1 << 7);
408 if (!(s
->dregs
[MODE_And_ID
] & MODE2
))
409 iaddr
= s
->regs
[Index_Address
] & 0x0f;
411 iaddr
= s
->regs
[Index_Address
] & 0x1f;
417 lwarn ("attempt to write %#x to reserved indirect register %d\n",
421 case FS_And_Playback_Data_Format
:
422 if (s
->regs
[Index_Address
] & MCE
) {
423 cs_reset_voices (s
, val
);
426 if (s
->dregs
[Alternate_Feature_Status
] & PMCE
) {
427 val
= (val
& ~0x0f) | (s
->dregs
[iaddr
] & 0x0f);
428 cs_reset_voices (s
, val
);
431 lwarn ("[P]MCE(%#x, %#x) is not set, val=%#x\n",
432 s
->regs
[Index_Address
],
433 s
->dregs
[Alternate_Feature_Status
],
438 s
->dregs
[iaddr
] = val
;
441 case Interface_Configuration
:
442 val
&= ~(1 << 5); /* D5 is reserved */
443 s
->dregs
[iaddr
] = val
;
445 lwarn ("PIO is not supported (%#x)\n", val
);
449 if (!s
->dma_running
) {
450 cs_reset_voices (s
, s
->dregs
[FS_And_Playback_Data_Format
]);
454 if (s
->dma_running
) {
455 DMA_release_DREQ (s
->dma
);
456 AUD_set_active_out (s
->voice
, 0);
462 case Error_Status_And_Initialization
:
463 lwarn ("attempt to write to read only register %d\n", iaddr
);
467 dolog ("val=%#x\n", val
);
469 s
->dregs
[iaddr
] |= MODE2
;
471 s
->dregs
[iaddr
] &= ~MODE2
;
474 case Alternate_Feature_Enable_I
:
476 lerr ("timer is not yet supported\n");
477 s
->dregs
[iaddr
] = val
;
480 case Alternate_Feature_Status
:
481 if ((s
->dregs
[iaddr
] & PI
) && !(val
& PI
)) {
483 qemu_irq_lower (s
->pic
);
484 s
->regs
[Status
] &= ~INT
;
486 s
->dregs
[iaddr
] = val
;
489 case Version_Chip_ID
:
490 lwarn ("write to Version_Chip_ID register %#x\n", val
);
491 s
->dregs
[iaddr
] = val
;
495 s
->dregs
[iaddr
] = val
;
498 dolog ("written value %#x to indirect register %d\n", val
, iaddr
);
502 if (s
->regs
[Status
] & INT
) {
503 qemu_irq_lower (s
->pic
);
505 s
->regs
[Status
] &= ~INT
;
506 s
->dregs
[Alternate_Feature_Status
] &= ~(PI
| CI
| TI
);
510 lwarn ("attempt to write value %#x to PIO register\n", val
);
515 static int cs_write_audio (CSState
*s
, int nchan
, int dma_pos
,
516 int dma_len
, int len
)
519 uint8_t tmpbuf
[4096];
525 int left
= dma_len
- dma_pos
;
529 to_copy
= audio_MIN (temp
, left
);
530 if (to_copy
> sizeof (tmpbuf
)) {
531 to_copy
= sizeof (tmpbuf
);
534 copied
= DMA_read_memory (nchan
, tmpbuf
, dma_pos
, to_copy
);
537 int16_t linbuf
[4096];
539 for (i
= 0; i
< copied
; ++i
)
540 linbuf
[i
] = s
->tab
[tmpbuf
[i
]];
541 copied
= AUD_write (s
->voice
, linbuf
, copied
<< 1);
545 copied
= AUD_write (s
->voice
, tmpbuf
, copied
);
549 dma_pos
= (dma_pos
+ copied
) % dma_len
;
560 static int cs_dma_read (void *opaque
, int nchan
, int dma_pos
, int dma_len
)
566 copy
= s
->voice
? (s
->audio_free
>> (s
->tab
!= NULL
)) : dma_len
;
568 if (s
->dregs
[Pin_Control
] & IEN
) {
569 till
= (s
->dregs
[Playback_Lower_Base_Count
]
570 | (s
->dregs
[Playback_Upper_Base_Count
] << 8)) << s
->shift
;
571 till
-= s
->transferred
;
572 copy
= audio_MIN (till
, copy
);
575 if ((copy
<= 0) || (dma_len
<= 0)) {
579 written
= cs_write_audio (s
, nchan
, dma_pos
, dma_len
, copy
);
581 dma_pos
= (dma_pos
+ written
) % dma_len
;
582 s
->audio_free
-= (written
<< (s
->tab
!= NULL
));
584 if (written
== till
) {
585 s
->regs
[Status
] |= INT
;
586 s
->dregs
[Alternate_Feature_Status
] |= PI
;
588 qemu_irq_raise (s
->pic
);
591 s
->transferred
+= written
;
597 static int cs4231a_pre_load (void *opaque
)
601 if (s
->dma_running
) {
602 DMA_release_DREQ (s
->dma
);
603 AUD_set_active_out (s
->voice
, 0);
609 static int cs4231a_post_load (void *opaque
, int version_id
)
613 if (s
->dma_running
&& (s
->dregs
[Interface_Configuration
] & PEN
)) {
615 cs_reset_voices (s
, s
->dregs
[FS_And_Playback_Data_Format
]);
620 static const VMStateDescription vmstate_cs4231a
= {
623 .minimum_version_id
= 1,
624 .pre_load
= cs4231a_pre_load
,
625 .post_load
= cs4231a_post_load
,
626 .fields
= (VMStateField
[]) {
627 VMSTATE_UINT32_ARRAY (regs
, CSState
, CS_REGS
),
628 VMSTATE_BUFFER (dregs
, CSState
),
629 VMSTATE_INT32 (dma_running
, CSState
),
630 VMSTATE_INT32 (audio_free
, CSState
),
631 VMSTATE_INT32 (transferred
, CSState
),
632 VMSTATE_INT32 (aci_counter
, CSState
),
633 VMSTATE_END_OF_LIST ()
637 static const MemoryRegionOps cs_ioport_ops
= {
641 .min_access_size
= 1,
642 .max_access_size
= 1,
646 static void cs4231a_initfn (Object
*obj
)
648 CSState
*s
= CS4231A (obj
);
650 memory_region_init_io (&s
->ioports
, OBJECT(s
), &cs_ioport_ops
, s
,
654 static void cs4231a_realizefn (DeviceState
*dev
, Error
**errp
)
656 ISADevice
*d
= ISA_DEVICE (dev
);
657 CSState
*s
= CS4231A (dev
);
659 isa_init_irq (d
, &s
->pic
, s
->irq
);
661 isa_register_ioport (d
, &s
->ioports
, s
->port
);
663 DMA_register_channel (s
->dma
, cs_dma_read
, s
);
665 AUD_register_card ("cs4231a", &s
->card
);
668 static int cs4231a_init (ISABus
*bus
)
670 isa_create_simple (bus
, TYPE_CS4231A
);
674 static Property cs4231a_properties
[] = {
675 DEFINE_PROP_UINT32 ("iobase", CSState
, port
, 0x534),
676 DEFINE_PROP_UINT32 ("irq", CSState
, irq
, 9),
677 DEFINE_PROP_UINT32 ("dma", CSState
, dma
, 3),
678 DEFINE_PROP_END_OF_LIST (),
681 static void cs4231a_class_initfn (ObjectClass
*klass
, void *data
)
683 DeviceClass
*dc
= DEVICE_CLASS (klass
);
685 dc
->realize
= cs4231a_realizefn
;
686 dc
->reset
= cs4231a_reset
;
687 set_bit(DEVICE_CATEGORY_SOUND
, dc
->categories
);
688 dc
->desc
= "Crystal Semiconductor CS4231A";
689 dc
->vmsd
= &vmstate_cs4231a
;
690 dc
->props
= cs4231a_properties
;
693 static const TypeInfo cs4231a_info
= {
694 .name
= TYPE_CS4231A
,
695 .parent
= TYPE_ISA_DEVICE
,
696 .instance_size
= sizeof (CSState
),
697 .instance_init
= cs4231a_initfn
,
698 .class_init
= cs4231a_class_initfn
,
701 static void cs4231a_register_types (void)
703 type_register_static (&cs4231a_info
);
704 isa_register_soundhw("cs4231a", "CS4231A", cs4231a_init
);
707 type_init (cs4231a_register_types
)