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 int cs4231a_pre_load (void *opaque)
603
if (s->dma_running) {
604
DMA_release_DREQ (s->dma);
605
AUD_set_active_out (s->voice, 0);
611
static int cs4231a_post_load (void *opaque, int version_id)
615
if (s->dma_running && (s->dregs[Interface_Configuration] & PEN)) {
617
cs_reset_voices (s, s->dregs[FS_And_Playback_Data_Format]);
622
static const VMStateDescription vmstate_cs4231a = {
625
.minimum_version_id = 1,
626
.minimum_version_id_old = 1,
627
.pre_load = cs4231a_pre_load,
628
.post_load = cs4231a_post_load,
629
.fields = (VMStateField []) {
630
VMSTATE_UINT32_ARRAY(regs, CSState, CS_REGS),
631
VMSTATE_BUFFER(dregs, CSState),
632
VMSTATE_INT32(dma_running, CSState),
633
VMSTATE_INT32(audio_free, CSState),
634
VMSTATE_INT32(transferred, CSState),
635
VMSTATE_INT32(aci_counter, CSState),
636
VMSTATE_END_OF_LIST()
640
static int cs4231a_initfn (ISADevice *dev)
642
CSState *s = DO_UPCAST (CSState, dev, dev);
645
isa_init_irq (dev, &s->pic, s->irq);
647
for (i = 0; i < 4; i++) {
648
isa_init_ioport(dev, i);
649
register_ioport_write (s->port + i, 1, 1, cs_write, s);
650
register_ioport_read (s->port + i, 1, 1, cs_read, s);
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
int cs4231a_init (qemu_irq *pic)
664
isa_create_simple ("cs4231a");
668
static ISADeviceInfo cs4231a_info = {
669
.qdev.name = "cs4231a",
670
.qdev.desc = "Crystal Semiconductor CS4231A",
671
.qdev.size = sizeof (CSState),
672
.qdev.vmsd = &vmstate_cs4231a,
673
.init = cs4231a_initfn,
674
.qdev.props = (Property[]) {
675
DEFINE_PROP_HEX32 ("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 (),
682
static void cs4231a_register (void)
684
isa_qdev_register (&cs4231a_info);
686
device_init (cs4231a_register)