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