qemu

Форк
0
/
asc.c 
727 строк · 19.9 Кб
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 "hw/sysbus.h"
16
#include "hw/irq.h"
17
#include "audio/audio.h"
18
#include "hw/audio/asc.h"
19
#include "hw/qdev-properties.h"
20
#include "migration/vmstate.h"
21
#include "trace.h"
22

23
/*
24
 * Linux doesn't provide information about ASC, see arch/m68k/mac/macboing.c
25
 * and arch/m68k/include/asm/mac_asc.h
26
 *
27
 * best information is coming from MAME:
28
 *   https://github.com/mamedev/mame/blob/master/src/devices/sound/asc.h
29
 *   https://github.com/mamedev/mame/blob/master/src/devices/sound/asc.cpp
30
 *   Emulation by R. Belmont
31
 * or MESS:
32
 *   http://mess.redump.net/mess/driver_info/easc
33
 *
34
 *     0x800: VERSION
35
 *     0x801: MODE
36
 *            1=FIFO mode,
37
 *            2=wavetable mode
38
 *     0x802: CONTROL
39
 *            bit 0=analog or PWM output,
40
 *                1=stereo/mono,
41
 *                7=processing time exceeded
42
 *     0x803: FIFO MODE
43
 *            bit 7=clear FIFO,
44
 *            bit 1="non-ROM companding",
45
 *            bit 0="ROM companding")
46
 *     0x804: FIFO IRQ STATUS
47
 *            bit 0=ch A 1/2 full,
48
 *                1=ch A full,
49
 *                2=ch B 1/2 full,
50
 *                3=ch B full)
51
 *     0x805: WAVETABLE CONTROL
52
 *            bits 0-3 wavetables 0-3 start
53
 *     0x806: VOLUME
54
 *            bits 2-4 = 3 bit internal ASC volume,
55
 *            bits 5-7 = volume control sent to Sony sound chip
56
 *     0x807: CLOCK RATE
57
 *            0 = Mac 22257 Hz,
58
 *            1 = undefined,
59
 *            2 = 22050 Hz,
60
 *            3 = 44100 Hz
61
 *     0x80a: PLAY REC A
62
 *     0x80f: TEST
63
 *            bits 6-7 = digital test,
64
 *            bits 4-5 = analog test
65
 *     0x810: WAVETABLE 0 PHASE
66
 *            big-endian 9.15 fixed-point, only 24 bits valid
67
 *     0x814: WAVETABLE 0 INCREMENT
68
 *            big-endian 9.15 fixed-point, only 24 bits valid
69
 *     0x818: WAVETABLE 1 PHASE
70
 *     0x81C: WAVETABLE 1 INCREMENT
71
 *     0x820: WAVETABLE 2 PHASE
72
 *     0x824: WAVETABLE 2 INCREMENT
73
 *     0x828: WAVETABLE 3 PHASE
74
 *     0x82C: WAVETABLE 3 INCREMENT
75
 *     0x830: UNKNOWN START
76
 *            NetBSD writes Wavetable data here (are there more
77
 *            wavetables/channels than we know about?)
78
 *     0x857: UNKNOWN END
79
 */
80

81
#define ASC_SIZE           0x2000
82

83
enum {
84
    ASC_VERSION     = 0x00,
85
    ASC_MODE        = 0x01,
86
    ASC_CONTROL     = 0x02,
87
    ASC_FIFOMODE    = 0x03,
88
    ASC_FIFOIRQ     = 0x04,
89
    ASC_WAVECTRL    = 0x05,
90
    ASC_VOLUME      = 0x06,
91
    ASC_CLOCK       = 0x07,
92
    ASC_PLAYRECA    = 0x0a,
93
    ASC_TEST        = 0x0f,
94
    ASC_WAVETABLE   = 0x10
95
};
96

97
#define ASC_FIFO_STATUS_HALF_FULL      1
98
#define ASC_FIFO_STATUS_FULL_EMPTY     2
99

100
#define ASC_EXTREGS_FIFOCTRL           0x8
101
#define ASC_EXTREGS_INTCTRL            0x9
102
#define ASC_EXTREGS_CDXA_DECOMP_FILT   0x10
103

104
#define ASC_FIFO_CYCLE_TIME            ((NANOSECONDS_PER_SECOND / ASC_FREQ) * \
105
                                        0x400)
106

107
static void asc_raise_irq(ASCState *s)
108
{
109
    qemu_set_irq(s->irq, 1);
110
}
111

112
static void asc_lower_irq(ASCState *s)
113
{
114
    qemu_set_irq(s->irq, 0);
115
}
116

