xref: /openbmc/qemu/hw/audio/asc.c (revision 83baec642a13a69398a2643a1f905606c13cd363)
1ac13a6b3SMark Cave-Ayland /*
2ac13a6b3SMark Cave-Ayland  * QEMU Apple Sound Chip emulation
3ac13a6b3SMark Cave-Ayland  *
4ac13a6b3SMark Cave-Ayland  * Apple Sound Chip (ASC) 344S0063
5ac13a6b3SMark Cave-Ayland  * Enhanced Apple Sound Chip (EASC) 343S1063
6ac13a6b3SMark Cave-Ayland  *
7ac13a6b3SMark Cave-Ayland  * Copyright (c) 2012-2018 Laurent Vivier <laurent@vivier.eu>
8ac13a6b3SMark Cave-Ayland  * Copyright (c) 2022 Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
9ac13a6b3SMark Cave-Ayland  *
10ac13a6b3SMark Cave-Ayland  * SPDX-License-Identifier: GPL-2.0-or-later
11ac13a6b3SMark Cave-Ayland  */
12ac13a6b3SMark Cave-Ayland 
13ac13a6b3SMark Cave-Ayland #include "qemu/osdep.h"
14ac13a6b3SMark Cave-Ayland #include "qemu/timer.h"
15ac13a6b3SMark Cave-Ayland #include "hw/sysbus.h"
16ac13a6b3SMark Cave-Ayland #include "hw/irq.h"
17ac13a6b3SMark Cave-Ayland #include "audio/audio.h"
18ac13a6b3SMark Cave-Ayland #include "hw/audio/asc.h"
19ac13a6b3SMark Cave-Ayland #include "hw/qdev-properties.h"
20ac13a6b3SMark Cave-Ayland #include "migration/vmstate.h"
21ac13a6b3SMark Cave-Ayland #include "trace.h"
22ac13a6b3SMark Cave-Ayland 
23ac13a6b3SMark Cave-Ayland /*
24ac13a6b3SMark Cave-Ayland  * Linux doesn't provide information about ASC, see arch/m68k/mac/macboing.c
25ac13a6b3SMark Cave-Ayland  * and arch/m68k/include/asm/mac_asc.h
26ac13a6b3SMark Cave-Ayland  *
27ac13a6b3SMark Cave-Ayland  * best information is coming from MAME:
28ac13a6b3SMark Cave-Ayland  *   https://github.com/mamedev/mame/blob/master/src/devices/sound/asc.h
29ac13a6b3SMark Cave-Ayland  *   https://github.com/mamedev/mame/blob/master/src/devices/sound/asc.cpp
30ac13a6b3SMark Cave-Ayland  *   Emulation by R. Belmont
31ac13a6b3SMark Cave-Ayland  * or MESS:
32ac13a6b3SMark Cave-Ayland  *   http://mess.redump.net/mess/driver_info/easc
33ac13a6b3SMark Cave-Ayland  *
34ac13a6b3SMark Cave-Ayland  *     0x800: VERSION
35ac13a6b3SMark Cave-Ayland  *     0x801: MODE
36ac13a6b3SMark Cave-Ayland  *            1=FIFO mode,
37ac13a6b3SMark Cave-Ayland  *            2=wavetable mode
38ac13a6b3SMark Cave-Ayland  *     0x802: CONTROL
39ac13a6b3SMark Cave-Ayland  *            bit 0=analog or PWM output,
40ac13a6b3SMark Cave-Ayland  *                1=stereo/mono,
41ac13a6b3SMark Cave-Ayland  *                7=processing time exceeded
42ac13a6b3SMark Cave-Ayland  *     0x803: FIFO MODE
43ac13a6b3SMark Cave-Ayland  *            bit 7=clear FIFO,
44ac13a6b3SMark Cave-Ayland  *            bit 1="non-ROM companding",
45ac13a6b3SMark Cave-Ayland  *            bit 0="ROM companding")
46ac13a6b3SMark Cave-Ayland  *     0x804: FIFO IRQ STATUS
47ac13a6b3SMark Cave-Ayland  *            bit 0=ch A 1/2 full,
48ac13a6b3SMark Cave-Ayland  *                1=ch A full,
49ac13a6b3SMark Cave-Ayland  *                2=ch B 1/2 full,
50ac13a6b3SMark Cave-Ayland  *                3=ch B full)
51ac13a6b3SMark Cave-Ayland  *     0x805: WAVETABLE CONTROL
52ac13a6b3SMark Cave-Ayland  *            bits 0-3 wavetables 0-3 start
53ac13a6b3SMark Cave-Ayland  *     0x806: VOLUME
54ac13a6b3SMark Cave-Ayland  *            bits 2-4 = 3 bit internal ASC volume,
55ac13a6b3SMark Cave-Ayland  *            bits 5-7 = volume control sent to Sony sound chip
56ac13a6b3SMark Cave-Ayland  *     0x807: CLOCK RATE
57ac13a6b3SMark Cave-Ayland  *            0 = Mac 22257 Hz,
58ac13a6b3SMark Cave-Ayland  *            1 = undefined,
59ac13a6b3SMark Cave-Ayland  *            2 = 22050 Hz,
60ac13a6b3SMark Cave-Ayland  *            3 = 44100 Hz
61ac13a6b3SMark Cave-Ayland  *     0x80a: PLAY REC A
62ac13a6b3SMark Cave-Ayland  *     0x80f: TEST
63ac13a6b3SMark Cave-Ayland  *            bits 6-7 = digital test,
64ac13a6b3SMark Cave-Ayland  *            bits 4-5 = analog test
65ac13a6b3SMark Cave-Ayland  *     0x810: WAVETABLE 0 PHASE
66ac13a6b3SMark Cave-Ayland  *            big-endian 9.15 fixed-point, only 24 bits valid
67ac13a6b3SMark Cave-Ayland  *     0x814: WAVETABLE 0 INCREMENT
68ac13a6b3SMark Cave-Ayland  *            big-endian 9.15 fixed-point, only 24 bits valid
69ac13a6b3SMark Cave-Ayland  *     0x818: WAVETABLE 1 PHASE
70ac13a6b3SMark Cave-Ayland  *     0x81C: WAVETABLE 1 INCREMENT
71ac13a6b3SMark Cave-Ayland  *     0x820: WAVETABLE 2 PHASE
72ac13a6b3SMark Cave-Ayland  *     0x824: WAVETABLE 2 INCREMENT
73ac13a6b3SMark Cave-Ayland  *     0x828: WAVETABLE 3 PHASE
74ac13a6b3SMark Cave-Ayland  *     0x82C: WAVETABLE 3 INCREMENT
75ac13a6b3SMark Cave-Ayland  *     0x830: UNKNOWN START
76ac13a6b3SMark Cave-Ayland  *            NetBSD writes Wavetable data here (are there more
77ac13a6b3SMark Cave-Ayland  *            wavetables/channels than we know about?)
78ac13a6b3SMark Cave-Ayland  *     0x857: UNKNOWN END
79ac13a6b3SMark Cave-Ayland  */
80ac13a6b3SMark Cave-Ayland 
81ac13a6b3SMark Cave-Ayland #define ASC_SIZE           0x2000
82ac13a6b3SMark Cave-Ayland 
83ac13a6b3SMark Cave-Ayland enum {
84ac13a6b3SMark Cave-Ayland     ASC_VERSION     = 0x00,
85ac13a6b3SMark Cave-Ayland     ASC_MODE        = 0x01,
86ac13a6b3SMark Cave-Ayland     ASC_CONTROL     = 0x02,
87ac13a6b3SMark Cave-Ayland     ASC_FIFOMODE    = 0x03,
88ac13a6b3SMark Cave-Ayland     ASC_FIFOIRQ     = 0x04,
89ac13a6b3SMark Cave-Ayland     ASC_WAVECTRL    = 0x05,
90ac13a6b3SMark Cave-Ayland     ASC_VOLUME      = 0x06,
91ac13a6b3SMark Cave-Ayland     ASC_CLOCK       = 0x07,
92ac13a6b3SMark Cave-Ayland     ASC_PLAYRECA    = 0x0a,
93ac13a6b3SMark Cave-Ayland     ASC_TEST        = 0x0f,
94ac13a6b3SMark Cave-Ayland     ASC_WAVETABLE   = 0x10
95ac13a6b3SMark Cave-Ayland };
96ac13a6b3SMark Cave-Ayland 
97ac13a6b3SMark Cave-Ayland #define ASC_FIFO_STATUS_HALF_FULL      1
98ac13a6b3SMark Cave-Ayland #define ASC_FIFO_STATUS_FULL_EMPTY     2
99ac13a6b3SMark Cave-Ayland 
100ac13a6b3SMark Cave-Ayland #define ASC_EXTREGS_FIFOCTRL           0x8
101ac13a6b3SMark Cave-Ayland #define ASC_EXTREGS_INTCTRL            0x9
102ac13a6b3SMark Cave-Ayland #define ASC_EXTREGS_CDXA_DECOMP_FILT   0x10
103ac13a6b3SMark Cave-Ayland 
104ac13a6b3SMark Cave-Ayland #define ASC_FIFO_CYCLE_TIME            ((NANOSECONDS_PER_SECOND / ASC_FREQ) * \
105ac13a6b3SMark Cave-Ayland                                         0x400)
106ac13a6b3SMark Cave-Ayland 
asc_raise_irq(ASCState * s)107ac13a6b3SMark Cave-Ayland static void asc_raise_irq(ASCState *s)
108ac13a6b3SMark Cave-Ayland {
109ac13a6b3SMark Cave-Ayland     qemu_set_irq(s->irq, 1);
110ac13a6b3SMark Cave-Ayland }
111ac13a6b3SMark Cave-Ayland 
asc_lower_irq(ASCState * s)112ac13a6b3SMark Cave-Ayland static void asc_lower_irq(ASCState *s)
113ac13a6b3SMark Cave-Ayland {
114ac13a6b3SMark Cave-Ayland     qemu_set_irq(s->irq, 0);
115ac13a6b3SMark Cave-Ayland }
116ac13a6b3SMark Cave-Ayland 
asc_fifo_get(ASCFIFOState * fs)117ac13a6b3SMark Cave-Ayland static uint8_t asc_fifo_get(ASCFIFOState *fs)
118ac13a6b3SMark Cave-Ayland {
119ac13a6b3SMark Cave-Ayland     ASCState *s = container_of(fs, ASCState, fifos[fs->index]);
120ac13a6b3SMark Cave-Ayland     bool fifo_half_irq_enabled = fs->extregs[ASC_EXTREGS_INTCTRL] & 1;
121ac13a6b3SMark Cave-Ayland     uint8_t val;
122ac13a6b3SMark Cave-Ayland 
123ac13a6b3SMark Cave-Ayland     assert(fs->cnt);
124ac13a6b3SMark Cave-Ayland 
125ac13a6b3SMark Cave-Ayland     val = fs->fifo[fs->rptr];
126ac13a6b3SMark Cave-Ayland     trace_asc_fifo_get('A' + fs->index, fs->rptr, fs->cnt, val);
127ac13a6b3SMark Cave-Ayland 
128ac13a6b3SMark Cave-Ayland     fs->rptr++;
129ac13a6b3SMark Cave-Ayland     fs->rptr &= 0x3ff;
130ac13a6b3SMark Cave-Ayland     fs->cnt--;
131ac13a6b3SMark Cave-Ayland 
132ac13a6b3SMark Cave-Ayland     if (fs->cnt <= 0x1ff) {
133ac13a6b3SMark Cave-Ayland         /* FIFO less than half full */
134ac13a6b3SMark Cave-Ayland         fs->int_status |= ASC_FIFO_STATUS_HALF_FULL;
135ac13a6b3SMark Cave-Ayland     } else {
136ac13a6b3SMark Cave-Ayland         /* FIFO more than half full */
137ac13a6b3SMark Cave-Ayland         fs->int_status &= ~ASC_FIFO_STATUS_HALF_FULL;
138ac13a6b3SMark Cave-Ayland     }
139ac13a6b3SMark Cave-Ayland 
140ac13a6b3SMark Cave-Ayland     if (fs->cnt == 0x1ff && fifo_half_irq_enabled) {
141ac13a6b3SMark Cave-Ayland         /* Raise FIFO half full IRQ */
142ac13a6b3SMark Cave-Ayland         asc_raise_irq(s);
143ac13a6b3SMark Cave-Ayland     }
144ac13a6b3SMark Cave-Ayland 
145ac13a6b3SMark Cave-Ayland     if (fs->cnt == 0) {
146ac13a6b3SMark Cave-Ayland         /* Raise FIFO empty IRQ */
147ac13a6b3SMark Cave-Ayland         fs->int_status |= ASC_FIFO_STATUS_FULL_EMPTY;
148ac13a6b3SMark Cave-Ayland         asc_raise_irq(s);
149ac13a6b3SMark Cave-Ayland     }
150ac13a6b3SMark Cave-Ayland 
151ac13a6b3SMark Cave-Ayland     return val;
152ac13a6b3SMark Cave-Ayland }
153ac13a6b3SMark Cave-Ayland 
generate_fifo(ASCState * s,int maxsamples)154ac13a6b3SMark Cave-Ayland static int generate_fifo(ASCState *s, int maxsamples)
155ac13a6b3SMark Cave-Ayland {
156ac13a6b3SMark Cave-Ayland     int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
157ac13a6b3SMark Cave-Ayland     uint8_t *buf = s->mixbuf;
158ac13a6b3SMark Cave-Ayland     int i, wcount = 0;
159ac13a6b3SMark Cave-Ayland 
160ac13a6b3SMark Cave-Ayland     while (wcount < maxsamples) {
161ac13a6b3SMark Cave-Ayland         uint8_t val;
162ac13a6b3SMark Cave-Ayland         int16_t d, f0, f1;
163ac13a6b3SMark Cave-Ayland         int32_t t;
164ac13a6b3SMark Cave-Ayland         int shift, filter;
165ac13a6b3SMark Cave-Ayland         bool hasdata = false;
166ac13a6b3SMark Cave-Ayland 
167ac13a6b3SMark Cave-Ayland         for (i = 0; i < 2; i++) {
168ac13a6b3SMark Cave-Ayland             ASCFIFOState *fs = &s->fifos[i];
169ac13a6b3SMark Cave-Ayland 
170ac13a6b3SMark Cave-Ayland             switch (fs->extregs[ASC_EXTREGS_FIFOCTRL] & 0x83) {
171ac13a6b3SMark Cave-Ayland             case 0x82:
172ac13a6b3SMark Cave-Ayland                 /*
173ac13a6b3SMark Cave-Ayland                  * CD-XA BRR mode: decompress 15 bytes into 28 16-bit
174ac13a6b3SMark Cave-Ayland                  * samples
175ac13a6b3SMark Cave-Ayland                  */
176ac13a6b3SMark Cave-Ayland                 if (!fs->cnt) {
177ac13a6b3SMark Cave-Ayland                     val = 0x80;
178ac13a6b3SMark Cave-Ayland                     break;
179ac13a6b3SMark Cave-Ayland                 }
180ac13a6b3SMark Cave-Ayland 
181ac13a6b3SMark Cave-Ayland                 if (fs->xa_cnt == -1) {
182ac13a6b3SMark Cave-Ayland                     /* Start of packet, get flags */
183ac13a6b3SMark Cave-Ayland                     fs->xa_flags = asc_fifo_get(fs);
184ac13a6b3SMark Cave-Ayland                     fs->xa_cnt = 0;
185ac13a6b3SMark Cave-Ayland                 }
186ac13a6b3SMark Cave-Ayland 
187ac13a6b3SMark Cave-Ayland                 shift = fs->xa_flags & 0xf;
188ac13a6b3SMark Cave-Ayland                 filter = fs->xa_flags >> 4;
189ac13a6b3SMark Cave-Ayland                 f0 = (int8_t)fs->extregs[ASC_EXTREGS_CDXA_DECOMP_FILT +
190ac13a6b3SMark Cave-Ayland                                  (filter << 1) + 1];
191ac13a6b3SMark Cave-Ayland                 f1 = (int8_t)fs->extregs[ASC_EXTREGS_CDXA_DECOMP_FILT +
192ac13a6b3SMark Cave-Ayland                                  (filter << 1)];
193ac13a6b3SMark Cave-Ayland 
194ac13a6b3SMark Cave-Ayland                 if ((fs->xa_cnt & 1) == 0) {
195ac13a6b3SMark Cave-Ayland                     if (!fs->cnt) {
196ac13a6b3SMark Cave-Ayland                         val = 0x80;
197ac13a6b3SMark Cave-Ayland                         break;
198ac13a6b3SMark Cave-Ayland                     }
199ac13a6b3SMark Cave-Ayland 
200ac13a6b3SMark Cave-Ayland                     fs->xa_val = asc_fifo_get(fs);
201ac13a6b3SMark Cave-Ayland                     d = (fs->xa_val & 0xf) << 12;
202ac13a6b3SMark Cave-Ayland                 } else {
203ac13a6b3SMark Cave-Ayland                     d = (fs->xa_val & 0xf0) << 8;
204ac13a6b3SMark Cave-Ayland                 }
205ac13a6b3SMark Cave-Ayland                 t = (d >> shift) + (((fs->xa_last[0] * f0) +
206ac13a6b3SMark Cave-Ayland                                      (fs->xa_last[1] * f1) + 32) >> 6);
207ac13a6b3SMark Cave-Ayland                 if (t < -32768) {
208ac13a6b3SMark Cave-Ayland                     t = -32768;
209ac13a6b3SMark Cave-Ayland                 } else if (t > 32767) {
210ac13a6b3SMark Cave-Ayland                     t = 32767;
211ac13a6b3SMark Cave-Ayland                 }
212ac13a6b3SMark Cave-Ayland 
213ac13a6b3SMark Cave-Ayland                 /*
214ac13a6b3SMark Cave-Ayland                  * CD-XA BRR generates 16-bit signed output, so convert to
215ac13a6b3SMark Cave-Ayland                  * 8-bit before writing to buffer. Does real hardware do the
216ac13a6b3SMark Cave-Ayland                  * same?
217ac13a6b3SMark Cave-Ayland                  */
218ac13a6b3SMark Cave-Ayland                 val = (uint8_t)(t / 256) ^ 0x80;
219ac13a6b3SMark Cave-Ayland                 hasdata = true;
220ac13a6b3SMark Cave-Ayland                 fs->xa_cnt++;
221ac13a6b3SMark Cave-Ayland 
222ac13a6b3SMark Cave-Ayland                 fs->xa_last[1] = fs->xa_last[0];
223ac13a6b3SMark Cave-Ayland                 fs->xa_last[0] = (int16_t)t;
224ac13a6b3SMark Cave-Ayland 
225ac13a6b3SMark Cave-Ayland                 if (fs->xa_cnt == 28) {
226ac13a6b3SMark Cave-Ayland                     /* End of packet */
227ac13a6b3SMark Cave-Ayland                     fs->xa_cnt = -1;
228ac13a6b3SMark Cave-Ayland                 }
229ac13a6b3SMark Cave-Ayland                 break;
230ac13a6b3SMark Cave-Ayland 
231ac13a6b3SMark Cave-Ayland             default:
232ac13a6b3SMark Cave-Ayland                 /* fallthrough */
233ac13a6b3SMark Cave-Ayland             case 0x80:
234ac13a6b3SMark Cave-Ayland                 /* Raw mode */
235ac13a6b3SMark Cave-Ayland                 if (fs->cnt) {
236ac13a6b3SMark Cave-Ayland                     val = asc_fifo_get(fs);
237ac13a6b3SMark Cave-Ayland                     hasdata = true;
238ac13a6b3SMark Cave-Ayland                 } else {
239ac13a6b3SMark Cave-Ayland                     val = 0x80;
240ac13a6b3SMark Cave-Ayland                 }
241ac13a6b3SMark Cave-Ayland                 break;
242ac13a6b3SMark Cave-Ayland             }
243ac13a6b3SMark Cave-Ayland 
244ac13a6b3SMark Cave-Ayland             buf[wcount * 2 + i] = val;
245ac13a6b3SMark Cave-Ayland         }
246ac13a6b3SMark Cave-Ayland 
247ac13a6b3SMark Cave-Ayland         if (!hasdata) {
248ac13a6b3SMark Cave-Ayland             break;
249ac13a6b3SMark Cave-Ayland         }
250ac13a6b3SMark Cave-Ayland 
251ac13a6b3SMark Cave-Ayland         wcount++;
252ac13a6b3SMark Cave-Ayland     }
253ac13a6b3SMark Cave-Ayland 
254ac13a6b3SMark Cave-Ayland     /*
255ac13a6b3SMark Cave-Ayland      * MacOS (un)helpfully leaves the FIFO engine running even when it has
256ac13a6b3SMark Cave-Ayland      * finished writing out samples, but still expects the FIFO empty
257ac13a6b3SMark Cave-Ayland      * interrupts to be generated for each FIFO cycle (without these interrupts
258ac13a6b3SMark Cave-Ayland      * MacOS will freeze)
259ac13a6b3SMark Cave-Ayland      */
260ac13a6b3SMark Cave-Ayland     if (s->fifos[0].cnt == 0 && s->fifos[1].cnt == 0) {
261ac13a6b3SMark Cave-Ayland         if (!s->fifo_empty_ns) {
262ac13a6b3SMark Cave-Ayland             /* FIFO has completed first empty cycle */
263ac13a6b3SMark Cave-Ayland             s->fifo_empty_ns = now;
264ac13a6b3SMark Cave-Ayland         } else if (now > (s->fifo_empty_ns + ASC_FIFO_CYCLE_TIME)) {
265ac13a6b3SMark Cave-Ayland             /* FIFO has completed entire cycle with no data */
266ac13a6b3SMark Cave-Ayland             s->fifos[0].int_status |= ASC_FIFO_STATUS_HALF_FULL |
267ac13a6b3SMark Cave-Ayland                                       ASC_FIFO_STATUS_FULL_EMPTY;
268ac13a6b3SMark Cave-Ayland             s->fifos[1].int_status |= ASC_FIFO_STATUS_HALF_FULL |
269ac13a6b3SMark Cave-Ayland                                       ASC_FIFO_STATUS_FULL_EMPTY;
270ac13a6b3SMark Cave-Ayland             s->fifo_empty_ns = now;
271ac13a6b3SMark Cave-Ayland             asc_raise_irq(s);
272ac13a6b3SMark Cave-Ayland         }
273ac13a6b3SMark Cave-Ayland     } else {
274ac13a6b3SMark Cave-Ayland         /* FIFO contains data, reset empty time */
275ac13a6b3SMark Cave-Ayland         s->fifo_empty_ns = 0;
276ac13a6b3SMark Cave-Ayland     }
277ac13a6b3SMark Cave-Ayland 
278ac13a6b3SMark Cave-Ayland     return wcount;
279ac13a6b3SMark Cave-Ayland }
280ac13a6b3SMark Cave-Ayland 
generate_wavetable(ASCState * s,int maxsamples)281ac13a6b3SMark Cave-Ayland static int generate_wavetable(ASCState *s, int maxsamples)
282ac13a6b3SMark Cave-Ayland {
283ac13a6b3SMark Cave-Ayland     uint8_t *buf = s->mixbuf;
284ac13a6b3SMark Cave-Ayland     int channel, count = 0;
285ac13a6b3SMark Cave-Ayland 
286ac13a6b3SMark Cave-Ayland     while (count < maxsamples) {
287ac13a6b3SMark Cave-Ayland         uint32_t left = 0, right = 0;
288ac13a6b3SMark Cave-Ayland         uint8_t sample;
289ac13a6b3SMark Cave-Ayland 
290ac13a6b3SMark Cave-Ayland         for (channel = 0; channel < 4; channel++) {
291ac13a6b3SMark Cave-Ayland             ASCFIFOState *fs = &s->fifos[channel >> 1];
292ac13a6b3SMark Cave-Ayland             int chanreg = ASC_WAVETABLE + (channel << 3);
293ac13a6b3SMark Cave-Ayland             uint32_t phase, incr, offset;
294ac13a6b3SMark Cave-Ayland 
295ac13a6b3SMark Cave-Ayland             phase = ldl_be_p(&s->regs[chanreg]);
296ac13a6b3SMark Cave-Ayland             incr = ldl_be_p(&s->regs[chanreg + sizeof(uint32_t)]);
297ac13a6b3SMark Cave-Ayland 
298ac13a6b3SMark Cave-Ayland             phase += incr;
299ac13a6b3SMark Cave-Ayland             offset = (phase >> 15) & 0x1ff;
300ac13a6b3SMark Cave-Ayland             sample = fs->fifo[0x200 * (channel >> 1) + offset];
301ac13a6b3SMark Cave-Ayland 
302ac13a6b3SMark Cave-Ayland             stl_be_p(&s->regs[chanreg], phase);
303ac13a6b3SMark Cave-Ayland 
304ac13a6b3SMark Cave-Ayland             left += sample;
305ac13a6b3SMark Cave-Ayland             right += sample;
306ac13a6b3SMark Cave-Ayland         }
307ac13a6b3SMark Cave-Ayland 
308ac13a6b3SMark Cave-Ayland         buf[count * 2] = left >> 2;
309ac13a6b3SMark Cave-Ayland         buf[count * 2 + 1] = right >> 2;
310ac13a6b3SMark Cave-Ayland 
311ac13a6b3SMark Cave-Ayland         count++;
312ac13a6b3SMark Cave-Ayland     }
313ac13a6b3SMark Cave-Ayland 
314ac13a6b3SMark Cave-Ayland     return count;
315ac13a6b3SMark Cave-Ayland }
316ac13a6b3SMark Cave-Ayland 
asc_out_cb(void * opaque,int free_b)317ac13a6b3SMark Cave-Ayland static void asc_out_cb(void *opaque, int free_b)
318ac13a6b3SMark Cave-Ayland {
319ac13a6b3SMark Cave-Ayland     ASCState *s = opaque;
320ac13a6b3SMark Cave-Ayland     int samples, generated;
321ac13a6b3SMark Cave-Ayland 
322ac13a6b3SMark Cave-Ayland     if (free_b == 0) {
323ac13a6b3SMark Cave-Ayland         return;
324ac13a6b3SMark Cave-Ayland     }
325ac13a6b3SMark Cave-Ayland 
326ac13a6b3SMark Cave-Ayland     samples = MIN(s->samples, free_b >> s->shift);
327ac13a6b3SMark Cave-Ayland 
328ac13a6b3SMark Cave-Ayland     switch (s->regs[ASC_MODE] & 3) {
329ac13a6b3SMark Cave-Ayland     default:
330ac13a6b3SMark Cave-Ayland         /* Off */
331ac13a6b3SMark Cave-Ayland         generated = 0;
332ac13a6b3SMark Cave-Ayland         break;
333ac13a6b3SMark Cave-Ayland     case 1:
334ac13a6b3SMark Cave-Ayland         /* FIFO mode */
335ac13a6b3SMark Cave-Ayland         generated = generate_fifo(s, samples);
336ac13a6b3SMark Cave-Ayland         break;
337ac13a6b3SMark Cave-Ayland     case 2:
338ac13a6b3SMark Cave-Ayland         /* Wave table mode */
339ac13a6b3SMark Cave-Ayland         generated = generate_wavetable(s, samples);
340ac13a6b3SMark Cave-Ayland         break;
341ac13a6b3SMark Cave-Ayland     }
342ac13a6b3SMark Cave-Ayland 
343ac13a6b3SMark Cave-Ayland     if (!generated) {
3445243e554SMark Cave-Ayland         /* Workaround for audio underflow bug on Windows dsound backend */
3455243e554SMark Cave-Ayland         int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
3465243e554SMark Cave-Ayland         int silent_samples = muldiv64(now - s->fifo_empty_ns,
3475243e554SMark Cave-Ayland                                       NANOSECONDS_PER_SECOND, ASC_FREQ);
3485243e554SMark Cave-Ayland 
3495243e554SMark Cave-Ayland         if (silent_samples > ASC_FIFO_CYCLE_TIME / 2) {
3505243e554SMark Cave-Ayland             /*
3515243e554SMark Cave-Ayland              * No new FIFO data within half a cycle time (~23ms) so fill the
3525243e554SMark Cave-Ayland              * entire available buffer with silence. This prevents an issue
3535243e554SMark Cave-Ayland              * with the Windows dsound backend whereby the sound appears to
3545243e554SMark Cave-Ayland              * loop because the FIFO has run out of data, and the driver
3555243e554SMark Cave-Ayland              * reuses the stale content in its circular audio buffer.
3565243e554SMark Cave-Ayland              */
3575243e554SMark Cave-Ayland             AUD_write(s->voice, s->silentbuf, samples << s->shift);
3585243e554SMark Cave-Ayland         }
359ac13a6b3SMark Cave-Ayland         return;
360ac13a6b3SMark Cave-Ayland     }
361ac13a6b3SMark Cave-Ayland 
362ac13a6b3SMark Cave-Ayland     AUD_write(s->voice, s->mixbuf, generated << s->shift);
363ac13a6b3SMark Cave-Ayland }
364ac13a6b3SMark Cave-Ayland 
asc_fifo_read(void * opaque,hwaddr addr,unsigned size)365ac13a6b3SMark Cave-Ayland static uint64_t asc_fifo_read(void *opaque, hwaddr addr,
366ac13a6b3SMark Cave-Ayland                               unsigned size)
367ac13a6b3SMark Cave-Ayland {
368ac13a6b3SMark Cave-Ayland     ASCFIFOState *fs = opaque;
369ac13a6b3SMark Cave-Ayland 
370ac13a6b3SMark Cave-Ayland     trace_asc_read_fifo('A' + fs->index, addr, size, fs->fifo[addr]);
371ac13a6b3SMark Cave-Ayland     return fs->fifo[addr];
372ac13a6b3SMark Cave-Ayland }
373ac13a6b3SMark Cave-Ayland 
asc_fifo_write(void * opaque,hwaddr addr,uint64_t value,unsigned size)374ac13a6b3SMark Cave-Ayland static void asc_fifo_write(void *opaque, hwaddr addr, uint64_t value,
375ac13a6b3SMark Cave-Ayland                            unsigned size)
376ac13a6b3SMark Cave-Ayland {
377ac13a6b3SMark Cave-Ayland     ASCFIFOState *fs = opaque;
378ac13a6b3SMark Cave-Ayland     ASCState *s = container_of(fs, ASCState, fifos[fs->index]);
379ac13a6b3SMark Cave-Ayland     bool fifo_half_irq_enabled = fs->extregs[ASC_EXTREGS_INTCTRL] & 1;
380ac13a6b3SMark Cave-Ayland 
381ac13a6b3SMark Cave-Ayland     trace_asc_write_fifo('A' + fs->index, addr, size, fs->wptr, fs->cnt, value);
382ac13a6b3SMark Cave-Ayland 
383ac13a6b3SMark Cave-Ayland     if (s->regs[ASC_MODE] == 1) {
384ac13a6b3SMark Cave-Ayland         fs->fifo[fs->wptr++] = value;
385ac13a6b3SMark Cave-Ayland         fs->wptr &= 0x3ff;
386ac13a6b3SMark Cave-Ayland         fs->cnt++;
387ac13a6b3SMark Cave-Ayland 
388ac13a6b3SMark Cave-Ayland         if (fs->cnt <= 0x1ff) {
389ac13a6b3SMark Cave-Ayland             /* FIFO less than half full */
390ac13a6b3SMark Cave-Ayland             fs->int_status |= ASC_FIFO_STATUS_HALF_FULL;
391ac13a6b3SMark Cave-Ayland         } else {
392ac13a6b3SMark Cave-Ayland             /* FIFO at least half full */
393ac13a6b3SMark Cave-Ayland             fs->int_status &= ~ASC_FIFO_STATUS_HALF_FULL;
394ac13a6b3SMark Cave-Ayland         }
395ac13a6b3SMark Cave-Ayland 
396ac13a6b3SMark Cave-Ayland         if (fs->cnt == 0x200 && fifo_half_irq_enabled) {
397ac13a6b3SMark Cave-Ayland             /* Raise FIFO half full interrupt */
398ac13a6b3SMark Cave-Ayland             asc_raise_irq(s);
399ac13a6b3SMark Cave-Ayland         }
400ac13a6b3SMark Cave-Ayland 
401ac13a6b3SMark Cave-Ayland         if (fs->cnt == 0x3ff) {
402ac13a6b3SMark Cave-Ayland             /* Raise FIFO full interrupt */
403ac13a6b3SMark Cave-Ayland             fs->int_status |= ASC_FIFO_STATUS_FULL_EMPTY;
404ac13a6b3SMark Cave-Ayland             asc_raise_irq(s);
405ac13a6b3SMark Cave-Ayland         }
406ac13a6b3SMark Cave-Ayland     } else {
407ac13a6b3SMark Cave-Ayland         fs->fifo[addr] = value;
408ac13a6b3SMark Cave-Ayland     }
409ac13a6b3SMark Cave-Ayland     return;
410ac13a6b3SMark Cave-Ayland }
411ac13a6b3SMark Cave-Ayland 
412ac13a6b3SMark Cave-Ayland static const MemoryRegionOps asc_fifo_ops = {
413ac13a6b3SMark Cave-Ayland     .read = asc_fifo_read,
414ac13a6b3SMark Cave-Ayland     .write = asc_fifo_write,
415ac13a6b3SMark Cave-Ayland     .impl = {
416ac13a6b3SMark Cave-Ayland         .min_access_size = 1,
417ac13a6b3SMark Cave-Ayland         .max_access_size = 1,
418ac13a6b3SMark Cave-Ayland     },
419ac13a6b3SMark Cave-Ayland     .endianness = DEVICE_BIG_ENDIAN,
420ac13a6b3SMark Cave-Ayland };
421ac13a6b3SMark Cave-Ayland 
422ac13a6b3SMark Cave-Ayland static void asc_fifo_reset(ASCFIFOState *fs);
423ac13a6b3SMark Cave-Ayland 
asc_read(void * opaque,hwaddr addr,unsigned size)424ac13a6b3SMark Cave-Ayland static uint64_t asc_read(void *opaque, hwaddr addr,
425ac13a6b3SMark Cave-Ayland                          unsigned size)
426ac13a6b3SMark Cave-Ayland {
427ac13a6b3SMark Cave-Ayland     ASCState *s = opaque;
428ac13a6b3SMark Cave-Ayland     uint64_t prev, value;
429ac13a6b3SMark Cave-Ayland 
430ac13a6b3SMark Cave-Ayland     switch (addr) {
431ac13a6b3SMark Cave-Ayland     case ASC_VERSION:
432ac13a6b3SMark Cave-Ayland         switch (s->type) {
433ac13a6b3SMark Cave-Ayland         default:
434ac13a6b3SMark Cave-Ayland         case ASC_TYPE_ASC:
435ac13a6b3SMark Cave-Ayland             value = 0;
436ac13a6b3SMark Cave-Ayland             break;
437ac13a6b3SMark Cave-Ayland         case ASC_TYPE_EASC:
438ac13a6b3SMark Cave-Ayland             value = 0xb0;
439ac13a6b3SMark Cave-Ayland             break;
440ac13a6b3SMark Cave-Ayland         }
441ac13a6b3SMark Cave-Ayland         break;
442ac13a6b3SMark Cave-Ayland     case ASC_FIFOIRQ:
443ac13a6b3SMark Cave-Ayland         prev = (s->fifos[0].int_status & 0x3) |
444ac13a6b3SMark Cave-Ayland                 (s->fifos[1].int_status & 0x3) << 2;
445ac13a6b3SMark Cave-Ayland 
446ac13a6b3SMark Cave-Ayland         s->fifos[0].int_status = 0;
447ac13a6b3SMark Cave-Ayland         s->fifos[1].int_status = 0;
448ac13a6b3SMark Cave-Ayland         asc_lower_irq(s);
449ac13a6b3SMark Cave-Ayland         value = prev;
450ac13a6b3SMark Cave-Ayland         break;
451ac13a6b3SMark Cave-Ayland     default:
452ac13a6b3SMark Cave-Ayland         value = s->regs[addr];
453ac13a6b3SMark Cave-Ayland         break;
454ac13a6b3SMark Cave-Ayland     }
455ac13a6b3SMark Cave-Ayland 
456ac13a6b3SMark Cave-Ayland     trace_asc_read_reg(addr, size, value);
457ac13a6b3SMark Cave-Ayland     return value;
458ac13a6b3SMark Cave-Ayland }
459ac13a6b3SMark Cave-Ayland 
asc_write(void * opaque,hwaddr addr,uint64_t value,unsigned size)460ac13a6b3SMark Cave-Ayland static void asc_write(void *opaque, hwaddr addr, uint64_t value,
461ac13a6b3SMark Cave-Ayland                       unsigned size)
462ac13a6b3SMark Cave-Ayland {
463ac13a6b3SMark Cave-Ayland     ASCState *s = opaque;
464ac13a6b3SMark Cave-Ayland 
465ac13a6b3SMark Cave-Ayland     switch (addr) {
466ac13a6b3SMark Cave-Ayland     case ASC_MODE:
467ac13a6b3SMark Cave-Ayland         value &= 3;
468ac13a6b3SMark Cave-Ayland         if (value != s->regs[ASC_MODE]) {
469ac13a6b3SMark Cave-Ayland             asc_fifo_reset(&s->fifos[0]);
470ac13a6b3SMark Cave-Ayland             asc_fifo_reset(&s->fifos[1]);
471ac13a6b3SMark Cave-Ayland             asc_lower_irq(s);
472ac13a6b3SMark Cave-Ayland             if (value != 0) {
473ac13a6b3SMark Cave-Ayland                 AUD_set_active_out(s->voice, 1);
474ac13a6b3SMark Cave-Ayland             } else {
475ac13a6b3SMark Cave-Ayland                 AUD_set_active_out(s->voice, 0);
476ac13a6b3SMark Cave-Ayland             }
477ac13a6b3SMark Cave-Ayland         }
478ac13a6b3SMark Cave-Ayland         break;
479ac13a6b3SMark Cave-Ayland     case ASC_FIFOMODE:
480ac13a6b3SMark Cave-Ayland         if (value & 0x80) {
481ac13a6b3SMark Cave-Ayland             asc_fifo_reset(&s->fifos[0]);
482ac13a6b3SMark Cave-Ayland             asc_fifo_reset(&s->fifos[1]);
483ac13a6b3SMark Cave-Ayland             asc_lower_irq(s);
484ac13a6b3SMark Cave-Ayland         }
485ac13a6b3SMark Cave-Ayland         break;
486ac13a6b3SMark Cave-Ayland     case ASC_WAVECTRL:
487ac13a6b3SMark Cave-Ayland         break;
488ac13a6b3SMark Cave-Ayland     case ASC_VOLUME:
489ac13a6b3SMark Cave-Ayland         {
490ac13a6b3SMark Cave-Ayland             int vol = (value & 0xe0);
491ac13a6b3SMark Cave-Ayland 
492ac13a6b3SMark Cave-Ayland             AUD_set_volume_out(s->voice, 0, vol, vol);
493ac13a6b3SMark Cave-Ayland             break;
494ac13a6b3SMark Cave-Ayland         }
495ac13a6b3SMark Cave-Ayland     }
496ac13a6b3SMark Cave-Ayland 
497ac13a6b3SMark Cave-Ayland     trace_asc_write_reg(addr, size, value);
498ac13a6b3SMark Cave-Ayland     s->regs[addr] = value;
499ac13a6b3SMark Cave-Ayland }
500ac13a6b3SMark Cave-Ayland 
501ac13a6b3SMark Cave-Ayland static const MemoryRegionOps asc_regs_ops = {
502ac13a6b3SMark Cave-Ayland     .read = asc_read,
503ac13a6b3SMark Cave-Ayland     .write = asc_write,
504ac13a6b3SMark Cave-Ayland     .endianness = DEVICE_BIG_ENDIAN,
505ac13a6b3SMark Cave-Ayland     .impl = {
506ac13a6b3SMark Cave-Ayland         .min_access_size = 1,
507ac13a6b3SMark Cave-Ayland         .max_access_size = 1,
508ac13a6b3SMark Cave-Ayland     }
509ac13a6b3SMark Cave-Ayland };
510ac13a6b3SMark Cave-Ayland 
asc_ext_read(void * opaque,hwaddr addr,unsigned size)511ac13a6b3SMark Cave-Ayland static uint64_t asc_ext_read(void *opaque, hwaddr addr,
512ac13a6b3SMark Cave-Ayland                              unsigned size)
513ac13a6b3SMark Cave-Ayland {
514ac13a6b3SMark Cave-Ayland     ASCFIFOState *fs = opaque;
515ac13a6b3SMark Cave-Ayland     uint64_t value;
516ac13a6b3SMark Cave-Ayland 
517ac13a6b3SMark Cave-Ayland     value = fs->extregs[addr];
518ac13a6b3SMark Cave-Ayland 
519ac13a6b3SMark Cave-Ayland     trace_asc_read_extreg('A' + fs->index, addr, size, value);
520ac13a6b3SMark Cave-Ayland     return value;
521ac13a6b3SMark Cave-Ayland }
522ac13a6b3SMark Cave-Ayland 
asc_ext_write(void * opaque,hwaddr addr,uint64_t value,unsigned size)523ac13a6b3SMark Cave-Ayland static void asc_ext_write(void *opaque, hwaddr addr, uint64_t value,
524ac13a6b3SMark Cave-Ayland                           unsigned size)
525ac13a6b3SMark Cave-Ayland {
526ac13a6b3SMark Cave-Ayland     ASCFIFOState *fs = opaque;
527ac13a6b3SMark Cave-Ayland 
528ac13a6b3SMark Cave-Ayland     trace_asc_write_extreg('A' + fs->index, addr, size, value);
529ac13a6b3SMark Cave-Ayland 
530ac13a6b3SMark Cave-Ayland     fs->extregs[addr] = value;
531ac13a6b3SMark Cave-Ayland }
532ac13a6b3SMark Cave-Ayland 
533ac13a6b3SMark Cave-Ayland static const MemoryRegionOps asc_extregs_ops = {
534ac13a6b3SMark Cave-Ayland     .read = asc_ext_read,
535ac13a6b3SMark Cave-Ayland     .write = asc_ext_write,
536ac13a6b3SMark Cave-Ayland     .impl = {
537ac13a6b3SMark Cave-Ayland         .min_access_size = 1,
538ac13a6b3SMark Cave-Ayland         .max_access_size = 1,
539ac13a6b3SMark Cave-Ayland     },
540ac13a6b3SMark Cave-Ayland     .endianness = DEVICE_BIG_ENDIAN,
541ac13a6b3SMark Cave-Ayland };
542ac13a6b3SMark Cave-Ayland 
asc_post_load(void * opaque,int version)543ac13a6b3SMark Cave-Ayland static int asc_post_load(void *opaque, int version)
544ac13a6b3SMark Cave-Ayland {
545ac13a6b3SMark Cave-Ayland     ASCState *s = ASC(opaque);
546ac13a6b3SMark Cave-Ayland 
547ac13a6b3SMark Cave-Ayland     if (s->regs[ASC_MODE] != 0) {
548ac13a6b3SMark Cave-Ayland         AUD_set_active_out(s->voice, 1);
549ac13a6b3SMark Cave-Ayland     }
550ac13a6b3SMark Cave-Ayland 
551ac13a6b3SMark Cave-Ayland     return 0;
552ac13a6b3SMark Cave-Ayland }
553ac13a6b3SMark Cave-Ayland 
554ac13a6b3SMark Cave-Ayland static const VMStateDescription vmstate_asc_fifo = {
555ac13a6b3SMark Cave-Ayland     .name = "apple-sound-chip.fifo",
556ac13a6b3SMark Cave-Ayland     .version_id = 0,
557ac13a6b3SMark Cave-Ayland     .minimum_version_id = 0,
558856a6fe4SRichard Henderson     .fields = (const VMStateField[]) {
559ac13a6b3SMark Cave-Ayland         VMSTATE_UINT8_ARRAY(fifo, ASCFIFOState, ASC_FIFO_SIZE),
560ac13a6b3SMark Cave-Ayland         VMSTATE_UINT8(int_status, ASCFIFOState),
561ac13a6b3SMark Cave-Ayland         VMSTATE_INT32(cnt, ASCFIFOState),
562ac13a6b3SMark Cave-Ayland         VMSTATE_INT32(wptr, ASCFIFOState),
563ac13a6b3SMark Cave-Ayland         VMSTATE_INT32(rptr, ASCFIFOState),
564ac13a6b3SMark Cave-Ayland         VMSTATE_UINT8_ARRAY(extregs, ASCFIFOState, ASC_EXTREG_SIZE),
565ac13a6b3SMark Cave-Ayland         VMSTATE_INT32(xa_cnt, ASCFIFOState),
566ac13a6b3SMark Cave-Ayland         VMSTATE_UINT8(xa_val, ASCFIFOState),
567ac13a6b3SMark Cave-Ayland         VMSTATE_UINT8(xa_flags, ASCFIFOState),
568ac13a6b3SMark Cave-Ayland         VMSTATE_INT16_ARRAY(xa_last, ASCFIFOState, 2),
569ac13a6b3SMark Cave-Ayland         VMSTATE_END_OF_LIST()
570ac13a6b3SMark Cave-Ayland     }
571ac13a6b3SMark Cave-Ayland };
572ac13a6b3SMark Cave-Ayland 
573ac13a6b3SMark Cave-Ayland static const VMStateDescription vmstate_asc = {
574ac13a6b3SMark Cave-Ayland     .name = "apple-sound-chip",
575ac13a6b3SMark Cave-Ayland     .version_id = 0,
576ac13a6b3SMark Cave-Ayland     .minimum_version_id = 0,
577ac13a6b3SMark Cave-Ayland     .post_load = asc_post_load,
578856a6fe4SRichard Henderson     .fields = (const VMStateField[]) {
579ac13a6b3SMark Cave-Ayland         VMSTATE_STRUCT_ARRAY(fifos, ASCState, 2, 0, vmstate_asc_fifo,
580ac13a6b3SMark Cave-Ayland                              ASCFIFOState),
581ac13a6b3SMark Cave-Ayland         VMSTATE_UINT8_ARRAY(regs, ASCState, ASC_REG_SIZE),
582ac13a6b3SMark Cave-Ayland         VMSTATE_INT64(fifo_empty_ns, ASCState),
583ac13a6b3SMark Cave-Ayland         VMSTATE_END_OF_LIST()
584ac13a6b3SMark Cave-Ayland     }
585ac13a6b3SMark Cave-Ayland };
586ac13a6b3SMark Cave-Ayland 
asc_fifo_reset(ASCFIFOState * fs)587ac13a6b3SMark Cave-Ayland static void asc_fifo_reset(ASCFIFOState *fs)
588ac13a6b3SMark Cave-Ayland {
589ac13a6b3SMark Cave-Ayland     fs->wptr = 0;
590ac13a6b3SMark Cave-Ayland     fs->rptr = 0;
591ac13a6b3SMark Cave-Ayland     fs->cnt = 0;
592ac13a6b3SMark Cave-Ayland     fs->xa_cnt = -1;
593ac13a6b3SMark Cave-Ayland     fs->int_status = 0;
594ac13a6b3SMark Cave-Ayland }
595ac13a6b3SMark Cave-Ayland 
asc_fifo_init(ASCFIFOState * fs,int index)596ac13a6b3SMark Cave-Ayland static void asc_fifo_init(ASCFIFOState *fs, int index)
597ac13a6b3SMark Cave-Ayland {
598ac13a6b3SMark Cave-Ayland     ASCState *s = container_of(fs, ASCState, fifos[index]);
599ac13a6b3SMark Cave-Ayland     char *name;
600ac13a6b3SMark Cave-Ayland 
601ac13a6b3SMark Cave-Ayland     fs->index = index;
602ac13a6b3SMark Cave-Ayland     name = g_strdup_printf("asc.fifo%c", 'A' + index);
603ac13a6b3SMark Cave-Ayland     memory_region_init_io(&fs->mem_fifo, OBJECT(s), &asc_fifo_ops, fs,
604ac13a6b3SMark Cave-Ayland                           name, ASC_FIFO_SIZE);
605ac13a6b3SMark Cave-Ayland     g_free(name);
606ac13a6b3SMark Cave-Ayland 
607ac13a6b3SMark Cave-Ayland     name = g_strdup_printf("asc.extregs%c", 'A' + index);
608ac13a6b3SMark Cave-Ayland     memory_region_init_io(&fs->mem_extregs, OBJECT(s), &asc_extregs_ops,
609ac13a6b3SMark Cave-Ayland                           fs, name, ASC_EXTREG_SIZE);
610ac13a6b3SMark Cave-Ayland     g_free(name);
611ac13a6b3SMark Cave-Ayland }
612ac13a6b3SMark Cave-Ayland 
asc_reset_hold(Object * obj,ResetType type)613*ad80e367SPeter Maydell static void asc_reset_hold(Object *obj, ResetType type)
614ac13a6b3SMark Cave-Ayland {
615ac13a6b3SMark Cave-Ayland     ASCState *s = ASC(obj);
616ac13a6b3SMark Cave-Ayland 
617ac13a6b3SMark Cave-Ayland     AUD_set_active_out(s->voice, 0);
618ac13a6b3SMark Cave-Ayland 
619ac13a6b3SMark Cave-Ayland     memset(s->regs, 0, sizeof(s->regs));
620ac13a6b3SMark Cave-Ayland     asc_fifo_reset(&s->fifos[0]);
621ac13a6b3SMark Cave-Ayland     asc_fifo_reset(&s->fifos[1]);
622ac13a6b3SMark Cave-Ayland     s->fifo_empty_ns = 0;
623ac13a6b3SMark Cave-Ayland 
624ac13a6b3SMark Cave-Ayland     if (s->type == ASC_TYPE_ASC) {
625ac13a6b3SMark Cave-Ayland         /* FIFO half full IRQs enabled by default */
626ac13a6b3SMark Cave-Ayland         s->fifos[0].extregs[ASC_EXTREGS_INTCTRL] = 1;
627ac13a6b3SMark Cave-Ayland         s->fifos[1].extregs[ASC_EXTREGS_INTCTRL] = 1;
628ac13a6b3SMark Cave-Ayland     }
629ac13a6b3SMark Cave-Ayland }
630ac13a6b3SMark Cave-Ayland 
asc_unrealize(DeviceState * dev)631ac13a6b3SMark Cave-Ayland static void asc_unrealize(DeviceState *dev)
632ac13a6b3SMark Cave-Ayland {
633ac13a6b3SMark Cave-Ayland     ASCState *s = ASC(dev);
634ac13a6b3SMark Cave-Ayland 
635ac13a6b3SMark Cave-Ayland     g_free(s->mixbuf);
6365243e554SMark Cave-Ayland     g_free(s->silentbuf);
637ac13a6b3SMark Cave-Ayland 
638ac13a6b3SMark Cave-Ayland     AUD_remove_card(&s->card);
639ac13a6b3SMark Cave-Ayland }
640ac13a6b3SMark Cave-Ayland 
asc_realize(DeviceState * dev,Error ** errp)641ac13a6b3SMark Cave-Ayland static void asc_realize(DeviceState *dev, Error **errp)
642ac13a6b3SMark Cave-Ayland {
643ac13a6b3SMark Cave-Ayland     ASCState *s = ASC(dev);
644ac13a6b3SMark Cave-Ayland     struct audsettings as;
645ac13a6b3SMark Cave-Ayland 
646ac13a6b3SMark Cave-Ayland     if (!AUD_register_card("Apple Sound Chip", &s->card, errp)) {
647ac13a6b3SMark Cave-Ayland         return;
648ac13a6b3SMark Cave-Ayland     }
649ac13a6b3SMark Cave-Ayland 
650ac13a6b3SMark Cave-Ayland     as.freq = ASC_FREQ;
651ac13a6b3SMark Cave-Ayland     as.nchannels = 2;
652ac13a6b3SMark Cave-Ayland     as.fmt = AUDIO_FORMAT_U8;
653ac13a6b3SMark Cave-Ayland     as.endianness = AUDIO_HOST_ENDIANNESS;
654ac13a6b3SMark Cave-Ayland 
655ac13a6b3SMark Cave-Ayland     s->voice = AUD_open_out(&s->card, s->voice, "asc.out", s, asc_out_cb,
656ac13a6b3SMark Cave-Ayland                             &as);
657ac13a6b3SMark Cave-Ayland     s->shift = 1;
658ac13a6b3SMark Cave-Ayland     s->samples = AUD_get_buffer_size_out(s->voice) >> s->shift;
659ac13a6b3SMark Cave-Ayland     s->mixbuf = g_malloc0(s->samples << s->shift);
660ac13a6b3SMark Cave-Ayland 
6615243e554SMark Cave-Ayland     s->silentbuf = g_malloc0(s->samples << s->shift);
6625243e554SMark Cave-Ayland     memset(s->silentbuf, 0x80, s->samples << s->shift);
6635243e554SMark Cave-Ayland 
664ac13a6b3SMark Cave-Ayland     /* Add easc registers if required */
665ac13a6b3SMark Cave-Ayland     if (s->type == ASC_TYPE_EASC) {
666ac13a6b3SMark Cave-Ayland         memory_region_add_subregion(&s->asc, ASC_EXTREG_OFFSET,
667ac13a6b3SMark Cave-Ayland                                     &s->fifos[0].mem_extregs);
668ac13a6b3SMark Cave-Ayland         memory_region_add_subregion(&s->asc,
669ac13a6b3SMark Cave-Ayland                                     ASC_EXTREG_OFFSET + ASC_EXTREG_SIZE,
670ac13a6b3SMark Cave-Ayland                                     &s->fifos[1].mem_extregs);
671ac13a6b3SMark Cave-Ayland     }
672ac13a6b3SMark Cave-Ayland }
673ac13a6b3SMark Cave-Ayland 
asc_init(Object * obj)674ac13a6b3SMark Cave-Ayland static void asc_init(Object *obj)
675ac13a6b3SMark Cave-Ayland {
676ac13a6b3SMark Cave-Ayland     ASCState *s = ASC(obj);
677ac13a6b3SMark Cave-Ayland     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
678ac13a6b3SMark Cave-Ayland 
679ac13a6b3SMark Cave-Ayland     memory_region_init(&s->asc, OBJECT(obj), "asc", ASC_SIZE);
680ac13a6b3SMark Cave-Ayland 
681ac13a6b3SMark Cave-Ayland     asc_fifo_init(&s->fifos[0], 0);
682ac13a6b3SMark Cave-Ayland     asc_fifo_init(&s->fifos[1], 1);
683ac13a6b3SMark Cave-Ayland 
684ac13a6b3SMark Cave-Ayland     memory_region_add_subregion(&s->asc, ASC_FIFO_OFFSET,
685ac13a6b3SMark Cave-Ayland                                 &s->fifos[0].mem_fifo);
686ac13a6b3SMark Cave-Ayland     memory_region_add_subregion(&s->asc,
687ac13a6b3SMark Cave-Ayland                                 ASC_FIFO_OFFSET + ASC_FIFO_SIZE,
688ac13a6b3SMark Cave-Ayland                                 &s->fifos[1].mem_fifo);
689ac13a6b3SMark Cave-Ayland 
690ac13a6b3SMark Cave-Ayland     memory_region_init_io(&s->mem_regs, OBJECT(obj), &asc_regs_ops, s,
691ac13a6b3SMark Cave-Ayland                           "asc.regs", ASC_REG_SIZE);
692ac13a6b3SMark Cave-Ayland     memory_region_add_subregion(&s->asc, ASC_REG_OFFSET, &s->mem_regs);
693ac13a6b3SMark Cave-Ayland 
694ac13a6b3SMark Cave-Ayland     sysbus_init_irq(sbd, &s->irq);
695ac13a6b3SMark Cave-Ayland     sysbus_init_mmio(sbd, &s->asc);
696ac13a6b3SMark Cave-Ayland }
697ac13a6b3SMark Cave-Ayland 
698ac13a6b3SMark Cave-Ayland static Property asc_properties[] = {
699ac13a6b3SMark Cave-Ayland     DEFINE_AUDIO_PROPERTIES(ASCState, card),
700ac13a6b3SMark Cave-Ayland     DEFINE_PROP_UINT8("asctype", ASCState, type, ASC_TYPE_ASC),
701ac13a6b3SMark Cave-Ayland     DEFINE_PROP_END_OF_LIST(),
702ac13a6b3SMark Cave-Ayland };
703ac13a6b3SMark Cave-Ayland 
asc_class_init(ObjectClass * oc,void * data)704ac13a6b3SMark Cave-Ayland static void asc_class_init(ObjectClass *oc, void *data)
705ac13a6b3SMark Cave-Ayland {
706ac13a6b3SMark Cave-Ayland     DeviceClass *dc = DEVICE_CLASS(oc);
707ac13a6b3SMark Cave-Ayland     ResettableClass *rc = RESETTABLE_CLASS(oc);
708ac13a6b3SMark Cave-Ayland 
709ac13a6b3SMark Cave-Ayland     dc->realize = asc_realize;
710ac13a6b3SMark Cave-Ayland     dc->unrealize = asc_unrealize;
711ac13a6b3SMark Cave-Ayland     set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
712ac13a6b3SMark Cave-Ayland     dc->vmsd = &vmstate_asc;
713ac13a6b3SMark Cave-Ayland     device_class_set_props(dc, asc_properties);
714ac13a6b3SMark Cave-Ayland     rc->phases.hold = asc_reset_hold;
715ac13a6b3SMark Cave-Ayland }
716ac13a6b3SMark Cave-Ayland 
717ac13a6b3SMark Cave-Ayland static const TypeInfo asc_info_types[] = {
718ac13a6b3SMark Cave-Ayland     {
719ac13a6b3SMark Cave-Ayland         .name = TYPE_ASC,
720ac13a6b3SMark Cave-Ayland         .parent = TYPE_SYS_BUS_DEVICE,
721ac13a6b3SMark Cave-Ayland         .instance_size = sizeof(ASCState),
722ac13a6b3SMark Cave-Ayland         .instance_init = asc_init,
723ac13a6b3SMark Cave-Ayland         .class_init = asc_class_init,
724ac13a6b3SMark Cave-Ayland     },
725ac13a6b3SMark Cave-Ayland };
726ac13a6b3SMark Cave-Ayland 
727ac13a6b3SMark Cave-Ayland DEFINE_TYPES(asc_info_types)
728