From nobody Thu Nov 6 10:38:32 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1540820933394310.4143047057355; Mon, 29 Oct 2018 06:48:53 -0700 (PDT) Received: from localhost ([::1]:45694 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gH7uS-0004VB-EC for importer@patchew.org; Mon, 29 Oct 2018 09:48:48 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:32935) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gH7mV-0005AG-Jm for qemu-devel@nongnu.org; Mon, 29 Oct 2018 09:40:38 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gH7mS-0006eS-8S for qemu-devel@nongnu.org; Mon, 29 Oct 2018 09:40:35 -0400 Received: from chuckie.co.uk ([82.165.15.123]:38058 helo=s16892447.onlinehome-server.info) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1gH7mR-0006aX-Pr; Mon, 29 Oct 2018 09:40:32 -0400 Received: from host109-147-184-151.range109-147.btcentralplus.com ([109.147.184.151] helo=kentang.home) by s16892447.onlinehome-server.info with esmtpsa (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.76) (envelope-from ) id 1gH7ma-0000jE-4t; Mon, 29 Oct 2018 13:40:42 +0000 From: Mark Cave-Ayland To: qemu-devel@nongnu.org, kwolf@redhat.com, famz@redhat.com, qemu-block@nongnu.org, jasowang@redhat.com, dgilbert@redhat.com, mreitz@redhat.com, hpoussin@reactos.org, kraxel@redhat.com, pbonzini@redhat.com, afaerber@suse.de, aurelien@aurel32.net, laurent@vivier.eu Date: Mon, 29 Oct 2018 13:39:54 +0000 Message-Id: <20181029134000.11157-6-mark.cave-ayland@ilande.co.uk> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20181029134000.11157-1-mark.cave-ayland@ilande.co.uk> References: <20181029134000.11157-1-mark.cave-ayland@ilande.co.uk> X-SA-Exim-Connect-IP: 109.147.184.151 X-SA-Exim-Mail-From: mark.cave-ayland@ilande.co.uk X-SA-Exim-Version: 4.2.1 (built Sun, 08 Jan 2012 02:45:44 +0000) X-SA-Exim-Scanned: Yes (on s16892447.onlinehome-server.info) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 82.165.15.123 Subject: [Qemu-devel] [PATCH v5 05/11] hw/m68k: Apple Sound Chip (ASC) emulation X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" From: Laurent Vivier This is broken as the linux driver seems broken too... Co-developed-by: Mark Cave-Ayland Signed-off-by: Mark Cave-Ayland Signed-off-by: Laurent Vivier --- hw/audio/Makefile.objs | 1 + hw/audio/asc.c | 446 +++++++++++++++++++++++++++++++++++++++++++++= ++++ include/hw/audio/asc.h | 48 ++++++ 3 files changed, 495 insertions(+) create mode 100644 hw/audio/asc.c create mode 100644 include/hw/audio/asc.h diff --git a/hw/audio/Makefile.objs b/hw/audio/Makefile.objs index 63db383709..44d1ada7b0 100644 --- a/hw/audio/Makefile.objs +++ b/hw/audio/Makefile.objs @@ -16,3 +16,4 @@ common-obj-$(CONFIG_MARVELL_88W8618) +=3D marvell_88w8618= .o common-obj-$(CONFIG_MILKYMIST) +=3D milkymist-ac97.o =20 common-obj-y +=3D soundhw.o +common-obj-$(CONFIG_ASC) +=3D asc.o diff --git a/hw/audio/asc.c b/hw/audio/asc.c new file mode 100644 index 0000000000..4fd23eb8e1 --- /dev/null +++ b/hw/audio/asc.c @@ -0,0 +1,446 @@ +/* + * QEMU Apple Sound Chip emulation + * + * Apple Sound Chip (ASC) 344S0063 + * Enhanced Apple Sound Chip (EASC) 343S1063 + * + * Copyright (c) 2012-2018 Laurent Vivier + * + * This work is licensed under the terms of the GNU GPL, version 2 or late= r. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "hw/sysbus.h" +#include "audio/audio.h" +#include "hw/audio/asc.h" + +/* + * Linux doesn't provide information about ASC, see arch/m68k/mac/macboing= .c + * and arch/m68k/include/asm/mac_asc.h + * + * best information is coming from MAME: + * http://mamedev.org/source/src/emu/sound/asc.h.html + * http://mamedev.org/source/src/emu/sound/asc.c.html + * Emulation by R. Belmont + * + * 0x800: VERSION + * 0x801: MODE + * 1=3DFIFO mode, + * 2=3Dwavetable mode + * 0x802: CONTROL + * bit 0=3Danalog or PWM output, + * 1=3Dstereo/mono, + * 7=3Dprocessing time exceeded + * 0x803: FIFO MODE + * bit 7=3Dclear FIFO, + * bit 1=3D"non-ROM companding", + * bit 0=3D"ROM companding") + * 0x804: FIFO IRQ STATUS + * bit 0=3Dch A 1/2 full, + * 1=3Dch A full, + * 2=3Dch B 1/2 full, + * 3=3Dch B full) + * 0x805: WAVETABLE CONTROL + * bits 0-3 wavetables 0-3 start + * 0x806: VOLUME + * bits 2-4 =3D 3 bit internal ASC volume, + * bits 5-7 =3D volume control sent to Sony sound chip + * 0x807: CLOCK RATE + * 0 =3D Mac 22257 Hz, + * 1 =3D undefined, + * 2 =3D 22050 Hz, + * 3 =3D 44100 Hz + * 0x80a: PLAY REC A + * 0x80f: TEST + * bits 6-7 =3D digital test, + * bits 4-5 =3D analog test + * 0x810: WAVETABLE 0 PHASE + * big-endian 9.15 fixed-point, only 24 bits valid + * 0x814: WAVETABLE 0 INCREMENT + * big-endian 9.15 fixed-point, only 24 bits valid + * 0x818: WAVETABLE 1 PHASE + * 0x81C: WAVETABLE 1 INCREMENT + * 0x820: WAVETABLE 2 PHASE + * 0x824: WAVETABLE 2 INCREMENT + * 0x828: WAVETABLE 3 PHASE + * 0x82C: WAVETABLE 3 INCREMENT + */ + +#define ASC_LENGTH 0x2000 +#define ASC_BUF_SIZE 0x0800 + +#define ASC_REG_BASE 0x0800 +enum { + ASC_VERSION =3D 0x00, + ASC_MODE =3D 0x01, + ASC_CONTROL =3D 0x02, + ASC_FIFOMODE =3D 0x03, + ASC_FIFOIRQ =3D 0x04, + ASC_WAVECTRL =3D 0x05, + ASC_VOLUME =3D 0x06, + ASC_CLOCK =3D 0x07, + ASC_PLAYRECA =3D 0x0a, + ASC_TEST =3D 0x0f, + ASC_WAVETABLE =3D 0x10 +}; + +static inline uint32_t get_phase(ASCState *s, int channel) +{ + return be32_to_cpu(*(uint32_t *)(s->regs + ASC_WAVETABLE + channel * 8= )); +} + +static inline void set_phase(ASCState *s, int channel, uint32_t phase) +{ + *(uint32_t *)(s->regs + ASC_WAVETABLE + channel * 8) =3D cpu_to_be32(p= hase); +} + +static inline uint32_t get_incr(ASCState *s, int channel) +{ + return be32_to_cpu(*(uint32_t *)(s->regs + ASC_WAVETABLE + 4 + + channel * 8)); +} + +static inline uint32_t incr_phase(ASCState *s, int channel) +{ + uint32_t incr =3D get_incr(s, channel); + uint32_t phase =3D get_phase(s, channel); + + set_phase(s, channel, phase + incr); + + return get_phase(s, channel); +} + +static void generate_fifo(ASCState *s, int free_b) +{ + int8_t buf[2048]; + int i; + int to_copy; + + do { + to_copy =3D audio_MIN(sizeof(buf), free_b); + for (i =3D 0; i < (to_copy >> 1); to_copy++) { + int8_t left, right; + + left =3D s->fifo[s->a_rptr] ^ 0x80; + right =3D s->fifo[s->b_rptr + 0x400] ^ 0x80; + + if (s->a_cnt) { + s->a_rptr++; + s->a_rptr &=3D 0x3ff; + s->a_cnt--; + } + + if (s->b_cnt) { + s->b_rptr++; + s->b_rptr &=3D 0x3ff; + s->b_cnt--; + } + + if (s->type =3D=3D ASC_TYPE_SONORA) { + if (s->a_cnt < 0x200) { + s->regs[ASC_FIFOIRQ] |=3D 4; /* FIFO A less than half = full */ + qemu_irq_raise(s->irq); + } + if (s->b_cnt < 0x200) { + s->regs[ASC_FIFOIRQ] |=3D 8; /* FIFO B less than half = full */ + qemu_irq_raise(s->irq); + } + } else { + if (s->a_cnt =3D=3D 0x1ff) { + s->regs[ASC_FIFOIRQ] |=3D 1; /* FIFO A half empty */ + qemu_irq_raise(s->irq); + } else if (s->a_cnt =3D=3D 0x001) { + s->regs[ASC_FIFOIRQ] |=3D 2; /* FIFO A half empty */ + qemu_irq_raise(s->irq); + } + if (s->b_cnt =3D=3D 0x1ff) { + s->regs[ASC_FIFOIRQ] |=3D 4; /* FIFO A half empty */ + qemu_irq_raise(s->irq); + } else if (s->b_cnt =3D=3D 0x001) { + s->regs[ASC_FIFOIRQ] |=3D 8; /* FIFO A half empty */ + qemu_irq_raise(s->irq); + } + } + buf[i * 2] =3D left; + buf[i * 2 + 1] =3D right; + } + AUD_write(s->channel, buf, to_copy); + free_b -=3D to_copy; + } while (free_b); +} + +static void generate_wavetable(ASCState *s, int free_b) +{ + int8_t buf[2048]; + int i; + int channel; + int to_copy; + int control =3D s->regs[ASC_WAVECTRL]; + + do { + to_copy =3D audio_MIN(sizeof(buf), free_b); + for (i =3D 0; i < (to_copy >> 1); i++) { + int32_t left, right; + int8_t sample; + + left =3D 0; + right =3D 0; + + if (control) { /* FIXME: how to use it ? */ + for (channel =3D 0; channel < 4; channel++) { + uint32_t phase =3D incr_phase(s, channel); + + phase =3D (phase >> 15) & 0x1ff; + sample =3D s->fifo[0x200 * channel + phase] ^ 0x80; + + left +=3D sample; + right +=3D sample; + } + buf[i * 2] =3D left >> 2; + buf[i * 2 + 1] =3D right >> 2; + } else { + /* FIXME: only works with linux macboing.c */ + uint32_t phase =3D incr_phase(s, 0); + phase =3D (phase >> 15) & 0x7ff; + sample =3D s->fifo[phase]; + buf[i * 2] =3D sample; + buf[i * 2 + 1] =3D sample; + } + } + AUD_write(s->channel, buf, to_copy); + free_b -=3D to_copy; + } while (free_b); +} + +static void asc_out_cb(void *opaque, int free_b) +{ + ASCState *s =3D opaque; + + switch (s->regs[ASC_MODE] & 3) { + case 0: /* Off */ + break; + case 1: /* FIFO mode */ + generate_fifo(s, free_b); + break; + case 2: /* Wave table mode */ + generate_wavetable(s, free_b); + break; + } +} + +static uint64_t asc_read(void *opaque, hwaddr addr, + unsigned size) +{ + ASCState *s =3D opaque; + uint64_t prev; + + if (addr < 0x800) { + return s->fifo[addr]; + } + + addr -=3D 0x800; + + if (addr >=3D 0x030) { + return 0; + } + + switch (addr) { + case ASC_VERSION: + switch (s->type) { + case ASC_TYPE_ASC: + return 0; + case ASC_TYPE_V8: + case ASC_TYPE_EAGLE: + case ASC_TYPE_SPICE: + case ASC_TYPE_VASP: + return 0xe8; + case ASC_TYPE_SONORA: + return 0xbc; + default: + break; + } + break; + case ASC_MODE: + switch (s->type) { + case ASC_TYPE_V8: + case ASC_TYPE_EAGLE: + case ASC_TYPE_SPICE: + case ASC_TYPE_VASP: + return 1; + default: + break; + } + break; + case ASC_CONTROL: + switch (s->type) { + case ASC_TYPE_V8: + case ASC_TYPE_EAGLE: + case ASC_TYPE_SPICE: + case ASC_TYPE_VASP: + return 1; + default: + break; + } + break; + case ASC_FIFOIRQ: + if (s->type =3D=3D ASC_TYPE_V8) { + prev =3D 3; + } else { + prev =3D s->regs[ASC_FIFOIRQ]; + } + s->regs[ASC_FIFOIRQ] =3D 0; + qemu_irq_lower(s->irq); + return prev; + default: + break; + } + + return s->regs[addr]; +} + +static void asc_write(void *opaque, hwaddr addr, uint64_t value, + unsigned size) +{ + ASCState *s =3D opaque; + + if (addr < 0x800) { + if (s->regs[ASC_MODE] =3D=3D 1) { + if (addr < 0x400) { + /* FIFO A */ + s->fifo[s->a_wptr++] =3D value; + s->a_cnt++; + if (s->a_cnt =3D=3D 0x3ff) { + s->regs[ASC_FIFOIRQ] |=3D 2; /* FIFO A Full */ + } + s->a_wptr &=3D 0x3ff; + } else { + /* FIFO B */ + s->fifo[s->b_wptr++ + 0x400] =3D value; + s->b_cnt++; + if (s->b_cnt =3D=3D 0x3ff) { + s->regs[ASC_FIFOIRQ] |=3D 8; /* FIFO B Full */ + } + s->b_wptr &=3D 0x3ff; + } + } else { + s->fifo[addr] =3D value; + } + return; + } + + addr -=3D 0x800; + if (addr >=3D 0x30) { + return; + } + switch (addr) { + case ASC_MODE: + value &=3D 3; + if (value !=3D s->regs[ASC_MODE]) { + s->a_rptr =3D 0; + s->a_wptr =3D 0; + s->a_cnt =3D 0; + s->b_rptr =3D 0; + s->b_wptr =3D 0; + s->b_cnt =3D 0; + if (value !=3D 0) { + AUD_set_active_out(s->channel, 1); + } else { + AUD_set_active_out(s->channel, 0); + } + } + break; + case ASC_FIFOMODE: + if (value & 0x80) { + s->a_rptr =3D 0; + s->a_wptr =3D 0; + s->a_cnt =3D 0; + s->b_rptr =3D 0; + s->b_wptr =3D 0; + s->b_cnt =3D 0; + } + break; + case ASC_WAVECTRL: + break; + } + s->regs[addr] =3D value; +} + +static const MemoryRegionOps asc_mmio_ops =3D { + .read =3D asc_read, + .write =3D asc_write, + .impl =3D { + .min_access_size =3D 1, + .max_access_size =3D 1, + }, + .endianness =3D DEVICE_BIG_ENDIAN, +}; + +static void asc_reset(DeviceState *d) +{ + ASCState *s =3D ASC(d); + + AUD_set_active_out(s->channel, 0); + + memset(s->regs, 0, sizeof(s->regs)); + s->a_wptr =3D 0; + s->a_rptr =3D 0; + s->a_cnt =3D 0; + s->b_wptr =3D 0; + s->b_rptr =3D 0; + s->b_cnt =3D 0; +} + +static void asc_init(Object *obj) +{ + ASCState *s =3D ASC(obj); + SysBusDevice *sbd =3D SYS_BUS_DEVICE(obj); + struct audsettings as; + + AUD_register_card("Apple Sound Chip", &s->card); + + as.freq =3D 22257; + as.nchannels =3D 2; + as.fmt =3D AUD_FMT_S8; + as.endianness =3D 0; + + s->channel =3D AUD_open_out(&s->card, s->channel, "asc.out", + s, asc_out_cb, &as); + + s->fifo =3D g_malloc0(ASC_BUF_SIZE); + + memory_region_init_io(&s->mem_regs, obj, &asc_mmio_ops, s, "asc", + ASC_LENGTH); + + sysbus_init_irq(sbd, &s->irq); + sysbus_init_mmio(sbd, &s->mem_regs); +} + +static Property asc_properties[] =3D { + DEFINE_PROP_UINT8("asctype", ASCState, type, ASC_TYPE_ASC), + DEFINE_PROP_END_OF_LIST(), +}; + +static void asc_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(oc); + + dc->reset =3D asc_reset; + dc->props =3D asc_properties; +} + +static TypeInfo asc_info =3D { + .name =3D TYPE_ASC, + .parent =3D TYPE_SYS_BUS_DEVICE, + .instance_size =3D sizeof(ASCState), + .instance_init =3D asc_init, + .class_init =3D asc_class_init, +}; + +static void asc_register_types(void) +{ + type_register_static(&asc_info); +} + +type_init(asc_register_types) diff --git a/include/hw/audio/asc.h b/include/hw/audio/asc.h new file mode 100644 index 0000000000..3540e32f69 --- /dev/null +++ b/include/hw/audio/asc.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2012-2018 Laurent Vivier + * + * This work is licensed under the terms of the GNU GPL, version 2 or late= r. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef HW_AUDIO_ASC_H +#define HW_AUDIO_ASC_H + +#include "qemu/osdep.h" +#include "hw/sysbus.h" +#include "audio/audio.h" + +enum { + ASC_TYPE_ASC =3D 0, /* original discrete Apple Sound Chip */ + ASC_TYPE_EASC =3D 1, /* discrete Enhanced Apple Sound Chip */ + ASC_TYPE_V8 =3D 2, /* ASC included in the V8 ASIC (LC/LCII) */ + ASC_TYPE_EAGLE =3D 3, /* ASC included in the Eagle ASIC (Classic II)= */ + ASC_TYPE_SPICE =3D 4, /* ASC included in the Spice ASIC (Color Class= ic) */ + ASC_TYPE_SONORA =3D 5, /* ASC included in the Sonora ASIC (LCIII) */ + ASC_TYPE_VASP =3D 6, /* ASC included in the VASP ASIC (IIvx/IIvi) = */ + ASC_TYPE_ARDBEG =3D 7 /* ASC included in the Ardbeg ASIC (LC520) */ +}; + +typedef struct ASCState { + SysBusDevice parent_obj; + + MemoryRegion mem_regs; + QEMUSoundCard card; + SWVoiceOut *channel; + + qemu_irq irq; + + uint8_t type; + int a_wptr, a_rptr, a_cnt; + int b_wptr, b_rptr, b_cnt; + + uint8_t *fifo; + + uint8_t regs[48]; +} ASCState; + +#define TYPE_ASC "apple-sound-chip" +#define ASC(obj) OBJECT_CHECK(ASCState, (obj), TYPE_ASC) + +#endif --=20 2.11.0