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