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