117
static uint8_t asc_fifo_get(ASCFIFOState *fs)
118
{
119
    ASCState *s = container_of(fs, ASCState, fifos[fs->index]);
120
    bool fifo_half_irq_enabled = fs->extregs[ASC_EXTREGS_INTCTRL] & 1;
121
    uint8_t val;
122

123
    assert(fs->cnt);
124

125
    val = fs->fifo[fs->rptr];
126
    trace_asc_fifo_get('A' + fs->index, fs->rptr, fs->cnt, val);
127

128
    fs->rptr++;
129
    fs->rptr &= 0x3ff;
130
    fs->cnt--;
131

132
    if (fs->cnt <= 0x1ff) {
133
        /* FIFO less than half full */
134
        fs->int_status |= ASC_FIFO_STATUS_HALF_FULL;
135
    } else {
136
        /* FIFO more than half full */
137
        fs->int_status &= ~ASC_FIFO_STATUS_HALF_FULL;
138
    }
139

140
    if (fs->cnt == 0x1ff && fifo_half_irq_enabled) {
141
        /* Raise FIFO half full IRQ */
142
        asc_raise_irq(s);
143
    }
144

145
    if (fs->cnt == 0) {
146
        /* Raise FIFO empty IRQ */
147
        fs->int_status |= ASC_FIFO_STATUS_FULL_EMPTY;
148
        asc_raise_irq(s);
149
    }
150

151
    return val;
152
}
153

154
static int generate_fifo(ASCState *s, int maxsamples)
155
{
156
    int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
157
    uint8_t *buf = s->mixbuf;
158
    int i, wcount = 0;
159

160
    while (wcount < maxsamples) {
161
        uint8_t val;
162
        int16_t d, f0, f1;
163
        int32_t t;
164
        int shift, filter;
165
        bool hasdata = false;
166

167
        for (i = 0; i < 2; i++) {
168
            ASCFIFOState *fs = &s->fifos[i];
169

170
            switch (fs->extregs[ASC_EXTREGS_FIFOCTRL] & 0x83) {
171
            case 0x82:
172
                /*
173
                 * CD-XA BRR mode: decompress 15 bytes into 28 16-bit
174
                 * samples
175
                 */
176
                if (!fs->cnt) {
177
                    val = 0x80;
178
                    break;
179
                }
180

181
                if (fs->xa_cnt == -1) {
182
                    /* Start of packet, get flags */
183
                    fs->xa_flags = asc_fifo_get(fs);
184
                    fs->xa_cnt = 0;
185
                }
186

187
                shift = fs->xa_flags & 0xf;
188
                filter = fs->xa_flags >> 4;
189
                f0 = (int8_t)fs->extregs[ASC_EXTREGS_CDXA_DECOMP_FILT +
190
                                 (filter << 1) + 1];
191
                f1 = (int8_t)fs->extregs[ASC_EXTREGS_CDXA_DECOMP_FILT +
192
                                 (filter << 1)];
193

194
                if ((fs->xa_cnt & 1) == 0) {
195
                    if (!fs->cnt) {
196
                        val = 0x80;
197
                        break;
198
                    }
199

200
                    fs->xa_val = asc_fifo_get(fs);
201
                    d = (fs->xa_val & 0xf) << 12;
202
                } else {
203
                    d = (fs->xa_val & 0xf0) << 8;
204
                }
205
                t = (d >> shift) + (((fs->xa_last[0] * f0) +
206
                                     (fs->xa_last[1] * f1) + 32) >> 6);
207
                if (t < -32768) {
208
                    t = -32768;
209
                } else if (t > 32767) {
210
                    t = 32767;
211
                }
212

213
                /*
214
                 * CD-XA BRR generates 16-bit signed output, so convert to
215
                 * 8-bit before writing to buffer. Does real hardware do the
216
                 * same?
217
                 */
218
                val = (uint8_t)(t / 256) ^ 0x80;
219
                hasdata = true;
220
                fs->xa_cnt++;
221

222
                fs->xa_last[1] = fs->xa_last[0];
223
                fs->xa_last[0] = (int16_t)t;
224

225
                if (fs->xa_cnt == 28) {
226
                    /* End of packet */
227
                    fs->xa_cnt = -1;
228
                }
229
                break;
230

231
            default:
232
                /* fallthrough */
233
            case 0x80:
234
                /* Raw mode */
235
                if (fs->cnt) {
236
                    val = asc_fifo_get(fs);
237
                    hasdata = true;
238
                } else {
239
                    val = 0x80;
240
                }
241
                break;
242
            }
243

244
            buf[wcount * 2 + i] = val;
245
        }
246

247
        if (!hasdata) {
248
            break;
249
        }
250

251
        wcount++;
252
    }
253

254
    /*
255
     * MacOS (un)helpfully leaves the FIFO engine running even when it has
256
     * finished writing out samples, but still expects the FIFO empty
257
     * interrupts to be generated for each FIFO cycle (without these interrupts
258
     * MacOS will freeze)
259
     */
260
    if (s->fifos[0].cnt == 0 && s->fifos[1].cnt == 0) {
261
        if (!s->fifo_empty_ns) {
262
            /* FIFO has completed first empty cycle */
263
            s->fifo_empty_ns = now;
264
        } else if (now > (s->fifo_empty_ns + ASC_FIFO_CYCLE_TIME)) {
265
            /* FIFO has completed entire cycle with no data */
266
            s->fifos[0].int_status |= ASC_FIFO_STATUS_HALF_FULL |
267
                                      ASC_FIFO_STATUS_FULL_EMPTY;
268
            s->fifos[1].int_status |= ASC_FIFO_STATUS_HALF_FULL |
269
                                      ASC_FIFO_STATUS_FULL_EMPTY;
270
            s->fifo_empty_ns = now;
271
            asc_raise_irq(s);
272
        }
273
    } else {
274
        /* FIFO contains data, reset empty time */
275
        s->fifo_empty_ns = 0;
276
    }
277

278
    return wcount;
279
}
280

