From patchwork Wed Jun 27 23:29:42 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Vivier X-Patchwork-Id: 935795 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=vivier.eu Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41GKGS5BJBz9s01 for ; Thu, 28 Jun 2018 09:42:56 +1000 (AEST) Received: from localhost ([::1]:33686 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fYK5O-0008GL-DV for incoming@patchwork.ozlabs.org; Wed, 27 Jun 2018 19:42:54 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:48596) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fYJtV-00082T-8u for qemu-devel@nongnu.org; Wed, 27 Jun 2018 19:30:40 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fYJtR-0003lQ-Ps for qemu-devel@nongnu.org; Wed, 27 Jun 2018 19:30:37 -0400 Received: from mout.kundenserver.de ([212.227.126.187]:54179) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1fYJtJ-0003hn-Pc; Wed, 27 Jun 2018 19:30:26 -0400 Received: from localhost.localdomain ([78.238.229.36]) by mrelayeu.kundenserver.de (mreue001 [212.227.15.167]) with ESMTPSA (Nemesis) id 0M6ror-1gK4g71UQP-00wmop; Thu, 28 Jun 2018 01:29:59 +0200 From: Laurent Vivier To: qemu-devel@nongnu.org Date: Thu, 28 Jun 2018 01:29:42 +0200 Message-Id: <20180627232951.14725-2-laurent@vivier.eu> X-Mailer: git-send-email 2.14.4 In-Reply-To: <20180627232951.14725-1-laurent@vivier.eu> References: <20180627232951.14725-1-laurent@vivier.eu> X-Provags-ID: V03:K1:lRYADil+q1t6aa92OxZeydffpZ078XYfqkFTqRhbdzcuHFr54cq o9pwpJyS3zRaYbJ5+hhFlUKSmkcZgdkFunpYRgAVZdOoVzKqqyhF6fLq/sMqVTZD0cHHDNZ ThotK2HuVgE4QQWv0KpwS1x/8tlj0r6t/GXHcnmh0chkX8KMS+9Y9uB9Nv0YDDTgnv/LmXU jQQiEdsd5bUBP52IBg1Cw== X-UI-Out-Filterresults: notjunk:1; V01:K0:8HsenzDxLO0=:JaHSeb9fhq2aBR0NlyVUns XZRLFoHUnHkK69zoF0tAKsAOhWkpsaNY1WzkEXhcJr/k+Eg5lJU5SuIpJp4Eqw4vtTN4oMRrN z2qPACoVdfGn0JDnewT4mhseg5LTQz8gZf0tnJ6iKHhusOqYW3PwbSkX9ulo+ym8hktOSgulx zbQ/ndS46WlRmVAhiatzKebYiTGZSJCa1EhmRUSkfim4hijdxXlqTMp74SU/KnWIlp8eMp5L9 J1gYskGk0ZlxmiOyVbGTcEnT4h1qvN+FHmk3I/PZ4Tq4DTdRRG0uzd1Y26pbvgm+wM6k9+uP2 R5EER0gN4hjyHcdAgTghyHskk1+H1d2XWa80v+sQMm/vj0cOs7eMOQeC7xp3EKfMKPzC8O+j4 3EadiWQ/LNTjBPYBpZ/Axi48LfK/w3u3hfDuVa8qdrLoK5xnD84Eu+SwyIj5uLecd15+8TRAs f/EbZ+LTnUbQBST9H/0Eu9Wbjvf+oxkRX62OqgVfdffth4xTSf6P+bKb+0tLP0jpTcKUKPmh0 bkHskz/nId9Z5ifHm9ev9plTKxUydNn+vmTTZQoyLrl7Mzj2CQIXYed8B6fkoHcNqOaULflo6 IMqEwTFmy/vB4UqQn06IHPflIkfrp7+w8OK1rVjOpDzcSTzgVWdy5po1gSuNmb+Yr2kQ2pxY/ l3Kn8ZpUqlFf6xAjC+hdXYt+F1a5Uxzn8cI3XtXcPCBq3jpPsk8HLyq0HdhGytboUqPY= X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 212.227.126.187 Subject: [Qemu-devel] [RFC v3 01/10] hw/m68k: add via support 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: , Cc: Kevin Wolf , Fam Zheng , qemu-block@nongnu.org, Jason Wang , Mark Cave-Ayland , "Dr. David Alan Gilbert" , Laurent Vivier , =?utf-8?q?Herv=C3=A9_Poussineau?= , Gerd Hoffmann , Paolo Bonzini , Max Reitz , Yongbok Kim , =?utf-8?q?Andreas_F=C3=A4rber?= , Aurelien Jarno Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Co-developed-by: Mark Cave-Ayland Signed-off-by: Mark Cave-Ayland Signed-off-by: Laurent Vivier --- hw/misc/Makefile.objs | 1 + hw/misc/mac_via.c | 675 ++++++++++++++++++++++++++++++++++++++++++++++ include/hw/misc/mac_via.h | 106 ++++++++ 3 files changed, 782 insertions(+) create mode 100644 hw/misc/mac_via.c create mode 100644 include/hw/misc/mac_via.h diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index 9350900845..24eb8011f1 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -70,5 +70,6 @@ obj-$(CONFIG_PVPANIC) += pvpanic.o obj-$(CONFIG_HYPERV_TESTDEV) += hyperv_testdev.o obj-$(CONFIG_AUX) += auxbus.o obj-$(CONFIG_ASPEED_SOC) += aspeed_scu.o aspeed_sdmc.o +obj-$(CONFIG_MAC_VIA) += mac_via.o obj-y += mmio_interface.o obj-$(CONFIG_MSF2) += msf2-sysreg.o diff --git a/hw/misc/mac_via.c b/hw/misc/mac_via.c new file mode 100644 index 0000000000..586477ca9e --- /dev/null +++ b/hw/misc/mac_via.c @@ -0,0 +1,675 @@ +/* + * QEMU m68k Macintosh VIA device support + * + * Copyright (c) 2011-2018 Laurent Vivier + * + * Some parts from hw/cuda.c + * + * Copyright (c) 2004-2007 Fabrice Bellard + * Copyright (c) 2007 Jocelyn Mayer + * + * some parts from linux-2.6.29, arch/m68k/include/asm/mac_via.h + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "hw/sysbus.h" +#include "qemu/timer.h" +#include "hw/misc/mac_via.h" +#include "hw/misc/mos6522.h" +#include "hw/input/adb.h" +#include "sysemu/sysemu.h" +#include "qapi/error.h" +#include "qemu/cutils.h" + + +/* + * VIAs: There are two in every machine, + */ + +#define VIA_SIZE (0x2000) + +/* + * Not all of these are true post MacII I think. + * CSA: probably the ones CHRP marks as 'unused' change purposes + * when the IWM becomes the SWIM. + * http://www.rs6000.ibm.com/resource/technology/chrpio/via5.mak.html + * ftp://ftp.austin.ibm.com/pub/technology/spec/chrp/inwork/CHRP_IORef_1.0.pdf + * + * also, http://developer.apple.com/technotes/hw/hw_09.html claims the + * following changes for IIfx: + * VIA1A_vSccWrReq not available and that VIA1A_vSync has moved to an IOP. + * Also, "All of the functionality of VIA2 has been moved to other chips". + */ + +#define VIA1A_vSccWrReq 0x80 /* SCC write. (input) + * [CHRP] SCC WREQ: Reflects the state of the + * Wait/Request pins from the SCC. + * [Macintosh Family Hardware] + * as CHRP on SE/30,II,IIx,IIcx,IIci. + * on IIfx, "0 means an active request" + */ +#define VIA1A_vRev8 0x40 /* Revision 8 board ??? + * [CHRP] En WaitReqB: Lets the WaitReq_L + * signal from port B of the SCC appear on + * the PA7 input pin. Output. + * [Macintosh Family] On the SE/30, this + * is the bit to flip screen buffers. + * 0=alternate, 1=main. + * on II,IIx,IIcx,IIci,IIfx this is a bit + * for Rev ID. 0=II,IIx, 1=IIcx,IIci,IIfx + */ +#define VIA1A_vHeadSel 0x20 /* Head select for IWM. + * [CHRP] unused. + * [Macintosh Family] "Floppy disk + * state-control line SEL" on all but IIfx + */ +#define VIA1A_vOverlay 0x10 /* [Macintosh Family] On SE/30,II,IIx,IIcx + * this bit enables the "Overlay" address + * map in the address decoders as it is on + * reset for mapping the ROM over the reset + * vector. 1=use overlay map. + * On the IIci,IIfx it is another bit of the + * CPU ID: 0=normal IIci, 1=IIci with parity + * feature or IIfx. + * [CHRP] En WaitReqA: Lets the WaitReq_L + * signal from port A of the SCC appear + * on the PA7 input pin (CHRP). Output. + * [MkLinux] "Drive Select" + * (with 0x20 being 'disk head select') + */ +#define VIA1A_vSync 0x08 /* [CHRP] Sync Modem: modem clock select: + * 1: select the external serial clock to + * drive the SCC's /RTxCA pin. + * 0: Select the 3.6864MHz clock to drive + * the SCC cell. + * [Macintosh Family] Correct on all but IIfx + */ + +/* Macintosh Family Hardware sez: bits 0-2 of VIA1A are volume control + * on Macs which had the PWM sound hardware. Reserved on newer models. + * On IIci,IIfx, bits 1-2 are the rest of the CPU ID: + * bit 2: 1=IIci, 0=IIfx + * bit 1: 1 on both IIci and IIfx. + * MkLinux sez bit 0 is 'burnin flag' in this case. + * CHRP sez: VIA1A bits 0-2 and 5 are 'unused': if programmed as + * inputs, these bits will read 0. + */ +#define VIA1A_vVolume 0x07 /* Audio volume mask for PWM */ +#define VIA1A_CPUID0 0x02 /* CPU id bit 0 on RBV, others */ +#define VIA1A_CPUID1 0x04 /* CPU id bit 0 on RBV, others */ +#define VIA1A_CPUID2 0x10 /* CPU id bit 0 on RBV, others */ +#define VIA1A_CPUID3 0x40 /* CPU id bit 0 on RBV, others */ + +/* Info on VIA1B is from Macintosh Family Hardware & MkLinux. + * CHRP offers no info. */ +#define VIA1B_vSound 0x80 /* Sound enable (for compatibility with + * PWM hardware) 0=enabled. + * Also, on IIci w/parity, shows parity error + * 0=error, 1=OK. */ +#define VIA1B_vMystery 0x40 /* On IIci, parity enable. 0=enabled,1=disabled + * On SE/30, vertical sync interrupt enable. + * 0=enabled. This vSync interrupt shows up + * as a slot $E interrupt. */ +#define VIA1B_vADBS2 0x20 /* ADB state input bit 1 (unused on IIfx) */ +#define VIA1B_vADBS1 0x10 /* ADB state input bit 0 (unused on IIfx) */ +#define VIA1B_vADBInt 0x08 /* ADB interrupt 0=interrupt (unused on IIfx)*/ +#define VIA1B_vRTCEnb 0x04 /* Enable Real time clock. 0=enabled. */ +#define VIA1B_vRTCClk 0x02 /* Real time clock serial-clock line. */ +#define VIA1B_vRTCData 0x01 /* Real time clock serial-data line. */ + +/* + * VIA2 A register is the interrupt lines raised off the nubus + * slots. + * The below info is from 'Macintosh Family Hardware.' + * MkLinux calls the 'IIci internal video IRQ' below the 'RBV slot 0 irq.' + * It also notes that the slot $9 IRQ is the 'Ethernet IRQ' and + * defines the 'Video IRQ' as 0x40 for the 'EVR' VIA work-alike. + * Perhaps OSS uses vRAM1 and vRAM2 for ADB. + */ + +#define VIA2A_vRAM1 0x80 /* RAM size bit 1 (IIci: reserved) */ +#define VIA2A_vRAM0 0x40 /* RAM size bit 0 (IIci: internal video IRQ) */ +#define VIA2A_vIRQE 0x20 /* IRQ from slot $E */ +#define VIA2A_vIRQD 0x10 /* IRQ from slot $D */ +#define VIA2A_vIRQC 0x08 /* IRQ from slot $C */ +#define VIA2A_vIRQB 0x04 /* IRQ from slot $B */ +#define VIA2A_vIRQA 0x02 /* IRQ from slot $A */ +#define VIA2A_vIRQ9 0x01 /* IRQ from slot $9 */ + +/* RAM size bits decoded as follows: + * bit1 bit0 size of ICs in bank A + * 0 0 256 kbit + * 0 1 1 Mbit + * 1 0 4 Mbit + * 1 1 16 Mbit + */ + +/* + * Register B has the fun stuff in it + */ + +#define VIA2B_vVBL 0x80 /* VBL output to VIA1 (60.15Hz) driven by + * timer T1. + * on IIci, parity test: 0=test mode. + * [MkLinux] RBV_PARODD: 1=odd,0=even. */ +#define VIA2B_vSndJck 0x40 /* External sound jack status. + * 0=plug is inserted. On SE/30, always 0 */ +#define VIA2B_vTfr0 0x20 /* Transfer mode bit 0 ack from NuBus */ +#define VIA2B_vTfr1 0x10 /* Transfer mode bit 1 ack from NuBus */ +#define VIA2B_vMode32 0x08 /* 24/32bit switch - doubles as cache flush + * on II, AMU/PMMU control. + * if AMU, 0=24bit to 32bit translation + * if PMMU, 1=PMMU is accessing page table. + * on SE/30 tied low. + * on IIx,IIcx,IIfx, unused. + * on IIci/RBV, cache control. 0=flush cache. + */ +#define VIA2B_vPower 0x04 /* Power off, 0=shut off power. + * on SE/30 this signal sent to PDS card. + */ +#define VIA2B_vBusLk 0x02 /* Lock NuBus transactions, 0=locked. + * on SE/30 sent to PDS card. + */ +#define VIA2B_vCDis 0x01 /* Cache control. On IIci, 1=disable cache card + * on others, 0=disable processor's instruction + * and data caches. + */ + +/* interrupt flags */ + +#define IRQ_SET 0x80 + +/* common */ + +#define VIA_IRQ_TIMER1 0x40 +#define VIA_IRQ_TIMER2 0x20 + +/* Apple sez: http://developer.apple.com/technotes/ov/ov_04.html + * Another example of a valid function that has no ROM support is the use + * of the alternate video page for page-flipping animation. Since there + * is no ROM call to flip pages, it is necessary to go play with the + * right bit in the VIA chip (6522 Versatile Interface Adapter). + * [CSA: don't know which one this is, but it's one of 'em!] + */ + +/* + * 6522 registers - see databook. + * CSA: Assignments for VIA1 confirmed from CHRP spec. + */ + +/* partial address decode. 0xYYXX : XX part for RBV, YY part for VIA */ +/* Note: 15 VIA regs, 8 RBV regs */ + +#define vBufB 0x0000 /* [VIA/RBV] Register B */ +#define vBufAH 0x0200 /* [VIA only] Buffer A, with handshake. DON'T USE! */ +#define vDirB 0x0400 /* [VIA only] Data Direction Register B. */ +#define vDirA 0x0600 /* [VIA only] Data Direction Register A. */ +#define vT1CL 0x0800 /* [VIA only] Timer one counter low. */ +#define vT1CH 0x0a00 /* [VIA only] Timer one counter high. */ +#define vT1LL 0x0c00 /* [VIA only] Timer one latches low. */ +#define vT1LH 0x0e00 /* [VIA only] Timer one latches high. */ +#define vT2CL 0x1000 /* [VIA only] Timer two counter low. */ +#define vT2CH 0x1200 /* [VIA only] Timer two counter high. */ +#define vSR 0x1400 /* [VIA only] Shift register. */ +#define vACR 0x1600 /* [VIA only] Auxilary control register. */ +#define vPCR 0x1800 /* [VIA only] Peripheral control register. */ + /* CHRP sez never ever to *write* this. + * Mac family says never to *change* this. + * In fact we need to initialize it once at start. + */ +#define vIFR 0x1a00 /* [VIA/RBV] Interrupt flag register. */ +#define vIER 0x1c00 /* [VIA/RBV] Interrupt enable register. */ +#define vBufA 0x1e00 /* [VIA/RBV] register A (no handshake) */ + +/* from linux 2.6 drivers/macintosh/via-macii.c */ + +/* Bits in ACR */ + +#define VIA1ACR_vShiftCtrl 0x1c /* Shift register control bits */ +#define VIA1ACR_vShiftExtClk 0x0c /* Shift on external clock */ +#define VIA1ACR_vShiftOut 0x10 /* Shift out if 1 */ + +/* Apple Macintosh Family Hardware Refenece + * Table 19-10 ADB transaction states + */ + +#define VIA1B_vADB_StateMask (VIA1B_vADBS1 | VIA1B_vADBS2) +#define VIA1B_vADB_StateShift 4 + +#define VIA_ADB_POLL_FREQ 50 /* XXX: not real */ + +#define VIA_TIMER_FREQ (783360) + + +static void via1_VBL(void *opaque) +{ + MacVIAState *m = opaque; + MOS6522Q800VIA1State *v1s = MOS6522_Q800_VIA1(&m->mos6522_via1); + MOS6522State *s = MOS6522(v1s); + MOS6522DeviceClass *mdc = MOS6522_DEVICE_GET_CLASS(s); + + s->ifr |= VIA1_IRQ_VBLANK; + mdc->update_irq(s); + + timer_mod(m->VBL_timer, (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 16630) + / 16630 * 16630); +} + +static void via1_one_second(void *opaque) +{ + MacVIAState *m = opaque; + MOS6522Q800VIA1State *v1s = MOS6522_Q800_VIA1(&m->mos6522_via1); + MOS6522State *s = MOS6522(v1s); + MOS6522DeviceClass *mdc = MOS6522_DEVICE_GET_CLASS(s); + + s->ifr |= VIA1_IRQ_ONE_SECOND; + mdc->update_irq(s); + + timer_mod(m->one_second_timer, (qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + + 1000) / 1000 * 1000); +} + +static void via1_irq_request(void *opaque, int irq, int level) +{ + MOS6522Q800VIA1State *v1s = opaque; + MOS6522State *s = MOS6522(v1s); + MOS6522DeviceClass *mdc = MOS6522_DEVICE_GET_CLASS(s); + + if (level) { + s->ifr |= 1 << irq; + } else { + s->ifr &= ~(1 << irq); + } + + mdc->update_irq(s); +} + +static void via2_irq_request(void *opaque, int irq, int level) +{ + MOS6522Q800VIA2State *v2s = opaque; + MOS6522State *s = MOS6522(v2s); + MOS6522DeviceClass *mdc = MOS6522_DEVICE_GET_CLASS(s); + + if (level) { + s->ifr |= 1 << irq; + } else { + s->ifr &= ~(1 << irq); + } + + mdc->update_irq(s); +} + +#define RTC_OFFSET 2082844800 +static uint8_t PRAM[256]; + +static void via1_rtc_update(MacVIAState *m) +{ + MOS6522Q800VIA1State *v1s = MOS6522_Q800_VIA1(&m->mos6522_via1); + MOS6522State *s = MOS6522(v1s); + + if (s->b & VIA1B_vRTCEnb) { + return; + } + + if (s->dirb & VIA1B_vRTCData) { + /* send bits to the RTC */ + if (!(v1s->last_b & VIA1B_vRTCClk) && (s->b & VIA1B_vRTCClk)) { + m->data_out <<= 1; + m->data_out |= s->b & VIA1B_vRTCData; + m->data_out_cnt++; + } + } else { + /* receive bits from the RTC */ + if ((v1s->last_b & VIA1B_vRTCClk) && + !(s->b & VIA1B_vRTCClk) && + m->data_in_cnt) { + s->b = (s->b & ~VIA1B_vRTCData) | + ((m->data_in >> 7) & VIA1B_vRTCData); + m->data_in <<= 1; + m->data_in_cnt--; + } + } + + if (m->data_out_cnt == 8) { + m->data_out_cnt = 0; + + if (m->cmd == 0) { + if (m->data_out & 0x80) { + /* this is a read command */ + uint32_t time = m->tick_offset + + (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / + NANOSECONDS_PER_SECOND); + if (m->data_out == 0x81) { /* seconds register 0 */ + m->data_in = time & 0xff; + m->data_in_cnt = 8; + } else if (m->data_out == 0x85) { /* seconds register 1 */ + m->data_in = (time >> 8) & 0xff; + m->data_in_cnt = 8; + } else if (m->data_out == 0x89) { /* seconds register 2 */ + m->data_in = (time >> 16) & 0xff; + m->data_in_cnt = 8; + } else if (m->data_out == 0x8d) { /* seconds register 3 */ + m->data_in = (time >> 24) & 0xff; + m->data_in_cnt = 8; + } else if ((m->data_out & 0xf3) == 0xa1) { + /* PRAM address 0x10 -> 0x13 */ + int addr = (m->data_out >> 2) & 0x03; + m->data_in = PRAM[addr]; + m->data_in_cnt = 8; + } else if ((m->data_out & 0xf3) == 0xa1) { + /* PRAM address 0x00 -> 0x0f */ + int addr = (m->data_out >> 2) & 0x0f; + m->data_in = PRAM[addr]; + m->data_in_cnt = 8; + } else if ((m->data_out & 0xf8) == 0xb8) { + /* extended memory designator and sector number */ + m->cmd = m->data_out; + } + } else { + /* this is a write command */ + m->cmd = m->data_out; + } + } else { + if (m->cmd & 0x80) { + if ((m->cmd & 0xf8) == 0xb8) { + /* extended memory designator and sector number */ + int sector = m->cmd & 0x07; + int addr = (m->data_out >> 2) & 0x1f; + + m->data_in = PRAM[sector * 8 + addr]; + m->data_in_cnt = 8; + } + } else if (!m->wprotect) { + /* this is a write command */ + if (m->alt != 0) { + /* extended memory designator and sector number */ + int sector = m->cmd & 0x07; + int addr = (m->alt >> 2) & 0x1f; + + PRAM[sector * 8 + addr] = m->data_out; + + m->alt = 0; + } else if (m->cmd == 0x01) { /* seconds register 0 */ + /* FIXME */ + } else if (m->cmd == 0x05) { /* seconds register 1 */ + /* FIXME */ + } else if (m->cmd == 0x09) { /* seconds register 2 */ + /* FIXME */ + } else if (m->cmd == 0x0d) { /* seconds register 3 */ + /* FIXME */ + } else if (m->cmd == 0x31) { + /* Test Register */ + } else if (m->cmd == 0x35) { + /* Write Protect register */ + m->wprotect = m->data_out & 1; + } else if ((m->cmd & 0xf3) == 0xa1) { + /* PRAM address 0x10 -> 0x13 */ + int addr = (m->cmd >> 2) & 0x03; + PRAM[addr] = m->data_out; + } else if ((m->cmd & 0xf3) == 0xa1) { + /* PRAM address 0x00 -> 0x0f */ + int addr = (m->cmd >> 2) & 0x0f; + PRAM[addr] = m->data_out; + } else if ((m->cmd & 0xf8) == 0xb8) { + /* extended memory designator and sector number */ + m->alt = m->cmd; + } + } + } + m->data_out = 0; + } +} + +static uint64_t mos6522_q800_via1_read(void *opaque, hwaddr addr, unsigned size) +{ + MOS6522Q800VIA1State *s = opaque; + MOS6522State *ms = MOS6522(s); + + addr = (addr >> 9) & 0xf; + return mos6522_read(ms, addr, size); +} + +static void mos6522_q800_via1_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size) +{ + MOS6522Q800VIA1State *s = opaque; + MOS6522State *ms = MOS6522(s); + + addr = (addr >> 9) & 0xf; + mos6522_write(ms, addr, val, size); +} + +static const MemoryRegionOps mos6522_q800_via1_ops = { + .read = mos6522_q800_via1_read, + .write = mos6522_q800_via1_write, + .endianness = DEVICE_BIG_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 1, + }, +}; + +static uint64_t mos6522_q800_via2_read(void *opaque, hwaddr addr, unsigned size) +{ + MOS6522Q800VIA2State *s = opaque; + MOS6522State *ms = MOS6522(s); + + addr = (addr >> 9) & 0xf; + return mos6522_read(ms, addr, size); +} + +static void mos6522_q800_via2_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size) +{ + MOS6522Q800VIA2State *s = opaque; + MOS6522State *ms = MOS6522(s); + + addr = (addr >> 9) & 0xf; + mos6522_write(ms, addr, val, size); +} + +static const MemoryRegionOps mos6522_q800_via2_ops = { + .read = mos6522_q800_via2_read, + .write = mos6522_q800_via2_write, + .endianness = DEVICE_BIG_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 1, + }, +}; + +static void mac_via_reset(DeviceState *dev) +{ + MacVIAState *m = MAC_VIA(dev); + + timer_mod(m->VBL_timer, (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 16630) + / 16630 * 16630); + + timer_mod(m->one_second_timer, (qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + + 1000) / 1000 * 1000); +} + +static void mac_via_realize(DeviceState *dev, Error **errp) +{ + MacVIAState *m = MAC_VIA(dev); + struct tm tm; + + /* VIA 1 */ + m->one_second_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, via1_one_second, m); + m->VBL_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, via1_VBL, m); + + qemu_get_timedate(&tm, 0); + m->tick_offset = (uint32_t)mktimegm(&tm) + RTC_OFFSET; +} + +static void mac_via_init(Object *obj) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + MacVIAState *m = MAC_VIA(obj); + MOS6522State *ms; + + object_initialize(&m->mos6522_via1, sizeof(m->mos6522_via1), + TYPE_MOS6522_Q800_VIA1); + qdev_set_parent_bus(DEVICE(&m->mos6522_via1), sysbus_get_default()); + object_property_add_child(obj, TYPE_MOS6522_Q800_VIA1, + OBJECT(&m->mos6522_via1), NULL); + + object_initialize(&m->mos6522_via2, sizeof(m->mos6522_via2), + TYPE_MOS6522_Q800_VIA2); + qdev_set_parent_bus(DEVICE(&m->mos6522_via2), sysbus_get_default()); + object_property_add_child(obj, TYPE_MOS6522_Q800_VIA2, + OBJECT(&m->mos6522_via2), NULL); + + /* Pass through mos6522 output IRQs */ + ms = MOS6522(&m->mos6522_via1); + object_property_add_alias(obj, "irq[0]", OBJECT(ms), + SYSBUS_DEVICE_GPIO_IRQ "[0]", &error_abort); + ms = MOS6522(&m->mos6522_via2); + object_property_add_alias(obj, "irq[1]", OBJECT(ms), + SYSBUS_DEVICE_GPIO_IRQ "[0]", &error_abort); + + /* Pass through mos6522 input IRQs */ + qdev_pass_gpios(DEVICE(&m->mos6522_via1), DEVICE(obj), "via1-irq"); + qdev_pass_gpios(DEVICE(&m->mos6522_via2), DEVICE(obj), "via2-irq"); + + /* MMIO */ + memory_region_init(&m->mmio, obj, "mac-via", 2 * VIA_SIZE); + sysbus_init_mmio(sbd, &m->mmio); + + memory_region_init_io(&m->via1mem, obj, &mos6522_q800_via1_ops, + MOS6522_Q800_VIA1(&m->mos6522_via1), "via1", + VIA_SIZE); + memory_region_add_subregion(&m->mmio, 0x0, &m->via1mem); + + memory_region_init_io(&m->via2mem, obj, &mos6522_q800_via2_ops, + MOS6522_Q800_VIA2(&m->mos6522_via2), "via2", + VIA_SIZE); + memory_region_add_subregion(&m->mmio, VIA_SIZE, &m->via2mem); + + /* ADB */ + qbus_create_inplace((BusState *)&m->adb_bus, sizeof(m->adb_bus), + TYPE_ADB_BUS, DEVICE(obj), "adb.0"); +} + +static void mac_via_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = mac_via_realize; + dc->reset = mac_via_reset; +} + +static TypeInfo mac_via_info = { + .name = TYPE_MAC_VIA, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(MacVIAState), + .instance_init = mac_via_init, + .class_init = mac_via_class_init, +}; + +/* VIA 1 */ +static void mos6522_q800_via1_portB_write(MOS6522State *s) +{ + MOS6522Q800VIA1State *v1s = container_of(s, MOS6522Q800VIA1State, + parent_obj); + MacVIAState *m = container_of(v1s, MacVIAState, mos6522_via1); + + via1_rtc_update(m); + + v1s->last_b = s->b; +} + +static void mos6522_q800_via1_reset(DeviceState *dev) +{ + MOS6522State *ms = MOS6522(dev); + MOS6522DeviceClass *mdc = MOS6522_DEVICE_GET_CLASS(ms); + + mdc->parent_reset(dev); + + ms->timers[0].frequency = VIA_TIMER_FREQ; + ms->timers[1].frequency = VIA_TIMER_FREQ; + + ms->b = VIA1B_vADB_StateMask | VIA1B_vADBInt | VIA1B_vRTCEnb; +} + +static void mos6522_q800_via1_init(Object *obj) +{ + qdev_init_gpio_in_named(DEVICE(obj), via1_irq_request, "via1-irq", + VIA1_IRQ_NB); +} + +static void mos6522_q800_via1_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + MOS6522DeviceClass *mdc = MOS6522_DEVICE_CLASS(oc); + + dc->reset = mos6522_q800_via1_reset; + mdc->portB_write = mos6522_q800_via1_portB_write; +} + +static const TypeInfo mos6522_q800_via1_type_info = { + .name = TYPE_MOS6522_Q800_VIA1, + .parent = TYPE_MOS6522, + .instance_size = sizeof(MOS6522Q800VIA1State), + .instance_init = mos6522_q800_via1_init, + .class_init = mos6522_q800_via1_class_init, +}; + +/* VIA 2 */ +static void mos6522_q800_via2_portB_write(MOS6522State *s) +{ + if (s->dirb & VIA2B_vPower && (s->b & VIA2B_vPower) == 0) { + /* shutdown */ + qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); + } +} + +static void mos6522_q800_via2_reset(DeviceState *dev) +{ + MOS6522State *ms = MOS6522(dev); + MOS6522DeviceClass *mdc = MOS6522_DEVICE_GET_CLASS(ms); + + mdc->parent_reset(dev); + + ms->timers[0].frequency = VIA_TIMER_FREQ; + ms->timers[1].frequency = VIA_TIMER_FREQ; + + ms->dirb = 0; + ms->b = 0; +} + +static void mos6522_q800_via2_init(Object *obj) +{ + qdev_init_gpio_in_named(DEVICE(obj), via2_irq_request, "via2-irq", + VIA2_IRQ_NB); +} + +static void mos6522_q800_via2_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + MOS6522DeviceClass *mdc = MOS6522_DEVICE_CLASS(oc); + + dc->reset = mos6522_q800_via2_reset; + mdc->portB_write = mos6522_q800_via2_portB_write; +} + +static const TypeInfo mos6522_q800_via2_type_info = { + .name = TYPE_MOS6522_Q800_VIA2, + .parent = TYPE_MOS6522, + .instance_size = sizeof(MOS6522Q800VIA2State), + .instance_init = mos6522_q800_via2_init, + .class_init = mos6522_q800_via2_class_init, +}; + +static void mac_via_register_types(void) +{ + type_register_static(&mos6522_q800_via1_type_info); + type_register_static(&mos6522_q800_via2_type_info); + type_register_static(&mac_via_info); +} + +type_init(mac_via_register_types); diff --git a/include/hw/misc/mac_via.h b/include/hw/misc/mac_via.h new file mode 100644 index 0000000000..a3a972ccc5 --- /dev/null +++ b/include/hw/misc/mac_via.h @@ -0,0 +1,106 @@ +/* + * + * Copyright (c) 2011-2018 Laurent Vivier + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef HW_MISC_MAC_VIA_H +#define HW_MISC_MAC_VIA_H + +#include "exec/memory.h" +#include "hw/sysbus.h" +#include "hw/misc/mos6522.h" + + +/* VIA 1 */ +#define VIA1_IRQ_ONE_SECOND_BIT 0 +#define VIA1_IRQ_VBLANK_BIT 1 +#define VIA1_IRQ_ADB_READY_BIT 2 +#define VIA1_IRQ_ADB_DATA_BIT 3 +#define VIA1_IRQ_ADB_CLOCK_BIT 4 + +#define VIA1_IRQ_NB 8 + +#define VIA1_IRQ_ONE_SECOND (1 << VIA1_IRQ_ONE_SECOND_BIT) +#define VIA1_IRQ_VBLANK (1 << VIA1_IRQ_VBLANK_BIT) +#define VIA1_IRQ_ADB_READY (1 << VIA1_IRQ_ADB_READY_BIT) +#define VIA1_IRQ_ADB_DATA (1 << VIA1_IRQ_ADB_DATA_BIT) +#define VIA1_IRQ_ADB_CLOCK (1 << VIA1_IRQ_ADB_CLOCK_BIT) + + +#define TYPE_MOS6522_Q800_VIA1 "mos6522-q800-via1" +#define MOS6522_Q800_VIA1(obj) OBJECT_CHECK(MOS6522Q800VIA1State, (obj), \ + TYPE_MOS6522_Q800_VIA1) + +typedef struct MOS6522Q800VIA1State { + /*< private >*/ + MOS6522State parent_obj; + + qemu_irq irqs[VIA1_IRQ_NB]; + uint8_t last_b; +} MOS6522Q800VIA1State; + + +/* VIA 2 */ +#define VIA2_IRQ_SCSI_DATA_BIT 0 +#define VIA2_IRQ_SLOT_BIT 1 +#define VIA2_IRQ_UNUSED_BIT 2 +#define VIA2_IRQ_SCSI_BIT 3 +#define VIA2_IRQ_ASC_BIT 4 + +#define VIA2_IRQ_NB 8 + +#define VIA2_IRQ_SCSI_DATA (1 << VIA2_IRQ_SCSI_DATA_BIT) +#define VIA2_IRQ_SLOT (1 << VIA2_IRQ_SLOT_BIT) +#define VIA2_IRQ_UNUSED (1 << VIA2_IRQ_SCSI_BIT) +#define VIA2_IRQ_SCSI (1 << VIA2_IRQ_UNUSED_BIT) +#define VIA2_IRQ_ASC (1 << VIA2_IRQ_ASC_BIT) + +#define TYPE_MOS6522_Q800_VIA2 "mos6522-q800-via2" +#define MOS6522_Q800_VIA2(obj) OBJECT_CHECK(MOS6522Q800VIA2State, (obj), \ + TYPE_MOS6522_Q800_VIA2) + +typedef struct MOS6522Q800VIA2State { + /*< private >*/ + MOS6522State parent_obj; +} MOS6522Q800VIA2State; + + +#define TYPE_MAC_VIA "mac_via" +#define MAC_VIA(obj) OBJECT_CHECK(MacVIAState, (obj), TYPE_MAC_VIA) + +typedef struct MacVIAState { + SysBusDevice busdev; + + /* MMIO */ + MemoryRegion mmio; + MemoryRegion via1mem; + MemoryRegion via2mem; + + /* VIAs */ + MOS6522Q800VIA1State mos6522_via1; + MOS6522Q800VIA2State mos6522_via2; + + /* RTC */ + uint32_t tick_offset; + + uint8_t data_out; + int data_out_cnt; + uint8_t data_in; + uint8_t data_in_cnt; + uint8_t cmd; + int wprotect; + int alt; + + /* ADB */ + ADBBusState adb_bus; + + /* external timers */ + QEMUTimer *one_second_timer; + QEMUTimer *VBL_timer; + +} MacVIAState; + +#endif From patchwork Wed Jun 27 23:29:43 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Vivier X-Patchwork-Id: 935790 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=vivier.eu Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41GK8p3SB3z9s0w for ; Thu, 28 Jun 2018 09:38:02 +1000 (AEST) Received: from localhost ([::1]:33656 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fYK0e-0004Us-45 for incoming@patchwork.ozlabs.org; Wed, 27 Jun 2018 19:38:00 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:48480) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fYJtM-0007uT-Hl for qemu-devel@nongnu.org; Wed, 27 Jun 2018 19:30:31 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fYJtK-0003iP-VZ for qemu-devel@nongnu.org; Wed, 27 Jun 2018 19:30:28 -0400 Received: from mout.kundenserver.de ([212.227.126.135]:37943) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1fYJtE-0003e1-6R; Wed, 27 Jun 2018 19:30:20 -0400 Received: from localhost.localdomain ([78.238.229.36]) by mrelayeu.kundenserver.de (mreue001 [212.227.15.167]) with ESMTPSA (Nemesis) id 0MFDJ5-1fO9f10Ivb-00GGXJ; Thu, 28 Jun 2018 01:30:00 +0200 From: Laurent Vivier To: qemu-devel@nongnu.org Date: Thu, 28 Jun 2018 01:29:43 +0200 Message-Id: <20180627232951.14725-3-laurent@vivier.eu> X-Mailer: git-send-email 2.14.4 In-Reply-To: <20180627232951.14725-1-laurent@vivier.eu> References: <20180627232951.14725-1-laurent@vivier.eu> X-Provags-ID: V03:K1:fRKQhfSo3CsTuubd54NO1AzaPYrbG15JKcPXGb16DJKTTFWzqMX Syx96nQFisTb97tE1pHMRYGAOYUJlan+6f9d18Jq7GFe07ZqgZV8LE70kW7WrhEzROmuDrS U0RGj9NmvrZ0RxIaS9+bLTAX2BZVhICTvJLJyJuXmckt1wDSoyH4GnyWTBwPpGuiUfVV61C yI3SiKvQPdHd/hyY4alnA== X-UI-Out-Filterresults: notjunk:1; V01:K0:eAEPJfo/yTw=:/GFJzregC22i4rayaJxxYK V7WODApmr2Y4JVxiZ7L/bmRV9tu9n8tq4c6yCpMNfc/bV29S14FA6+YGLAUAeFOocij1PcW94 UsFRCHAUOdTAUT32tkn3lbXlpzTPbLGGoHsH8MU0k5v9FLF5Y1F0fP6w+SzdmOKY6tf/DUGdH efIr6YyraMTBpYZ7x8T867njx2raQUQ3n4MIRRwXHLFVqRV4UmIO2QoP8gecS08Gx2hdqtj1A iIhK8ynoQlbwBWyOD+VvPQ6b3TQRqTwWh/PBEE8x7yIlV31+egrDLU/mzPx7qHmm/0ni3a4cw M5LdXd+l8X6DsKWPqLQIgOa5rAZgC2YtEJo74dx7gVQ5bbTjY4hj33MFwaGhrhadDTXltOKxE wFv3AhmmxdgZ7DKcYD6XHLfAUcV7uJaPNSfUGyaBprNM+3+QROMowGVt+zl+e5NMNRuJYAghc FT9CUqAeJ+jz/Oo5dGxYpYxYnnFoYIrYnP0uYp28PX6zmtbEe3NHcipPzgKCR7U2sNDIlSqXV yLiYwQPliQxfbYwJCgFVGS3Siy09Qmvys8BXRLh9a1O2xC6tkyyRqozJMKWDeB1nRfNiK+poR 0dXtoxaa8qBB2JVsBKuPgDkYSK13dhNs6U+5VZKYyBONfBIUOjdPdUAhcnzEdJ0xFb9J6nld+ gO3V0TnjM+H65osMsiDQTAqCchtafzUFZltLo3VjhmIT+orFON1+Jk0sgXnrfkzoKs9A= X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 212.227.126.135 Subject: [Qemu-devel] [RFC v3 02/10] ADB: VIA probes ADB bus when it is idle 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: , Cc: Kevin Wolf , Fam Zheng , qemu-block@nongnu.org, Jason Wang , Mark Cave-Ayland , "Dr. David Alan Gilbert" , Laurent Vivier , =?utf-8?q?Herv=C3=A9_Poussineau?= , Gerd Hoffmann , Paolo Bonzini , Max Reitz , Yongbok Kim , =?utf-8?q?Andreas_F=C3=A4rber?= , Aurelien Jarno Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Co-developed-by: Mark Cave-Ayland Signed-off-by: Mark Cave-Ayland Signed-off-by: Laurent Vivier --- hw/input/adb-kbd.c | 4 ++ hw/input/adb-mouse.c | 4 ++ hw/input/adb.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++ hw/misc/mac_via.c | 56 ++++++++++++++++++++++ include/hw/input/adb.h | 10 ++++ include/hw/misc/mac_via.h | 1 + 6 files changed, 190 insertions(+) diff --git a/hw/input/adb-kbd.c b/hw/input/adb-kbd.c index b026e9d49f..f439e106bb 100644 --- a/hw/input/adb-kbd.c +++ b/hw/input/adb-kbd.c @@ -195,6 +195,10 @@ static int adb_kbd_poll(ADBDevice *d, uint8_t *obuf) int keycode; int olen; + if (obuf == NULL) { + return s->count; + } + olen = 0; if (s->count == 0) { return 0; diff --git a/hw/input/adb-mouse.c b/hw/input/adb-mouse.c index 83833b0035..7615c252d5 100644 --- a/hw/input/adb-mouse.c +++ b/hw/input/adb-mouse.c @@ -73,6 +73,10 @@ static int adb_mouse_poll(ADBDevice *d, uint8_t *obuf) return 0; } + if (obuf == NULL) { + return 2; + } + dx = s->dx; if (dx < -63) { dx = -63; diff --git a/hw/input/adb.c b/hw/input/adb.c index bbb40aeef1..99852879d8 100644 --- a/hw/input/adb.c +++ b/hw/input/adb.c @@ -25,6 +25,17 @@ #include "hw/input/adb.h" #include "adb-internal.h" +#define ADB_POLL_FREQ 50 + +/* Apple Macintosh Family Hardware Refenece + * Table 19-10 ADB transaction states + */ + +#define STATE_NEW 0 +#define STATE_EVEN 1 +#define STATE_ODD 2 +#define STATE_IDLE 3 + /* error codes */ #define ADB_RET_NOTPRESENT (-2) @@ -84,6 +95,110 @@ int adb_poll(ADBBusState *s, uint8_t *obuf, uint16_t poll_mask) return olen; } +int adb_via_poll(ADBBusState *adb, int state, uint8_t *data) +{ + if (state != STATE_IDLE) { + return 0; + } + if (adb->data_in_size < adb->data_in_index) { + return 0; + } + if (adb->data_out_index != 0) { + return 0; + } + adb->data_in_index = 0; + adb->data_out_index = 0; + adb->data_in_size = adb_poll(adb, adb->data_in, 0xffff); + if (adb->data_in_size) { + *data = adb->data_in[adb->data_in_index++]; + qemu_irq_raise(adb->data_ready); + } + return adb->data_in_size; +} + +int adb_send(ADBBusState *adb, int state, uint8_t data) +{ + switch (state) { + case STATE_NEW: + adb->data_out_index = 0; + break; + case STATE_EVEN: + if ((adb->data_out_index & 1) == 0) { + return 0; + } + break; + case STATE_ODD: + if (adb->data_out_index & 1) { + return 0; + } + break; + case STATE_IDLE: + return 0; + } + adb->data_out[adb->data_out_index++] = data; + qemu_irq_raise(adb->data_ready); + return 1; +} + +int adb_receive(ADBBusState *adb, int state, uint8_t *data) +{ + switch (state) { + case STATE_NEW: + return 0; + case STATE_EVEN: + if (adb->data_in_size <= 0) { + qemu_irq_raise(adb->data_ready); + return 0; + } + if (adb->data_in_index >= adb->data_in_size) { + *data = 0; + qemu_irq_raise(adb->data_ready); + return 1; + } + if ((adb->data_in_index & 1) == 0) { + return 0; + } + break; + case STATE_ODD: + if (adb->data_in_size <= 0) { + qemu_irq_raise(adb->data_ready); + return 0; + } + if (adb->data_in_index >= adb->data_in_size) { + *data = 0; + qemu_irq_raise(adb->data_ready); + return 1; + } + if (adb->data_in_index & 1) { + return 0; + } + break; + case STATE_IDLE: + if (adb->data_out_index == 0) { + return 0; + } + adb->data_in_size = adb_request(adb, adb->data_in, + adb->data_out, adb->data_out_index); + adb->data_out_index = 0; + adb->data_in_index = 0; + if (adb->data_in_size < 0) { + *data = 0xff; + qemu_irq_raise(adb->data_ready); + return -1; + } + if (adb->data_in_size == 0) { + return 0; + } + break; + } + *data = adb->data_in[adb->data_in_index++]; + qemu_irq_raise(adb->data_ready); + if (*data == 0xff || *data == 0) { + return 0; + } + return 1; +} + static const TypeInfo adb_bus_type_info = { .name = TYPE_ADB_BUS, .parent = TYPE_BUS, diff --git a/hw/misc/mac_via.c b/hw/misc/mac_via.c index 586477ca9e..200121f798 100644 --- a/hw/misc/mac_via.c +++ b/hw/misc/mac_via.c @@ -424,6 +424,53 @@ static void via1_rtc_update(MacVIAState *m) } } +static void via1_adb_update(MacVIAState *m) +{ + MOS6522Q800VIA1State *v1s = MOS6522_Q800_VIA1(&m->mos6522_via1); + MOS6522State *s = MOS6522(v1s); + int state; + int ret; + + state = (s->b & VIA1B_vADB_StateMask) >> VIA1B_vADB_StateShift; + + if (s->acr & VIA1ACR_vShiftOut) { + /* output mode */ + ret = adb_send(&m->adb_bus, state, s->sr); + if (ret > 0) { + s->b &= ~VIA1B_vADBInt; + } else { + s->b |= VIA1B_vADBInt; + } + } else { + /* input mode */ + ret = adb_receive(&m->adb_bus, state, &s->sr); + if (ret > 0 && s->sr != 0xff) { + s->b &= ~VIA1B_vADBInt; + } else { + s->b |= VIA1B_vADBInt; + } + } +} + +static void via_adb_poll(void *opaque) +{ + MacVIAState *m = opaque; + MOS6522Q800VIA1State *v1s = MOS6522_Q800_VIA1(&m->mos6522_via1); + MOS6522State *s = MOS6522(v1s); + int state; + + if (s->b & VIA1B_vADBInt) { + state = (s->b & VIA1B_vADB_StateMask) >> VIA1B_vADB_StateShift; + if (adb_via_poll(&m->adb_bus, state, &s->sr)) { + s->b &= ~VIA1B_vADBInt; + } + } + + timer_mod(m->adb_poll_timer, + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + + (NANOSECONDS_PER_SECOND / VIA_ADB_POLL_FREQ)); +} + static uint64_t mos6522_q800_via1_read(void *opaque, hwaddr addr, unsigned size) { MOS6522Q800VIA1State *s = opaque; @@ -486,6 +533,10 @@ static void mac_via_reset(DeviceState *dev) { MacVIAState *m = MAC_VIA(dev); + timer_mod(m->adb_poll_timer, + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + + (NANOSECONDS_PER_SECOND / VIA_ADB_POLL_FREQ)); + timer_mod(m->VBL_timer, (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 16630) / 16630 * 16630); @@ -504,6 +555,7 @@ static void mac_via_realize(DeviceState *dev, Error **errp) qemu_get_timedate(&tm, 0); m->tick_offset = (uint32_t)mktimegm(&tm) + RTC_OFFSET; + m->adb_poll_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, via_adb_poll, m); } static void mac_via_init(Object *obj) @@ -553,6 +605,9 @@ static void mac_via_init(Object *obj) /* ADB */ qbus_create_inplace((BusState *)&m->adb_bus, sizeof(m->adb_bus), TYPE_ADB_BUS, DEVICE(obj), "adb.0"); + + m->adb_bus.data_ready = qdev_get_gpio_in_named(DEVICE(obj), "via1-irq", + VIA1_IRQ_ADB_READY_BIT); } static void mac_via_class_init(ObjectClass *oc, void *data) @@ -579,6 +634,7 @@ static void mos6522_q800_via1_portB_write(MOS6522State *s) MacVIAState *m = container_of(v1s, MacVIAState, mos6522_via1); via1_rtc_update(m); + via1_adb_update(m); v1s->last_b = s->b; } diff --git a/include/hw/input/adb.h b/include/hw/input/adb.h index f99d478252..1888c5aab7 100644 --- a/include/hw/input/adb.h +++ b/include/hw/input/adb.h @@ -76,6 +76,12 @@ struct ADBBusState { ADBDevice *devices[MAX_ADB_DEVICES]; int nb_devices; int poll_index; + qemu_irq data_ready; + int data_in_size; + int data_in_index; + int data_out_index; + uint8_t data_in[128]; + uint8_t data_out[16]; }; int adb_request(ADBBusState *s, uint8_t *buf_out, @@ -85,4 +91,8 @@ int adb_poll(ADBBusState *s, uint8_t *buf_out, uint16_t poll_mask); #define TYPE_ADB_KEYBOARD "adb-keyboard" #define TYPE_ADB_MOUSE "adb-mouse" +int adb_via_poll(ADBBusState *s, int state, uint8_t *data); +int adb_send(ADBBusState *adb, int state, uint8_t data); +int adb_receive(ADBBusState *adb, int state, uint8_t *data); + #endif /* ADB_H */ diff --git a/include/hw/misc/mac_via.h b/include/hw/misc/mac_via.h index a3a972ccc5..85d8715b12 100644 --- a/include/hw/misc/mac_via.h +++ b/include/hw/misc/mac_via.h @@ -96,6 +96,7 @@ typedef struct MacVIAState { /* ADB */ ADBBusState adb_bus; + QEMUTimer *adb_poll_timer; /* external timers */ QEMUTimer *one_second_timer; From patchwork Wed Jun 27 23:29:44 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Vivier X-Patchwork-Id: 935786 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=vivier.eu Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41GK1847Hdz9rx7 for ; Thu, 28 Jun 2018 09:31:24 +1000 (AEST) Received: from localhost ([::1]:33615 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fYJuE-0007yM-1s for incoming@patchwork.ozlabs.org; Wed, 27 Jun 2018 19:31:22 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:48477) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fYJtM-0007u3-Ai for qemu-devel@nongnu.org; Wed, 27 Jun 2018 19:30:31 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fYJtK-0003iW-Uw for qemu-devel@nongnu.org; Wed, 27 Jun 2018 19:30:28 -0400 Received: from mout.kundenserver.de ([212.227.126.135]:37834) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1fYJtD-0003db-8b; Wed, 27 Jun 2018 19:30:19 -0400 Received: from localhost.localdomain ([78.238.229.36]) by mrelayeu.kundenserver.de (mreue001 [212.227.15.167]) with ESMTPSA (Nemesis) id 0MOXED-1fT4YO1a2H-005mgx; Thu, 28 Jun 2018 01:30:01 +0200 From: Laurent Vivier To: qemu-devel@nongnu.org Date: Thu, 28 Jun 2018 01:29:44 +0200 Message-Id: <20180627232951.14725-4-laurent@vivier.eu> X-Mailer: git-send-email 2.14.4 In-Reply-To: <20180627232951.14725-1-laurent@vivier.eu> References: <20180627232951.14725-1-laurent@vivier.eu> X-Provags-ID: V03:K1:OtgBMjp5HVGwqOu6iC6fMfp7q6AVa0x55tME4kJnDp5ADhBemqc CyIResYThVfsE71QklnkEgCZ6NlTbr9ngCKCDgROLfS2tebt4EQInIlBcK+5YWGFfP+/MwM rtB7JEuluq+oAETg+UTRq7tJPpt+z4NutymsO9dxVdVQM6pqtLgKFRG/Rk5XSJGHmbqC+xN 81h4xc/VBKc8ySg2wd29g== X-UI-Out-Filterresults: notjunk:1; V01:K0:Uin2GxQLHdk=:T77+v1nrq53u/2tPAPUBpo 483e1NkW9ynuP3g/ZxPTaMTkI/00y3oZxYQdEP/+QYOlXObXbyM3g7qBkOb/dERY/t0hxD5Ag GXHOhcCNpbBOK/A4gu0KTRSqGFqgZlWq4HfxZfUMc/ay0Z0la5zyzAgES3U/kr+ZaCXEiYO3J 39W5amzW8wa7divzy1TmNXSa30oIwuE/F0bifSwmf54JFYb7RRnXicms8LKat1jQLL24nZGhz ib7Y5wPKOhwmCdolVBlQqcTGlgwD23vw0f/mr2zphWi/vgBMMJi3dpRu8j9G5Dt7lalCPiDnv vq13rTeVnFTLyDkirDWvZR79hJElTcaOVplFjWn/qar5qMOehAllenYQ41WaHNKkdHrqjYRQD lXhedRxedHsyTMupzM1NAFGmxEhf1uNHQAoTA1WUPcUsjcZI2UIWvY3Lc+czUcWcLezVBtWls Jpb7V77/CISD97s+GevsMHnQdPv6VgRX6CRoepmYprrwIkRtQFVbozZmJNhVQCogsQKTri9J6 NqaM68jWNisqpxsW3ujYfvRMyG5x82z15chM4XDJ7GEnV/tAkQyVW++Wy372XS9jqVGvCdl/m tUQ1kYGSSkK2vL++6yBmMHFUAVrjxKo4Z/c7afiGApQIV6rARriO00eMQTrojzLKsLXYd5Xiz RXzY13rC3xv2vBo+QTh4cdy7QJz4UlFOTVNwGXvOQG1bf2g+zEMLiO/2kSixudn7dLHo= X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 212.227.126.135 Subject: [Qemu-devel] [RFC v3 03/10] escc: introduce a selector for the register bit 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: , Cc: Kevin Wolf , Fam Zheng , qemu-block@nongnu.org, Jason Wang , Mark Cave-Ayland , "Dr. David Alan Gilbert" , Laurent Vivier , =?utf-8?q?Herv=C3=A9_Poussineau?= , Gerd Hoffmann , Paolo Bonzini , Max Reitz , Yongbok Kim , =?utf-8?q?Andreas_F=C3=A4rber?= , Aurelien Jarno Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" On Sparc and PowerMac, the bit 0 of the address selects the register type (control or data) and bit 1 selects the channel (B or A). On m68k Macintosh, the bit 0 selects the channel and bit 1 the register type. This patch introduces a new parameter (bit_swap) to the device interface to indicate bits usage must be swapped between registers and channels. For the moment all the machines use the bit 0, but this change will be needed to emulate Quadra 800. Signed-off-by: Laurent Vivier --- hw/char/escc.c | 30 ++++++++++++++++++++++++------ include/hw/char/escc.h | 1 + 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/hw/char/escc.c b/hw/char/escc.c index 628f5f81f7..cec75b06f9 100644 --- a/hw/char/escc.c +++ b/hw/char/escc.c @@ -42,14 +42,21 @@ * mouse and keyboard ports don't implement all functions and they are * only asynchronous. There is no DMA. * - * Z85C30 is also used on PowerMacs. There are some small differences - * between Sparc version (sunzilog) and PowerMac (pmac): + * Z85C30 is also used on PowerMacs and m68k Macs. + * + * There are some small differences between Sparc version (sunzilog) + * and PowerMac (pmac): * Offset between control and data registers * There is some kind of lockup bug, but we can ignore it * CTS is inverted * DMA on pmac using DBDMA chip * pmac can do IRDA and faster rates, sunzilog can only do 38400 * pmac baud rate generator clock is 3.6864 MHz, sunzilog 4.9152 MHz + * + * Linux driver for m68k Macs is the same as for PowerMac (pmac_zilog), + * but registers are grouped by type and not by channel: + * channel is selected by bit 0 of the address (instead of bit 1) + * and register is selected by bit 1 of the address (instead of bit 0). */ /* @@ -169,6 +176,16 @@ static void handle_kbd_command(ESCCChannelState *s, int val); static int serial_can_receive(void *opaque); static void serial_receive_byte(ESCCChannelState *s, int ch); +static int reg_shift(ESCCState *s) +{ + return s->bit_swap ? s->it_shift + 1 : s->it_shift; +} + +static int chn_shift(ESCCState *s) +{ + return s->bit_swap ? s->it_shift : s->it_shift + 1; +} + static void clear_queue(void *opaque) { ESCCChannelState *s = opaque; @@ -433,8 +450,8 @@ static void escc_mem_write(void *opaque, hwaddr addr, int newreg, channel; val &= 0xff; - saddr = (addr >> serial->it_shift) & 1; - channel = (addr >> (serial->it_shift + 1)) & 1; + saddr = (addr >> reg_shift(serial)) & 1; + channel = (addr >> chn_shift(serial)) & 1; s = &serial->chn[channel]; switch (saddr) { case SERIAL_CTRL: @@ -537,8 +554,8 @@ static uint64_t escc_mem_read(void *opaque, hwaddr addr, uint32_t ret; int channel; - saddr = (addr >> serial->it_shift) & 1; - channel = (addr >> (serial->it_shift + 1)) & 1; + saddr = (addr >> reg_shift(serial)) & 1; + channel = (addr >> chn_shift(serial)) & 1; s = &serial->chn[channel]; switch (saddr) { case SERIAL_CTRL: @@ -822,6 +839,7 @@ static void escc_realize(DeviceState *dev, Error **errp) static Property escc_properties[] = { DEFINE_PROP_UINT32("frequency", ESCCState, frequency, 0), DEFINE_PROP_UINT32("it_shift", ESCCState, it_shift, 0), + DEFINE_PROP_BOOL("bit_swap", ESCCState, bit_swap, false), DEFINE_PROP_UINT32("disabled", ESCCState, disabled, 0), DEFINE_PROP_UINT32("chnBtype", ESCCState, chn[0].type, 0), DEFINE_PROP_UINT32("chnAtype", ESCCState, chn[1].type, 0), diff --git a/include/hw/char/escc.h b/include/hw/char/escc.h index 42aca83611..8762f61c14 100644 --- a/include/hw/char/escc.h +++ b/include/hw/char/escc.h @@ -50,6 +50,7 @@ typedef struct ESCCState { struct ESCCChannelState chn[2]; uint32_t it_shift; + bool bit_swap; MemoryRegion mmio; uint32_t disabled; uint32_t frequency; From patchwork Wed Jun 27 23:29:45 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Vivier X-Patchwork-Id: 935793 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=vivier.eu Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41GKCZ541Dz9s01 for ; Thu, 28 Jun 2018 09:40:26 +1000 (AEST) Received: from localhost ([::1]:33668 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fYK2x-0006MU-IN for incoming@patchwork.ozlabs.org; Wed, 27 Jun 2018 19:40:23 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:48522) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fYJtQ-0007y3-Bz for qemu-devel@nongnu.org; Wed, 27 Jun 2018 19:30:35 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fYJtN-0003jf-0w for qemu-devel@nongnu.org; Wed, 27 Jun 2018 19:30:32 -0400 Received: from mout.kundenserver.de ([212.227.126.130]:51426) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1fYJtM-0003ij-Ft; Wed, 27 Jun 2018 19:30:28 -0400 Received: from localhost.localdomain ([78.238.229.36]) by mrelayeu.kundenserver.de (mreue001 [212.227.15.167]) with ESMTPSA (Nemesis) id 0MUxAq-1fdtMU2fG8-00YCUo; Thu, 28 Jun 2018 01:30:03 +0200 From: Laurent Vivier To: qemu-devel@nongnu.org Date: Thu, 28 Jun 2018 01:29:45 +0200 Message-Id: <20180627232951.14725-5-laurent@vivier.eu> X-Mailer: git-send-email 2.14.4 In-Reply-To: <20180627232951.14725-1-laurent@vivier.eu> References: <20180627232951.14725-1-laurent@vivier.eu> X-Provags-ID: V03:K1:U4wDYfEBpRGtdHDGzIZ2iK2iCCc9xpLxRCUpe9x9XCAKQYo86de /WSJ50RNYMmdCSBR7Rnh7g0o0VTeE44G+QTEuremWPoAt2F9EAsz8tHdeVUNZKQheZHaX69 3GW63JWwGwkfZmAaZci6V/LzAsckgIgHCoD6b7MRSm8eo6bPgFr0o3o5pKd/LreVZnCWNB+ e2x4/i3+mCZ0Cu4pLXVsA== X-UI-Out-Filterresults: notjunk:1; V01:K0:PHj0KqzdyCc=:lobXDWfJa1xjSu3zxbS2T9 j/GVuy8Fm/XRQW1fGjBDweyl2sAkWHyKLDxrfryxFi8Ax/izowAQuDNtos2KDtfx9imewhAS1 Ab7zb289lz1QWcENwB7tkSpLFz1BGq9gojLDfbrozY7HrujtM54D6s7uKs4772JrSg6amzH3g fHh4clmrloytnDmWJcKpCms9ADcI8sPcMFAgPtyRgMBP2u2/0IgymQFu2yenOQoTN3gbBNMU3 cTgZj06D05XoCYyO9TcE89GXIxX/9OUyWzKlr6X38/Jx+VuIDNzCq9jFJZ/wW/wc+DXPaNqBM FZ2lDaghbDSFO/OKZReJj6CeGokIHp373UBln7wMoQh+QWwAu8UyUfsHa0ojRllYoQvKX0UDs bR15LM0INoeUCE/DKfXzgTp7yeUYUQjmIjoLEvznB3Pt4MnHNDj2gP8jby6natHTAx5cyCoyE 8ULZbBiWqAh7QqgX/qWJTE0ddLSVra7oO0WiIuQGnS1kgPvffecvOU7S88XdGHuoXZ0NLxIrr oeFuXh5mOAVB9NEHCJWyDHTZE4Gj5dOY1z7EV3pkv+qZuFCkPVbpHiRZJchArdPieR654AoqM /glstLt8GIZJmEd74TdRW1B8FvPXNTPpadJ/Guupa8Iu6WUnkiR101iW5cCBvEjsRLQUKK0F0 r9RsHRIiWsRf1WnBLahyXtGDoboz8G1HKzScDnjyUzufEskQNn9hSUTj+vTO+Ba7PGWQ= X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 212.227.126.130 Subject: [Qemu-devel] [RFC v3 04/10] hw/m68k: add video card 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: , Cc: Kevin Wolf , Fam Zheng , qemu-block@nongnu.org, Jason Wang , Mark Cave-Ayland , "Dr. David Alan Gilbert" , Laurent Vivier , =?utf-8?q?Herv=C3=A9_Poussineau?= , Gerd Hoffmann , Paolo Bonzini , Max Reitz , Yongbok Kim , =?utf-8?q?Andreas_F=C3=A4rber?= , Aurelien Jarno Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Co-developed-by: Mark Cave-Ayland Signed-off-by: Mark Cave-Ayland Signed-off-by: Laurent Vivier --- arch_init.c | 4 + hw/display/Makefile.objs | 1 + hw/display/macfb-template.h | 158 +++++++++++++++++++++++++++ hw/display/macfb.c | 252 ++++++++++++++++++++++++++++++++++++++++++++ include/hw/display/macfb.h | 42 ++++++++ qemu-options.hx | 2 +- vl.c | 3 +- 7 files changed, 460 insertions(+), 2 deletions(-) create mode 100644 hw/display/macfb-template.h create mode 100644 hw/display/macfb.c create mode 100644 include/hw/display/macfb.h diff --git a/arch_init.c b/arch_init.c index f4f3f610c8..5a71b48dc5 100644 --- a/arch_init.c +++ b/arch_init.c @@ -39,6 +39,10 @@ int graphic_width = 1024; int graphic_height = 768; int graphic_depth = 8; +#elif defined(TARGET_M68K) +int graphic_width = 800; +int graphic_height = 600; +int graphic_depth = 8; #else int graphic_width = 800; int graphic_height = 600; diff --git a/hw/display/Makefile.objs b/hw/display/Makefile.objs index fb8408c6d0..bb9f509e4f 100644 --- a/hw/display/Makefile.objs +++ b/hw/display/Makefile.objs @@ -22,6 +22,7 @@ common-obj-$(CONFIG_EXYNOS4) += exynos4210_fimd.o common-obj-$(CONFIG_FRAMEBUFFER) += framebuffer.o common-obj-$(CONFIG_MILKYMIST) += milkymist-vgafb.o common-obj-$(CONFIG_ZAURUS) += tc6393xb.o +common-obj-$(CONFIG_MACFB) += macfb.o common-obj-$(CONFIG_MILKYMIST_TMU2) += milkymist-tmu2.o milkymist-tmu2.o-cflags := $(X11_CFLAGS) diff --git a/hw/display/macfb-template.h b/hw/display/macfb-template.h new file mode 100644 index 0000000000..b6ae5d728f --- /dev/null +++ b/hw/display/macfb-template.h @@ -0,0 +1,158 @@ +#if defined(READ_BITS) +#define PALETTE(i, r, g, b) \ + do { \ + r = s->color_palette[i * 3]; \ + g = s->color_palette[i * 3 + 1]; \ + b = s->color_palette[i * 3 + 2]; \ + } while (0) + +#if READ_BITS == 1 +#define READ_PIXEL(from, x, r, g, b) \ + do { \ + int bit = x & 7; \ + int idx = (*from >> (7 - bit)) & 1; \ + r = g = b = ((1 - idx) << 7); \ + from += (bit == 7); \ + } while (0) +#elif READ_BITS == 2 +#define READ_PIXEL(from, x, r, g, b) \ + do { \ + int bit = (x & 3); \ + int idx = (*from >> ((3 - bit) << 1)) & 3; \ + PALETTE(idx, r, g, b); \ + from += (bit == 3); \ + } while (0) +#elif READ_BITS == 4 +#define READ_PIXEL(from, x, r, g, b) \ + do { \ + int bit = x & 1; \ + int idx = (*from >> ((1 - bit) << 2)) & 15; \ + PALETTE(idx, r, g, b); \ + from += (bit == 1); \ + } while (0) +#elif READ_BITS == 8 +#define READ_PIXEL(from, x, r, g, b) \ + do { \ + PALETTE(*from, r, g, b); \ + from++; \ + } while (0) +#elif READ_BITS == 16 +#define READ_PIXEL(from, x, r, g, b) \ + do { \ + uint16_t pixel; \ + pixel = (from[0] << 8) | from[1]; \ + r = ((pixel >> 10) & 0x1f) << 3; \ + g = ((pixel >> 5) & 0x1f) << 3; \ + b = (pixel & 0x1f) << 3; \ + from += 2; \ + } while (0) +#elif READ_BITS == 24 +#define READ_PIXEL(from, x, r, g, b) \ + do { \ + r = *from++; \ + g = *from++; \ + b = *from++; \ + } while (0) +#else +#error unknown bit depth +#endif + +#if WRITE_BITS == 8 +#define WRITE_PIXEL(to, r, g, b) \ + do { \ + *to = rgb_to_pixel8(r, g, b); \ + to += 1; \ + } while (0) +#elif WRITE_BITS == 15 +#define WRITE_PIXEL(to, r, g, b) \ + do { \ + *(uint16_t *)to = rgb_to_pixel15(r, g, b); \ + to += 2; \ + } while (0) +#elif WRITE_BITS == 16 +#define WRITE_PIXEL(to, r, g, b) \ + do { \ + *(uint16_t *)to = rgb_to_pixel16(r, g, b); \ + to += 2; \ + } while (0) +#elif WRITE_BITS == 24 +#define WRITE_PIXEL(to, r, g, b) \ + do { \ + uint32_t tmp = rgb_to_pixel24(r, g, b); \ + *(to++) = tmp & 0xff; \ + *(to++) = (tmp >> 8) & 0xff; \ + *(to++) = (tmp >> 16) & 0xff; \ + } while (0) +#elif WRITE_BITS == 32 +#define WRITE_PIXEL(to, r, g, b) \ + do { \ + *(uint32_t *)to = rgb_to_pixel32(r, g, b); \ + to += 4; \ + } while (0) +#else +#error unknown bit depth +#endif + +static void glue(glue(glue(draw_line, READ_BITS), _), WRITE_BITS) + (MacfbState *s, uint8_t *to, uint8_t *from, int width) +{ + uint8_t r, g, b; + int x; + for (x = 0; x < width; x++) { + READ_PIXEL(from, x, r, g, b); + WRITE_PIXEL(to, r, g, b); + } +} +#undef READ_BITS +#undef READ_PIXEL +#undef WRITE_PIXEL + +#elif defined(WRITE_BITS) + +#undef MACFB_RECLEVEL +#define MACFB_RECLEVEL 2 +#define READ_BITS 1 +#include "macfb-template.h" +#define READ_BITS 2 +#include "macfb-template.h" +#define READ_BITS 4 +#include "macfb-template.h" +#define READ_BITS 8 +#include "macfb-template.h" +#define READ_BITS 16 +#include "macfb-template.h" +#define READ_BITS 24 +#include "macfb-template.h" +#undef WRITE_BITS + +#else + +#define WRITE_BITS 8 +#include "macfb-template.h" + +#define WRITE_BITS 16 +#include "macfb-template.h" + +#define WRITE_BITS 24 +#include "macfb-template.h" + +#define WRITE_BITS 32 +#include "macfb-template.h" + +typedef void (*macfb_draw_line_func_t)(MacfbState *, uint8_t *, uint8_t *, int); + +static macfb_draw_line_func_t macfb_draw_line[24][32] = { + [0] = { [7] = draw_line1_8, [15] = draw_line1_16, + [23] = draw_line1_24, [31] = draw_line1_32 }, + [1] = { [7] = draw_line2_8, [15] = draw_line2_16, + [23] = draw_line2_24, [31] = draw_line2_32 }, + [3] = { [7] = draw_line4_8, [15] = draw_line4_16, + [23] = draw_line4_24, [31] = draw_line4_32 }, + [7] = { [7] = draw_line8_8, [15] = draw_line8_16, + [23] = draw_line8_24, [31] = draw_line8_32 }, + [15] = { [7] = draw_line16_8, [15] = draw_line16_16, + [23] = draw_line16_24, [31] = draw_line16_32 }, + [23] = { [7] = draw_line24_8, [15] = draw_line24_16, + [23] = draw_line24_24, [31] = draw_line24_32 }, +}; +#endif diff --git a/hw/display/macfb.c b/hw/display/macfb.c new file mode 100644 index 0000000000..05841f4483 --- /dev/null +++ b/hw/display/macfb.c @@ -0,0 +1,252 @@ +/* + * QEMU Motorola 680x0 Macintosh Video Card Emulation + * Copyright (c) 2012-2018 Laurent Vivier + * + * some parts from QEMU G364 framebuffer Emulator. + * Copyright (c) 2007-2011 Herve Poussineau + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "hw/sysbus.h" +#include "ui/console.h" +#include "ui/pixel_ops.h" +#include "hw/display/macfb.h" + +#define VIDEO_BASE 0x00001000 +#define DAFB_BASE 0x00800000 + +#define MACFB_PAGE_SIZE 4096 +#define MACFB_VRAM_SIZE (4 * 1024 * 1024) + +#define DAFB_RESET 0x200 +#define DAFB_LUT 0x213 + +#include "macfb-template.h" + +static int macfb_check_dirty(MacfbState *s, DirtyBitmapSnapshot *snap, + ram_addr_t addr, int len) +{ + return memory_region_snapshot_get_dirty(&s->mem_vram, snap, addr, len); +} + +static void macfb_draw_graphic(MacfbState *s) +{ + DisplaySurface *surface = qemu_console_surface(s->con); + DirtyBitmapSnapshot *snap = NULL; + ram_addr_t page; + int y, ymin; + int macfb_stride = (s->depth * s->width + 7) / 8; + macfb_draw_line_func_t draw_line; + + if (s->depth > 24) { + hw_error("macfb: unknown guest depth %d", s->depth); + return; + } + if (surface_bits_per_pixel(surface) > 32) { + hw_error("macfb: unknown host depth %d", + surface_bits_per_pixel(surface)); + return; + } + draw_line = macfb_draw_line[s->depth - 1][surface_bits_per_pixel(surface) + - 1]; + + if (draw_line == NULL) { + hw_error("macfb: unknown guest/host depth combination %d/%d", s->depth, + surface_bits_per_pixel(surface)); + return; + } + + snap = memory_region_snapshot_and_clear_dirty(&s->mem_vram, 0x0, + memory_region_size(&s->mem_vram), + DIRTY_MEMORY_VGA); + + ymin = -1; + page = 0; + for (y = 0; y < s->height; y++, page += macfb_stride) { + if (macfb_check_dirty(s, snap, page, macfb_stride)) { + uint8_t *data_display; + + data_display = surface_data(surface) + y * surface_stride(surface); + draw_line(s, data_display, s->vram + page, s->width); + + if (ymin < 0) { + ymin = y; + } + } else { + if (ymin >= 0) { + dpy_gfx_update(s->con, 0, ymin, s->width, y - ymin); + ymin = -1; + } + } + } + + if (ymin >= 0) { + dpy_gfx_update(s->con, 0, ymin, s->width, y - ymin); + } + + g_free(snap); +} + +static void macfb_invalidate_display(void *opaque) +{ + MacfbState *s = opaque; + + memory_region_set_dirty(&s->mem_vram, 0, MACFB_VRAM_SIZE); +} + +static void macfb_update_display(void *opaque) +{ + MacfbState *s = opaque; + DisplaySurface *surface = qemu_console_surface(s->con); + + qemu_flush_coalesced_mmio_buffer(); + + if (s->width == 0 || s->height == 0) { + return; + } + + if (s->width != surface_width(surface) || + s->height != surface_height(surface)) { + qemu_console_resize(s->con, s->width, s->height); + } + + macfb_draw_graphic(s); +} + +static void macfb_reset(MacfbState *s) +{ + int i; + + s->palette_current = 0; + for (i = 0; i < 256; i++) { + s->color_palette[i * 3] = 255 - i; + s->color_palette[i * 3 + 1] = 255 - i; + s->color_palette[i * 3 + 2] = 255 - i; + } + memset(s->vram, 0, MACFB_VRAM_SIZE); + macfb_invalidate_display(s); +} + +static uint64_t macfb_ctrl_read(void *opaque, + hwaddr addr, + unsigned int size) +{ + return 0; +} + +static void macfb_ctrl_write(void *opaque, + hwaddr addr, + uint64_t val, + unsigned int size) +{ + MacfbState *s = opaque; + switch (addr) { + case DAFB_RESET: + s->palette_current = 0; + break; + case DAFB_LUT: + s->color_palette[s->palette_current++] = val; + if (s->palette_current % 3) { + macfb_invalidate_display(s); + } + break; + } +} + +static const MemoryRegionOps macfb_ctrl_ops = { + .read = macfb_ctrl_read, + .write = macfb_ctrl_write, + .endianness = DEVICE_BIG_ENDIAN, + .impl.min_access_size = 1, + .impl.max_access_size = 4, +}; + +static int macfb_post_load(void *opaque, int version_id) +{ + macfb_invalidate_display(opaque); + return 0; +} + +static const VMStateDescription vmstate_macfb = { + .name = "macfb", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .post_load = macfb_post_load, + .fields = (VMStateField[]) { + VMSTATE_BUFFER_UNSAFE(color_palette, MacfbState, 0, 256 * 3), + VMSTATE_UINT32(palette_current, MacfbState), + VMSTATE_END_OF_LIST() + } +}; + +static const GraphicHwOps macfb_ops = { + .invalidate = macfb_invalidate_display, + .gfx_update = macfb_update_display, +}; + +static void macfb_common_realize(DeviceState *dev, MacfbState *s) +{ + s->vram = g_malloc0(MACFB_VRAM_SIZE); + + s->con = graphic_console_init(dev, 0, &macfb_ops, s); + + memory_region_init_io(&s->mem_ctrl, NULL, &macfb_ctrl_ops, s, "macfb-ctrl", + 0x1000); + memory_region_init_ram_ptr(&s->mem_vram, NULL, "macfb-vram", + MACFB_VRAM_SIZE, s->vram); + vmstate_register_ram(&s->mem_vram, dev); + memory_region_set_coalescing(&s->mem_vram); +} + +static void macfb_sysbus_realize(DeviceState *dev, Error **errp) +{ + MacfbSysBusState *s = MACFB(dev); + MacfbState *ms = &s->macfb; + + macfb_common_realize(dev, ms); + sysbus_init_mmio(SYS_BUS_DEVICE(s), &ms->mem_ctrl); + sysbus_init_mmio(SYS_BUS_DEVICE(s), &ms->mem_vram); +} + +static void macfb_sysbus_reset(DeviceState *d) +{ + MacfbSysBusState *s = MACFB(d); + macfb_reset(&s->macfb); +} + +static Property macfb_sysbus_properties[] = { + DEFINE_PROP_UINT32("width", MacfbSysBusState, macfb.width, 640), + DEFINE_PROP_UINT32("height", MacfbSysBusState, macfb.height, 480), + DEFINE_PROP_UINT8("depth", MacfbSysBusState, macfb.depth, 8), + DEFINE_PROP_END_OF_LIST(), +}; + +static void macfb_sysbus_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = macfb_sysbus_realize; + dc->desc = "SysBus Macintosh framebuffer"; + dc->reset = macfb_sysbus_reset; + dc->vmsd = &vmstate_macfb; + dc->props = macfb_sysbus_properties; +} + +static TypeInfo macfb_sysbus_info = { + .name = TYPE_MACFB, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(MacfbSysBusState), + .class_init = macfb_sysbus_class_init, +}; + +static void macfb_register_types(void) +{ + type_register_static(&macfb_sysbus_info); +} + +type_init(macfb_register_types) diff --git a/include/hw/display/macfb.h b/include/hw/display/macfb.h new file mode 100644 index 0000000000..70ea5480fe --- /dev/null +++ b/include/hw/display/macfb.h @@ -0,0 +1,42 @@ +/* + * QEMU Motorola 680x0 Macintosh Video Card Emulation + * Copyright (c) 2012-2018 Laurent Vivier + * + * some parts from QEMU G364 framebuffer Emulator. + * Copyright (c) 2007-2011 Herve Poussineau + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef MACFB_H +#define MACFB_H + +#include "qemu/osdep.h" +#include "exec/memory.h" +#include "ui/console.h" + +typedef struct MacfbState { + MemoryRegion mem_vram; + MemoryRegion mem_ctrl; + QemuConsole *con; + + uint8_t *vram; + uint32_t palette_current; + uint8_t color_palette[256 * 3]; + uint32_t width, height; /* in pixels */ + uint8_t depth; +} MacfbState; + +#define TYPE_MACFB "sysbus-macfb" +#define MACFB(obj) \ + OBJECT_CHECK(MacfbSysBusState, (obj), TYPE_MACFB) + +typedef struct { + SysBusDevice busdev; + + MacfbState macfb; +} MacfbSysBusState; + +#endif diff --git a/qemu-options.hx b/qemu-options.hx index d5b0c26e8e..b48f925128 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1539,7 +1539,7 @@ ETEXI DEF("g", 1, QEMU_OPTION_g , "-g WxH[xDEPTH] Set the initial graphical resolution and depth\n", - QEMU_ARCH_PPC | QEMU_ARCH_SPARC) + QEMU_ARCH_PPC | QEMU_ARCH_SPARC | QEMU_ARCH_M68K) STEXI @item -g @var{width}x@var{height}[x@var{depth}] @findex -g diff --git a/vl.c b/vl.c index d26f19b06d..87ba3859eb 100644 --- a/vl.c +++ b/vl.c @@ -3310,7 +3310,8 @@ int main(int argc, char **argv, char **envp) if (*p == 'x') { p++; depth = strtol(p, (char **)&p, 10); - if (depth != 8 && depth != 15 && depth != 16 && + if (depth != 1 && depth != 2 && depth != 4 && + depth != 8 && depth != 15 && depth != 16 && depth != 24 && depth != 32) goto graphic_error; } else if (*p == '\0') { From patchwork Wed Jun 27 23:29:46 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Vivier X-Patchwork-Id: 935791 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=vivier.eu Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41GKBl3gj7z9s01 for ; Thu, 28 Jun 2018 09:39:43 +1000 (AEST) Received: from localhost ([::1]:33661 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fYK2H-0005iC-3s for incoming@patchwork.ozlabs.org; Wed, 27 Jun 2018 19:39:41 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:48515) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fYJtO-0007wP-ID for qemu-devel@nongnu.org; Wed, 27 Jun 2018 19:30:35 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fYJtM-0003j6-EA for qemu-devel@nongnu.org; Wed, 27 Jun 2018 19:30:30 -0400 Received: from mout.kundenserver.de ([212.227.126.187]:43610) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1fYJtL-0003ia-TI; Wed, 27 Jun 2018 19:30:28 -0400 Received: from localhost.localdomain ([78.238.229.36]) by mrelayeu.kundenserver.de (mreue001 [212.227.15.167]) with ESMTPSA (Nemesis) id 0M4NmW-1gLzYO0Mpg-00yhYk; Thu, 28 Jun 2018 01:30:04 +0200 From: Laurent Vivier To: qemu-devel@nongnu.org Date: Thu, 28 Jun 2018 01:29:46 +0200 Message-Id: <20180627232951.14725-6-laurent@vivier.eu> X-Mailer: git-send-email 2.14.4 In-Reply-To: <20180627232951.14725-1-laurent@vivier.eu> References: <20180627232951.14725-1-laurent@vivier.eu> X-Provags-ID: V03:K1:O0Z6e+QpP3yzdTpkAcjnCRGFt6CDdQhTG0KS6AeHYeaijU8EpDz DvgROSTwbRsf5YenIEiJLQmCkD3cX736PB0YoXRNq2gUKQIuYRVjcwh7IzD8DAK5N7ErlJX 3r0oHkwqzKHDaIKEwbClYnRmBS+8C3JvvfO5biX9oKkicJg1jNZRSgro66z7MGOBQlCFK89 BrMG5JJBCgcB2n67CuNfg== X-UI-Out-Filterresults: notjunk:1; V01:K0:XiEQywzEhOU=:6+hxdJTPOtjzFwenRnoxlf 72rEVsBnBtGKKyIqxUNZYYyajIgi3J7QGAd19nGNQl67GA+6gGzk8HuGxJDNyMa5Ky4dBAinZ /PCM1mXH07UM0mZyADPZhc1JKCpix5f/QjtQwcyuO8GDK44ZvKneYLaT+nrKMOISFC7N0j73I nJpqit5I/UJIsHOrs9bfXakpv2++dELQSZeogwW21y58PbW5VcAUcDfUOWePbVvYcpwDK5u6c +uyTHWui/pdUIHHXXm9/WA0Sq4LlxDdXFoVwz6vZ5Z5bV1G1aziSEX0L4MJ6jpUDG/x456mW9 PaaMtj18Xsgpf+i5XPBOtC6U3CkGx8DpjeVZ8b4HfwZVJsPaZCbVEIdBTbD/ayzBZIrQ1OMvF jggVrWD03UGcW0pxPjUteaewrlQ+Au88RJ8rJ2waXm7c9VRB3T7lp9qlP7+1OCUcg9VL5T+AO SMH7qVnUIyYmG2IQPzfcs8eULXgjDNhg0IYzJFg5qtdZSUJYX3xZ9vedejT2aWprIJ1ZBbfxg NiHVSqDxuNIqWju3PGDnUOAl/dPTwvaqlZVUAV0Trq+HbGKOQ+VAJ+IioZ84S/+N2UNq1BHuB hyga0fDqNp5dj8PLlaRhplckhW3SxKur/hqGxqOlLN2yEr+FHfpVHLia9GbHCQSWN3e5EEbHa mCcYYC6O8Fy3KrxgfCZYlaB1ewf9nsuet8tssFELFqWnm1zaMB7RnTMR4l5ezFOHEWCg= X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 212.227.126.187 Subject: [Qemu-devel] [RFC v3 05/10] 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: , Cc: Kevin Wolf , Fam Zheng , qemu-block@nongnu.org, Jason Wang , Mark Cave-Ayland , "Dr. David Alan Gilbert" , Laurent Vivier , =?utf-8?q?Herv=C3=A9_Poussineau?= , Gerd Hoffmann , Paolo Bonzini , Max Reitz , Yongbok Kim , =?utf-8?q?Andreas_F=C3=A4rber?= , Aurelien Jarno Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" 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 | 463 +++++++++++++++++++++++++++++++++++++++++++++++++ include/hw/audio/asc.h | 48 +++++ 3 files changed, 512 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) += marvell_88w8618.o common-obj-$(CONFIG_MILKYMIST) += milkymist-ac97.o common-obj-y += soundhw.o +common-obj-$(CONFIG_ASC) += asc.o diff --git a/hw/audio/asc.c b/hw/audio/asc.c new file mode 100644 index 0000000000..1066bf4488 --- /dev/null +++ b/hw/audio/asc.c @@ -0,0 +1,463 @@ +/* + * 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 later. + * 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=FIFO mode, + * 2=wavetable mode + * 0x802: CONTROL + * bit 0=analog or PWM output, + * 1=stereo/mono, + * 7=processing time exceeded + * 0x803: FIFO MODE + * bit 7=clear FIFO, + * bit 1="non-ROM companding", + * bit 0="ROM companding") + * 0x804: FIFO IRQ STATUS + * bit 0=ch A 1/2 full, + * 1=ch A full, + * 2=ch B 1/2 full, + * 3=ch B full) + * 0x805: WAVETABLE CONTROL + * bits 0-3 wavetables 0-3 start + * 0x806: VOLUME + * bits 2-4 = 3 bit internal ASC volume, + * bits 5-7 = volume control sent to Sony sound chip + * 0x807: CLOCK RATE + * 0 = Mac 22257 Hz, + * 1 = undefined, + * 2 = 22050 Hz, + * 3 = 44100 Hz + * 0x80a: PLAY REC A + * 0x80f: TEST + * bits 6-7 = digital test, + * bits 4-5 = 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 = 0x00, + ASC_MODE = 0x01, + ASC_CONTROL = 0x02, + ASC_FIFOMODE = 0x03, + ASC_FIFOIRQ = 0x04, + ASC_WAVECTRL = 0x05, + ASC_VOLUME = 0x06, + ASC_CLOCK = 0x07, + ASC_PLAYRECA = 0x0a, + ASC_TEST = 0x0f, + ASC_WAVETABLE = 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) = cpu_to_be32(phase); +} + +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 = get_incr(s, channel); + uint32_t phase = 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 = audio_MIN(sizeof(buf), free_b); + for (i = 0; i < (to_copy >> 1); to_copy++) { + int8_t left, right; + + left = s->fifo[s->a_rptr] ^ 0x80; + right = s->fifo[s->b_rptr + 0x400] ^ 0x80; + + if (s->a_cnt) { + s->a_rptr++; + s->a_rptr &= 0x3ff; + s->a_cnt--; + } + + if (s->b_cnt) { + s->b_rptr++; + s->b_rptr &= 0x3ff; + s->b_cnt--; + } + + if (s->type == ASC_TYPE_SONORA) { + if (s->a_cnt < 0x200) { + s->regs[ASC_FIFOIRQ] |= 4; /* FIFO A less than half full */ + qemu_irq_raise(s->irq); + } + if (s->b_cnt < 0x200) { + s->regs[ASC_FIFOIRQ] |= 8; /* FIFO B less than half full */ + qemu_irq_raise(s->irq); + } + } else { + if (s->a_cnt == 0x1ff) { + s->regs[ASC_FIFOIRQ] |= 1; /* FIFO A half empty */ + qemu_irq_raise(s->irq); + } else if (s->a_cnt == 0x001) { + s->regs[ASC_FIFOIRQ] |= 2; /* FIFO A half empty */ + qemu_irq_raise(s->irq); + } + if (s->b_cnt == 0x1ff) { + s->regs[ASC_FIFOIRQ] |= 4; /* FIFO A half empty */ + qemu_irq_raise(s->irq); + } else if (s->b_cnt == 0x001) { + s->regs[ASC_FIFOIRQ] |= 8; /* FIFO A half empty */ + qemu_irq_raise(s->irq); + } + } + buf[i * 2] = left; + buf[i * 2 + 1] = right; + } + AUD_write(s->channel, buf, to_copy); + free_b -= 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 = s->regs[ASC_WAVECTRL]; + + do { + to_copy = audio_MIN(sizeof(buf), free_b); + for (i = 0; i < (to_copy >> 1); i++) { + int32_t left, right; + int8_t sample; + + left = 0; + right = 0; + + if (control) { /* FIXME: how to use it ? */ + for (channel = 0; channel < 4; channel++) { + uint32_t phase = incr_phase(s, channel); + + phase = (phase >> 15) & 0x1ff; + sample = s->fifo[0x200 * channel + phase] ^ 0x80; + + left += sample; + right += sample; + } + buf[i * 2] = left >> 2; + buf[i * 2 + 1] = right >> 2; + } else { + /* FIXME: only works with linux macboing.c */ + uint32_t phase = incr_phase(s, 0); + phase = (phase >> 15) & 0x7ff; + sample = s->fifo[phase]; + buf[i * 2] = sample; + buf[i * 2 + 1] = sample; + } + } + AUD_write(s->channel, buf, to_copy); + free_b -= to_copy; + } while (free_b); +} + +static void asc_out_cb(void *opaque, int free_b) +{ + ASCState *s = 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 = opaque; + uint64_t prev; + + if (addr < 0x800) { + return s->fifo[addr]; + } + + addr -= 0x800; + + if (addr >= 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 == ASC_TYPE_V8) { + prev = 3; + } else { + prev = s->regs[ASC_FIFOIRQ]; + } + s->regs[ASC_FIFOIRQ] = 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 = opaque; + + if (addr < 0x800) { + if (s->regs[ASC_MODE] == 1) { + if (addr < 0x400) { + /* FIFO A */ + s->fifo[s->a_wptr++] = value; + s->a_cnt++; + if (s->a_cnt == 0x3ff) { + s->regs[ASC_FIFOIRQ] |= 2; /* FIFO A Full */ + } + s->a_wptr &= 0x3ff; + } else { + /* FIFO B */ + s->fifo[s->b_wptr++ + 0x400] = value; + s->b_cnt++; + if (s->b_cnt == 0x3ff) { + s->regs[ASC_FIFOIRQ] |= 8; /* FIFO B Full */ + } + s->b_wptr &= 0x3ff; + } + } else { + s->fifo[addr] = value; + } + return; + } + + addr -= 0x800; + if (addr >= 0x30) { + return; + } + switch (addr) { + case ASC_MODE: + value &= 3; + if (value != s->regs[ASC_MODE]) { + s->a_rptr = 0; + s->a_wptr = 0; + s->a_cnt = 0; + s->b_rptr = 0; + s->b_wptr = 0; + s->b_cnt = 0; + if (value != 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 = 0; + s->a_wptr = 0; + s->a_cnt = 0; + s->b_rptr = 0; + s->b_wptr = 0; + s->b_cnt = 0; + } + break; + case ASC_WAVECTRL: + break; + } + s->regs[addr] = value; +} + +static const MemoryRegionOps asc_mmio_ops = { + .read = asc_read, + .write = asc_write, + .impl = { + .min_access_size = 1, + .max_access_size = 1, + }, + .endianness = DEVICE_BIG_ENDIAN, +}; + +static int asc_post_load(void *opaque, int version_id) +{ + return 0; +} + +static const VMStateDescription vmstate_asc = { + .name = "apple-sound-chip", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .post_load = asc_post_load, + .fields = (VMStateField[]) { + VMSTATE_END_OF_LIST() + } +}; + +static void asc_reset(DeviceState *d) +{ + ASCState *s = ASC(d); + + AUD_set_active_out(s->channel, 0); + + memset(s->regs, 0, sizeof(s->regs)); + s->a_wptr = 0; + s->a_rptr = 0; + s->a_cnt = 0; + s->b_wptr = 0; + s->b_rptr = 0; + s->b_cnt = 0; +} + +static void asc_init(Object *obj) +{ + ASCState *s = ASC(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + struct audsettings as; + + AUD_register_card("Apple Sound Chip", &s->card); + + as.freq = 22257; + as.nchannels = 2; + as.fmt = AUD_FMT_S8; + as.endianness = 0; + + s->channel = AUD_open_out(&s->card, s->channel, "asc.out", + s, asc_out_cb, &as); + + s->fifo = g_malloc0(ASC_BUF_SIZE); + + memory_region_init_io(&s->mem_regs, NULL, &asc_mmio_ops, s, "asc", + ASC_LENGTH); + + sysbus_init_irq(sbd, &s->irq); + sysbus_init_mmio(sbd, &s->mem_regs); +} + +static Property asc_properties[] = { + 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 = DEVICE_CLASS(oc); + + dc->reset = asc_reset; + dc->vmsd = &vmstate_asc; + dc->props = asc_properties; +} + +static TypeInfo asc_info = { + .name = TYPE_ASC, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(ASCState), + .instance_init = asc_init, + .class_init = 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 later. + * 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 = 0, /* original discrete Apple Sound Chip */ + ASC_TYPE_EASC = 1, /* discrete Enhanced Apple Sound Chip */ + ASC_TYPE_V8 = 2, /* ASC included in the V8 ASIC (LC/LCII) */ + ASC_TYPE_EAGLE = 3, /* ASC included in the Eagle ASIC (Classic II) */ + ASC_TYPE_SPICE = 4, /* ASC included in the Spice ASIC (Color Classic) */ + ASC_TYPE_SONORA = 5, /* ASC included in the Sonora ASIC (LCIII) */ + ASC_TYPE_VASP = 6, /* ASC included in the VASP ASIC (IIvx/IIvi) */ + ASC_TYPE_ARDBEG = 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 From patchwork Wed Jun 27 23:29:47 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Vivier X-Patchwork-Id: 935792 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=vivier.eu Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41GKC82N7fz9s01 for ; Thu, 28 Jun 2018 09:40:04 +1000 (AEST) Received: from localhost ([::1]:33664 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fYK2c-0005wv-0x for incoming@patchwork.ozlabs.org; Wed, 27 Jun 2018 19:40:02 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:48643) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fYJtZ-00086g-6h for qemu-devel@nongnu.org; Wed, 27 Jun 2018 19:30:44 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fYJtW-0003nC-1B for qemu-devel@nongnu.org; Wed, 27 Jun 2018 19:30:41 -0400 Received: from mout.kundenserver.de ([212.227.126.130]:50040) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1fYJtP-0003kK-91; Wed, 27 Jun 2018 19:30:31 -0400 Received: from localhost.localdomain ([78.238.229.36]) by mrelayeu.kundenserver.de (mreue001 [212.227.15.167]) with ESMTPSA (Nemesis) id 0Ls3iR-1gITB424f1-013ys9; Thu, 28 Jun 2018 01:30:06 +0200 From: Laurent Vivier To: qemu-devel@nongnu.org Date: Thu, 28 Jun 2018 01:29:47 +0200 Message-Id: <20180627232951.14725-7-laurent@vivier.eu> X-Mailer: git-send-email 2.14.4 In-Reply-To: <20180627232951.14725-1-laurent@vivier.eu> References: <20180627232951.14725-1-laurent@vivier.eu> X-Provags-ID: V03:K1:Rx5gnj0f0eklEE9LGJePg5TmwiqyWkA3cAbrXYhvmCSa6/22WdP bH+nnGc2uCvsH5KQoUPxK4FqHSX0Tz1uxFw0pXvT49p+k+Jr6ENwdgtnHTU3MeYWqTQ7JSD +0nUNOC/VU8Tc7Iapw46eozFT8xueLBamfKCq5SxLaGl4pk//y5km3nztbgfoDAjTf4LWyt 18rkHsqxD+5TEu1yldu/Q== X-UI-Out-Filterresults: notjunk:1; V01:K0:tiq+qG+0HiQ=:RP7cv7ZFQ5NcFNiDhWfTDl 8OoP0QxosMeYcTpiA/a45nSxyszJjgfJnwKI7UK/JqTndIfoF2Hj+apzgoWH2Zu+WbTw63hUT zp+BhJq1vt291hrk7u+dwheSZjeStU7lFCYQZs4llJKzY0o5j72F3Gh6DgJKiKLgTpP4iuNEL jBTDpVDXHBG+HSBJCShUQJTLBMlkEMyqujiKWoxtjxwffw4xrMo7U2MLpV6HkdTgm5SLoFdqU t+Z5vVdrBLfruLdCQaaoIVmn79Vj9Zm2O/oERhSwLRfXiyKpUgr4rna0EMRNlZFhaFWyKnDth rJHmiw0eIrEdwLkk70Ptt/EKbaw11fg1b/FNKN5LhHTodBBn2xexrT+BZP+zO6MJR0SVG4JTn k2+1+hqrsBqrb4aBCw3teKBWsWeGWxEfQoyONITXvLFR5q0NK/7w144VAie7RRNEsCGz7fOKm IPAucTFNoyyU32+YWucy8J9mc67DueHjeNyh7Xq/03l3AA7sChFfIIaD/wVwV3dxVLlgpfbPn QGb3tWGv2SSc5l6JZ5Y1tWoFV3tM4OeSyUdLoz3siqm1Ss+Rmlf4OhsCltGySEdkWlAqhJm1k 2Dl4m4l0Gx4FPmxNvTNdksby+wN/U1muaFjwDkHPIBrihtOxph3HvdX2TmM7W1W+0D/IIKZG8 bQQ9bp4mV/p+FeJCAhYZRHinLqtsRZNSD6RU8Q/eE/FMT9YSftR1afsh3ajU3d3NdiBM= X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 212.227.126.130 Subject: [Qemu-devel] [RFC v3 06/10] ESP: add pseudo-DMA as used by Macintosh 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: , Cc: Kevin Wolf , Fam Zheng , qemu-block@nongnu.org, Jason Wang , Mark Cave-Ayland , "Dr. David Alan Gilbert" , Laurent Vivier , =?utf-8?q?Herv=C3=A9_Poussineau?= , Gerd Hoffmann , Paolo Bonzini , Max Reitz , Yongbok Kim , =?utf-8?q?Andreas_F=C3=A4rber?= , Aurelien Jarno Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Co-developed-by: Mark Cave-Ayland Signed-off-by: Mark Cave-Ayland Signed-off-by: Laurent Vivier --- hw/mips/mips_jazz.c | 2 +- hw/scsi/esp.c | 297 ++++++++++++++++++++++++++++++++++++++++++++------ include/hw/scsi/esp.h | 11 +- 3 files changed, 276 insertions(+), 34 deletions(-) diff --git a/hw/mips/mips_jazz.c b/hw/mips/mips_jazz.c index 90cb306f53..87118f2d03 100644 --- a/hw/mips/mips_jazz.c +++ b/hw/mips/mips_jazz.c @@ -282,7 +282,7 @@ static void mips_jazz_init(MachineState *machine, /* SCSI adapter */ esp = esp_init(0x80002000, 0, rc4030_dma_read, rc4030_dma_write, dmas[0], - qdev_get_gpio_in(rc4030, 5), &esp_reset, &dma_enable); + qdev_get_gpio_in(rc4030, 5), NULL, &esp_reset, &dma_enable); scsi_bus_legacy_handle_cmdline(&esp->bus); /* Floppy */ diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c index 9ed9727744..8270abe298 100644 --- a/hw/scsi/esp.c +++ b/hw/scsi/esp.c @@ -37,6 +37,8 @@ * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR53C9X.txt */ +/* on Macintosh Quadra it is a NCR53C96 */ + static void esp_raise_irq(ESPState *s) { if (!(s->rregs[ESP_RSTAT] & STAT_INT)) { @@ -55,6 +57,16 @@ static void esp_lower_irq(ESPState *s) } } +static void esp_raise_drq(ESPState *s) +{ + qemu_irq_raise(s->irq_data); +} + +static void esp_lower_drq(ESPState *s) +{ + qemu_irq_lower(s->irq_data); +} + void esp_dma_enable(ESPState *s, int irq, int level) { if (level) { @@ -81,29 +93,11 @@ void esp_request_cancelled(SCSIRequest *req) } } -static uint32_t get_cmd(ESPState *s, uint8_t *buf, uint8_t buflen) +static int get_cmd_cb(ESPState *s) { - uint32_t dmalen; int target; target = s->wregs[ESP_WBUSID] & BUSID_DID; - if (s->dma) { - dmalen = s->rregs[ESP_TCLO]; - dmalen |= s->rregs[ESP_TCMID] << 8; - dmalen |= s->rregs[ESP_TCHI] << 16; - if (dmalen > buflen) { - return 0; - } - s->dma_memory_read(s->dma_opaque, buf, dmalen); - } else { - dmalen = s->ti_size; - if (dmalen > TI_BUFSZ) { - return 0; - } - memcpy(buf, s->ti_buf, dmalen); - buf[0] = buf[2] >> 5; - } - trace_esp_get_cmd(dmalen, target); s->ti_size = 0; s->ti_rptr = 0; @@ -122,8 +116,48 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf, uint8_t buflen) s->rregs[ESP_RINTR] = INTR_DC; s->rregs[ESP_RSEQ] = SEQ_0; esp_raise_irq(s); + return -1; + } + return 0; +} + +static uint32_t get_cmd(ESPState *s, uint8_t *buf, uint8_t buflen) +{ + int target; + uint32_t dmalen; + + target = s->wregs[ESP_WBUSID] & BUSID_DID; + if (s->dma) { + dmalen = s->rregs[ESP_TCLO]; + dmalen |= s->rregs[ESP_TCMID] << 8; + dmalen |= s->rregs[ESP_TCHI] << 16; + if (dmalen > buflen) { + return 0; + } + if (s->dma_memory_read) { + s->dma_memory_read(s->dma_opaque, buf, dmalen); + } else { + memcpy(s->pdma_buf, buf, dmalen); + s->pdma_len = dmalen; + s->pdma_start = s->pdma_buf; + s->pdma_cur = s->pdma_buf; + esp_raise_drq(s); + return 0; + } + } else { + dmalen = s->ti_size; + if (dmalen > TI_BUFSZ) { + return 0; + } + memcpy(buf, s->ti_buf, dmalen); + buf[0] = buf[2] >> 5; + } + trace_esp_get_cmd(dmalen, target); + + if (get_cmd_cb(s) < 0) { return 0; } + return dmalen; } @@ -162,6 +196,15 @@ static void do_cmd(ESPState *s, uint8_t *buf) do_busid_cmd(s, &buf[1], busid); } +static void satn_pdma_cb(ESPState *s) +{ + if (get_cmd_cb(s) < 0) { + return; + } + if (s->pdma_cur != s->pdma_start) + do_cmd(s, s->pdma_start); +} + static void handle_satn(ESPState *s) { uint8_t buf[32]; @@ -171,11 +214,21 @@ static void handle_satn(ESPState *s) s->dma_cb = handle_satn; return; } + s->pdma_cb = satn_pdma_cb; len = get_cmd(s, buf, sizeof(buf)); if (len) do_cmd(s, buf); } +static void s_without_satn_pdma_cb(ESPState *s) +{ + if (get_cmd_cb(s) < 0) { + return; + } + if (s->pdma_cur != s->pdma_start) + do_busid_cmd(s, s->pdma_start, 0); +} + static void handle_s_without_atn(ESPState *s) { uint8_t buf[32]; @@ -185,18 +238,36 @@ static void handle_s_without_atn(ESPState *s) s->dma_cb = handle_s_without_atn; return; } + s->pdma_cb = s_without_satn_pdma_cb; len = get_cmd(s, buf, sizeof(buf)); if (len) { do_busid_cmd(s, buf, 0); } } +static void satn_stop_pdma_cb(ESPState *s) +{ + if (get_cmd_cb(s) < 0) { + return; + } + s->cmdlen = s->pdma_cur - s->pdma_start; + if (s->cmdlen) { + trace_esp_handle_satn_stop(s->cmdlen); + s->do_cmd = 1; + s->rregs[ESP_RSTAT] = STAT_TC | STAT_CD; + s->rregs[ESP_RINTR] = INTR_BS | INTR_FC; + s->rregs[ESP_RSEQ] = SEQ_CD; + esp_raise_irq(s); + } +} + static void handle_satn_stop(ESPState *s) { if (s->dma && !s->dma_enabled) { s->dma_cb = handle_satn_stop; return; } + s->pdma_cb = satn_stop_pdma_cb;; s->cmdlen = get_cmd(s, s->cmdbuf, sizeof(s->cmdbuf)); if (s->cmdlen) { trace_esp_handle_satn_stop(s->cmdlen); @@ -208,16 +279,33 @@ static void handle_satn_stop(ESPState *s) } } +static void write_response_pdma_cb(ESPState *s) +{ + s->rregs[ESP_RSTAT] = STAT_TC | STAT_ST; + s->rregs[ESP_RINTR] = INTR_BS | INTR_FC; + s->rregs[ESP_RSEQ] = SEQ_CD; + esp_raise_irq(s); +} + static void write_response(ESPState *s) { trace_esp_write_response(s->status); s->ti_buf[0] = s->status; s->ti_buf[1] = 0; if (s->dma) { - s->dma_memory_write(s->dma_opaque, s->ti_buf, 2); - s->rregs[ESP_RSTAT] = STAT_TC | STAT_ST; - s->rregs[ESP_RINTR] = INTR_BS | INTR_FC; - s->rregs[ESP_RSEQ] = SEQ_CD; + if (s->dma_memory_write) { + s->dma_memory_write(s->dma_opaque, s->ti_buf, 2); + s->rregs[ESP_RSTAT] = STAT_TC | STAT_ST; + s->rregs[ESP_RINTR] = INTR_BS | INTR_FC; + s->rregs[ESP_RSEQ] = SEQ_CD; + } else { + s->pdma_len = 2; + s->pdma_start = s->ti_buf; + s->pdma_cur = s->ti_buf; + s->pdma_cb = write_response_pdma_cb; + esp_raise_drq(s); + return; + } } else { s->ti_size = 2; s->ti_rptr = 0; @@ -239,6 +327,39 @@ static void esp_dma_done(ESPState *s) esp_raise_irq(s); } +static void do_dma_pdma_cb(ESPState *s) +{ + int to_device = (s->ti_size < 0); + int len = s->pdma_cur - s->pdma_start; + if (s->do_cmd) { + s->ti_size = 0; + s->cmdlen = 0; + s->do_cmd = 0; + do_cmd(s, s->cmdbuf); + return; + } + s->dma_left -= len; + s->async_buf += len; + s->async_len -= len; + if (to_device) { + s->ti_size += len; + } else { + s->ti_size -= len; + } + if (s->async_len == 0) { + scsi_req_continue(s->current_req); + /* If there is still data to be read from the device then + complete the DMA operation immediately. Otherwise defer + until the scsi layer has completed. */ + if (to_device || s->dma_left != 0 || s->ti_size == 0) { + return; + } + } + + /* Partially filled a scsi buffer. Complete immediately. */ + esp_dma_done(s); +} + static void esp_do_dma(ESPState *s) { uint32_t len; @@ -249,10 +370,26 @@ static void esp_do_dma(ESPState *s) trace_esp_do_dma(s->cmdlen, len); assert (s->cmdlen <= sizeof(s->cmdbuf) && len <= sizeof(s->cmdbuf) - s->cmdlen); - s->dma_memory_read(s->dma_opaque, &s->cmdbuf[s->cmdlen], len); + if (s->dma_memory_read) { + s->dma_memory_read(s->dma_opaque, &s->cmdbuf[s->cmdlen], len); + } else { + s->pdma_len = len; + s->pdma_start = &s->cmdbuf[s->cmdlen]; + s->pdma_cur = &s->cmdbuf[s->cmdlen]; + s->pdma_cb = do_dma_pdma_cb; + esp_raise_drq(s); + return; + } + s->ti_size = 0; + s->cmdlen = 0; + s->do_cmd = 0; + do_cmd(s, s->cmdbuf); return; } if (s->async_len == 0) { + if (s->dma_left == 0) { + esp_dma_done(s); + } /* Defer until data is available. */ return; } @@ -261,9 +398,27 @@ static void esp_do_dma(ESPState *s) } to_device = (s->ti_size < 0); if (to_device) { - s->dma_memory_read(s->dma_opaque, s->async_buf, len); + if (s->dma_memory_read) { + s->dma_memory_read(s->dma_opaque, s->async_buf, len); + } else { + s->pdma_len = len; + s->pdma_start = s->async_buf; + s->pdma_cur = s->async_buf; + s->pdma_cb = do_dma_pdma_cb; + esp_raise_drq(s); + return; + } } else { - s->dma_memory_write(s->dma_opaque, s->async_buf, len); + if (s->dma_memory_write) { + s->dma_memory_write(s->dma_opaque, s->async_buf, len); + } else { + s->pdma_len = len; + s->pdma_start = s->async_buf; + s->pdma_cur = s->async_buf; + s->pdma_cb = do_dma_pdma_cb; + esp_raise_drq(s); + return; + } } s->dma_left -= len; s->async_buf += len; @@ -356,8 +511,7 @@ static void handle_ti(ESPState *s) s->dma_left = minlen; s->rregs[ESP_RSTAT] &= ~STAT_TC; esp_do_dma(s); - } - if (s->do_cmd) { + } else if (s->do_cmd) { trace_esp_handle_ti_cmd(s->cmdlen); s->ti_size = 0; s->cmdlen = 0; @@ -384,6 +538,7 @@ void esp_hard_reset(ESPState *s) static void esp_soft_reset(ESPState *s) { qemu_irq_lower(s->irq); + qemu_irq_lower(s->irq_data); esp_hard_reset(s); } @@ -409,6 +564,7 @@ uint64_t esp_reg_read(ESPState *s, uint32_t saddr) s->ti_size--; s->rregs[ESP_FIFO] = s->ti_buf[s->ti_rptr++]; } + esp_raise_irq(s); if (s->ti_rptr == s->ti_wptr) { s->ti_rptr = 0; s->ti_wptr = 0; @@ -619,11 +775,85 @@ static const MemoryRegionOps sysbus_esp_mem_ops = { .valid.accepts = esp_mem_accepts, }; +static void sysbus_esp_pdma_write(void *opaque, hwaddr addr, + uint64_t val, unsigned int size) +{ + SysBusESPState *sysbus = opaque; + ESPState *s = &sysbus->esp; + uint32_t dmalen; + + dmalen = s->rregs[ESP_TCLO]; + dmalen |= s->rregs[ESP_TCMID] << 8; + dmalen |= s->rregs[ESP_TCHI] << 16; + if (dmalen == 0 || s->pdma_len == 0) { + return; + } + switch (size) { + case 1: + *s->pdma_cur++ = val; + s->pdma_len--; + dmalen--; + break; + case 2: + *s->pdma_cur++ = val >> 8; + *s->pdma_cur++ = val; + s->pdma_len -= 2; + dmalen -= 2; + break; + } + s->rregs[ESP_TCLO] = dmalen & 0xff; + s->rregs[ESP_TCMID] = dmalen >> 8; + s->rregs[ESP_TCHI] = dmalen >> 16; + if (s->pdma_len == 0 && s->pdma_cb) { + esp_lower_drq(s); + s->pdma_cb(s); + s->pdma_cb = NULL; + } +} + +static uint64_t sysbus_esp_pdma_read(void *opaque, hwaddr addr, + unsigned int size) +{ + SysBusESPState *sysbus = opaque; + ESPState *s = &sysbus->esp; + uint64_t val = 0; + + if (s->pdma_len == 0) { + return 0; + } + switch (size) { + case 1: + val = *s->pdma_cur++; + s->pdma_len--; + break; + case 2: + val = *s->pdma_cur++; + val = (val << 8) | *s->pdma_cur++; + s->pdma_len -= 2; + break; + } + + if (s->pdma_len == 0 && s->pdma_cb) { + esp_lower_drq(s); + s->pdma_cb(s); + s->pdma_cb = NULL; + } + return val; +} + +static const MemoryRegionOps sysbus_esp_pdma_ops = { + .read = sysbus_esp_pdma_read, + .write = sysbus_esp_pdma_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid.min_access_size = 1, + .valid.max_access_size = 2, +}; + ESPState *esp_init(hwaddr espaddr, int it_shift, ESPDMAMemoryReadWriteFunc dma_memory_read, ESPDMAMemoryReadWriteFunc dma_memory_write, - void *dma_opaque, qemu_irq irq, qemu_irq *reset, - qemu_irq *dma_enable) + void *dma_opaque, qemu_irq irq, qemu_irq irq_data, + qemu_irq *reset, qemu_irq *dma_enable) { DeviceState *dev; SysBusDevice *s; @@ -642,6 +872,7 @@ ESPState *esp_init(hwaddr espaddr, int it_shift, qdev_init_nofail(dev); s = SYS_BUS_DEVICE(dev); sysbus_connect_irq(s, 0, irq); + sysbus_connect_irq(s, 1, irq_data); sysbus_mmio_map(s, 0, espaddr); *reset = qdev_get_gpio_in(dev, 0); *dma_enable = qdev_get_gpio_in(dev, 1); @@ -681,12 +912,16 @@ static void sysbus_esp_realize(DeviceState *dev, Error **errp) ESPState *s = &sysbus->esp; sysbus_init_irq(sbd, &s->irq); + sysbus_init_irq(sbd, &s->irq_data); assert(sysbus->it_shift != -1); s->chip_id = TCHI_FAS100A; memory_region_init_io(&sysbus->iomem, OBJECT(sysbus), &sysbus_esp_mem_ops, - sysbus, "esp", ESP_REGS << sysbus->it_shift); + sysbus, "esp-regs", ESP_REGS << sysbus->it_shift); sysbus_init_mmio(sbd, &sysbus->iomem); + memory_region_init_io(&sysbus->pdma, OBJECT(sysbus), &sysbus_esp_pdma_ops, + sysbus, "esp-pdma", 2); + sysbus_init_mmio(sbd, &sysbus->pdma); qdev_init_gpio_in(dev, sysbus_esp_gpio_demux, 2); diff --git a/include/hw/scsi/esp.h b/include/hw/scsi/esp.h index 93fdaced67..43312e4bc8 100644 --- a/include/hw/scsi/esp.h +++ b/include/hw/scsi/esp.h @@ -18,6 +18,7 @@ struct ESPState { uint8_t rregs[ESP_REGS]; uint8_t wregs[ESP_REGS]; qemu_irq irq; + qemu_irq irq_data; uint8_t chip_id; bool tchi_written; int32_t ti_size; @@ -46,6 +47,11 @@ struct ESPState { ESPDMAMemoryReadWriteFunc dma_memory_write; void *dma_opaque; void (*dma_cb)(ESPState *s); + uint8_t pdma_buf[32]; + uint32_t pdma_len; + uint8_t *pdma_start; + uint8_t *pdma_cur; + void (*pdma_cb)(ESPState *s); }; #define TYPE_ESP "esp" @@ -57,6 +63,7 @@ typedef struct { /*< public >*/ MemoryRegion iomem; + MemoryRegion pdma; uint32_t it_shift; ESPState esp; } SysBusESPState; @@ -134,8 +141,8 @@ typedef struct { ESPState *esp_init(hwaddr espaddr, int it_shift, ESPDMAMemoryReadWriteFunc dma_memory_read, ESPDMAMemoryReadWriteFunc dma_memory_write, - void *dma_opaque, qemu_irq irq, qemu_irq *reset, - qemu_irq *dma_enable); + void *dma_opaque, qemu_irq irq, qemu_irq irq_data, + qemu_irq *reset, qemu_irq *dma_enable); void esp_dma_enable(ESPState *s, int irq, int level); void esp_request_cancelled(SCSIRequest *req); void esp_command_complete(SCSIRequest *req, uint32_t status, size_t resid); From patchwork Wed Jun 27 23:29:48 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Vivier X-Patchwork-Id: 935796 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=vivier.eu Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41GKHg22D5z9s01 for ; Thu, 28 Jun 2018 09:43:59 +1000 (AEST) Received: from localhost ([::1]:33691 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fYK6P-0000Vu-0M for incoming@patchwork.ozlabs.org; Wed, 27 Jun 2018 19:43:57 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:48675) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fYJte-000899-Fa for qemu-devel@nongnu.org; Wed, 27 Jun 2018 19:30:49 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fYJtY-0003nr-9K for qemu-devel@nongnu.org; Wed, 27 Jun 2018 19:30:46 -0400 Received: from mout.kundenserver.de ([212.227.126.131]:56543) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1fYJtR-0003kz-8S; Wed, 27 Jun 2018 19:30:33 -0400 Received: from localhost.localdomain ([78.238.229.36]) by mrelayeu.kundenserver.de (mreue001 [212.227.15.167]) with ESMTPSA (Nemesis) id 0LjR72-1g9qUg3jey-00bYX4; Thu, 28 Jun 2018 01:30:07 +0200 From: Laurent Vivier To: qemu-devel@nongnu.org Date: Thu, 28 Jun 2018 01:29:48 +0200 Message-Id: <20180627232951.14725-8-laurent@vivier.eu> X-Mailer: git-send-email 2.14.4 In-Reply-To: <20180627232951.14725-1-laurent@vivier.eu> References: <20180627232951.14725-1-laurent@vivier.eu> X-Provags-ID: V03:K1:01dld7eEeWaVWB7+ytSbkHc2HFD/eVcfzBQabgfHF2bLGPvX90Q QoGT0XkuIilnxwx9ZtX07u+/GaEjT7bY6iDdDrT0WxOlQr6l1rcweiJI5w7fyt/xB6XMcl5 SMRfhmdNEmp4Tt9lyFodTTrDlTfNWDodkoXBnVCUC1i+AilBsGo4yHpdKa2eXqPUZp2cpfS mYt5qE8zeGTZDjBdWH5AA== X-UI-Out-Filterresults: notjunk:1; V01:K0:lYA1Kc7UPVQ=:dB8s3qqRDHxu/xsH57U2qn 6LP3xgxvoIoN9vGsZ7v1ZrTdJxGRZxDw5NWQTU22sKxg5KAmGQMVlhqNgBpB5N6O/lmR/3ddl heKgKYKpQ+oRb8B3pLPEl8YUbQ7pKx2p5XGiEzyyKmLyijj0WbFzS8J25Kt8K2CSHjci9aRKV /exPwDCE/+uaRzUj/cR3MjU/BvuI72LMaWQTb9K6PvxttAiU98DDHtS+jbQBgTUAuh/vNkeCp GN1+OrGsPUu1j557EgMqWsBqwwYjXiqyms8oNfvW5DOfskpFvSVa10Z792XL0JqH1Dgu7fyWO Wc8R+9JIcbQLZtfBfksE24i0TtVen105cAL3zma9mIElqBK4TyD+guaQ1vxpVAmNOhj+s3CZ9 pxSl3x5Kmb23jLtubAlUVFMZWxu98YvJjHYt0ZNdai+PJIZX5LXt4E7yi+Wrg9neZgTFUhjS3 UiA8WUsa3SYCw/U8vNxFANHVsjIiBRauC3q7dLVHvMsuBpPTkF8RvfkCjlHcnzsYQS+5DGXth K1MPzZyat+Cae7jRqHBuibUxgo+DgvCcB4XNgsDsOic2OONurScmxOAF7fhQUhMzNjoCEvEOG NWOlQqXb6fntKQX8ZYvIFglb6tWvG/O8A1P7bnjyowGw1cBsa5dmMUmv6g+lB4mAN2mkznp0M YoeKQKSyHQQZquLSTUn9lIfiCKlzfAEhwkjqnuw7xzWouj/0++IcbyouRTEMRdBibdtY= X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 212.227.126.131 Subject: [Qemu-devel] [RFC v3 07/10] hw/m68k: add Nubus support 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: , Cc: Kevin Wolf , Fam Zheng , qemu-block@nongnu.org, Jason Wang , Mark Cave-Ayland , "Dr. David Alan Gilbert" , Laurent Vivier , =?utf-8?q?Herv=C3=A9_Poussineau?= , Gerd Hoffmann , Paolo Bonzini , Max Reitz , Yongbok Kim , =?utf-8?q?Andreas_F=C3=A4rber?= , Aurelien Jarno Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Co-developed-by: Mark Cave-Ayland Signed-off-by: Mark Cave-Ayland Signed-off-by: Laurent Vivier --- hw/Makefile.objs | 1 + hw/display/macfb.c | 56 ++++++++++ hw/nubus/Makefile.objs | 4 + hw/nubus/mac-nubus-bridge.c | 45 ++++++++ hw/nubus/nubus-bridge.c | 34 ++++++ hw/nubus/nubus-bus.c | 111 +++++++++++++++++++ hw/nubus/nubus-device.c | 210 ++++++++++++++++++++++++++++++++++++ include/hw/display/macfb.h | 21 ++++ include/hw/nubus/mac-nubus-bridge.h | 24 +++++ include/hw/nubus/nubus.h | 69 ++++++++++++ 10 files changed, 575 insertions(+) create mode 100644 hw/nubus/Makefile.objs create mode 100644 hw/nubus/mac-nubus-bridge.c create mode 100644 hw/nubus/nubus-bridge.c create mode 100644 hw/nubus/nubus-bus.c create mode 100644 hw/nubus/nubus-device.c create mode 100644 include/hw/nubus/mac-nubus-bridge.h create mode 100644 include/hw/nubus/nubus.h diff --git a/hw/Makefile.objs b/hw/Makefile.objs index a19c1417ed..8c97b4b97b 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -35,6 +35,7 @@ devices-dirs-$(CONFIG_SOFTMMU) += watchdog/ devices-dirs-$(CONFIG_SOFTMMU) += xen/ devices-dirs-$(CONFIG_MEM_HOTPLUG) += mem/ devices-dirs-$(CONFIG_SOFTMMU) += smbios/ +devices-dirs-$(CONFIG_NUBUS) += nubus/ devices-dirs-y += core/ common-obj-y += $(devices-dirs-y) obj-y += $(devices-dirs-y) diff --git a/hw/display/macfb.c b/hw/display/macfb.c index 05841f4483..d05ade7920 100644 --- a/hw/display/macfb.c +++ b/hw/display/macfb.c @@ -14,6 +14,7 @@ #include "hw/sysbus.h" #include "ui/console.h" #include "ui/pixel_ops.h" +#include "hw/nubus/nubus.h" #include "hw/display/macfb.h" #define VIDEO_BASE 0x00001000 @@ -213,12 +214,38 @@ static void macfb_sysbus_realize(DeviceState *dev, Error **errp) sysbus_init_mmio(SYS_BUS_DEVICE(s), &ms->mem_vram); } +const uint8_t macfb_rom[] = { + 255, 0, 0, 0, +}; + +static void macfb_nubus_realize(DeviceState *dev, Error **errp) +{ + NubusDevice *nd = NUBUS_DEVICE(dev); + MacfbNubusState *s = NUBUS_MACFB(dev); + MacfbNubusDeviceClass *ndc = MACFB_NUBUS_GET_CLASS(dev); + MacfbState *ms = &s->macfb; + + ndc->parent_realize(dev, errp); + + macfb_common_realize(dev, ms); + memory_region_add_subregion(&nd->slot_mem, DAFB_BASE, &ms->mem_ctrl); + memory_region_add_subregion(&nd->slot_mem, VIDEO_BASE, &ms->mem_vram); + + nubus_register_rom(nd, macfb_rom, sizeof(macfb_rom), 1, 9, 0xf); +} + static void macfb_sysbus_reset(DeviceState *d) { MacfbSysBusState *s = MACFB(d); macfb_reset(&s->macfb); } +static void macfb_nubus_reset(DeviceState *d) +{ + MacfbNubusState *s = NUBUS_MACFB(d); + macfb_reset(&s->macfb); +} + static Property macfb_sysbus_properties[] = { DEFINE_PROP_UINT32("width", MacfbSysBusState, macfb.width, 640), DEFINE_PROP_UINT32("height", MacfbSysBusState, macfb.height, 480), @@ -226,6 +253,13 @@ static Property macfb_sysbus_properties[] = { DEFINE_PROP_END_OF_LIST(), }; +static Property macfb_nubus_properties[] = { + DEFINE_PROP_UINT32("width", MacfbNubusState, macfb.width, 640), + DEFINE_PROP_UINT32("height", MacfbNubusState, macfb.height, 480), + DEFINE_PROP_UINT8("depth", MacfbNubusState, macfb.depth, 8), + DEFINE_PROP_END_OF_LIST(), +}; + static void macfb_sysbus_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -237,6 +271,19 @@ static void macfb_sysbus_class_init(ObjectClass *klass, void *data) dc->props = macfb_sysbus_properties; } +static void macfb_nubus_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + MacfbNubusDeviceClass *ndc = MACFB_NUBUS_DEVICE_CLASS(klass); + + device_class_set_parent_realize(dc, macfb_nubus_realize, + &ndc->parent_realize); + dc->desc = "Nubus Macintosh framebuffer"; + dc->reset = macfb_nubus_reset; + dc->vmsd = &vmstate_macfb; + dc->props = macfb_nubus_properties; +} + static TypeInfo macfb_sysbus_info = { .name = TYPE_MACFB, .parent = TYPE_SYS_BUS_DEVICE, @@ -244,9 +291,18 @@ static TypeInfo macfb_sysbus_info = { .class_init = macfb_sysbus_class_init, }; +static TypeInfo macfb_nubus_info = { + .name = TYPE_NUBUS_MACFB, + .parent = TYPE_NUBUS_DEVICE, + .instance_size = sizeof(MacfbNubusState), + .class_init = macfb_nubus_class_init, + .class_size = sizeof(MacfbNubusDeviceClass), +}; + static void macfb_register_types(void) { type_register_static(&macfb_sysbus_info); + type_register_static(&macfb_nubus_info); } type_init(macfb_register_types) diff --git a/hw/nubus/Makefile.objs b/hw/nubus/Makefile.objs new file mode 100644 index 0000000000..ebb050a4ad --- /dev/null +++ b/hw/nubus/Makefile.objs @@ -0,0 +1,4 @@ +common-obj-y += nubus-device.o +common-obj-y += nubus-bus.o +common-obj-y += nubus-bridge.o +common-obj-$(CONFIG_MAC) += mac-nubus-bridge.o diff --git a/hw/nubus/mac-nubus-bridge.c b/hw/nubus/mac-nubus-bridge.c new file mode 100644 index 0000000000..7c329300b8 --- /dev/null +++ b/hw/nubus/mac-nubus-bridge.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2013-2018 Laurent Vivier + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "hw/sysbus.h" +#include "hw/nubus/mac-nubus-bridge.h" + + +static void mac_nubus_bridge_init(Object *obj) +{ + MacNubusState *s = MAC_NUBUS_BRIDGE(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + s->bus = NUBUS_BUS(qbus_create(TYPE_NUBUS_BUS, DEVICE(s), NULL)); + + sysbus_init_mmio(sbd, &s->bus->super_slot_io); + sysbus_init_mmio(sbd, &s->bus->slot_io); +} + +static void mac_nubus_bridge_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->desc = "Nubus bridge"; +} + +static const TypeInfo mac_nubus_bridge_info = { + .name = TYPE_MAC_NUBUS_BRIDGE, + .parent = TYPE_NUBUS_BRIDGE, + .instance_init = mac_nubus_bridge_init, + .instance_size = sizeof(MacNubusState), + .class_init = mac_nubus_bridge_class_init, +}; + +static void mac_nubus_bridge_register_types(void) +{ + type_register_static(&mac_nubus_bridge_info); +} + +type_init(mac_nubus_bridge_register_types) diff --git a/hw/nubus/nubus-bridge.c b/hw/nubus/nubus-bridge.c new file mode 100644 index 0000000000..cd8c6a91eb --- /dev/null +++ b/hw/nubus/nubus-bridge.c @@ -0,0 +1,34 @@ +/* + * QEMU Macintosh Nubus + * + * Copyright (c) 2013-2018 Laurent Vivier + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "hw/sysbus.h" +#include "hw/nubus/nubus.h" + +static void nubus_bridge_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->fw_name = "nubus"; +} + +static const TypeInfo nubus_bridge_info = { + .name = TYPE_NUBUS_BRIDGE, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SysBusDevice), + .class_init = nubus_bridge_class_init, +}; + +static void nubus_register_types(void) +{ + type_register_static(&nubus_bridge_info); +} + +type_init(nubus_register_types) diff --git a/hw/nubus/nubus-bus.c b/hw/nubus/nubus-bus.c new file mode 100644 index 0000000000..cd566ae640 --- /dev/null +++ b/hw/nubus/nubus-bus.c @@ -0,0 +1,111 @@ +/* + * QEMU Macintosh Nubus + * + * Copyright (c) 2013-2018 Laurent Vivier + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "hw/nubus/nubus.h" +#include "hw/sysbus.h" +#include "qapi/error.h" + + +static NubusBus *nubus_find(void) +{ + /* Returns NULL unless there is exactly one nubus device */ + return NUBUS_BUS(object_resolve_path_type("", TYPE_NUBUS_BUS, NULL)); +} + +static void nubus_slot_write(void *opaque, hwaddr addr, uint64_t val, + unsigned int size) +{ + return; +} + + +static uint64_t nubus_slot_read(void *opaque, hwaddr addr, + unsigned int size) +{ + return 0; +} + +static const MemoryRegionOps nubus_slot_ops = { + .read = nubus_slot_read, + .write = nubus_slot_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 1, + }, +}; + +static void nubus_super_slot_write(void *opaque, hwaddr addr, uint64_t val, + unsigned int size) +{ + return; +} + +static uint64_t nubus_super_slot_read(void *opaque, hwaddr addr, + unsigned int size) +{ + return 0; +} + +static const MemoryRegionOps nubus_super_slot_ops = { + .read = nubus_super_slot_read, + .write = nubus_super_slot_write, + .endianness = DEVICE_BIG_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 1, + }, +}; + +static void nubus_realize(BusState *bus, Error **errp) +{ + if (!nubus_find()) { + error_setg(errp, "at most one %s device is permitted", TYPE_NUBUS_BUS); + return; + } +} + +static void nubus_init(Object *obj) +{ + NubusBus *nubus = NUBUS_BUS(obj); + + memory_region_init_io(&nubus->super_slot_io, obj, &nubus_super_slot_ops, + nubus, "nubus-super-slots", + NUBUS_SUPER_SLOT_NB * NUBUS_SUPER_SLOT_SIZE); + + memory_region_init_io(&nubus->slot_io, obj, &nubus_slot_ops, + nubus, "nubus-slots", + NUBUS_SLOT_NB * NUBUS_SLOT_SIZE); + + nubus->current_slot = NUBUS_FIRST_SLOT; +} + +static void nubus_class_init(ObjectClass *oc, void *data) +{ + BusClass *bc = BUS_CLASS(oc); + + bc->realize = nubus_realize; +} + +static const TypeInfo nubus_bus_info = { + .name = TYPE_NUBUS_BUS, + .parent = TYPE_BUS, + .instance_size = sizeof(NubusBus), + .instance_init = nubus_init, + .class_init = nubus_class_init, +}; + +static void nubus_register_types(void) +{ + type_register_static(&nubus_bus_info); +} + +type_init(nubus_register_types) diff --git a/hw/nubus/nubus-device.c b/hw/nubus/nubus-device.c new file mode 100644 index 0000000000..6b35ddb33d --- /dev/null +++ b/hw/nubus/nubus-device.c @@ -0,0 +1,210 @@ +/* + * QEMU Macintosh Nubus + * + * Copyright (c) 2013-2018 Laurent Vivier + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "hw/nubus/nubus.h" +#include "qapi/error.h" + + +/* The Format Block Structure */ + +#define FBLOCK_DIRECTORY_OFFSET 0 +#define FBLOCK_LENGTH 4 +#define FBLOCK_CRC 8 +#define FBLOCK_REVISION_LEVEL 12 +#define FBLOCK_FORMAT 13 +#define FBLOCK_TEST_PATTERN 14 +#define FBLOCK_RESERVED 18 +#define FBLOCK_BYTE_LANES 19 + +#define FBLOCK_SIZE 20 + +# define FBLOCK_PATTERN_VAL 0x5a932bc7 + +static uint64_t nubus_fblock_read(void *opaque, hwaddr addr, unsigned int size) +{ + NubusDevice *dev = opaque; + uint64_t val; + +#define BYTE(v, b) (((v) >> (24 - 8 * (b))) & 0xff) + switch (addr) { + case FBLOCK_BYTE_LANES: + val = dev->byte_lanes; + val |= (val ^ 0xf) << 4; + break; + case FBLOCK_RESERVED: + val = 0x00; + break; + case FBLOCK_TEST_PATTERN...FBLOCK_TEST_PATTERN + 3: + val = BYTE(FBLOCK_PATTERN_VAL, addr - FBLOCK_TEST_PATTERN); + break; + case FBLOCK_FORMAT: + val = dev->rom_format; + break; + case FBLOCK_REVISION_LEVEL: + val = dev->rom_rev; + break; + case FBLOCK_CRC...FBLOCK_CRC + 3: + val = BYTE(dev->rom_crc, addr - FBLOCK_CRC); + break; + case FBLOCK_LENGTH...FBLOCK_LENGTH + 3: + val = BYTE(dev->rom_length, addr - FBLOCK_LENGTH); + break; + case FBLOCK_DIRECTORY_OFFSET...FBLOCK_DIRECTORY_OFFSET + 3: + val = BYTE(dev->directory_offset, addr - FBLOCK_DIRECTORY_OFFSET); + break; + default: + val = 0; + break; + } + return val; +} + +static void nubus_fblock_write(void *opaque, hwaddr addr, uint64_t val, + unsigned int size) +{ + /* READ-ONLY */ +} + +static const MemoryRegionOps nubus_format_block_ops = { + .read = nubus_fblock_read, + .write = nubus_fblock_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 1, + } +}; + +static void nubus_register_format_block(NubusDevice *dev) +{ + char fblock_name[27]; + + sprintf(fblock_name, "nubus-slot-%d-format-block", dev->slot_nb); + + hwaddr fblock_offset = memory_region_size(&dev->slot_mem) - FBLOCK_SIZE; + memory_region_init_io(&dev->fblock_io, NULL, &nubus_format_block_ops, + dev, fblock_name, FBLOCK_SIZE); + memory_region_add_subregion(&dev->slot_mem, fblock_offset, + &dev->fblock_io); +} + +static void mac_nubus_rom_write(void *opaque, hwaddr addr, uint64_t val, + unsigned int size) +{ +} + +static uint64_t mac_nubus_rom_read(void *opaque, hwaddr addr, + unsigned int size) +{ + NubusDevice *dev = opaque; + + return dev->rom[addr]; +} + +static const MemoryRegionOps mac_nubus_rom_ops = { + .read = mac_nubus_rom_read, + .write = mac_nubus_rom_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 1, + }, +}; + + +void nubus_register_rom(NubusDevice *dev, const uint8_t *rom, uint32_t size, + int revision, int format, uint8_t byte_lanes) +{ + hwaddr rom_offset; + char rom_name[18]; + + /* FIXME : really compute CRC */ + dev->rom_length = 0; + dev->rom_crc = 0; + + dev->rom_rev = revision; + dev->rom_format = format; + + dev->byte_lanes = byte_lanes; + dev->directory_offset = -size; + + /* ROM */ + + dev->rom = rom; + sprintf(rom_name, "nubus-slot-%d-rom", dev->slot_nb); + memory_region_init_io(&dev->rom_io, NULL, &mac_nubus_rom_ops, + dev, rom_name, size); + memory_region_set_readonly(&dev->rom_io, true); + + rom_offset = memory_region_size(&dev->slot_mem) - FBLOCK_SIZE + + dev->directory_offset; + memory_region_add_subregion(&dev->slot_mem, rom_offset, &dev->rom_io); + +} + +static void nubus_device_realize(DeviceState *dev, Error **errp) +{ + NubusBus *nubus = NUBUS_BUS(qdev_get_parent_bus(DEVICE(dev))); + NubusDevice *nd = NUBUS_DEVICE(dev); + char name[16]; + hwaddr slot_offset; + + if (nubus->current_slot < NUBUS_FIRST_SLOT || + nubus->current_slot > NUBUS_LAST_SLOT) { + error_setg(errp, "Cannot register nubus card, not enough slots"); + return; + } + + nd->slot_nb = nubus->current_slot++; + snprintf(name, sizeof(name), "nubus-slot-%d", nd->slot_nb); + + if (nd->slot_nb < NUBUS_FIRST_SLOT) { + /* Super */ + slot_offset = (nd->slot_nb - 6) * NUBUS_SUPER_SLOT_SIZE; + + memory_region_init(&nd->slot_mem, OBJECT(dev), name, + NUBUS_SUPER_SLOT_SIZE); + memory_region_add_subregion(&nubus->super_slot_io, slot_offset, + &nd->slot_mem); + } else { + /* Normal */ + slot_offset = nd->slot_nb * NUBUS_SLOT_SIZE; + + memory_region_init(&nd->slot_mem, OBJECT(dev), name, NUBUS_SLOT_SIZE); + memory_region_add_subregion(&nubus->slot_io, slot_offset, + &nd->slot_mem); + } + + nubus_register_format_block(nd); +} + +static void nubus_device_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = nubus_device_realize; + dc->bus_type = TYPE_NUBUS_BUS; +} + +static const TypeInfo nubus_device_type_info = { + .name = TYPE_NUBUS_DEVICE, + .parent = TYPE_DEVICE, + .abstract = true, + .instance_size = sizeof(NubusDevice), + .class_init = nubus_device_class_init, +}; + +static void nubus_register_types(void) +{ + type_register_static(&nubus_device_type_info); +} + +type_init(nubus_register_types) diff --git a/include/hw/display/macfb.h b/include/hw/display/macfb.h index 70ea5480fe..3059f2f36a 100644 --- a/include/hw/display/macfb.h +++ b/include/hw/display/macfb.h @@ -39,4 +39,25 @@ typedef struct { MacfbState macfb; } MacfbSysBusState; +#define MACFB_NUBUS_DEVICE_CLASS(class) \ + OBJECT_CLASS_CHECK(MacfbNubusDeviceClass, (class), TYPE_NUBUS_MACFB) +#define MACFB_NUBUS_GET_CLASS(obj) \ + OBJECT_GET_CLASS(MacfbNubusDeviceClass, (obj), TYPE_NUBUS_MACFB) + +typedef struct MacfbNubusDeviceClass { + DeviceClass parent_class; + + DeviceRealize parent_realize; +} MacfbNubusDeviceClass; + +#define TYPE_NUBUS_MACFB "nubus-macfb" +#define NUBUS_MACFB(obj) \ + OBJECT_CHECK(MacfbNubusState, (obj), TYPE_NUBUS_MACFB) + +typedef struct { + NubusDevice busdev; + + MacfbState macfb; +} MacfbNubusState; + #endif diff --git a/include/hw/nubus/mac-nubus-bridge.h b/include/hw/nubus/mac-nubus-bridge.h new file mode 100644 index 0000000000..ce9c789d99 --- /dev/null +++ b/include/hw/nubus/mac-nubus-bridge.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2013-2018 Laurent Vivier + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef HW_NUBUS_MAC_H +#define HW_NUBUS_MAC_H + +#include "hw/nubus/nubus.h" + +#define TYPE_MAC_NUBUS_BRIDGE "mac-nubus-bridge" +#define MAC_NUBUS_BRIDGE(obj) OBJECT_CHECK(MacNubusState, (obj), \ + TYPE_MAC_NUBUS_BRIDGE) + +typedef struct MacNubusState { + SysBusDevice sysbus_dev; + + NubusBus *bus; +} MacNubusState; + +#endif diff --git a/include/hw/nubus/nubus.h b/include/hw/nubus/nubus.h new file mode 100644 index 0000000000..096bafb322 --- /dev/null +++ b/include/hw/nubus/nubus.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2013-2018 Laurent Vivier + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef HW_NUBUS_NUBUS_H +#define HW_NUBUS_NUBUS_H + +#include "hw/qdev.h" +#include "exec/address-spaces.h" + +#define NUBUS_SUPER_SLOT_SIZE 0x10000000U +#define NUBUS_SUPER_SLOT_NB 0x9 + +#define NUBUS_SLOT_SIZE 0x01000000 +#define NUBUS_SLOT_NB 0xF + +#define NUBUS_FIRST_SLOT 0x9 +#define NUBUS_LAST_SLOT 0xF + +#define TYPE_NUBUS_DEVICE "nubus-device" +#define NUBUS_DEVICE(obj) \ + OBJECT_CHECK(NubusDevice, (obj), TYPE_NUBUS_DEVICE) + +#define TYPE_NUBUS_BUS "nubus-bus" +#define NUBUS_BUS(obj) OBJECT_CHECK(NubusBus, (obj), TYPE_NUBUS_BUS) + +#define TYPE_NUBUS_BRIDGE "nubus-bridge" +#define NUBUS_BRIDGE(obj) OBJECT_CHECK(NubusBridge, (obj), TYPE_NUBUS_BRIDGE) + +typedef struct NubusBus { + BusState qbus; + + MemoryRegion super_slot_io; + MemoryRegion slot_io; + + int current_slot; +} NubusBus; + +typedef struct NubusDevice { + DeviceState qdev; + + int slot_nb; + MemoryRegion slot_mem; + + /* Format Block */ + + MemoryRegion fblock_io; + + uint32_t rom_length; + uint32_t rom_crc; + uint8_t rom_rev; + uint8_t rom_format; + uint8_t byte_lanes; + int32_t directory_offset; + + /* ROM */ + + MemoryRegion rom_io; + const uint8_t *rom; +} NubusDevice; + +void nubus_register_rom(NubusDevice *dev, const uint8_t *rom, uint32_t size, + int revision, int format, uint8_t byte_lanes); + +#endif From patchwork Wed Jun 27 23:29:49 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Vivier X-Patchwork-Id: 935794 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=vivier.eu Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41GKFY3jxkz9s01 for ; Thu, 28 Jun 2018 09:42:09 +1000 (AEST) Received: from localhost ([::1]:33679 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fYK4d-0007jL-7R for incoming@patchwork.ozlabs.org; Wed, 27 Jun 2018 19:42:07 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:48603) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fYJtW-000844-Ig for qemu-devel@nongnu.org; Wed, 27 Jun 2018 19:30:40 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fYJtT-0003m0-4n for qemu-devel@nongnu.org; Wed, 27 Jun 2018 19:30:38 -0400 Received: from mout.kundenserver.de ([212.227.126.133]:35214) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1fYJtS-0003lj-QZ; Wed, 27 Jun 2018 19:30:35 -0400 Received: from localhost.localdomain ([78.238.229.36]) by mrelayeu.kundenserver.de (mreue001 [212.227.15.167]) with ESMTPSA (Nemesis) id 0LpTGA-1g2gMg1qFi-00fOYe; Thu, 28 Jun 2018 01:30:08 +0200 From: Laurent Vivier To: qemu-devel@nongnu.org Date: Thu, 28 Jun 2018 01:29:49 +0200 Message-Id: <20180627232951.14725-9-laurent@vivier.eu> X-Mailer: git-send-email 2.14.4 In-Reply-To: <20180627232951.14725-1-laurent@vivier.eu> References: <20180627232951.14725-1-laurent@vivier.eu> X-Provags-ID: V03:K1:ciqDDgRiQI1VW0YEAUvrxKJwGnUyRhoKi5J1AmVRsuxpuCNIFgq 2zhQhdrUaLOluS3K9g+WvUSJdy+n35zRHZ0mYqQcv2OusKMbRFbFMcb8FwAIdOCPBtghPLN LjwyD2FL74SvWuTha6EidmgbSNcb35ZGa+YZl7RJ1eY0TldPVpcnI2FICc+I8gGQ+ZfGcHk Yxjd1L/T2Eso5qEv+csuQ== X-UI-Out-Filterresults: notjunk:1; V01:K0:4V2c1u9Qh9E=:ilkTbA3zwSAM9Qw/hDwUS4 6DaoqrlBvXzhMahQ3nmZNpY4a2kBvanKq44n5Rps1HuHVPWmmfXnfohFgGgKg0W5lCYcs6pWu Zi8AX3v4ZOEGk3mapyQAL2YhJhsCkoUPJtpZNcPrYui/DfMO+MMsL3y+S2ep+2dJEBTLjF7J8 rj7Y+8N+F0ksQuvw+spsP/nBDW7N14tWEw46HUTMnGl7KvSgwiiDbLCNhkcb1cZ2XpsHcl074 qGJaPOIirbP0ZJyqYJM8q1z+4dEm1qWvqlAbO8ZpRoHGCUzoUd9ZJe4QK2RqsM+dVzDrwTp2X RUHLm8Ty3lXSbK5S1i8INF4nS/4q6Y+cE25X9zIKkGLaZqjroYWN5NUTUgUmtpTH1GsTlg9pP rCoDbMsn49Oxx8dwyNM9PYok4KFBjRzOLJZ/BMnnfLJrHW3lMTcOTMma+eVZZzCzQg1q2oSi8 wqyBnWSvvSz5fwJV+duKoysNN0TDPdR3YSo33iUAfQF7RO8oc6LDBupMLbitj0eOr7WEKCJv+ YhAYQBpfpYVj5s9yhOni5qHA/pXyYCX0BikEQ/pW25crjy2q2XlL7lxDdhWiE2BCmBhSDzNt9 nYGqYMLTRAG7flyzV5mcLmlB6MwnTl6r4PQMSvMLjxlaP4S+xkNxyI5PkP2pdvJZx1mwwbtz0 1g1J3lDcR1TiVYwt4Z+qJS9TRzsZUaAyah3sgtps/g9fvHt4R3CRw5RA8/SV5suhmueU= X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 212.227.126.133 Subject: [Qemu-devel] [RFC v3 08/10] hw/m68k: add a dummy SWIM floppy controller 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: , Cc: Kevin Wolf , Fam Zheng , qemu-block@nongnu.org, Jason Wang , Mark Cave-Ayland , "Dr. David Alan Gilbert" , Laurent Vivier , =?utf-8?q?Herv=C3=A9_Poussineau?= , Gerd Hoffmann , Paolo Bonzini , Max Reitz , Yongbok Kim , =?utf-8?q?Andreas_F=C3=A4rber?= , Aurelien Jarno Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Co-developed-by: Mark Cave-Ayland Signed-off-by: Mark Cave-Ayland Signed-off-by: Laurent Vivier --- hw/block/Makefile.objs | 1 + hw/block/swim.c | 284 ++++++++++++++++++++++++++++++++++++++++++++++++ include/hw/block/swim.h | 53 +++++++++ 3 files changed, 338 insertions(+) create mode 100644 hw/block/swim.c create mode 100644 include/hw/block/swim.h diff --git a/hw/block/Makefile.objs b/hw/block/Makefile.objs index 53ce5751ae..068de3f0c9 100644 --- a/hw/block/Makefile.objs +++ b/hw/block/Makefile.objs @@ -8,6 +8,7 @@ common-obj-$(CONFIG_XEN) += xen_disk.o common-obj-$(CONFIG_ECC) += ecc.o common-obj-$(CONFIG_ONENAND) += onenand.o common-obj-$(CONFIG_NVME_PCI) += nvme.o +common-obj-$(CONFIG_SWIM) += swim.o obj-$(CONFIG_SH4) += tc58128.o diff --git a/hw/block/swim.c b/hw/block/swim.c new file mode 100644 index 0000000000..6b1d0371e8 --- /dev/null +++ b/hw/block/swim.c @@ -0,0 +1,284 @@ +/* + * QEMU Macintosh floppy disk controller emulator (SWIM) + * + * Copyright (c) 2014-2018 Laurent Vivier + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "hw/sysbus.h" +#include "hw/block/swim.h" + +/* IWM registers */ + +#define IWM_PH0L 0 +#define IWM_PH0H 1 +#define IWM_PH1L 2 +#define IWM_PH1H 3 +#define IWM_PH2L 4 +#define IWM_PH2H 5 +#define IWM_PH3L 6 +#define IWM_PH3H 7 +#define IWM_MTROFF 8 +#define IWM_MTRON 9 +#define IWM_INTDRIVE 10 +#define IWM_EXTDRIVE 11 +#define IWM_Q6L 12 +#define IWM_Q6H 13 +#define IWM_Q7L 14 +#define IWM_Q7H 15 + +/* SWIM registers */ + +#define SWIM_WRITE_DATA 0 +#define SWIM_WRITE_MARK 1 +#define SWIM_WRITE_CRC 2 +#define SWIM_WRITE_PARAMETER 3 +#define SWIM_WRITE_PHASE 4 +#define SWIM_WRITE_SETUP 5 +#define SWIM_WRITE_MODE0 6 +#define SWIM_WRITE_MODE1 7 + +#define SWIM_READ_DATA 8 +#define SWIM_READ_MARK 9 +#define SWIM_READ_ERROR 10 +#define SWIM_READ_PARAMETER 11 +#define SWIM_READ_PHASE 12 +#define SWIM_READ_SETUP 13 +#define SWIM_READ_STATUS 14 +#define SWIM_READ_HANDSHAKE 15 + +#define REG_SHIFT 9 + +#define SWIM_MODE_IWM 0 +#define SWIM_MODE_SWIM 1 + +/* bits in phase register */ + +#define SWIM_SEEK_NEGATIVE 0x074 +#define SWIM_STEP 0x071 +#define SWIM_MOTOR_ON 0x072 +#define SWIM_MOTOR_OFF 0x076 +#define SWIM_INDEX 0x073 +#define SWIM_EJECT 0x077 +#define SWIM_SETMFM 0x171 +#define SWIM_SETGCR 0x175 +#define SWIM_RELAX 0x033 +#define SWIM_LSTRB 0x008 +#define SWIM_CA_MASK 0x077 + +/* Select values for swim_select and swim_readbit */ + +#define SWIM_READ_DATA_0 0x074 +#define SWIM_TWOMEG_DRIVE 0x075 +#define SWIM_SINGLE_SIDED 0x076 +#define SWIM_DRIVE_PRESENT 0x077 +#define SWIM_DISK_IN 0x170 +#define SWIM_WRITE_PROT 0x171 +#define SWIM_TRACK_ZERO 0x172 +#define SWIM_TACHO 0x173 +#define SWIM_READ_DATA_1 0x174 +#define SWIM_MFM_MODE 0x175 +#define SWIM_SEEK_COMPLETE 0x176 +#define SWIM_ONEMEG_MEDIA 0x177 + +/* Bits in handshake register */ + +#define SWIM_MARK_BYTE 0x01 +#define SWIM_CRC_ZERO 0x02 +#define SWIM_RDDATA 0x04 +#define SWIM_SENSE 0x08 +#define SWIM_MOTEN 0x10 +#define SWIM_ERROR 0x20 +#define SWIM_DAT2BYTE 0x40 +#define SWIM_DAT1BYTE 0x80 + +/* bits in setup register */ + +#define SWIM_S_INV_WDATA 0x01 +#define SWIM_S_3_5_SELECT 0x02 +#define SWIM_S_GCR 0x04 +#define SWIM_S_FCLK_DIV2 0x08 +#define SWIM_S_ERROR_CORR 0x10 +#define SWIM_S_IBM_DRIVE 0x20 +#define SWIM_S_GCR_WRITE 0x40 +#define SWIM_S_TIMEOUT 0x80 + +/* bits in mode register */ + +#define SWIM_CLFIFO 0x01 +#define SWIM_ENBL1 0x02 +#define SWIM_ENBL2 0x04 +#define SWIM_ACTION 0x08 +#define SWIM_WRITE_MODE 0x10 +#define SWIM_HEDSEL 0x20 +#define SWIM_MOTON 0x80 + + +static void iwmctrl_write(void *opaque, hwaddr reg, uint64_t value, + unsigned size) +{ + SWIMCtrl *swimctrl = opaque; + + reg >>= REG_SHIFT; + + swimctrl->regs[reg >> 1] = reg & 1; + + if (swimctrl->regs[IWM_Q6] && + swimctrl->regs[IWM_Q7]) { + if (swimctrl->regs[IWM_MTR]) { + /* data register */ + swimctrl->iwm_data = value; + } else { + /* mode register */ + swimctrl->iwm_mode = value; + /* detect sequence to switch from IWM mode to SWIM mode */ + switch (swimctrl->iwm_switch) { + case 0: + if (value == 0x57) { + swimctrl->iwm_switch++; + } + break; + case 1: + if (value == 0x17) { + swimctrl->iwm_switch++; + } + break; + case 2: + if (value == 0x57) { + swimctrl->iwm_switch++; + } + break; + case 3: + if (value == 0x57) { + swimctrl->mode = SWIM_MODE_SWIM; + swimctrl->iwm_switch = 0; + } + break; + } + } + } +} + +static uint64_t iwmctrl_read(void *opaque, hwaddr reg, unsigned size) +{ + SWIMCtrl *swimctrl = opaque; + + reg >>= REG_SHIFT; + + swimctrl->regs[reg >> 1] = reg & 1; + + return 0; +} + +static void swimctrl_write(void *opaque, hwaddr reg, uint64_t value, + unsigned size) +{ + SWIMCtrl *swimctrl = opaque; + + if (swimctrl->mode == SWIM_MODE_IWM) { + iwmctrl_write(opaque, reg, value, size); + return; + } + + reg >>= REG_SHIFT; + + switch (reg) { + case SWIM_WRITE_PHASE: + swimctrl->swim_phase = value; + break; + case SWIM_WRITE_MODE0: + swimctrl->swim_mode &= ~value; + break; + case SWIM_WRITE_MODE1: + swimctrl->swim_mode |= value; + break; + case SWIM_WRITE_DATA: + case SWIM_WRITE_MARK: + case SWIM_WRITE_CRC: + case SWIM_WRITE_PARAMETER: + case SWIM_WRITE_SETUP: + break; + } +} + +static uint64_t swimctrl_read(void *opaque, hwaddr reg, unsigned size) +{ + SWIMCtrl *swimctrl = opaque; + uint32_t value = 0; + + if (swimctrl->mode == SWIM_MODE_IWM) { + return iwmctrl_read(opaque, reg, size); + } + + reg >>= REG_SHIFT; + + switch (reg) { + case SWIM_READ_PHASE: + value = swimctrl->swim_phase; + break; + case SWIM_READ_HANDSHAKE: + if (swimctrl->swim_phase == SWIM_DRIVE_PRESENT) { + /* always answer "no drive present" */ + value = SWIM_SENSE; + } + break; + case SWIM_READ_DATA: + case SWIM_READ_MARK: + case SWIM_READ_ERROR: + case SWIM_READ_PARAMETER: + case SWIM_READ_SETUP: + case SWIM_READ_STATUS: + break; + } + + return value; +} + +static const MemoryRegionOps swimctrl_mem_ops = { + .write = swimctrl_write, + .read = swimctrl_read, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void swim_init(Object *obj) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + SWIMCtrl *swimctrl = SWIM(obj); + + memory_region_init_io(&swimctrl->iomem, obj, &swimctrl_mem_ops, swimctrl, + "swim", 0x2000); + sysbus_init_mmio(sbd, &swimctrl->iomem); +} + +static Property swim_properties[] = { + DEFINE_PROP_DRIVE("driveA", SWIMCtrl, drives[0].blk), + DEFINE_PROP_DRIVE("driveB", SWIMCtrl, drives[1].blk), + DEFINE_PROP_END_OF_LIST(), +}; + +static void swim_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->props = swim_properties; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); +} + +static const TypeInfo swim_info = { + .name = TYPE_SWIM, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SWIMCtrl), + .instance_init = swim_init, + .class_init = swim_class_init, +}; + +static void swim_register_types(void) +{ + type_register_static(&swim_info); +} + +type_init(swim_register_types) diff --git a/include/hw/block/swim.h b/include/hw/block/swim.h new file mode 100644 index 0000000000..2c0258967c --- /dev/null +++ b/include/hw/block/swim.h @@ -0,0 +1,53 @@ +/* + * QEMU Macintosh floppy disk controller emulator (SWIM) + * + * Copyright (c) 2014-2018 Laurent Vivier + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#ifndef SWIM_H +#define SWIM_H + +#include "qemu/osdep.h" +#include "hw/sysbus.h" + +#define MAX_FD 2 + +typedef struct SWIMCtrl SWIMCtrl; + +typedef struct FDrive { + SWIMCtrl *swimctrl; + BlockBackend *blk; +} FDrive; + +#define TYPE_SWIM "swim" +#define SWIM(obj) OBJECT_CHECK(SWIMCtrl, (obj), TYPE_SWIM) + +typedef struct SWIMCtrl { + SysBusDevice parent_obj; + + MemoryRegion iomem; + FDrive drives[MAX_FD]; + int mode; + /* IWM mode */ + int iwm_switch; + int regs[8]; +#define IWM_PH0 0 +#define IWM_PH1 1 +#define IWM_PH2 2 +#define IWM_PH3 3 +#define IWM_MTR 4 +#define IWM_DRIVE 5 +#define IWM_Q6 6 +#define IWM_Q7 7 + uint8_t iwm_data; + uint8_t iwm_mode; + /* SWIM mode */ + uint8_t swim_phase; + uint8_t swim_mode; +} SWIMCtrl; + +#endif From patchwork Wed Jun 27 23:29:50 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Vivier X-Patchwork-Id: 935789 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=vivier.eu Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41GK870n7Jz9s01 for ; Thu, 28 Jun 2018 09:37:27 +1000 (AEST) Received: from localhost ([::1]:33650 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fYK04-0003xG-Nm for incoming@patchwork.ozlabs.org; Wed, 27 Jun 2018 19:37:24 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:48613) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fYJtX-00084Y-5B for qemu-devel@nongnu.org; Wed, 27 Jun 2018 19:30:43 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fYJtV-0003mq-9K for qemu-devel@nongnu.org; Wed, 27 Jun 2018 19:30:39 -0400 Received: from mout.kundenserver.de ([212.227.126.130]:39794) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1fYJtR-0003kx-8Z; Wed, 27 Jun 2018 19:30:33 -0400 Received: from localhost.localdomain ([78.238.229.36]) by mrelayeu.kundenserver.de (mreue001 [212.227.15.167]) with ESMTPSA (Nemesis) id 0Ly6OT-1gBJUy3685-015cVT; Thu, 28 Jun 2018 01:30:10 +0200 From: Laurent Vivier To: qemu-devel@nongnu.org Date: Thu, 28 Jun 2018 01:29:50 +0200 Message-Id: <20180627232951.14725-10-laurent@vivier.eu> X-Mailer: git-send-email 2.14.4 In-Reply-To: <20180627232951.14725-1-laurent@vivier.eu> References: <20180627232951.14725-1-laurent@vivier.eu> MIME-Version: 1.0 X-Provags-ID: V03:K1:3ZUJZhBU5CDADQAngPwU1BSO5t3We1uUlBdTJjQn+JCJ/tUCAPL MpEQt1+i1D4Wpq8xXRDHRdorUbKo51Zvp2otkZf6gEB/m+I3TsOdIPscePnGEjpBExqihQC Lu+Wz8yIoy/PswiPaAPuYbGYtSgS2Xufp4PHLwYjR9R8cbdIOsm9hATyE037XBCoWTuqdl3 bY7e3R+XPwdosuz3A76ig== X-UI-Out-Filterresults: notjunk:1; V01:K0:AJOn2GvUvUI=:/y8Sl+VuHUgxTmHE7cUkt0 lTw5rTPNvXX61y71dVeQWzNOu2mhE3sclfwaEwALId1EDxWdiLpiDolsudar3Gzk5XKNTKCGN Cz/sj0Kt1kExeEfGmpmiCBs4HHA+OrEYKwB81XJvFQkuhTPmHHp9u2ESYawEAzClRA3bdZRTh LtZVnQdA2T1CBcGgoJ0cVw5zCmchaGTdSthuqyqUqo4bjgzkBeapLgVg4NqeqEL0DhHWDrUh+ Ry/OJmpSxWH7dZDg6IF6uyOxp/t94tD0gl5fre/Iyu09uF3MYmk79c96P6McVPF27WnC4w2Ic X4JkXQpZShAXccYe0BS/lt58MUSV5vxvUCmhiMO7WXjeR6ArhZetOVA4a+oMt+7BAP6T1u5On 5DbY4NEuz5SCYT1YpWRKA9bVGPJLC1su2EWqmHaJRveJXnYdvZmdfKUc/ShmSyMkQwOjMdgY5 iaIAPVpsCe1xsZetqJ6NISBxas/f35KrJTOxlwAFT40wwdnWgbJq9AEwLftUh2xzcjbGw4JnA PmPYGOdFIlQEk4vla6fi5ZFDdYe+DsGCFRdtgTEMt1D4qAPv3tp+KPjKtO1hcW2H4uyrYUZgD VHMGugWYPbydiHHcUwJptzB5LbxPsNz4mNKcad7ZuQhoy8cM39bKUhtKQyQgey2ZpK3XOFR2D HeVTc3SR5lgx7dLrhW3aS8dAKUYhw23g5QFZpx0JPCYLr7EVVzTK/D5pNqzL33+PufmCcTZxi 8VJrtNgmddhSNbUP X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 212.227.126.130 Subject: [Qemu-devel] [RFC v3 09/10] dp8393x: manage big endian bus 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: , Cc: Kevin Wolf , Fam Zheng , qemu-block@nongnu.org, Jason Wang , Mark Cave-Ayland , "Dr. David Alan Gilbert" , Laurent Vivier , =?utf-8?q?Herv=C3=A9_Poussineau?= , Gerd Hoffmann , Paolo Bonzini , Max Reitz , Yongbok Kim , =?utf-8?q?Andreas_F=C3=A4rber?= , Aurelien Jarno Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" This is needed by Quadra 800, this card can run on little-endian or big-endian bus. Signed-off-by: Laurent Vivier Tested-by: Hervé Poussineau --- hw/net/dp8393x.c | 88 ++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 57 insertions(+), 31 deletions(-) diff --git a/hw/net/dp8393x.c b/hw/net/dp8393x.c index f2d2ce344c..62adff9ba3 100644 --- a/hw/net/dp8393x.c +++ b/hw/net/dp8393x.c @@ -150,6 +150,7 @@ typedef struct dp8393xState { /* Hardware */ uint8_t it_shift; + bool big_endian; qemu_irq irq; #ifdef DEBUG_SONIC int irq_level; @@ -220,6 +221,29 @@ static uint32_t dp8393x_wt(dp8393xState *s) return s->regs[SONIC_WT1] << 16 | s->regs[SONIC_WT0]; } +static uint16_t dp8393x_get(dp8393xState *s, int width, uint16_t *base, + int offset) +{ + uint16_t val; + + if (s->big_endian) { + val = be16_to_cpu(base[offset * width + width - 1]); + } else { + val = le16_to_cpu(base[offset * width]); + } + return val; +} + +static void dp8393x_put(dp8393xState *s, int width, uint16_t *base, int offset, + uint16_t val) +{ + if (s->big_endian) { + base[offset * width + width - 1] = cpu_to_be16(val); + } else { + base[offset * width] = cpu_to_le16(val); + } +} + static void dp8393x_update_irq(dp8393xState *s) { int level = (s->regs[SONIC_IMR] & s->regs[SONIC_ISR]) ? 1 : 0; @@ -251,12 +275,12 @@ static void dp8393x_do_load_cam(dp8393xState *s) /* Fill current entry */ address_space_rw(&s->as, dp8393x_cdp(s), MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); - s->cam[index][0] = data[1 * width] & 0xff; - s->cam[index][1] = data[1 * width] >> 8; - s->cam[index][2] = data[2 * width] & 0xff; - s->cam[index][3] = data[2 * width] >> 8; - s->cam[index][4] = data[3 * width] & 0xff; - s->cam[index][5] = data[3 * width] >> 8; + s->cam[index][0] = dp8393x_get(s, width, data, 1) & 0xff; + s->cam[index][1] = dp8393x_get(s, width, data, 1) >> 8; + s->cam[index][2] = dp8393x_get(s, width, data, 2) & 0xff; + s->cam[index][3] = dp8393x_get(s, width, data, 2) >> 8; + s->cam[index][4] = dp8393x_get(s, width, data, 3) & 0xff; + s->cam[index][5] = dp8393x_get(s, width, data, 3) >> 8; DPRINTF("load cam[%d] with %02x%02x%02x%02x%02x%02x\n", index, s->cam[index][0], s->cam[index][1], s->cam[index][2], s->cam[index][3], s->cam[index][4], s->cam[index][5]); @@ -269,7 +293,7 @@ static void dp8393x_do_load_cam(dp8393xState *s) /* Read CAM enable */ address_space_rw(&s->as, dp8393x_cdp(s), MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); - s->regs[SONIC_CE] = data[0 * width]; + s->regs[SONIC_CE] = dp8393x_get(s, width, data, 0); DPRINTF("load cam done. cam enable mask 0x%04x\n", s->regs[SONIC_CE]); /* Done */ @@ -290,10 +314,10 @@ static void dp8393x_do_read_rra(dp8393xState *s) MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); /* Update SONIC registers */ - s->regs[SONIC_CRBA0] = data[0 * width]; - s->regs[SONIC_CRBA1] = data[1 * width]; - s->regs[SONIC_RBWC0] = data[2 * width]; - s->regs[SONIC_RBWC1] = data[3 * width]; + s->regs[SONIC_CRBA0] = dp8393x_get(s, width, data, 0); + s->regs[SONIC_CRBA1] = dp8393x_get(s, width, data, 1); + s->regs[SONIC_RBWC0] = dp8393x_get(s, width, data, 2); + s->regs[SONIC_RBWC1] = dp8393x_get(s, width, data, 3); DPRINTF("CRBA0/1: 0x%04x/0x%04x, RBWC0/1: 0x%04x/0x%04x\n", s->regs[SONIC_CRBA0], s->regs[SONIC_CRBA1], s->regs[SONIC_RBWC0], s->regs[SONIC_RBWC1]); @@ -408,12 +432,12 @@ static void dp8393x_do_transmit_packets(dp8393xState *s) tx_len = 0; /* Update registers */ - s->regs[SONIC_TCR] = data[0 * width] & 0xf000; - s->regs[SONIC_TPS] = data[1 * width]; - s->regs[SONIC_TFC] = data[2 * width]; - s->regs[SONIC_TSA0] = data[3 * width]; - s->regs[SONIC_TSA1] = data[4 * width]; - s->regs[SONIC_TFS] = data[5 * width]; + s->regs[SONIC_TCR] = dp8393x_get(s, width, data, 0) & 0xf000; + s->regs[SONIC_TPS] = dp8393x_get(s, width, data, 1); + s->regs[SONIC_TFC] = dp8393x_get(s, width, data, 2); + s->regs[SONIC_TSA0] = dp8393x_get(s, width, data, 3); + s->regs[SONIC_TSA1] = dp8393x_get(s, width, data, 4); + s->regs[SONIC_TFS] = dp8393x_get(s, width, data, 5); /* Handle programmable interrupt */ if (s->regs[SONIC_TCR] & SONIC_TCR_PINT) { @@ -439,9 +463,9 @@ static void dp8393x_do_transmit_packets(dp8393xState *s) address_space_rw(&s->as, dp8393x_ttda(s) + sizeof(uint16_t) * (4 + 3 * i) * width, MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); - s->regs[SONIC_TSA0] = data[0 * width]; - s->regs[SONIC_TSA1] = data[1 * width]; - s->regs[SONIC_TFS] = data[2 * width]; + s->regs[SONIC_TSA0] = dp8393x_get(s, width, data, 0); + s->regs[SONIC_TSA1] = dp8393x_get(s, width, data, 1); + s->regs[SONIC_TFS] = dp8393x_get(s, width, data, 2); } } @@ -468,7 +492,8 @@ static void dp8393x_do_transmit_packets(dp8393xState *s) s->regs[SONIC_TCR] |= SONIC_TCR_PTX; /* Write status */ - data[0 * width] = s->regs[SONIC_TCR] & 0x0fff; /* status */ + dp8393x_put(s, width, data, 0, + s->regs[SONIC_TCR] & 0x0fff); /* status */ size = sizeof(uint16_t) * width; address_space_rw(&s->as, dp8393x_ttda(s), @@ -482,8 +507,8 @@ static void dp8393x_do_transmit_packets(dp8393xState *s) sizeof(uint16_t) * (4 + 3 * s->regs[SONIC_TFC]) * width, MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); - s->regs[SONIC_CTDA] = data[0 * width] & ~0x1; - if (data[0 * width] & 0x1) { + s->regs[SONIC_CTDA] = dp8393x_get(s, width, data, 0) & ~0x1; + if (dp8393x_get(s, width, data, 0) & 0x1) { /* EOL detected */ break; } @@ -746,7 +771,7 @@ static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf, address = dp8393x_crda(s) + sizeof(uint16_t) * 5 * width; address_space_rw(&s->as, address, MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); - if (data[0 * width] & 0x1) { + if (dp8393x_get(s, width, data, 0) & 0x1) { /* Still EOL ; stop reception */ return -1; } else { @@ -790,11 +815,11 @@ static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf, /* Write status to memory */ DPRINTF("Write status at %08x\n", dp8393x_crda(s)); - data[0 * width] = s->regs[SONIC_RCR]; /* status */ - data[1 * width] = rx_len; /* byte count */ - data[2 * width] = s->regs[SONIC_TRBA0]; /* pkt_ptr0 */ - data[3 * width] = s->regs[SONIC_TRBA1]; /* pkt_ptr1 */ - data[4 * width] = s->regs[SONIC_RSC]; /* seq_no */ + dp8393x_put(s, width, data, 0, s->regs[SONIC_RCR]); /* status */ + dp8393x_put(s, width, data, 1, rx_len); /* byte count */ + dp8393x_put(s, width, data, 2, s->regs[SONIC_TRBA0]); /* pkt_ptr0 */ + dp8393x_put(s, width, data, 3, s->regs[SONIC_TRBA1]); /* pkt_ptr1 */ + dp8393x_put(s, width, data, 4, s->regs[SONIC_RSC]); /* seq_no */ size = sizeof(uint16_t) * 5 * width; address_space_rw(&s->as, dp8393x_crda(s), MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 1); @@ -803,12 +828,12 @@ static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf, size = sizeof(uint16_t) * width; address_space_rw(&s->as, dp8393x_crda(s) + sizeof(uint16_t) * 5 * width, MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); - s->regs[SONIC_LLFA] = data[0 * width]; + s->regs[SONIC_LLFA] = dp8393x_get(s, width, data, 0); if (s->regs[SONIC_LLFA] & 0x1) { /* EOL detected */ s->regs[SONIC_ISR] |= SONIC_ISR_RDE; } else { - data[0 * width] = 0; /* in_use */ + dp8393x_put(s, width, data, 0, 0); /* in_use */ address_space_rw(&s->as, dp8393x_crda(s) + sizeof(uint16_t) * 6 * width, MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, sizeof(uint16_t), 1); s->regs[SONIC_CRDA] = s->regs[SONIC_LLFA]; @@ -921,6 +946,7 @@ static Property dp8393x_properties[] = { DEFINE_NIC_PROPERTIES(dp8393xState, conf), DEFINE_PROP_PTR("dma_mr", dp8393xState, dma_mr), DEFINE_PROP_UINT8("it_shift", dp8393xState, it_shift, 0), + DEFINE_PROP_BOOL("big_endian", dp8393xState, big_endian, false), DEFINE_PROP_END_OF_LIST(), }; From patchwork Wed Jun 27 23:29:51 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Vivier X-Patchwork-Id: 935797 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=vivier.eu Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41GKJY0dXKz9s01 for ; Thu, 28 Jun 2018 09:44:45 +1000 (AEST) Received: from localhost ([::1]:33693 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fYK78-0000zk-NW for incoming@patchwork.ozlabs.org; Wed, 27 Jun 2018 19:44:42 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:48631) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fYJtX-00085K-To for qemu-devel@nongnu.org; Wed, 27 Jun 2018 19:30:44 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fYJtU-0003mc-P3 for qemu-devel@nongnu.org; Wed, 27 Jun 2018 19:30:39 -0400 Received: from mout.kundenserver.de ([212.227.126.135]:51777) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1fYJtU-0003mN-94; Wed, 27 Jun 2018 19:30:36 -0400 Received: from localhost.localdomain ([78.238.229.36]) by mrelayeu.kundenserver.de (mreue001 [212.227.15.167]) with ESMTPSA (Nemesis) id 0MfvWO-1fkSzX0896-00NAx4; Thu, 28 Jun 2018 01:30:11 +0200 From: Laurent Vivier To: qemu-devel@nongnu.org Date: Thu, 28 Jun 2018 01:29:51 +0200 Message-Id: <20180627232951.14725-11-laurent@vivier.eu> X-Mailer: git-send-email 2.14.4 In-Reply-To: <20180627232951.14725-1-laurent@vivier.eu> References: <20180627232951.14725-1-laurent@vivier.eu> X-Provags-ID: V03:K1:eOdCg0gl2HpULJMzhHGdOjNiKXZCPTVzE2P/Jee5uYgmj6Im6Dy ua+WiCS075i+/x/rPFeB9pQjuzP1XgbHRJoX7PjOrwruqomUWnnRF0xsSOEoPjrZ5h+VX5m b8nkqlRe35Wr34Fp/LsHk99LzwuWxKKY3FYb+ny6xCMn1lGDbXcFgG4aE+U35IqhBpIwkTk +yV05+k6IdtJPXyYN5+ow== X-UI-Out-Filterresults: notjunk:1; V01:K0:oj1CLGCgBR8=:t9EgLxnd/+ZQfYoMbi4yym V0cuOZCFpAIMS88W0K3nlmp+f5llfxzirZI9y2U40i/2I8fLsM6MtrtnHF6SHZVfDZolWwgz8 K2Kc2OmPmLWSVQPpYHj3z/iGpfc6lWkJYvQaYtPokKnFYY7Qv/zj4T8KukGWcUZ+WujobPjHD uyJTH2x1pywacy3ETxFTczVeYNa96PHdTrvN766jJfqktb4B8Kir74jpn9IFyBnxEQgUnarVO OnuEXuGRbJ2vOp0lNCp7tG/yeNgSrf0pliXNmtxV+cAfkN1dDnWFUmMD4/X6hoWFG2A0Xjx+L atG/aLz5Hsx29hSCmqn6wK0QV1hkKvb1PJvwReWSKWgnGAxV+B6+f2qZwcNXl6v5dXB63QF+f x5WLeS2ajuWmm4wk8mm7JdPFunxjyGuxUGWHmuwQ0URHwcnsI1D+Fwsu5Zyb+j6UoGa8GzT5a uJ8FCdrzrAqArxPcPYFijPOddkswKy5bwd83nznm5dk1HoPzrwNXb35F3d2/G839wx8Dw+ItR B1bEOIMXXgw8GvC40ERTR/+9ziUFHWIEeFwzIZyctJjySu+0RlmrR8Ry9bbW6mYWK1x8dQ+Tz 04mkNC/jcFjNKt9IQ5RV6U9mZ88e5d1xkCa0om360U/o1b7LA1dwMwVLVcic+vOo+TC2njmE1 xGhbarfKgfY0n/3MesumJ8c4UUiXl5/4qN+FVA7bDaDke898ejn0vg1ds6K9S1qBchOI= X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 212.227.126.135 Subject: [Qemu-devel] [RFC v3 10/10] hw/m68k: define Macintosh Quadra 800 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: , Cc: Kevin Wolf , Fam Zheng , qemu-block@nongnu.org, Jason Wang , Mark Cave-Ayland , "Dr. David Alan Gilbert" , Laurent Vivier , =?utf-8?q?Herv=C3=A9_Poussineau?= , Gerd Hoffmann , Paolo Bonzini , Max Reitz , Yongbok Kim , =?utf-8?q?Andreas_F=C3=A4rber?= , Aurelien Jarno Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" From: Laurent Vivier Co-developed-by: Mark Cave-Ayland Signed-off-by: Mark Cave-Ayland Signed-off-by: Laurent Vivier --- MAINTAINERS | 19 ++ default-configs/m68k-softmmu.mak | 14 ++ hw/intc/Makefile.objs | 1 + hw/intc/q800_irq.c | 73 ++++++++ hw/m68k/Makefile.objs | 6 +- hw/m68k/bootinfo.h | 100 ++++++++++ hw/m68k/q800.c | 385 +++++++++++++++++++++++++++++++++++++++ include/hw/intc/q800_irq.h | 39 ++++ tests/qom-test.c | 5 + tests/test-hmp.c | 3 +- 10 files changed, 642 insertions(+), 3 deletions(-) create mode 100644 hw/intc/q800_irq.c create mode 100644 hw/m68k/bootinfo.h create mode 100644 hw/m68k/q800.c create mode 100644 include/hw/intc/q800_irq.h diff --git a/MAINTAINERS b/MAINTAINERS index 8c626f6a07..3c7c8d891e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -693,6 +693,25 @@ F: hw/char/mcf_uart.c F: hw/net/mcf_fec.c F: include/hw/m68k/mcf*.h +q800 +M: Laurent Vivier +S: Maintained +F: hw/audio/asc.c +F: hw/block/swim.c +F: hw/m68k/bootinfo.h +F: hw/display/macfb-template.h +F: hw/display/macfb.c +F: hw/intc/q800_irq.c +F: hw/m68k/q800.c +F: hw/misc/mac_via.c +F: hw/nubus/* +F: include/hw/audio/asc.h +F: include/hw/block/swim.h +F: include/hw/display/macfb.h +F: include/hw/intc/q800_irq.h +F: include/hw/misc/mac_via.h +F: include/hw/nubus/* + MicroBlaze Machines ------------------- petalogix_s3adsp1800 diff --git a/default-configs/m68k-softmmu.mak b/default-configs/m68k-softmmu.mak index 60f7cdfbf2..993644aa42 100644 --- a/default-configs/m68k-softmmu.mak +++ b/default-configs/m68k-softmmu.mak @@ -2,3 +2,17 @@ CONFIG_COLDFIRE=y CONFIG_PTIMER=y +CONFIG_ESCC=y +CONFIG_FRAMEBUFFER=y +CONFIG_ADB=y +CONFIG_MOS6522=y +CONFIG_MAC_VIA=y +CONFIG_Q800_IRQ=y +CONFIG_MAC=y +CONFIG_SCSI=y +CONFIG_ESP=y +CONFIG_ASC=y +CONFIG_MACFB=y +CONFIG_NUBUS=y +CONFIG_DP8393X=y +CONFIG_SWIM=y diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs index 0e9963f5ee..030967a0b3 100644 --- a/hw/intc/Makefile.objs +++ b/hw/intc/Makefile.objs @@ -46,3 +46,4 @@ obj-$(CONFIG_ARM_GIC) += arm_gicv3_cpuif.o obj-$(CONFIG_MIPS_CPS) += mips_gic.o obj-$(CONFIG_NIOS2) += nios2_iic.o obj-$(CONFIG_OMPIC) += ompic.o +obj-$(CONFIG_Q800_IRQ) += q800_irq.o diff --git a/hw/intc/q800_irq.c b/hw/intc/q800_irq.c new file mode 100644 index 0000000000..ec9d542d2e --- /dev/null +++ b/hw/intc/q800_irq.c @@ -0,0 +1,73 @@ +/* + * QEMU Motorla 680x0 Macintosh hardware System Emulator + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "hw/intc/q800_irq.h" + + +static void q800_set_irq(void *opaque, int irq, int level) +{ + Q800IRQControllerState *s = opaque; + int i; + + + if (level) { + s->ipr |= 1 << irq; + } else { + s->ipr &= ~(1 << irq); + } + + for (i = 7; i >= 0; i--) { + if ((s->ipr >> i) & 1) { + m68k_set_irq_level(s->cpu, i + 1, i + 25); + return; + } + } + m68k_set_irq_level(s->cpu, 0, 0); +} + +static void q800_irq_init(Object *obj) +{ + Q800IRQControllerState *s = Q800_IRQC(obj); + + qdev_init_gpio_in(DEVICE(obj), q800_set_irq, 8); + + object_property_add_link(obj, "cpu", TYPE_M68K_CPU, + (Object **) &s->cpu, + qdev_prop_allow_set_link_before_realize, + 0, NULL); +} + +static const TypeInfo q800_irq_type_info = { + .name = TYPE_Q800_IRQC, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(Q800IRQControllerState), + .instance_init = q800_irq_init, +}; + +static void q800_irq_register_types(void) +{ + type_register_static(&q800_irq_type_info); +} + +type_init(q800_irq_register_types); diff --git a/hw/m68k/Makefile.objs b/hw/m68k/Makefile.objs index d1f089c08a..18ebf1937a 100644 --- a/hw/m68k/Makefile.objs +++ b/hw/m68k/Makefile.objs @@ -1,2 +1,4 @@ -obj-y += an5206.o mcf5208.o -obj-y += mcf5206.o mcf_intc.o +obj-$(CONFIG_COLDFIRE) += an5206.o mcf5208.o +obj-$(CONFIG_MAC) += q800.o + +obj-$(CONFIG_COLDFIRE) += mcf5206.o mcf_intc.o diff --git a/hw/m68k/bootinfo.h b/hw/m68k/bootinfo.h new file mode 100644 index 0000000000..6584775f6d --- /dev/null +++ b/hw/m68k/bootinfo.h @@ -0,0 +1,100 @@ +struct bi_record { + uint16_t tag; /* tag ID */ + uint16_t size; /* size of record */ + uint32_t data[0]; /* data */ +}; + +/* machine independent tags */ + +#define BI_LAST 0x0000 /* last record */ +#define BI_MACHTYPE 0x0001 /* machine type (u_long) */ +#define BI_CPUTYPE 0x0002 /* cpu type (u_long) */ +#define BI_FPUTYPE 0x0003 /* fpu type (u_long) */ +#define BI_MMUTYPE 0x0004 /* mmu type (u_long) */ +#define BI_MEMCHUNK 0x0005 /* memory chunk address and size */ + /* (struct mem_info) */ +#define BI_RAMDISK 0x0006 /* ramdisk address and size */ + /* (struct mem_info) */ +#define BI_COMMAND_LINE 0x0007 /* kernel command line parameters */ + /* (string) */ + +/* Macintosh-specific tags (all u_long) */ + +#define BI_MAC_MODEL 0x8000 /* Mac Gestalt ID (model type) */ +#define BI_MAC_VADDR 0x8001 /* Mac video base address */ +#define BI_MAC_VDEPTH 0x8002 /* Mac video depth */ +#define BI_MAC_VROW 0x8003 /* Mac video rowbytes */ +#define BI_MAC_VDIM 0x8004 /* Mac video dimensions */ +#define BI_MAC_VLOGICAL 0x8005 /* Mac video logical base */ +#define BI_MAC_SCCBASE 0x8006 /* Mac SCC base address */ +#define BI_MAC_BTIME 0x8007 /* Mac boot time */ +#define BI_MAC_GMTBIAS 0x8008 /* Mac GMT timezone offset */ +#define BI_MAC_MEMSIZE 0x8009 /* Mac RAM size (sanity check) */ +#define BI_MAC_CPUID 0x800a /* Mac CPU type (sanity check) */ +#define BI_MAC_ROMBASE 0x800b /* Mac system ROM base address */ + +/* Macintosh hardware profile data */ + +#define BI_MAC_VIA1BASE 0x8010 /* Mac VIA1 base address (always present) */ +#define BI_MAC_VIA2BASE 0x8011 /* Mac VIA2 base address (type varies) */ +#define BI_MAC_VIA2TYPE 0x8012 /* Mac VIA2 type (VIA, RBV, OSS) */ +#define BI_MAC_ADBTYPE 0x8013 /* Mac ADB interface type */ +#define BI_MAC_ASCBASE 0x8014 /* Mac Apple Sound Chip base address */ +#define BI_MAC_SCSI5380 0x8015 /* Mac NCR 5380 SCSI (base address, multi) */ +#define BI_MAC_SCSIDMA 0x8016 /* Mac SCSI DMA (base address) */ +#define BI_MAC_SCSI5396 0x8017 /* Mac NCR 53C96 SCSI (base address, multi) */ +#define BI_MAC_IDETYPE 0x8018 /* Mac IDE interface type */ +#define BI_MAC_IDEBASE 0x8019 /* Mac IDE interface base address */ +#define BI_MAC_NUBUS 0x801a /* Mac Nubus type (none, regular, pseudo) */ +#define BI_MAC_SLOTMASK 0x801b /* Mac Nubus slots present */ +#define BI_MAC_SCCTYPE 0x801c /* Mac SCC serial type (normal, IOP) */ +#define BI_MAC_ETHTYPE 0x801d /* Mac builtin ethernet type (Sonic, MACE */ +#define BI_MAC_ETHBASE 0x801e /* Mac builtin ethernet base address */ +#define BI_MAC_PMU 0x801f /* Mac power management / poweroff hardware */ +#define BI_MAC_IOP_SWIM 0x8020 /* Mac SWIM floppy IOP */ +#define BI_MAC_IOP_ADB 0x8021 /* Mac ADB IOP */ + +#define BOOTINFO0(as, base, id) \ + do { \ + stw_phys(as, base, id); \ + base += 2; \ + stw_phys(as, base, sizeof(struct bi_record)); \ + base += 2; \ + } while (0) + +#define BOOTINFO1(as, base, id, value) \ + do { \ + stw_phys(as, base, id); \ + base += 2; \ + stw_phys(as, base, sizeof(struct bi_record) + 4); \ + base += 2; \ + stl_phys(as, base, value); \ + base += 4; \ + } while (0) + +#define BOOTINFO2(as, base, id, value1, value2) \ + do { \ + stw_phys(as, base, id); \ + base += 2; \ + stw_phys(as, base, sizeof(struct bi_record) + 8); \ + base += 2; \ + stl_phys(as, base, value1); \ + base += 4; \ + stl_phys(as, base, value2); \ + base += 4; \ + } while (0) + +#define BOOTINFOSTR(as, base, id, string) \ + do { \ + int i; \ + stw_phys(as, base, id); \ + base += 2; \ + stw_phys(as, base, \ + (sizeof(struct bi_record) + strlen(string) + 2) & ~1); \ + base += 2; \ + for (i = 0; string[i]; i++) { \ + stb_phys(as, base++, string[i]); \ + } \ + stb_phys(as, base++, 0); \ + base = (parameters_base + 1) & ~1; \ + } while (0) diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c new file mode 100644 index 0000000000..51ad3c6c76 --- /dev/null +++ b/hw/m68k/q800.c @@ -0,0 +1,385 @@ +/* + * QEMU Motorla 680x0 Macintosh hardware System Emulator + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "sysemu/sysemu.h" +#include "cpu.h" +#include "hw/hw.h" +#include "hw/boards.h" +#include "elf.h" +#include "hw/loader.h" +#include "hw/display/framebuffer.h" +#include "ui/console.h" +#include "exec/address-spaces.h" +#include "hw/char/escc.h" +#include "hw/sysbus.h" +#include "hw/scsi/esp.h" +#include "bootinfo.h" +#include "hw/misc/mac_via.h" +#include "hw/input/adb.h" +#include "hw/audio/asc.h" +#include "hw/nubus/mac-nubus-bridge.h" +#include "hw/display/macfb.h" +#include "hw/intc/q800_irq.h" +#include "hw/block/swim.h" +#include "net/net.h" +#include "qapi/error.h" + +#define MACROM_ADDR 0x40000000 +#define MACROM_SIZE 0x00100000 + +/* + * .ident = MAC_MODEL_Q800, + * .name = "Quadra 800", + * .adb_type = MAC_ADB_II, + * .via_type = MAC_VIA_QUADRA, + * .scsi_type = MAC_SCSI_QUADRA, + * .scc_type = MAC_SCC_QUADRA, + * .ether_type = MAC_ETHER_SONIC, + * .nubus_type = MAC_NUBUS + */ + +#define MACROM_FILENAME "MacROM.bin" + +#define Q800_MACHINE_ID 35 +#define Q800_CPU_ID (1 << 2) +#define Q800_FPU_ID (1 << 2) +#define Q800_MMU_ID (1 << 2) + +#define MACH_MAC 3 +#define Q800_MAC_CPU_ID 2 + +#define VIA_BASE 0x50f00000 +#define SONIC_PROM_BASE 0x50f08000 +#define SONIC_BASE 0x50f0a000 +#define SCC_BASE 0x50f0c020 +#define ESP_BASE 0x50f10000 +#define ESP_PDMA 0x50f10100 +#define ASC_BASE 0x50F14000 +#define SWIM_BASE 0x50F1E000 +#define NUBUS_SUPER_SLOT_BASE 0x60000000 +#define NUBUS_SLOT_BASE 0xf0000000 + +/* the video base, whereas it a Nubus address, + * is needed by the kernel to have early display and + * thus provided by the bootloader + */ +#define VIDEO_BASE 0xf9001000 + +#define MAC_CLOCK 3686418 + +static void main_cpu_reset(void *opaque) +{ + M68kCPU *cpu = opaque; + CPUState *cs = CPU(cpu); + + cpu_reset(cs); + cpu->env.aregs[7] = ldl_phys(cs->as, 0); + cpu->env.pc = ldl_phys(cs->as, 4); +} + +static void q800_init(MachineState *machine) +{ + M68kCPU *cpu = NULL; + int linux_boot; + int32_t kernel_size; + uint64_t elf_entry; + char *filename; + int bios_size; + ram_addr_t initrd_base; + int32_t initrd_size; + MemoryRegion *rom; + MemoryRegion *ram; + ram_addr_t ram_size = machine->ram_size; + const char *kernel_filename = machine->kernel_filename; + const char *initrd_filename = machine->initrd_filename; + const char *kernel_cmdline = machine->kernel_cmdline; + hwaddr parameters_base; + CPUState *cs; + DeviceState *dev; + DeviceState *via_dev, *pic_dev; + SysBusESPState *sysbus_esp; + ESPState *esp; + SysBusDevice *sysbus; + BusState *adb_bus; + NubusBus *nubus; + DriveInfo *fds[2]; + + linux_boot = (kernel_filename != NULL); + + /* init CPUs */ + cpu = M68K_CPU(cpu_create(machine->cpu_type)); + if (!cpu) { + hw_error("qemu: unable to find m68k CPU definition\n"); + exit(1); + } + qemu_register_reset(main_cpu_reset, cpu); + + ram = g_malloc(sizeof(*ram)); + memory_region_init_ram(ram, NULL, "m68k_mac.ram", ram_size, &error_abort); + memory_region_add_subregion(get_system_memory(), 0, ram); + + /* IRQ controller */ + + pic_dev = qdev_create(NULL, TYPE_Q800_IRQC); + object_property_set_link(OBJECT(pic_dev), OBJECT(cpu), "cpu", + &error_abort); + qdev_init_nofail(pic_dev); + + /* VIA */ + + via_dev = qdev_create(NULL, TYPE_MAC_VIA); + qdev_init_nofail(via_dev); + sysbus = SYS_BUS_DEVICE(via_dev); + sysbus_mmio_map(sysbus, 0, VIA_BASE); + qdev_connect_gpio_out_named(DEVICE(sysbus), "irq", 0, + qdev_get_gpio_in(pic_dev, 0)); + qdev_connect_gpio_out_named(DEVICE(sysbus), "irq", 1, + qdev_get_gpio_in(pic_dev, 1)); + + adb_bus = qdev_get_child_bus(via_dev, "adb.0"); + dev = qdev_create(adb_bus, TYPE_ADB_KEYBOARD); + qdev_init_nofail(dev); + dev = qdev_create(adb_bus, TYPE_ADB_MOUSE); + qdev_init_nofail(dev); + + /* MACSONIC */ + + if (nb_nics != 1) { + hw_error("Q800 needs a dp83932 ethernet interfaces"); + } + if (!nd_table[0].model) { + nd_table[0].model = g_strdup("dp83932"); + } + if (strcmp(nd_table[0].model, "dp83932") != 0) { + hw_error("Q800 needs a dp83932 ethernet interfaces"); + } else { + /* MacSonic driver needs an Apple MAC address + * Valid prefix are: + * 00:05:02 Apple + * 00:80:19 Dayna Communications, Inc. + * 00:A0:40 Apple + * 08:00:07 Apple + * (Q800 use the last one) + */ + nd_table[0].macaddr.a[0] = 0x08; + nd_table[0].macaddr.a[1] = 0x00; + nd_table[0].macaddr.a[2] = 0x07; + } + qemu_check_nic_model(&nd_table[0], "dp83932"); + dev = qdev_create(NULL, "dp8393x"); + qdev_set_nic_properties(dev, &nd_table[0]); + qdev_prop_set_uint8(dev, "it_shift", 2); + qdev_prop_set_bit(dev, "big_endian", true); + qdev_prop_set_ptr(dev, "dma_mr", get_system_memory()); + qdev_init_nofail(dev); + sysbus = SYS_BUS_DEVICE(dev); + sysbus_mmio_map(sysbus, 0, SONIC_BASE); + sysbus_mmio_map(sysbus, 1, SONIC_PROM_BASE); + sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(pic_dev, 2)); + + /* SCC */ + + dev = qdev_create(NULL, TYPE_ESCC); + qdev_prop_set_uint32(dev, "disabled", 0); + qdev_prop_set_uint32(dev, "frequency", MAC_CLOCK); + qdev_prop_set_uint32(dev, "it_shift", 1); + qdev_prop_set_bit(dev, "bit_swap", true); + qdev_prop_set_chr(dev, "chrA", serial_hd(0)); + qdev_prop_set_chr(dev, "chrB", serial_hd(1)); + qdev_prop_set_uint32(dev, "chnBtype", 0); + qdev_prop_set_uint32(dev, "chnAtype", 0); + qdev_init_nofail(dev); + sysbus = SYS_BUS_DEVICE(dev); + sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(pic_dev, 3)); + sysbus_connect_irq(sysbus, 1, qdev_get_gpio_in(pic_dev, 3)); + sysbus_mmio_map(sysbus, 0, SCC_BASE); + + /* SCSI */ + + dev = qdev_create(NULL, TYPE_ESP); + sysbus_esp = ESP_STATE(dev); + esp = &sysbus_esp->esp; + esp->dma_memory_read = NULL; + esp->dma_memory_write = NULL; + esp->dma_opaque = NULL; + sysbus_esp->it_shift = 4; + esp->dma_enabled = 1; + qdev_init_nofail(dev); + + sysbus = SYS_BUS_DEVICE(dev); + sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in_named(via_dev, + "via2-irq", + VIA2_IRQ_SCSI_BIT)); + sysbus_connect_irq(sysbus, 1, + qdev_get_gpio_in_named(via_dev, "via2-irq", + VIA2_IRQ_SCSI_DATA_BIT)); + sysbus_mmio_map(sysbus, 0, ESP_BASE); + sysbus_mmio_map(sysbus, 1, ESP_PDMA); + + scsi_bus_legacy_handle_cmdline(&esp->bus); + + /* Apple Sound Chip */ + + dev = qdev_create(NULL, TYPE_ASC); + qdev_prop_set_uint8(dev, "asctype", ASC_TYPE_ASC); + qdev_init_nofail(dev); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, ASC_BASE); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, + qdev_get_gpio_in_named(via_dev, "via2-irq", + VIA2_IRQ_ASC_BIT)); + + /* SWIM floppy controller */ + + if (drive_get_max_bus(IF_FLOPPY) >= 2) { + fprintf(stderr, "qemu: too many floppy drives\n"); + exit(1); + } + fds[0] = drive_get(IF_FLOPPY, 0, 0); + fds[1] = drive_get(IF_FLOPPY, 0, 1); + + dev = qdev_create(NULL, TYPE_SWIM); + if (fds[0]) { + qdev_prop_set_drive(dev, "driveA", blk_by_legacy_dinfo(fds[0]), + &error_fatal); + } + if (fds[1]) { + qdev_prop_set_drive(dev, "driveB", blk_by_legacy_dinfo(fds[1]), + &error_fatal); + } + qdev_init_nofail(dev); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, SWIM_BASE); + + /* NuBus */ + + dev = qdev_create(NULL, TYPE_MAC_NUBUS_BRIDGE); + qdev_init_nofail(dev); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, NUBUS_SUPER_SLOT_BASE); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, NUBUS_SLOT_BASE); + + nubus = MAC_NUBUS_BRIDGE(dev)->bus; + + /* framebuffer in nubus slot #9 */ + + dev = qdev_create(BUS(nubus), TYPE_NUBUS_MACFB); + qdev_prop_set_uint32(dev, "width", graphic_width); + qdev_prop_set_uint32(dev, "height", graphic_height); + qdev_prop_set_uint8(dev, "depth", graphic_depth); + qdev_init_nofail(dev); + + cs = CPU(cpu); + if (linux_boot) { + uint64_t high; + kernel_size = load_elf(kernel_filename, NULL, NULL, + &elf_entry, NULL, &high, 1, + EM_68K, 0, 0); + if (kernel_size < 0) { + hw_error("qemu: could not load kernel '%s'\n", + kernel_filename); + exit(1); + } + stl_phys(cs->as, 4, elf_entry); /* reset initial PC */ + parameters_base = (high + 1) & ~1; + + BOOTINFO1(cs->as, parameters_base, BI_MACHTYPE, MACH_MAC); + BOOTINFO1(cs->as, parameters_base, BI_FPUTYPE, Q800_FPU_ID); + BOOTINFO1(cs->as, parameters_base, BI_MMUTYPE, Q800_MMU_ID); + BOOTINFO1(cs->as, parameters_base, BI_CPUTYPE, Q800_CPU_ID); + BOOTINFO1(cs->as, parameters_base, BI_MAC_CPUID, Q800_MAC_CPU_ID); + BOOTINFO1(cs->as, parameters_base, BI_MAC_MODEL, Q800_MACHINE_ID); + BOOTINFO1(cs->as, parameters_base, + BI_MAC_MEMSIZE, ram_size >> 20); /* in MB */ + BOOTINFO2(cs->as, parameters_base, BI_MEMCHUNK, 0, ram_size); + BOOTINFO1(cs->as, parameters_base, BI_MAC_VADDR, VIDEO_BASE); + BOOTINFO1(cs->as, parameters_base, BI_MAC_VDEPTH, graphic_depth); + BOOTINFO1(cs->as, parameters_base, BI_MAC_VDIM, + (graphic_height << 16) | graphic_width); + BOOTINFO1(cs->as, parameters_base, BI_MAC_VROW, + (graphic_width * graphic_depth + 7) / 8); + BOOTINFO1(cs->as, parameters_base, BI_MAC_SCCBASE, SCC_BASE); + + if (kernel_cmdline) { + BOOTINFOSTR(cs->as, parameters_base, BI_COMMAND_LINE, + kernel_cmdline); + } + + /* load initrd */ + if (initrd_filename) { + initrd_size = get_image_size(initrd_filename); + if (initrd_size < 0) { + hw_error("qemu: could not load initial ram disk '%s'\n", + initrd_filename); + exit(1); + } + + initrd_base = (ram_size - initrd_size) & TARGET_PAGE_MASK; + load_image_targphys(initrd_filename, initrd_base, + ram_size - initrd_base); + BOOTINFO2(cs->as, parameters_base, BI_RAMDISK, initrd_base, + initrd_size); + } else { + initrd_base = 0; + initrd_size = 0; + } + BOOTINFO0(cs->as, parameters_base, BI_LAST); + } else { + uint8_t *ptr; + /* allocate and load BIOS */ + rom = g_malloc(sizeof(*rom)); + memory_region_init_ram(rom, NULL, "m68k_mac.rom", MACROM_SIZE, + &error_abort); + if (bios_name == NULL) { + bios_name = MACROM_FILENAME; + } + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); + memory_region_set_readonly(rom, true); + memory_region_add_subregion(get_system_memory(), MACROM_ADDR, rom); + + /* Load MacROM binary */ + if (filename) { + bios_size = load_image_targphys(filename, MACROM_ADDR, MACROM_SIZE); + g_free(filename); + } else { + bios_size = -1; + } + if (bios_size < 0 || bios_size > MACROM_SIZE) { + hw_error("qemu: could not load MacROM '%s'\n", bios_name); + exit(1); + } + ptr = rom_ptr(MACROM_ADDR); + stl_phys(cs->as, 0, ldl_p(ptr)); /* reset initial SP */ + stl_phys(cs->as, 4, + MACROM_ADDR + ldl_p(ptr + 4)); /* reset initial PC */ + } +} + +static void q800_machine_init(MachineClass *mc) +{ + mc->desc = "Macintosh Quadra 800"; + mc->init = q800_init; + mc->default_cpu_type = M68K_CPU_TYPE_NAME("m68040"); + mc->max_cpus = 1; + mc->is_default = 0; + mc->block_default_type = IF_SCSI; +} + +DEFINE_MACHINE("q800", q800_machine_init) diff --git a/include/hw/intc/q800_irq.h b/include/hw/intc/q800_irq.h new file mode 100644 index 0000000000..91c2de1cc5 --- /dev/null +++ b/include/hw/intc/q800_irq.h @@ -0,0 +1,39 @@ +/* + * QEMU Motorla 680x0 Macintosh hardware System Emulator + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef Q800_IRQ_H +#define Q800_IRQ_H + +#include "hw/sysbus.h" + +#define TYPE_Q800_IRQC "q800-irq-controller" +#define Q800_IRQC(obj) OBJECT_CHECK(Q800IRQControllerState, (obj), \ + TYPE_Q800_IRQC) + +typedef struct Q800IRQControllerState { + SysBusDevice parent_obj; + + M68kCPU *cpu; + uint8_t ipr; +} Q800IRQControllerState; + +#endif diff --git a/tests/qom-test.c b/tests/qom-test.c index e6f712cbd3..373699fda4 100644 --- a/tests/qom-test.c +++ b/tests/qom-test.c @@ -19,12 +19,17 @@ static const char *blacklist_x86[] = { "xenfv", "xenpv", NULL }; +static const char *blacklist_m68k[] = { + "q800", NULL +}; + static const struct { const char *arch; const char **machine; } blacklists[] = { { "i386", blacklist_x86 }, { "x86_64", blacklist_x86 }, + { "m68k", blacklist_m68k }, }; static bool is_blacklisted(const char *arch, const char *mach) diff --git a/tests/test-hmp.c b/tests/test-hmp.c index 5352c9c088..f3b79d5bdf 100644 --- a/tests/test-hmp.c +++ b/tests/test-hmp.c @@ -139,7 +139,8 @@ static void add_machine_test_case(const char *mname) char *path; /* Ignore blacklisted machines that have known problems */ - if (!strcmp("xenfv", mname) || !strcmp("xenpv", mname)) { + if (!strcmp("xenfv", mname) || !strcmp("xenpv", mname) || + !strcmp("q800", mname)) { return; }