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