281
static int generate_wavetable(ASCState *s, int maxsamples)
282
{
283
    uint8_t *buf = s->mixbuf;
284
    int channel, count = 0;
285

286
    while (count < maxsamples) {
287
        uint32_t left = 0, right = 0;
288
        uint8_t sample;
289

290
        for (channel = 0; channel < 4; channel++) {
291
            ASCFIFOState *fs = &s->fifos[channel >> 1];
292
            int chanreg = ASC_WAVETABLE + (channel << 3);
293
            uint32_t phase, incr, offset;
294

295
            phase = ldl_be_p(&s->regs[chanreg]);
296
            incr = ldl_be_p(&s->regs[chanreg + sizeof(uint32_t)]);
297

298
            phase += incr;
299
            offset = (phase >> 15) & 0x1ff;
300
            sample = fs->fifo[0x200 * (channel >> 1) + offset];
301

302
            stl_be_p(&s->regs[chanreg], phase);
303

304
            left += sample;
305
            right += sample;
306
        }
307

308
        buf[count * 2] = left >> 2;
309
        buf[count * 2 + 1] = right >> 2;
310

311
        count++;
312
    }
313

314
    return count;
315
}
316

317
static void asc_out_cb(void *opaque, int free_b)
318
{
319
    ASCState *s = opaque;
320
    int samples, generated;
321

322
    if (free_b == 0) {
323
        return;
324
    }
325

326
    samples = MIN(s->samples, free_b >> s->shift);
327

328
    switch (s->regs[ASC_MODE] & 3) {
329
    default:
330
        /* Off */
331
        generated = 0;
332
        break;
333
    case 1:
334
        /* FIFO mode */
335
        generated = generate_fifo(s, samples);
336
        break;
337
    case 2:
338
        /* Wave table mode */
339
        generated = generate_wavetable(s, samples);
340
        break;
341
    }
342

343
    if (!generated) {
344
        /* Workaround for audio underflow bug on Windows dsound backend */
345
        int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
346
        int silent_samples = muldiv64(now - s->fifo_empty_ns,
347
                                      NANOSECONDS_PER_SECOND, ASC_FREQ);
348

349
        if (silent_samples > ASC_FIFO_CYCLE_TIME / 2) {
350
            /*
351
             * No new FIFO data within half a cycle time (~23ms) so fill the
352
             * entire available buffer with silence. This prevents an issue
353
             * with the Windows dsound backend whereby the sound appears to
354
             * loop because the FIFO has run out of data, and the driver
355
             * reuses the stale content in its circular audio buffer.
356
             */
357
            AUD_write(s->voice, s->silentbuf, samples << s->shift);
358
        }
359
        return;
360
    }
361

362
    AUD_write(s->voice, s->mixbuf, generated << s->shift);
363
}
364

365
static uint64_t asc_fifo_read(void *opaque, hwaddr addr,
366
                              unsigned size)
367
{
368
    ASCFIFOState *fs = opaque;
369

370
    trace_asc_read_fifo('A' + fs->index, addr, size, fs->fifo[addr]);
371
    return fs->fifo[addr];
372
}
373

374
static void asc_fifo_write(void *opaque, hwaddr addr, uint64_t value,
375
                           unsigned size)
