2 * QEMU Apple Sound Chip emulation
4 * Apple Sound Chip (ASC) 344S0063
5 * Enhanced Apple Sound Chip (EASC) 343S1063
7 * Copyright (c) 2012-2018 Laurent Vivier <laurent@vivier.eu>
8 * Copyright (c) 2022 Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
10 * SPDX-License-Identifier: GPL-2.0-or-later
13 #include "qemu/osdep.h"
14 #include "qemu/timer.h"
15 #include "hw/sysbus.h"
17 #include "audio/audio.h"
18 #include "hw/audio/asc.h"
19 #include "hw/qdev-properties.h"
20 #include "migration/vmstate.h"
24 * Linux doesn't provide information about ASC, see arch/m68k/mac/macboing.c
25 * and arch/m68k/include/asm/mac_asc.h
27 * best information is coming from MAME:
28 * https://github.com/mamedev/mame/blob/master/src/devices/sound/asc.h
29 * https://github.com/mamedev/mame/blob/master/src/devices/sound/asc.cpp
30 * Emulation by R. Belmont
32 * http://mess.redump.net/mess/driver_info/easc
39 * bit 0=analog or PWM output,
41 * 7=processing time exceeded
44 * bit 1="non-ROM companding",
45 * bit 0="ROM companding")
46 * 0x804: FIFO IRQ STATUS
47 * bit 0=ch A 1/2 full,
51 * 0x805: WAVETABLE CONTROL
52 * bits 0-3 wavetables 0-3 start
54 * bits 2-4 = 3 bit internal ASC volume,
55 * bits 5-7 = volume control sent to Sony sound chip
63 * bits 6-7 = digital test,
64 * bits 4-5 = analog test
65 * 0x810: WAVETABLE 0 PHASE
66 * big-endian 9.15 fixed-point, only 24 bits valid
67 * 0x814: WAVETABLE 0 INCREMENT
68 * big-endian 9.15 fixed-point, only 24 bits valid
69 * 0x818: WAVETABLE 1 PHASE
70 * 0x81C: WAVETABLE 1 INCREMENT
71 * 0x820: WAVETABLE 2 PHASE
72 * 0x824: WAVETABLE 2 INCREMENT
73 * 0x828: WAVETABLE 3 PHASE
74 * 0x82C: WAVETABLE 3 INCREMENT
75 * 0x830: UNKNOWN START
76 * NetBSD writes Wavetable data here (are there more
77 * wavetables/channels than we know about?)
81 #define ASC_SIZE 0x2000
97 #define ASC_FIFO_STATUS_HALF_FULL 1
98 #define ASC_FIFO_STATUS_FULL_EMPTY 2
100 #define ASC_EXTREGS_FIFOCTRL 0x8
101 #define ASC_EXTREGS_INTCTRL 0x9
102 #define ASC_EXTREGS_CDXA_DECOMP_FILT 0x10
104 #define ASC_FIFO_CYCLE_TIME ((NANOSECONDS_PER_SECOND / ASC_FREQ) * \
107 static void asc_raise_irq(ASCState
*s
)
109 qemu_set_irq(s
->irq
, 1);
112 static void asc_lower_irq(ASCState
*s
)
114 qemu_set_irq(s
->irq
, 0);
117 static uint8_t asc_fifo_get(ASCFIFOState
*fs
)
119 ASCState
*s
= container_of(fs
, ASCState
, fifos
[fs
->index
]);
120 bool fifo_half_irq_enabled
= fs
->extregs
[ASC_EXTREGS_INTCTRL
] & 1;
125 val
= fs
->fifo
[fs
->rptr
];
126 trace_asc_fifo_get('A' + fs
->index
, fs
->rptr
, fs
->cnt
, val
);
132 if (fs
->cnt
<= 0x1ff) {
133 /* FIFO less than half full */
134 fs
->int_status
|= ASC_FIFO_STATUS_HALF_FULL
;
136 /* FIFO more than half full */
137 fs
->int_status
&= ~ASC_FIFO_STATUS_HALF_FULL
;
140 if (fs
->cnt
== 0x1ff && fifo_half_irq_enabled
) {
141 /* Raise FIFO half full IRQ */
146 /* Raise FIFO empty IRQ */
147 fs
->int_status
|= ASC_FIFO_STATUS_FULL_EMPTY
;
154 static int generate_fifo(ASCState
*s
, int maxsamples
)
156 int64_t now
= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
);
157 uint8_t *buf
= s
->mixbuf
;
160 while (wcount
< maxsamples
) {
165 bool hasdata
= false;
167 for (i
= 0; i
< 2; i
++) {
168 ASCFIFOState
*fs
= &s
->fifos
[i
];
170 switch (fs
->extregs
[ASC_EXTREGS_FIFOCTRL
] & 0x83) {
173 * CD-XA BRR mode: decompress 15 bytes into 28 16-bit
181 if (fs
->xa_cnt
== -1) {
182 /* Start of packet, get flags */
183 fs
->xa_flags
= asc_fifo_get(fs
);
187 shift
= fs
->xa_flags
& 0xf;
188 filter
= fs
->xa_flags
>> 4;
189 f0
= (int8_t)fs
->extregs
[ASC_EXTREGS_CDXA_DECOMP_FILT
+
191 f1
= (int8_t)fs
->extregs
[ASC_EXTREGS_CDXA_DECOMP_FILT
+
194 if ((fs
->xa_cnt
& 1) == 0) {
200 fs
->xa_val
= asc_fifo_get(fs
);
201 d
= (fs
->xa_val
& 0xf) << 12;
203 d
= (fs
->xa_val
& 0xf0) << 8;
205 t
= (d
>> shift
) + (((fs
->xa_last
[0] * f0
) +
206 (fs
->xa_last
[1] * f1
) + 32) >> 6);
209 } else if (t
> 32767) {
214 * CD-XA BRR generates 16-bit signed output, so convert to
215 * 8-bit before writing to buffer. Does real hardware do the
218 val
= (uint8_t)(t
/ 256) ^ 0x80;
222 fs
->xa_last
[1] = fs
->xa_last
[0];
223 fs
->xa_last
[0] = (int16_t)t
;
225 if (fs
->xa_cnt
== 28) {
236 val
= asc_fifo_get(fs
);
244 buf
[wcount
* 2 + i
] = val
;
255 * MacOS (un)helpfully leaves the FIFO engine running even when it has
256 * finished writing out samples, but still expects the FIFO empty
257 * interrupts to be generated for each FIFO cycle (without these interrupts
260 if (s
->fifos
[0].cnt
== 0 && s
->fifos
[1].cnt
== 0) {
261 if (!s
->fifo_empty_ns
) {
262 /* FIFO has completed first empty cycle */
263 s
->fifo_empty_ns
= now
;
264 } else if (now
> (s
->fifo_empty_ns
+ ASC_FIFO_CYCLE_TIME
)) {
265 /* FIFO has completed entire cycle with no data */
266 s
->fifos
[0].int_status
|= ASC_FIFO_STATUS_HALF_FULL
|
267 ASC_FIFO_STATUS_FULL_EMPTY
;
268 s
->fifos
[1].int_status
|= ASC_FIFO_STATUS_HALF_FULL
|
269 ASC_FIFO_STATUS_FULL_EMPTY
;
270 s
->fifo_empty_ns
= now
;
274 /* FIFO contains data, reset empty time */
275 s
->fifo_empty_ns
= 0;
281 static int generate_wavetable(ASCState
*s
, int maxsamples
)
283 uint8_t *buf
= s
->mixbuf
;
284 int channel
, count
= 0;
286 while (count
< maxsamples
) {
287 uint32_t left
= 0, right
= 0;
290 for (channel
= 0; channel
< 4; channel
++) {
291 ASCFIFOState
*fs
= &s
->fifos
[channel
>> 1];
292 int chanreg
= ASC_WAVETABLE
+ (channel
<< 3);
293 uint32_t phase
, incr
, offset
;
295 phase
= ldl_be_p(&s
->regs
[chanreg
]);
296 incr
= ldl_be_p(&s
->regs
[chanreg
+ sizeof(uint32_t)]);
299 offset
= (phase
>> 15) & 0x1ff;
300 sample
= fs
->fifo
[0x200 * (channel
>> 1) + offset
];
302 stl_be_p(&s
->regs
[chanreg
], phase
);
308 buf
[count
* 2] = left
>> 2;
309 buf
[count
* 2 + 1] = right
>> 2;
317 static void asc_out_cb(void *opaque
, int free_b
)
319 ASCState
*s
= opaque
;
320 int samples
, generated
;
326 samples
= MIN(s
->samples
, free_b
>> s
->shift
);
328 switch (s
->regs
[ASC_MODE
] & 3) {
335 generated
= generate_fifo(s
, samples
);
338 /* Wave table mode */
339 generated
= generate_wavetable(s
, samples
);
344 /* Workaround for audio underflow bug on Windows dsound backend */
345 int64_t now
= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
);
346 int silent_samples
= muldiv64(now
- s
->fifo_empty_ns
,
347 NANOSECONDS_PER_SECOND
, ASC_FREQ
);
349 if (silent_samples
> ASC_FIFO_CYCLE_TIME
/ 2) {
351 * No new FIFO data within half a cycle time (~23ms) so fill the
352 * entire available buffer with silence. This prevents an issue
353 * with the Windows dsound backend whereby the sound appears to
354 * loop because the FIFO has run out of data, and the driver
355 * reuses the stale content in its circular audio buffer.
357 AUD_write(s
->voice
, s
->silentbuf
, samples
<< s
->shift
);
362 AUD_write(s
->voice
, s
->mixbuf
, generated
<< s
->shift
);
365 static uint64_t asc_fifo_read(void *opaque
, hwaddr addr
,
368 ASCFIFOState
*fs
= opaque
;
370 trace_asc_read_fifo('A' + fs
->index
, addr
, size
, fs
->fifo
[addr
]);
371 return fs
->fifo
[addr
];
374 static void asc_fifo_write(void *opaque
, hwaddr addr
, uint64_t value
,
377 ASCFIFOState
*fs
= opaque
;
378 ASCState
*s
= container_of(fs
, ASCState
, fifos
[fs
->index
]);
379 bool fifo_half_irq_enabled
= fs
->extregs
[ASC_EXTREGS_INTCTRL
] & 1;
381 trace_asc_write_fifo('A' + fs
->index
, addr
, size
, fs
->wptr
, fs
->cnt
, value
);
383 if (s
->regs
[ASC_MODE
] == 1) {
384 fs
->fifo
[fs
->wptr
++] = value
;
388 if (fs
->cnt
<= 0x1ff) {
389 /* FIFO less than half full */
390 fs
->int_status
|= ASC_FIFO_STATUS_HALF_FULL
;
392 /* FIFO at least half full */
393 fs
->int_status
&= ~ASC_FIFO_STATUS_HALF_FULL
;
396 if (fs
->cnt
== 0x200 && fifo_half_irq_enabled
) {
397 /* Raise FIFO half full interrupt */
401 if (fs
->cnt
== 0x3ff) {
402 /* Raise FIFO full interrupt */
403 fs
->int_status
|= ASC_FIFO_STATUS_FULL_EMPTY
;
407 fs
->fifo
[addr
] = value
;
412 static const MemoryRegionOps asc_fifo_ops
= {
413 .read
= asc_fifo_read
,
414 .write
= asc_fifo_write
,
416 .min_access_size
= 1,
417 .max_access_size
= 1,
419 .endianness
= DEVICE_BIG_ENDIAN
,
422 static void asc_fifo_reset(ASCFIFOState
*fs
);
424 static uint64_t asc_read(void *opaque
, hwaddr addr
,
427 ASCState
*s
= opaque
;
428 uint64_t prev
, value
;
443 prev
= (s
->fifos
[0].int_status
& 0x3) |
444 (s
->fifos
[1].int_status
& 0x3) << 2;
446 s
->fifos
[0].int_status
= 0;
447 s
->fifos
[1].int_status
= 0;
452 value
= s
->regs
[addr
];
456 trace_asc_read_reg(addr
, size
, value
);
460 static void asc_write(void *opaque
, hwaddr addr
, uint64_t value
,
463 ASCState
*s
= opaque
;
468 if (value
!= s
->regs
[ASC_MODE
]) {
469 asc_fifo_reset(&s
->fifos
[0]);
470 asc_fifo_reset(&s
->fifos
[1]);
473 AUD_set_active_out(s
->voice
, 1);
475 AUD_set_active_out(s
->voice
, 0);
481 asc_fifo_reset(&s
->fifos
[0]);
482 asc_fifo_reset(&s
->fifos
[1]);
490 int vol
= (value
& 0xe0);
492 AUD_set_volume_out(s
->voice
, 0, vol
, vol
);
497 trace_asc_write_reg(addr
, size
, value
);
498 s
->regs
[addr
] = value
;
501 static const MemoryRegionOps asc_regs_ops
= {
504 .endianness
= DEVICE_BIG_ENDIAN
,
506 .min_access_size
= 1,
507 .max_access_size
= 1,
511 static uint64_t asc_ext_read(void *opaque
, hwaddr addr
,
514 ASCFIFOState
*fs
= opaque
;
517 value
= fs
->extregs
[addr
];
519 trace_asc_read_extreg('A' + fs
->index
, addr
, size
, value
);
523 static void asc_ext_write(void *opaque
, hwaddr addr
, uint64_t value
,
526 ASCFIFOState
*fs
= opaque
;
528 trace_asc_write_extreg('A' + fs
->index
, addr
, size
, value
);
530 fs
->extregs
[addr
] = value
;
533 static const MemoryRegionOps asc_extregs_ops
= {
534 .read
= asc_ext_read
,
535 .write
= asc_ext_write
,
537 .min_access_size
= 1,
538 .max_access_size
= 1,
540 .endianness
= DEVICE_BIG_ENDIAN
,
543 static int asc_post_load(void *opaque
, int version
)
545 ASCState
*s
= ASC(opaque
);
547 if (s
->regs
[ASC_MODE
] != 0) {
548 AUD_set_active_out(s
->voice
, 1);
554 static const VMStateDescription vmstate_asc_fifo
= {
555 .name
= "apple-sound-chip.fifo",
557 .minimum_version_id
= 0,
558 .fields
= (const VMStateField
[]) {
559 VMSTATE_UINT8_ARRAY(fifo
, ASCFIFOState
, ASC_FIFO_SIZE
),
560 VMSTATE_UINT8(int_status
, ASCFIFOState
),
561 VMSTATE_INT32(cnt
, ASCFIFOState
),
562 VMSTATE_INT32(wptr
, ASCFIFOState
),
563 VMSTATE_INT32(rptr
, ASCFIFOState
),
564 VMSTATE_UINT8_ARRAY(extregs
, ASCFIFOState
, ASC_EXTREG_SIZE
),
565 VMSTATE_INT32(xa_cnt
, ASCFIFOState
),
566 VMSTATE_UINT8(xa_val
, ASCFIFOState
),
567 VMSTATE_UINT8(xa_flags
, ASCFIFOState
),
568 VMSTATE_INT16_ARRAY(xa_last
, ASCFIFOState
, 2),
569 VMSTATE_END_OF_LIST()
573 static const VMStateDescription vmstate_asc
= {
574 .name
= "apple-sound-chip",
576 .minimum_version_id
= 0,
577 .post_load
= asc_post_load
,
578 .fields
= (const VMStateField
[]) {
579 VMSTATE_STRUCT_ARRAY(fifos
, ASCState
, 2, 0, vmstate_asc_fifo
,
581 VMSTATE_UINT8_ARRAY(regs
, ASCState
, ASC_REG_SIZE
),
582 VMSTATE_INT64(fifo_empty_ns
, ASCState
),
583 VMSTATE_END_OF_LIST()
587 static void asc_fifo_reset(ASCFIFOState
*fs
)
596 static void asc_fifo_init(ASCFIFOState
*fs
, int index
)
598 ASCState
*s
= container_of(fs
, ASCState
, fifos
[index
]);
602 name
= g_strdup_printf("asc.fifo%c", 'A' + index
);
603 memory_region_init_io(&fs
->mem_fifo
, OBJECT(s
), &asc_fifo_ops
, fs
,
604 name
, ASC_FIFO_SIZE
);
607 name
= g_strdup_printf("asc.extregs%c", 'A' + index
);
608 memory_region_init_io(&fs
->mem_extregs
, OBJECT(s
), &asc_extregs_ops
,
609 fs
, name
, ASC_EXTREG_SIZE
);
613 static void asc_reset_hold(Object
*obj
, ResetType type
)
615 ASCState
*s
= ASC(obj
);
617 AUD_set_active_out(s
->voice
, 0);
619 memset(s
->regs
, 0, sizeof(s
->regs
));
620 asc_fifo_reset(&s
->fifos
[0]);
621 asc_fifo_reset(&s
->fifos
[1]);
622 s
->fifo_empty_ns
= 0;
624 if (s
->type
== ASC_TYPE_ASC
) {
625 /* FIFO half full IRQs enabled by default */
626 s
->fifos
[0].extregs
[ASC_EXTREGS_INTCTRL
] = 1;
627 s
->fifos
[1].extregs
[ASC_EXTREGS_INTCTRL
] = 1;
631 static void asc_unrealize(DeviceState
*dev
)
633 ASCState
*s
= ASC(dev
);
636 g_free(s
->silentbuf
);
638 AUD_remove_card(&s
->card
);
641 static void asc_realize(DeviceState
*dev
, Error
**errp
)
643 ASCState
*s
= ASC(dev
);
644 struct audsettings as
;
646 if (!AUD_register_card("Apple Sound Chip", &s
->card
, errp
)) {
652 as
.fmt
= AUDIO_FORMAT_U8
;
653 as
.endianness
= AUDIO_HOST_ENDIANNESS
;
655 s
->voice
= AUD_open_out(&s
->card
, s
->voice
, "asc.out", s
, asc_out_cb
,
658 s
->samples
= AUD_get_buffer_size_out(s
->voice
) >> s
->shift
;
659 s
->mixbuf
= g_malloc0(s
->samples
<< s
->shift
);
661 s
->silentbuf
= g_malloc0(s
->samples
<< s
->shift
);
662 memset(s
->silentbuf
, 0x80, s
->samples
<< s
->shift
);
664 /* Add easc registers if required */
665 if (s
->type
== ASC_TYPE_EASC
) {
666 memory_region_add_subregion(&s
->asc
, ASC_EXTREG_OFFSET
,
667 &s
->fifos
[0].mem_extregs
);
668 memory_region_add_subregion(&s
->asc
,
669 ASC_EXTREG_OFFSET
+ ASC_EXTREG_SIZE
,
670 &s
->fifos
[1].mem_extregs
);
674 static void asc_init(Object
*obj
)
676 ASCState
*s
= ASC(obj
);
677 SysBusDevice
*sbd
= SYS_BUS_DEVICE(obj
);
679 memory_region_init(&s
->asc
, OBJECT(obj
), "asc", ASC_SIZE
);
681 asc_fifo_init(&s
->fifos
[0], 0);
682 asc_fifo_init(&s
->fifos
[1], 1);
684 memory_region_add_subregion(&s
->asc
, ASC_FIFO_OFFSET
,
685 &s
->fifos
[0].mem_fifo
);
686 memory_region_add_subregion(&s
->asc
,
687 ASC_FIFO_OFFSET
+ ASC_FIFO_SIZE
,
688 &s
->fifos
[1].mem_fifo
);
690 memory_region_init_io(&s
->mem_regs
, OBJECT(obj
), &asc_regs_ops
, s
,
691 "asc.regs", ASC_REG_SIZE
);
692 memory_region_add_subregion(&s
->asc
, ASC_REG_OFFSET
, &s
->mem_regs
);
694 sysbus_init_irq(sbd
, &s
->irq
);
695 sysbus_init_mmio(sbd
, &s
->asc
);
698 static Property asc_properties
[] = {
699 DEFINE_AUDIO_PROPERTIES(ASCState
, card
),
700 DEFINE_PROP_UINT8("asctype", ASCState
, type
, ASC_TYPE_ASC
),
701 DEFINE_PROP_END_OF_LIST(),
704 static void asc_class_init(ObjectClass
*oc
, void *data
)
706 DeviceClass
*dc
= DEVICE_CLASS(oc
);
707 ResettableClass
*rc
= RESETTABLE_CLASS(oc
);
709 dc
->realize
= asc_realize
;
710 dc
->unrealize
= asc_unrealize
;
711 set_bit(DEVICE_CATEGORY_SOUND
, dc
->categories
);
712 dc
->vmsd
= &vmstate_asc
;
713 device_class_set_props(dc
, asc_properties
);
714 rc
->phases
.hold
= asc_reset_hold
;
717 static const TypeInfo asc_info_types
[] = {
720 .parent
= TYPE_SYS_BUS_DEVICE
,
721 .instance_size
= sizeof(ASCState
),
722 .instance_init
= asc_init
,
723 .class_init
= asc_class_init
,
727 DEFINE_TYPES(asc_info_types
)