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