376
{
377
    ASCFIFOState *fs = opaque;
378
    ASCState *s = container_of(fs, ASCState, fifos[fs->index]);
379
    bool fifo_half_irq_enabled = fs->extregs[ASC_EXTREGS_INTCTRL] & 1;
380

381
    trace_asc_write_fifo('A' + fs->index, addr, size, fs->wptr, fs->cnt, value);
382

383
    if (s->regs[ASC_MODE] == 1) {
384
        fs->fifo[fs->wptr++] = value;
385
        fs->wptr &= 0x3ff;
386
        fs->cnt++;
387

388
        if (fs->cnt <= 0x1ff) {
389
            /* FIFO less than half full */
390
            fs->int_status |= ASC_FIFO_STATUS_HALF_FULL;
391
        } else {
392
            /* FIFO at least half full */
393
            fs->int_status &= ~ASC_FIFO_STATUS_HALF_FULL;
394
        }
395

396
        if (fs->cnt == 0x200 && fifo_half_irq_enabled) {
397
            /* Raise FIFO half full interrupt */
398
            asc_raise_irq(s);
399
        }
400

401
        if (fs->cnt == 0x3ff) {
402
            /* Raise FIFO full interrupt */
403
            fs->int_status |= ASC_FIFO_STATUS_FULL_EMPTY;
404
            asc_raise_irq(s);
405
        }
406
    } else {
407
        fs->fifo[addr] = value;
408
    }
409
    return;
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

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

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

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

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

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

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

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

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

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

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
    s->shift = 1;
658
    s->samples = AUD_get_buffer_size_out(s->voice) >> s->shift;
659
    s->mixbuf = g_malloc0(s->samples << s->shift);
660

661
    s->silentbuf = g_malloc0(s->samples << s->shift);
662
    memset(s->silentbuf, 0x80, s->samples << s->shift);
663

664
    /* Add easc registers if required */
665
    if (s->type == ASC_TYPE_EASC) {
666
        memory_region_add_subregion(&s->asc, ASC_EXTREG_OFFSET,
667
                                    &s->fifos[0].mem_extregs);
668
        memory_region_add_subregion(&s->asc,
669
                                    ASC_EXTREG_OFFSET + ASC_EXTREG_SIZE,
670
                                    &s->fifos[1].mem_extregs);
671
    }
672
}
673

674
static void asc_init(Object *obj)
675
{
676
    ASCState *s = ASC(obj);
677
    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
678

679
    memory_region_init(&s->asc, OBJECT(obj), "asc", ASC_SIZE);
680

681
    asc_fifo_init(&s->fifos[0], 0);
682
    asc_fifo_init(&s->fifos[1], 1);
683

684
    memory_region_add_subregion(&s->asc, ASC_FIFO_OFFSET,
685
                                &s->fifos[0].mem_fifo);
686
    memory_region_add_subregion(&s->asc,
687
                                ASC_FIFO_OFFSET + ASC_FIFO_SIZE,
688
                                &s->fifos[1].mem_fifo);
689

690
    memory_region_init_io(&s->mem_regs, OBJECT(obj), &asc_regs_ops, s,
691
                          "asc.regs", ASC_REG_SIZE);
692
    memory_region_add_subregion(&s->asc, ASC_REG_OFFSET, &s->mem_regs);
693

694
    sysbus_init_irq(sbd, &s->irq);
695
    sysbus_init_mmio(sbd, &s->asc);
696
}
697

698
static Property asc_properties[] = {
699
    DEFINE_AUDIO_PROPERTIES(ASCState, card),
700
    DEFINE_PROP_UINT8("asctype", ASCState, type, ASC_TYPE_ASC),
701
    DEFINE_PROP_END_OF_LIST(),
702
};
703

704
static void asc_class_init(ObjectClass *oc, void *data)
705
{
706
    DeviceClass *dc = DEVICE_CLASS(oc);
707
    ResettableClass *rc = RESETTABLE_CLASS(oc);
708

709
    dc->realize = asc_realize;
710
    dc->unrealize = asc_unrealize;
711
    set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
712
    dc->vmsd = &vmstate_asc;
713
    device_class_set_props(dc, asc_properties);
714
    rc->phases.hold = asc_reset_hold;
715
}
716

717
static const TypeInfo asc_info_types[] = {
718
    {
719
        .name = TYPE_ASC,
720
        .parent = TYPE_SYS_BUS_DEVICE,
721
        .instance_size = sizeof(ASCState),
722
        .instance_init = asc_init,
723
        .class_init = asc_class_init,
724
    },
725
};
726

727
DEFINE_TYPES(asc_info_types)
728

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.